/******************************************************************************
* asm-x86/guest/hyperv-hcall.h
*
* This program is free software; you can redistribute it and/or
* modify it under the terms and conditions of the GNU General Public
* License, version 2, as published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* General Public License for more details.
*
* You should have received a copy of the GNU General Public
* License along with this program; If not, see .
*
* 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:
*/