Skip to content

Commit d5cf5ac

Browse files
committed
update test conditions
1 parent ca52feb commit d5cf5ac

3 files changed

Lines changed: 172 additions & 28 deletions

File tree

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

Lines changed: 83 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -57,6 +57,8 @@ CheckExcludedRegions (
5757
RMRListNode *Head;
5858
RMRListNode *Current;
5959
BOOLEAN Found;
60+
BOOLEAN FoundInMemoryMap;
61+
UINT32 FoundMemoryType;
6062
UNIT_TEST_STATUS TestStatus;
6163

6264
//
@@ -105,6 +107,8 @@ CheckExcludedRegions (
105107
} else {
106108
UT_LOG_ERROR ("GetMemoryMap Failed\n");
107109
DEBUG ((DEBUG_ERROR, "%a: GetMemoryMap Failed\n", __func__));
110+
TestStatus = UNIT_TEST_ERROR_TEST_FAILED;
111+
UT_ASSERT_STATUS_EQUAL (Status, TestStatus);
108112
return UNIT_TEST_ERROR_TEST_FAILED;
109113
}
110114

@@ -116,8 +120,10 @@ CheckExcludedRegions (
116120
TestStatus = UNIT_TEST_PASSED;
117121

118122
while (Current != NULL) {
119-
Found = FALSE;
120-
EfiMemNext = EfiMemoryMap;
123+
Found = FALSE;
124+
FoundInMemoryMap = FALSE;
125+
FoundMemoryType = 0;
126+
EfiMemNext = EfiMemoryMap;
121127

122128
UT_LOG_INFO ("Checking RMR region: Base=0x%lX, Length=0x%lX\n", Current->BaseAddress, Current->Length);
123129
DEBUG ((DEBUG_INFO, "%a: Checking RMR region: Base=0x%lX, Length=0x%lX\n", __func__, Current->BaseAddress, Current->Length));
@@ -127,6 +133,9 @@ CheckExcludedRegions (
127133
if ((EfiMemNext->PhysicalStart <= Current->BaseAddress) &&
128134
((EfiMemNext->PhysicalStart + (EFI_PAGE_SIZE * EfiMemNext->NumberOfPages)) >= (Current->BaseAddress + Current->Length)))
129135
{
136+
FoundInMemoryMap = TRUE;
137+
FoundMemoryType = EfiMemNext->Type;
138+
130139
UT_LOG_INFO (
131140
"Found encompassing memory range: Base=0x%lX, Length=0x%lX, Type=%d\n",
132141
EfiMemNext->PhysicalStart,
@@ -142,22 +151,9 @@ CheckExcludedRegions (
142151
EfiMemNext->Type
143152
));
144153

145-
// Verify memory range is marked as reserved
146-
if (EfiMemNext->Type == EfiReservedMemoryType) {
147-
UT_LOG_INFO (
148-
"RMR between 0x%lX and 0x%lX found with reserved memory type %d\n",
149-
Current->BaseAddress,
150-
Current->BaseAddress + Current->Length,
151-
EfiMemNext->Type
152-
);
153-
DEBUG ((
154-
DEBUG_INFO,
155-
"%a: RMR between 0x%lX and 0x%lX found with reserved memory type %d\n",
156-
__func__,
157-
Current->BaseAddress,
158-
Current->BaseAddress + Current->Length,
159-
EfiMemNext->Type
160-
));
154+
if ((EfiMemNext->Type == EfiReservedMemoryType) ||
155+
(EfiMemNext->Type == EfiRuntimeServicesData))
156+
{
161157
Found = TRUE;
162158
}
163159

@@ -168,28 +164,51 @@ CheckExcludedRegions (
168164
EfiMemNext = NEXT_MEMORY_DESCRIPTOR (EfiMemNext, EfiDescriptorSize);
169165
}
170166

167+
//
168+
// Report whether the RMR region was located in the UEFI memory map,
169+
// and if found, the memory type (even if it is not reserved).
170+
//
171+
if (!FoundInMemoryMap) {
172+
UT_LOG_INFO (
173+
"RMR region Base=0x%lX, Length=0x%lX was NOT found in the UEFI memory map\n",
174+
Current->BaseAddress,
175+
Current->Length
176+
);
177+
DEBUG ((
178+
DEBUG_INFO,
179+
"%a: RMR region Base=0x%lX, Length=0x%lX was NOT found in the UEFI memory map\n",
180+
__func__,
181+
Current->BaseAddress,
182+
Current->Length
183+
));
184+
TestStatus = UNIT_TEST_ERROR_TEST_FAILED;
185+
}
186+
171187
if (!Found) {
172188
UT_LOG_ERROR (
173-
"RMR between 0x%lX and 0x%lX NOT found with reserved memory type!\n",
189+
"RMR between 0x%lX and 0x%lX NOT found with an acceptable memory type (Reserved or RuntimeServicesData)! Memory type found: %d\n",
174190
Current->BaseAddress,
175-
Current->BaseAddress + Current->Length
191+
Current->BaseAddress + Current->Length,
192+
FoundMemoryType
176193
);
177194
DEBUG ((
178195
DEBUG_ERROR,
179-
"%a: RMR between 0x%lX and 0x%lX NOT found with reserved memory type!\n",
196+
"%a: RMR between 0x%lX and 0x%lX NOT found with an acceptable memory type (Reserved or RuntimeServicesData)! Memory type found: %d\n",
180197
__func__,
181198
Current->BaseAddress,
182-
Current->BaseAddress + Current->Length
199+
Current->BaseAddress + Current->Length,
200+
FoundMemoryType
183201
));
184202
TestStatus = UNIT_TEST_ERROR_TEST_FAILED;
185203
}
186204

187205
Current = Current->Next;
188206
}
189207

190-
UT_LOG_INFO ("%a: Result=%d\n", __func__, TestStatus);
191-
DEBUG ((DEBUG_INFO, "%a: Result=%d\n", __func__, TestStatus));
208+
UT_LOG_INFO ("%a: Result=%d (%a)\n", __func__, TestStatus, (TestStatus == UNIT_TEST_PASSED) ? "PASSED" : "FAILED");
209+
DEBUG ((DEBUG_INFO, "%a: Result=%d (%a)\n", __func__, TestStatus, (TestStatus == UNIT_TEST_PASSED) ? "PASSED" : "FAILED"));
192210

211+
UT_ASSERT_STATUS_EQUAL (TestStatus, UNIT_TEST_PASSED);
193212
return TestStatus;
194213
} // CheckExcludedRegions()
195214

@@ -225,6 +244,8 @@ CheckIOMMUEnabled (
225244
UINT64 StrTabBase;
226245
UINT64 StrTabBaseAddr;
227246
UINT32 GError;
247+
UINT32 GbpaValue;
248+
UINT32 AbortBit;
228249
UNIT_TEST_STATUS TestStatus;
229250

230251
//
@@ -253,6 +274,7 @@ CheckIOMMUEnabled (
253274

254275
//
255276
// Step 4: For each SMMU, check:
277+
// - SMMU GBPA Set (GBPA.ABORT == 1), or:
256278
// - SMMU Enable bit (SMMUEN) in CR0 register
257279
// - Command Queue Enable bit (CMDQEN) in CR0 register
258280
// - Event Queue Enable bit (EVTQEN) in CR0 register
@@ -277,9 +299,41 @@ CheckIOMMUEnabled (
277299
UT_LOG_INFO ("SMMUEN bit: %d\n", SmmuEnBit);
278300
DEBUG ((DEBUG_INFO, "%a: SMMUEN bit: %d\n", __func__, SmmuEnBit));
279301
if (SmmuEnBit == 0) {
280-
UT_LOG_ERROR ("SMMUEN bit is disabled for SMMUv3 at base address 0x%lX\n", SmmuBaseAddresses[Iterator]);
281-
DEBUG ((DEBUG_ERROR, "%a: SMMUEN bit is disabled for SMMUv3 at base address 0x%lX\n", __func__, SmmuBaseAddresses[Iterator]));
302+
//
303+
// SMMU translation is not enabled. The SMMU is still DMA-safe if it is
304+
// configured for global abort (GBPA.ABORT == 1).
305+
//
306+
GbpaValue = MmioRead32 ((UINTN)(SmmuBaseAddresses[Iterator] + SMMU_GBPA));
307+
AbortBit = GbpaValue & SMMU_GBPA_ABORT;
308+
UT_LOG_INFO ("GBPA Register Value: 0x%X, ABORT bit: %d\n", GbpaValue, AbortBit ? 1 : 0);
309+
DEBUG ((DEBUG_INFO, "%a: GBPA Register Value: 0x%X, ABORT bit: %d\n", __func__, GbpaValue, AbortBit ? 1 : 0));
310+
311+
if (AbortBit != 0) {
312+
//
313+
// Global abort is set: all DMA is aborted, so this SMMU is DMA-safe.
314+
// Skip the remaining translation-related checks for this SMMU.
315+
//
316+
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]);
317+
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]));
318+
continue;
319+
}
320+
321+
//
322+
// SMMU is in global bypass (not abort) and not enabled. This is permitted
323+
// only if the SMMU has a Reserved Memory Range (RMR) associated with it in
324+
// the IORT, since the RMR describes memory that is expected to bypass
325+
// translation.
326+
//
327+
if (SmmuHasAssociatedRmr (IortTable, SmmuBaseAddresses[Iterator])) {
328+
UT_LOG_INFO ("SMMUEN is disabled and SMMU is in global bypass, but an RMR is associated with SMMUv3 at base address 0x%lX. This is permitted.\n", SmmuBaseAddresses[Iterator]);
329+
DEBUG ((DEBUG_INFO, "%a: SMMUEN is disabled and SMMU is in global bypass, but an RMR is associated with SMMUv3 at base address 0x%lX. This is permitted.\n", __func__, SmmuBaseAddresses[Iterator]));
330+
continue;
331+
}
332+
333+
UT_LOG_ERROR ("SMMUEN bit is disabled, global abort is not set, and no RMR is associated for SMMUv3 at base address 0x%lX\n", SmmuBaseAddresses[Iterator]);
334+
DEBUG ((DEBUG_ERROR, "%a: SMMUEN bit is disabled, global abort is not set, and no RMR is associated for SMMUv3 at base address 0x%lX\n", __func__, SmmuBaseAddresses[Iterator]));
282335
TestStatus = UNIT_TEST_ERROR_TEST_FAILED;
336+
continue;
283337
}
284338

285339
//
@@ -337,8 +391,9 @@ CheckIOMMUEnabled (
337391
}
338392
}
339393

340-
UT_LOG_INFO ("%a: Result=%d\n", __func__, TestStatus);
341-
DEBUG ((DEBUG_INFO, "%a: Result=%d\n", __func__, TestStatus));
394+
UT_LOG_INFO ("%a: Result=%d (%a)\n", __func__, TestStatus, (TestStatus == UNIT_TEST_PASSED) ? "PASSED" : "FAILED");
395+
DEBUG ((DEBUG_INFO, "%a: Result=%d (%a)\n", __func__, TestStatus, (TestStatus == UNIT_TEST_PASSED) ? "PASSED" : "FAILED"));
342396

397+
UT_ASSERT_STATUS_EQUAL (TestStatus, UNIT_TEST_PASSED);
343398
return TestStatus;
344399
} // CheckIOMMUEnabled()

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

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@ SPDX-License-Identifier: BSD-2-Clause-Patent
2323
//
2424
#define SMMU_CR0 0x0020
2525
#define SMMU_CR0ACK 0x0024
26+
#define SMMU_GBPA 0x0044
2627
#define SMMU_GERROR 0x0060
2728
#define SMMU_STRTAB_BASE 0x0080
2829

@@ -33,6 +34,11 @@ SPDX-License-Identifier: BSD-2-Clause-Patent
3334
#define SMMU_CR0_EVTQEN BIT2 // Event Queue Enable bit
3435
#define SMMU_CR0_CMDQEN BIT3 // Command Queue Enable bit
3536

37+
//
38+
// SMMUv3 GBPA Register Bits
39+
//
40+
#define SMMU_GBPA_ABORT BIT20 // Global Bypass Abort bit (abort all DMA when SMMUEN == 0)
41+
3642
//
3743
// STRTAB_BASE lower bits mask (bits [5:0] are reserved/config)
3844
//
@@ -100,4 +106,22 @@ GetIortAcpiTableRmrList (
100106
IN EFI_ACPI_DESCRIPTION_HEADER *IortTable
101107
);
102108

109+
/**
110+
Determine whether the given SMMUv3 (identified by its base address) has at
111+
least one Reserved Memory Range (RMR) node associated with it via the RMR
112+
node's ID mappings.
113+
114+
@param[in] IortTable Pointer to the IORT table.
115+
@param[in] SmmuBase Base address of the SMMUv3 to check.
116+
117+
@retval TRUE At least one RMR node references the specified SMMUv3.
118+
@retval FALSE No RMR node references the specified SMMUv3, or inputs invalid.
119+
**/
120+
BOOLEAN
121+
EFIAPI
122+
SmmuHasAssociatedRmr (
123+
IN EFI_ACPI_DESCRIPTION_HEADER *IortTable,
124+
IN UINT64 SmmuBase
125+
);
126+
103127
#endif // _DMA_PROTECTION_H_

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

Lines changed: 65 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -201,3 +201,68 @@ GetIortAcpiTableRmrList (
201201

202202
return Head;
203203
}
204+
205+
/**
206+
Determine whether the given SMMUv3 (identified by its base address) has at
207+
least one Reserved Memory Range (RMR) node associated with it via the RMR
208+
node's ID mappings.
209+
210+
Each RMR node contains an ID mapping table; each mapping's OutputReference is
211+
the byte offset (from the start of the IORT table) of the node the RMR is
212+
associated with. This function walks every RMR node's ID mappings and checks
213+
whether any of them reference an SMMUv3 node whose Base matches SmmuBase.
214+
215+
@param[in] IortTable Pointer to the IORT table.
216+
@param[in] SmmuBase Base address of the SMMUv3 to check.
217+
218+
@retval TRUE At least one RMR node references the specified SMMUv3.
219+
@retval FALSE No RMR node references the specified SMMUv3, or inputs invalid.
220+
**/
221+
BOOLEAN
222+
EFIAPI
223+
SmmuHasAssociatedRmr (
224+
IN EFI_ACPI_DESCRIPTION_HEADER *IortTable,
225+
IN UINT64 SmmuBase
226+
)
227+
{
228+
EFI_ACPI_6_0_IO_REMAPPING_TABLE *Iort;
229+
EFI_ACPI_6_0_IO_REMAPPING_NODE *Node;
230+
EFI_ACPI_6_0_IO_REMAPPING_RMR_NODE *RmrNode;
231+
EFI_ACPI_6_0_IO_REMAPPING_ID_TABLE *IdMapping;
232+
EFI_ACPI_6_0_IO_REMAPPING_NODE *OutputNode;
233+
EFI_ACPI_6_0_IO_REMAPPING_SMMU3_NODE *SmmuNode;
234+
UINT32 Count;
235+
UINT32 MappingIndex;
236+
237+
if (IortTable == NULL) {
238+
return FALSE;
239+
}
240+
241+
Iort = (EFI_ACPI_6_0_IO_REMAPPING_TABLE *)IortTable;
242+
Node = (EFI_ACPI_6_0_IO_REMAPPING_NODE *)((UINT8 *)Iort + Iort->NodeOffset);
243+
244+
// Iterate through all nodes looking for RMR nodes
245+
for (Count = 0; Count < Iort->NumNodes; Count++) {
246+
if (Node->Type == EFI_ACPI_IORT_TYPE_RMR) {
247+
RmrNode = (EFI_ACPI_6_0_IO_REMAPPING_RMR_NODE *)Node;
248+
IdMapping = (EFI_ACPI_6_0_IO_REMAPPING_ID_TABLE *)((UINT8 *)RmrNode + RmrNode->Node.IdReference);
249+
250+
// Walk each ID mapping and resolve the referenced output node
251+
for (MappingIndex = 0; MappingIndex < RmrNode->Node.NumIdMappings; MappingIndex++) {
252+
OutputNode = (EFI_ACPI_6_0_IO_REMAPPING_NODE *)((UINT8 *)Iort + IdMapping[MappingIndex].OutputReference);
253+
254+
if (OutputNode->Type == EFI_ACPI_IORT_TYPE_SMMUv3) {
255+
SmmuNode = (EFI_ACPI_6_0_IO_REMAPPING_SMMU3_NODE *)OutputNode;
256+
if (SmmuNode->Base == SmmuBase) {
257+
return TRUE;
258+
}
259+
}
260+
}
261+
}
262+
263+
// Move to the next node
264+
Node = (EFI_ACPI_6_0_IO_REMAPPING_NODE *)((UINT8 *)Node + Node->Length);
265+
}
266+
267+
return FALSE;
268+
}

0 commit comments

Comments
 (0)