summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--OvmfPkg/VirtioNetDxe/SnpInitialize.c18
-rw-r--r--OvmfPkg/VirtioNetDxe/SnpSharedHelpers.c224
-rw-r--r--OvmfPkg/VirtioNetDxe/VirtioNet.h38
-rw-r--r--OvmfPkg/VirtioNetDxe/VirtioNet.inf1
4 files changed, 279 insertions, 2 deletions
diff --git a/OvmfPkg/VirtioNetDxe/SnpInitialize.c b/OvmfPkg/VirtioNetDxe/SnpInitialize.c
index 9621f936d2..ffb3deefe0 100644
--- a/OvmfPkg/VirtioNetDxe/SnpInitialize.c
+++ b/OvmfPkg/VirtioNetDxe/SnpInitialize.c
@@ -147,7 +147,8 @@ ReleaseQueue:
EfiSimpleNetworkInitialized state.
@retval EFI_OUT_OF_RESOURCES Failed to allocate the stack to track the heads
- of free descriptor chains.
+ of free descriptor chains or failed to init
+ TxBufCollection.
@return Status codes from VIRTIO_DEVICE_PROTOCOL.
AllocateSharedPages() or
VirtioMapAllBytesInSharedBuffer()
@@ -176,6 +177,15 @@ VirtioNetInitTx (
return EFI_OUT_OF_RESOURCES;
}
+ Dev->TxBufCollection = OrderedCollectionInit (
+ VirtioNetTxBufMapInfoCompare,
+ VirtioNetTxBufDeviceAddressCompare
+ );
+ if (Dev->TxBufCollection == NULL) {
+ Status = EFI_OUT_OF_RESOURCES;
+ goto FreeTxFreeStack;
+ }
+
//
// Allocate TxSharedReq header and map with BusMasterCommonBuffer so that it
// can be accessed equally by both processor and device.
@@ -186,7 +196,7 @@ VirtioNetInitTx (
&TxSharedReqBuffer
);
if (EFI_ERROR (Status)) {
- goto FreeTxFreeStack;
+ goto UninitTxBufCollection;
}
ZeroMem (TxSharedReqBuffer, sizeof *Dev->TxSharedReq);
@@ -267,6 +277,10 @@ FreeTxSharedReqBuffer:
EFI_SIZE_TO_PAGES (sizeof *(Dev->TxSharedReq)),
TxSharedReqBuffer
);
+
+UninitTxBufCollection:
+ OrderedCollectionUninit (Dev->TxBufCollection);
+
FreeTxFreeStack:
FreePool (Dev->TxFreeStack);
diff --git a/OvmfPkg/VirtioNetDxe/SnpSharedHelpers.c b/OvmfPkg/VirtioNetDxe/SnpSharedHelpers.c
index 2fce8142d5..18dbf18125 100644
--- a/OvmfPkg/VirtioNetDxe/SnpSharedHelpers.c
+++ b/OvmfPkg/VirtioNetDxe/SnpSharedHelpers.c
@@ -18,6 +18,16 @@
#include "VirtioNet.h"
+//
+// The user structure for the ordered collection that will track the mapping
+// info of the packets queued in TxRing
+//
+typedef struct {
+ VOID *Buffer;
+ EFI_PHYSICAL_ADDRESS DeviceAddress; // lookup key for reverse mapping
+ VOID *BufMap;
+} TX_BUF_MAP_INFO;
+
/**
Release RX and TX resources on the boundary of the
EfiSimpleNetworkInitialized state.
@@ -54,6 +64,10 @@ VirtioNetShutdownTx (
IN OUT VNET_DEV *Dev
)
{
+ ORDERED_COLLECTION_ENTRY *Entry, *Entry2;
+ TX_BUF_MAP_INFO *TxBufMapInfo;
+ VOID *UserStruct;
+
Dev->VirtIo->UnmapSharedBuffer (Dev->VirtIo, Dev->TxSharedReqMap);
Dev->VirtIo->FreeSharedPages (
Dev->VirtIo,
@@ -61,6 +75,17 @@ VirtioNetShutdownTx (
Dev->TxSharedReq
);
+ for (Entry = OrderedCollectionMin (Dev->TxBufCollection);
+ Entry != NULL;
+ Entry = Entry2) {
+ Entry2 = OrderedCollectionNext (Entry);
+ OrderedCollectionDelete (Dev->TxBufCollection, Entry, &UserStruct);
+ TxBufMapInfo = UserStruct;
+ Dev->VirtIo->UnmapSharedBuffer (Dev->VirtIo, TxBufMapInfo->BufMap);
+ FreePool (TxBufMapInfo);
+ }
+ OrderedCollectionUninit (Dev->TxBufCollection);
+
FreePool (Dev->TxFreeStack);
}
@@ -83,3 +108,202 @@ VirtioNetUninitRing (
Dev->VirtIo->UnmapSharedBuffer (Dev->VirtIo, RingMap);
VirtioRingUninit (Dev->VirtIo, Ring);
}
+
+
+/**
+ Map Caller-supplied TxBuf buffer to the device-mapped address
+
+ @param[in] Dev The VNET_DEV driver instance which wants to
+ map the Tx packet.
+ @param[in] Buffer The system physical address of TxBuf
+ @param[in] NumberOfBytes Number of bytes to map
+ @param[out] DeviceAddress The resulting device address for the bus
+ master access.
+
+ @retval EFI_OUT_OF_RESOURCES The request could not be completed due to
+ a lack of resources.
+ @return Status codes from
+ VirtioMapAllBytesInSharedBuffer()
+ @retval EFI_SUCCESS Caller-supplied buffer is succesfully mapped.
+*/
+EFI_STATUS
+EFIAPI
+VirtioNetMapTxBuf (
+ IN VNET_DEV *Dev,
+ IN VOID *Buffer,
+ IN UINTN NumberOfBytes,
+ OUT EFI_PHYSICAL_ADDRESS *DeviceAddress
+ )
+{
+ EFI_STATUS Status;
+ TX_BUF_MAP_INFO *TxBufMapInfo;
+ EFI_PHYSICAL_ADDRESS Address;
+ VOID *Mapping;
+
+ TxBufMapInfo = AllocatePool (sizeof (*TxBufMapInfo));
+ if (TxBufMapInfo == NULL) {
+ return EFI_OUT_OF_RESOURCES;
+ }
+
+ Status = VirtioMapAllBytesInSharedBuffer (
+ Dev->VirtIo,
+ VirtioOperationBusMasterRead,
+ Buffer,
+ NumberOfBytes,
+ &Address,
+ &Mapping
+ );
+ if (EFI_ERROR (Status)) {
+ goto FreeTxBufMapInfo;
+ }
+
+ TxBufMapInfo->Buffer = Buffer;
+ TxBufMapInfo->DeviceAddress = Address;
+ TxBufMapInfo->BufMap = Mapping;
+
+ Status = OrderedCollectionInsert (
+ Dev->TxBufCollection,
+ NULL,
+ TxBufMapInfo
+ );
+ switch (Status) {
+ case EFI_OUT_OF_RESOURCES:
+ goto UnmapTxBuf;
+ case EFI_ALREADY_STARTED:
+ //
+ // This should never happen: it implies
+ //
+ // - an identity-mapping VIRTIO_DEVICE_PROTOCOL.MapSharedBuffer()
+ // implementation -- which is fine,
+ //
+ // - and an SNP client that queues multiple instances of the exact same
+ // buffer address with SNP.Transmit() -- which is undefined behavior,
+ // based on the TxBuf language in UEFI-2.7,
+ // EFI_SIMPLE_NETWORK.GetStatus().
+ //
+ ASSERT (FALSE);
+ Status = EFI_INVALID_PARAMETER;
+ goto UnmapTxBuf;
+ default:
+ ASSERT_EFI_ERROR (Status);
+ break;
+ }
+
+ *DeviceAddress = Address;
+ return EFI_SUCCESS;
+
+UnmapTxBuf:
+ Dev->VirtIo->UnmapSharedBuffer (Dev->VirtIo, Mapping);
+
+FreeTxBufMapInfo:
+ FreePool (TxBufMapInfo);
+ return Status;
+}
+
+/**
+ Unmap (aka reverse mapping) device mapped TxBuf buffer to the system
+ physical address
+
+ @param[in] Dev The VNET_DEV driver instance which wants to
+ reverse- and unmap the Tx packet.
+ @param[out] Buffer The system physical address of TxBuf
+ @param[in] DeviceAddress The device address for the TxBuf
+
+ @retval EFI_INVALID_PARAMETER The DeviceAddress is not mapped
+ @retval EFI_SUCCESS The TxBuf at DeviceAddress has been unmapped,
+ and Buffer has been set to TxBuf's system
+ physical address.
+
+*/
+EFI_STATUS
+EFIAPI
+VirtioNetUnmapTxBuf (
+ IN VNET_DEV *Dev,
+ OUT VOID **Buffer,
+ IN EFI_PHYSICAL_ADDRESS DeviceAddress
+ )
+{
+ ORDERED_COLLECTION_ENTRY *Entry;
+ TX_BUF_MAP_INFO *TxBufMapInfo;
+ VOID *UserStruct;
+
+ Entry = OrderedCollectionFind (Dev->TxBufCollection, &DeviceAddress);
+ if (Entry == NULL) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ OrderedCollectionDelete (Dev->TxBufCollection, Entry, &UserStruct);
+
+ TxBufMapInfo = UserStruct;
+
+ *Buffer = TxBufMapInfo->Buffer;
+ Dev->VirtIo->UnmapSharedBuffer (Dev->VirtIo, TxBufMapInfo->BufMap);
+ FreePool (TxBufMapInfo);
+
+ return EFI_SUCCESS;
+}
+
+/**
+ Comparator function for two TX_BUF_MAP_INFO objects.
+
+ @param[in] UserStruct1 Pointer to the first TX_BUF_MAP_INFO object.
+
+ @param[in] UserStruct2 Pointer to the second TX_BUF_MAP_INFO object.
+
+ @retval <0 If UserStruct1 compares less than UserStruct2.
+
+ @retval 0 If UserStruct1 compares equal to UserStruct2.
+
+ @retval >0 If UserStruct1 compares greater than UserStruct2.
+*/
+INTN
+EFIAPI
+VirtioNetTxBufMapInfoCompare (
+ IN CONST VOID *UserStruct1,
+ IN CONST VOID *UserStruct2
+ )
+{
+ CONST TX_BUF_MAP_INFO *MapInfo1;
+ CONST TX_BUF_MAP_INFO *MapInfo2;
+
+ MapInfo1 = UserStruct1;
+ MapInfo2 = UserStruct2;
+
+ return MapInfo1->DeviceAddress < MapInfo2->DeviceAddress ? -1 :
+ MapInfo1->DeviceAddress > MapInfo2->DeviceAddress ? 1 :
+ 0;
+}
+
+/**
+ Compare a standalone DeviceAddress against a TX_BUF_MAP_INFO object
+ containing an embedded DeviceAddress.
+
+ @param[in] StandaloneKey Pointer to DeviceAddress, which has type
+ EFI_PHYSICAL_ADDRESS.
+
+ @param[in] UserStruct Pointer to the TX_BUF_MAP_INFO object with the
+ embedded DeviceAddress.
+
+ @retval <0 If StandaloneKey compares less than UserStruct's key.
+
+ @retval 0 If StandaloneKey compares equal to UserStruct's key.
+
+ @retval >0 If StandaloneKey compares greater than UserStruct's key.
+**/
+INTN
+EFIAPI
+VirtioNetTxBufDeviceAddressCompare (
+ IN CONST VOID *StandaloneKey,
+ IN CONST VOID *UserStruct
+ )
+{
+ CONST EFI_PHYSICAL_ADDRESS *DeviceAddress;
+ CONST TX_BUF_MAP_INFO *MapInfo;
+
+ DeviceAddress = StandaloneKey;
+ MapInfo = UserStruct;
+
+ return *DeviceAddress < MapInfo->DeviceAddress ? -1 :
+ *DeviceAddress > MapInfo->DeviceAddress ? 1 :
+ 0;
+}
diff --git a/OvmfPkg/VirtioNetDxe/VirtioNet.h b/OvmfPkg/VirtioNetDxe/VirtioNet.h
index 027f75993e..3fc88cfb79 100644
--- a/OvmfPkg/VirtioNetDxe/VirtioNet.h
+++ b/OvmfPkg/VirtioNetDxe/VirtioNet.h
@@ -26,6 +26,7 @@
#include <Protocol/DevicePath.h>
#include <Protocol/DriverBinding.h>
#include <Protocol/SimpleNetwork.h>
+#include <Library/OrderedCollectionLib.h>
#define VNET_SIG SIGNATURE_32 ('V', 'N', 'E', 'T')
@@ -100,6 +101,7 @@ typedef struct {
VIRTIO_1_0_NET_REQ *TxSharedReq; // VirtioNetInitTx
VOID *TxSharedReqMap; // VirtioNetInitTx
UINT16 TxLastUsed; // VirtioNetInitTx
+ ORDERED_COLLECTION *TxBufCollection; // VirtioNetInitTx
} VNET_DEV;
@@ -281,6 +283,42 @@ VirtioNetUninitRing (
);
//
+// utility functions to map caller-supplied Tx buffer system physical address
+// to a device address and vice versa
+//
+EFI_STATUS
+EFIAPI
+VirtioNetMapTxBuf (
+ IN VNET_DEV *Dev,
+ IN VOID *Buffer,
+ IN UINTN NumberOfBytes,
+ OUT EFI_PHYSICAL_ADDRESS *DeviceAddress
+ );
+
+EFI_STATUS
+EFIAPI
+VirtioNetUnmapTxBuf (
+ IN VNET_DEV *Dev,
+ OUT VOID **Buffer,
+ IN EFI_PHYSICAL_ADDRESS DeviceAddress
+ );
+
+INTN
+EFIAPI
+VirtioNetTxBufMapInfoCompare (
+ IN CONST VOID *UserStruct1,
+ IN CONST VOID *UserStruct2
+ );
+
+INTN
+EFIAPI
+VirtioNetTxBufDeviceAddressCompare (
+ IN CONST VOID *StandaloneKey,
+ IN CONST VOID *UserStruct
+ );
+
+
+//
// event callbacks
//
VOID
diff --git a/OvmfPkg/VirtioNetDxe/VirtioNet.inf b/OvmfPkg/VirtioNetDxe/VirtioNet.inf
index a855ad4ac1..9ff6d87e61 100644
--- a/OvmfPkg/VirtioNetDxe/VirtioNet.inf
+++ b/OvmfPkg/VirtioNetDxe/VirtioNet.inf
@@ -49,6 +49,7 @@
DebugLib
DevicePathLib
MemoryAllocationLib
+ OrderedCollectionLib
UefiBootServicesTableLib
UefiDriverEntryPoint
UefiLib