Skip to content

Commit 0bc8e37

Browse files
committed
address kuns comments
1 parent af25664 commit 0bc8e37

5 files changed

Lines changed: 107 additions & 108 deletions

File tree

UefiTestingPkg/AuditTests/DMAProtectionAudit/UEFI/DMASmmuProtectionUnitTestApp.inf

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -44,6 +44,7 @@
4444

4545
[LibraryClasses]
4646
UefiApplicationEntryPoint
47+
BaseLib
4748
DebugLib
4849
UnitTestLib
4950
UnitTestBootLib

UefiTestingPkg/AuditTests/DMAProtectionAudit/UEFI/README.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@ Shell based UEFI unit test based off of the UnitTestFrameworkPkg that test for:
1616
3. All excluded regions are set as (EfiReservedMemoryType or EfiACPIMemoryNVS) for IVRS.
1717
4. Bus mastering enabled (BME) is disabled on ExitBootServices. Because we can no longer write to file after ExitBootServices
1818
a variable is used to store the test state and the machine.
19-
5. For ARM SMMUv3, each SMMU unit in the IORT has translation enabled (or is otherwise DMA-safe via GBPA abort / IORT RMR).
19+
5. For ARM SMMUv3, each SMMU unit in the IORT has translation enabled (or is otherwise DMA-safe via GBPA abort).
2020

2121
Note: this unit test requires a restart to finish its testing. If you plan to use this unit test in automation make sure
2222
to set up your startup.nsh script properly.

UefiTestingPkg/AuditTests/DMAProtectionAudit/UEFI/SMMU/DMAProtectionTestArch.c

Lines changed: 34 additions & 60 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@ SPDX-License-Identifier: BSD-2-Clause-Patent
1717
1818
**/
1919

20+
#include <Library/BaseLib.h>
2021
#include <Library/DebugLib.h>
2122
#include <Library/UefiLib.h>
2223
#include <Library/UnitTestLib.h>
@@ -66,8 +67,9 @@ CheckExcludedRegions (
6667
UINTN EfiDescriptorSize;
6768
UINT32 EfiDescriptorVersion;
6869
EFI_ACPI_DESCRIPTION_HEADER *IortTable;
69-
RMRListNode *Head;
70-
RMRListNode *Current;
70+
LIST_ENTRY RmrList;
71+
LIST_ENTRY *Link;
72+
RMR_LIST_NODE *RmrEntry;
7173
BOOLEAN Found;
7274
BOOLEAN FoundInMemoryMap;
7375
UINT32 FoundMemoryType;
@@ -83,15 +85,14 @@ CheckExcludedRegions (
8385
//
8486
// Step 2: Get the RMR (Reserved Memory Range) nodes from IORT Table
8587
//
86-
Head = GetIortAcpiTableRmrList (IortTable);
87-
if (Head == NULL) {
88+
InitializeListHead (&RmrList);
89+
Status = GetIortAcpiTableRmrList (IortTable, &RmrList);
90+
UT_ASSERT_NOT_EFI_ERROR (Status);
91+
if (IsListEmpty (&RmrList)) {
8892
UT_LOG_INFO ("No RMRs Found in IORT\n");
89-
DEBUG ((DEBUG_INFO, "%a: No RMRs Found in IORT\n", __func__));
9093
return UNIT_TEST_PASSED;
9194
}
9295

93-
Current = Head;
94-
9596
//
9697
// Step 3: Get the EFI memory map.
9798
//
@@ -118,7 +119,6 @@ CheckExcludedRegions (
118119
UT_ASSERT_NOT_EFI_ERROR (Status);
119120
} else {
120121
UT_LOG_ERROR ("GetMemoryMap Failed\n");
121-
DEBUG ((DEBUG_ERROR, "%a: GetMemoryMap Failed\n", __func__));
122122
TestStatus = UNIT_TEST_ERROR_TEST_FAILED;
123123
UT_ASSERT_STATUS_EQUAL (Status, TestStatus);
124124
return UNIT_TEST_ERROR_TEST_FAILED;
@@ -131,19 +131,22 @@ CheckExcludedRegions (
131131
EfiMemoryMapEnd = (EFI_MEMORY_DESCRIPTOR *)((UINT8 *)EfiMemoryMap + EfiMemoryMapSize);
132132
TestStatus = UNIT_TEST_PASSED;
133133

134-
while (Current != NULL) {
134+
for (Link = GetFirstNode (&RmrList);
135+
!IsNull (&RmrList, Link);
136+
Link = GetNextNode (&RmrList, Link))
137+
{
138+
RmrEntry = RMR_LIST_NODE_FROM_LINK (Link);
135139
Found = FALSE;
136140
FoundInMemoryMap = FALSE;
137141
FoundMemoryType = 0;
138142
EfiMemNext = EfiMemoryMap;
139143

140-
UT_LOG_INFO ("Checking RMR region: Base=0x%lX, Length=0x%lX\n", Current->BaseAddress, Current->Length);
141-
DEBUG ((DEBUG_INFO, "%a: Checking RMR region: Base=0x%lX, Length=0x%lX\n", __func__, Current->BaseAddress, Current->Length));
144+
UT_LOG_INFO ("Checking RMR region: Base=0x%lX, Length=0x%lX\n", RmrEntry->BaseAddress, RmrEntry->Length);
142145

143146
while (EfiMemNext < EfiMemoryMapEnd) {
144147
// Check if memory range fully encompasses RMR
145-
if ((EfiMemNext->PhysicalStart <= Current->BaseAddress) &&
146-
((EfiMemNext->PhysicalStart + (EFI_PAGE_SIZE * EfiMemNext->NumberOfPages)) >= (Current->BaseAddress + Current->Length)))
148+
if ((EfiMemNext->PhysicalStart <= RmrEntry->BaseAddress) &&
149+
((EfiMemNext->PhysicalStart + (EFI_PAGE_SIZE * EfiMemNext->NumberOfPages)) >= (RmrEntry->BaseAddress + RmrEntry->Length)))
147150
{
148151
FoundInMemoryMap = TRUE;
149152
FoundMemoryType = EfiMemNext->Type;
@@ -154,14 +157,6 @@ CheckExcludedRegions (
154157
EFI_PAGE_SIZE * EfiMemNext->NumberOfPages,
155158
EfiMemNext->Type
156159
);
157-
DEBUG ((
158-
DEBUG_INFO,
159-
"%a: Found encompassing memory range: Base=0x%lX, Length=0x%lX, Type=%d\n",
160-
__func__,
161-
EfiMemNext->PhysicalStart,
162-
EFI_PAGE_SIZE * EfiMemNext->NumberOfPages,
163-
EfiMemNext->Type
164-
));
165160

166161
if ((EfiMemNext->Type == EfiReservedMemoryType) ||
167162
(EfiMemNext->Type == EfiRuntimeServicesData))
@@ -183,42 +178,34 @@ CheckExcludedRegions (
183178
if (!FoundInMemoryMap) {
184179
UT_LOG_INFO (
185180
"RMR region Base=0x%lX, Length=0x%lX was NOT found in the UEFI memory map\n",
186-
Current->BaseAddress,
187-
Current->Length
181+
RmrEntry->BaseAddress,
182+
RmrEntry->Length
188183
);
189-
DEBUG ((
190-
DEBUG_INFO,
191-
"%a: RMR region Base=0x%lX, Length=0x%lX was NOT found in the UEFI memory map\n",
192-
__func__,
193-
Current->BaseAddress,
194-
Current->Length
195-
));
196184
TestStatus = UNIT_TEST_ERROR_TEST_FAILED;
197185
}
198186

199187
if (!Found) {
200188
UT_LOG_ERROR (
201189
"RMR between 0x%lX and 0x%lX NOT found with an acceptable memory type (Reserved or RuntimeServicesData)! Memory type found: %d\n",
202-
Current->BaseAddress,
203-
Current->BaseAddress + Current->Length,
190+
RmrEntry->BaseAddress,
191+
RmrEntry->BaseAddress + RmrEntry->Length,
204192
FoundMemoryType
205193
);
206-
DEBUG ((
207-
DEBUG_ERROR,
208-
"%a: RMR between 0x%lX and 0x%lX NOT found with an acceptable memory type (Reserved or RuntimeServicesData)! Memory type found: %d\n",
209-
__func__,
210-
Current->BaseAddress,
211-
Current->BaseAddress + Current->Length,
212-
FoundMemoryType
213-
));
214194
TestStatus = UNIT_TEST_ERROR_TEST_FAILED;
215195
}
216-
217-
Current = Current->Next;
218196
}
219197

220198
UT_LOG_INFO ("%a: Result=%d (%a)\n", __func__, TestStatus, (TestStatus == UNIT_TEST_PASSED) ? "PASSED" : "FAILED");
221-
DEBUG ((DEBUG_INFO, "%a: Result=%d (%a)\n", __func__, TestStatus, (TestStatus == UNIT_TEST_PASSED) ? "PASSED" : "FAILED"));
199+
200+
//
201+
// Free every RMR entry appended by GetIortAcpiTableRmrList.
202+
//
203+
while (!IsListEmpty (&RmrList)) {
204+
Link = GetFirstNode (&RmrList);
205+
RmrEntry = RMR_LIST_NODE_FROM_LINK (Link);
206+
RemoveEntryList (Link);
207+
FreePool (RmrEntry);
208+
}
222209

223210
UT_ASSERT_STATUS_EQUAL (TestStatus, UNIT_TEST_PASSED);
224211
return TestStatus;
@@ -287,7 +274,6 @@ CheckIOMMUEnabled (
287274
//
288275
UT_ASSERT_TRUE (SmmuCount > 0);
289276
UT_LOG_INFO ("Found %d SMMUv3 units in IORT\n", SmmuCount);
290-
DEBUG ((DEBUG_INFO, "%a: Found %d SMMUv3 units in IORT\n", __func__, SmmuCount));
291277

292278
TestStatus = UNIT_TEST_PASSED;
293279

@@ -302,21 +288,18 @@ CheckIOMMUEnabled (
302288
//
303289
for (Iterator = 0; Iterator < SmmuCount; Iterator++) {
304290
UT_LOG_INFO ("Checking SMMUv3 at base address 0x%lX\n", SmmuBaseAddresses[Iterator]);
305-
DEBUG ((DEBUG_INFO, "%a: Checking SMMUv3 at base address 0x%lX\n", __func__, SmmuBaseAddresses[Iterator]));
306291

307292
//
308293
// Read CR0 register
309294
//
310295
Cr0Value = MmioRead32 ((UINTN)(SmmuBaseAddresses[Iterator] + SMMU_CR0));
311296
UT_LOG_INFO ("CR0 Register Value: 0x%X\n", Cr0Value);
312-
DEBUG ((DEBUG_INFO, "%a: CR0 Register Value: 0x%X\n", __func__, Cr0Value));
313297

314298
//
315299
// Check SMMUEN bit (bit 0)
316300
//
317301
SmmuEnBit = Cr0Value & SMMU_CR0_SMMUEN;
318302
UT_LOG_INFO ("SMMUEN bit: %d\n", SmmuEnBit);
319-
DEBUG ((DEBUG_INFO, "%a: SMMUEN bit: %d\n", __func__, SmmuEnBit));
320303
if (SmmuEnBit == 0) {
321304
//
322305
// SMMU translation is not enabled. The SMMU is still DMA-safe if it is
@@ -325,20 +308,17 @@ CheckIOMMUEnabled (
325308
GbpaValue = MmioRead32 ((UINTN)(SmmuBaseAddresses[Iterator] + SMMU_GBPA));
326309
AbortBit = GbpaValue & SMMU_GBPA_ABORT;
327310
UT_LOG_INFO ("GBPA Register Value: 0x%X, ABORT bit: %d\n", GbpaValue, AbortBit ? 1 : 0);
328-
DEBUG ((DEBUG_INFO, "%a: GBPA Register Value: 0x%X, ABORT bit: %d\n", __func__, GbpaValue, AbortBit ? 1 : 0));
329311

330312
if (AbortBit != 0) {
331313
//
332314
// Global abort is set: all DMA is aborted, so this SMMU is DMA-safe.
333315
// Skip the remaining translation-related checks for this SMMU.
334316
//
335317
UT_LOG_INFO ("SMMUEN is disabled but global abort (GBPA.ABORT) is set for SMMUv3 at base address 0x%lX. SMMU is DMA-safe.\n", SmmuBaseAddresses[Iterator]);
336-
DEBUG ((DEBUG_INFO, "%a: SMMUEN is disabled but global abort (GBPA.ABORT) is set for SMMUv3 at base address 0x%lX. SMMU is DMA-safe.\n", __func__, SmmuBaseAddresses[Iterator]));
337318
continue;
338319
}
339320

340321
UT_LOG_ERROR ("SMMUEN bit is disabled and global abort is not set for SMMUv3 at base address 0x%lX\n", SmmuBaseAddresses[Iterator]);
341-
DEBUG ((DEBUG_ERROR, "%a: SMMUEN bit is disabled and global abort is not set for SMMUv3 at base address 0x%lX\n", __func__, SmmuBaseAddresses[Iterator]));
342322
TestStatus = UNIT_TEST_ERROR_TEST_FAILED;
343323
continue;
344324
}
@@ -348,10 +328,8 @@ CheckIOMMUEnabled (
348328
//
349329
CmdQEnBit = Cr0Value & SMMU_CR0_CMDQEN;
350330
UT_LOG_INFO ("CMDQEN bit: %d\n", CmdQEnBit ? 1 : 0);
351-
DEBUG ((DEBUG_INFO, "%a: CMDQEN bit: %d\n", __func__, CmdQEnBit ? 1 : 0));
352331
if (CmdQEnBit == 0) {
353332
UT_LOG_ERROR ("CMDQEN bit is disabled for SMMUv3 at base address 0x%lX\n", SmmuBaseAddresses[Iterator]);
354-
DEBUG ((DEBUG_ERROR, "%a: CMDQEN bit is disabled for SMMUv3 at base address 0x%lX\n", __func__, SmmuBaseAddresses[Iterator]));
355333
TestStatus = UNIT_TEST_ERROR_TEST_FAILED;
356334
}
357335

@@ -360,10 +338,8 @@ CheckIOMMUEnabled (
360338
//
361339
EvtQEnBit = Cr0Value & SMMU_CR0_EVTQEN;
362340
UT_LOG_INFO ("EVTQEN bit: %d\n", EvtQEnBit ? 1 : 0);
363-
DEBUG ((DEBUG_INFO, "%a: EVTQEN bit: %d\n", __func__, EvtQEnBit ? 1 : 0));
364341
if (EvtQEnBit == 0) {
365342
UT_LOG_ERROR ("EVTQEN bit is disabled for SMMUv3 at base address 0x%lX\n", SmmuBaseAddresses[Iterator]);
366-
DEBUG ((DEBUG_ERROR, "%a: EVTQEN bit is disabled for SMMUv3 at base address 0x%lX\n", __func__, SmmuBaseAddresses[Iterator]));
367343
TestStatus = UNIT_TEST_ERROR_TEST_FAILED;
368344
}
369345

@@ -373,15 +349,12 @@ CheckIOMMUEnabled (
373349
//
374350
StrTabBase = MmioRead64 ((UINTN)(SmmuBaseAddresses[Iterator] + SMMU_STRTAB_BASE));
375351
UT_LOG_INFO ("STRTAB_BASE Register Value: 0x%lX\n", StrTabBase);
376-
DEBUG ((DEBUG_INFO, "%a: STRTAB_BASE Register Value: 0x%lX\n", __func__, StrTabBase));
377352

378353
// Extract the address portion by masking out lower 6 bits (bits [5:0] are reserved/config)
379354
StrTabBaseAddr = StrTabBase & ~SMMU_STRTAB_BASE_ADDR_MASK;
380355
UT_LOG_INFO ("STRTAB_BASE Address: 0x%lX\n", StrTabBaseAddr);
381-
DEBUG ((DEBUG_INFO, "%a: STRTAB_BASE Address: 0x%lX\n", __func__, StrTabBaseAddr));
382356
if (StrTabBaseAddr == 0) {
383357
UT_LOG_ERROR ("STRTAB_BASE is NULL for SMMUv3 at base address 0x%lX\n", SmmuBaseAddresses[Iterator]);
384-
DEBUG ((DEBUG_ERROR, "%a: STRTAB_BASE is NULL for SMMUv3 at base address 0x%lX\n", __func__, SmmuBaseAddresses[Iterator]));
385358
TestStatus = UNIT_TEST_ERROR_TEST_FAILED;
386359
}
387360

@@ -390,16 +363,17 @@ CheckIOMMUEnabled (
390363
//
391364
GError = MmioRead32 ((UINTN)(SmmuBaseAddresses[Iterator] + SMMU_GERROR));
392365
UT_LOG_INFO ("GERROR Register Value: 0x%X\n", GError);
393-
DEBUG ((DEBUG_INFO, "%a: GERROR Register Value: 0x%X\n", __func__, GError));
394366
if (GError != 0) {
395367
UT_LOG_ERROR ("GERROR register is non-zero for SMMUv3 at base address 0x%lX\n", SmmuBaseAddresses[Iterator]);
396-
DEBUG ((DEBUG_ERROR, "%a: GERROR register is non-zero for SMMUv3 at base address 0x%lX\n", __func__, SmmuBaseAddresses[Iterator]));
397368
TestStatus = UNIT_TEST_ERROR_TEST_FAILED;
398369
}
399370
}
400371

401372
UT_LOG_INFO ("%a: Result=%d (%a)\n", __func__, TestStatus, (TestStatus == UNIT_TEST_PASSED) ? "PASSED" : "FAILED");
402-
DEBUG ((DEBUG_INFO, "%a: Result=%d (%a)\n", __func__, TestStatus, (TestStatus == UNIT_TEST_PASSED) ? "PASSED" : "FAILED"));
373+
374+
// Free the SMMU base address array allocated by ParseIortAcpiTableSmmu.
375+
FreePool (SmmuBaseAddresses);
376+
SmmuBaseAddresses = NULL;
403377

404378
UT_ASSERT_STATUS_EQUAL (TestStatus, UNIT_TEST_PASSED);
405379
return TestStatus;

UefiTestingPkg/AuditTests/DMAProtectionAudit/UEFI/SMMU/DmaProtection.h

Lines changed: 34 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -45,13 +45,21 @@ SPDX-License-Identifier: BSD-2-Clause-Patent
4545
#define SMMU_STRTAB_BASE_ADDR_MASK 0x3FULL
4646

4747
//
48-
// RMR List Node Structure for tracking Reserved Memory Ranges
48+
// Signature and structure used to track Reserved Memory Ranges (RMRs) parsed
49+
// from the IORT. Nodes are linked into a doubly-linked list rooted at a
50+
// caller-provided LIST_ENTRY head. Use RMR_LIST_NODE_FROM_LINK() to recover
51+
// the containing RMR_LIST_NODE from a LIST_ENTRY *.
4952
//
50-
typedef struct _RMRListNode {
51-
UINT64 BaseAddress;
52-
UINT64 Length;
53-
struct _RMRListNode *Next;
54-
} RMRListNode;
53+
#define RMR_LIST_NODE_SIGNATURE SIGNATURE_32 ('R', 'M', 'R', 'N')
54+
55+
typedef struct {
56+
UINT32 Signature;
57+
LIST_ENTRY Link;
58+
UINT64 BaseAddress;
59+
UINT64 Length;
60+
} RMR_LIST_NODE;
61+
62+
#define RMR_LIST_NODE_FROM_LINK(a) CR (a, RMR_LIST_NODE, Link, RMR_LIST_NODE_SIGNATURE)
5563

5664
//
5765
// Function Prototypes
@@ -94,16 +102,31 @@ ParseIortAcpiTableSmmu (
94102
);
95103

96104
/**
97-
Parse the IORT table to find all RMR (Reserved Memory Range) nodes.
105+
Parse the IORT table and append each Reserved Memory Range (RMR) descriptor
106+
to the caller-provided doubly-linked list.
107+
108+
Each entry appended is an RMR_LIST_NODE. The caller is responsible for:
109+
- Initializing RmrList (e.g. via InitializeListHead) before calling.
110+
- Freeing every appended RMR_LIST_NODE (e.g. via RemoveEntryList + FreePool)
111+
when done. Entries appended before an error return must also be freed.
98112
99-
@param[in] IortTable Pointer to the IORT table.
113+
If no RMR nodes are found, EFI_SUCCESS is returned and RmrList is left empty
114+
(IsListEmpty returns TRUE).
100115
101-
@retval Pointer to head of linked list of RMR entries, or NULL if none found.
116+
@param[in] IortTable Pointer to the IORT table.
117+
@param[in,out] RmrList List head to append RMR entries to.
118+
119+
@retval EFI_SUCCESS IORT was parsed; RmrList may be empty if there
120+
are no RMR nodes.
121+
@retval EFI_INVALID_PARAMETER IortTable or RmrList is NULL.
122+
@retval EFI_OUT_OF_RESOURCES Failed to allocate an RMR_LIST_NODE. Any entries
123+
appended before the failure remain in RmrList.
102124
**/
103-
RMRListNode *
125+
EFI_STATUS
104126
EFIAPI
105127
GetIortAcpiTableRmrList (
106-
IN EFI_ACPI_DESCRIPTION_HEADER *IortTable
128+
IN EFI_ACPI_DESCRIPTION_HEADER *IortTable,
129+
IN OUT LIST_ENTRY *RmrList
107130
);
108131

109132
#endif // _DMA_PROTECTION_H_

0 commit comments

Comments
 (0)