Skip to content

Commit f288cf7

Browse files
committed
update test conditions
1 parent 2cfab49 commit f288cf7

4 files changed

Lines changed: 105 additions & 39 deletions

File tree

UefiTestingPkg/AuditTests/DMAProtectionAudit/UEFI/DMAProtectionUnitTestApp.c

Lines changed: 0 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -317,10 +317,8 @@ CheckBMETeardown (
317317
for (i = 0; i < (PreVarSize)/(sizeof (BOOLEAN)); i++) {
318318
// BME Enabled before exit boot services
319319
UT_LOG_INFO (PreBuffer[i] ? "Pre-EBS BME %d: True\n" : "Pre-EBS BME %d: False\n", i);
320-
DEBUG ((DEBUG_INFO, PreBuffer[i] ? "%a: Pre-EBS BME %d: True\n" : "%a: Pre-EBS BME %d: False\n", __func__, i));
321320
// BME Disabled after exit boot services
322321
UT_LOG_INFO (PostBuffer[i] ? "Post-EBS BME %d: True\n" : "Post-EBS BME %d: False\n", i);
323-
DEBUG ((DEBUG_INFO, PostBuffer[i] ? "%a: Post-EBS BME %d: True\n" : "%a: Post-EBS BME %d: False\n", __func__, i));
324322
UT_ASSERT_FALSE (PostBuffer[i]);
325323
}
326324

@@ -351,7 +349,6 @@ CheckBMETeardown (
351349
}
352350

353351
UT_LOG_INFO ("PASSED: BME test.\n");
354-
DEBUG ((DEBUG_INFO, "PASSED: BME test.\n"));
355352

356353
return UNIT_TEST_PASSED;
357354
} // CheckBMETeardown()

UefiTestingPkg/AuditTests/DMAProtectionAudit/UEFI/README.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +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).
1920

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

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

Lines changed: 98 additions & 36 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,16 @@
11
/** @file -- DMAProtectionTestArch.c
22
33
This file contains architecture specific DMA protection tests for ARM SMMU (SMMUv3):
4-
1) Check the CR0 registers of the SMMUv3 nodes to verify SMMU translation is enabled
4+
1) Check the CR0 registers of the SMMUv3 nodes to verify SMMU translation is enabled.
5+
An SMMU that is not enabled (SMMUEN == 0) is still considered DMA-safe only if
6+
it is configured for global abort (GBPA.ABORT == 1), so all DMA is aborted.
57
2) Check that Command Queue is enabled (CMDQEN bit in CR0)
68
3) Check that Event Queue is enabled (EVTQEN bit in CR0)
79
4) Check that Stream Table Base is configured (STRTAB_BASE is not NULL)
810
5) Check that GERROR register is 0 (no global errors)
9-
6) Check RMR (Reserved Memory Range) regions from IORT are set as reserved in memory map
11+
6) Check RMR (Reserved Memory Range) regions from IORT are found in the EFI memory map
12+
and marked with an acceptable memory type (EfiReservedMemoryType or
13+
EfiRuntimeServicesData).
1014
1115
Copyright (c) Microsoft Corporation. All rights reserved.
1216
SPDX-License-Identifier: BSD-2-Clause-Patent
@@ -32,12 +36,20 @@ SPDX-License-Identifier: BSD-2-Clause-Patent
3236

3337
/**
3438
Test to verify that the Reserved Memory Range (RMR) regions defined in the IORT
35-
are properly marked as reserved in the EFI memory map.
39+
are found in the EFI memory map and marked with an acceptable memory type.
40+
41+
For each RMR region, the test verifies that:
42+
1) An EFI memory map descriptor fully encompasses the RMR region, and
43+
2) That descriptor's memory type is acceptable, i.e. EfiReservedMemoryType
44+
or EfiRuntimeServicesData.
45+
46+
If an RMR region is not found in the memory map, or is found but is not one of
47+
the acceptable memory types, the test fails.
3648
3749
@param[in] Context The unit test context (not used).
3850
39-
@retval UNIT_TEST_PASSED All RMR regions are properly marked as reserved.
40-
@retval UNIT_TEST_ERROR_TEST_FAILED A RMR region was not found or not marked as reserved.
51+
@retval UNIT_TEST_PASSED All RMR regions were found with an acceptable memory type.
52+
@retval UNIT_TEST_ERROR_TEST_FAILED A RMR region was not found, or had an unacceptable memory type.
4153
**/
4254
UNIT_TEST_STATUS
4355
EFIAPI
@@ -57,6 +69,8 @@ CheckExcludedRegions (
5769
RMRListNode *Head;
5870
RMRListNode *Current;
5971
BOOLEAN Found;
72+
BOOLEAN FoundInMemoryMap;
73+
UINT32 FoundMemoryType;
6074
UNIT_TEST_STATUS TestStatus;
6175

6276
//
@@ -105,6 +119,8 @@ CheckExcludedRegions (
105119
} else {
106120
UT_LOG_ERROR ("GetMemoryMap Failed\n");
107121
DEBUG ((DEBUG_ERROR, "%a: GetMemoryMap Failed\n", __func__));
122+
TestStatus = UNIT_TEST_ERROR_TEST_FAILED;
123+
UT_ASSERT_STATUS_EQUAL (Status, TestStatus);
108124
return UNIT_TEST_ERROR_TEST_FAILED;
109125
}
110126

@@ -116,8 +132,10 @@ CheckExcludedRegions (
116132
TestStatus = UNIT_TEST_PASSED;
117133

118134
while (Current != NULL) {
119-
Found = FALSE;
120-
EfiMemNext = EfiMemoryMap;
135+
Found = FALSE;
136+
FoundInMemoryMap = FALSE;
137+
FoundMemoryType = 0;
138+
EfiMemNext = EfiMemoryMap;
121139

122140
UT_LOG_INFO ("Checking RMR region: Base=0x%lX, Length=0x%lX\n", Current->BaseAddress, Current->Length);
123141
DEBUG ((DEBUG_INFO, "%a: Checking RMR region: Base=0x%lX, Length=0x%lX\n", __func__, Current->BaseAddress, Current->Length));
@@ -127,6 +145,9 @@ CheckExcludedRegions (
127145
if ((EfiMemNext->PhysicalStart <= Current->BaseAddress) &&
128146
((EfiMemNext->PhysicalStart + (EFI_PAGE_SIZE * EfiMemNext->NumberOfPages)) >= (Current->BaseAddress + Current->Length)))
129147
{
148+
FoundInMemoryMap = TRUE;
149+
FoundMemoryType = EfiMemNext->Type;
150+
130151
UT_LOG_INFO (
131152
"Found encompassing memory range: Base=0x%lX, Length=0x%lX, Type=%d\n",
132153
EfiMemNext->PhysicalStart,
@@ -142,22 +163,9 @@ CheckExcludedRegions (
142163
EfiMemNext->Type
143164
));
144165

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-
));
166+
if ((EfiMemNext->Type == EfiReservedMemoryType) ||
167+
(EfiMemNext->Type == EfiRuntimeServicesData))
168+
{
161169
Found = TRUE;
162170
}
163171

@@ -168,43 +176,73 @@ CheckExcludedRegions (
168176
EfiMemNext = NEXT_MEMORY_DESCRIPTOR (EfiMemNext, EfiDescriptorSize);
169177
}
170178

179+
//
180+
// Report whether the RMR region was located in the UEFI memory map,
181+
// and if found, the memory type (even if it is not reserved).
182+
//
183+
if (!FoundInMemoryMap) {
184+
UT_LOG_INFO (
185+
"RMR region Base=0x%lX, Length=0x%lX was NOT found in the UEFI memory map\n",
186+
Current->BaseAddress,
187+
Current->Length
188+
);
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+
));
196+
TestStatus = UNIT_TEST_ERROR_TEST_FAILED;
197+
}
198+
171199
if (!Found) {
172200
UT_LOG_ERROR (
173-
"RMR between 0x%lX and 0x%lX NOT found with reserved memory type!\n",
201+
"RMR between 0x%lX and 0x%lX NOT found with an acceptable memory type (Reserved or RuntimeServicesData)! Memory type found: %d\n",
174202
Current->BaseAddress,
175-
Current->BaseAddress + Current->Length
203+
Current->BaseAddress + Current->Length,
204+
FoundMemoryType
176205
);
177206
DEBUG ((
178207
DEBUG_ERROR,
179-
"%a: RMR between 0x%lX and 0x%lX NOT found with reserved memory type!\n",
208+
"%a: RMR between 0x%lX and 0x%lX NOT found with an acceptable memory type (Reserved or RuntimeServicesData)! Memory type found: %d\n",
180209
__func__,
181210
Current->BaseAddress,
182-
Current->BaseAddress + Current->Length
211+
Current->BaseAddress + Current->Length,
212+
FoundMemoryType
183213
));
184214
TestStatus = UNIT_TEST_ERROR_TEST_FAILED;
185215
}
186216

187217
Current = Current->Next;
188218
}
189219

190-
UT_LOG_INFO ("%a: Result=%d\n", __func__, TestStatus);
191-
DEBUG ((DEBUG_INFO, "%a: Result=%d\n", __func__, TestStatus));
220+
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"));
192222

223+
UT_ASSERT_STATUS_EQUAL (TestStatus, UNIT_TEST_PASSED);
193224
return TestStatus;
194225
} // CheckExcludedRegions()
195226

196227
/**
197-
Test to verify that all SMMUv3 units found in the IORT have translation enabled.
198-
This checks:
228+
Test to verify that all SMMUv3 units found in the IORT are configured to be
229+
DMA-safe.
230+
231+
For each SMMUv3 unit, if translation is enabled (CR0.SMMUEN == 1) this checks:
199232
1) CR0 register's SMMUEN bit to confirm the SMMU is actively translating
200233
2) CR0 register's CMDQEN bit to confirm the command queue is enabled
201234
3) CR0 register's EVTQEN bit to confirm the event queue is enabled
202235
4) STRTAB_BASE register is not NULL (stream table must be configured)
203236
5) GERROR register is 0 (no global errors)
204237
238+
If translation is not enabled (CR0.SMMUEN == 0), the SMMU is still considered
239+
DMA-safe (and the checks above are skipped) only if it is configured for global
240+
abort (GBPA.ABORT == 1), so all DMA is aborted. Otherwise the SMMU is considered
241+
unsafe and the test fails.
242+
205243
@param[in] Context The unit test context (not used).
206244
207-
@retval UNIT_TEST_PASSED All SMMU units are properly configured.
245+
@retval UNIT_TEST_PASSED All SMMU units are properly configured.
208246
@retval UNIT_TEST_ERROR_TEST_FAILED An SMMU unit is not properly configured.
209247
**/
210248
UNIT_TEST_STATUS
@@ -225,6 +263,8 @@ CheckIOMMUEnabled (
225263
UINT64 StrTabBase;
226264
UINT64 StrTabBaseAddr;
227265
UINT32 GError;
266+
UINT32 GbpaValue;
267+
UINT32 AbortBit;
228268
UNIT_TEST_STATUS TestStatus;
229269

230270
//
@@ -253,6 +293,7 @@ CheckIOMMUEnabled (
253293

254294
//
255295
// Step 4: For each SMMU, check:
296+
// - SMMU GBPA Set (GBPA.ABORT == 1), or:
256297
// - SMMU Enable bit (SMMUEN) in CR0 register
257298
// - Command Queue Enable bit (CMDQEN) in CR0 register
258299
// - Event Queue Enable bit (EVTQEN) in CR0 register
@@ -277,9 +318,29 @@ CheckIOMMUEnabled (
277318
UT_LOG_INFO ("SMMUEN bit: %d\n", SmmuEnBit);
278319
DEBUG ((DEBUG_INFO, "%a: SMMUEN bit: %d\n", __func__, SmmuEnBit));
279320
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]));
321+
//
322+
// SMMU translation is not enabled. The SMMU is still DMA-safe if it is
323+
// configured for global abort (GBPA.ABORT == 1).
324+
//
325+
GbpaValue = MmioRead32 ((UINTN)(SmmuBaseAddresses[Iterator] + SMMU_GBPA));
326+
AbortBit = GbpaValue & SMMU_GBPA_ABORT;
327+
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));
329+
330+
if (AbortBit != 0) {
331+
//
332+
// Global abort is set: all DMA is aborted, so this SMMU is DMA-safe.
333+
// Skip the remaining translation-related checks for this SMMU.
334+
//
335+
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]));
337+
continue;
338+
}
339+
340+
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]));
282342
TestStatus = UNIT_TEST_ERROR_TEST_FAILED;
343+
continue;
283344
}
284345

285346
//
@@ -337,8 +398,9 @@ CheckIOMMUEnabled (
337398
}
338399
}
339400

340-
UT_LOG_INFO ("%a: Result=%d\n", __func__, TestStatus);
341-
DEBUG ((DEBUG_INFO, "%a: Result=%d\n", __func__, TestStatus));
401+
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"));
342403

404+
UT_ASSERT_STATUS_EQUAL (TestStatus, UNIT_TEST_PASSED);
343405
return TestStatus;
344406
} // CheckIOMMUEnabled()

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

Lines changed: 6 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
//

0 commit comments

Comments
 (0)