diff options
Diffstat (limited to 'roms/edk2/OvmfPkg/XenPvBlkDxe')
-rw-r--r-- | roms/edk2/OvmfPkg/XenPvBlkDxe/BlockFront.c | 639 | ||||
-rw-r--r-- | roms/edk2/OvmfPkg/XenPvBlkDxe/BlockFront.h | 95 | ||||
-rw-r--r-- | roms/edk2/OvmfPkg/XenPvBlkDxe/BlockIo.c | 270 | ||||
-rw-r--r-- | roms/edk2/OvmfPkg/XenPvBlkDxe/BlockIo.h | 102 | ||||
-rw-r--r-- | roms/edk2/OvmfPkg/XenPvBlkDxe/ComponentName.c | 170 | ||||
-rw-r--r-- | roms/edk2/OvmfPkg/XenPvBlkDxe/ComponentName.h | 88 | ||||
-rw-r--r-- | roms/edk2/OvmfPkg/XenPvBlkDxe/DriverBinding.h | 137 | ||||
-rw-r--r-- | roms/edk2/OvmfPkg/XenPvBlkDxe/XenPvBlkDxe.c | 388 | ||||
-rw-r--r-- | roms/edk2/OvmfPkg/XenPvBlkDxe/XenPvBlkDxe.h | 73 | ||||
-rw-r--r-- | roms/edk2/OvmfPkg/XenPvBlkDxe/XenPvBlkDxe.inf | 57 |
10 files changed, 2019 insertions, 0 deletions
diff --git a/roms/edk2/OvmfPkg/XenPvBlkDxe/BlockFront.c b/roms/edk2/OvmfPkg/XenPvBlkDxe/BlockFront.c new file mode 100644 index 000000000..122a6baed --- /dev/null +++ b/roms/edk2/OvmfPkg/XenPvBlkDxe/BlockFront.c @@ -0,0 +1,639 @@ +/** @file
+ Minimal block driver for Mini-OS.
+
+ Copyright (c) 2007-2008 Samuel Thibault.
+ Copyright (C) 2014, Citrix Ltd.
+ Copyright (c) 2014, Intel Corporation. All rights reserved.<BR>
+
+ SPDX-License-Identifier: BSD-2-Clause-Patent
+**/
+
+#include <Library/PrintLib.h>
+#include <Library/DebugLib.h>
+
+#include "BlockFront.h"
+
+#include <IndustryStandard/Xen/io/protocols.h>
+#include <IndustryStandard/Xen/io/xenbus.h>
+
+/**
+ Helper to read an integer from XenStore.
+
+ If the number overflows according to the range defined by UINT64,
+ then ASSERT().
+
+ @param This A pointer to a XENBUS_PROTOCOL instance.
+ @param Node The XenStore node to read from.
+ @param FromBackend Read frontend or backend value.
+ @param ValuePtr Where to put the value.
+
+ @retval XENSTORE_STATUS_SUCCESS If successful, will update ValuePtr.
+ @return Any other return value indicate the error,
+ ValuePtr is not updated in this case.
+**/
+STATIC
+XENSTORE_STATUS
+XenBusReadUint64 (
+ IN XENBUS_PROTOCOL *This,
+ IN CONST CHAR8 *Node,
+ IN BOOLEAN FromBackend,
+ OUT UINT64 *ValuePtr
+ )
+{
+ XENSTORE_STATUS Status;
+ CHAR8 *Ptr;
+
+ if (!FromBackend) {
+ Status = This->XsRead (This, XST_NIL, Node, (VOID**)&Ptr);
+ } else {
+ Status = This->XsBackendRead (This, XST_NIL, Node, (VOID**)&Ptr);
+ }
+ if (Status != XENSTORE_STATUS_SUCCESS) {
+ return Status;
+ }
+ // AsciiStrDecimalToUint64 will ASSERT if Ptr overflow UINT64.
+ *ValuePtr = AsciiStrDecimalToUint64 (Ptr);
+ FreePool (Ptr);
+ return Status;
+}
+
+/**
+ Free an instance of XEN_BLOCK_FRONT_DEVICE.
+
+ @param Dev The instance to free.
+**/
+STATIC
+VOID
+XenPvBlockFree (
+ IN XEN_BLOCK_FRONT_DEVICE *Dev
+ )
+{
+ XENBUS_PROTOCOL *XenBusIo = Dev->XenBusIo;
+
+ if (Dev->RingRef != 0) {
+ XenBusIo->GrantEndAccess (XenBusIo, Dev->RingRef);
+ }
+ if (Dev->Ring.sring != NULL) {
+ FreePages (Dev->Ring.sring, 1);
+ }
+ if (Dev->EventChannel != 0) {
+ XenBusIo->EventChannelClose (XenBusIo, Dev->EventChannel);
+ }
+ FreePool (Dev);
+}
+
+/**
+ Wait until until the backend has reached the ExpectedState.
+
+ @param Dev A XEN_BLOCK_FRONT_DEVICE instance.
+ @param ExpectedState The backend state expected.
+ @param LastStatePtr An optional pointer where to right the final state.
+
+ @return Return XENSTORE_STATUS_SUCCESS if the new backend state is ExpectedState
+ or return an error otherwise.
+**/
+STATIC
+XENSTORE_STATUS
+XenPvBlkWaitForBackendState (
+ IN XEN_BLOCK_FRONT_DEVICE *Dev,
+ IN XenbusState ExpectedState,
+ OUT XenbusState *LastStatePtr OPTIONAL
+ )
+{
+ XENBUS_PROTOCOL *XenBusIo = Dev->XenBusIo;
+ XenbusState State;
+ UINT64 Value;
+ XENSTORE_STATUS Status = XENSTORE_STATUS_SUCCESS;
+
+ while (TRUE) {
+ Status = XenBusReadUint64 (XenBusIo, "state", TRUE, &Value);
+ if (Status != XENSTORE_STATUS_SUCCESS) {
+ return Status;
+ }
+ if (Value > XenbusStateReconfigured) {
+ //
+ // Value is not a State value.
+ //
+ return XENSTORE_STATUS_EIO;
+ }
+ State = Value;
+ if (State == ExpectedState) {
+ break;
+ } else if (State > ExpectedState) {
+ Status = XENSTORE_STATUS_FAIL;
+ break;
+ }
+ DEBUG ((DEBUG_INFO,
+ "XenPvBlk: waiting backend state %d, current: %d\n",
+ ExpectedState, State));
+ XenBusIo->WaitForWatch (XenBusIo, Dev->StateWatchToken);
+ }
+
+ if (LastStatePtr != NULL) {
+ *LastStatePtr = State;
+ }
+
+ return Status;
+}
+
+EFI_STATUS
+XenPvBlockFrontInitialization (
+ IN XENBUS_PROTOCOL *XenBusIo,
+ IN CONST CHAR8 *NodeName,
+ OUT XEN_BLOCK_FRONT_DEVICE **DevPtr
+ )
+{
+ XENSTORE_TRANSACTION Transaction;
+ CHAR8 *DeviceType;
+ blkif_sring_t *SharedRing;
+ XENSTORE_STATUS Status;
+ XEN_BLOCK_FRONT_DEVICE *Dev;
+ XenbusState State;
+ UINT64 Value;
+ CHAR8 *Params;
+
+ ASSERT (NodeName != NULL);
+
+ Dev = AllocateZeroPool (sizeof (XEN_BLOCK_FRONT_DEVICE));
+ Dev->Signature = XEN_BLOCK_FRONT_SIGNATURE;
+ Dev->NodeName = NodeName;
+ Dev->XenBusIo = XenBusIo;
+ Dev->DeviceId = XenBusIo->DeviceId;
+
+ XenBusIo->XsRead (XenBusIo, XST_NIL, "device-type", (VOID**)&DeviceType);
+ if (AsciiStrCmp (DeviceType, "cdrom") == 0) {
+ Dev->MediaInfo.CdRom = TRUE;
+ } else {
+ Dev->MediaInfo.CdRom = FALSE;
+ }
+ FreePool (DeviceType);
+
+ if (Dev->MediaInfo.CdRom) {
+ Status = XenBusIo->XsBackendRead (XenBusIo, XST_NIL, "params", (VOID**)&Params);
+ if (Status != XENSTORE_STATUS_SUCCESS) {
+ DEBUG ((DEBUG_ERROR, "%a: Failed to read params (%d)\n", __FUNCTION__, Status));
+ goto Error;
+ }
+ if (AsciiStrLen (Params) == 0 || AsciiStrCmp (Params, "aio:") == 0) {
+ FreePool (Params);
+ DEBUG ((DEBUG_INFO, "%a: Empty cdrom\n", __FUNCTION__));
+ goto Error;
+ }
+ FreePool (Params);
+ }
+
+ Status = XenBusReadUint64 (XenBusIo, "backend-id", FALSE, &Value);
+ if (Status != XENSTORE_STATUS_SUCCESS || Value > MAX_UINT16) {
+ DEBUG ((DEBUG_ERROR, "XenPvBlk: Failed to get backend-id (%d)\n",
+ Status));
+ goto Error;
+ }
+ Dev->DomainId = (domid_t)Value;
+ XenBusIo->EventChannelAllocate (XenBusIo, Dev->DomainId, &Dev->EventChannel);
+
+ SharedRing = (blkif_sring_t*) AllocatePages (1);
+ SHARED_RING_INIT (SharedRing);
+ FRONT_RING_INIT (&Dev->Ring, SharedRing, EFI_PAGE_SIZE);
+ XenBusIo->GrantAccess (XenBusIo,
+ Dev->DomainId,
+ (INTN) SharedRing >> EFI_PAGE_SHIFT,
+ FALSE,
+ &Dev->RingRef);
+
+Again:
+ Status = XenBusIo->XsTransactionStart (XenBusIo, &Transaction);
+ if (Status != XENSTORE_STATUS_SUCCESS) {
+ DEBUG ((DEBUG_WARN, "XenPvBlk: Failed to start transaction, %d\n", Status));
+ goto Error;
+ }
+
+ Status = XenBusIo->XsPrintf (XenBusIo, &Transaction, NodeName, "ring-ref", "%d",
+ Dev->RingRef);
+ if (Status != XENSTORE_STATUS_SUCCESS) {
+ DEBUG ((DEBUG_ERROR, "XenPvBlk: Failed to write ring-ref.\n"));
+ goto AbortTransaction;
+ }
+ Status = XenBusIo->XsPrintf (XenBusIo, &Transaction, NodeName,
+ "event-channel", "%d", Dev->EventChannel);
+ if (Status != XENSTORE_STATUS_SUCCESS) {
+ DEBUG ((DEBUG_ERROR, "XenPvBlk: Failed to write event-channel.\n"));
+ goto AbortTransaction;
+ }
+ Status = XenBusIo->XsPrintf (XenBusIo, &Transaction, NodeName,
+ "protocol", "%a", XEN_IO_PROTO_ABI_NATIVE);
+ if (Status != XENSTORE_STATUS_SUCCESS) {
+ DEBUG ((DEBUG_ERROR, "XenPvBlk: Failed to write protocol.\n"));
+ goto AbortTransaction;
+ }
+
+ Status = XenBusIo->SetState (XenBusIo, &Transaction, XenbusStateConnected);
+ if (Status != XENSTORE_STATUS_SUCCESS) {
+ DEBUG ((DEBUG_ERROR, "XenPvBlk: Failed to switch state.\n"));
+ goto AbortTransaction;
+ }
+
+ Status = XenBusIo->XsTransactionEnd (XenBusIo, &Transaction, FALSE);
+ if (Status == XENSTORE_STATUS_EAGAIN) {
+ goto Again;
+ }
+
+ XenBusIo->RegisterWatchBackend (XenBusIo, "state", &Dev->StateWatchToken);
+
+ //
+ // Waiting for backend
+ //
+ Status = XenPvBlkWaitForBackendState (Dev, XenbusStateConnected, &State);
+ if (Status != XENSTORE_STATUS_SUCCESS) {
+ DEBUG ((DEBUG_ERROR,
+ "XenPvBlk: backend for %a/%d not available, rc=%d state=%d\n",
+ XenBusIo->Type, XenBusIo->DeviceId, Status, State));
+ goto Error2;
+ }
+
+ Status = XenBusReadUint64 (XenBusIo, "info", TRUE, &Value);
+ if (Status != XENSTORE_STATUS_SUCCESS || Value > MAX_UINT32) {
+ goto Error2;
+ }
+ Dev->MediaInfo.VDiskInfo = (UINT32)Value;
+ if (Dev->MediaInfo.VDiskInfo & VDISK_READONLY) {
+ Dev->MediaInfo.ReadWrite = FALSE;
+ } else {
+ Dev->MediaInfo.ReadWrite = TRUE;
+ }
+
+ Status = XenBusReadUint64 (XenBusIo, "sectors", TRUE, &Dev->MediaInfo.Sectors);
+ if (Status != XENSTORE_STATUS_SUCCESS) {
+ goto Error2;
+ }
+
+ Status = XenBusReadUint64 (XenBusIo, "sector-size", TRUE, &Value);
+ if (Status != XENSTORE_STATUS_SUCCESS || Value > MAX_UINT32) {
+ goto Error2;
+ }
+ if ((UINT32)Value % 512 != 0) {
+ //
+ // This is not supported by the driver.
+ //
+ DEBUG ((DEBUG_ERROR, "XenPvBlk: Unsupported sector-size value %Lu, "
+ "it must be a multiple of 512\n", Value));
+ goto Error2;
+ }
+ Dev->MediaInfo.SectorSize = (UINT32)Value;
+
+ // Default value
+ Value = 0;
+ XenBusReadUint64 (XenBusIo, "feature-barrier", TRUE, &Value);
+ if (Value == 1) {
+ Dev->MediaInfo.FeatureBarrier = TRUE;
+ } else {
+ Dev->MediaInfo.FeatureBarrier = FALSE;
+ }
+
+ // Default value
+ Value = 0;
+ XenBusReadUint64 (XenBusIo, "feature-flush-cache", TRUE, &Value);
+ if (Value == 1) {
+ Dev->MediaInfo.FeatureFlushCache = TRUE;
+ } else {
+ Dev->MediaInfo.FeatureFlushCache = FALSE;
+ }
+
+ DEBUG ((DEBUG_INFO, "XenPvBlk: New disk with %ld sectors of %d bytes\n",
+ Dev->MediaInfo.Sectors, Dev->MediaInfo.SectorSize));
+
+ *DevPtr = Dev;
+ return EFI_SUCCESS;
+
+Error2:
+ XenBusIo->UnregisterWatch (XenBusIo, Dev->StateWatchToken);
+ XenBusIo->XsRemove (XenBusIo, XST_NIL, "ring-ref");
+ XenBusIo->XsRemove (XenBusIo, XST_NIL, "event-channel");
+ XenBusIo->XsRemove (XenBusIo, XST_NIL, "protocol");
+ goto Error;
+AbortTransaction:
+ XenBusIo->XsTransactionEnd (XenBusIo, &Transaction, TRUE);
+Error:
+ XenPvBlockFree (Dev);
+ return EFI_DEVICE_ERROR;
+}
+
+VOID
+XenPvBlockFrontShutdown (
+ IN XEN_BLOCK_FRONT_DEVICE *Dev
+ )
+{
+ XENBUS_PROTOCOL *XenBusIo = Dev->XenBusIo;
+ XENSTORE_STATUS Status;
+ UINT64 Value;
+
+ XenPvBlockSync (Dev);
+
+ Status = XenBusIo->SetState (XenBusIo, XST_NIL, XenbusStateClosing);
+ if (Status != XENSTORE_STATUS_SUCCESS) {
+ DEBUG ((DEBUG_ERROR,
+ "XenPvBlk: error while changing state to Closing: %d\n",
+ Status));
+ goto Close;
+ }
+
+ Status = XenPvBlkWaitForBackendState (Dev, XenbusStateClosing, NULL);
+ if (Status != XENSTORE_STATUS_SUCCESS) {
+ DEBUG ((DEBUG_ERROR,
+ "XenPvBlk: error while waiting for closing backend state: %d\n",
+ Status));
+ goto Close;
+ }
+
+ Status = XenBusIo->SetState (XenBusIo, XST_NIL, XenbusStateClosed);
+ if (Status != XENSTORE_STATUS_SUCCESS) {
+ DEBUG ((DEBUG_ERROR,
+ "XenPvBlk: error while changing state to Closed: %d\n",
+ Status));
+ goto Close;
+ }
+
+ Status = XenPvBlkWaitForBackendState (Dev, XenbusStateClosed, NULL);
+ if (Status != XENSTORE_STATUS_SUCCESS) {
+ DEBUG ((DEBUG_ERROR,
+ "XenPvBlk: error while waiting for closed backend state: %d\n",
+ Status));
+ goto Close;
+ }
+
+ Status = XenBusIo->SetState (XenBusIo, XST_NIL, XenbusStateInitialising);
+ if (Status != XENSTORE_STATUS_SUCCESS) {
+ DEBUG ((DEBUG_ERROR,
+ "XenPvBlk: error while changing state to initialising: %d\n",
+ Status));
+ goto Close;
+ }
+
+ while (TRUE) {
+ Status = XenBusReadUint64 (XenBusIo, "state", TRUE, &Value);
+ if (Status != XENSTORE_STATUS_SUCCESS) {
+ DEBUG ((DEBUG_ERROR,
+ "XenPvBlk: error while waiting for new backend state: %d\n",
+ Status));
+ goto Close;
+ }
+ if (Value <= XenbusStateInitWait || Value >= XenbusStateClosed) {
+ break;
+ }
+ DEBUG ((DEBUG_INFO,
+ "XenPvBlk: waiting backend state %d, current: %Lu\n",
+ XenbusStateInitWait, Value));
+ XenBusIo->WaitForWatch (XenBusIo, Dev->StateWatchToken);
+ }
+
+Close:
+ XenBusIo->UnregisterWatch (XenBusIo, Dev->StateWatchToken);
+ XenBusIo->XsRemove (XenBusIo, XST_NIL, "ring-ref");
+ XenBusIo->XsRemove (XenBusIo, XST_NIL, "event-channel");
+ XenBusIo->XsRemove (XenBusIo, XST_NIL, "protocol");
+
+ XenPvBlockFree (Dev);
+}
+
+STATIC
+VOID
+XenPvBlockWaitSlot (
+ IN XEN_BLOCK_FRONT_DEVICE *Dev
+ )
+{
+ /* Wait for a slot */
+ if (RING_FULL (&Dev->Ring)) {
+ while (TRUE) {
+ XenPvBlockAsyncIoPoll (Dev);
+ if (!RING_FULL (&Dev->Ring)) {
+ break;
+ }
+ /* Really no slot, could wait for an event on Dev->EventChannel. */
+ }
+ }
+}
+
+VOID
+XenPvBlockAsyncIo (
+ IN OUT XEN_BLOCK_FRONT_IO *IoData,
+ IN BOOLEAN IsWrite
+ )
+{
+ XEN_BLOCK_FRONT_DEVICE *Dev = IoData->Dev;
+ XENBUS_PROTOCOL *XenBusIo = Dev->XenBusIo;
+ blkif_request_t *Request;
+ RING_IDX RingIndex;
+ BOOLEAN Notify;
+ INT32 NumSegments, Index;
+ UINTN Start, End;
+
+ // Can't io at non-sector-aligned location
+ ASSERT(!(IoData->Sector & ((Dev->MediaInfo.SectorSize / 512) - 1)));
+ // Can't io non-sector-sized amounts
+ ASSERT(!(IoData->Size & (Dev->MediaInfo.SectorSize - 1)));
+ // Can't io non-sector-aligned buffer
+ ASSERT(!((UINTN) IoData->Buffer & (Dev->MediaInfo.SectorSize - 1)));
+
+ Start = (UINTN) IoData->Buffer & ~EFI_PAGE_MASK;
+ End = ((UINTN) IoData->Buffer + IoData->Size + EFI_PAGE_SIZE - 1) & ~EFI_PAGE_MASK;
+ IoData->NumRef = NumSegments = (INT32)((End - Start) / EFI_PAGE_SIZE);
+
+ ASSERT (NumSegments <= BLKIF_MAX_SEGMENTS_PER_REQUEST);
+
+ XenPvBlockWaitSlot (Dev);
+ RingIndex = Dev->Ring.req_prod_pvt;
+ Request = RING_GET_REQUEST (&Dev->Ring, RingIndex);
+
+ Request->operation = IsWrite ? BLKIF_OP_WRITE : BLKIF_OP_READ;
+ Request->nr_segments = (UINT8)NumSegments;
+ Request->handle = Dev->DeviceId;
+ Request->id = (UINTN) IoData;
+ Request->sector_number = IoData->Sector;
+
+ for (Index = 0; Index < NumSegments; Index++) {
+ Request->seg[Index].first_sect = 0;
+ Request->seg[Index].last_sect = EFI_PAGE_SIZE / 512 - 1;
+ }
+ Request->seg[0].first_sect = (UINT8)(((UINTN) IoData->Buffer & EFI_PAGE_MASK) / 512);
+ Request->seg[NumSegments - 1].last_sect =
+ (UINT8)((((UINTN) IoData->Buffer + IoData->Size - 1) & EFI_PAGE_MASK) / 512);
+ for (Index = 0; Index < NumSegments; Index++) {
+ UINTN Data = Start + Index * EFI_PAGE_SIZE;
+ XenBusIo->GrantAccess (XenBusIo, Dev->DomainId,
+ Data >> EFI_PAGE_SHIFT, IsWrite,
+ &Request->seg[Index].gref);
+ IoData->GrantRef[Index] = Request->seg[Index].gref;
+ }
+
+ Dev->Ring.req_prod_pvt = RingIndex + 1;
+
+ MemoryFence ();
+ RING_PUSH_REQUESTS_AND_CHECK_NOTIFY (&Dev->Ring, Notify);
+
+ if (Notify) {
+ UINT32 ReturnCode;
+ ReturnCode = XenBusIo->EventChannelNotify (XenBusIo, Dev->EventChannel);
+ if (ReturnCode != 0) {
+ DEBUG ((DEBUG_ERROR,
+ "XenPvBlk: Unexpected return value from EventChannelNotify: %d\n",
+ ReturnCode));
+ }
+ }
+}
+
+EFI_STATUS
+XenPvBlockIo (
+ IN OUT XEN_BLOCK_FRONT_IO *IoData,
+ IN BOOLEAN IsWrite
+ )
+{
+ //
+ // Status value that correspond to an IO in progress.
+ //
+ IoData->Status = EFI_ALREADY_STARTED;
+ XenPvBlockAsyncIo (IoData, IsWrite);
+
+ while (IoData->Status == EFI_ALREADY_STARTED) {
+ XenPvBlockAsyncIoPoll (IoData->Dev);
+ }
+
+ return IoData->Status;
+}
+
+STATIC
+VOID
+XenPvBlockPushOperation (
+ IN XEN_BLOCK_FRONT_DEVICE *Dev,
+ IN UINT8 Operation,
+ IN UINT64 Id
+ )
+{
+ INT32 Index;
+ blkif_request_t *Request;
+ BOOLEAN Notify;
+
+ XenPvBlockWaitSlot (Dev);
+ Index = Dev->Ring.req_prod_pvt;
+ Request = RING_GET_REQUEST(&Dev->Ring, Index);
+ Request->operation = Operation;
+ Request->nr_segments = 0;
+ Request->handle = Dev->DeviceId;
+ Request->id = Id;
+ /* Not needed anyway, but the backend will check it */
+ Request->sector_number = 0;
+ Dev->Ring.req_prod_pvt = Index + 1;
+ MemoryFence ();
+ RING_PUSH_REQUESTS_AND_CHECK_NOTIFY (&Dev->Ring, Notify);
+ if (Notify) {
+ XENBUS_PROTOCOL *XenBusIo = Dev->XenBusIo;
+ UINT32 ReturnCode;
+ ReturnCode = XenBusIo->EventChannelNotify (XenBusIo, Dev->EventChannel);
+ if (ReturnCode != 0) {
+ DEBUG ((DEBUG_ERROR,
+ "XenPvBlk: Unexpected return value from EventChannelNotify: %d\n",
+ ReturnCode));
+ }
+ }
+}
+
+VOID
+XenPvBlockSync (
+ IN XEN_BLOCK_FRONT_DEVICE *Dev
+ )
+{
+ if (Dev->MediaInfo.ReadWrite) {
+ if (Dev->MediaInfo.FeatureBarrier) {
+ XenPvBlockPushOperation (Dev, BLKIF_OP_WRITE_BARRIER, 0);
+ }
+
+ if (Dev->MediaInfo.FeatureFlushCache) {
+ XenPvBlockPushOperation (Dev, BLKIF_OP_FLUSH_DISKCACHE, 0);
+ }
+ }
+
+ /* Note: This won't finish if another thread enqueues requests. */
+ while (TRUE) {
+ XenPvBlockAsyncIoPoll (Dev);
+ if (RING_FREE_REQUESTS (&Dev->Ring) == RING_SIZE (&Dev->Ring)) {
+ break;
+ }
+ }
+}
+
+VOID
+XenPvBlockAsyncIoPoll (
+ IN XEN_BLOCK_FRONT_DEVICE *Dev
+ )
+{
+ RING_IDX ProducerIndex, ConsumerIndex;
+ blkif_response_t *Response;
+ INT32 More;
+
+ do {
+ ProducerIndex = Dev->Ring.sring->rsp_prod;
+ /* Ensure we see queued responses up to 'ProducerIndex'. */
+ MemoryFence ();
+ ConsumerIndex = Dev->Ring.rsp_cons;
+
+ while (ConsumerIndex != ProducerIndex) {
+ XEN_BLOCK_FRONT_IO *IoData = NULL;
+ INT16 Status;
+
+ Response = RING_GET_RESPONSE (&Dev->Ring, ConsumerIndex);
+
+ IoData = (VOID *) (UINTN) Response->id;
+ Status = Response->status;
+
+ switch (Response->operation) {
+ case BLKIF_OP_READ:
+ case BLKIF_OP_WRITE:
+ {
+ INT32 Index;
+
+ if (Status != BLKIF_RSP_OKAY) {
+ DEBUG ((DEBUG_ERROR,
+ "XenPvBlk: "
+ "%a error %d on %a at sector %Lx, num bytes %Lx\n",
+ Response->operation == BLKIF_OP_READ ? "read" : "write",
+ Status, IoData->Dev->NodeName,
+ (UINT64)IoData->Sector,
+ (UINT64)IoData->Size));
+ }
+
+ for (Index = 0; Index < IoData->NumRef; Index++) {
+ Dev->XenBusIo->GrantEndAccess (Dev->XenBusIo, IoData->GrantRef[Index]);
+ }
+
+ break;
+ }
+
+ case BLKIF_OP_WRITE_BARRIER:
+ if (Status != BLKIF_RSP_OKAY) {
+ DEBUG ((DEBUG_ERROR, "XenPvBlk: write barrier error %d\n", Status));
+ }
+ break;
+ case BLKIF_OP_FLUSH_DISKCACHE:
+ if (Status != BLKIF_RSP_OKAY) {
+ DEBUG ((DEBUG_ERROR, "XenPvBlk: flush error %d\n", Status));
+ }
+ break;
+
+ default:
+ DEBUG ((DEBUG_ERROR,
+ "XenPvBlk: unrecognized block operation %d response (status %d)\n",
+ Response->operation, Status));
+ break;
+ }
+
+ Dev->Ring.rsp_cons = ++ConsumerIndex;
+ if (IoData != NULL) {
+ IoData->Status = Status ? EFI_DEVICE_ERROR : EFI_SUCCESS;
+ }
+ if (Dev->Ring.rsp_cons != ConsumerIndex) {
+ /* We reentered, we must not continue here */
+ break;
+ }
+ }
+
+ RING_FINAL_CHECK_FOR_RESPONSES (&Dev->Ring, More);
+ } while (More != 0);
+}
diff --git a/roms/edk2/OvmfPkg/XenPvBlkDxe/BlockFront.h b/roms/edk2/OvmfPkg/XenPvBlkDxe/BlockFront.h new file mode 100644 index 000000000..7c2d7f2c9 --- /dev/null +++ b/roms/edk2/OvmfPkg/XenPvBlkDxe/BlockFront.h @@ -0,0 +1,95 @@ +/** @file
+ BlockFront functions and types declarations.
+
+ Copyright (C) 2014, Citrix Ltd.
+
+ SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+#include "XenPvBlkDxe.h"
+
+#include <IndustryStandard/Xen/event_channel.h>
+#include <IndustryStandard/Xen/io/blkif.h>
+
+typedef struct _XEN_BLOCK_FRONT_DEVICE XEN_BLOCK_FRONT_DEVICE;
+typedef struct _XEN_BLOCK_FRONT_IO XEN_BLOCK_FRONT_IO;
+
+struct _XEN_BLOCK_FRONT_IO
+{
+ XEN_BLOCK_FRONT_DEVICE *Dev;
+ UINT8 *Buffer;
+ UINTN Size;
+ UINTN Sector; ///< 512 bytes sector.
+
+ grant_ref_t GrantRef[BLKIF_MAX_SEGMENTS_PER_REQUEST];
+ INT32 NumRef;
+
+ EFI_STATUS Status;
+};
+
+typedef struct
+{
+ UINT64 Sectors;
+ UINT32 SectorSize;
+ UINT32 VDiskInfo;
+ BOOLEAN ReadWrite;
+ BOOLEAN CdRom;
+ BOOLEAN FeatureBarrier;
+ BOOLEAN FeatureFlushCache;
+} XEN_BLOCK_FRONT_MEDIA_INFO;
+
+#define XEN_BLOCK_FRONT_SIGNATURE SIGNATURE_32 ('X', 'p', 'v', 'B')
+struct _XEN_BLOCK_FRONT_DEVICE {
+ UINT32 Signature;
+ EFI_BLOCK_IO_PROTOCOL BlockIo;
+ domid_t DomainId;
+
+ blkif_front_ring_t Ring;
+ grant_ref_t RingRef;
+ evtchn_port_t EventChannel;
+ blkif_vdev_t DeviceId;
+
+ CONST CHAR8 *NodeName;
+ XEN_BLOCK_FRONT_MEDIA_INFO MediaInfo;
+
+ VOID *StateWatchToken;
+
+ XENBUS_PROTOCOL *XenBusIo;
+};
+
+#define XEN_BLOCK_FRONT_FROM_BLOCK_IO(b) \
+ CR (b, XEN_BLOCK_FRONT_DEVICE, BlockIo, XEN_BLOCK_FRONT_SIGNATURE)
+
+EFI_STATUS
+XenPvBlockFrontInitialization (
+ IN XENBUS_PROTOCOL *XenBusIo,
+ IN CONST CHAR8 *NodeName,
+ OUT XEN_BLOCK_FRONT_DEVICE **DevPtr
+ );
+
+VOID
+XenPvBlockFrontShutdown (
+ IN XEN_BLOCK_FRONT_DEVICE *Dev
+ );
+
+VOID
+XenPvBlockAsyncIo (
+ IN OUT XEN_BLOCK_FRONT_IO *IoData,
+ IN BOOLEAN IsWrite
+ );
+
+EFI_STATUS
+XenPvBlockIo (
+ IN OUT XEN_BLOCK_FRONT_IO *IoData,
+ IN BOOLEAN IsWrite
+ );
+
+VOID
+XenPvBlockAsyncIoPoll (
+ IN XEN_BLOCK_FRONT_DEVICE *Dev
+ );
+
+VOID
+XenPvBlockSync (
+ IN XEN_BLOCK_FRONT_DEVICE *Dev
+ );
diff --git a/roms/edk2/OvmfPkg/XenPvBlkDxe/BlockIo.c b/roms/edk2/OvmfPkg/XenPvBlkDxe/BlockIo.c new file mode 100644 index 000000000..c013fc80f --- /dev/null +++ b/roms/edk2/OvmfPkg/XenPvBlkDxe/BlockIo.c @@ -0,0 +1,270 @@ +/** @file
+ BlockIo implementation for Xen PV Block driver.
+
+ This file is implementing the interface between the actual driver in
+ BlockFront.c to the BlockIo protocol.
+
+ Copyright (C) 2014, Citrix Ltd.
+
+ SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#include "XenPvBlkDxe.h"
+
+#include "BlockFront.h"
+
+///
+/// Block I/O Media structure
+///
+GLOBAL_REMOVE_IF_UNREFERENCED
+EFI_BLOCK_IO_MEDIA gXenPvBlkDxeBlockIoMedia = {
+ 0, // MediaId
+ FALSE, // RemovableMedia
+ FALSE, // MediaPresent
+ FALSE, // LogicalPartition
+ TRUE, // ReadOnly
+ FALSE, // WriteCaching
+ 512, // BlockSize
+ 512, // IoAlign, BlockFront does not support less than 512 bits-aligned.
+ 0, // LastBlock
+ 0, // LowestAlignedLba
+ 0, // LogicalBlocksPerPhysicalBlock
+ 0 // OptimalTransferLengthGranularity
+};
+
+///
+/// Block I/O Protocol instance
+///
+GLOBAL_REMOVE_IF_UNREFERENCED
+EFI_BLOCK_IO_PROTOCOL gXenPvBlkDxeBlockIo = {
+ EFI_BLOCK_IO_PROTOCOL_REVISION3, // Revision
+ &gXenPvBlkDxeBlockIoMedia, // Media
+ XenPvBlkDxeBlockIoReset, // Reset
+ XenPvBlkDxeBlockIoReadBlocks, // ReadBlocks
+ XenPvBlkDxeBlockIoWriteBlocks, // WriteBlocks
+ XenPvBlkDxeBlockIoFlushBlocks // FlushBlocks
+};
+
+
+
+
+/**
+ Read/Write BufferSize bytes from Lba into Buffer.
+
+ This function is common to XenPvBlkDxeBlockIoReadBlocks and
+ XenPvBlkDxeBlockIoWriteBlocks.
+
+ @param This Indicates a pointer to the calling context.
+ @param MediaId Id of the media, changes every time the media is replaced.
+ @param Lba The starting Logical Block Address to read from/write to.
+ @param BufferSize Size of Buffer, must be a multiple of device block size.
+ @param Buffer A pointer to the destination/source buffer for the data.
+ @param IsWrite Indicate if the operation is write or read.
+
+ @return See description of XenPvBlkDxeBlockIoReadBlocks and
+ XenPvBlkDxeBlockIoWriteBlocks.
+**/
+STATIC
+EFI_STATUS
+XenPvBlkDxeBlockIoReadWriteBlocks (
+ IN EFI_BLOCK_IO_PROTOCOL *This,
+ IN UINT32 MediaId,
+ IN EFI_LBA Lba,
+ IN UINTN BufferSize,
+ IN OUT VOID *Buffer,
+ IN BOOLEAN IsWrite
+ )
+{
+ XEN_BLOCK_FRONT_IO IoData;
+ EFI_BLOCK_IO_MEDIA *Media = This->Media;
+ UINTN Sector;
+ EFI_STATUS Status;
+
+ if (Buffer == NULL) {
+ return EFI_INVALID_PARAMETER;
+ }
+ if (BufferSize == 0) {
+ return EFI_SUCCESS;
+ }
+
+ if (BufferSize % Media->BlockSize != 0) {
+ DEBUG ((DEBUG_ERROR, "XenPvBlkDxe: Bad buffer size: 0x%Lx\n",
+ (UINT64)BufferSize));
+ return EFI_BAD_BUFFER_SIZE;
+ }
+
+ if (Lba > Media->LastBlock ||
+ (BufferSize / Media->BlockSize) - 1 > Media->LastBlock - Lba) {
+ DEBUG ((DEBUG_ERROR,
+ "XenPvBlkDxe: %a with invalid LBA: 0x%Lx, size: 0x%Lx\n",
+ IsWrite ? "Write" : "Read", Lba, (UINT64)BufferSize));
+ return EFI_INVALID_PARAMETER;
+ }
+
+ if (IsWrite && Media->ReadOnly) {
+ return EFI_WRITE_PROTECTED;
+ }
+
+ if ((Media->IoAlign > 1) && (UINTN)Buffer & (Media->IoAlign - 1)) {
+ //
+ // Grub2 does not appear to respect IoAlign of 512, so reallocate the
+ // buffer here.
+ //
+ VOID *NewBuffer;
+
+ //
+ // Try again with a properly aligned buffer.
+ //
+ NewBuffer = AllocateAlignedPages((BufferSize + EFI_PAGE_SIZE) / EFI_PAGE_SIZE,
+ Media->IoAlign);
+ if (!IsWrite) {
+ Status = XenPvBlkDxeBlockIoReadBlocks (This, MediaId,
+ Lba, BufferSize, NewBuffer);
+ CopyMem (Buffer, NewBuffer, BufferSize);
+ } else {
+ CopyMem (NewBuffer, Buffer, BufferSize);
+ Status = XenPvBlkDxeBlockIoWriteBlocks (This, MediaId,
+ Lba, BufferSize, NewBuffer);
+ }
+ FreeAlignedPages (NewBuffer, (BufferSize + EFI_PAGE_SIZE) / EFI_PAGE_SIZE);
+ return Status;
+ }
+
+ IoData.Dev = XEN_BLOCK_FRONT_FROM_BLOCK_IO (This);
+ Sector = (UINTN)MultU64x32 (Lba, Media->BlockSize / 512);
+
+ while (BufferSize > 0) {
+ if (((UINTN)Buffer & EFI_PAGE_MASK) == 0) {
+ IoData.Size = MIN (BLKIF_MAX_SEGMENTS_PER_REQUEST * EFI_PAGE_SIZE,
+ BufferSize);
+ } else {
+ IoData.Size = MIN ((BLKIF_MAX_SEGMENTS_PER_REQUEST - 1) * EFI_PAGE_SIZE,
+ BufferSize);
+ }
+
+ IoData.Buffer = Buffer;
+ IoData.Sector = Sector;
+ BufferSize -= IoData.Size;
+ Buffer = (VOID*) ((UINTN) Buffer + IoData.Size);
+ Sector += IoData.Size / 512;
+ Status = XenPvBlockIo (&IoData, IsWrite);
+ if (EFI_ERROR (Status)) {
+ DEBUG ((DEBUG_ERROR, "XenPvBlkDxe: Error during %a operation.\n",
+ IsWrite ? "write" : "read"));
+ return Status;
+ }
+ }
+ return EFI_SUCCESS;
+}
+
+
+/**
+ Read BufferSize bytes from Lba into Buffer.
+
+ @param This Indicates a pointer to the calling context.
+ @param MediaId Id of the media, changes every time the media is replaced.
+ @param Lba The starting Logical Block Address to read from
+ @param BufferSize Size of Buffer, must be a multiple of device block size.
+ @param Buffer A pointer to the destination buffer for the data. The caller is
+ responsible for either having implicit or explicit ownership of the buffer.
+
+ @retval EFI_SUCCESS The data was read correctly from the device.
+ @retval EFI_DEVICE_ERROR The device reported an error while performing the read.
+ @retval EFI_NO_MEDIA There is no media in the device.
+ @retval EFI_MEDIA_CHANGED The MediaId does not match the current device.
+ @retval EFI_BAD_BUFFER_SIZE The Buffer was not a multiple of the block size of the device.
+ @retval EFI_INVALID_PARAMETER The read request contains LBAs that are not valid,
+ or the buffer is not on proper alignment.
+
+**/
+EFI_STATUS
+EFIAPI
+XenPvBlkDxeBlockIoReadBlocks (
+ IN EFI_BLOCK_IO_PROTOCOL *This,
+ IN UINT32 MediaId,
+ IN EFI_LBA Lba,
+ IN UINTN BufferSize,
+ OUT VOID *Buffer
+ )
+{
+ return XenPvBlkDxeBlockIoReadWriteBlocks (This,
+ MediaId, Lba, BufferSize, Buffer, FALSE);
+}
+
+/**
+ Write BufferSize bytes from Lba into Buffer.
+
+ @param This Indicates a pointer to the calling context.
+ @param MediaId The media ID that the write request is for.
+ @param Lba The starting logical block address to be written. The caller is
+ responsible for writing to only legitimate locations.
+ @param BufferSize Size of Buffer, must be a multiple of device block size.
+ @param Buffer A pointer to the source buffer for the data.
+
+ @retval EFI_SUCCESS The data was written correctly to the device.
+ @retval EFI_WRITE_PROTECTED The device can not be written to.
+ @retval EFI_DEVICE_ERROR The device reported an error while performing the write.
+ @retval EFI_NO_MEDIA There is no media in the device.
+ @retval EFI_MEDIA_CHANGED The MediaId does not match the current device.
+ @retval EFI_BAD_BUFFER_SIZE The Buffer was not a multiple of the block size of the device.
+ @retval EFI_INVALID_PARAMETER The write request contains LBAs that are not valid,
+ or the buffer is not on proper alignment.
+
+**/
+EFI_STATUS
+EFIAPI
+XenPvBlkDxeBlockIoWriteBlocks (
+ IN EFI_BLOCK_IO_PROTOCOL *This,
+ IN UINT32 MediaId,
+ IN EFI_LBA Lba,
+ IN UINTN BufferSize,
+ IN VOID *Buffer
+ )
+{
+ return XenPvBlkDxeBlockIoReadWriteBlocks (This,
+ MediaId, Lba, BufferSize, Buffer, TRUE);
+}
+
+/**
+ Flush the Block Device.
+
+ @param This Indicates a pointer to the calling context.
+
+ @retval EFI_SUCCESS All outstanding data was written to the device
+ @retval EFI_DEVICE_ERROR The device reported an error while writing back the data
+ @retval EFI_NO_MEDIA There is no media in the device.
+
+**/
+EFI_STATUS
+EFIAPI
+XenPvBlkDxeBlockIoFlushBlocks (
+ IN EFI_BLOCK_IO_PROTOCOL *This
+ )
+{
+ XenPvBlockSync (XEN_BLOCK_FRONT_FROM_BLOCK_IO (This));
+ return EFI_SUCCESS;
+}
+
+/**
+ Reset the block device hardware.
+
+ @param[in] This Indicates a pointer to the calling context.
+ @param[in] ExtendedVerification Not used.
+
+ @retval EFI_SUCCESS The device was reset.
+
+**/
+EFI_STATUS
+EFIAPI
+XenPvBlkDxeBlockIoReset (
+ IN EFI_BLOCK_IO_PROTOCOL *This,
+ IN BOOLEAN ExtendedVerification
+ )
+{
+ //
+ // Since the initialization of the devices is done, then the device is
+ // working correctly.
+ //
+ return EFI_SUCCESS;
+}
diff --git a/roms/edk2/OvmfPkg/XenPvBlkDxe/BlockIo.h b/roms/edk2/OvmfPkg/XenPvBlkDxe/BlockIo.h new file mode 100644 index 000000000..110079118 --- /dev/null +++ b/roms/edk2/OvmfPkg/XenPvBlkDxe/BlockIo.h @@ -0,0 +1,102 @@ +/** @file
+ BlockIo function declaration for Xen PV block driver.
+
+ Copyright (C) 2014, Citrix Ltd.
+
+ SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+/**
+ Read BufferSize bytes from Lba into Buffer.
+
+ @param This Indicates a pointer to the calling context.
+ @param MediaId Id of the media, changes every time the media is replaced.
+ @param Lba The starting Logical Block Address to read from
+ @param BufferSize Size of Buffer, must be a multiple of device block size.
+ @param Buffer A pointer to the destination buffer for the data. The caller is
+ responsible for either having implicit or explicit ownership of the buffer.
+
+ @retval EFI_SUCCESS The data was read correctly from the device.
+ @retval EFI_DEVICE_ERROR The device reported an error while performing the read.
+ @retval EFI_NO_MEDIA There is no media in the device.
+ @retval EFI_MEDIA_CHANGED The MediaId does not match the current device.
+ @retval EFI_BAD_BUFFER_SIZE The Buffer was not a multiple of the block size of the device.
+ @retval EFI_INVALID_PARAMETER The read request contains LBAs that are not valid,
+ or the buffer is not on proper alignment.
+
+**/
+EFI_STATUS
+EFIAPI
+XenPvBlkDxeBlockIoReadBlocks (
+ IN EFI_BLOCK_IO_PROTOCOL *This,
+ IN UINT32 MediaId,
+ IN EFI_LBA Lba,
+ IN UINTN BufferSize,
+ OUT VOID *Buffer
+ );
+
+/**
+ Write BufferSize bytes from Lba into Buffer.
+
+ @param This Indicates a pointer to the calling context.
+ @param MediaId The media ID that the write request is for.
+ @param Lba The starting logical block address to be written. The caller is
+ responsible for writing to only legitimate locations.
+ @param BufferSize Size of Buffer, must be a multiple of device block size.
+ @param Buffer A pointer to the source buffer for the data.
+
+ @retval EFI_SUCCESS The data was written correctly to the device.
+ @retval EFI_WRITE_PROTECTED The device can not be written to.
+ @retval EFI_DEVICE_ERROR The device reported an error while performing the write.
+ @retval EFI_NO_MEDIA There is no media in the device.
+ @retval EFI_MEDIA_CHANGED The MediaId does not match the current device.
+ @retval EFI_BAD_BUFFER_SIZE The Buffer was not a multiple of the block size of the device.
+ @retval EFI_INVALID_PARAMETER The write request contains LBAs that are not valid,
+ or the buffer is not on proper alignment.
+
+**/
+EFI_STATUS
+EFIAPI
+XenPvBlkDxeBlockIoWriteBlocks (
+ IN EFI_BLOCK_IO_PROTOCOL *This,
+ IN UINT32 MediaId,
+ IN EFI_LBA Lba,
+ IN UINTN BufferSize,
+ IN VOID *Buffer
+ );
+
+/**
+ Flush the Block Device.
+
+ @param This Indicates a pointer to the calling context.
+
+ @retval EFI_SUCCESS All outstanding data was written to the device
+ @retval EFI_DEVICE_ERROR The device reported an error while writing back the data
+ @retval EFI_NO_MEDIA There is no media in the device.
+
+**/
+EFI_STATUS
+EFIAPI
+XenPvBlkDxeBlockIoFlushBlocks (
+ IN EFI_BLOCK_IO_PROTOCOL *This
+ );
+
+/**
+ Reset the block device hardware.
+
+ @param[in] This Indicates a pointer to the calling context.
+ @param[in] ExtendedVerification Not used.
+
+ @retval EFI_SUCCESS The device was reset.
+
+**/
+EFI_STATUS
+EFIAPI
+XenPvBlkDxeBlockIoReset (
+ IN EFI_BLOCK_IO_PROTOCOL *This,
+ IN BOOLEAN ExtendedVerification
+ );
+
+extern EFI_BLOCK_IO_MEDIA gXenPvBlkDxeBlockIoMedia;
+extern EFI_BLOCK_IO_PROTOCOL gXenPvBlkDxeBlockIo;
diff --git a/roms/edk2/OvmfPkg/XenPvBlkDxe/ComponentName.c b/roms/edk2/OvmfPkg/XenPvBlkDxe/ComponentName.c new file mode 100644 index 000000000..8ab6628a9 --- /dev/null +++ b/roms/edk2/OvmfPkg/XenPvBlkDxe/ComponentName.c @@ -0,0 +1,170 @@ +/** @file
+ Component Name functions implementation for XenPvBlk driver.
+
+ Copyright (C) 2014, Citrix Ltd.
+
+ SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#include "XenPvBlkDxe.h"
+
+///
+/// Component Name Protocol instance
+///
+GLOBAL_REMOVE_IF_UNREFERENCED
+EFI_COMPONENT_NAME_PROTOCOL gXenPvBlkDxeComponentName = {
+ (EFI_COMPONENT_NAME_GET_DRIVER_NAME) XenPvBlkDxeComponentNameGetDriverName,
+ (EFI_COMPONENT_NAME_GET_CONTROLLER_NAME)XenPvBlkDxeComponentNameGetControllerName,
+ "eng"
+};
+
+///
+/// Component Name 2 Protocol instance
+///
+GLOBAL_REMOVE_IF_UNREFERENCED
+EFI_COMPONENT_NAME2_PROTOCOL gXenPvBlkDxeComponentName2 = {
+ XenPvBlkDxeComponentNameGetDriverName,
+ XenPvBlkDxeComponentNameGetControllerName,
+ "en"
+};
+
+///
+/// Table of driver names
+///
+GLOBAL_REMOVE_IF_UNREFERENCED
+EFI_UNICODE_STRING_TABLE mXenPvBlkDxeDriverNameTable[] = {
+ { "eng;en", (CHAR16 *)L"Xen PV Block Driver" },
+ { NULL, NULL }
+};
+
+///
+/// Table of controller names
+///
+GLOBAL_REMOVE_IF_UNREFERENCED
+EFI_UNICODE_STRING_TABLE mXenPvBlkDxeControllerNameTable[] = {
+ { "eng;en", (CHAR16 *)L"Xen PV Block Device" },
+ { 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
+XenPvBlkDxeComponentNameGetDriverName (
+ IN EFI_COMPONENT_NAME2_PROTOCOL *This,
+ IN CHAR8 *Language,
+ OUT CHAR16 **DriverName
+ )
+{
+ return LookupUnicodeString2 (
+ Language,
+ This->SupportedLanguages,
+ mXenPvBlkDxeDriverNameTable,
+ DriverName,
+ (BOOLEAN)(This != &gXenPvBlkDxeComponentName2)
+ );
+}
+
+/**
+ 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
+XenPvBlkDxeComponentNameGetControllerName (
+ IN EFI_COMPONENT_NAME2_PROTOCOL *This,
+ IN EFI_HANDLE ControllerHandle,
+ IN EFI_HANDLE ChildHandle OPTIONAL,
+ IN CHAR8 *Language,
+ OUT CHAR16 **ControllerName
+ )
+{
+ EFI_STATUS Status;
+
+ //
+ // ChildHandle must be NULL for a Device Driver
+ //
+ if (ChildHandle != NULL) {
+ return EFI_UNSUPPORTED;
+ }
+
+ //
+ // Make sure this driver is currently managing ControllerHandle
+ //
+ Status = EfiTestManagedDevice (
+ ControllerHandle,
+ gXenPvBlkDxeDriverBinding.DriverBindingHandle,
+ &gXenBusProtocolGuid
+ );
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ //
+ // Lookup name of controller specified by ControllerHandle
+ //
+ return LookupUnicodeString2 (
+ Language,
+ This->SupportedLanguages,
+ mXenPvBlkDxeControllerNameTable,
+ ControllerName,
+ (BOOLEAN)(This != &gXenPvBlkDxeComponentName2)
+ );
+}
diff --git a/roms/edk2/OvmfPkg/XenPvBlkDxe/ComponentName.h b/roms/edk2/OvmfPkg/XenPvBlkDxe/ComponentName.h new file mode 100644 index 000000000..12ea12601 --- /dev/null +++ b/roms/edk2/OvmfPkg/XenPvBlkDxe/ComponentName.h @@ -0,0 +1,88 @@ +/** @file
+ Component Name functions declaration for XenPvBlk 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
+XenPvBlkDxeComponentNameGetDriverName (
+ 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
+XenPvBlkDxeComponentNameGetControllerName (
+ 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/XenPvBlkDxe/DriverBinding.h b/roms/edk2/OvmfPkg/XenPvBlkDxe/DriverBinding.h new file mode 100644 index 000000000..fa2983644 --- /dev/null +++ b/roms/edk2/OvmfPkg/XenPvBlkDxe/DriverBinding.h @@ -0,0 +1,137 @@ +
+/** @file
+ Driver Binding functions declaration for XenPvBlk 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.
+
+ This function checks to see if the driver specified by This supports the device specified by
+ ControllerHandle. Drivers will typically use the device path attached to
+ ControllerHandle and/or the services from the bus I/O abstraction attached to
+ ControllerHandle to determine if the driver supports ControllerHandle. This function
+ may be called many times during platform initialization. In order to reduce boot times, the tests
+ performed by this function must be very small, and take as little time as possible to execute. This
+ function must not change the state of any hardware devices, and this function must be aware that the
+ device specified by ControllerHandle may already be managed by the same driver or a
+ different driver. This function must match its calls to AllocatePages() with FreePages(),
+ AllocatePool() with FreePool(), and OpenProtocol() with CloseProtocol().
+ Because ControllerHandle may have been previously started by the same driver, if a protocol is
+ already in the opened state, then it must not be closed with CloseProtocol(). This is required
+ to guarantee the state of ControllerHandle is not modified by this function.
+
+ @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
+XenPvBlkDxeDriverBindingSupported (
+ 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
+XenPvBlkDxeDriverBindingStart (
+ 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
+XenPvBlkDxeDriverBindingStop (
+ IN EFI_DRIVER_BINDING_PROTOCOL *This,
+ IN EFI_HANDLE ControllerHandle,
+ IN UINTN NumberOfChildren,
+ IN EFI_HANDLE *ChildHandleBuffer OPTIONAL
+ );
diff --git a/roms/edk2/OvmfPkg/XenPvBlkDxe/XenPvBlkDxe.c b/roms/edk2/OvmfPkg/XenPvBlkDxe/XenPvBlkDxe.c new file mode 100644 index 000000000..1440e1d23 --- /dev/null +++ b/roms/edk2/OvmfPkg/XenPvBlkDxe/XenPvBlkDxe.c @@ -0,0 +1,388 @@ +/** @file
+ This driver produce a BlockIo protocol instance for a Xen PV block device.
+
+ This driver support XenBus protocol of type 'vbd'. Every function that
+ comsume XenBus protocol are in BlockFront, which the implementation to access
+ a Xen PV device. The BlockIo implementation is in it's one file and will call
+ BlockFront functions.
+
+ Copyright (C) 2014, Citrix Ltd.
+
+ SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#include "XenPvBlkDxe.h"
+
+#include "BlockFront.h"
+
+
+///
+/// Driver Binding Protocol instance
+///
+EFI_DRIVER_BINDING_PROTOCOL gXenPvBlkDxeDriverBinding = {
+ XenPvBlkDxeDriverBindingSupported,
+ XenPvBlkDxeDriverBindingStart,
+ XenPvBlkDxeDriverBindingStop,
+ XEN_PV_BLK_DXE_VERSION,
+ NULL,
+ NULL
+};
+
+
+/**
+ 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
+XenPvBlkDxeUnload (
+ 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, &gXenPvBlkDxeDriverBinding,
+ &gEfiComponentNameProtocolGuid, &gXenPvBlkDxeComponentName,
+ &gEfiComponentName2ProtocolGuid, &gXenPvBlkDxeComponentName2,
+ 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 Others An unexpected error occurred.
+**/
+EFI_STATUS
+EFIAPI
+XenPvBlkDxeDriverEntryPoint (
+ IN EFI_HANDLE ImageHandle,
+ IN EFI_SYSTEM_TABLE *SystemTable
+ )
+{
+ EFI_STATUS Status;
+
+ //
+ // Install UEFI Driver Model protocol(s).
+ //
+ Status = EfiLibInstallDriverBindingComponentName2 (
+ ImageHandle,
+ SystemTable,
+ &gXenPvBlkDxeDriverBinding,
+ ImageHandle,
+ &gXenPvBlkDxeComponentName,
+ &gXenPvBlkDxeComponentName2
+ );
+ 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.
+
+ This function checks to see if the driver specified by This supports the device specified by
+ ControllerHandle. Drivers will typically use the device path attached to
+ ControllerHandle and/or the services from the bus I/O abstraction attached to
+ ControllerHandle to determine if the driver supports ControllerHandle. This function
+ may be called many times during platform initialization. In order to reduce boot times, the tests
+ performed by this function must be very small, and take as little time as possible to execute. This
+ function must not change the state of any hardware devices, and this function must be aware that the
+ device specified by ControllerHandle may already be managed by the same driver or a
+ different driver. This function must match its calls to AllocatePages() with FreePages(),
+ AllocatePool() with FreePool(), and OpenProtocol() with CloseProtocol().
+ Because ControllerHandle may have been previously started by the same driver, if a protocol is
+ already in the opened state, then it must not be closed with CloseProtocol(). This is required
+ to guarantee the state of ControllerHandle is not modified by this function.
+
+ @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
+XenPvBlkDxeDriverBindingSupported (
+ IN EFI_DRIVER_BINDING_PROTOCOL *This,
+ IN EFI_HANDLE ControllerHandle,
+ IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath OPTIONAL
+ )
+{
+ EFI_STATUS Status;
+ XENBUS_PROTOCOL *XenBusIo;
+
+ Status = gBS->OpenProtocol (
+ ControllerHandle,
+ &gXenBusProtocolGuid,
+ (VOID **)&XenBusIo,
+ This->DriverBindingHandle,
+ ControllerHandle,
+ EFI_OPEN_PROTOCOL_BY_DRIVER
+ );
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+ if (AsciiStrCmp (XenBusIo->Type, "vbd") == 0) {
+ Status = EFI_SUCCESS;
+ } else {
+ Status = EFI_UNSUPPORTED;
+ }
+
+ gBS->CloseProtocol (ControllerHandle, &gXenBusProtocolGuid,
+ This->DriverBindingHandle, ControllerHandle);
+
+ return Status;
+}
+
+/**
+ Starts a device 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
+XenPvBlkDxeDriverBindingStart (
+ IN EFI_DRIVER_BINDING_PROTOCOL *This,
+ IN EFI_HANDLE ControllerHandle,
+ IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath OPTIONAL
+ )
+{
+ EFI_STATUS Status;
+ XENBUS_PROTOCOL *XenBusIo;
+ XEN_BLOCK_FRONT_DEVICE *Dev;
+ EFI_BLOCK_IO_MEDIA *Media;
+
+ Status = gBS->OpenProtocol (
+ ControllerHandle,
+ &gXenBusProtocolGuid,
+ (VOID **)&XenBusIo,
+ This->DriverBindingHandle,
+ ControllerHandle,
+ EFI_OPEN_PROTOCOL_BY_DRIVER
+ );
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ Status = XenPvBlockFrontInitialization (XenBusIo, XenBusIo->Node, &Dev);
+ if (EFI_ERROR (Status)) {
+ goto CloseProtocol;
+ }
+
+ CopyMem (&Dev->BlockIo, &gXenPvBlkDxeBlockIo, sizeof (EFI_BLOCK_IO_PROTOCOL));
+ Media = AllocateCopyPool (sizeof (EFI_BLOCK_IO_MEDIA),
+ &gXenPvBlkDxeBlockIoMedia);
+ if (Dev->MediaInfo.VDiskInfo & VDISK_REMOVABLE) {
+ Media->RemovableMedia = TRUE;
+ }
+ Media->MediaPresent = TRUE;
+ Media->ReadOnly = !Dev->MediaInfo.ReadWrite;
+ if (Dev->MediaInfo.CdRom) {
+ //
+ // If it's a cdrom, the blocksize value need to be 2048 for OVMF to
+ // recognize it as a cdrom:
+ // MdeModulePkg/Universal/Disk/PartitionDxe/ElTorito.c
+ //
+ Media->BlockSize = 2048;
+ Media->LastBlock = DivU64x32 (Dev->MediaInfo.Sectors,
+ Media->BlockSize / Dev->MediaInfo.SectorSize) - 1;
+ } else {
+ Media->BlockSize = Dev->MediaInfo.SectorSize;
+ Media->LastBlock = Dev->MediaInfo.Sectors - 1;
+ }
+ ASSERT (Media->BlockSize % 512 == 0);
+ Dev->BlockIo.Media = Media;
+
+ Status = gBS->InstallMultipleProtocolInterfaces (
+ &ControllerHandle,
+ &gEfiBlockIoProtocolGuid, &Dev->BlockIo,
+ NULL
+ );
+ if (EFI_ERROR (Status)) {
+ DEBUG ((DEBUG_ERROR, "XenPvBlk: install protocol fail: %r\n", Status));
+ goto UninitBlockFront;
+ }
+
+ return EFI_SUCCESS;
+
+UninitBlockFront:
+ FreePool (Media);
+ XenPvBlockFrontShutdown (Dev);
+CloseProtocol:
+ gBS->CloseProtocol (ControllerHandle, &gXenBusProtocolGuid,
+ This->DriverBindingHandle, ControllerHandle);
+ return Status;
+}
+
+/**
+ Stops a device 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
+XenPvBlkDxeDriverBindingStop (
+ IN EFI_DRIVER_BINDING_PROTOCOL *This,
+ IN EFI_HANDLE ControllerHandle,
+ IN UINTN NumberOfChildren,
+ IN EFI_HANDLE *ChildHandleBuffer OPTIONAL
+ )
+{
+ EFI_BLOCK_IO_PROTOCOL *BlockIo;
+ XEN_BLOCK_FRONT_DEVICE *Dev;
+ EFI_BLOCK_IO_MEDIA *Media;
+ EFI_STATUS Status;
+
+ Status = gBS->OpenProtocol (
+ ControllerHandle, &gEfiBlockIoProtocolGuid,
+ (VOID **)&BlockIo,
+ This->DriverBindingHandle, ControllerHandle,
+ EFI_OPEN_PROTOCOL_GET_PROTOCOL
+ );
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ Status = gBS->UninstallProtocolInterface (ControllerHandle,
+ &gEfiBlockIoProtocolGuid, BlockIo);
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ Media = BlockIo->Media;
+ Dev = XEN_BLOCK_FRONT_FROM_BLOCK_IO (BlockIo);
+ XenPvBlockFrontShutdown (Dev);
+
+ FreePool (Media);
+
+ gBS->CloseProtocol (ControllerHandle, &gXenBusProtocolGuid,
+ This->DriverBindingHandle, ControllerHandle);
+
+ return EFI_SUCCESS;
+}
diff --git a/roms/edk2/OvmfPkg/XenPvBlkDxe/XenPvBlkDxe.h b/roms/edk2/OvmfPkg/XenPvBlkDxe/XenPvBlkDxe.h new file mode 100644 index 000000000..78c103deb --- /dev/null +++ b/roms/edk2/OvmfPkg/XenPvBlkDxe/XenPvBlkDxe.h @@ -0,0 +1,73 @@ +/** @file
+ Main header for XenPvBlkDxe
+
+ Copyright (C) 2014, Citrix Ltd.
+
+ SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#ifndef __EFI_XEN_PV_BLK_DXE_H__
+#define __EFI_XEN_PV_BLK_DXE_H__
+
+#include <Uefi.h>
+
+#define xen_mb() MemoryFence()
+#define xen_rmb() MemoryFence()
+#define xen_wmb() MemoryFence()
+
+//
+// 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>
+
+
+//
+// UEFI Driver Model Protocols
+//
+#include <Protocol/DriverBinding.h>
+#include <Protocol/ComponentName2.h>
+#include <Protocol/ComponentName.h>
+
+
+//
+// Consumed Protocols
+//
+#include <Protocol/XenBus.h>
+
+
+//
+// Produced Protocols
+//
+#include <Protocol/BlockIo.h>
+
+
+//
+// Driver Version
+//
+#define XEN_PV_BLK_DXE_VERSION 0x00000010
+
+
+//
+// Protocol instances
+//
+extern EFI_DRIVER_BINDING_PROTOCOL gXenPvBlkDxeDriverBinding;
+extern EFI_COMPONENT_NAME2_PROTOCOL gXenPvBlkDxeComponentName2;
+extern EFI_COMPONENT_NAME_PROTOCOL gXenPvBlkDxeComponentName;
+
+
+//
+// Include files with function prototypes
+//
+#include "DriverBinding.h"
+#include "ComponentName.h"
+#include "BlockIo.h"
+
+
+#endif
diff --git a/roms/edk2/OvmfPkg/XenPvBlkDxe/XenPvBlkDxe.inf b/roms/edk2/OvmfPkg/XenPvBlkDxe/XenPvBlkDxe.inf new file mode 100644 index 000000000..5dd8e8be1 --- /dev/null +++ b/roms/edk2/OvmfPkg/XenPvBlkDxe/XenPvBlkDxe.inf @@ -0,0 +1,57 @@ +## @file
+# This driver produces a Block I/O protocol for a Xen PV block device.
+#
+# Copyright (C) 2014, Citrix Ltd.
+#
+# SPDX-License-Identifier: BSD-2-Clause-Patent
+#
+##
+
+[Defines]
+ INF_VERSION = 0x00010005
+ BASE_NAME = XenPvBlkDxe
+ FILE_GUID = 8c2487ea-9af3-11e3-b966-b8ac6f7d65e6
+ MODULE_TYPE = UEFI_DRIVER
+
+ VERSION_STRING = 1.0
+ ENTRY_POINT = XenPvBlkDxeDriverEntryPoint
+ UNLOAD_IMAGE = XenPvBlkDxeUnload
+
+
+[Packages]
+ MdePkg/MdePkg.dec
+ OvmfPkg/OvmfPkg.dec
+
+[Sources]
+ BlockFront.c
+ BlockFront.h
+ BlockIo.c
+ BlockIo.h
+ ComponentName.c
+ ComponentName.h
+ DriverBinding.h
+ XenPvBlkDxe.c
+ XenPvBlkDxe.h
+
+
+[LibraryClasses]
+ UefiDriverEntryPoint
+ UefiBootServicesTableLib
+ MemoryAllocationLib
+ BaseMemoryLib
+ BaseLib
+ UefiLib
+ DevicePathLib
+ DebugLib
+
+
+[Protocols]
+ gEfiDriverBindingProtocolGuid
+ gEfiBlockIoProtocolGuid
+ gEfiComponentName2ProtocolGuid
+ gEfiComponentNameProtocolGuid
+ gXenBusProtocolGuid
+
+
+[Guids]
+
|