[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index] [Xen-devel] [PATCH v3 05/19] OvmfPkg/XenBusDxe: Add support to make Xen Hypercalls.
Contributed-under: TianoCore Contribution Agreement 1.0 Signed-off-by: Anthony PERARD <anthony.perard@xxxxxxxxxx> Reviewed-by: Konrad Rzeszutek Wilk <konrad.wilk@xxxxxxxxxx> --- CC: Konrad Rzeszutek Wilk <konrad.wilk@xxxxxxxxxx> Change in V3: - adding IA32 support. (not reviewed yet) both XenBusDxe/Ia32/hypercall.{S,asm} file are new Change in V2: - file header, copyright - Add License - Add push/pop instruction. - fix types - Comment of exported functions - Improve coding style - Add error handling in the main init function (of the drivers) - Comment assembly --- OvmfPkg/XenBusDxe/Ia32/hypercall.S | 22 ++++++ OvmfPkg/XenBusDxe/Ia32/hypercall.asm | 26 +++++++ OvmfPkg/XenBusDxe/X64/hypercall.S | 22 ++++++ OvmfPkg/XenBusDxe/X64/hypercall.asm | 26 +++++++ OvmfPkg/XenBusDxe/XenBusDxe.c | 18 +++++ OvmfPkg/XenBusDxe/XenBusDxe.h | 5 ++ OvmfPkg/XenBusDxe/XenBusDxe.inf | 10 +++ OvmfPkg/XenBusDxe/XenHypercall.c | 134 +++++++++++++++++++++++++++++++++++ OvmfPkg/XenBusDxe/XenHypercall.h | 100 ++++++++++++++++++++++++++ 9 files changed, 363 insertions(+) create mode 100644 OvmfPkg/XenBusDxe/Ia32/hypercall.S create mode 100644 OvmfPkg/XenBusDxe/Ia32/hypercall.asm create mode 100644 OvmfPkg/XenBusDxe/X64/hypercall.S create mode 100644 OvmfPkg/XenBusDxe/X64/hypercall.asm create mode 100644 OvmfPkg/XenBusDxe/XenHypercall.c create mode 100644 OvmfPkg/XenBusDxe/XenHypercall.h diff --git a/OvmfPkg/XenBusDxe/Ia32/hypercall.S b/OvmfPkg/XenBusDxe/Ia32/hypercall.S new file mode 100644 index 0000000..d2b4167 --- /dev/null +++ b/OvmfPkg/XenBusDxe/Ia32/hypercall.S @@ -0,0 +1,22 @@ +# INTN +# EFIAPI +# XenHypercall2 ( +# IN VOID *HypercallAddr, +# IN OUT INTN Arg1, +# IN OUT INTN Arg2 +# ); +ASM_GLOBAL ASM_PFX(XenHypercall2) +ASM_PFX(XenHypercall2): + # Save only ebx, ecx is supposed to be a scratch register and needs to be + # saved by the caller + push %ebx + # Copy HypercallAddr to eax + mov 8(%esp), %eax + # Copy Arg1 to the register expected by Xen + mov 12(%esp), %ebx + # Copy Arg2 to the register expected by Xen + mov 16(%esp), %ecx + # Call HypercallAddr + call *%eax + pop %ebx + ret diff --git a/OvmfPkg/XenBusDxe/Ia32/hypercall.asm b/OvmfPkg/XenBusDxe/Ia32/hypercall.asm new file mode 100644 index 0000000..0fff9a2 --- /dev/null +++ b/OvmfPkg/XenBusDxe/Ia32/hypercall.asm @@ -0,0 +1,26 @@ +.code + +; INTN +; EFIAPI +; XenHypercall2 ( +; IN VOID *HypercallAddr, +; IN OUT INTN Arg1, +; IN OUT INTN Arg2 +; ); +XenHypercall2 PROC + ; Save only ebx, ecx is supposed to be a scratch register and needs to be + ; saved by the caller + push ebx + ; Copy HypercallAddr to eax + mov eax, [esp + 8] + ; Copy Arg1 to the register expected by Xen + mov ebx, [esp + 12] + ; Copy Arg2 to the register expected by Xen + mov ecx, [esp + 16] + ; Call HypercallAddr + call eax + pop ebx + ret +XenHypercall2 ENDP + +END diff --git a/OvmfPkg/XenBusDxe/X64/hypercall.S b/OvmfPkg/XenBusDxe/X64/hypercall.S new file mode 100644 index 0000000..a167917 --- /dev/null +++ b/OvmfPkg/XenBusDxe/X64/hypercall.S @@ -0,0 +1,22 @@ +# INTN +# EFIAPI +# XenHypercall2 ( +# IN VOID *HypercallAddr, +# IN OUT INTN Arg1, +# IN OUT INTN Arg2 +# ); +ASM_GLOBAL ASM_PFX(XenHypercall2) +ASM_PFX(XenHypercall2): + push %rdi + push %rsi + # Copy HypercallAddr to rax + movq %rcx, %rax + # Copy Arg1 to the register expected by Xen + movq %rdx, %rdi + # Copy Arg2 to the register expected by Xen + movq %r8, %rsi + # Call HypercallAddr + call *%rax + pop %rsi + pop %rdi + ret diff --git a/OvmfPkg/XenBusDxe/X64/hypercall.asm b/OvmfPkg/XenBusDxe/X64/hypercall.asm new file mode 100644 index 0000000..c11c3e5 --- /dev/null +++ b/OvmfPkg/XenBusDxe/X64/hypercall.asm @@ -0,0 +1,26 @@ +.code + +; INTN +; EFIAPI +; XenHypercall2 ( +; IN VOID *HypercallAddr, +; IN OUT INTN Arg1, +; IN OUT INTN Arg2 +; ); +XenHypercall2 PROC + push rdi + push rsi + ; Copy HypercallAddr to rax + mov rax, rcx + ; Copy Arg1 to the register expected by Xen + mov rdi, rdx + ; Copy Arg2 to the register expected by Xen + mov rsi, r8 + ; Call HypercallAddr + call rax + pop rsi + pop rdi + ret +XenHypercall2 ENDP + +END diff --git a/OvmfPkg/XenBusDxe/XenBusDxe.c b/OvmfPkg/XenBusDxe/XenBusDxe.c index 8a04c8e..d764365 100644 --- a/OvmfPkg/XenBusDxe/XenBusDxe.c +++ b/OvmfPkg/XenBusDxe/XenBusDxe.c @@ -45,6 +45,8 @@ #include "XenBusDxe.h" +#include "XenHypercall.h" + /// /// Driver Binding Protocol instance @@ -280,6 +282,8 @@ NotifyExitBoot ( @retval EFI_SUCCESS The device was started. @retval EFI_DEVICE_ERROR The device could not be started due to a device error.Currently not implemented. @retval EFI_OUT_OF_RESOURCES The request could not be completed due to a lack of resources. + @retval EFI_UNSUPPORTED Something is missing on the system that + prevent to start the edvice. @retval Others The driver failded to start the device. **/ @@ -311,6 +315,20 @@ XenBusDxeDriverBindingStart ( mMyDevice = Dev; EfiReleaseLock (&mMyDeviceLock); + Status = XenHyperpageInit (Dev); + if (EFI_ERROR (Status)) { + DEBUG ((EFI_D_ERROR, "XenBus: Unable to retrieve the hyperpage.\n")); + Status = EFI_UNSUPPORTED; + goto ErrorAllocated; + } + + Status = XenGetSharedInfoPage (Dev); + if (EFI_ERROR (Status)) { + DEBUG ((EFI_D_ERROR, "XenBus: Unable to get the shared info page.\n")); + Status = EFI_UNSUPPORTED; + goto ErrorAllocated; + } + Status = gBS->CreateEvent (EVT_SIGNAL_EXIT_BOOT_SERVICES, TPL_CALLBACK, NotifyExitBoot, (VOID*) Dev, diff --git a/OvmfPkg/XenBusDxe/XenBusDxe.h b/OvmfPkg/XenBusDxe/XenBusDxe.h index 8d7fe89..0b27699 100644 --- a/OvmfPkg/XenBusDxe/XenBusDxe.h +++ b/OvmfPkg/XenBusDxe/XenBusDxe.h @@ -86,6 +86,8 @@ extern EFI_COMPONENT_NAME_PROTOCOL gXenBusDxeComponentName; // // Other stuff // +#include <IndustryStandard/Xen/xen.h> + #define PCI_VENDOR_ID_XEN 0x5853 #define PCI_DEVICE_ID_XEN_PLATFORM 0x0001 @@ -99,6 +101,9 @@ struct _XENBUS_DEVICE { EFI_DRIVER_BINDING_PROTOCOL *This; EFI_HANDLE ControllerHandle; EFI_EVENT ExitBootEvent; + + VOID *Hyperpage; + shared_info_t *SharedInfo; }; #endif diff --git a/OvmfPkg/XenBusDxe/XenBusDxe.inf b/OvmfPkg/XenBusDxe/XenBusDxe.inf index 25fd2f6..b824d63 100644 --- a/OvmfPkg/XenBusDxe/XenBusDxe.inf +++ b/OvmfPkg/XenBusDxe/XenBusDxe.inf @@ -31,6 +31,16 @@ DriverBinding.h ComponentName.c ComponentName.h + XenHypercall.c + XenHypercall.h + +[Sources.IA32] + Ia32/hypercall.S + Ia32/hypercall.asm + +[Sources.X64] + X64/hypercall.S + X64/hypercall.asm [LibraryClasses] UefiDriverEntryPoint diff --git a/OvmfPkg/XenBusDxe/XenHypercall.c b/OvmfPkg/XenBusDxe/XenHypercall.c new file mode 100644 index 0000000..1b4dc14 --- /dev/null +++ b/OvmfPkg/XenBusDxe/XenHypercall.c @@ -0,0 +1,134 @@ +/** @file + Functions to make Xen hypercalls. + + Copyright (C) 2014, Citrix Ltd. + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions + are met: + + * Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in + the documentation and/or other materials provided with the + distribution. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN + ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + POSSIBILITY OF SUCH DAMAGE. + +**/ + +#include <PiDxe.h> +#include <Library/HobLib.h> +#include <Guid/XenInfo.h> + +#include "XenBusDxe.h" +#include "XenHypercall.h" + +#include <IndustryStandard/Xen/hvm/params.h> +#include <IndustryStandard/Xen/memory.h> + +EFI_STATUS +XenHyperpageInit ( + IN OUT XENBUS_DEVICE *Dev + ) +{ + EFI_HOB_GUID_TYPE *GuidHob; + EFI_XEN_INFO *XenInfo; + + GuidHob = GetFirstGuidHob (&gEfiXenInfoGuid); + if (GuidHob == NULL) { + return EFI_NOT_FOUND; + } + XenInfo = (EFI_XEN_INFO *) GET_GUID_HOB_DATA (GuidHob); + Dev->Hyperpage = XenInfo->HyperPages; + return EFI_SUCCESS; +} + +UINT64 +XenHypercallHvmGetParam ( + IN XENBUS_DEVICE *Dev, + IN INTN Index + ) +{ + xen_hvm_param_t Parameter; + INTN Error; + + ASSERT (Dev->Hyperpage != NULL); + + Parameter.domid = DOMID_SELF; + Parameter.index = Index; + Error = XenHypercall2 (Dev->Hyperpage + __HYPERVISOR_hvm_op * 32, + HVMOP_get_param, (INTN) &Parameter); + if (Error != 0) { + DEBUG ((EFI_D_ERROR, + "XenHypercall: Error %d trying to get HVM parameter %d\n", + Error, Index)); + return 0; + } + return Parameter.value; +} + +INTN +XenHypercallMemoryOp ( + IN XENBUS_DEVICE *Dev, + IN UINTN Operation, + IN OUT VOID *Arguments + ) +{ + ASSERT (Dev->Hyperpage != NULL); + return XenHypercall2 (Dev->Hyperpage + __HYPERVISOR_memory_op * 32, + Operation, (INTN) Arguments); +} + +INTN +XenHypercallEventChannelOp ( + IN XENBUS_DEVICE *Dev, + IN INTN Operation, + IN OUT VOID *Arguments + ) +{ + ASSERT (Dev->Hyperpage != NULL); + return XenHypercall2 (Dev->Hyperpage + __HYPERVISOR_event_channel_op * 32, + Operation, (INTN) Arguments); +} + +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 (Dev, XENMEM_add_to_physmap, &Parameter) != 0) { + FreePages (Dev->SharedInfo, 1); + Dev->SharedInfo = NULL; + return EFI_LOAD_ERROR; + } + + return EFI_SUCCESS; +} diff --git a/OvmfPkg/XenBusDxe/XenHypercall.h b/OvmfPkg/XenBusDxe/XenHypercall.h new file mode 100644 index 0000000..29eaf9f --- /dev/null +++ b/OvmfPkg/XenBusDxe/XenHypercall.h @@ -0,0 +1,100 @@ +#ifndef __XENBUS_DXE_HYPERCALL_H__ +#define __XENBUS_DXE_HYPERCALL_H__ + +typedef struct _XENBUS_DEVICE XENBUS_DEVICE; + +/** + This function will put the two arguments in the right place (registers) and + call HypercallAddr, which correspond to an entry in the hypercall pages. + + @param HypercallAddr A memory address where the hypercall to call is. + @param Arg1 First argument. + @param Arg2 Second argument. + + @return Return 0 if success otherwise it return an errno. +**/ +INTN +EFIAPI +XenHypercall2 ( + IN VOID *HypercallAddr, + IN OUT INTN Arg1, + IN OUT INTN Arg2 + ); + +/** + Get the page where all hypercall are from the XenInfo hob. + + @param Dev A XENBUS_DEVICE instance. + + @retval EFI_NOT_FOUND hyperpage could not be found. + @retval EFI_SUCCESS Successfully retrieve the hyperpage pointer. +**/ +EFI_STATUS +XenHyperpageInit ( + XENBUS_DEVICE *Dev + ); + +/** + 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. + + @return The value of the asked parameter or 0 in case of error. +**/ +UINT64 +XenHypercallHvmGetParam ( + XENBUS_DEVICE *Dev, + INTN Index + ); + +/** + 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 Arguments The arguments associated to the operation. + + @return Return the return value from the hypercall, 0 in case of success + otherwise, an error code. +**/ +INTN +XenHypercallMemoryOp ( + IN XENBUS_DEVICE *Dev, + IN UINTN Operation, + IN OUT VOID *Arguments + ); + +/** + Do an operation on the event channels. + + @param Dev A XENBUS_DEVICE instance. + @param Operation The operation number, e.g. EVTCHNOP_send. + @param Arguments The argument associated to the operation. + + @return Return the return value from the hypercall, 0 in case of success + otherwise, an error code. +**/ +INTN +XenHypercallEventChannelOp ( + IN XENBUS_DEVICE *Dev, + IN INTN Operation, + 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 -- Anthony PERARD _______________________________________________ Xen-devel mailing list Xen-devel@xxxxxxxxxxxxx http://lists.xen.org/xen-devel
|
Lists.xenproject.org is hosted with RackSpace, monitoring our |