3 Copyright (c) 2009, Hewlett-Packard Company
4 Portions copyright (c) 2010, Apple Inc. All rights reserved.
6 All rights reserved. This program and the accompanying materials
7 are licensed and made available under the terms and conditions of the BSD License
8 which accompanies this distribution. The full text of the license may be found at
9 http://opensource.org/licenses/bsd-license.php
11 THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
12 WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
20 // For debug switch me back to to EFI_D_PAGE when done
22 #define L_EFI_D_PAGE EFI_D_ERROR
25 // Translation/page table definitions
28 // First Level Descriptors
29 typedef UINT32 ARM_FIRST_LEVEL_DESCRIPTOR
;
31 // memory space covered by a first level descriptor
32 #define ARM_PAGE_DESC_ENTRY_MVA_SIZE 0x00100000 // 1MB
34 // number of first level descriptors to cover entire 32-bit memory space
35 #define FIRST_LEVEL_ENTRY_COUNT (0xFFFFFFFF / ARM_PAGE_DESC_ENTRY_MVA_SIZE + 1)
38 // page table 1st level descriptor entries
39 #define ARM_PAGE_DESC_BASE_MASK 0xFFFFFC00
40 #define ARM_PAGE_DESC_BASE_SHFIT 10
41 #define ARM_PAGE_DESC_DOMAIN_MASK 0x000001E0
42 #define ARM_PAGE_DESC_DOMAIN_SHIFT 5
43 #define ARM_PAGE_DESC_NS 0x00000008
45 #define ARM_FIRST_LEVEL_DESC_ALIGN 0x00004000 // 16KB
47 // section 1st level desriptor entries
48 #define ARM_SECTION_BASE_MASK 0xFFF00000
49 #define ARM_SECTION_BASE_SHIFT 20
50 #define ARM_SECTION_NS 0x00080000
51 #define ARM_SECTION_nG 0x00020000
52 #define ARM_SECTION_S 0x00010000
53 #define ARM_SECTION_AP2 0x00008000
54 #define ARM_SECTION_TEX_MASK 0x00007000
55 #define ARM_SECTION_TEX_SHIFT 12
56 #define ARM_SECTION_AP10_MASK 0x00000C00
57 #define ARM_SECTION_AP10_SHIFT 10
58 #define ARM_SECTION_DOMAIN_MASK 0x000001E0
59 #define ARM_SECTION_DOMAIN_SHIFT 5
60 #define ARM_SECTION_XN 0x00000010
61 #define ARM_SECTION_C 0x00000008
62 #define ARM_SECTION_B 0x00000004
64 // section level AP[2:0] definitions
65 #define ARM_SECTION_AP_NO_ACCESS 0 // AP[2:0] = 0
66 #define ARM_SECTION_AP_READ_WRITE ARM_SECTION_AP10_MASK // AP[2:0] = 011
67 #define ARM_SECTION_AP_READ_ONLY (ARM_SECTION_AP2 | ARM_SECTION_AP10_MASK) // AP[2:0] = 111
69 // common 1st level descriptor fields
70 #define ARM_DESC_TYPE_MASK 0x00000003
72 // descriptor type values
73 #define ARM_DESC_TYPE_FAULT 0x0
74 #define ARM_DESC_TYPE_PAGE_TABLE 0x1
75 #define ARM_DESC_TYPE_SECTION 0x2
78 // Second Level Descriptors
79 typedef UINT32 ARM_PAGE_TABLE_ENTRY
;
81 // small page 2nd level descriptor entries
82 #define ARM_SMALL_PAGE_BASE_MASK 0xFFFFF000
83 #define ARM_SMALL_PAGE_INDEX_MASK 0x000FF000
84 #define ARM_SMALL_PAGE_BASE_SHIFT 12
85 #define ARM_SMALL_PAGE_TEX_MASK 0x000001C0
86 #define ARM_SMALL_PAGE_TEX_SHIFT 6
87 #define ARM_SMALL_PAGE_XN 0x00000001
89 // large page 2nd level descriptor entries
90 #define ARM_LARGE_PAGE_BASE_MASK 0xFFFF0000
91 #define ARM_LARGE_PAGE_BASE_SHIFT 16
92 #define ARM_LARGE_PAGE_TEX_MASK 0x00007000
93 #define ARM_LARGE_PAGE_TEX_SHIFT 12
94 #define ARM_LARGE_PAGE_XN 0x00008000
96 // common 2nd level desriptor fields
97 #define ARM_PAGE_nG 0x00000800
98 #define ARM_PAGE_S 0x00000400
99 #define ARM_PAGE_AP2 0x00000200
100 #define ARM_PAGE_AP10_MASK 0x00000030
101 #define ARM_PAGE_AP10_SHIFT 4
102 #define ARM_PAGE_C 0x00000008
103 #define ARM_PAGE_B 0x00000004
104 #define ARM_PAGE_DESC_TYPE_MASK 0x00000003
106 // descriptor type values
107 #define ARM_PAGE_TYPE_FAULT 0x0
108 #define ARM_PAGE_TYPE_LARGE 0x1
109 #define ARM_PAGE_TYPE_SMALL 0x2
110 #define ARM_PAGE_TYPE_SMALL_XN 0x3
112 #define SMALL_PAGE_TABLE_ENTRY_COUNT (ARM_PAGE_DESC_ENTRY_MVA_SIZE / EFI_PAGE_SIZE)
115 // Translation Table Base 0 fields
116 #define ARM_TTBR0_BASE_MASK 0xFFFFC000
117 #define ARM_TTBR0_BASE_SHIFT 14
118 #define ARM_TTRB0_NOS 0x00000020
120 // define the combination of interesting attributes: cacheability and access permissions
121 #define ARM_SECTION_CACHEABILITY_MASK ( ARM_SECTION_TEX_MASK | ARM_SECTION_C | ARM_SECTION_B )
122 #define ARM_SECTION_RW_PERMISSIONS_MASK ( ARM_SECTION_AP2 | ARM_SECTION_AP10_MASK )
123 #define ARM_DESCRIPTOR_ATTRIBUTES ( ARM_SECTION_CACHEABILITY_MASK | ARM_SECTION_RW_PERMISSIONS_MASK | ARM_SECTION_XN )
125 // cacheability values for section entries
126 #define ARM_SECTION_STRONGLY_ORDERED 0
127 #define ARM_SECTION_SHAREABLE_DEVICE ARM_SECTION_B
128 #define ARM_SECTION_WRITE_THROUGH ARM_SECTION_C
129 #define ARM_SECTION_WRITE_BACK_NWA ( ARM_SECTION_C| ARM_SECTION_B )
130 #define ARM_SECTION_NORMAL_UNCACHEABLE ( 0x1 << ARM_SECTION_TEX_SHIFT )
131 #define ARM_SECTION_WRITE_BACK ( ( 0x1 << ARM_SECTION_TEX_SHIFT ) | ARM_SECTION_C | ARM_SECTION_B )
132 #define ARM_SECTION_NONSHAREABLE_DEVICE ( 0x2 << ARM_SECTION_TEX_SHIFT )
134 // permissions values for section entries
135 #define ARM_SECTION_NO_ACCESS 0
136 #define ARM_SECTION_PRIV_ACCESS_ONLY ( 0x1 << ARM_SECTION_AP10_SHIFT)
137 #define ARM_SECTION_USER_READ_ONLY ( 0x2 << ARM_SECTION_AP10_SHIFT)
138 #define ARM_SECTION_FULL_ACCESS ( 0x3 << ARM_SECTION_AP10_SHIFT)
139 #define ARM_SECTION_PRIV_READ_ONLY ( ARM_SECTION_AP2 | (0x1 << ARM_SECTION_AP10_SHIFT) )
140 #define ARM_SECTION_READ_ONLY_DEP ( ARM_SECTION_AP2 | (0x2 << ARM_SECTION_AP10_SHIFT) )
141 #define ARM_SECTION_READ_ONLY ( ARM_SECTION_AP2 | (0x3 << ARM_SECTION_AP10_SHIFT) )
146 SectionToGcdAttributes (
147 IN UINT32 SectionAttributes
,
148 OUT UINT64
*GcdAttributes
153 // determine cacheability attributes
154 switch(SectionAttributes
& ARM_SECTION_CACHEABILITY_MASK
) {
155 case ARM_SECTION_STRONGLY_ORDERED
:
156 *GcdAttributes
|= EFI_MEMORY_UC
;
158 case ARM_SECTION_SHAREABLE_DEVICE
:
159 *GcdAttributes
|= EFI_MEMORY_UC
;
161 case ARM_SECTION_WRITE_THROUGH
:
162 *GcdAttributes
|= EFI_MEMORY_WT
;
164 case ARM_SECTION_WRITE_BACK_NWA
:
165 *GcdAttributes
|= EFI_MEMORY_WB
;
167 case ARM_SECTION_NORMAL_UNCACHEABLE
:
168 *GcdAttributes
|= EFI_MEMORY_WC
;
170 case ARM_SECTION_WRITE_BACK
:
171 *GcdAttributes
|= EFI_MEMORY_WB
;
173 case ARM_SECTION_NONSHAREABLE_DEVICE
:
174 *GcdAttributes
|= EFI_MEMORY_UC
;
177 return EFI_UNSUPPORTED
;
180 // determine protection attributes
181 switch(SectionAttributes
& ARM_SECTION_RW_PERMISSIONS_MASK
) {
182 case ARM_SECTION_NO_ACCESS
: // no read, no write
183 //*GcdAttributes |= EFI_MEMORY_WP | EFI_MEMORY_RP;
186 case ARM_SECTION_PRIV_ACCESS_ONLY
:
187 case ARM_SECTION_FULL_ACCESS
:
188 // normal read/write access, do not add additional attributes
191 // read only cases map to write-protect
192 case ARM_SECTION_PRIV_READ_ONLY
:
193 case ARM_SECTION_READ_ONLY_DEP
:
194 case ARM_SECTION_READ_ONLY
:
195 *GcdAttributes
|= EFI_MEMORY_WP
;
199 return EFI_UNSUPPORTED
;
202 // now process eXectue Never attribute
203 if ((SectionAttributes
& ARM_SECTION_XN
) != 0 ) {
204 *GcdAttributes
|= EFI_MEMORY_XP
;
211 Searches memory descriptors covered by given memory range.
213 This function searches into the Gcd Memory Space for descriptors
214 (from StartIndex to EndIndex) that contains the memory range
215 specified by BaseAddress and Length.
217 @param MemorySpaceMap Gcd Memory Space Map as array.
218 @param NumberOfDescriptors Number of descriptors in map.
219 @param BaseAddress BaseAddress for the requested range.
220 @param Length Length for the requested range.
221 @param StartIndex Start index into the Gcd Memory Space Map.
222 @param EndIndex End index into the Gcd Memory Space Map.
224 @retval EFI_SUCCESS Search successfully.
225 @retval EFI_NOT_FOUND The requested descriptors does not exist.
229 SearchGcdMemorySpaces (
230 IN EFI_GCD_MEMORY_SPACE_DESCRIPTOR
*MemorySpaceMap
,
231 IN UINTN NumberOfDescriptors
,
232 IN EFI_PHYSICAL_ADDRESS BaseAddress
,
234 OUT UINTN
*StartIndex
,
242 for (Index
= 0; Index
< NumberOfDescriptors
; Index
++) {
243 if (BaseAddress
>= MemorySpaceMap
[Index
].BaseAddress
&&
244 BaseAddress
< MemorySpaceMap
[Index
].BaseAddress
+ MemorySpaceMap
[Index
].Length
) {
247 if (BaseAddress
+ Length
- 1 >= MemorySpaceMap
[Index
].BaseAddress
&&
248 BaseAddress
+ Length
- 1 < MemorySpaceMap
[Index
].BaseAddress
+ MemorySpaceMap
[Index
].Length
) {
253 return EFI_NOT_FOUND
;
258 Sets the attributes for a specified range in Gcd Memory Space Map.
260 This function sets the attributes for a specified range in
261 Gcd Memory Space Map.
263 @param MemorySpaceMap Gcd Memory Space Map as array
264 @param NumberOfDescriptors Number of descriptors in map
265 @param BaseAddress BaseAddress for the range
266 @param Length Length for the range
267 @param Attributes Attributes to set
269 @retval EFI_SUCCESS Memory attributes set successfully
270 @retval EFI_NOT_FOUND The specified range does not exist in Gcd Memory Space
274 SetGcdMemorySpaceAttributes (
275 IN EFI_GCD_MEMORY_SPACE_DESCRIPTOR
*MemorySpaceMap
,
276 IN UINTN NumberOfDescriptors
,
277 IN EFI_PHYSICAL_ADDRESS BaseAddress
,
286 EFI_PHYSICAL_ADDRESS RegionStart
;
290 // Get all memory descriptors covered by the memory range
292 Status
= SearchGcdMemorySpaces (
300 if (EFI_ERROR (Status
)) {
305 // Go through all related descriptors and set attributes accordingly
307 for (Index
= StartIndex
; Index
<= EndIndex
; Index
++) {
308 if (MemorySpaceMap
[Index
].GcdMemoryType
== EfiGcdMemoryTypeNonExistent
) {
312 // Calculate the start and end address of the overlapping range
314 if (BaseAddress
>= MemorySpaceMap
[Index
].BaseAddress
) {
315 RegionStart
= BaseAddress
;
317 RegionStart
= MemorySpaceMap
[Index
].BaseAddress
;
319 if (BaseAddress
+ Length
- 1 < MemorySpaceMap
[Index
].BaseAddress
+ MemorySpaceMap
[Index
].Length
) {
320 RegionLength
= BaseAddress
+ Length
- RegionStart
;
322 RegionLength
= MemorySpaceMap
[Index
].BaseAddress
+ MemorySpaceMap
[Index
].Length
- RegionStart
;
325 // Set memory attributes according to MTRR attribute and the original attribute of descriptor
327 gDS
->SetMemorySpaceAttributes (
330 (MemorySpaceMap
[Index
].Attributes
& ~EFI_MEMORY_CACHETYPE_MASK
) | (MemorySpaceMap
[Index
].Capabilities
& Attributes
)
340 IN EFI_CPU_ARCH_PROTOCOL
*CpuProtocol
346 UINT32 SectionAttributes
;
347 EFI_PHYSICAL_ADDRESS NextRegionBase
;
348 UINT64 NextRegionLength
;
349 UINT64 GcdAttributes
;
350 UINT32 NextRegionAttributes
= 0;
351 volatile ARM_FIRST_LEVEL_DESCRIPTOR
*FirstLevelTable
;
352 UINTN NumberOfDescriptors
;
353 EFI_GCD_MEMORY_SPACE_DESCRIPTOR
*MemorySpaceMap
;
356 DEBUG ((L_EFI_D_PAGE
, "SyncCacheConfig()\n"));
358 // This code assumes MMU is enabled and filed with section translations
359 ASSERT (ArmMmuEnabled ());
362 // Get the memory space map from GCD
364 MemorySpaceMap
= NULL
;
365 Status
= gDS
->GetMemorySpaceMap (&NumberOfDescriptors
, &MemorySpaceMap
);
366 ASSERT_EFI_ERROR (Status
);
369 // The GCD implementation maintains its own copy of the state of memory space attributes. GCD needs
370 // to know what the initial memory space attributes are. The CPU Arch. Protocol does not provide a
371 // GetMemoryAttributes function for GCD to get this so we must resort to calling GCD (as if we were
372 // a client) to update its copy of the attributes. This is bad architecture and should be replaced
373 // with a way for GCD to query the CPU Arch. driver of the existing memory space attributes instead.
375 // obtain page table base
376 FirstLevelTable
= (ARM_FIRST_LEVEL_DESCRIPTOR
*)(ArmGetTranslationTableBaseAddress ());
379 // iterate through each 1MB descriptor
380 NextRegionBase
= NextRegionLength
= 0;
381 for (i
=0; i
< FIRST_LEVEL_ENTRY_COUNT
; i
++) {
383 // obtain existing descriptor and make sure it contains a valid Base Address even if it is a fault section
384 Descriptor
= FirstLevelTable
[i
] | (ARM_SECTION_BASE_MASK
& (i
<< ARM_SECTION_BASE_SHIFT
));
386 // extract attributes (cacheability and permissions)
387 SectionAttributes
= Descriptor
& 0xDEC;
389 // do we already have an existing region (or are we about to finish)?
390 // Skip the first entry, and make sure we close on the last entry
391 if ( (NextRegionLength
> 0) || (i
== (FIRST_LEVEL_ENTRY_COUNT
-1)) ) {
392 // attributes are changing, update attributes in GCD
393 if (SectionAttributes
!= NextRegionAttributes
) {
395 // convert section entry attributes to GCD bitmask
396 Status
= SectionToGcdAttributes (NextRegionAttributes
, &GcdAttributes
);
397 ASSERT_EFI_ERROR (Status
);
399 // update GCD with these changes (this will recurse into our own CpuSetMemoryAttributes below which is OK)
400 SetGcdMemorySpaceAttributes (MemorySpaceMap
, NumberOfDescriptors
, NextRegionBase
, NextRegionLength
, GcdAttributes
);
403 // start on a new region
404 NextRegionLength
= 0;
405 NextRegionBase
= Descriptor
& ARM_SECTION_BASE_MASK
;
409 // starting a new region?
410 if (NextRegionLength
== 0) {
411 NextRegionAttributes
= SectionAttributes
;
414 NextRegionLength
+= ARM_PAGE_DESC_ENTRY_MVA_SIZE
;
416 } // section entry loop
425 IN EFI_PHYSICAL_ADDRESS BaseAddress
,
427 IN UINT64 Attributes
,
428 IN EFI_PHYSICAL_ADDRESS VirtualMask
434 UINT32 FirstLevelIdx
;
436 UINT32 NumPageEntries
;
439 UINT32 PageTableIndex
;
440 UINT32 PageTableEntry
;
442 volatile ARM_FIRST_LEVEL_DESCRIPTOR
*FirstLevelTable
;
443 volatile ARM_PAGE_TABLE_ENTRY
*PageTable
;
445 // EntryMask: bitmask of values to change (1 = change this value, 0 = leave alone)
446 // EntryValue: values at bit positions specified by EntryMask
448 // Although the PI spec is unclear on this the GCD guarantees that only
449 // one Attribute bit is set at a time, so we can safely use a switch statement
450 switch (Attributes
) {
452 // modify cacheability attributes
453 EntryMask
= ARM_SMALL_PAGE_TEX_MASK
| ARM_PAGE_C
| ARM_PAGE_B
;
454 // map to strongly ordered
455 EntryValue
= 0; // TEX[2:0] = 0, C=0, B=0
459 // modify cacheability attributes
460 EntryMask
= ARM_SMALL_PAGE_TEX_MASK
| ARM_PAGE_C
| ARM_PAGE_B
;
461 // map to normal non-cachable
462 EntryValue
= (0x1 << ARM_SMALL_PAGE_TEX_SHIFT
); // TEX [2:0]= 001 = 0x2, B=0, C=0
466 // modify cacheability attributes
467 EntryMask
= ARM_SMALL_PAGE_TEX_MASK
| ARM_PAGE_C
| ARM_PAGE_B
;
468 // write through with no-allocate
469 EntryValue
= ARM_PAGE_C
; // TEX [2:0] = 0, C=1, B=0
473 // modify cacheability attributes
474 EntryMask
= ARM_SMALL_PAGE_TEX_MASK
| ARM_PAGE_C
| ARM_PAGE_B
;
475 // write back (with allocate)
476 EntryValue
= (0x1 << ARM_SMALL_PAGE_TEX_SHIFT
) | ARM_PAGE_C
| ARM_PAGE_B
; // TEX [2:0] = 001, C=1, B=1
482 // cannot be implemented UEFI definition unclear for ARM
483 // Cause a page fault if these ranges are accessed.
486 DEBUG ((L_EFI_D_PAGE
, "SetMemoryAttributes(): setting page %lx with unsupported attribute %x will page fault on access\n", BaseAddress
, Attributes
));
490 return EFI_UNSUPPORTED
;
493 // obtain page table base
494 FirstLevelTable
= (ARM_FIRST_LEVEL_DESCRIPTOR
*)ArmGetTranslationTableBaseAddress ();
496 // calculate number of 4KB page table entries to change
497 NumPageEntries
= Length
/EFI_PAGE_SIZE
;
499 // iterate for the number of 4KB pages to change
501 for(p
=0; p
<NumPageEntries
; p
++) {
502 // calculate index into first level translation table for page table value
504 FirstLevelIdx
= ((BaseAddress
+ Offset
) & ARM_SECTION_BASE_MASK
) >> ARM_SECTION_BASE_SHIFT
;
505 ASSERT (FirstLevelIdx
< FIRST_LEVEL_ENTRY_COUNT
);
507 // read the descriptor from the first level page table
508 Descriptor
= FirstLevelTable
[FirstLevelIdx
];
510 // does this descriptor need to be converted from section entry to 4K pages?
511 if ((Descriptor
& ARM_DESC_TYPE_MASK
) != ARM_DESC_TYPE_PAGE_TABLE
) {
512 Status
= ConvertSectionToPages (FirstLevelIdx
<< ARM_SECTION_BASE_SHIFT
);
513 if (EFI_ERROR(Status
)) {
518 // re-read descriptor
519 Descriptor
= FirstLevelTable
[FirstLevelIdx
];
522 // obtain page table base address
523 PageTable
= (ARM_PAGE_TABLE_ENTRY
*)(Descriptor
& ARM_SMALL_PAGE_BASE_MASK
);
525 // calculate index into the page table
526 PageTableIndex
= ((BaseAddress
+ Offset
) & ARM_SMALL_PAGE_INDEX_MASK
) >> ARM_SMALL_PAGE_BASE_SHIFT
;
527 ASSERT (PageTableIndex
< SMALL_PAGE_TABLE_ENTRY_COUNT
);
530 PageTableEntry
= PageTable
[PageTableIndex
];
532 // mask off appropriate fields
533 PageTableEntry
&= ~EntryMask
;
535 // mask in new attributes and/or permissions
536 PageTableEntry
|= EntryValue
;
538 if (VirtualMask
!= 0) {
539 // Make this virtual address point at a physical page
540 PageTableEntry
&= ~VirtualMask
;
544 PageTable
[PageTableIndex
] = PageTableEntry
;
547 Status
= EFI_SUCCESS
;
548 Offset
+= EFI_PAGE_SIZE
;
550 } // end first level translation table loop
558 UpdateSectionEntries (
559 IN EFI_PHYSICAL_ADDRESS BaseAddress
,
561 IN UINT64 Attributes
,
562 IN EFI_PHYSICAL_ADDRESS VirtualMask
565 EFI_STATUS Status
= EFI_SUCCESS
;
568 UINT32 FirstLevelIdx
;
573 volatile ARM_FIRST_LEVEL_DESCRIPTOR
*FirstLevelTable
;
575 // EntryMask: bitmask of values to change (1 = change this value, 0 = leave alone)
576 // EntryValue: values at bit positions specified by EntryMask
578 // Make sure we handle a section range that is unmapped
579 EntryMask
= ARM_DESC_TYPE_MASK
;
580 EntryValue
= ARM_DESC_TYPE_SECTION
;
582 // Although the PI spec is unclear on this the GCD guarantees that only
583 // one Attribute bit is set at a time, so we can safely use a switch statement
586 // modify cacheability attributes
587 EntryMask
|= ARM_SECTION_TEX_MASK
| ARM_SECTION_C
| ARM_SECTION_B
;
588 // map to strongly ordered
589 EntryValue
|= 0; // TEX[2:0] = 0, C=0, B=0
593 // modify cacheability attributes
594 EntryMask
|= ARM_SECTION_TEX_MASK
| ARM_SECTION_C
| ARM_SECTION_B
;
595 // map to normal non-cachable
596 EntryValue
|= (0x1 << ARM_SECTION_TEX_SHIFT
); // TEX [2:0]= 001 = 0x2, B=0, C=0
600 // modify cacheability attributes
601 EntryMask
|= ARM_SECTION_TEX_MASK
| ARM_SECTION_C
| ARM_SECTION_B
;
602 // write through with no-allocate
603 EntryValue
|= ARM_SECTION_C
; // TEX [2:0] = 0, C=1, B=0
607 // modify cacheability attributes
608 EntryMask
|= ARM_SECTION_TEX_MASK
| ARM_SECTION_C
| ARM_SECTION_B
;
609 // write back (with allocate)
610 EntryValue
|= (0x1 << ARM_SECTION_TEX_SHIFT
) | ARM_SECTION_C
| ARM_SECTION_B
; // TEX [2:0] = 001, C=1, B=1
617 // cannot be implemented UEFI definition unclear for ARM
618 // Cause a page fault if these ranges are accessed.
619 EntryValue
= ARM_DESC_TYPE_FAULT
;
620 DEBUG ((L_EFI_D_PAGE
, "SetMemoryAttributes(): setting section %lx with unsupported attribute %x will page fault on access\n", BaseAddress
, Attributes
));
625 return EFI_UNSUPPORTED
;
628 // obtain page table base
629 FirstLevelTable
= (ARM_FIRST_LEVEL_DESCRIPTOR
*)ArmGetTranslationTableBaseAddress ();
631 // calculate index into first level translation table for start of modification
632 FirstLevelIdx
= (BaseAddress
& ARM_SECTION_BASE_MASK
) >> ARM_SECTION_BASE_SHIFT
;
633 ASSERT (FirstLevelIdx
< FIRST_LEVEL_ENTRY_COUNT
);
635 // calculate number of 1MB first level entries this applies to
636 NumSections
= Length
/ ARM_PAGE_DESC_ENTRY_MVA_SIZE
;
638 // iterate through each descriptor
639 for(i
=0; i
<NumSections
; i
++) {
640 Descriptor
= FirstLevelTable
[FirstLevelIdx
+ i
];
642 // has this descriptor already been coverted to pages?
643 if ((Descriptor
& ARM_DESC_TYPE_MASK
) != ARM_DESC_TYPE_PAGE_TABLE
) {
644 // forward this 1MB range to page table function instead
645 Status
= UpdatePageEntries ((FirstLevelIdx
+ i
) << ARM_SECTION_BASE_SHIFT
, ARM_PAGE_DESC_ENTRY_MVA_SIZE
, Attributes
, VirtualMask
);
647 // still a section entry
649 // mask off appropriate fields
650 Descriptor
&= ~EntryMask
;
652 // mask in new attributes and/or permissions
653 Descriptor
|= EntryValue
;
654 if (VirtualMask
!= 0) {
655 Descriptor
&= ~VirtualMask
;
658 FirstLevelTable
[FirstLevelIdx
+ i
] = Descriptor
;
660 Status
= EFI_SUCCESS
;
668 ConvertSectionToPages (
669 IN EFI_PHYSICAL_ADDRESS BaseAddress
673 EFI_PHYSICAL_ADDRESS PageTableAddr
;
674 UINT32 FirstLevelIdx
;
675 UINT32 SectionDescriptor
;
676 UINT32 PageTableDescriptor
;
677 UINT32 PageDescriptor
;
680 volatile ARM_FIRST_LEVEL_DESCRIPTOR
*FirstLevelTable
;
681 volatile ARM_PAGE_TABLE_ENTRY
*PageTable
;
683 DEBUG ((L_EFI_D_PAGE
, "Converting section at 0x%x to pages\n", (UINTN
)BaseAddress
));
685 // obtain page table base
686 FirstLevelTable
= (ARM_FIRST_LEVEL_DESCRIPTOR
*)ArmGetTranslationTableBaseAddress ();
688 // calculate index into first level translation table for start of modification
689 FirstLevelIdx
= (BaseAddress
& ARM_SECTION_BASE_MASK
) >> ARM_SECTION_BASE_SHIFT
;
690 ASSERT (FirstLevelIdx
< FIRST_LEVEL_ENTRY_COUNT
);
692 // get section attributes and convert to page attributes
693 SectionDescriptor
= FirstLevelTable
[FirstLevelIdx
];
694 PageDescriptor
= ARM_PAGE_TYPE_SMALL
;
695 PageDescriptor
|= ((SectionDescriptor
& ARM_SECTION_TEX_MASK
) >> ARM_SECTION_TEX_SHIFT
) << ARM_SMALL_PAGE_TEX_SHIFT
;
696 if ((SectionDescriptor
& ARM_SECTION_B
) != 0) {
697 PageDescriptor
|= ARM_PAGE_B
;
699 if ((SectionDescriptor
& ARM_SECTION_C
) != 0) {
700 PageDescriptor
|= ARM_PAGE_C
;
702 PageDescriptor
|= ((SectionDescriptor
& ARM_SECTION_AP10_MASK
) >> ARM_SECTION_AP10_SHIFT
) << ARM_PAGE_AP10_SHIFT
;
703 if ((SectionDescriptor
& ARM_SECTION_AP2
) != 0) {
704 PageDescriptor
|= ARM_PAGE_AP2
;
706 if ((SectionDescriptor
& ARM_SECTION_XN
) != 0) {
707 PageDescriptor
|= ARM_PAGE_TYPE_SMALL_XN
;
709 if ((SectionDescriptor
& ARM_SECTION_nG
) != 0) {
710 PageDescriptor
|= ARM_PAGE_nG
;
712 if ((SectionDescriptor
& ARM_SECTION_S
) != 0) {
713 PageDescriptor
|= ARM_PAGE_S
;
716 // allocate a page table for the 4KB entries (we use up a full page even though we only need 1KB)
717 Status
= gBS
->AllocatePages (AllocateAnyPages
, EfiBootServicesData
, 1, &PageTableAddr
);
718 if (EFI_ERROR(Status
)) {
722 PageTable
= (volatile ARM_PAGE_TABLE_ENTRY
*)(UINTN
)PageTableAddr
;
724 // write the page table entries out
725 for (i
=0; i
<(ARM_PAGE_DESC_ENTRY_MVA_SIZE
/EFI_PAGE_SIZE
); i
++) {
726 PageTable
[i
] = ((BaseAddress
+ (i
<< 12)) & ARM_SMALL_PAGE_BASE_MASK
) | PageDescriptor
;
729 // flush d-cache so descriptors make it back to uncached memory for subsequent table walks
730 // TODO: change to use only PageTable base and length
731 // ArmInvalidateDataCache ();
732 DEBUG ((EFI_D_ERROR
, "InvalidateDataCacheRange (%x, %x)\n", (UINTN
)PageTableAddr
, EFI_PAGE_SIZE
));
734 InvalidateDataCacheRange ((VOID
*)(UINTN
)PageTableAddr
, EFI_PAGE_SIZE
);
736 // formulate page table entry, Domain=0, NS=0
737 PageTableDescriptor
= (((UINTN
)PageTableAddr
) & ARM_PAGE_DESC_BASE_MASK
) | ARM_DESC_TYPE_PAGE_TABLE
;
739 // write the page table entry out, repalcing section entry
740 FirstLevelTable
[FirstLevelIdx
] = PageTableDescriptor
;
748 SetMemoryAttributes (
749 IN EFI_PHYSICAL_ADDRESS BaseAddress
,
751 IN UINT64 Attributes
,
752 IN EFI_PHYSICAL_ADDRESS VirtualMask
757 if(((BaseAddress
& 0xFFFFF) == 0) && ((Length
& 0xFFFFF) == 0)) {
758 // is the base and length a multiple of 1 MB?
759 DEBUG ((L_EFI_D_PAGE
, "SetMemoryAttributes(): MMU section 0x%x length 0x%x to %lx\n", (UINTN
)BaseAddress
, (UINTN
)Length
, Attributes
));
760 Status
= UpdateSectionEntries (BaseAddress
, Length
, Attributes
, VirtualMask
);
762 // base and/or length is not a multiple of 1 MB
763 DEBUG ((L_EFI_D_PAGE
, "SetMemoryAttributes(): MMU page 0x%x length 0x%x to %lx\n", (UINTN
)BaseAddress
, (UINTN
)Length
, Attributes
));
764 Status
= UpdatePageEntries (BaseAddress
, Length
, Attributes
, VirtualMask
);
767 // flush d-cache so descriptors make it back to uncached memory for subsequent table walks
768 // flush and invalidate pages
769 ArmCleanInvalidateDataCache ();
771 ArmInvalidateInstructionCache ();
773 // invalidate all TLB entries so changes are synced
781 This function modifies the attributes for the memory region specified by BaseAddress and
782 Length from their current attributes to the attributes specified by Attributes.
784 @param This The EFI_CPU_ARCH_PROTOCOL instance.
785 @param BaseAddress The physical address that is the start address of a memory region.
786 @param Length The size in bytes of the memory region.
787 @param Attributes The bit mask of attributes to set for the memory region.
789 @retval EFI_SUCCESS The attributes were set for the memory region.
790 @retval EFI_ACCESS_DENIED The attributes for the memory resource range specified by
791 BaseAddress and Length cannot be modified.
792 @retval EFI_INVALID_PARAMETER Length is zero.
793 @retval EFI_OUT_OF_RESOURCES There are not enough system resources to modify the attributes of
794 the memory resource range.
795 @retval EFI_UNSUPPORTED The processor does not support one or more bytes of the memory
796 resource range specified by BaseAddress and Length.
797 The bit mask of attributes is not support for the memory resource
798 range specified by BaseAddress and Length.
803 CpuSetMemoryAttributes (
804 IN EFI_CPU_ARCH_PROTOCOL
*This
,
805 IN EFI_PHYSICAL_ADDRESS BaseAddress
,
810 DEBUG ((L_EFI_D_PAGE
, "SetMemoryAttributes(%lx, %lx, %lx)\n", BaseAddress
, Length
, Attributes
));
811 if ( ((BaseAddress
& (EFI_PAGE_SIZE
-1)) != 0) || ((Length
& (EFI_PAGE_SIZE
-1)) != 0)){
812 // minimum granularity is EFI_PAGE_SIZE (4KB on ARM)
813 DEBUG ((L_EFI_D_PAGE
, "SetMemoryAttributes(%lx, %lx, %lx): minimum ganularity is EFI_PAGE_SIZE\n", BaseAddress
, Length
, Attributes
));
814 return EFI_UNSUPPORTED
;
817 return SetMemoryAttributes (BaseAddress
, Length
, Attributes
, 0);
823 // Add a new protocol to support
828 CpuConvertPagesToUncachedVirtualAddress (
829 IN VIRTUAL_UNCACHED_PAGES_PROTOCOL
*This
,
830 IN EFI_PHYSICAL_ADDRESS Address
,
832 IN EFI_PHYSICAL_ADDRESS VirtualMask
,
833 OUT UINT64
*Attributes OPTIONAL
837 EFI_GCD_MEMORY_SPACE_DESCRIPTOR GcdDescriptor
;
840 if (Attributes
!= NULL
) {
841 Status
= gDS
->GetMemorySpaceDescriptor (Address
, &GcdDescriptor
);
842 if (!EFI_ERROR (Status
)) {
843 *Attributes
= GcdDescriptor
.Attributes
;
848 // Make this address range page fault if accessed. If it is a DMA buffer than this would
849 // be the PCI address. Code should always use the CPU address, and we will or in VirtualMask
852 Status
= SetMemoryAttributes (Address
, Length
, EFI_MEMORY_WP
, 0);
853 if (!EFI_ERROR (Status
)) {
854 Status
= SetMemoryAttributes (Address
| VirtualMask
, Length
, EFI_MEMORY_UC
, VirtualMask
);
863 CpuReconvertPagesPages (
864 IN VIRTUAL_UNCACHED_PAGES_PROTOCOL
*This
,
865 IN EFI_PHYSICAL_ADDRESS Address
,
867 IN EFI_PHYSICAL_ADDRESS VirtualMask
,
874 // Unmap the alaised Address
876 Status
= SetMemoryAttributes (Address
| VirtualMask
, Length
, EFI_MEMORY_WP
, 0);
877 if (!EFI_ERROR (Status
)) {
879 // Restore atttributes
881 Status
= SetMemoryAttributes (Address
, Length
, Attributes
, 0);
888 VIRTUAL_UNCACHED_PAGES_PROTOCOL gVirtualUncachedPages
= {
889 CpuConvertPagesToUncachedVirtualAddress
,
890 CpuReconvertPagesPages