73 lines
1.7 KiB
C
73 lines
1.7 KiB
C
#ifndef _BITS_HYPERV_H
|
|
#define _BITS_HYPERV_H
|
|
|
|
/** @file
|
|
*
|
|
* Hyper-V interface
|
|
*
|
|
*/
|
|
|
|
FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
|
|
|
|
#include <stddef.h>
|
|
#include <stdint.h>
|
|
#include <ipxe/io.h>
|
|
|
|
/**
|
|
* Issue hypercall
|
|
*
|
|
* @v hv Hyper-V hypervisor
|
|
* @v code Call code
|
|
* @v in Input parameters
|
|
* @v out Output parameters
|
|
* @ret status Status code
|
|
*/
|
|
static inline __attribute__ (( always_inline )) int
|
|
hv_call ( struct hv_hypervisor *hv, unsigned int code, const void *in,
|
|
void *out ) {
|
|
void *hypercall = hv->hypercall;
|
|
uint32_t in_phys;
|
|
uint32_t out_phys;
|
|
uint32_t discard_ecx;
|
|
uint32_t discard_edx;
|
|
uint16_t result;
|
|
|
|
in_phys = ( ( __builtin_constant_p ( in ) && ( in == NULL ) )
|
|
? 0 : virt_to_phys ( in ) );
|
|
out_phys = ( ( __builtin_constant_p ( out ) && ( out == NULL ) )
|
|
? 0 : virt_to_phys ( out ) );
|
|
__asm__ __volatile__ ( "call *%9"
|
|
: "=a" ( result ), "=c" ( discard_ecx ),
|
|
"=d" ( discard_edx )
|
|
: "d" ( 0 ), "a" ( code ),
|
|
"b" ( 0 ), "c" ( in_phys ),
|
|
"D" ( 0 ), "S" ( out_phys ),
|
|
"m" ( hypercall ) );
|
|
return result;
|
|
}
|
|
|
|
/**
|
|
* Set bit atomically
|
|
*
|
|
* @v bits Bit field
|
|
* @v bit Bit to set
|
|
*/
|
|
static inline __attribute__ (( always_inline )) void
|
|
hv_set_bit ( void *bits, unsigned int bit ) {
|
|
struct {
|
|
uint32_t dword[ ( bit / 32 ) + 1 ];
|
|
} *dwords = bits;
|
|
|
|
/* Set bit using "lock bts". Inform compiler that any memory
|
|
* from the start of the bit field up to and including the
|
|
* dword containing this bit may be modified. (This is
|
|
* overkill but shouldn't matter in practice since we're
|
|
* unlikely to subsequently read other bits from the same bit
|
|
* field.)
|
|
*/
|
|
__asm__ __volatile__ ( "lock bts %1, %0"
|
|
: "+m" ( *dwords ) : "Ir" ( bit ) );
|
|
}
|
|
|
|
#endif /* _BITS_HYPERV_H */
|