summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorAnthony PERARD <anthony.perard@citrix.com>2014-10-29 06:49:10 +0000
committerjljusten <jljusten@Edk2>2014-10-29 06:49:10 +0000
commitabcbbb14a44a83b4cdf90137307a62e7b58e6720 (patch)
tree233c7beab4c4edcc10b0936cd8ef56e3accde136
parenta154f420147b0a3f449bb52da1e76dabef3478a5 (diff)
downloadedk2-abcbbb14a44a83b4cdf90137307a62e7b58e6720.tar.gz
edk2-abcbbb14a44a83b4cdf90137307a62e7b58e6720.tar.bz2
edk2-abcbbb14a44a83b4cdf90137307a62e7b58e6720.zip
OvmfPkg/XenBusDxe: Add support to make Xen Hypercalls.
Change in V4: - Replace the license by the commonly used file header text. - add file header to XenHypercall.h (license, copyright, brief desc) 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 Contributed-under: TianoCore Contribution Agreement 1.0 Signed-off-by: Anthony PERARD <anthony.perard@citrix.com> Reviewed-by: Konrad Rzeszutek Wilk <konrad.wilk@oracle.com> Reviewed-by: Jordan Justen <jordan.l.justen@intel.com> git-svn-id: https://svn.code.sf.net/p/edk2/code/trunk/edk2@16260 6f19259b-4bc3-4df7-8a09-765794883524
-rw-r--r--OvmfPkg/XenBusDxe/Ia32/hypercall.S22
-rw-r--r--OvmfPkg/XenBusDxe/Ia32/hypercall.asm26
-rw-r--r--OvmfPkg/XenBusDxe/X64/hypercall.S22
-rw-r--r--OvmfPkg/XenBusDxe/X64/hypercall.asm26
-rw-r--r--OvmfPkg/XenBusDxe/XenBusDxe.c18
-rw-r--r--OvmfPkg/XenBusDxe/XenBusDxe.h5
-rw-r--r--OvmfPkg/XenBusDxe/XenBusDxe.inf10
-rw-r--r--OvmfPkg/XenBusDxe/XenHypercall.c118
-rw-r--r--OvmfPkg/XenBusDxe/XenHypercall.h115
9 files changed, 362 insertions, 0 deletions
diff --git a/OvmfPkg/XenBusDxe/Ia32/hypercall.S b/OvmfPkg/XenBusDxe/Ia32/hypercall.S
new file mode 100644
index 0000000000..77d3478475
--- /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 0000000000..9ead740f91
--- /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 0000000000..83cf466953
--- /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 0000000000..5b3451473d
--- /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 f3c74e1fbe..4c638b85f1 100644
--- a/OvmfPkg/XenBusDxe/XenBusDxe.c
+++ b/OvmfPkg/XenBusDxe/XenBusDxe.c
@@ -29,6 +29,8 @@
#include "XenBusDxe.h"
+#include "XenHypercall.h"
+
///
/// Driver Binding Protocol instance
@@ -264,6 +266,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.
**/
@@ -295,6 +299,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 d7537f3fe5..ccec0ce0e5 100644
--- a/OvmfPkg/XenBusDxe/XenBusDxe.h
+++ b/OvmfPkg/XenBusDxe/XenBusDxe.h
@@ -70,6 +70,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
@@ -83,6 +85,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 fb63ec251e..6da3d2d670 100644
--- a/OvmfPkg/XenBusDxe/XenBusDxe.inf
+++ b/OvmfPkg/XenBusDxe/XenBusDxe.inf
@@ -34,6 +34,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 0000000000..0f2ba5d693
--- /dev/null
+++ b/OvmfPkg/XenBusDxe/XenHypercall.c
@@ -0,0 +1,118 @@
+/** @file
+ Functions to make Xen hypercalls.
+
+ Copyright (C) 2014, Citrix Ltd.
+
+ This program and the accompanying materials
+ are licensed and made available under the terms and conditions of the BSD License
+ which accompanies this distribution. The full text of the license may be found at
+ http://opensource.org/licenses/bsd-license.php
+
+ THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+ WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+
+**/
+
+#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 0000000000..3627b1886c
--- /dev/null
+++ b/OvmfPkg/XenBusDxe/XenHypercall.h
@@ -0,0 +1,115 @@
+/** @file
+ Functions declarations to make Xen hypercalls.
+
+ Copyright (C) 2014, Citrix Ltd.
+
+ This program and the accompanying materials
+ are licensed and made available under the terms and conditions of the BSD License
+ which accompanies this distribution. The full text of the license may be found at
+ http://opensource.org/licenses/bsd-license.php
+
+ THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+ WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+
+**/
+
+#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