3 Copyright (c) 2009, Hewlett-Packard Company. All rights reserved.<BR>
4 Portions copyright (c) 2010, Apple Inc. All rights reserved.<BR>
5 Portions copyright (c) 2011-2013, ARM Ltd. All rights reserved.<BR>
7 This program and the accompanying materials
8 are licensed and made available under the terms and conditions of the BSD License
9 which accompanies this distribution. The full text of the license may be found at
10 http://opensource.org/licenses/bsd-license.php
12 THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
13 WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
20 #define TT_ATTR_INDX_INVALID ((UINT32)~0)
24 GetFirstPageAttribute (
25 IN UINT64
*FirstLevelTableAddress
,
31 // Get the first entry of the table
32 FirstEntry
= *FirstLevelTableAddress
;
34 if ((FirstEntry
& TT_TYPE_MASK
) == TT_TYPE_TABLE_ENTRY
) {
35 // Only valid for Levels 0, 1 and 2
36 ASSERT (TableLevel
< 3);
38 // Get the attribute of the subsequent table
39 return GetFirstPageAttribute ((UINT64
*)(FirstEntry
& TT_ADDRESS_MASK_DESCRIPTION_TABLE
), TableLevel
+ 1);
40 } else if (((FirstEntry
& TT_TYPE_MASK
) == TT_TYPE_BLOCK_ENTRY
) ||
41 ((TableLevel
== 3) && ((FirstEntry
& TT_TYPE_MASK
) == TT_TYPE_BLOCK_ENTRY_LEVEL3
)))
43 return FirstEntry
& TT_ATTR_INDX_MASK
;
45 return TT_ATTR_INDX_INVALID
;
51 GetNextEntryAttribute (
52 IN UINT64
*TableAddress
,
55 IN UINT64 BaseAddress
,
56 IN OUT UINT32
*PrevEntryAttribute
,
57 IN OUT UINT64
*StartGcdRegion
62 UINT32 EntryAttribute
;
65 UINTN NumberOfDescriptors
;
66 EFI_GCD_MEMORY_SPACE_DESCRIPTOR
*MemorySpaceMap
;
68 // Get the memory space map from GCD
69 MemorySpaceMap
= NULL
;
70 Status
= gDS
->GetMemorySpaceMap (&NumberOfDescriptors
, &MemorySpaceMap
);
71 ASSERT_EFI_ERROR (Status
);
73 // We cannot get more than 3-level page table
74 ASSERT (TableLevel
<= 3);
76 // While the top level table might not contain TT_ENTRY_COUNT entries;
77 // the subsequent ones should be filled up
78 for (Index
= 0; Index
< EntryCount
; Index
++) {
79 Entry
= TableAddress
[Index
];
80 EntryType
= Entry
& TT_TYPE_MASK
;
81 EntryAttribute
= Entry
& TT_ATTR_INDX_MASK
;
83 // If Entry is a Table Descriptor type entry then go through the sub-level table
84 if ((EntryType
== TT_TYPE_BLOCK_ENTRY
) ||
85 ((TableLevel
== 3) && (EntryType
== TT_TYPE_BLOCK_ENTRY_LEVEL3
))) {
86 if ((*PrevEntryAttribute
== TT_ATTR_INDX_INVALID
) || (EntryAttribute
!= *PrevEntryAttribute
)) {
87 if (*PrevEntryAttribute
!= TT_ATTR_INDX_INVALID
) {
88 // Update GCD with the last region
89 SetGcdMemorySpaceAttributes (MemorySpaceMap
, NumberOfDescriptors
,
91 (BaseAddress
+ (Index
* TT_ADDRESS_AT_LEVEL(TableLevel
)) - 1) - *StartGcdRegion
,
92 PageAttributeToGcdAttribute (EntryAttribute
));
95 // Start of the new region
96 *StartGcdRegion
= BaseAddress
+ (Index
* TT_ADDRESS_AT_LEVEL(TableLevel
));
97 *PrevEntryAttribute
= EntryAttribute
;
101 } else if (EntryType
== TT_TYPE_TABLE_ENTRY
) {
102 // Table Entry type is only valid for Level 0, 1, 2
103 ASSERT (TableLevel
< 3);
105 // Increase the level number and scan the sub-level table
106 GetNextEntryAttribute ((UINT64
*)(Entry
& TT_ADDRESS_MASK_DESCRIPTION_TABLE
),
107 TT_ENTRY_COUNT
, TableLevel
+ 1,
108 (BaseAddress
+ (Index
* TT_ADDRESS_AT_LEVEL(TableLevel
))),
109 PrevEntryAttribute
, StartGcdRegion
);
111 if (*PrevEntryAttribute
!= TT_ATTR_INDX_INVALID
) {
112 // Update GCD with the last region
113 SetGcdMemorySpaceAttributes (MemorySpaceMap
, NumberOfDescriptors
,
115 (BaseAddress
+ (Index
* TT_ADDRESS_AT_LEVEL(TableLevel
)) - 1) - *StartGcdRegion
,
116 PageAttributeToGcdAttribute (EntryAttribute
));
118 // Start of the new region
119 *StartGcdRegion
= BaseAddress
+ (Index
* TT_ADDRESS_AT_LEVEL(TableLevel
));
120 *PrevEntryAttribute
= TT_ATTR_INDX_INVALID
;
125 return BaseAddress
+ (EntryCount
* TT_ADDRESS_AT_LEVEL(TableLevel
));
130 IN EFI_CPU_ARCH_PROTOCOL
*CpuProtocol
134 UINT32 PageAttribute
= 0;
135 UINT64
*FirstLevelTableAddress
;
138 UINTN NumberOfDescriptors
;
139 EFI_GCD_MEMORY_SPACE_DESCRIPTOR
*MemorySpaceMap
;
142 UINT64 BaseAddressGcdRegion
;
143 UINT64 EndAddressGcdRegion
;
145 // This code assumes MMU is enabled and filed with section translations
146 ASSERT (ArmMmuEnabled ());
149 // Get the memory space map from GCD
151 MemorySpaceMap
= NULL
;
152 Status
= gDS
->GetMemorySpaceMap (&NumberOfDescriptors
, &MemorySpaceMap
);
153 ASSERT_EFI_ERROR (Status
);
155 // The GCD implementation maintains its own copy of the state of memory space attributes. GCD needs
156 // to know what the initial memory space attributes are. The CPU Arch. Protocol does not provide a
157 // GetMemoryAttributes function for GCD to get this so we must resort to calling GCD (as if we were
158 // a client) to update its copy of the attributes. This is bad architecture and should be replaced
159 // with a way for GCD to query the CPU Arch. driver of the existing memory space attributes instead.
161 // Obtain page table base
162 FirstLevelTableAddress
= (UINT64
*)(ArmGetTTBR0BaseAddress ());
164 // Get Translation Control Register value
166 // Get Address Region Size
167 T0SZ
= Tcr
& TCR_T0SZ_MASK
;
169 // Get the level of the first table for the indicated Address Region Size
170 GetRootTranslationTableInfo (T0SZ
, &TableLevel
, &TableCount
);
172 // First Attribute of the Page Tables
173 PageAttribute
= GetFirstPageAttribute (FirstLevelTableAddress
, TableLevel
);
175 // We scan from the start of the memory map (ie: at the address 0x0)
176 BaseAddressGcdRegion
= 0x0;
177 EndAddressGcdRegion
= GetNextEntryAttribute (FirstLevelTableAddress
,
178 TableCount
, TableLevel
,
179 BaseAddressGcdRegion
,
180 &PageAttribute
, &BaseAddressGcdRegion
);
182 // Update GCD with the last region
183 SetGcdMemorySpaceAttributes (MemorySpaceMap
, NumberOfDescriptors
,
184 BaseAddressGcdRegion
,
185 EndAddressGcdRegion
- BaseAddressGcdRegion
,
186 PageAttributeToGcdAttribute (PageAttribute
));