#ifndef __HVCALL_H__
#define __HVCALL_H__

#include "patch-utils.h"

#define HVSC_SYSCALL                    811                     // which syscall to overwrite with hvsc redirect
#define HVSC_SYSCALL_ADDR               0x8000000000195540ULL   // where above syscall is in lv2
#define NEW_POKE_SYSCALL                813                     // which syscall to overwrite with new poke
#define NEW_POKE_SYSCALL_ADDR           0x8000000000195A68ULL   // where above syscall is in lv2

#define HV_BASE                         0x8000000014000000ULL   // where in lv2 to map lv1
#define HV_SIZE                         0x370000                // size of lv1 memory to map/dump

#define HPTE_V_BOLTED           0x0000000000000010ULL
#define HPTE_V_LARGE            0x0000000000000004ULL
#define HPTE_V_VALID            0x0000000000000001ULL
#define HPTE_R_PROT_MASK        0x0000000000000003ULL
#define MM_EA2VA(ea)            ((ea) & ~0x8000000000000000ULL)

#define SC_QUOTE_(x) #x
#define SYSCALL(num) "li %%r11, " SC_QUOTE_(num) "; sc;"

#define INSTALL_HVSC_REDIRECT(hvcall) uint64_t original_syscall_code_1 = lv2peek(HVSC_SYSCALL_ADDR); \
    uint64_t original_syscall_code_2 = lv2peek(HVSC_SYSCALL_ADDR + 8); \
    uint64_t original_syscall_code_3 = lv2peek(HVSC_SYSCALL_ADDR + 16); \
    uint64_t original_syscall_code_4 = lv2peek(HVSC_SYSCALL_ADDR + 24); \
    lv2poke(HVSC_SYSCALL_ADDR, 0x7C0802A6F8010010ULL);  \
    lv2poke(HVSC_SYSCALL_ADDR + 8, 0x3960000044000022ULL | (uint64_t)hvcall << 32); \
    lv2poke(HVSC_SYSCALL_ADDR + 16, 0xE80100107C0803A6ULL); \
    lv2poke(HVSC_SYSCALL_ADDR + 24, 0x4e80002060000000ULL);
    
#define REMOVE_HVSC_REDIRECT() lv2poke(HVSC_SYSCALL_ADDR, original_syscall_code_1); \
    lv2poke(HVSC_SYSCALL_ADDR + 8, original_syscall_code_2); \
    lv2poke(HVSC_SYSCALL_ADDR + 16, original_syscall_code_3); \
    lv2poke(HVSC_SYSCALL_ADDR + 24, original_syscall_code_4);

int lv1_insert_htab_entry(uint64_t htab_id, uint64_t hpte_group, uint64_t hpte_v, uint64_t hpte_r, uint64_t bolted_flag, uint64_t flags, uint64_t *hpte_index, uint64_t *hpte_evicted_v, uint64_t *hpte_evicted_r);
int lv1_allocate_memory(uint64_t size, uint64_t page_size_exp, uint64_t flags, uint64_t *addr, uint64_t *muid);
int lv1_undocumented_function_114(uint64_t start, uint64_t page_size, uint64_t size, uint64_t *lpar_addr);
void lv1_undocumented_function_115(uint64_t lpar_addr);

uint64_t lv2_alloc(uint64_t size, uint64_t pool);

#endif
