/* SPDX-License-Identifier: GPL-2.0-only */ /****************************************************************************** * asm-x86/guest/hyperv-hcall.h * * Copyright (c) 2019 Microsoft. */ #ifndef __X86_HYPERV_HCALL_H__ #define __X86_HYPERV_HCALL_H__ #include #include #include #include #include #include static inline uint64_t hv_do_hypercall(uint64_t control, paddr_t input_addr, paddr_t output_addr) { uint64_t status; register unsigned long r8 asm ( "r8" ) = output_addr; /* See TLFS for volatile registers */ asm volatile ( "call hv_hcall_page" : "=a" (status), "+c" (control), "+d" (input_addr) ASM_CALL_CONSTRAINT : "r" (r8) : "memory" ); return status; } static inline uint64_t hv_do_fast_hypercall(uint16_t code, uint64_t input1, uint64_t input2) { uint64_t status; uint64_t control = code | HV_HYPERCALL_FAST_BIT; register unsigned long r8 asm ( "r8" ) = input2; /* See TLFS for volatile registers */ asm volatile ( "call hv_hcall_page" : "=a" (status), "+c" (control), "+d" (input1) ASM_CALL_CONSTRAINT : "r" (r8) ); return status; } static inline uint64_t hv_do_rep_hypercall(uint16_t code, uint16_t rep_count, uint16_t varhead_size, paddr_t input, paddr_t output) { uint64_t control = code; uint64_t status; uint16_t rep_comp; control |= (uint64_t)varhead_size << HV_HYPERCALL_VARHEAD_OFFSET; control |= (uint64_t)rep_count << HV_HYPERCALL_REP_COMP_OFFSET; do { status = hv_do_hypercall(control, input, output); if ( (status & HV_HYPERCALL_RESULT_MASK) != HV_STATUS_SUCCESS ) break; rep_comp = MASK_EXTR(status, HV_HYPERCALL_REP_COMP_MASK); control &= ~HV_HYPERCALL_REP_START_MASK; control |= MASK_INSR(rep_comp, HV_HYPERCALL_REP_START_MASK); } while ( rep_comp < rep_count ); return status; } #endif /* __X86_HYPERV_HCALL_H__ */ /* * Local variables: * mode: C * c-file-style: "BSD" * c-basic-offset: 4 * tab-width: 4 * indent-tabs-mode: nil * End: */