Ovmf/Xen: refactor XenBusDxe hypercall implementation

This refactors the Xen hypercall implementation that is part of the
XenBusDxe driver, in preparation of splitting it off entirely into
a XenHypercallLib library. This involves:
- removing the dependency on XENBUS_DEVICE* pointers in the XenHypercall()
  prototypes
- moving the discovered hyperpage address to a global variable
- moving XenGetSharedInfoPage() to its only user XenBusDxe.c (the shared info
  page is not strictly part of the Xen hypercall interface, and is not used
  by other expected users of XenHypercallLib such as the Xen console version
  of SerialPortLib
- reimplement XenHypercall2() in C and move the indexing of the hyperpage
  there; the existing asm implementations are renamed to __XenHypercall2() and
  invoked from the new C implementation.

Contributed-under: TianoCore Contribution Agreement 1.0
Acked-by: Laszlo Ersek <lersek@redhat.com>
Reviewed-by: Anthony PERARD <anthony.perard@citrix.com>
Signed-off-by: Ard Biesheuvel <ard.biesheuvel@linaro.org>
Signed-off-by: Laszlo Ersek <lersek@redhat.com>

git-svn-id: https://svn.code.sf.net/p/edk2/code/trunk/edk2@16969 6f19259b-4bc3-4df7-8a09-765794883524
This commit is contained in:
Ard Biesheuvel 2015-02-28 20:32:27 +00:00 committed by lersek
parent d6970b9b41
commit bbc3758ab5
9 changed files with 84 additions and 81 deletions

View File

@ -28,7 +28,7 @@ XenEventChannelNotify (
evtchn_send_t Send; evtchn_send_t Send;
Send.port = Port; Send.port = Port;
ReturnCode = XenHypercallEventChannelOp (Dev, EVTCHNOP_send, &Send); ReturnCode = XenHypercallEventChannelOp (EVTCHNOP_send, &Send);
return (UINT32)ReturnCode; return (UINT32)ReturnCode;
} }
@ -40,15 +40,12 @@ XenBusEventChannelAllocate (
OUT evtchn_port_t *Port OUT evtchn_port_t *Port
) )
{ {
XENBUS_PRIVATE_DATA *Private;
evtchn_alloc_unbound_t Parameter; evtchn_alloc_unbound_t Parameter;
UINT32 ReturnCode; UINT32 ReturnCode;
Private = XENBUS_PRIVATE_DATA_FROM_THIS (This);
Parameter.dom = DOMID_SELF; Parameter.dom = DOMID_SELF;
Parameter.remote_dom = DomainId; Parameter.remote_dom = DomainId;
ReturnCode = (UINT32)XenHypercallEventChannelOp (Private->Dev, ReturnCode = (UINT32)XenHypercallEventChannelOp (
EVTCHNOP_alloc_unbound, EVTCHNOP_alloc_unbound,
&Parameter); &Parameter);
if (ReturnCode != 0) { if (ReturnCode != 0) {
@ -79,10 +76,8 @@ XenBusEventChannelClose (
IN evtchn_port_t Port IN evtchn_port_t Port
) )
{ {
XENBUS_PRIVATE_DATA *Private;
evtchn_close_t Close; evtchn_close_t Close;
Private = XENBUS_PRIVATE_DATA_FROM_THIS (This);
Close.port = Port; Close.port = Port;
return (UINT32)XenHypercallEventChannelOp (Private->Dev, EVTCHNOP_close, &Close); return (UINT32)XenHypercallEventChannelOp (EVTCHNOP_close, &Close);
} }

View File

@ -161,7 +161,7 @@ XenGrantTableInit (
Parameters.idx = Index; Parameters.idx = Index;
Parameters.space = XENMAPSPACE_grant_table; Parameters.space = XENMAPSPACE_grant_table;
Parameters.gpfn = (xen_pfn_t) ((UINTN) GrantTable >> EFI_PAGE_SHIFT) + Index; Parameters.gpfn = (xen_pfn_t) ((UINTN) GrantTable >> EFI_PAGE_SHIFT) + Index;
ReturnCode = XenHypercallMemoryOp (Dev, XENMEM_add_to_physmap, &Parameters); ReturnCode = XenHypercallMemoryOp (XENMEM_add_to_physmap, &Parameters);
if (ReturnCode != 0) { if (ReturnCode != 0) {
DEBUG ((EFI_D_ERROR, "Xen GrantTable, add_to_physmap hypercall error: %d\n", ReturnCode)); DEBUG ((EFI_D_ERROR, "Xen GrantTable, add_to_physmap hypercall error: %d\n", ReturnCode));
} }
@ -184,7 +184,7 @@ XenGrantTableDeinit (
Parameters.domid = DOMID_SELF; Parameters.domid = DOMID_SELF;
Parameters.gpfn = (xen_pfn_t) ((UINTN) GrantTable >> EFI_PAGE_SHIFT) + Index; Parameters.gpfn = (xen_pfn_t) ((UINTN) GrantTable >> EFI_PAGE_SHIFT) + Index;
DEBUG ((EFI_D_INFO, "Xen GrantTable, removing %X\n", Parameters.gpfn)); DEBUG ((EFI_D_INFO, "Xen GrantTable, removing %X\n", Parameters.gpfn));
ReturnCode = XenHypercallMemoryOp (Dev, XENMEM_remove_from_physmap, &Parameters); ReturnCode = XenHypercallMemoryOp (XENMEM_remove_from_physmap, &Parameters);
if (ReturnCode != 0) { if (ReturnCode != 0) {
DEBUG ((EFI_D_ERROR, "Xen GrantTable, remove_from_physmap hypercall error: %d\n", ReturnCode)); DEBUG ((EFI_D_ERROR, "Xen GrantTable, remove_from_physmap hypercall error: %d\n", ReturnCode));
} }

View File

@ -2,13 +2,13 @@ SECTION .text
; INTN ; INTN
; EFIAPI ; EFIAPI
; XenHypercall2 ( ; __XenHypercall2 (
; IN VOID *HypercallAddr, ; IN VOID *HypercallAddr,
; IN OUT INTN Arg1, ; IN OUT INTN Arg1,
; IN OUT INTN Arg2 ; IN OUT INTN Arg2
; ); ; );
global ASM_PFX(XenHypercall2) global ASM_PFX(__XenHypercall2)
ASM_PFX(XenHypercall2): ASM_PFX(__XenHypercall2):
; Save only ebx, ecx is supposed to be a scratch register and needs to be ; Save only ebx, ecx is supposed to be a scratch register and needs to be
; saved by the caller ; saved by the caller
push ebx push ebx

View File

@ -3,13 +3,13 @@ SECTION .text
; INTN ; INTN
; EFIAPI ; EFIAPI
; XenHypercall2 ( ; __XenHypercall2 (
; IN VOID *HypercallAddr, ; IN VOID *HypercallAddr,
; IN OUT INTN Arg1, ; IN OUT INTN Arg1,
; IN OUT INTN Arg2 ; IN OUT INTN Arg2
; ); ; );
global ASM_PFX(XenHypercall2) global ASM_PFX(__XenHypercall2)
ASM_PFX(XenHypercall2): ASM_PFX(__XenHypercall2):
push rdi push rdi
push rsi push rsi
; Copy HypercallAddr to rax ; Copy HypercallAddr to rax

View File

@ -34,6 +34,8 @@
#include "XenStore.h" #include "XenStore.h"
#include "XenBus.h" #include "XenBus.h"
#include <IndustryStandard/Xen/hvm/params.h>
#include <IndustryStandard/Xen/memory.h>
/// ///
/// Driver Binding Protocol instance /// Driver Binding Protocol instance
@ -51,6 +53,46 @@ EFI_DRIVER_BINDING_PROTOCOL gXenBusDxeDriverBinding = {
STATIC EFI_LOCK mMyDeviceLock = EFI_INITIALIZE_LOCK_VARIABLE (TPL_CALLBACK); STATIC EFI_LOCK mMyDeviceLock = EFI_INITIALIZE_LOCK_VARIABLE (TPL_CALLBACK);
STATIC XENBUS_DEVICE *mMyDevice = NULL; STATIC XENBUS_DEVICE *mMyDevice = NULL;
/**
Map the shared_info_t page into memory.
@param Dev A XENBUS_DEVICE instance.
@retval EFI_SUCCESS Dev->SharedInfo whill contain a pointer to
the shared info page
@retval EFI_LOAD_ERROR The shared info page could not be mapped. The
hypercall returned an error.
**/
STATIC
EFI_STATUS
XenGetSharedInfoPage (
IN OUT XENBUS_DEVICE *Dev
)
{
xen_add_to_physmap_t Parameter;
ASSERT (Dev->SharedInfo == NULL);
Parameter.domid = DOMID_SELF;
Parameter.space = XENMAPSPACE_shared_info;
Parameter.idx = 0;
//
// using reserved page because the page is not released when Linux is
// starting because of the add_to_physmap. QEMU might try to access the
// page, and fail because it have no right to do so (segv).
//
Dev->SharedInfo = AllocateReservedPages (1);
Parameter.gpfn = (UINTN) Dev->SharedInfo >> EFI_PAGE_SHIFT;
if (XenHypercallMemoryOp (XENMEM_add_to_physmap, &Parameter) != 0) {
FreePages (Dev->SharedInfo, 1);
Dev->SharedInfo = NULL;
return EFI_LOAD_ERROR;
}
return EFI_SUCCESS;
}
/** /**
Unloads an image. Unloads an image.
@ -348,7 +390,7 @@ XenBusDxeDriverBindingStart (
MmioAddr = BarDesc->AddrRangeMin; MmioAddr = BarDesc->AddrRangeMin;
FreePool (BarDesc); FreePool (BarDesc);
Status = XenHyperpageInit (Dev); Status = XenHyperpageInit ();
if (EFI_ERROR (Status)) { if (EFI_ERROR (Status)) {
DEBUG ((EFI_D_ERROR, "XenBus: Unable to retrieve the hyperpage.\n")); DEBUG ((EFI_D_ERROR, "XenBus: Unable to retrieve the hyperpage.\n"));
Status = EFI_UNSUPPORTED; Status = EFI_UNSUPPORTED;

View File

@ -91,7 +91,6 @@ struct _XENBUS_DEVICE {
EFI_DEVICE_PATH_PROTOCOL *DevicePath; EFI_DEVICE_PATH_PROTOCOL *DevicePath;
LIST_ENTRY ChildList; LIST_ENTRY ChildList;
VOID *Hyperpage;
shared_info_t *SharedInfo; shared_info_t *SharedInfo;
}; };

View File

@ -23,9 +23,21 @@
#include <IndustryStandard/Xen/hvm/params.h> #include <IndustryStandard/Xen/hvm/params.h>
#include <IndustryStandard/Xen/memory.h> #include <IndustryStandard/Xen/memory.h>
STATIC VOID *HyperPage;
//
// Interface exposed by the ASM implementation of the core hypercall
//
INTN
EFIAPI
__XenHypercall2 (
IN VOID *HypercallAddr,
IN OUT INTN Arg1,
IN OUT INTN Arg2
);
EFI_STATUS EFI_STATUS
XenHyperpageInit ( XenHyperpageInit (
IN OUT XENBUS_DEVICE *Dev
) )
{ {
EFI_HOB_GUID_TYPE *GuidHob; EFI_HOB_GUID_TYPE *GuidHob;
@ -36,24 +48,21 @@ XenHyperpageInit (
return EFI_NOT_FOUND; return EFI_NOT_FOUND;
} }
XenInfo = (EFI_XEN_INFO *) GET_GUID_HOB_DATA (GuidHob); XenInfo = (EFI_XEN_INFO *) GET_GUID_HOB_DATA (GuidHob);
Dev->Hyperpage = XenInfo->HyperPages; HyperPage = XenInfo->HyperPages;
return EFI_SUCCESS; return EFI_SUCCESS;
} }
UINT64 UINT64
XenHypercallHvmGetParam ( XenHypercallHvmGetParam (
IN XENBUS_DEVICE *Dev,
IN UINT32 Index IN UINT32 Index
) )
{ {
xen_hvm_param_t Parameter; xen_hvm_param_t Parameter;
INTN Error; INTN Error;
ASSERT (Dev->Hyperpage != NULL);
Parameter.domid = DOMID_SELF; Parameter.domid = DOMID_SELF;
Parameter.index = Index; Parameter.index = Index;
Error = XenHypercall2 ((UINT8*)Dev->Hyperpage + __HYPERVISOR_hvm_op * 32, Error = XenHypercall2 (__HYPERVISOR_hvm_op,
HVMOP_get_param, (INTN) &Parameter); HVMOP_get_param, (INTN) &Parameter);
if (Error != 0) { if (Error != 0) {
DEBUG ((EFI_D_ERROR, DEBUG ((EFI_D_ERROR,
@ -66,53 +75,33 @@ XenHypercallHvmGetParam (
INTN INTN
XenHypercallMemoryOp ( XenHypercallMemoryOp (
IN XENBUS_DEVICE *Dev,
IN UINTN Operation, IN UINTN Operation,
IN OUT VOID *Arguments IN OUT VOID *Arguments
) )
{ {
ASSERT (Dev->Hyperpage != NULL); return XenHypercall2 (__HYPERVISOR_memory_op,
return XenHypercall2 ((UINT8*)Dev->Hyperpage + __HYPERVISOR_memory_op * 32,
Operation, (INTN) Arguments); Operation, (INTN) Arguments);
} }
INTN INTN
XenHypercallEventChannelOp ( XenHypercallEventChannelOp (
IN XENBUS_DEVICE *Dev,
IN INTN Operation, IN INTN Operation,
IN OUT VOID *Arguments IN OUT VOID *Arguments
) )
{ {
ASSERT (Dev->Hyperpage != NULL); return XenHypercall2 (__HYPERVISOR_event_channel_op,
return XenHypercall2 ((UINT8*)Dev->Hyperpage + __HYPERVISOR_event_channel_op * 32,
Operation, (INTN) Arguments); Operation, (INTN) Arguments);
} }
EFI_STATUS INTN
XenGetSharedInfoPage ( EFIAPI
IN OUT XENBUS_DEVICE *Dev XenHypercall2 (
IN UINTN HypercallID,
IN OUT INTN Arg1,
IN OUT INTN Arg2
) )
{ {
xen_add_to_physmap_t Parameter; ASSERT (HyperPage != NULL);
ASSERT (Dev->SharedInfo == NULL); return __XenHypercall2 ((UINT8*)HyperPage + HypercallID * 32, Arg1, Arg2);
Parameter.domid = DOMID_SELF;
Parameter.space = XENMAPSPACE_shared_info;
Parameter.idx = 0;
//
// using reserved page because the page is not released when Linux is
// starting because of the add_to_physmap. QEMU might try to access the
// page, and fail because it have no right to do so (segv).
//
Dev->SharedInfo = AllocateReservedPages (1);
Parameter.gpfn = (UINTN) Dev->SharedInfo >> EFI_PAGE_SHIFT;
if (XenHypercallMemoryOp (Dev, XENMEM_add_to_physmap, &Parameter) != 0) {
FreePages (Dev->SharedInfo, 1);
Dev->SharedInfo = NULL;
return EFI_LOAD_ERROR;
}
return EFI_SUCCESS;
} }

View File

@ -18,9 +18,9 @@
/** /**
This function will put the two arguments in the right place (registers) and This function will put the two arguments in the right place (registers) and
call HypercallAddr, which correspond to an entry in the hypercall pages. invoke the hypercall identified by HypercallID.
@param HypercallAddr A memory address where the hypercall to call is. @param HypercallID The symbolic ID of the hypercall to be invoked
@param Arg1 First argument. @param Arg1 First argument.
@param Arg2 Second argument. @param Arg2 Second argument.
@ -29,7 +29,7 @@
INTN INTN
EFIAPI EFIAPI
XenHypercall2 ( XenHypercall2 (
IN VOID *HypercallAddr, IN INTN HypercallID,
IN OUT INTN Arg1, IN OUT INTN Arg1,
IN OUT INTN Arg2 IN OUT INTN Arg2
); );
@ -44,27 +44,23 @@ XenHypercall2 (
**/ **/
EFI_STATUS EFI_STATUS
XenHyperpageInit ( XenHyperpageInit (
XENBUS_DEVICE *Dev
); );
/** /**
Return the value of the HVM parameter Index. Return the value of the HVM parameter Index.
@param Dev A XENBUS_DEVICE instance.
@param Index The parameter to get, e.g. HVM_PARAM_STORE_EVTCHN. @param Index The parameter to get, e.g. HVM_PARAM_STORE_EVTCHN.
@return The value of the asked parameter or 0 in case of error. @return The value of the asked parameter or 0 in case of error.
**/ **/
UINT64 UINT64
XenHypercallHvmGetParam ( XenHypercallHvmGetParam (
XENBUS_DEVICE *Dev,
UINT32 Index UINT32 Index
); );
/** /**
Hypercall to do different operation on the memory. Hypercall to do different operation on the memory.
@param Dev A XENBUS_DEVICE instance.
@param Operation The operation number, e.g. XENMEM_add_to_physmap. @param Operation The operation number, e.g. XENMEM_add_to_physmap.
@param Arguments The arguments associated to the operation. @param Arguments The arguments associated to the operation.
@ -73,7 +69,6 @@ XenHypercallHvmGetParam (
**/ **/
INTN INTN
XenHypercallMemoryOp ( XenHypercallMemoryOp (
IN XENBUS_DEVICE *Dev,
IN UINTN Operation, IN UINTN Operation,
IN OUT VOID *Arguments IN OUT VOID *Arguments
); );
@ -81,7 +76,6 @@ XenHypercallMemoryOp (
/** /**
Do an operation on the event channels. Do an operation on the event channels.
@param Dev A XENBUS_DEVICE instance.
@param Operation The operation number, e.g. EVTCHNOP_send. @param Operation The operation number, e.g. EVTCHNOP_send.
@param Arguments The argument associated to the operation. @param Arguments The argument associated to the operation.
@ -90,24 +84,8 @@ XenHypercallMemoryOp (
**/ **/
INTN INTN
XenHypercallEventChannelOp ( XenHypercallEventChannelOp (
IN XENBUS_DEVICE *Dev,
IN INTN Operation, IN INTN Operation,
IN OUT VOID *Arguments IN OUT VOID *Arguments
); );
/**
Map the shared_info_t page into memory.
@param Dev A XENBUS_DEVICE instance.
@retval EFI_SUCCESS Dev->SharedInfo whill contain a pointer to
the shared info page
@retval EFI_LOAD_ERROR The shared info page could not be mapped. The
hypercall returned an error.
**/
EFI_STATUS
XenGetSharedInfoPage (
IN OUT XENBUS_DEVICE *Dev
);
#endif #endif

View File

@ -1057,8 +1057,8 @@ XenStoreInit (
xs.Dev = Dev; xs.Dev = Dev;
xs.EventChannel = (evtchn_port_t)XenHypercallHvmGetParam (Dev, HVM_PARAM_STORE_EVTCHN); xs.EventChannel = (evtchn_port_t)XenHypercallHvmGetParam (HVM_PARAM_STORE_EVTCHN);
XenStoreGpfn = (UINTN)XenHypercallHvmGetParam (Dev, HVM_PARAM_STORE_PFN); XenStoreGpfn = (UINTN)XenHypercallHvmGetParam (HVM_PARAM_STORE_PFN);
xs.XenStore = (VOID *) (XenStoreGpfn << EFI_PAGE_SHIFT); xs.XenStore = (VOID *) (XenStoreGpfn << EFI_PAGE_SHIFT);
DEBUG ((EFI_D_INFO, "XenBusInit: XenBus rings @%p, event channel %x\n", DEBUG ((EFI_D_INFO, "XenBusInit: XenBus rings @%p, event channel %x\n",
xs.XenStore, xs.EventChannel)); xs.XenStore, xs.EventChannel));