MdeModulePkg/XhciDxe: Add boundary check for TRB ring allocation

According the Xhci Spec, TRB Rings may be larger than a Page, however they
shall not cross a 64K byte boundary, so add a parameter to indicate
whether the memory allocation is for TRB Rings or not. It will ensure the
allocation not crossing 64K boundary in UsbHcAllocMemFromBlock if the
memory is allocated for TRB Rings.

Signed-off-by: jdzhang <jdzhang@kunluntech.com.cn>
Reviewed-by: Hao A Wu <hao.a.wu@intel.com>
This commit is contained in:
jdzhang 2022-10-18 10:56:02 +08:00 committed by mergify[bot]
parent 31b1638468
commit c6720db5dd
3 changed files with 47 additions and 22 deletions

View File

@ -132,8 +132,9 @@ UsbHcFreeMemBlock (
/**
Alloc some memory from the block.
@param Block The memory block to allocate memory from.
@param Units Number of memory units to allocate.
@param Block The memory block to allocate memory from.
@param Units Number of memory units to allocate.
@param AllocationForRing The allocated memory is for Ring or not.
@return The pointer to the allocated memory. If couldn't allocate the needed memory,
the return value is NULL.
@ -142,7 +143,8 @@ UsbHcFreeMemBlock (
VOID *
UsbHcAllocMemFromBlock (
IN USBHC_MEM_BLOCK *Block,
IN UINTN Units
IN UINTN Units,
IN BOOLEAN AllocationForRing
)
{
UINTN Byte;
@ -151,12 +153,15 @@ UsbHcAllocMemFromBlock (
UINT8 StartBit;
UINTN Available;
UINTN Count;
UINTN MemUnitAddr;
UINTN AlignmentMask;
ASSERT ((Block != 0) && (Units != 0));
StartByte = 0;
StartBit = 0;
Available = 0;
StartByte = 0;
StartBit = 0;
Available = 0;
AlignmentMask = ~((UINTN)USBHC_MEM_TRB_RINGS_BOUNDARY - 1);
for (Byte = 0, Bit = 0; Byte < Block->BitsLen;) {
//
@ -165,6 +170,20 @@ UsbHcAllocMemFromBlock (
// Available counts the consective number of zero bit.
//
if (!USB_HC_BIT_IS_SET (Block->Bits[Byte], Bit)) {
if (AllocationForRing && (Available != 0)) {
MemUnitAddr = (UINTN)Block->BufHost + (Byte * 8 + Bit) * USBHC_MEM_UNIT;
if ((MemUnitAddr & AlignmentMask) != ((MemUnitAddr - USBHC_MEM_UNIT) & AlignmentMask)) {
//
// If the TRB Ring memory cross 64K-byte boundary, then restart the
// search starting at current memory unit.
// Doing so is to meet the TRB Ring boundary requirement in XHCI spec.
//
Available = 0;
StartByte = Byte;
StartBit = Bit;
}
}
Available++;
if (Available >= Units) {
@ -438,8 +457,9 @@ UsbHcFreeMemPool (
Allocate some memory from the host controller's memory pool
which can be used to communicate with host controller.
@param Pool The host controller's memory pool.
@param Size Size of the memory to allocate.
@param Pool The host controller's memory pool.
@param Size Size of the memory to allocate.
@param AllocationForRing The allocated memory is for Ring or not.
@return The allocated memory or NULL.
@ -447,7 +467,8 @@ UsbHcFreeMemPool (
VOID *
UsbHcAllocateMem (
IN USBHC_MEM_POOL *Pool,
IN UINTN Size
IN UINTN Size,
IN BOOLEAN AllocationForRing
)
{
USBHC_MEM_BLOCK *Head;
@ -466,7 +487,7 @@ UsbHcAllocateMem (
// First check whether current memory blocks can satisfy the allocation.
//
for (Block = Head; Block != NULL; Block = Block->Next) {
Mem = UsbHcAllocMemFromBlock (Block, AllocSize / USBHC_MEM_UNIT);
Mem = UsbHcAllocMemFromBlock (Block, AllocSize / USBHC_MEM_UNIT, AllocationForRing);
if (Mem != NULL) {
ZeroMem (Mem, Size);
@ -501,7 +522,7 @@ UsbHcAllocateMem (
// Add the new memory block to the pool, then allocate memory from it
//
UsbHcInsertMemBlockToPool (Head, NewBlock);
Mem = UsbHcAllocMemFromBlock (NewBlock, AllocSize / USBHC_MEM_UNIT);
Mem = UsbHcAllocMemFromBlock (NewBlock, AllocSize / USBHC_MEM_UNIT, AllocationForRing);
if (Mem != NULL) {
ZeroMem (Mem, Size);

View File

@ -48,6 +48,8 @@ typedef struct _USBHC_MEM_POOL {
#define USBHC_MEM_ROUND(Len) (((Len) + USBHC_MEM_UNIT_MASK) & (~USBHC_MEM_UNIT_MASK))
#define USBHC_MEM_TRB_RINGS_BOUNDARY SIZE_64KB
//
// Advance the byte and bit to the next bit, adjust byte accordingly.
//
@ -92,8 +94,9 @@ UsbHcFreeMemPool (
Allocate some memory from the host controller's memory pool
which can be used to communicate with host controller.
@param Pool The host controller's memory pool.
@param Size Size of the memory to allocate.
@param Pool The host controller's memory pool.
@param Size Size of the memory to allocate.
@param AllocationForRing The allocated memory is for Ring or not.
@return The allocated memory or NULL.
@ -101,7 +104,8 @@ UsbHcFreeMemPool (
VOID *
UsbHcAllocateMem (
IN USBHC_MEM_POOL *Pool,
IN UINTN Size
IN UINTN Size,
IN BOOLEAN AllocationForRing
);
/**

View File

@ -506,7 +506,7 @@ XhcInitSched (
// Software shall set Device Context Base Address Array entries for unallocated Device Slots to '0'.
//
Entries = (Xhc->MaxSlotsEn + 1) * sizeof (UINT64);
Dcbaa = UsbHcAllocateMem (Xhc->MemPool, Entries);
Dcbaa = UsbHcAllocateMem (Xhc->MemPool, Entries, FALSE);
ASSERT (Dcbaa != NULL);
ZeroMem (Dcbaa, Entries);
@ -795,7 +795,7 @@ CreateEventRing (
ASSERT (EventRing != NULL);
Size = sizeof (TRB_TEMPLATE) * EVENT_RING_TRB_NUMBER;
Buf = UsbHcAllocateMem (Xhc->MemPool, Size);
Buf = UsbHcAllocateMem (Xhc->MemPool, Size, TRUE);
ASSERT (Buf != NULL);
ASSERT (((UINTN)Buf & 0x3F) == 0);
ZeroMem (Buf, Size);
@ -814,7 +814,7 @@ CreateEventRing (
EventRing->EventRingCCS = 1;
Size = sizeof (EVENT_RING_SEG_TABLE_ENTRY) * ERST_NUMBER;
Buf = UsbHcAllocateMem (Xhc->MemPool, Size);
Buf = UsbHcAllocateMem (Xhc->MemPool, Size, FALSE);
ASSERT (Buf != NULL);
ASSERT (((UINTN)Buf & 0x3F) == 0);
ZeroMem (Buf, Size);
@ -892,7 +892,7 @@ CreateTransferRing (
LINK_TRB *EndTrb;
EFI_PHYSICAL_ADDRESS PhyAddr;
Buf = UsbHcAllocateMem (Xhc->MemPool, sizeof (TRB_TEMPLATE) * TrbNum);
Buf = UsbHcAllocateMem (Xhc->MemPool, sizeof (TRB_TEMPLATE) * TrbNum, TRUE);
ASSERT (Buf != NULL);
ASSERT (((UINTN)Buf & 0x3F) == 0);
ZeroMem (Buf, sizeof (TRB_TEMPLATE) * TrbNum);
@ -2182,7 +2182,7 @@ XhcInitializeDeviceSlot (
// 4.3.3 Device Slot Initialization
// 1) Allocate an Input Context data structure (6.2.5) and initialize all fields to '0'.
//
InputContext = UsbHcAllocateMem (Xhc->MemPool, sizeof (INPUT_CONTEXT));
InputContext = UsbHcAllocateMem (Xhc->MemPool, sizeof (INPUT_CONTEXT), FALSE);
ASSERT (InputContext != NULL);
ASSERT (((UINTN)InputContext & 0x3F) == 0);
ZeroMem (InputContext, sizeof (INPUT_CONTEXT));
@ -2284,7 +2284,7 @@ XhcInitializeDeviceSlot (
//
// 6) Allocate the Output Device Context data structure (6.2.1) and initialize it to '0'.
//
OutputContext = UsbHcAllocateMem (Xhc->MemPool, sizeof (DEVICE_CONTEXT));
OutputContext = UsbHcAllocateMem (Xhc->MemPool, sizeof (DEVICE_CONTEXT), FALSE);
ASSERT (OutputContext != NULL);
ASSERT (((UINTN)OutputContext & 0x3F) == 0);
ZeroMem (OutputContext, sizeof (DEVICE_CONTEXT));
@ -2398,7 +2398,7 @@ XhcInitializeDeviceSlot64 (
// 4.3.3 Device Slot Initialization
// 1) Allocate an Input Context data structure (6.2.5) and initialize all fields to '0'.
//
InputContext = UsbHcAllocateMem (Xhc->MemPool, sizeof (INPUT_CONTEXT_64));
InputContext = UsbHcAllocateMem (Xhc->MemPool, sizeof (INPUT_CONTEXT_64), FALSE);
ASSERT (InputContext != NULL);
ASSERT (((UINTN)InputContext & 0x3F) == 0);
ZeroMem (InputContext, sizeof (INPUT_CONTEXT_64));
@ -2500,7 +2500,7 @@ XhcInitializeDeviceSlot64 (
//
// 6) Allocate the Output Device Context data structure (6.2.1) and initialize it to '0'.
//
OutputContext = UsbHcAllocateMem (Xhc->MemPool, sizeof (DEVICE_CONTEXT_64));
OutputContext = UsbHcAllocateMem (Xhc->MemPool, sizeof (DEVICE_CONTEXT_64), FALSE);
ASSERT (OutputContext != NULL);
ASSERT (((UINTN)OutputContext & 0x3F) == 0);
ZeroMem (OutputContext, sizeof (DEVICE_CONTEXT_64));