diff options
author | Angelos Mouzakitis <a.mouzakitis@virtualopensystems.com> | 2023-10-10 14:33:42 +0000 |
---|---|---|
committer | Angelos Mouzakitis <a.mouzakitis@virtualopensystems.com> | 2023-10-10 14:33:42 +0000 |
commit | af1a266670d040d2f4083ff309d732d648afba2a (patch) | |
tree | 2fc46203448ddcc6f81546d379abfaeb323575e9 /roms/edk2/OvmfPkg/XenBusDxe | |
parent | e02cda008591317b1625707ff8e115a4841aa889 (diff) |
Change-Id: Iaf8d18082d3991dec7c0ebbea540f092188eb4ec
Diffstat (limited to 'roms/edk2/OvmfPkg/XenBusDxe')
-rw-r--r-- | roms/edk2/OvmfPkg/XenBusDxe/ComponentName.c | 168 | ||||
-rw-r--r-- | roms/edk2/OvmfPkg/XenBusDxe/ComponentName.h | 88 | ||||
-rw-r--r-- | roms/edk2/OvmfPkg/XenBusDxe/DriverBinding.h | 122 | ||||
-rw-r--r-- | roms/edk2/OvmfPkg/XenBusDxe/EventChannel.c | 78 | ||||
-rw-r--r-- | roms/edk2/OvmfPkg/XenBusDxe/EventChannel.h | 82 | ||||
-rw-r--r-- | roms/edk2/OvmfPkg/XenBusDxe/GrantTable.c | 201 | ||||
-rw-r--r-- | roms/edk2/OvmfPkg/XenBusDxe/GrantTable.h | 70 | ||||
-rw-r--r-- | roms/edk2/OvmfPkg/XenBusDxe/Helpers.c | 9 | ||||
-rw-r--r-- | roms/edk2/OvmfPkg/XenBusDxe/TestAndClearBit.c | 40 | ||||
-rw-r--r-- | roms/edk2/OvmfPkg/XenBusDxe/XenBus.c | 370 | ||||
-rw-r--r-- | roms/edk2/OvmfPkg/XenBusDxe/XenBus.h | 38 | ||||
-rw-r--r-- | roms/edk2/OvmfPkg/XenBusDxe/XenBusDxe.c | 484 | ||||
-rw-r--r-- | roms/edk2/OvmfPkg/XenBusDxe/XenBusDxe.h | 128 | ||||
-rw-r--r-- | roms/edk2/OvmfPkg/XenBusDxe/XenBusDxe.inf | 64 | ||||
-rw-r--r-- | roms/edk2/OvmfPkg/XenBusDxe/XenStore.c | 1538 | ||||
-rw-r--r-- | roms/edk2/OvmfPkg/XenBusDxe/XenStore.h | 364 |
16 files changed, 3844 insertions, 0 deletions
diff --git a/roms/edk2/OvmfPkg/XenBusDxe/ComponentName.c b/roms/edk2/OvmfPkg/XenBusDxe/ComponentName.c new file mode 100644 index 000000000..83e7628a2 --- /dev/null +++ b/roms/edk2/OvmfPkg/XenBusDxe/ComponentName.c @@ -0,0 +1,168 @@ +/** @file
+ Component Name functions implementation for XenBus Bus driver.
+
+ Copyright (C) 2014, Citrix Ltd.
+
+ SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#include "XenBusDxe.h"
+
+///
+/// Component Name Protocol instance
+///
+GLOBAL_REMOVE_IF_UNREFERENCED
+EFI_COMPONENT_NAME_PROTOCOL gXenBusDxeComponentName = {
+ (EFI_COMPONENT_NAME_GET_DRIVER_NAME) XenBusDxeComponentNameGetDriverName,
+ (EFI_COMPONENT_NAME_GET_CONTROLLER_NAME)XenBusDxeComponentNameGetControllerName,
+ "eng"
+};
+
+///
+/// Component Name 2 Protocol instance
+///
+GLOBAL_REMOVE_IF_UNREFERENCED
+EFI_COMPONENT_NAME2_PROTOCOL gXenBusDxeComponentName2 = {
+ XenBusDxeComponentNameGetDriverName,
+ XenBusDxeComponentNameGetControllerName,
+ "en"
+};
+
+///
+/// Table of driver names
+///
+GLOBAL_REMOVE_IF_UNREFERENCED
+EFI_UNICODE_STRING_TABLE mXenBusDxeDriverNameTable[] = {
+ { "eng;en", (CHAR16 *)L"XenBus Bus Driver" },
+ { NULL, NULL }
+};
+
+///
+/// Table of controller names
+///
+GLOBAL_REMOVE_IF_UNREFERENCED
+EFI_UNICODE_STRING_TABLE mXenBusDxeControllerNameTable[] = {
+ { "eng;en", (CHAR16 *)L"XenBus Controller" },
+ { NULL, NULL }
+};
+
+/**
+ Retrieves a Unicode string that is the user-readable name of the EFI Driver.
+
+ @param This A pointer to the EFI_COMPONENT_NAME_PROTOCOL instance.
+ @param Language A pointer to a three-character ISO 639-2 language identifier.
+ This is the language of the driver name that that the caller
+ is requesting, and it must match one of the languages specified
+ in SupportedLanguages. The number of languages supported by a
+ driver is up to the driver writer.
+ @param DriverName A pointer to the Unicode string to return. This Unicode string
+ is the name of the driver specified by This in the language
+ specified by Language.
+
+ @retval EFI_SUCCESS The Unicode string for the Driver specified by This
+ and the language specified by Language was returned
+ in DriverName.
+ @retval EFI_INVALID_PARAMETER Language is NULL.
+ @retval EFI_INVALID_PARAMETER DriverName is NULL.
+ @retval EFI_UNSUPPORTED The driver specified by This does not support the
+ language specified by Language.
+
+**/
+EFI_STATUS
+EFIAPI
+XenBusDxeComponentNameGetDriverName (
+ IN EFI_COMPONENT_NAME2_PROTOCOL *This,
+ IN CHAR8 *Language,
+ OUT CHAR16 **DriverName
+ )
+{
+ return LookupUnicodeString2 (
+ Language,
+ This->SupportedLanguages,
+ mXenBusDxeDriverNameTable,
+ DriverName,
+ (BOOLEAN)(This != &gXenBusDxeComponentName2)
+ );
+}
+
+/**
+ Retrieves a Unicode string that is the user readable name of the controller
+ that is being managed by an EFI Driver.
+
+ @param This A pointer to the EFI_COMPONENT_NAME_PROTOCOL instance.
+ @param ControllerHandle The handle of a controller that the driver specified by
+ This is managing. This handle specifies the controller
+ whose name is to be returned.
+ @param ChildHandle The handle of the child controller to retrieve the name
+ of. This is an optional parameter that may be NULL. It
+ will be NULL for device drivers. It will also be NULL
+ for a bus drivers that wish to retrieve the name of the
+ bus controller. It will not be NULL for a bus driver
+ that wishes to retrieve the name of a child controller.
+ @param Language A pointer to a three character ISO 639-2 language
+ identifier. This is the language of the controller name
+ that the caller is requesting, and it must match one
+ of the languages specified in SupportedLanguages. The
+ number of languages supported by a driver is up to the
+ driver writer.
+ @param ControllerName A pointer to the Unicode string to return. This Unicode
+ string is the name of the controller specified by
+ ControllerHandle and ChildHandle in the language specified
+ by Language, from the point of view of the driver specified
+ by This.
+
+ @retval EFI_SUCCESS The Unicode string for the user-readable name in the
+ language specified by Language for the driver
+ specified by This was returned in DriverName.
+ @retval EFI_INVALID_PARAMETER ControllerHandle is NULL.
+ @retval EFI_INVALID_PARAMETER ChildHandle is not NULL and it is not a valid EFI_HANDLE.
+ @retval EFI_INVALID_PARAMETER Language is NULL.
+ @retval EFI_INVALID_PARAMETER ControllerName is NULL.
+ @retval EFI_UNSUPPORTED The driver specified by This is not currently managing
+ the controller specified by ControllerHandle and
+ ChildHandle.
+ @retval EFI_UNSUPPORTED The driver specified by This does not support the
+ language specified by Language.
+
+**/
+EFI_STATUS
+EFIAPI
+XenBusDxeComponentNameGetControllerName (
+ IN EFI_COMPONENT_NAME2_PROTOCOL *This,
+ IN EFI_HANDLE ControllerHandle,
+ IN EFI_HANDLE ChildHandle OPTIONAL,
+ IN CHAR8 *Language,
+ OUT CHAR16 **ControllerName
+ )
+{
+ EFI_STATUS Status;
+
+ if (ChildHandle != NULL) {
+ // TODO Get controller name for a child.
+ return EFI_UNSUPPORTED;
+ }
+
+ //
+ // Make sure this driver is currently managing ControllerHandle
+ //
+ Status = EfiTestManagedDevice (
+ ControllerHandle,
+ gXenBusDxeDriverBinding.DriverBindingHandle,
+ &gXenIoProtocolGuid
+ );
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ //
+ // Lookup name of controller specified by ControllerHandle
+ //
+ return LookupUnicodeString2 (
+ Language,
+ This->SupportedLanguages,
+ mXenBusDxeControllerNameTable,
+ ControllerName,
+ (BOOLEAN)(This != &gXenBusDxeComponentName2)
+ );
+}
diff --git a/roms/edk2/OvmfPkg/XenBusDxe/ComponentName.h b/roms/edk2/OvmfPkg/XenBusDxe/ComponentName.h new file mode 100644 index 000000000..592c5426d --- /dev/null +++ b/roms/edk2/OvmfPkg/XenBusDxe/ComponentName.h @@ -0,0 +1,88 @@ +/** @file
+ Component Name functions declaration for XenBus Bus driver.
+
+ Copyright (C) 2014, Citrix Ltd.
+
+ SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+/**
+ Retrieves a Unicode string that is the user-readable name of the EFI Driver.
+
+ @param This A pointer to the EFI_COMPONENT_NAME_PROTOCOL instance.
+ @param Language A pointer to a three-character ISO 639-2 language identifier.
+ This is the language of the driver name that that the caller
+ is requesting, and it must match one of the languages specified
+ in SupportedLanguages. The number of languages supported by a
+ driver is up to the driver writer.
+ @param DriverName A pointer to the Unicode string to return. This Unicode string
+ is the name of the driver specified by This in the language
+ specified by Language.
+
+ @retval EFI_SUCCESS The Unicode string for the Driver specified by This
+ and the language specified by Language was returned
+ in DriverName.
+ @retval EFI_INVALID_PARAMETER Language is NULL.
+ @retval EFI_INVALID_PARAMETER DriverName is NULL.
+ @retval EFI_UNSUPPORTED The driver specified by This does not support the
+ language specified by Language.
+
+**/
+EFI_STATUS
+EFIAPI
+XenBusDxeComponentNameGetDriverName (
+ IN EFI_COMPONENT_NAME2_PROTOCOL *This,
+ IN CHAR8 *Language,
+ OUT CHAR16 **DriverName
+ );
+
+/**
+ Retrieves a Unicode string that is the user readable name of the controller
+ that is being managed by an EFI Driver.
+
+ @param This A pointer to the EFI_COMPONENT_NAME_PROTOCOL instance.
+ @param ControllerHandle The handle of a controller that the driver specified by
+ This is managing. This handle specifies the controller
+ whose name is to be returned.
+ @param ChildHandle The handle of the child controller to retrieve the name
+ of. This is an optional parameter that may be NULL. It
+ will be NULL for device drivers. It will also be NULL
+ for a bus drivers that wish to retrieve the name of the
+ bus controller. It will not be NULL for a bus driver
+ that wishes to retrieve the name of a child controller.
+ @param Language A pointer to a three character ISO 639-2 language
+ identifier. This is the language of the controller name
+ that the caller is requesting, and it must match one
+ of the languages specified in SupportedLanguages. The
+ number of languages supported by a driver is up to the
+ driver writer.
+ @param ControllerName A pointer to the Unicode string to return. This Unicode
+ string is the name of the controller specified by
+ ControllerHandle and ChildHandle in the language specified
+ by Language, from the point of view of the driver specified
+ by This.
+
+ @retval EFI_SUCCESS The Unicode string for the user-readable name in the
+ language specified by Language for the driver
+ specified by This was returned in DriverName.
+ @retval EFI_INVALID_PARAMETER ControllerHandle is NULL.
+ @retval EFI_INVALID_PARAMETER ChildHandle is not NULL and it is not a valid EFI_HANDLE.
+ @retval EFI_INVALID_PARAMETER Language is NULL.
+ @retval EFI_INVALID_PARAMETER ControllerName is NULL.
+ @retval EFI_UNSUPPORTED The driver specified by This is not currently managing
+ the controller specified by ControllerHandle and
+ ChildHandle.
+ @retval EFI_UNSUPPORTED The driver specified by This does not support the
+ language specified by Language.
+
+**/
+EFI_STATUS
+EFIAPI
+XenBusDxeComponentNameGetControllerName (
+ IN EFI_COMPONENT_NAME2_PROTOCOL *This,
+ IN EFI_HANDLE ControllerHandle,
+ IN EFI_HANDLE ChildHandle OPTIONAL,
+ IN CHAR8 *Language,
+ OUT CHAR16 **ControllerName
+ );
diff --git a/roms/edk2/OvmfPkg/XenBusDxe/DriverBinding.h b/roms/edk2/OvmfPkg/XenBusDxe/DriverBinding.h new file mode 100644 index 000000000..43ee8aff0 --- /dev/null +++ b/roms/edk2/OvmfPkg/XenBusDxe/DriverBinding.h @@ -0,0 +1,122 @@ +/** @file
+ Driver Binding functions declaration for XenBus Bus driver.
+
+ Copyright (C) 2014, Citrix Ltd.
+
+ SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+/**
+ Tests to see if this driver supports a given controller. If a child device is provided,
+ it further tests to see if this driver supports creating a handle for the specified child device.
+
+ @param[in] This A pointer to the EFI_DRIVER_BINDING_PROTOCOL instance.
+ @param[in] ControllerHandle The handle of the controller to test. This handle
+ must support a protocol interface that supplies
+ an I/O abstraction to the driver.
+ @param[in] RemainingDevicePath A pointer to the remaining portion of a device path. This
+ parameter is ignored by device drivers, and is optional for bus
+ drivers. For bus drivers, if this parameter is not NULL, then
+ the bus driver must determine if the bus controller specified
+ by ControllerHandle and the child controller specified
+ by RemainingDevicePath are both supported by this
+ bus driver.
+
+ @retval EFI_SUCCESS The device specified by ControllerHandle and
+ RemainingDevicePath is supported by the driver specified by This.
+ @retval EFI_ALREADY_STARTED The device specified by ControllerHandle and
+ RemainingDevicePath is already being managed by the driver
+ specified by This.
+ @retval EFI_ACCESS_DENIED The device specified by ControllerHandle and
+ RemainingDevicePath is already being managed by a different
+ driver or an application that requires exclusive access.
+ Currently not implemented.
+ @retval EFI_UNSUPPORTED The device specified by ControllerHandle and
+ RemainingDevicePath is not supported by the driver specified by This.
+**/
+EFI_STATUS
+EFIAPI
+XenBusDxeDriverBindingSupported (
+ IN EFI_DRIVER_BINDING_PROTOCOL *This,
+ IN EFI_HANDLE ControllerHandle,
+ IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath OPTIONAL
+ );
+
+/**
+ Starts a device controller or a bus controller.
+
+ The Start() function is designed to be invoked from the EFI boot service ConnectController().
+ As a result, much of the error checking on the parameters to Start() has been moved into this
+ common boot service. It is legal to call Start() from other locations,
+ but the following calling restrictions must be followed, or the system behavior will not be deterministic.
+ 1. ControllerHandle must be a valid EFI_HANDLE.
+ 2. If RemainingDevicePath is not NULL, then it must be a pointer to a naturally aligned
+ EFI_DEVICE_PATH_PROTOCOL.
+ 3. Prior to calling Start(), the Supported() function for the driver specified by This must
+ have been called with the same calling parameters, and Supported() must have returned EFI_SUCCESS.
+
+ @param[in] This A pointer to the EFI_DRIVER_BINDING_PROTOCOL instance.
+ @param[in] ControllerHandle The handle of the controller to start. This handle
+ must support a protocol interface that supplies
+ an I/O abstraction to the driver.
+ @param[in] RemainingDevicePath A pointer to the remaining portion of a device path. This
+ parameter is ignored by device drivers, and is optional for bus
+ drivers. For a bus driver, if this parameter is NULL, then handles
+ for all the children of Controller are created by this driver.
+ If this parameter is not NULL and the first Device Path Node is
+ not the End of Device Path Node, then only the handle for the
+ child device specified by the first Device Path Node of
+ RemainingDevicePath is created by this driver.
+ If the first Device Path Node of RemainingDevicePath is
+ the End of Device Path Node, no child handle is created by this
+ driver.
+
+ @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 Others The driver failed to start the device.
+
+**/
+EFI_STATUS
+EFIAPI
+XenBusDxeDriverBindingStart (
+ IN EFI_DRIVER_BINDING_PROTOCOL *This,
+ IN EFI_HANDLE ControllerHandle,
+ IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath OPTIONAL
+ );
+
+/**
+ Stops a device controller or a bus controller.
+
+ The Stop() function is designed to be invoked from the EFI boot service DisconnectController().
+ As a result, much of the error checking on the parameters to Stop() has been moved
+ into this common boot service. It is legal to call Stop() from other locations,
+ but the following calling restrictions must be followed, or the system behavior will not be deterministic.
+ 1. ControllerHandle must be a valid EFI_HANDLE that was used on a previous call to this
+ same driver's Start() function.
+ 2. The first NumberOfChildren handles of ChildHandleBuffer must all be a valid
+ EFI_HANDLE. In addition, all of these handles must have been created in this driver's
+ Start() function, and the Start() function must have called OpenProtocol() on
+ ControllerHandle with an Attribute of EFI_OPEN_PROTOCOL_BY_CHILD_CONTROLLER.
+
+ @param[in] This A pointer to the EFI_DRIVER_BINDING_PROTOCOL instance.
+ @param[in] ControllerHandle A handle to the device being stopped. The handle must
+ support a bus specific I/O protocol for the driver
+ to use to stop the device.
+ @param[in] NumberOfChildren The number of child device handles in ChildHandleBuffer.
+ @param[in] ChildHandleBuffer An array of child handles to be freed. May be NULL
+ if NumberOfChildren is 0.
+
+ @retval EFI_SUCCESS The device was stopped.
+ @retval EFI_DEVICE_ERROR The device could not be stopped due to a device error.
+
+**/
+EFI_STATUS
+EFIAPI
+XenBusDxeDriverBindingStop (
+ IN EFI_DRIVER_BINDING_PROTOCOL *This,
+ IN EFI_HANDLE ControllerHandle,
+ IN UINTN NumberOfChildren,
+ IN EFI_HANDLE *ChildHandleBuffer OPTIONAL
+ );
diff --git a/roms/edk2/OvmfPkg/XenBusDxe/EventChannel.c b/roms/edk2/OvmfPkg/XenBusDxe/EventChannel.c new file mode 100644 index 000000000..6c905b511 --- /dev/null +++ b/roms/edk2/OvmfPkg/XenBusDxe/EventChannel.c @@ -0,0 +1,78 @@ +/** @file
+ Event Channel function implementation.
+
+ Event channel are use to notify of an event that happened in a shared
+ structure for example.
+
+ Copyright (C) 2014, Citrix Ltd.
+
+ SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+#include "EventChannel.h"
+
+#include <Library/XenHypercallLib.h>
+
+UINT32
+XenEventChannelNotify (
+ IN XENBUS_DEVICE *Dev,
+ IN evtchn_port_t Port
+ )
+{
+ INTN ReturnCode;
+ evtchn_send_t Send;
+
+ Send.port = Port;
+ ReturnCode = XenHypercallEventChannelOp (EVTCHNOP_send, &Send);
+ return (UINT32)ReturnCode;
+}
+
+UINT32
+EFIAPI
+XenBusEventChannelAllocate (
+ IN XENBUS_PROTOCOL *This,
+ IN domid_t DomainId,
+ OUT evtchn_port_t *Port
+ )
+{
+ evtchn_alloc_unbound_t Parameter;
+ UINT32 ReturnCode;
+
+ Parameter.dom = DOMID_SELF;
+ Parameter.remote_dom = DomainId;
+ ReturnCode = (UINT32)XenHypercallEventChannelOp (
+ EVTCHNOP_alloc_unbound,
+ &Parameter);
+ if (ReturnCode != 0) {
+ DEBUG ((DEBUG_ERROR, "ERROR: alloc_unbound failed with rc=%d", ReturnCode));
+ return ReturnCode;
+ }
+ *Port = Parameter.port;
+ return ReturnCode;
+}
+
+UINT32
+EFIAPI
+XenBusEventChannelNotify (
+ IN XENBUS_PROTOCOL *This,
+ IN evtchn_port_t Port
+ )
+{
+ XENBUS_PRIVATE_DATA *Private;
+
+ Private = XENBUS_PRIVATE_DATA_FROM_THIS(This);
+ return XenEventChannelNotify (Private->Dev, Port);
+}
+
+UINT32
+EFIAPI
+XenBusEventChannelClose (
+ IN XENBUS_PROTOCOL *This,
+ IN evtchn_port_t Port
+ )
+{
+ evtchn_close_t Close;
+
+ Close.port = Port;
+ return (UINT32)XenHypercallEventChannelOp (EVTCHNOP_close, &Close);
+}
diff --git a/roms/edk2/OvmfPkg/XenBusDxe/EventChannel.h b/roms/edk2/OvmfPkg/XenBusDxe/EventChannel.h new file mode 100644 index 000000000..793571fab --- /dev/null +++ b/roms/edk2/OvmfPkg/XenBusDxe/EventChannel.h @@ -0,0 +1,82 @@ +/** @file
+ Event Channel function declaration.
+
+ Copyright (C) 2014, Citrix Ltd.
+
+ SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+#ifndef __XENBUS_EVENT_CHANNEL_H
+#define __XENBUS_EVENT_CHANNEL_H
+
+#include "XenBusDxe.h"
+
+#include <IndustryStandard/Xen/event_channel.h>
+
+/**
+ Send an event to the remote end of the channel whose local endpoint is Port.
+
+ @param Dev A pointer to XENBUS_DEVICE.
+ @param Port The port to notify.
+
+ @return Return 0 on success, or return the errno code from the hypercall.
+**/
+UINT32
+XenEventChannelNotify (
+ IN XENBUS_DEVICE *Dev,
+ IN evtchn_port_t Port
+ );
+
+/*
+ * XenBus protocol
+ */
+
+/**
+ Allocate a port that can be bind from domain DomainId.
+
+ @param This A pointer to the XENBUS_PROTOCOL.
+ @param DomainId The domain ID that can bind the newly allocated port.
+ @param Port A pointer to a evtchn_port_t that will contain the newly
+ allocated port.
+
+ @retval UINT32 The return value from the hypercall, 0 if success.
+**/
+UINT32
+EFIAPI
+XenBusEventChannelAllocate (
+ IN XENBUS_PROTOCOL *This,
+ IN domid_t DomainId,
+ OUT evtchn_port_t *Port
+ );
+
+/**
+ Send an event to the remote end of the channel whose local endpoint is Port.
+
+ @param This A pointer to the XENBUS_PROTOCOL.
+ @param Port Local port to the event from.
+
+ @retval UINT32 The return value from the hypercall, 0 if success.
+**/
+UINT32
+EFIAPI
+XenBusEventChannelNotify (
+ IN XENBUS_PROTOCOL *This,
+ IN evtchn_port_t Port
+ );
+
+/**
+ Close a local event channel Port.
+
+ @param This A pointer to the XENBUS_PROTOCOL.
+ @param Port The event channel to close.
+
+ @retval UINT32 The return value from the hypercall, 0 if success.
+**/
+UINT32
+EFIAPI
+XenBusEventChannelClose (
+ IN XENBUS_PROTOCOL *This,
+ IN evtchn_port_t Port
+ );
+
+#endif
diff --git a/roms/edk2/OvmfPkg/XenBusDxe/GrantTable.c b/roms/edk2/OvmfPkg/XenBusDxe/GrantTable.c new file mode 100644 index 000000000..58d687aba --- /dev/null +++ b/roms/edk2/OvmfPkg/XenBusDxe/GrantTable.c @@ -0,0 +1,201 @@ +/** @file
+ Grant Table function implementation.
+
+ Grant Table are used to grant access to certain page of the current
+ VM to an other VM.
+
+ Author: Steven Smith (sos22@cam.ac.uk)
+ Changes: Grzegorz Milos (gm281@cam.ac.uk)
+ Copyright (C) 2006, Cambridge University
+ Copyright (C) 2014, Citrix Ltd.
+
+ SPDX-License-Identifier: BSD-2-Clause-Patent
+**/
+#include "XenBusDxe.h"
+
+#include <IndustryStandard/Xen/memory.h>
+
+#include <Library/XenHypercallLib.h>
+#include <Library/SynchronizationLib.h>
+
+#include "GrantTable.h"
+
+#define NR_RESERVED_ENTRIES 8
+
+#define NR_GRANT_FRAMES (FixedPcdGet32 (PcdXenGrantFrames))
+#define NR_GRANT_ENTRIES (NR_GRANT_FRAMES * EFI_PAGE_SIZE / sizeof(grant_entry_v1_t))
+
+STATIC grant_entry_v1_t *GrantTable = NULL;
+STATIC grant_ref_t GrantList[NR_GRANT_ENTRIES];
+STATIC EFI_LOCK mGrantListLock;
+#ifdef GNT_DEBUG
+STATIC BOOLEAN GrantInUseList[NR_GRANT_ENTRIES];
+#endif
+
+STATIC
+VOID
+XenGrantTablePutFreeEntry (
+ grant_ref_t Ref
+ )
+{
+ EfiAcquireLock (&mGrantListLock);
+#ifdef GNT_DEBUG
+ ASSERT (GrantInUseList[Ref]);
+ GrantInUseList[Ref] = FALSE;
+#endif
+ GrantList[Ref] = GrantList[0];
+ GrantList[0] = Ref;
+ EfiReleaseLock (&mGrantListLock);
+}
+
+STATIC
+grant_ref_t
+XenGrantTableGetFreeEntry (
+ VOID
+ )
+{
+ grant_ref_t Ref;
+
+ EfiAcquireLock (&mGrantListLock);
+ Ref = GrantList[0];
+ ASSERT (Ref >= NR_RESERVED_ENTRIES && Ref < NR_GRANT_ENTRIES);
+ GrantList[0] = GrantList[Ref];
+#ifdef GNT_DEBUG
+ ASSERT (!GrantInUseList[Ref]);
+ GrantInUseList[Ref] = TRUE;
+#endif
+ EfiReleaseLock (&mGrantListLock);
+ return Ref;
+}
+
+STATIC
+grant_ref_t
+XenGrantTableGrantAccess (
+ IN domid_t DomainId,
+ IN UINTN Frame,
+ IN BOOLEAN ReadOnly
+ )
+{
+ grant_ref_t Ref;
+ UINT16 Flags;
+
+ ASSERT (GrantTable != NULL);
+ Ref = XenGrantTableGetFreeEntry ();
+ GrantTable[Ref].frame = (UINT32)Frame;
+ GrantTable[Ref].domid = DomainId;
+ MemoryFence ();
+ Flags = GTF_permit_access;
+ if (ReadOnly) {
+ Flags |= GTF_readonly;
+ }
+ GrantTable[Ref].flags = Flags;
+
+ return Ref;
+}
+
+STATIC
+EFI_STATUS
+XenGrantTableEndAccess (
+ grant_ref_t Ref
+ )
+{
+ UINT16 Flags, OldFlags;
+
+ ASSERT (GrantTable != NULL);
+ ASSERT (Ref >= NR_RESERVED_ENTRIES && Ref < NR_GRANT_ENTRIES);
+
+ OldFlags = GrantTable[Ref].flags;
+ do {
+ if ((Flags = OldFlags) & (GTF_reading | GTF_writing)) {
+ DEBUG ((DEBUG_WARN, "WARNING: g.e. still in use! (%x)\n", Flags));
+ return EFI_NOT_READY;
+ }
+ OldFlags = InterlockedCompareExchange16 (&GrantTable[Ref].flags, Flags, 0);
+ } while (OldFlags != Flags);
+
+ XenGrantTablePutFreeEntry (Ref);
+ return EFI_SUCCESS;
+}
+
+VOID
+XenGrantTableInit (
+ IN XENBUS_DEVICE *Dev
+ )
+{
+ xen_add_to_physmap_t Parameters;
+ INTN Index;
+ INTN ReturnCode;
+
+#ifdef GNT_DEBUG
+ SetMem(GrantInUseList, sizeof (GrantInUseList), 1);
+#endif
+ EfiInitializeLock (&mGrantListLock, TPL_NOTIFY);
+ for (Index = NR_RESERVED_ENTRIES; Index < NR_GRANT_ENTRIES; Index++) {
+ XenGrantTablePutFreeEntry ((grant_ref_t)Index);
+ }
+
+ GrantTable = (VOID*)(UINTN) Dev->XenIo->GrantTableAddress;
+ for (Index = 0; Index < NR_GRANT_FRAMES; Index++) {
+ Parameters.domid = DOMID_SELF;
+ Parameters.idx = Index;
+ Parameters.space = XENMAPSPACE_grant_table;
+ Parameters.gpfn = (xen_pfn_t) ((UINTN) GrantTable >> EFI_PAGE_SHIFT) + Index;
+ ReturnCode = XenHypercallMemoryOp (XENMEM_add_to_physmap, &Parameters);
+ if (ReturnCode != 0) {
+ DEBUG ((DEBUG_ERROR,
+ "Xen GrantTable, add_to_physmap hypercall error: %Ld\n",
+ (INT64)ReturnCode));
+ }
+ }
+}
+
+VOID
+XenGrantTableDeinit (
+ XENBUS_DEVICE *Dev
+ )
+{
+ INTN ReturnCode, Index;
+ xen_remove_from_physmap_t Parameters;
+
+ if (GrantTable == NULL) {
+ return;
+ }
+
+ for (Index = NR_GRANT_FRAMES - 1; Index >= 0; Index--) {
+ Parameters.domid = DOMID_SELF;
+ Parameters.gpfn = (xen_pfn_t) ((UINTN) GrantTable >> EFI_PAGE_SHIFT) + Index;
+ DEBUG ((DEBUG_INFO, "Xen GrantTable, removing %Lx\n",
+ (UINT64)Parameters.gpfn));
+ ReturnCode = XenHypercallMemoryOp (XENMEM_remove_from_physmap, &Parameters);
+ if (ReturnCode != 0) {
+ DEBUG ((DEBUG_ERROR,
+ "Xen GrantTable, remove_from_physmap hypercall error: %Ld\n",
+ (INT64)ReturnCode));
+ }
+ }
+ GrantTable = NULL;
+}
+
+EFI_STATUS
+EFIAPI
+XenBusGrantAccess (
+ IN XENBUS_PROTOCOL *This,
+ IN domid_t DomainId,
+ IN UINTN Frame, // MFN
+ IN BOOLEAN ReadOnly,
+ OUT grant_ref_t *RefPtr
+ )
+{
+ *RefPtr = XenGrantTableGrantAccess (DomainId, Frame, ReadOnly);
+ return EFI_SUCCESS;
+}
+
+EFI_STATUS
+EFIAPI
+XenBusGrantEndAccess (
+ IN XENBUS_PROTOCOL *This,
+ IN grant_ref_t Ref
+ )
+{
+ return XenGrantTableEndAccess (Ref);
+}
diff --git a/roms/edk2/OvmfPkg/XenBusDxe/GrantTable.h b/roms/edk2/OvmfPkg/XenBusDxe/GrantTable.h new file mode 100644 index 000000000..0c1e07633 --- /dev/null +++ b/roms/edk2/OvmfPkg/XenBusDxe/GrantTable.h @@ -0,0 +1,70 @@ +/** @file
+ Grant Table function declaration.
+
+ Grant Table are used to grant access to certain page of the current
+ VM to an other VM.
+
+ Copyright (C) 2014, Citrix Ltd.
+
+ SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+#ifndef __GNTTAB_H__
+#define __GNTTAB_H__
+
+#include <IndustryStandard/Xen/grant_table.h>
+
+/**
+ Initialize the Grant Table at the address MmioAddr.
+
+ @param Dev A pointer to XENBUS_DEVICE.
+ @param MmioAddr An address where the grant table can be mapped into
+ the guest.
+**/
+VOID
+XenGrantTableInit (
+ IN XENBUS_DEVICE *Dev
+ );
+
+/**
+ De-initialize the Grant Table.
+**/
+VOID
+XenGrantTableDeinit (
+ IN XENBUS_DEVICE *Dev
+ );
+
+/**
+ Grant access to the page Frame to the domain DomainId.
+
+ @param This A pointer to XENBUS_PROTOCOL instance.
+ @param DomainId ID of the domain to grant access to.
+ @param Frame Frame Number of the page to grant access to.
+ @param ReadOnly Provide read-only or read-write access.
+ @param RefPtr Reference number of the grant will be written to this pointer.
+**/
+EFI_STATUS
+EFIAPI
+XenBusGrantAccess (
+ IN XENBUS_PROTOCOL *This,
+ IN domid_t DomainId,
+ IN UINTN Frame, // MFN
+ IN BOOLEAN ReadOnly,
+ OUT grant_ref_t *RefPtr
+ );
+
+/**
+ End access to grant Ref, previously return by XenBusGrantAccess.
+
+ @param This A pointer to XENBUS_PROTOCOL instance.
+ @param Ref Reference numeber of a grant previously returned by
+ XenBusGrantAccess.
+**/
+EFI_STATUS
+EFIAPI
+XenBusGrantEndAccess (
+ IN XENBUS_PROTOCOL *This,
+ IN grant_ref_t Ref
+ );
+
+#endif /* !__GNTTAB_H__ */
diff --git a/roms/edk2/OvmfPkg/XenBusDxe/Helpers.c b/roms/edk2/OvmfPkg/XenBusDxe/Helpers.c new file mode 100644 index 000000000..b22f9c5b0 --- /dev/null +++ b/roms/edk2/OvmfPkg/XenBusDxe/Helpers.c @@ -0,0 +1,9 @@ +#include "XenBusDxe.h"
+
+CHAR8*
+AsciiStrDup (
+ IN CONST CHAR8* Str
+ )
+{
+ return AllocateCopyPool (AsciiStrSize (Str), Str);
+}
diff --git a/roms/edk2/OvmfPkg/XenBusDxe/TestAndClearBit.c b/roms/edk2/OvmfPkg/XenBusDxe/TestAndClearBit.c new file mode 100644 index 000000000..989ab7035 --- /dev/null +++ b/roms/edk2/OvmfPkg/XenBusDxe/TestAndClearBit.c @@ -0,0 +1,40 @@ +/** @file
+ Implementation of TestAndClearBit using compare-exchange primitive
+
+ Copyright (C) 2015, Linaro Ltd.
+ Copyright (c) 2015, Intel Corporation. All rights reserved.<BR>
+
+ SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#include <Base.h>
+#include <Library/SynchronizationLib.h>
+
+INT32
+EFIAPI
+TestAndClearBit (
+ IN INT32 Bit,
+ IN VOID *Address
+ )
+{
+ UINT16 Word, Read;
+ UINT16 Mask;
+
+ //
+ // Calculate the effective address relative to 'Address' based on the
+ // higher order bits of 'Bit'. Use signed shift instead of division to
+ // ensure we round towards -Inf, and end up with a positive shift in
+ // 'Bit', even if 'Bit' itself is negative.
+ //
+ Address = (VOID*)((UINT8*) Address + ((Bit >> 4) * sizeof(UINT16)));
+ Mask = 1U << (Bit & 15);
+
+ for (Word = *(UINT16 *) Address; Word & Mask; Word = Read) {
+ Read = InterlockedCompareExchange16 (Address, Word, Word & ~Mask);
+ if (Read == Word) {
+ return 1;
+ }
+ }
+ return 0;
+}
diff --git a/roms/edk2/OvmfPkg/XenBusDxe/XenBus.c b/roms/edk2/OvmfPkg/XenBusDxe/XenBus.c new file mode 100644 index 000000000..f8a41b6d3 --- /dev/null +++ b/roms/edk2/OvmfPkg/XenBusDxe/XenBus.c @@ -0,0 +1,370 @@ +/** @file
+ XenBus Bus driver implementation.
+
+ This file implement the necessary to discover and enumerate Xen PV devices
+ through XenStore.
+
+ Copyright (C) 2010 Spectra Logic Corporation
+ Copyright (C) 2008 Doug Rabson
+ Copyright (C) 2005 Rusty Russell, IBM Corporation
+ Copyright (C) 2005 Mike Wray, Hewlett-Packard
+ Copyright (C) 2005 XenSource Ltd
+ Copyright (C) 2014, Citrix Ltd.
+
+ This file may be distributed separately from the Linux kernel, or
+ incorporated into other software packages, subject to the following license:
+
+ SPDX-License-Identifier: MIT
+**/
+
+#include <Library/PrintLib.h>
+
+#include "XenBus.h"
+#include "GrantTable.h"
+#include "XenStore.h"
+#include "EventChannel.h"
+
+#include <IndustryStandard/Xen/io/xenbus.h>
+
+STATIC XENBUS_PRIVATE_DATA gXenBusPrivateData;
+
+STATIC XENBUS_DEVICE_PATH gXenBusDevicePathTemplate = {
+ { // Vendor
+ { // Vendor.Header
+ HARDWARE_DEVICE_PATH, // Vendor.Header.Type
+ HW_VENDOR_DP, // Vendor.Header.SubType
+ {
+ (UINT8) (sizeof (XENBUS_DEVICE_PATH)), // Vendor.Header.Length[0]
+ (UINT8) (sizeof (XENBUS_DEVICE_PATH) >> 8), // Vendor.Header.Length[1]
+ }
+ },
+ XENBUS_PROTOCOL_GUID, // Vendor.Guid
+ },
+ 0, // Type
+ 0 // DeviceId
+};
+
+
+/**
+ Search our internal record of configured devices (not the XenStore) to
+ determine if the XenBus device indicated by Node is known to the system.
+
+ @param Dev The XENBUS_DEVICE instance to search for device children.
+ @param Node The XenStore node path for the device to find.
+
+ @return The XENBUS_PRIVATE_DATA of the found device if any, or NULL.
+ */
+STATIC
+XENBUS_PRIVATE_DATA *
+XenBusDeviceInitialized (
+ IN XENBUS_DEVICE *Dev,
+ IN CONST CHAR8 *Node
+ )
+{
+ LIST_ENTRY *Entry;
+ XENBUS_PRIVATE_DATA *Child;
+ XENBUS_PRIVATE_DATA *Result;
+
+ if (IsListEmpty (&Dev->ChildList)) {
+ return NULL;
+ }
+
+ Result = NULL;
+ for (Entry = GetFirstNode (&Dev->ChildList);
+ !IsNodeAtEnd (&Dev->ChildList, Entry);
+ Entry = GetNextNode (&Dev->ChildList, Entry)) {
+ Child = XENBUS_PRIVATE_DATA_FROM_LINK (Entry);
+ if (!AsciiStrCmp (Child->XenBusIo.Node, Node)) {
+ Result = Child;
+ break;
+ }
+ }
+
+ return (Result);
+}
+
+STATIC
+XenbusState
+XenBusReadDriverState (
+ IN CONST CHAR8 *Path
+ )
+{
+ XenbusState State;
+ CHAR8 *Ptr = NULL;
+ XENSTORE_STATUS Status;
+
+ Status = XenStoreRead (XST_NIL, Path, "state", NULL, (VOID **)&Ptr);
+ if (Status != XENSTORE_STATUS_SUCCESS) {
+ State = XenbusStateClosed;
+ } else {
+ State = AsciiStrDecimalToUintn (Ptr);
+ }
+
+ if (Ptr != NULL) {
+ FreePool (Ptr);
+ }
+
+ return State;
+}
+
+//
+// Callers should ensure that they are only one calling XenBusAddDevice.
+//
+STATIC
+EFI_STATUS
+XenBusAddDevice (
+ XENBUS_DEVICE *Dev,
+ CONST CHAR8 *Type,
+ CONST CHAR8 *Id)
+{
+ CHAR8 DevicePath[XENSTORE_ABS_PATH_MAX];
+ XENSTORE_STATUS StatusXenStore;
+ XENBUS_PRIVATE_DATA *Private;
+ EFI_STATUS Status;
+ XENBUS_DEVICE_PATH *TempXenBusPath;
+ VOID *ChildXenIo;
+
+ AsciiSPrint (DevicePath, sizeof (DevicePath),
+ "device/%a/%a", Type, Id);
+
+ if (XenStorePathExists (XST_NIL, DevicePath, "")) {
+ XENBUS_PRIVATE_DATA *Child;
+ enum xenbus_state State;
+ CHAR8 *BackendPath;
+
+ Child = XenBusDeviceInitialized (Dev, DevicePath);
+ if (Child != NULL) {
+ /*
+ * We are already tracking this node
+ */
+ Status = EFI_SUCCESS;
+ goto out;
+ }
+
+ State = XenBusReadDriverState (DevicePath);
+ if (State != XenbusStateInitialising) {
+ /*
+ * Device is not new, so ignore it. This can
+ * happen if a device is going away after
+ * switching to Closed.
+ */
+ DEBUG ((DEBUG_INFO, "XenBus: Device %a ignored. "
+ "State %d\n", DevicePath, State));
+ Status = EFI_SUCCESS;
+ goto out;
+ }
+
+ StatusXenStore = XenStoreRead (XST_NIL, DevicePath, "backend",
+ NULL, (VOID **) &BackendPath);
+ if (StatusXenStore != XENSTORE_STATUS_SUCCESS) {
+ DEBUG ((DEBUG_ERROR, "xenbus: %a no backend path.\n", DevicePath));
+ Status = EFI_NOT_FOUND;
+ goto out;
+ }
+
+ Private = AllocateCopyPool (sizeof (*Private), &gXenBusPrivateData);
+ Private->XenBusIo.Type = AsciiStrDup (Type);
+ Private->XenBusIo.Node = AsciiStrDup (DevicePath);
+ Private->XenBusIo.Backend = BackendPath;
+ Private->XenBusIo.DeviceId = (UINT16)AsciiStrDecimalToUintn (Id);
+ Private->Dev = Dev;
+
+ TempXenBusPath = AllocateCopyPool (sizeof (XENBUS_DEVICE_PATH),
+ &gXenBusDevicePathTemplate);
+ if (!AsciiStrCmp (Private->XenBusIo.Type, "vbd")) {
+ TempXenBusPath->Type = XENBUS_DEVICE_PATH_TYPE_VBD;
+ }
+ TempXenBusPath->DeviceId = Private->XenBusIo.DeviceId;
+ Private->DevicePath = (XENBUS_DEVICE_PATH *)AppendDevicePathNode (
+ Dev->DevicePath,
+ &TempXenBusPath->Vendor.Header);
+ FreePool (TempXenBusPath);
+
+ InsertTailList (&Dev->ChildList, &Private->Link);
+
+ Status = gBS->InstallMultipleProtocolInterfaces (
+ &Private->Handle,
+ &gEfiDevicePathProtocolGuid, Private->DevicePath,
+ &gXenBusProtocolGuid, &Private->XenBusIo,
+ NULL);
+ if (EFI_ERROR (Status)) {
+ goto ErrorInstallProtocol;
+ }
+
+ Status = gBS->OpenProtocol (Dev->ControllerHandle,
+ &gXenIoProtocolGuid,
+ &ChildXenIo, Dev->This->DriverBindingHandle,
+ Private->Handle,
+ EFI_OPEN_PROTOCOL_BY_CHILD_CONTROLLER);
+ if (EFI_ERROR (Status)) {
+ DEBUG ((DEBUG_ERROR, "open by child controller fail (%r)\n",
+ Status));
+ goto ErrorOpenProtocolByChild;
+ }
+ } else {
+ DEBUG ((DEBUG_ERROR, "XenBus: does not exist: %a\n", DevicePath));
+ Status = EFI_NOT_FOUND;
+ }
+
+ return Status;
+
+ErrorOpenProtocolByChild:
+ gBS->UninstallMultipleProtocolInterfaces (
+ Private->Handle,
+ &gEfiDevicePathProtocolGuid, Private->DevicePath,
+ &gXenBusProtocolGuid, &Private->XenBusIo,
+ NULL);
+ErrorInstallProtocol:
+ RemoveEntryList (&Private->Link);
+ FreePool (Private->DevicePath);
+ FreePool ((VOID *) Private->XenBusIo.Backend);
+ FreePool ((VOID *) Private->XenBusIo.Node);
+ FreePool ((VOID *) Private->XenBusIo.Type);
+ FreePool (Private);
+out:
+ return Status;
+}
+
+/**
+ Enumerate all devices of the given type on this bus.
+
+ @param Dev A XENBUS_DEVICE instance.
+ @param Type String indicating the device sub-tree (e.g. "vfb", "vif")
+ to enumerate.
+
+ Devices that are found are been initialize via XenBusAddDevice ().
+ XenBusAddDevice () ignores duplicate detects and ignores duplicate devices,
+ so it can be called unconditionally for any device found in the XenStore.
+ */
+STATIC
+VOID
+XenBusEnumerateDeviceType (
+ XENBUS_DEVICE *Dev,
+ CONST CHAR8 *Type
+ )
+{
+ CONST CHAR8 **Directory;
+ UINTN Index;
+ UINT32 Count;
+ XENSTORE_STATUS Status;
+
+ Status = XenStoreListDirectory (XST_NIL,
+ "device", Type,
+ &Count, &Directory);
+ if (Status != XENSTORE_STATUS_SUCCESS) {
+ return;
+ }
+ for (Index = 0; Index < Count; Index++) {
+ XenBusAddDevice (Dev, Type, Directory[Index]);
+ }
+
+ FreePool ((VOID*)Directory);
+}
+
+
+/**
+ Enumerate the devices on a XenBus bus and install a XenBus Protocol instance.
+
+ Caller should ensure that it is the only one to call this function. This
+ function cannot be called concurrently.
+
+ @param Dev A XENBUS_DEVICE instance.
+
+ @return On success, XENSTORE_STATUS_SUCCESS. Otherwise an errno value
+ indicating the type of failure.
+ */
+XENSTORE_STATUS
+XenBusEnumerateBus (
+ XENBUS_DEVICE *Dev
+ )
+{
+ CONST CHAR8 **Types;
+ UINTN Index;
+ UINT32 Count;
+ XENSTORE_STATUS Status;
+
+ Status = XenStoreListDirectory (XST_NIL,
+ "device", "",
+ &Count, &Types);
+ if (Status != XENSTORE_STATUS_SUCCESS) {
+ return Status;
+ }
+
+ for (Index = 0; Index < Count; Index++) {
+ XenBusEnumerateDeviceType (Dev, Types[Index]);
+ }
+
+ FreePool ((VOID*)Types);
+
+ return XENSTORE_STATUS_SUCCESS;
+}
+
+STATIC
+XENSTORE_STATUS
+EFIAPI
+XenBusSetState (
+ IN XENBUS_PROTOCOL *This,
+ IN CONST XENSTORE_TRANSACTION *Transaction,
+ IN enum xenbus_state NewState
+ )
+{
+ enum xenbus_state CurrentState;
+ XENSTORE_STATUS Status;
+ CHAR8 *Temp;
+
+ DEBUG ((DEBUG_INFO, "XenBus: Set state to %d\n", NewState));
+
+ Status = XenStoreRead (Transaction, This->Node, "state", NULL, (VOID **)&Temp);
+ if (Status != XENSTORE_STATUS_SUCCESS) {
+ goto Out;
+ }
+ CurrentState = AsciiStrDecimalToUintn (Temp);
+ FreePool (Temp);
+ if (CurrentState == NewState) {
+ goto Out;
+ }
+
+ do {
+ Status = XenStoreSPrint (Transaction, This->Node, "state", "%d", NewState);
+ } while (Status == XENSTORE_STATUS_EAGAIN);
+ if (Status != XENSTORE_STATUS_SUCCESS) {
+ DEBUG ((DEBUG_ERROR, "XenBus: failed to write new state\n"));
+ goto Out;
+ }
+ DEBUG ((DEBUG_INFO, "XenBus: Set state to %d, done\n", NewState));
+
+Out:
+ return Status;
+}
+
+STATIC XENBUS_PRIVATE_DATA gXenBusPrivateData = {
+ XENBUS_PRIVATE_DATA_SIGNATURE, // Signature
+ { NULL, NULL }, // Link
+ NULL, // Handle
+ { // XenBusIo
+ XenBusXenStoreRead, // XenBusIo.XsRead
+ XenBusXenStoreBackendRead, // XenBusIo.XsBackendRead
+ XenBusXenStoreSPrint, // XenBusIo.XsPrintf
+ XenBusXenStoreRemove, // XenBusIo.XsRemove
+ XenBusXenStoreTransactionStart, // XenBusIo.XsTransactionStart
+ XenBusXenStoreTransactionEnd, // XenBusIo.XsTransactionEnd
+ XenBusSetState, // XenBusIo.SetState
+ XenBusGrantAccess, // XenBusIo.GrantAccess
+ XenBusGrantEndAccess, // XenBusIo.GrantEndAccess
+ XenBusEventChannelAllocate, // XenBusIo.EventChannelAllocate
+ XenBusEventChannelNotify, // XenBusIo.EventChannelNotify
+ XenBusEventChannelClose, // XenBusIo.EventChannelClose
+ XenBusRegisterWatch, // XenBusIo.RegisterWatch
+ XenBusRegisterWatchBackend, // XenBusIo.RegisterWatchBackend
+ XenBusUnregisterWatch, // XenBusIo.UnregisterWatch
+ XenBusWaitForWatch, // XenBusIo.WaitForWatch
+
+ NULL, // XenBusIo.Type
+ 0, // XenBusIo.DeviceId
+ NULL, // XenBusIo.Node
+ NULL, // XenBusIo.Backend
+ },
+
+ NULL, // Dev
+ NULL // DevicePath
+};
diff --git a/roms/edk2/OvmfPkg/XenBusDxe/XenBus.h b/roms/edk2/OvmfPkg/XenBusDxe/XenBus.h new file mode 100644 index 000000000..c85ca9946 --- /dev/null +++ b/roms/edk2/OvmfPkg/XenBusDxe/XenBus.h @@ -0,0 +1,38 @@ +/** @file
+ XenBus Bus driver declarations.
+
+ Copyright (C) 2014, Citrix Ltd.
+
+ SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+#ifndef _XEN_XENBUS_XENBUSB_H
+#define _XEN_XENBUS_XENBUSB_H
+
+#include "XenBusDxe.h"
+
+#define XENBUS_DEVICE_PATH_TYPE_VBD 0x1
+struct _XENBUS_DEVICE_PATH {
+ VENDOR_DEVICE_PATH Vendor;
+ UINT8 Type;
+ UINT16 DeviceId;
+};
+
+
+/**
+ Perform XenBus bus enumeration and install protocol for children.
+
+ Caller should ensure that it is the only one to call this function. This
+ function cannot be called concurrently.
+
+ @param Dev A XENBUS_DEVICE instance.
+
+ @return On success, XENSTORE_STATUS_SUCCESS. Otherwise an errno value
+ indicating the type of failure.
+**/
+XENSTORE_STATUS
+XenBusEnumerateBus (
+ XENBUS_DEVICE *Dev
+ );
+
+#endif /* _XEN_XENBUS_XENBUSB_H */
diff --git a/roms/edk2/OvmfPkg/XenBusDxe/XenBusDxe.c b/roms/edk2/OvmfPkg/XenBusDxe/XenBusDxe.c new file mode 100644 index 000000000..1f5628ad8 --- /dev/null +++ b/roms/edk2/OvmfPkg/XenBusDxe/XenBusDxe.c @@ -0,0 +1,484 @@ +/** @file
+ This driver produces XenBus Protocol instances for each Xen PV devices.
+
+ This XenBus bus driver will first initialize different services in order to
+ enumerate the ParaVirtualized devices available.
+
+ Those services are:
+ - HyperCall
+ - Event Channel
+ - Grant Table
+ - XenStore
+ - XenBus
+
+ Copyright (C) 2014, Citrix Ltd.
+
+ SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#include <Library/DebugLib.h>
+#include <Library/XenHypercallLib.h>
+
+#include "XenBusDxe.h"
+
+#include "GrantTable.h"
+#include "XenStore.h"
+#include "XenBus.h"
+
+#include <IndustryStandard/Xen/hvm/params.h>
+#include <IndustryStandard/Xen/memory.h>
+
+///
+/// Driver Binding Protocol instance
+///
+EFI_DRIVER_BINDING_PROTOCOL gXenBusDxeDriverBinding = {
+ XenBusDxeDriverBindingSupported,
+ XenBusDxeDriverBindingStart,
+ XenBusDxeDriverBindingStop,
+ XENBUS_DXE_VERSION,
+ NULL,
+ NULL
+};
+
+
+STATIC EFI_LOCK mMyDeviceLock = EFI_INITIALIZE_LOCK_VARIABLE (TPL_CALLBACK);
+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.
+
+ @param ImageHandle Handle that identifies the image to be unloaded.
+
+ @retval EFI_SUCCESS The image has been unloaded.
+ @retval EFI_INVALID_PARAMETER ImageHandle is not a valid image handle.
+
+**/
+EFI_STATUS
+EFIAPI
+XenBusDxeUnload (
+ IN EFI_HANDLE ImageHandle
+ )
+{
+ EFI_STATUS Status;
+
+ EFI_HANDLE *HandleBuffer;
+ UINTN HandleCount;
+ UINTN Index;
+
+ //
+ // Retrieve array of all handles in the handle database
+ //
+ Status = gBS->LocateHandleBuffer (
+ AllHandles,
+ NULL,
+ NULL,
+ &HandleCount,
+ &HandleBuffer
+ );
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ //
+ // Disconnect the current driver from handles in the handle database
+ //
+ for (Index = 0; Index < HandleCount; Index++) {
+ gBS->DisconnectController (HandleBuffer[Index], gImageHandle, NULL);
+ }
+
+ //
+ // Free the array of handles
+ //
+ FreePool (HandleBuffer);
+
+
+ //
+ // Uninstall protocols installed in the driver entry point
+ //
+ Status = gBS->UninstallMultipleProtocolInterfaces (
+ ImageHandle,
+ &gEfiDriverBindingProtocolGuid, &gXenBusDxeDriverBinding,
+ &gEfiComponentNameProtocolGuid, &gXenBusDxeComponentName,
+ &gEfiComponentName2ProtocolGuid, &gXenBusDxeComponentName2,
+ NULL
+ );
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ return EFI_SUCCESS;
+}
+
+/**
+ This is the declaration of an EFI image entry point. This entry point is
+ the same for UEFI Applications, UEFI OS Loaders, and UEFI Drivers including
+ both device drivers and bus drivers.
+
+ @param ImageHandle The firmware allocated handle for the UEFI image.
+ @param SystemTable A pointer to the EFI System Table.
+
+ @retval EFI_SUCCESS The operation completed successfully.
+ @retval EFI_ABORTED Xen hypercalls are not available.
+ @retval Others An unexpected error occurred.
+**/
+EFI_STATUS
+EFIAPI
+XenBusDxeDriverEntryPoint (
+ IN EFI_HANDLE ImageHandle,
+ IN EFI_SYSTEM_TABLE *SystemTable
+ )
+{
+ EFI_STATUS Status;
+
+ if (! XenHypercallIsAvailable ()) {
+ return EFI_ABORTED;
+ }
+
+ //
+ // Install UEFI Driver Model protocol(s).
+ //
+ Status = EfiLibInstallDriverBindingComponentName2 (
+ ImageHandle,
+ SystemTable,
+ &gXenBusDxeDriverBinding,
+ ImageHandle,
+ &gXenBusDxeComponentName,
+ &gXenBusDxeComponentName2
+ );
+ ASSERT_EFI_ERROR (Status);
+
+
+ return Status;
+}
+
+
+/**
+ Tests to see if this driver supports a given controller. If a child device is provided,
+ it further tests to see if this driver supports creating a handle for the specified child device.
+
+ @param[in] This A pointer to the EFI_DRIVER_BINDING_PROTOCOL instance.
+ @param[in] ControllerHandle The handle of the controller to test. This handle
+ must support a protocol interface that supplies
+ an I/O abstraction to the driver.
+ @param[in] RemainingDevicePath A pointer to the remaining portion of a device path. This
+ parameter is ignored by device drivers, and is optional for bus
+ drivers. For bus drivers, if this parameter is not NULL, then
+ the bus driver must determine if the bus controller specified
+ by ControllerHandle and the child controller specified
+ by RemainingDevicePath are both supported by this
+ bus driver.
+
+ @retval EFI_SUCCESS The device specified by ControllerHandle and
+ RemainingDevicePath is supported by the driver specified by This.
+ @retval EFI_ALREADY_STARTED The device specified by ControllerHandle and
+ RemainingDevicePath is already being managed by the driver
+ specified by This.
+ @retval EFI_ACCESS_DENIED The device specified by ControllerHandle and
+ RemainingDevicePath is already being managed by a different
+ driver or an application that requires exclusive access.
+ Currently not implemented.
+ @retval EFI_UNSUPPORTED The device specified by ControllerHandle and
+ RemainingDevicePath is not supported by the driver specified by This.
+**/
+EFI_STATUS
+EFIAPI
+XenBusDxeDriverBindingSupported (
+ IN EFI_DRIVER_BINDING_PROTOCOL *This,
+ IN EFI_HANDLE ControllerHandle,
+ IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath OPTIONAL
+ )
+{
+ EFI_STATUS Status;
+ XENIO_PROTOCOL *XenIo;
+
+ Status = gBS->OpenProtocol (
+ ControllerHandle,
+ &gXenIoProtocolGuid,
+ (VOID **)&XenIo,
+ This->DriverBindingHandle,
+ ControllerHandle,
+ EFI_OPEN_PROTOCOL_BY_DRIVER
+ );
+
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ gBS->CloseProtocol (ControllerHandle, &gXenIoProtocolGuid,
+ This->DriverBindingHandle, ControllerHandle);
+
+ return Status;
+}
+
+VOID
+EFIAPI
+NotifyExitBoot (
+ IN EFI_EVENT Event,
+ IN VOID *Context
+ )
+{
+ XENBUS_DEVICE *Dev = Context;
+
+ gBS->DisconnectController(Dev->ControllerHandle,
+ Dev->This->DriverBindingHandle, NULL);
+}
+
+/**
+ Starts a bus controller.
+
+ The Start() function is designed to be invoked from the EFI boot service ConnectController().
+ As a result, much of the error checking on the parameters to Start() has been moved into this
+ common boot service. It is legal to call Start() from other locations,
+ but the following calling restrictions must be followed, or the system behavior will not be deterministic.
+ 1. ControllerHandle must be a valid EFI_HANDLE.
+ 2. If RemainingDevicePath is not NULL, then it must be a pointer to a naturally aligned
+ EFI_DEVICE_PATH_PROTOCOL.
+ 3. Prior to calling Start(), the Supported() function for the driver specified by This must
+ have been called with the same calling parameters, and Supported() must have returned EFI_SUCCESS.
+
+ @param[in] This A pointer to the EFI_DRIVER_BINDING_PROTOCOL instance.
+ @param[in] ControllerHandle The handle of the controller to start. This handle
+ must support a protocol interface that supplies
+ an I/O abstraction to the driver.
+ @param[in] RemainingDevicePath A pointer to the remaining portion of a device path. This
+ parameter is ignored by device drivers, and is optional for bus
+ drivers. For a bus driver, if this parameter is NULL, then handles
+ for all the children of Controller are created by this driver.
+ If this parameter is not NULL and the first Device Path Node is
+ not the End of Device Path Node, then only the handle for the
+ child device specified by the first Device Path Node of
+ RemainingDevicePath is created by this driver.
+ If the first Device Path Node of RemainingDevicePath is
+ the End of Device Path Node, no child handle is created by this
+ driver.
+
+ @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 device.
+ @retval Others The driver failed to start the device.
+
+**/
+EFI_STATUS
+EFIAPI
+XenBusDxeDriverBindingStart (
+ IN EFI_DRIVER_BINDING_PROTOCOL *This,
+ IN EFI_HANDLE ControllerHandle,
+ IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath OPTIONAL
+ )
+{
+ EFI_STATUS Status;
+ XENBUS_DEVICE *Dev;
+ XENIO_PROTOCOL *XenIo;
+ EFI_DEVICE_PATH_PROTOCOL *DevicePath;
+
+ Status = gBS->OpenProtocol (
+ ControllerHandle,
+ &gXenIoProtocolGuid,
+ (VOID**)&XenIo,
+ This->DriverBindingHandle,
+ ControllerHandle,
+ EFI_OPEN_PROTOCOL_BY_DRIVER
+ );
+
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ Status = gBS->OpenProtocol (
+ ControllerHandle,
+ &gEfiDevicePathProtocolGuid,
+ (VOID **) &DevicePath,
+ This->DriverBindingHandle,
+ ControllerHandle,
+ EFI_OPEN_PROTOCOL_BY_DRIVER
+ );
+
+ if (EFI_ERROR (Status)) {
+ goto ErrorOpenningProtocol;
+ }
+
+ Dev = AllocateZeroPool (sizeof (*Dev));
+ Dev->Signature = XENBUS_DEVICE_SIGNATURE;
+ Dev->This = This;
+ Dev->ControllerHandle = ControllerHandle;
+ Dev->XenIo = XenIo;
+ Dev->DevicePath = DevicePath;
+ InitializeListHead (&Dev->ChildList);
+
+ EfiAcquireLock (&mMyDeviceLock);
+ if (mMyDevice != NULL) {
+ EfiReleaseLock (&mMyDeviceLock);
+ //
+ // There is already a XenBus running, only one can be used at a time.
+ //
+ Status = EFI_ALREADY_STARTED;
+ goto ErrorAllocated;
+ }
+ mMyDevice = Dev;
+ EfiReleaseLock (&mMyDeviceLock);
+
+ Status = XenGetSharedInfoPage (Dev);
+ if (EFI_ERROR (Status)) {
+ DEBUG ((DEBUG_ERROR, "XenBus: Unable to get the shared info page.\n"));
+ Status = EFI_UNSUPPORTED;
+ goto ErrorAllocated;
+ }
+
+ XenGrantTableInit (Dev);
+
+ Status = XenStoreInit (Dev);
+ ASSERT_EFI_ERROR (Status);
+
+ XenBusEnumerateBus (Dev);
+
+ Status = gBS->CreateEvent (EVT_SIGNAL_EXIT_BOOT_SERVICES, TPL_CALLBACK,
+ NotifyExitBoot,
+ (VOID*) Dev,
+ &Dev->ExitBootEvent);
+ ASSERT_EFI_ERROR (Status);
+
+ return EFI_SUCCESS;
+
+ErrorAllocated:
+ FreePool (Dev);
+ gBS->CloseProtocol (ControllerHandle, &gEfiDevicePathProtocolGuid,
+ This->DriverBindingHandle, ControllerHandle);
+ErrorOpenningProtocol:
+ gBS->CloseProtocol (ControllerHandle, &gXenIoProtocolGuid,
+ This->DriverBindingHandle, ControllerHandle);
+ return Status;
+}
+
+/**
+ Stops a bus controller.
+
+ The Stop() function is designed to be invoked from the EFI boot service DisconnectController().
+ As a result, much of the error checking on the parameters to Stop() has been moved
+ into this common boot service. It is legal to call Stop() from other locations,
+ but the following calling restrictions must be followed, or the system behavior will not be deterministic.
+ 1. ControllerHandle must be a valid EFI_HANDLE that was used on a previous call to this
+ same driver's Start() function.
+ 2. The first NumberOfChildren handles of ChildHandleBuffer must all be a valid
+ EFI_HANDLE. In addition, all of these handles must have been created in this driver's
+ Start() function, and the Start() function must have called OpenProtocol() on
+ ControllerHandle with an Attribute of EFI_OPEN_PROTOCOL_BY_CHILD_CONTROLLER.
+
+ @param[in] This A pointer to the EFI_DRIVER_BINDING_PROTOCOL instance.
+ @param[in] ControllerHandle A handle to the device being stopped. The handle must
+ support a bus specific I/O protocol for the driver
+ to use to stop the device.
+ @param[in] NumberOfChildren The number of child device handles in ChildHandleBuffer.
+ @param[in] ChildHandleBuffer An array of child handles to be freed. May be NULL
+ if NumberOfChildren is 0.
+
+ @retval EFI_SUCCESS The device was stopped.
+ @retval EFI_DEVICE_ERROR The device could not be stopped due to a device error.
+
+**/
+EFI_STATUS
+EFIAPI
+XenBusDxeDriverBindingStop (
+ IN EFI_DRIVER_BINDING_PROTOCOL *This,
+ IN EFI_HANDLE ControllerHandle,
+ IN UINTN NumberOfChildren,
+ IN EFI_HANDLE *ChildHandleBuffer OPTIONAL
+ )
+{
+ UINTN Index;
+ XENBUS_PROTOCOL *XenBusIo;
+ XENBUS_PRIVATE_DATA *ChildData;
+ EFI_STATUS Status;
+ XENBUS_DEVICE *Dev = mMyDevice;
+
+ for (Index = 0; Index < NumberOfChildren; Index++) {
+ Status = gBS->OpenProtocol (
+ ChildHandleBuffer[Index],
+ &gXenBusProtocolGuid,
+ (VOID **) &XenBusIo,
+ This->DriverBindingHandle,
+ ControllerHandle,
+ EFI_OPEN_PROTOCOL_GET_PROTOCOL);
+ if (EFI_ERROR (Status)) {
+ DEBUG ((DEBUG_ERROR, "XenBusDxe: get children protocol failed: %r\n", Status));
+ continue;
+ }
+ ChildData = XENBUS_PRIVATE_DATA_FROM_THIS (XenBusIo);
+
+ Status = gBS->CloseProtocol (Dev->ControllerHandle, &gXenIoProtocolGuid,
+ Dev->This->DriverBindingHandle, ChildData->Handle);
+ ASSERT_EFI_ERROR (Status);
+
+ Status = gBS->UninstallMultipleProtocolInterfaces (
+ ChildData->Handle,
+ &gEfiDevicePathProtocolGuid, ChildData->DevicePath,
+ &gXenBusProtocolGuid, &ChildData->XenBusIo,
+ NULL);
+ ASSERT_EFI_ERROR (Status);
+
+ FreePool ((VOID*)ChildData->XenBusIo.Type);
+ FreePool ((VOID*)ChildData->XenBusIo.Node);
+ FreePool ((VOID*)ChildData->XenBusIo.Backend);
+ FreePool (ChildData->DevicePath);
+ RemoveEntryList (&ChildData->Link);
+ FreePool (ChildData);
+ }
+ if (NumberOfChildren > 0) {
+ return EFI_SUCCESS;
+ }
+
+ gBS->CloseEvent (Dev->ExitBootEvent);
+ XenStoreDeinit (Dev);
+ XenGrantTableDeinit (Dev);
+
+ gBS->CloseProtocol (ControllerHandle, &gEfiDevicePathProtocolGuid,
+ This->DriverBindingHandle, ControllerHandle);
+ gBS->CloseProtocol (ControllerHandle, &gXenIoProtocolGuid,
+ This->DriverBindingHandle, ControllerHandle);
+
+ mMyDevice = NULL;
+ FreePool (Dev);
+ return EFI_SUCCESS;
+}
diff --git a/roms/edk2/OvmfPkg/XenBusDxe/XenBusDxe.h b/roms/edk2/OvmfPkg/XenBusDxe/XenBusDxe.h new file mode 100644 index 000000000..b1dcc3549 --- /dev/null +++ b/roms/edk2/OvmfPkg/XenBusDxe/XenBusDxe.h @@ -0,0 +1,128 @@ +/** @file
+ Function declaration and internal data for XenBusDxe.
+
+ Copyright (C) 2014, Citrix Ltd.
+
+ SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#ifndef __EFI_XENBUS_DXE_H__
+#define __EFI_XENBUS_DXE_H__
+
+#include <Uefi.h>
+
+//
+// Libraries
+//
+#include <Library/UefiBootServicesTableLib.h>
+#include <Library/MemoryAllocationLib.h>
+#include <Library/BaseMemoryLib.h>
+#include <Library/BaseLib.h>
+#include <Library/UefiLib.h>
+#include <Library/DevicePathLib.h>
+#include <Library/DebugLib.h>
+#include <Library/PcdLib.h>
+
+
+//
+// UEFI Driver Model Protocols
+//
+#include <Protocol/DriverBinding.h>
+
+
+//
+// Consumed Protocols
+//
+#include <Protocol/XenIo.h>
+
+
+//
+// Produced Protocols
+//
+#include <Protocol/XenBus.h>
+
+
+//
+// Driver Version
+//
+#define XENBUS_DXE_VERSION 0x00000010
+
+
+//
+// Protocol instances
+//
+extern EFI_DRIVER_BINDING_PROTOCOL gXenBusDxeDriverBinding;
+extern EFI_COMPONENT_NAME2_PROTOCOL gXenBusDxeComponentName2;
+extern EFI_COMPONENT_NAME_PROTOCOL gXenBusDxeComponentName;
+
+
+//
+// Include files with function prototypes
+//
+#include "DriverBinding.h"
+#include "ComponentName.h"
+
+//
+// Other stuff
+//
+#include <IndustryStandard/Xen/xen.h>
+
+typedef struct _XENBUS_DEVICE_PATH XENBUS_DEVICE_PATH;
+typedef struct _XENBUS_DEVICE XENBUS_DEVICE;
+
+// Have the state of the driver.
+#define XENBUS_DEVICE_SIGNATURE SIGNATURE_32 ('X','B','s','t')
+struct _XENBUS_DEVICE {
+ UINT32 Signature;
+ EFI_DRIVER_BINDING_PROTOCOL *This;
+ EFI_HANDLE ControllerHandle;
+ XENIO_PROTOCOL *XenIo;
+ EFI_EVENT ExitBootEvent;
+ EFI_DEVICE_PATH_PROTOCOL *DevicePath;
+ LIST_ENTRY ChildList;
+
+ shared_info_t *SharedInfo;
+};
+
+// There is one of this struct allocated for every child.
+#define XENBUS_PRIVATE_DATA_SIGNATURE SIGNATURE_32 ('X', 'B', 'p', 'd')
+typedef struct {
+ UINTN Signature;
+ LIST_ENTRY Link;
+ EFI_HANDLE Handle;
+ XENBUS_PROTOCOL XenBusIo;
+ XENBUS_DEVICE *Dev;
+ XENBUS_DEVICE_PATH *DevicePath;
+} XENBUS_PRIVATE_DATA;
+
+#define XENBUS_PRIVATE_DATA_FROM_THIS(a) \
+ CR (a, XENBUS_PRIVATE_DATA, XenBusIo, XENBUS_PRIVATE_DATA_SIGNATURE)
+#define XENBUS_PRIVATE_DATA_FROM_LINK(a) \
+ CR (a, XENBUS_PRIVATE_DATA, Link, XENBUS_PRIVATE_DATA_SIGNATURE)
+
+/*
+ * Helpers
+ */
+
+/**
+ Atomically test and clear a bit.
+
+ @param Bit Bit index to test in *Address
+ @param Address The Address to the buffer that contain the bit to test.
+
+ @return Value of the Bit before it was cleared.
+**/
+INT32
+EFIAPI
+TestAndClearBit (
+ IN INT32 Bit,
+ IN VOID *Address
+ );
+
+CHAR8*
+AsciiStrDup (
+ IN CONST CHAR8* Str
+ );
+
+#endif
diff --git a/roms/edk2/OvmfPkg/XenBusDxe/XenBusDxe.inf b/roms/edk2/OvmfPkg/XenBusDxe/XenBusDxe.inf new file mode 100644 index 000000000..536b49fa8 --- /dev/null +++ b/roms/edk2/OvmfPkg/XenBusDxe/XenBusDxe.inf @@ -0,0 +1,64 @@ +## @file
+# This driver produces a XenBus protocol for every Xen PV devices found.
+#
+# Copyright (C) 2014, Citrix Ltd.
+#
+# SPDX-License-Identifier: BSD-2-Clause-Patent
+#
+##
+
+[Defines]
+ INF_VERSION = 0x00010005
+ BASE_NAME = XenBusDxe
+ FILE_GUID = 565ec8ba-a484-11e3-802b-b8ac6f7d65e6
+ MODULE_TYPE = UEFI_DRIVER
+
+ VERSION_STRING = 1.0
+ ENTRY_POINT = XenBusDxeDriverEntryPoint
+ UNLOAD_IMAGE = XenBusDxeUnload
+
+
+[Packages]
+ MdePkg/MdePkg.dec
+ OvmfPkg/OvmfPkg.dec
+
+[Sources]
+ XenBusDxe.h
+ XenBusDxe.c
+ DriverBinding.h
+ ComponentName.c
+ ComponentName.h
+ GrantTable.c
+ GrantTable.h
+ EventChannel.c
+ EventChannel.h
+ XenStore.c
+ XenStore.h
+ XenBus.c
+ XenBus.h
+ Helpers.c
+ TestAndClearBit.c
+
+[LibraryClasses]
+ UefiDriverEntryPoint
+ UefiBootServicesTableLib
+ MemoryAllocationLib
+ BaseMemoryLib
+ BaseLib
+ UefiLib
+ DevicePathLib
+ DebugLib
+ XenHypercallLib
+ SynchronizationLib
+ PrintLib
+ PcdLib
+
+[Protocols]
+ gEfiDriverBindingProtocolGuid
+ gEfiComponentName2ProtocolGuid
+ gEfiComponentNameProtocolGuid
+ gXenBusProtocolGuid
+ gXenIoProtocolGuid
+
+[FixedPcd]
+ gUefiOvmfPkgTokenSpaceGuid.PcdXenGrantFrames
diff --git a/roms/edk2/OvmfPkg/XenBusDxe/XenStore.c b/roms/edk2/OvmfPkg/XenBusDxe/XenStore.c new file mode 100644 index 000000000..e5cca108e --- /dev/null +++ b/roms/edk2/OvmfPkg/XenBusDxe/XenStore.c @@ -0,0 +1,1538 @@ +/** @file
+ Low-level kernel interface to the XenStore.
+
+ The XenStore interface is a simple storage system that is a means of
+ communicating state and configuration data between the Xen Domain 0
+ and the various guest domains. All configuration data other than
+ a small amount of essential information required during the early
+ boot process of launching a Xen aware guest, is managed using the
+ XenStore.
+
+ The XenStore is ASCII string based, and has a structure and semantics
+ similar to a filesystem. There are files and directories, the directories
+ able to contain files or other directories. The depth of the hierarchy
+ is only limited by the XenStore's maximum path length.
+
+ The communication channel between the XenStore service and other
+ domains is via two, guest specific, ring buffers in a shared memory
+ area. One ring buffer is used for communicating in each direction.
+ The grant table references for this shared memory are given to the
+ guest either via the xen_start_info structure for a fully para-
+ virtualized guest, or via HVM hypercalls for a hardware virtualized
+ guest.
+
+ The XenStore communication relies on an event channel and thus
+ interrupts. But under OVMF this XenStore client will pull the
+ state of the event channel.
+
+ Several Xen services depend on the XenStore, most notably the
+ XenBus used to discover and manage Xen devices.
+
+ Copyright (C) 2005 Rusty Russell, IBM Corporation
+ Copyright (C) 2009,2010 Spectra Logic Corporation
+ Copyright (C) 2014, Citrix Ltd.
+
+ This file may be distributed separately from the Linux kernel, or
+ incorporated into other software packages, subject to the following license:
+
+ SPDX-License-Identifier: MIT
+**/
+
+#include "XenStore.h"
+
+#include <Library/PrintLib.h>
+
+#include <IndustryStandard/Xen/hvm/params.h>
+
+#include "EventChannel.h"
+#include <Library/XenHypercallLib.h>
+
+//
+// Private Data Structures
+//
+
+typedef struct {
+ CONST VOID *Data;
+ UINT32 Len;
+} WRITE_REQUEST;
+
+/* Register callback to watch subtree (node) in the XenStore. */
+#define XENSTORE_WATCH_SIGNATURE SIGNATURE_32 ('X','S','w','a')
+struct _XENSTORE_WATCH
+{
+ UINT32 Signature;
+ LIST_ENTRY Link;
+
+ /* Path being watched. */
+ CHAR8 *Node;
+};
+
+#define XENSTORE_WATCH_FROM_LINK(l) \
+ CR (l, XENSTORE_WATCH, Link, XENSTORE_WATCH_SIGNATURE)
+
+
+/**
+ * Structure capturing messages received from the XenStore service.
+ */
+#define XENSTORE_MESSAGE_SIGNATURE SIGNATURE_32 ('X', 'S', 's', 'm')
+typedef struct {
+ UINT32 Signature;
+ LIST_ENTRY Link;
+
+ struct xsd_sockmsg Header;
+
+ union {
+ /* Queued replies. */
+ struct {
+ CHAR8 *Body;
+ } Reply;
+
+ /* Queued watch events. */
+ struct {
+ XENSTORE_WATCH *Handle;
+ CONST CHAR8 **Vector;
+ UINT32 VectorSize;
+ } Watch;
+ } u;
+} XENSTORE_MESSAGE;
+#define XENSTORE_MESSAGE_FROM_LINK(r) \
+ CR (r, XENSTORE_MESSAGE, Link, XENSTORE_MESSAGE_SIGNATURE)
+
+/**
+ * Container for all XenStore related state.
+ */
+typedef struct {
+ /**
+ * Pointer to shared memory communication structures allowing us
+ * to communicate with the XenStore service.
+ */
+ struct xenstore_domain_interface *XenStore;
+
+ XENBUS_DEVICE *Dev;
+
+ /**
+ * A list of replies to our requests.
+ *
+ * The reply list is filled by xs_rcv_thread(). It
+ * is consumed by the context that issued the request
+ * to which a reply is made. The requester blocks in
+ * XenStoreReadReply ().
+ *
+ * /note Only one requesting context can be active at a time.
+ */
+ LIST_ENTRY ReplyList;
+
+ /** Lock protecting the reply list. */
+ EFI_LOCK ReplyLock;
+
+ /**
+ * List of registered watches.
+ */
+ LIST_ENTRY RegisteredWatches;
+
+ /** Lock protecting the registered watches list. */
+ EFI_LOCK RegisteredWatchesLock;
+
+ /**
+ * List of pending watch callback events.
+ */
+ LIST_ENTRY WatchEvents;
+
+ /** Lock protecting the watch callback list. */
+ EFI_LOCK WatchEventsLock;
+
+ /**
+ * The event channel for communicating with the
+ * XenStore service.
+ */
+ evtchn_port_t EventChannel;
+
+ /** Handle for XenStore events. */
+ EFI_EVENT EventChannelEvent;
+} XENSTORE_PRIVATE;
+
+//
+// Global Data
+//
+static XENSTORE_PRIVATE xs;
+
+
+//
+// Private Utility Functions
+//
+
+/**
+ Count and optionally record pointers to a number of NUL terminated
+ strings in a buffer.
+
+ @param Strings A pointer to a contiguous buffer of NUL terminated strings.
+ @param Len The length of the buffer pointed to by strings.
+ @param Dst An array to store pointers to each string found in strings.
+
+ @return A count of the number of strings found.
+**/
+STATIC
+UINT32
+ExtractStrings (
+ IN CONST CHAR8 *Strings,
+ IN UINTN Len,
+ OUT CONST CHAR8 **Dst OPTIONAL
+ )
+{
+ UINT32 Num = 0;
+ CONST CHAR8 *Ptr;
+
+ for (Ptr = Strings; Ptr < Strings + Len; Ptr += AsciiStrSize (Ptr)) {
+ if (Dst != NULL) {
+ *Dst++ = Ptr;
+ }
+ Num++;
+ }
+
+ return Num;
+}
+
+/**
+ Convert a contiguous buffer containing a series of NUL terminated
+ strings into an array of pointers to strings.
+
+ The returned pointer references the array of string pointers which
+ is followed by the storage for the string data. It is the client's
+ responsibility to free this storage.
+
+ The storage addressed by Strings is free'd prior to Split returning.
+
+ @param Strings A pointer to a contiguous buffer of NUL terminated strings.
+ @param Len The length of the buffer pointed to by strings.
+ @param NumPtr The number of strings found and returned in the strings
+ array.
+
+ @return An array of pointers to the strings found in the input buffer.
+**/
+STATIC
+CONST CHAR8 **
+Split (
+ IN CHAR8 *Strings,
+ IN UINTN Len,
+ OUT UINT32 *NumPtr
+ )
+{
+ CONST CHAR8 **Dst;
+
+ ASSERT(NumPtr != NULL);
+ ASSERT(Strings != NULL);
+
+ /* Protect against unterminated buffers. */
+ if (Len > 0) {
+ Strings[Len - 1] = '\0';
+ }
+
+ /* Count the Strings. */
+ *NumPtr = ExtractStrings (Strings, Len, NULL);
+
+ /* Transfer to one big alloc for easy freeing by the caller. */
+ Dst = AllocatePool (*NumPtr * sizeof (CHAR8 *) + Len);
+ CopyMem ((VOID*)&Dst[*NumPtr], Strings, Len);
+ FreePool (Strings);
+
+ /* Extract pointers to newly allocated array. */
+ Strings = (CHAR8 *) &Dst[*NumPtr];
+ ExtractStrings (Strings, Len, Dst);
+
+ return (Dst);
+}
+
+/**
+ Convert from watch token (unique identifier) to the associated
+ internal tracking structure for this watch.
+
+ @param Tocken The unique identifier for the watch to find.
+
+ @return A pointer to the found watch structure or NULL.
+**/
+STATIC
+XENSTORE_WATCH *
+XenStoreFindWatch (
+ IN CONST CHAR8 *Token
+ )
+{
+ XENSTORE_WATCH *Watch, *WantedWatch;
+ LIST_ENTRY *Entry;
+
+ WantedWatch = (VOID *) AsciiStrHexToUintn (Token);
+
+ if (IsListEmpty (&xs.RegisteredWatches)) {
+ return NULL;
+ }
+ for (Entry = GetFirstNode (&xs.RegisteredWatches);
+ !IsNull (&xs.RegisteredWatches, Entry);
+ Entry = GetNextNode (&xs.RegisteredWatches, Entry)) {
+ Watch = XENSTORE_WATCH_FROM_LINK (Entry);
+ if (Watch == WantedWatch)
+ return Watch;
+ }
+
+ return NULL;
+}
+
+//
+// Public Utility Functions
+// API comments for these methods can be found in XenStore.h
+//
+
+CHAR8 *
+XenStoreJoin (
+ IN CONST CHAR8 *DirectoryPath,
+ IN CONST CHAR8 *Node
+ )
+{
+ CHAR8 *Buf;
+ UINTN BufSize;
+
+ /* +1 for '/' and +1 for '\0' */
+ BufSize = AsciiStrLen (DirectoryPath) + AsciiStrLen (Node) + 2;
+ Buf = AllocatePool (BufSize);
+ ASSERT (Buf != NULL);
+
+ if (Node[0] == '\0') {
+ AsciiSPrint (Buf, BufSize, "%a", DirectoryPath);
+ } else {
+ AsciiSPrint (Buf, BufSize, "%a/%a", DirectoryPath, Node);
+ }
+
+ return Buf;
+}
+
+//
+// Low Level Communication Management
+//
+
+/**
+ Verify that the indexes for a ring are valid.
+
+ The difference between the producer and consumer cannot
+ exceed the size of the ring.
+
+ @param Cons The consumer index for the ring to test.
+ @param Prod The producer index for the ring to test.
+
+ @retval TRUE If indexes are in range.
+ @retval FALSE If the indexes are out of range.
+**/
+STATIC
+BOOLEAN
+XenStoreCheckIndexes (
+ XENSTORE_RING_IDX Cons,
+ XENSTORE_RING_IDX Prod
+ )
+{
+ return ((Prod - Cons) <= XENSTORE_RING_SIZE);
+}
+
+/**
+ Return a pointer to, and the length of, the contiguous
+ free region available for output in a ring buffer.
+
+ @param Cons The consumer index for the ring.
+ @param Prod The producer index for the ring.
+ @param Buffer The base address of the ring's storage.
+ @param LenPtr The amount of contiguous storage available.
+
+ @return A pointer to the start location of the free region.
+**/
+STATIC
+VOID *
+XenStoreGetOutputChunk (
+ IN XENSTORE_RING_IDX Cons,
+ IN XENSTORE_RING_IDX Prod,
+ IN CHAR8 *Buffer,
+ OUT UINT32 *LenPtr
+ )
+{
+ UINT32 Len;
+ Len = XENSTORE_RING_SIZE - MASK_XENSTORE_IDX (Prod);
+ if ((XENSTORE_RING_SIZE - (Prod - Cons)) < Len) {
+ Len = XENSTORE_RING_SIZE - (Prod - Cons);
+ }
+ *LenPtr = Len;
+ return (Buffer + MASK_XENSTORE_IDX (Prod));
+}
+
+/**
+ Return a pointer to, and the length of, the contiguous
+ data available to read from a ring buffer.
+
+ @param Cons The consumer index for the ring.
+ @param Prod The producer index for the ring.
+ @param Buffer The base address of the ring's storage.
+ @param LenPtr The amount of contiguous data available to read.
+
+ @return A pointer to the start location of the available data.
+**/
+STATIC
+CONST VOID *
+XenStoreGetInputChunk (
+ IN XENSTORE_RING_IDX Cons,
+ IN XENSTORE_RING_IDX Prod,
+ IN CONST CHAR8 *Buffer,
+ OUT UINT32 *LenPtr
+ )
+{
+ UINT32 Len;
+
+ Len = XENSTORE_RING_SIZE - MASK_XENSTORE_IDX (Cons);
+ if ((Prod - Cons) < Len) {
+ Len = Prod - Cons;
+ }
+ *LenPtr = Len;
+ return (Buffer + MASK_XENSTORE_IDX (Cons));
+}
+
+/**
+ Wait for an event or timeout.
+
+ @param Event Event to wait for.
+ @param Timeout A timeout value in 100ns units.
+
+ @retval EFI_SUCCESS Event have been triggered or the current TPL is not
+ TPL_APPLICATION.
+ @retval EFI_TIMEOUT Timeout have expired.
+**/
+STATIC
+EFI_STATUS
+XenStoreWaitForEvent (
+ IN EFI_EVENT Event,
+ IN UINT64 Timeout
+ )
+{
+ UINTN Index;
+ EFI_STATUS Status;
+ EFI_EVENT TimerEvent;
+ EFI_EVENT WaitList[2];
+
+ gBS->CreateEvent (EVT_TIMER, 0, NULL, NULL, &TimerEvent);
+ gBS->SetTimer (TimerEvent, TimerRelative, Timeout);
+
+ WaitList[0] = xs.EventChannelEvent;
+ WaitList[1] = TimerEvent;
+ Status = gBS->WaitForEvent (2, WaitList, &Index);
+ ASSERT (Status != EFI_INVALID_PARAMETER);
+ gBS->CloseEvent (TimerEvent);
+ if (Status == EFI_UNSUPPORTED) {
+ return EFI_SUCCESS;
+ }
+ if (Index == 1) {
+ return EFI_TIMEOUT;
+ } else {
+ return EFI_SUCCESS;
+ }
+}
+
+/**
+ Transmit data to the XenStore service.
+
+ The buffer pointed to by DataPtr is at least Len bytes in length.
+
+ @param DataPtr A pointer to the contiguous data to send.
+ @param Len The amount of data to send.
+
+ @return On success 0, otherwise an errno value indicating the
+ cause of failure.
+**/
+STATIC
+XENSTORE_STATUS
+XenStoreWriteStore (
+ IN CONST VOID *DataPtr,
+ IN UINT32 Len
+ )
+{
+ XENSTORE_RING_IDX Cons, Prod;
+ CONST CHAR8 *Data = (CONST CHAR8 *)DataPtr;
+
+ while (Len != 0) {
+ void *Dest;
+ UINT32 Available;
+
+ Cons = xs.XenStore->req_cons;
+ Prod = xs.XenStore->req_prod;
+ if ((Prod - Cons) == XENSTORE_RING_SIZE) {
+ /*
+ * Output ring is full. Wait for a ring event.
+ *
+ * Note that the events from both queues are combined, so being woken
+ * does not guarantee that data exist in the read ring.
+ */
+ EFI_STATUS Status;
+
+ Status = XenStoreWaitForEvent (xs.EventChannelEvent,
+ EFI_TIMER_PERIOD_SECONDS (1));
+ if (Status == EFI_TIMEOUT) {
+ DEBUG ((DEBUG_WARN, "XenStore Write, waiting for a ring event.\n"));
+ }
+ continue;
+ }
+
+ /* Verify queue sanity. */
+ if (!XenStoreCheckIndexes (Cons, Prod)) {
+ xs.XenStore->req_cons = xs.XenStore->req_prod = 0;
+ return XENSTORE_STATUS_EIO;
+ }
+
+ Dest = XenStoreGetOutputChunk (Cons, Prod, xs.XenStore->req, &Available);
+ if (Available > Len) {
+ Available = Len;
+ }
+
+ CopyMem (Dest, Data, Available);
+ Data += Available;
+ Len -= Available;
+
+ /*
+ * The store to the producer index, which indicates
+ * to the other side that new data has arrived, must
+ * be visible only after our copy of the data into the
+ * ring has completed.
+ */
+ MemoryFence ();
+ xs.XenStore->req_prod += Available;
+
+ /*
+ * The other side will see the change to req_prod at the time of the
+ * interrupt.
+ */
+ MemoryFence ();
+ XenEventChannelNotify (xs.Dev, xs.EventChannel);
+ }
+
+ return XENSTORE_STATUS_SUCCESS;
+}
+
+/**
+ Receive data from the XenStore service.
+
+ The buffer pointed to by DataPtr is at least Len bytes in length.
+
+ @param DataPtr A pointer to the contiguous buffer to receive the data.
+ @param Len The amount of data to receive.
+
+ @return On success 0, otherwise an errno value indicating the
+ cause of failure.
+**/
+STATIC
+XENSTORE_STATUS
+XenStoreReadStore (
+ OUT VOID *DataPtr,
+ IN UINT32 Len
+ )
+{
+ XENSTORE_RING_IDX Cons, Prod;
+ CHAR8 *Data = (CHAR8 *) DataPtr;
+
+ while (Len != 0) {
+ UINT32 Available;
+ CONST CHAR8 *Src;
+
+ Cons = xs.XenStore->rsp_cons;
+ Prod = xs.XenStore->rsp_prod;
+ if (Cons == Prod) {
+ /*
+ * Nothing to read. Wait for a ring event.
+ *
+ * Note that the events from both queues are combined, so being woken
+ * does not guarantee that data exist in the read ring.
+ */
+ EFI_STATUS Status;
+
+ Status = XenStoreWaitForEvent (xs.EventChannelEvent,
+ EFI_TIMER_PERIOD_SECONDS (1));
+ if (Status == EFI_TIMEOUT) {
+ DEBUG ((DEBUG_WARN, "XenStore Read, waiting for a ring event.\n"));
+ }
+ continue;
+ }
+
+ /* Verify queue sanity. */
+ if (!XenStoreCheckIndexes (Cons, Prod)) {
+ xs.XenStore->rsp_cons = xs.XenStore->rsp_prod = 0;
+ return XENSTORE_STATUS_EIO;
+ }
+
+ Src = XenStoreGetInputChunk (Cons, Prod, xs.XenStore->rsp, &Available);
+ if (Available > Len) {
+ Available = Len;
+ }
+
+ /*
+ * Insure the data we read is related to the indexes
+ * we read above.
+ */
+ MemoryFence ();
+
+ CopyMem (Data, Src, Available);
+ Data += Available;
+ Len -= Available;
+
+ /*
+ * Insure that the producer of this ring does not see
+ * the ring space as free until after we have copied it
+ * out.
+ */
+ MemoryFence ();
+ xs.XenStore->rsp_cons += Available;
+
+ /*
+ * The producer will see the updated consumer index when the event is
+ * delivered.
+ */
+ MemoryFence ();
+ XenEventChannelNotify (xs.Dev, xs.EventChannel);
+ }
+
+ return XENSTORE_STATUS_SUCCESS;
+}
+
+//
+// Received Message Processing
+//
+
+/**
+ Block reading the next message from the XenStore service and
+ process the result.
+
+ @return XENSTORE_STATUS_SUCCESS on success. Otherwise an errno value
+ indicating the type of failure encountered.
+**/
+STATIC
+XENSTORE_STATUS
+XenStoreProcessMessage (
+ VOID
+ )
+{
+ XENSTORE_MESSAGE *Message;
+ CHAR8 *Body;
+ XENSTORE_STATUS Status;
+
+ Message = AllocateZeroPool (sizeof (XENSTORE_MESSAGE));
+ Message->Signature = XENSTORE_MESSAGE_SIGNATURE;
+ Status = XenStoreReadStore (&Message->Header, sizeof (Message->Header));
+ if (Status != XENSTORE_STATUS_SUCCESS) {
+ FreePool (Message);
+ DEBUG ((DEBUG_ERROR, "XenStore: Error read store (%d)\n", Status));
+ return Status;
+ }
+
+ Body = AllocatePool (Message->Header.len + 1);
+ Status = XenStoreReadStore (Body, Message->Header.len);
+ if (Status != XENSTORE_STATUS_SUCCESS) {
+ FreePool (Body);
+ FreePool (Message);
+ DEBUG ((DEBUG_ERROR, "XenStore: Error read store (%d)\n", Status));
+ return Status;
+ }
+ Body[Message->Header.len] = '\0';
+
+ if (Message->Header.type == XS_WATCH_EVENT) {
+ Message->u.Watch.Vector = Split(Body, Message->Header.len,
+ &Message->u.Watch.VectorSize);
+
+ EfiAcquireLock (&xs.RegisteredWatchesLock);
+ Message->u.Watch.Handle =
+ XenStoreFindWatch (Message->u.Watch.Vector[XS_WATCH_TOKEN]);
+ DEBUG ((DEBUG_INFO, "XenStore: Watch event %a\n",
+ Message->u.Watch.Vector[XS_WATCH_TOKEN]));
+ if (Message->u.Watch.Handle != NULL) {
+ EfiAcquireLock (&xs.WatchEventsLock);
+ InsertHeadList (&xs.WatchEvents, &Message->Link);
+ EfiReleaseLock (&xs.WatchEventsLock);
+ } else {
+ DEBUG ((DEBUG_WARN, "XenStore: Watch handle %a not found\n",
+ Message->u.Watch.Vector[XS_WATCH_TOKEN]));
+ FreePool((VOID*)Message->u.Watch.Vector);
+ FreePool(Message);
+ }
+ EfiReleaseLock (&xs.RegisteredWatchesLock);
+ } else {
+ Message->u.Reply.Body = Body;
+ EfiAcquireLock (&xs.ReplyLock);
+ InsertTailList (&xs.ReplyList, &Message->Link);
+ EfiReleaseLock (&xs.ReplyLock);
+ }
+
+ return XENSTORE_STATUS_SUCCESS;
+}
+
+//
+// XenStore Message Request/Reply Processing
+//
+
+/**
+ Convert a XenStore error string into an errno number.
+
+ Unknown error strings are converted to EINVAL.
+
+ @param errorstring The error string to convert.
+
+ @return The errno best matching the input string.
+
+**/
+typedef struct {
+ XENSTORE_STATUS Status;
+ CONST CHAR8 *ErrorStr;
+} XenStoreErrors;
+
+static XenStoreErrors gXenStoreErrors[] = {
+ { XENSTORE_STATUS_EINVAL, "EINVAL" },
+ { XENSTORE_STATUS_EACCES, "EACCES" },
+ { XENSTORE_STATUS_EEXIST, "EEXIST" },
+ { XENSTORE_STATUS_EISDIR, "EISDIR" },
+ { XENSTORE_STATUS_ENOENT, "ENOENT" },
+ { XENSTORE_STATUS_ENOMEM, "ENOMEM" },
+ { XENSTORE_STATUS_ENOSPC, "ENOSPC" },
+ { XENSTORE_STATUS_EIO, "EIO" },
+ { XENSTORE_STATUS_ENOTEMPTY, "ENOTEMPTY" },
+ { XENSTORE_STATUS_ENOSYS, "ENOSYS" },
+ { XENSTORE_STATUS_EROFS, "EROFS" },
+ { XENSTORE_STATUS_EBUSY, "EBUSY" },
+ { XENSTORE_STATUS_EAGAIN, "EAGAIN" },
+ { XENSTORE_STATUS_EISCONN, "EISCONN" },
+ { XENSTORE_STATUS_E2BIG, "E2BIG" }
+};
+
+STATIC
+XENSTORE_STATUS
+XenStoreGetError (
+ CONST CHAR8 *ErrorStr
+ )
+{
+ UINT32 Index;
+
+ for (Index = 0; Index < ARRAY_SIZE(gXenStoreErrors); Index++) {
+ if (!AsciiStrCmp (ErrorStr, gXenStoreErrors[Index].ErrorStr)) {
+ return gXenStoreErrors[Index].Status;
+ }
+ }
+ DEBUG ((DEBUG_WARN, "XenStore gave unknown error %a\n", ErrorStr));
+ return XENSTORE_STATUS_EINVAL;
+}
+
+/**
+ Block waiting for a reply to a message request.
+
+ @param TypePtr The returned type of the reply.
+ @param LenPtr The returned body length of the reply.
+ @param Result The returned body of the reply.
+**/
+STATIC
+XENSTORE_STATUS
+XenStoreReadReply (
+ OUT enum xsd_sockmsg_type *TypePtr,
+ OUT UINT32 *LenPtr OPTIONAL,
+ OUT VOID **Result
+ )
+{
+ XENSTORE_MESSAGE *Message;
+ LIST_ENTRY *Entry;
+ CHAR8 *Body;
+
+ while (IsListEmpty (&xs.ReplyList)) {
+ XENSTORE_STATUS Status;
+ Status = XenStoreProcessMessage ();
+ if (Status != XENSTORE_STATUS_SUCCESS && Status != XENSTORE_STATUS_EAGAIN) {
+ DEBUG ((DEBUG_ERROR, "XenStore, error while reading the ring (%d).",
+ Status));
+ return Status;
+ }
+ }
+ EfiAcquireLock (&xs.ReplyLock);
+ Entry = GetFirstNode (&xs.ReplyList);
+ Message = XENSTORE_MESSAGE_FROM_LINK (Entry);
+ RemoveEntryList (Entry);
+ EfiReleaseLock (&xs.ReplyLock);
+
+ *TypePtr = Message->Header.type;
+ if (LenPtr != NULL) {
+ *LenPtr = Message->Header.len;
+ }
+ Body = Message->u.Reply.Body;
+
+ FreePool (Message);
+ *Result = Body;
+ return XENSTORE_STATUS_SUCCESS;
+}
+
+/**
+ Send a message with an optionally multi-part body to the XenStore service.
+
+ @param Transaction The transaction to use for this request.
+ @param RequestType The type of message to send.
+ @param WriteRequest Pointers to the body sections of the request.
+ @param NumRequests The number of body sections in the request.
+ @param LenPtr The returned length of the reply.
+ @param ResultPtr The returned body of the reply.
+
+ @return XENSTORE_STATUS_SUCCESS on success. Otherwise an errno indicating
+ the cause of failure.
+**/
+STATIC
+XENSTORE_STATUS
+XenStoreTalkv (
+ IN CONST XENSTORE_TRANSACTION *Transaction,
+ IN enum xsd_sockmsg_type RequestType,
+ IN CONST WRITE_REQUEST *WriteRequest,
+ IN UINT32 NumRequests,
+ OUT UINT32 *LenPtr OPTIONAL,
+ OUT VOID **ResultPtr OPTIONAL
+ )
+{
+ struct xsd_sockmsg Message;
+ void *Return = NULL;
+ UINT32 Index;
+ XENSTORE_STATUS Status;
+
+ if (Transaction == XST_NIL) {
+ Message.tx_id = 0;
+ } else {
+ Message.tx_id = Transaction->Id;
+ }
+ Message.req_id = 0;
+ Message.type = RequestType;
+ Message.len = 0;
+ for (Index = 0; Index < NumRequests; Index++) {
+ Message.len += WriteRequest[Index].Len;
+ }
+
+ Status = XenStoreWriteStore (&Message, sizeof (Message));
+ if (Status != XENSTORE_STATUS_SUCCESS) {
+ DEBUG ((DEBUG_ERROR, "XenStoreTalkv failed %d\n", Status));
+ goto Error;
+ }
+
+ for (Index = 0; Index < NumRequests; Index++) {
+ Status = XenStoreWriteStore (WriteRequest[Index].Data, WriteRequest[Index].Len);
+ if (Status != XENSTORE_STATUS_SUCCESS) {
+ DEBUG ((DEBUG_ERROR, "XenStoreTalkv failed %d\n", Status));
+ goto Error;
+ }
+ }
+
+ Status = XenStoreReadReply ((enum xsd_sockmsg_type *)&Message.type, LenPtr, &Return);
+
+Error:
+ if (Status != XENSTORE_STATUS_SUCCESS) {
+ return Status;
+ }
+
+ if (Message.type == XS_ERROR) {
+ Status = XenStoreGetError (Return);
+ FreePool (Return);
+ return Status;
+ }
+
+ /* Reply is either error or an echo of our request message type. */
+ ASSERT ((enum xsd_sockmsg_type)Message.type == RequestType);
+
+ if (ResultPtr) {
+ *ResultPtr = Return;
+ } else {
+ FreePool (Return);
+ }
+
+ return XENSTORE_STATUS_SUCCESS;
+}
+
+/**
+ Wrapper for XenStoreTalkv allowing easy transmission of a message with
+ a single, contiguous, message body.
+
+ The returned result is provided in malloced storage and thus must be free'd
+ by the caller.
+
+ @param Transaction The transaction to use for this request.
+ @param RequestType The type of message to send.
+ @param Body The body of the request.
+ @param LenPtr The returned length of the reply.
+ @param Result The returned body of the reply.
+
+ @return 0 on success. Otherwise an errno indicating
+ the cause of failure.
+**/
+STATIC
+XENSTORE_STATUS
+XenStoreSingle (
+ IN CONST XENSTORE_TRANSACTION *Transaction,
+ IN enum xsd_sockmsg_type RequestType,
+ IN CONST CHAR8 *Body,
+ OUT UINT32 *LenPtr OPTIONAL,
+ OUT VOID **Result OPTIONAL
+ )
+{
+ WRITE_REQUEST WriteRequest;
+
+ WriteRequest.Data = (VOID *) Body;
+ WriteRequest.Len = (UINT32)AsciiStrSize (Body);
+
+ return XenStoreTalkv (Transaction, RequestType, &WriteRequest, 1,
+ LenPtr, Result);
+}
+
+//
+// XenStore Watch Support
+//
+
+/**
+ Transmit a watch request to the XenStore service.
+
+ @param Path The path in the XenStore to watch.
+ @param Tocken A unique identifier for this watch.
+
+ @return XENSTORE_STATUS_SUCCESS on success. Otherwise an errno indicating the
+ cause of failure.
+**/
+STATIC
+XENSTORE_STATUS
+XenStoreWatch (
+ CONST CHAR8 *Path,
+ CONST CHAR8 *Token
+ )
+{
+ WRITE_REQUEST WriteRequest[2];
+
+ WriteRequest[0].Data = (VOID *) Path;
+ WriteRequest[0].Len = (UINT32)AsciiStrSize (Path);
+ WriteRequest[1].Data = (VOID *) Token;
+ WriteRequest[1].Len = (UINT32)AsciiStrSize (Token);
+
+ return XenStoreTalkv (XST_NIL, XS_WATCH, WriteRequest, 2, NULL, NULL);
+}
+
+/**
+ Transmit an uwatch request to the XenStore service.
+
+ @param Path The path in the XenStore to watch.
+ @param Tocken A unique identifier for this watch.
+
+ @return XENSTORE_STATUS_SUCCESS on success. Otherwise an errno indicating
+ the cause of failure.
+**/
+STATIC
+XENSTORE_STATUS
+XenStoreUnwatch (
+ CONST CHAR8 *Path,
+ CONST CHAR8 *Token
+ )
+{
+ WRITE_REQUEST WriteRequest[2];
+
+ WriteRequest[0].Data = (VOID *) Path;
+ WriteRequest[0].Len = (UINT32)AsciiStrSize (Path);
+ WriteRequest[1].Data = (VOID *) Token;
+ WriteRequest[1].Len = (UINT32)AsciiStrSize (Token);
+
+ return XenStoreTalkv (XST_NIL, XS_UNWATCH, WriteRequest, 2, NULL, NULL);
+}
+
+STATIC
+XENSTORE_STATUS
+XenStoreWaitWatch (
+ VOID *Token
+ )
+{
+ XENSTORE_MESSAGE *Message;
+ LIST_ENTRY *Entry = NULL;
+ LIST_ENTRY *Last = NULL;
+ XENSTORE_STATUS Status;
+
+ while (TRUE) {
+ EfiAcquireLock (&xs.WatchEventsLock);
+ if (IsListEmpty (&xs.WatchEvents) ||
+ Last == GetFirstNode (&xs.WatchEvents)) {
+ EfiReleaseLock (&xs.WatchEventsLock);
+ Status = XenStoreProcessMessage ();
+ if (Status != XENSTORE_STATUS_SUCCESS && Status != XENSTORE_STATUS_EAGAIN) {
+ return Status;
+ }
+ continue;
+ }
+
+ for (Entry = GetFirstNode (&xs.WatchEvents);
+ Entry != Last && !IsNull (&xs.WatchEvents, Entry);
+ Entry = GetNextNode (&xs.WatchEvents, Entry)) {
+ Message = XENSTORE_MESSAGE_FROM_LINK (Entry);
+ if (Message->u.Watch.Handle == Token) {
+ RemoveEntryList (Entry);
+ EfiReleaseLock (&xs.WatchEventsLock);
+ FreePool((VOID*)Message->u.Watch.Vector);
+ FreePool(Message);
+ return XENSTORE_STATUS_SUCCESS;
+ }
+ }
+ Last = GetFirstNode (&xs.WatchEvents);
+ EfiReleaseLock (&xs.WatchEventsLock);
+ }
+}
+
+VOID
+EFIAPI
+NotifyEventChannelCheckForEvent (
+ IN EFI_EVENT Event,
+ IN VOID *Context
+ )
+{
+ XENSTORE_PRIVATE *xsp;
+ xsp = (XENSTORE_PRIVATE *)Context;
+ if (TestAndClearBit (xsp->EventChannel, xsp->Dev->SharedInfo->evtchn_pending)) {
+ gBS->SignalEvent (Event);
+ }
+}
+
+/**
+ Setup communication channels with the XenStore service.
+
+ @retval EFI_SUCCESS if everything went well.
+**/
+STATIC
+EFI_STATUS
+XenStoreInitComms (
+ XENSTORE_PRIVATE *xsp
+ )
+{
+ EFI_STATUS Status;
+ EFI_EVENT TimerEvent;
+ struct xenstore_domain_interface *XenStore = xsp->XenStore;
+
+ Status = gBS->CreateEvent (EVT_TIMER, 0, NULL, NULL, &TimerEvent);
+ Status = gBS->SetTimer (TimerEvent, TimerRelative,
+ EFI_TIMER_PERIOD_SECONDS (5));
+ while (XenStore->rsp_prod != XenStore->rsp_cons) {
+ Status = gBS->CheckEvent (TimerEvent);
+ if (!EFI_ERROR (Status)) {
+ DEBUG ((DEBUG_WARN, "XENSTORE response ring is not quiescent "
+ "(%08x:%08x): fixing up\n",
+ XenStore->rsp_cons, XenStore->rsp_prod));
+ XenStore->rsp_cons = XenStore->rsp_prod;
+ }
+ }
+ gBS->CloseEvent (TimerEvent);
+
+ Status = gBS->CreateEvent (EVT_NOTIFY_WAIT, TPL_NOTIFY,
+ NotifyEventChannelCheckForEvent, xsp,
+ &xsp->EventChannelEvent);
+ ASSERT_EFI_ERROR (Status);
+
+ return Status;
+}
+
+/**
+ Initialize XenStore.
+
+ @param Dev A XENBUS_DEVICE instance.
+
+ @retval EFI_SUCCESS if everything went well.
+**/
+EFI_STATUS
+XenStoreInit (
+ XENBUS_DEVICE *Dev
+ )
+{
+ EFI_STATUS Status;
+ /**
+ * The HVM guest pseudo-physical frame number. This is Xen's mapping
+ * of the true machine frame number into our "physical address space".
+ */
+ UINTN XenStoreGpfn;
+
+ xs.Dev = Dev;
+
+ xs.EventChannel = (evtchn_port_t)XenHypercallHvmGetParam (HVM_PARAM_STORE_EVTCHN);
+ XenStoreGpfn = (UINTN)XenHypercallHvmGetParam (HVM_PARAM_STORE_PFN);
+ xs.XenStore = (VOID *) (XenStoreGpfn << EFI_PAGE_SHIFT);
+ DEBUG ((DEBUG_INFO, "XenBusInit: XenBus rings @%p, event channel %x\n",
+ xs.XenStore, xs.EventChannel));
+
+ InitializeListHead (&xs.ReplyList);
+ InitializeListHead (&xs.WatchEvents);
+ InitializeListHead (&xs.RegisteredWatches);
+
+ EfiInitializeLock (&xs.ReplyLock, TPL_NOTIFY);
+ EfiInitializeLock (&xs.RegisteredWatchesLock, TPL_NOTIFY);
+ EfiInitializeLock (&xs.WatchEventsLock, TPL_NOTIFY);
+
+ /* Initialize the shared memory rings to talk to xenstored */
+ Status = XenStoreInitComms (&xs);
+
+ return Status;
+}
+
+VOID
+XenStoreDeinit (
+ IN XENBUS_DEVICE *Dev
+ )
+{
+ //
+ // Emptying the list RegisteredWatches, but this list should already be
+ // empty. Every driver that is using Watches should unregister them when
+ // it is stopped.
+ //
+ if (!IsListEmpty (&xs.RegisteredWatches)) {
+ XENSTORE_WATCH *Watch;
+ LIST_ENTRY *Entry;
+ DEBUG ((DEBUG_WARN, "XenStore: RegisteredWatches is not empty, cleaning up..."));
+ Entry = GetFirstNode (&xs.RegisteredWatches);
+ while (!IsNull (&xs.RegisteredWatches, Entry)) {
+ Watch = XENSTORE_WATCH_FROM_LINK (Entry);
+ Entry = GetNextNode (&xs.RegisteredWatches, Entry);
+
+ XenStoreUnregisterWatch (Watch);
+ }
+ }
+
+ //
+ // Emptying the list WatchEvents, but this list should already be empty after
+ // having cleanup the list RegisteredWatches.
+ //
+ if (!IsListEmpty (&xs.WatchEvents)) {
+ LIST_ENTRY *Entry;
+ DEBUG ((DEBUG_WARN, "XenStore: WatchEvents is not empty, cleaning up..."));
+ Entry = GetFirstNode (&xs.WatchEvents);
+ while (!IsNull (&xs.WatchEvents, Entry)) {
+ XENSTORE_MESSAGE *Message = XENSTORE_MESSAGE_FROM_LINK (Entry);
+ Entry = GetNextNode (&xs.WatchEvents, Entry);
+ RemoveEntryList (&Message->Link);
+ FreePool ((VOID*)Message->u.Watch.Vector);
+ FreePool (Message);
+ }
+ }
+
+ if (!IsListEmpty (&xs.ReplyList)) {
+ XENSTORE_MESSAGE *Message;
+ LIST_ENTRY *Entry;
+ Entry = GetFirstNode (&xs.ReplyList);
+ while (!IsNull (&xs.ReplyList, Entry)) {
+ Message = XENSTORE_MESSAGE_FROM_LINK (Entry);
+ Entry = GetNextNode (&xs.ReplyList, Entry);
+ RemoveEntryList (&Message->Link);
+ FreePool (Message->u.Reply.Body);
+ FreePool (Message);
+ }
+ }
+
+ gBS->CloseEvent (xs.EventChannelEvent);
+
+ if (xs.XenStore->server_features & XENSTORE_SERVER_FEATURE_RECONNECTION) {
+ xs.XenStore->connection = XENSTORE_RECONNECT;
+ XenEventChannelNotify (xs.Dev, xs.EventChannel);
+ while (*(volatile UINT32*)&xs.XenStore->connection == XENSTORE_RECONNECT) {
+ XenStoreWaitForEvent (xs.EventChannelEvent, EFI_TIMER_PERIOD_MILLISECONDS (100));
+ }
+ } else {
+ /* If the backend reads the state while we're erasing it then the
+ * ring state will become corrupted, preventing guest frontends from
+ * connecting. This is rare. To help diagnose the failure, we fill
+ * the ring with XS_INVALID packets. */
+ SetMem (xs.XenStore->req, XENSTORE_RING_SIZE, 0xff);
+ SetMem (xs.XenStore->rsp, XENSTORE_RING_SIZE, 0xff);
+ xs.XenStore->req_cons = xs.XenStore->req_prod = 0;
+ xs.XenStore->rsp_cons = xs.XenStore->rsp_prod = 0;
+ }
+ xs.XenStore = NULL;
+}
+
+//
+// Public API
+// API comments for these methods can be found in XenStore.h
+//
+
+XENSTORE_STATUS
+XenStoreListDirectory (
+ IN CONST XENSTORE_TRANSACTION *Transaction,
+ IN CONST CHAR8 *DirectoryPath,
+ IN CONST CHAR8 *Node,
+ OUT UINT32 *DirectoryCountPtr,
+ OUT CONST CHAR8 ***DirectoryListPtr
+ )
+{
+ CHAR8 *Path;
+ CHAR8 *TempStr;
+ UINT32 Len = 0;
+ XENSTORE_STATUS Status;
+
+ Path = XenStoreJoin (DirectoryPath, Node);
+ Status = XenStoreSingle (Transaction, XS_DIRECTORY, Path, &Len,
+ (VOID **) &TempStr);
+ FreePool (Path);
+ if (Status != XENSTORE_STATUS_SUCCESS) {
+ return Status;
+ }
+
+ *DirectoryListPtr = Split (TempStr, Len, DirectoryCountPtr);
+
+ return XENSTORE_STATUS_SUCCESS;
+}
+
+BOOLEAN
+XenStorePathExists (
+ IN CONST XENSTORE_TRANSACTION *Transaction,
+ IN CONST CHAR8 *Directory,
+ IN CONST CHAR8 *Node
+ )
+{
+ CONST CHAR8 **TempStr;
+ XENSTORE_STATUS Status;
+ UINT32 TempNum;
+
+ Status = XenStoreListDirectory (Transaction, Directory, Node,
+ &TempNum, &TempStr);
+ if (Status != XENSTORE_STATUS_SUCCESS) {
+ return FALSE;
+ }
+ FreePool ((VOID*)TempStr);
+ return TRUE;
+}
+
+XENSTORE_STATUS
+XenStoreRead (
+ IN CONST XENSTORE_TRANSACTION *Transaction,
+ IN CONST CHAR8 *DirectoryPath,
+ IN CONST CHAR8 *Node,
+ OUT UINT32 *LenPtr OPTIONAL,
+ OUT VOID **Result
+ )
+{
+ CHAR8 *Path;
+ VOID *Value;
+ XENSTORE_STATUS Status;
+
+ Path = XenStoreJoin (DirectoryPath, Node);
+ Status = XenStoreSingle (Transaction, XS_READ, Path, LenPtr, &Value);
+ FreePool (Path);
+ if (Status != XENSTORE_STATUS_SUCCESS) {
+ return Status;
+ }
+
+ *Result = Value;
+ return XENSTORE_STATUS_SUCCESS;
+}
+
+XENSTORE_STATUS
+XenStoreWrite (
+ IN CONST XENSTORE_TRANSACTION *Transaction,
+ IN CONST CHAR8 *DirectoryPath,
+ IN CONST CHAR8 *Node,
+ IN CONST CHAR8 *Str
+ )
+{
+ CHAR8 *Path;
+ WRITE_REQUEST WriteRequest[2];
+ XENSTORE_STATUS Status;
+
+ Path = XenStoreJoin (DirectoryPath, Node);
+
+ WriteRequest[0].Data = (VOID *) Path;
+ WriteRequest[0].Len = (UINT32)AsciiStrSize (Path);
+ WriteRequest[1].Data = (VOID *) Str;
+ WriteRequest[1].Len = (UINT32)AsciiStrLen (Str);
+
+ Status = XenStoreTalkv (Transaction, XS_WRITE, WriteRequest, 2, NULL, NULL);
+ FreePool (Path);
+
+ return Status;
+}
+
+XENSTORE_STATUS
+XenStoreRemove (
+ IN CONST XENSTORE_TRANSACTION *Transaction,
+ IN CONST CHAR8 *DirectoryPath,
+ IN CONST CHAR8 *Node
+ )
+{
+ CHAR8 *Path;
+ XENSTORE_STATUS Status;
+
+ Path = XenStoreJoin (DirectoryPath, Node);
+ Status = XenStoreSingle (Transaction, XS_RM, Path, NULL, NULL);
+ FreePool (Path);
+
+ return Status;
+}
+
+XENSTORE_STATUS
+XenStoreTransactionStart (
+ OUT XENSTORE_TRANSACTION *Transaction
+ )
+{
+ CHAR8 *IdStr;
+ XENSTORE_STATUS Status;
+
+ Status = XenStoreSingle (XST_NIL, XS_TRANSACTION_START, "", NULL,
+ (VOID **) &IdStr);
+ if (Status == XENSTORE_STATUS_SUCCESS) {
+ Transaction->Id = (UINT32)AsciiStrDecimalToUintn (IdStr);
+ FreePool (IdStr);
+ }
+
+ return Status;
+}
+
+XENSTORE_STATUS
+XenStoreTransactionEnd (
+ IN CONST XENSTORE_TRANSACTION *Transaction,
+ IN BOOLEAN Abort
+ )
+{
+ CHAR8 AbortStr[2];
+
+ AbortStr[0] = Abort ? 'F' : 'T';
+ AbortStr[1] = '\0';
+
+ return XenStoreSingle (Transaction, XS_TRANSACTION_END, AbortStr, NULL, NULL);
+}
+
+XENSTORE_STATUS
+EFIAPI
+XenStoreVSPrint (
+ IN CONST XENSTORE_TRANSACTION *Transaction,
+ IN CONST CHAR8 *DirectoryPath,
+ IN CONST CHAR8 *Node,
+ IN CONST CHAR8 *FormatString,
+ IN VA_LIST Marker
+ )
+{
+ CHAR8 *Buf;
+ XENSTORE_STATUS Status;
+ UINTN BufSize;
+ VA_LIST Marker2;
+
+ VA_COPY (Marker2, Marker);
+ BufSize = SPrintLengthAsciiFormat (FormatString, Marker2) + 1;
+ VA_END (Marker2);
+ Buf = AllocateZeroPool (BufSize);
+ AsciiVSPrint (Buf, BufSize, FormatString, Marker);
+ Status = XenStoreWrite (Transaction, DirectoryPath, Node, Buf);
+ FreePool (Buf);
+
+ return Status;
+}
+
+XENSTORE_STATUS
+EFIAPI
+XenStoreSPrint (
+ IN CONST XENSTORE_TRANSACTION *Transaction,
+ IN CONST CHAR8 *DirectoryPath,
+ IN CONST CHAR8 *Node,
+ IN CONST CHAR8 *FormatString,
+ ...
+ )
+{
+ VA_LIST Marker;
+ XENSTORE_STATUS Status;
+
+ VA_START (Marker, FormatString);
+ Status = XenStoreVSPrint (Transaction, DirectoryPath, Node, FormatString, Marker);
+ VA_END (Marker);
+
+ return Status;
+}
+
+XENSTORE_STATUS
+XenStoreRegisterWatch (
+ IN CONST CHAR8 *DirectoryPath,
+ IN CONST CHAR8 *Node,
+ OUT XENSTORE_WATCH **WatchPtr
+ )
+{
+ /* Pointer in ascii is the token. */
+ CHAR8 Token[sizeof (XENSTORE_WATCH) * 2 + 1];
+ XENSTORE_STATUS Status;
+ XENSTORE_WATCH *Watch;
+
+ Watch = AllocateZeroPool (sizeof (XENSTORE_WATCH));
+ Watch->Signature = XENSTORE_WATCH_SIGNATURE;
+ Watch->Node = XenStoreJoin (DirectoryPath, Node);
+
+ EfiAcquireLock (&xs.RegisteredWatchesLock);
+ InsertTailList (&xs.RegisteredWatches, &Watch->Link);
+ EfiReleaseLock (&xs.RegisteredWatchesLock);
+
+ AsciiSPrint (Token, sizeof (Token), "%p", (VOID*) Watch);
+ Status = XenStoreWatch (Watch->Node, Token);
+
+ /* Ignore errors due to multiple registration. */
+ if (Status == XENSTORE_STATUS_EEXIST) {
+ Status = XENSTORE_STATUS_SUCCESS;
+ }
+
+ if (Status == XENSTORE_STATUS_SUCCESS) {
+ *WatchPtr = Watch;
+ } else {
+ EfiAcquireLock (&xs.RegisteredWatchesLock);
+ RemoveEntryList (&Watch->Link);
+ EfiReleaseLock (&xs.RegisteredWatchesLock);
+ FreePool (Watch->Node);
+ FreePool (Watch);
+ }
+
+ return Status;
+}
+
+VOID
+XenStoreUnregisterWatch (
+ IN XENSTORE_WATCH *Watch
+ )
+{
+ CHAR8 Token[sizeof (Watch) * 2 + 1];
+ LIST_ENTRY *Entry;
+
+ ASSERT (Watch->Signature == XENSTORE_WATCH_SIGNATURE);
+
+ AsciiSPrint (Token, sizeof (Token), "%p", (VOID *) Watch);
+ if (XenStoreFindWatch (Token) == NULL) {
+ return;
+ }
+
+ EfiAcquireLock (&xs.RegisteredWatchesLock);
+ RemoveEntryList (&Watch->Link);
+ EfiReleaseLock (&xs.RegisteredWatchesLock);
+
+ XenStoreUnwatch (Watch->Node, Token);
+
+ /* Cancel pending watch events. */
+ EfiAcquireLock (&xs.WatchEventsLock);
+ Entry = GetFirstNode (&xs.WatchEvents);
+ while (!IsNull (&xs.WatchEvents, Entry)) {
+ XENSTORE_MESSAGE *Message = XENSTORE_MESSAGE_FROM_LINK (Entry);
+ Entry = GetNextNode (&xs.WatchEvents, Entry);
+ if (Message->u.Watch.Handle == Watch) {
+ RemoveEntryList (&Message->Link);
+ FreePool ((VOID*)Message->u.Watch.Vector);
+ FreePool (Message);
+ }
+ }
+ EfiReleaseLock (&xs.WatchEventsLock);
+
+ FreePool (Watch->Node);
+ FreePool (Watch);
+}
+
+
+//
+// XENBUS protocol
+//
+
+XENSTORE_STATUS
+EFIAPI
+XenBusWaitForWatch (
+ IN XENBUS_PROTOCOL *This,
+ IN VOID *Token
+ )
+{
+ return XenStoreWaitWatch (Token);
+}
+
+XENSTORE_STATUS
+EFIAPI
+XenBusXenStoreRead (
+ IN XENBUS_PROTOCOL *This,
+ IN CONST XENSTORE_TRANSACTION *Transaction,
+ IN CONST CHAR8 *Node,
+ OUT VOID **Value
+ )
+{
+ return XenStoreRead (Transaction, This->Node, Node, NULL, Value);
+}
+
+XENSTORE_STATUS
+EFIAPI
+XenBusXenStoreBackendRead (
+ IN XENBUS_PROTOCOL *This,
+ IN CONST XENSTORE_TRANSACTION *Transaction,
+ IN CONST CHAR8 *Node,
+ OUT VOID **Value
+ )
+{
+ return XenStoreRead (Transaction, This->Backend, Node, NULL, Value);
+}
+
+XENSTORE_STATUS
+EFIAPI
+XenBusXenStoreRemove (
+ IN XENBUS_PROTOCOL *This,
+ IN CONST XENSTORE_TRANSACTION *Transaction,
+ IN const char *Node
+ )
+{
+ return XenStoreRemove (Transaction, This->Node, Node);
+}
+
+XENSTORE_STATUS
+EFIAPI
+XenBusXenStoreTransactionStart (
+ IN XENBUS_PROTOCOL *This,
+ OUT XENSTORE_TRANSACTION *Transaction
+ )
+{
+ return XenStoreTransactionStart (Transaction);
+}
+
+XENSTORE_STATUS
+EFIAPI
+XenBusXenStoreTransactionEnd (
+ IN XENBUS_PROTOCOL *This,
+ IN CONST XENSTORE_TRANSACTION *Transaction,
+ IN BOOLEAN Abort
+ )
+{
+ return XenStoreTransactionEnd (Transaction, Abort);
+}
+
+XENSTORE_STATUS
+EFIAPI
+XenBusXenStoreSPrint (
+ IN XENBUS_PROTOCOL *This,
+ IN CONST XENSTORE_TRANSACTION *Transaction,
+ IN CONST CHAR8 *DirectoryPath,
+ IN CONST CHAR8 *Node,
+ IN CONST CHAR8 *FormatString,
+ ...
+ )
+{
+ VA_LIST Marker;
+ XENSTORE_STATUS Status;
+
+ VA_START (Marker, FormatString);
+ Status = XenStoreVSPrint (Transaction, DirectoryPath, Node, FormatString, Marker);
+ VA_END (Marker);
+
+ return Status;
+}
+
+XENSTORE_STATUS
+EFIAPI
+XenBusRegisterWatch (
+ IN XENBUS_PROTOCOL *This,
+ IN CONST CHAR8 *Node,
+ OUT VOID **Token
+ )
+{
+ return XenStoreRegisterWatch (This->Node, Node, (XENSTORE_WATCH **) Token);
+}
+
+XENSTORE_STATUS
+EFIAPI
+XenBusRegisterWatchBackend (
+ IN XENBUS_PROTOCOL *This,
+ IN CONST CHAR8 *Node,
+ OUT VOID **Token
+ )
+{
+ return XenStoreRegisterWatch (This->Backend, Node, (XENSTORE_WATCH **) Token);
+}
+
+VOID
+EFIAPI
+XenBusUnregisterWatch (
+ IN XENBUS_PROTOCOL *This,
+ IN VOID *Token
+ )
+{
+ XenStoreUnregisterWatch ((XENSTORE_WATCH *) Token);
+}
diff --git a/roms/edk2/OvmfPkg/XenBusDxe/XenStore.h b/roms/edk2/OvmfPkg/XenBusDxe/XenStore.h new file mode 100644 index 000000000..effaad733 --- /dev/null +++ b/roms/edk2/OvmfPkg/XenBusDxe/XenStore.h @@ -0,0 +1,364 @@ +/** @file
+ Method declarations and structures for accessing the XenStore
+
+ Copyright (C) 2005 Rusty Russell, IBM Corporation
+ Copyright (C) 2005 XenSource Ltd.
+ Copyright (C) 2009,2010 Spectra Logic Corporation
+ Copyright (C) 2014, Citrix Ltd.
+
+ This file may be distributed separately from the Linux kernel, or
+ incorporated into other software packages, subject to the following license:
+
+ SPDX-License-Identifier: MIT
+**/
+
+#ifndef _XEN_XENSTORE_XENSTOREVAR_H
+#define _XEN_XENSTORE_XENSTOREVAR_H
+
+#include "XenBusDxe.h"
+
+#include <IndustryStandard/Xen/io/xs_wire.h>
+
+typedef struct _XENSTORE_WATCH XENSTORE_WATCH;
+
+/**
+ Fetch the contents of a directory in the XenStore.
+
+ @param Transaction The XenStore transaction covering this request.
+ @param DirectoryPath The dirname of the path to read.
+ @param Node The basename of the path to read.
+ @param DirectoryCountPtr The returned number of directory entries.
+ @param DirectoryListPtr An array of directory entry strings.
+
+ @return On success, XENSTORE_STATUS_SUCCESS. Otherwise an errno value
+ indicating the type of failure.
+
+ @note The results buffer is alloced and should be free'd by the
+ caller.
+**/
+XENSTORE_STATUS
+XenStoreListDirectory (
+ IN CONST XENSTORE_TRANSACTION *Transaction,
+ IN CONST CHAR8 *DirectoryPath,
+ IN CONST CHAR8 *Node,
+ OUT UINT32 *DirectoryCountPtr,
+ OUT CONST CHAR8 ***DirectoryListPtr
+ );
+
+/**
+ Determine if a path exists in the XenStore.
+
+ @param Transaction The XenStore transaction covering this request.
+ @param Directory The dirname of the path to read.
+ @param Node The basename of the path to read.
+
+ @retval TRUE The path exists.
+ @retval FALSE The path does not exist or an error occurred attempting
+ to make that determination.
+**/
+BOOLEAN
+XenStorePathExists (
+ IN CONST XENSTORE_TRANSACTION *Transaction,
+ IN CONST CHAR8 *Directory,
+ IN CONST CHAR8 *Node
+ );
+
+/**
+ Get the contents of a single "file". Returns the contents in *Result which
+ should be freed after use. The length of the value in bytes is returned in
+ *LenPtr.
+
+ @param Transaction The XenStore transaction covering this request.
+ @param DirectoryPath The dirname of the file to read.
+ @param Node The basename of the file to read.
+ @param LenPtr The amount of data read.
+ @param Result The returned contents from this file.
+
+ @return On success, XENSTORE_STATUS_SUCCESS. Otherwise an errno value
+ indicating the type of failure.
+
+ @note The results buffer is malloced and should be free'd by the
+ caller.
+**/
+XENSTORE_STATUS
+XenStoreRead (
+ IN CONST XENSTORE_TRANSACTION *Transaction,
+ IN CONST CHAR8 *DirectoryPath,
+ IN CONST CHAR8 *Node,
+ OUT UINT32 *LenPtr OPTIONAL,
+ OUT VOID **Result
+ );
+
+/**
+ Write to a single file.
+
+ @param Transaction The XenStore transaction covering this request.
+ @param DirectoryPath The dirname of the file to write.
+ @param Node The basename of the file to write.
+ @param Str The NUL terminated string of data to write.
+
+ @return On success, XENSTORE_STATUS_SUCCESS. Otherwise an errno value
+ indicating the type of failure.
+**/
+XENSTORE_STATUS
+XenStoreWrite (
+ IN CONST XENSTORE_TRANSACTION *Transaction,
+ IN CONST CHAR8 *DirectoryPath,
+ IN CONST CHAR8 *Node,
+ IN CONST CHAR8 *Str
+ );
+
+/**
+ Remove a file or directory (directories must be empty).
+
+ @param Transaction The XenStore transaction covering this request.
+ @param DirectoryPath The dirname of the directory to remove.
+ @param Node The basename of the directory to remove.
+
+ @return On success, XENSTORE_STATUS_SUCCESS. Otherwise an errno value
+ indicating the type of failure.
+**/
+XENSTORE_STATUS
+XenStoreRemove (
+ IN CONST XENSTORE_TRANSACTION *Transaction,
+ IN CONST CHAR8 *DirectoryPath,
+ IN CONST CHAR8 *Node
+ );
+
+/**
+ Start a transaction.
+
+ Changes by others will not be seen during the lifetime of this
+ transaction, and changes will not be visible to others until it
+ is committed (XenStoreTransactionEnd).
+
+ @param Transaction The returned transaction.
+
+ @return On success, XENSTORE_STATUS_SUCCESS. Otherwise an errno value
+ indicating the type of failure.
+**/
+XENSTORE_STATUS
+XenStoreTransactionStart (
+ OUT XENSTORE_TRANSACTION *Transaction
+ );
+
+/**
+ End a transaction.
+
+ @param Transaction The transaction to end/commit.
+ @param Abort If TRUE, the transaction is discarded
+ instead of committed.
+
+ @return On success, XENSTORE_STATUS_SUCCESS. Otherwise an errno value
+ indicating the type of failure.
+**/
+XENSTORE_STATUS
+XenStoreTransactionEnd (
+ IN CONST XENSTORE_TRANSACTION *Transaction,
+ IN BOOLEAN Abort
+ );
+
+/**
+ Printf formatted write to a XenStore file.
+
+ @param Transaction The XenStore transaction covering this request.
+ @param DirectoryPath The dirname of the path to read.
+ @param Node The basename of the path to read.
+ @param FormatString AsciiSPrint format string followed by a variable number
+ of arguments.
+
+ @return On success, XENSTORE_STATUS_SUCCESS. Otherwise an errno value
+ indicating the type of write failure.
+**/
+XENSTORE_STATUS
+EFIAPI
+XenStoreSPrint (
+ IN CONST XENSTORE_TRANSACTION *Transaction,
+ IN CONST CHAR8 *DirectoryPath,
+ IN CONST CHAR8 *Node,
+ IN CONST CHAR8 *FormatString,
+ ...
+ );
+
+/**
+ VA_LIST version of XenStoreSPrint().
+
+ @param Transaction The XenStore transaction covering this request.
+ @param DirectoryPath The dirname of the path to read.
+ @param Node The basename of the path to read.
+ @param FormatString Printf format string.
+ @param Marker VA_LIST of printf arguments.
+
+ @return On success, XENSTORE_STATUS_SUCCESS. Otherwise an errno value
+ indicating the type of write failure.
+**/
+XENSTORE_STATUS
+EFIAPI
+XenStoreVSPrint (
+ IN CONST XENSTORE_TRANSACTION *Transaction,
+ IN CONST CHAR8 *DirectoryPath,
+ IN CONST CHAR8 *Node,
+ IN CONST CHAR8 *FormatString,
+ IN VA_LIST Marker
+ );
+
+/**
+ Register a XenStore watch.
+
+ XenStore watches allow a client to be notified via a callback (embedded
+ within the watch object) of changes to an object in the XenStore.
+
+ @param DirectoryPath The dirname of the path to watch.
+ @param Node The basename of the path to watch.
+ @param WatchPtr A returned XENSTORE_WATCH pointer.
+
+ @return On success, XENSTORE_STATUS_SUCCESS. Otherwise an errno value
+ indicating the type of write failure. EEXIST errors from the
+ XenStore are suppressed, allowing multiple, physically different,
+ xenbus_watch objects, to watch the same path in the XenStore.
+**/
+XENSTORE_STATUS
+XenStoreRegisterWatch (
+ IN CONST CHAR8 *DirectoryPath,
+ IN CONST CHAR8 *Node,
+ OUT XENSTORE_WATCH **WatchPtr
+ );
+
+/**
+ Unregister a XenStore watch.
+
+ @param Watch An XENSTORE_WATCH object previously returned by a successful
+ call to XenStoreRegisterWatch ().
+**/
+VOID
+XenStoreUnregisterWatch (
+ IN XENSTORE_WATCH *Watch
+ );
+
+/**
+ Allocate and return the XenStore path string <DirectoryPath>/<Node>. If name
+ is the NUL string, the returned value contains the path string
+ <DirectoryPath>.
+
+ @param DirectoryPath The NUL terminated directory prefix for new path.
+ @param Node The NUL terminated basename for the new path.
+
+ @return A buffer containing the joined path.
+ */
+CHAR8 *
+XenStoreJoin (
+ IN CONST CHAR8 *DirectoryPath,
+ IN CONST CHAR8 *Node
+ );
+
+
+/**
+ Initialize the XenStore states and rings.
+
+ @param Dev A pointer to a XENBUS_DEVICE instance.
+
+ @return EFI_SUCCESS if everything went smoothly.
+**/
+EFI_STATUS
+XenStoreInit (
+ XENBUS_DEVICE *Dev
+ );
+
+/**
+ Deinitialize the XenStore states and rings.
+
+ @param Dev A pointer to a XENBUS_DEVICE instance.
+**/
+VOID
+XenStoreDeinit (
+ IN XENBUS_DEVICE *Dev
+ );
+
+
+//
+// XENBUS protocol
+//
+
+XENSTORE_STATUS
+EFIAPI
+XenBusWaitForWatch (
+ IN XENBUS_PROTOCOL *This,
+ IN VOID *Token
+ );
+
+XENSTORE_STATUS
+EFIAPI
+XenBusXenStoreRead (
+ IN XENBUS_PROTOCOL *This,
+ IN CONST XENSTORE_TRANSACTION *Transaction,
+ IN CONST CHAR8 *Node,
+ OUT VOID **Value
+ );
+
+XENSTORE_STATUS
+EFIAPI
+XenBusXenStoreBackendRead (
+ IN XENBUS_PROTOCOL *This,
+ IN CONST XENSTORE_TRANSACTION *Transaction,
+ IN CONST CHAR8 *Node,
+ OUT VOID **Value
+ );
+
+XENSTORE_STATUS
+EFIAPI
+XenBusXenStoreRemove (
+ IN XENBUS_PROTOCOL *This,
+ IN CONST XENSTORE_TRANSACTION *Transaction,
+ IN CONST CHAR8 *Node
+ );
+
+XENSTORE_STATUS
+EFIAPI
+XenBusXenStoreTransactionStart (
+ IN XENBUS_PROTOCOL *This,
+ OUT XENSTORE_TRANSACTION *Transaction
+ );
+
+XENSTORE_STATUS
+EFIAPI
+XenBusXenStoreTransactionEnd (
+ IN XENBUS_PROTOCOL *This,
+ IN CONST XENSTORE_TRANSACTION *Transaction,
+ IN BOOLEAN Abort
+ );
+
+XENSTORE_STATUS
+EFIAPI
+XenBusXenStoreSPrint (
+ IN XENBUS_PROTOCOL *This,
+ IN CONST XENSTORE_TRANSACTION *Transaction,
+ IN CONST CHAR8 *DirectoryPath,
+ IN CONST CHAR8 *Node,
+ IN CONST CHAR8 *FormatString,
+ ...
+ );
+
+XENSTORE_STATUS
+EFIAPI
+XenBusRegisterWatch (
+ IN XENBUS_PROTOCOL *This,
+ IN CONST CHAR8 *Node,
+ OUT VOID **Token
+ );
+
+XENSTORE_STATUS
+EFIAPI
+XenBusRegisterWatchBackend (
+ IN XENBUS_PROTOCOL *This,
+ IN CONST CHAR8 *Node,
+ OUT VOID **Token
+ );
+
+VOID
+EFIAPI
+XenBusUnregisterWatch (
+ IN XENBUS_PROTOCOL *This,
+ IN VOID *Token
+ );
+
+#endif /* _XEN_XENSTORE_XENSTOREVAR_H */
|