11/** @file -- DMAProtectionTestArch.c
22
33This 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.
572) Check that Command Queue is enabled (CMDQEN bit in CR0)
683) Check that Event Queue is enabled (EVTQEN bit in CR0)
794) Check that Stream Table Base is configured (STRTAB_BASE is not NULL)
8105) 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
1115Copyright (c) Microsoft Corporation. All rights reserved.
1216SPDX-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**/
4254UNIT_TEST_STATUS
4355EFIAPI
@@ -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**/
210248UNIT_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()
0 commit comments