[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

[Xen-devel] [PATCH v4 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>

---
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
---
 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     | 118 +++++++++++++++++++++++++++++++++++
 OvmfPkg/XenBusDxe/XenHypercall.h     | 115 ++++++++++++++++++++++++++++++++++
 9 files changed, 362 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 f3c74e1..4c638b8 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 d7537f3..ccec0ce 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 fb63ec2..6da3d2d 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 0000000..6335fb7
--- /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 0000000..203b8f0
--- /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
-- 
Anthony PERARD


_______________________________________________
Xen-devel mailing list
Xen-devel@xxxxxxxxxxxxx
http://lists.xen.org/xen-devel


 


Rackspace

Lists.xenproject.org is hosted with RackSpace, monitoring our
servers 24x7x365 and backed by RackSpace's Fanatical Support®.