]> git.proxmox.com Git - mirror_edk2.git/blob - ArmPkg/Drivers/CpuDxe/AArch64/Mmu.c
ArmPkg: Added Aarch64 support
[mirror_edk2.git] / ArmPkg / Drivers / CpuDxe / AArch64 / Mmu.c
1 /*++
2
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>
6
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
11
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.
14
15
16 --*/
17
18 #include "CpuDxe.h"
19
20 #define TT_ATTR_INDX_INVALID ((UINT32)~0)
21
22 STATIC
23 UINT64
24 GetFirstPageAttribute (
25 IN UINT64 *FirstLevelTableAddress,
26 IN UINTN TableLevel
27 )
28 {
29 UINT64 FirstEntry;
30
31 // Get the first entry of the table
32 FirstEntry = *FirstLevelTableAddress;
33
34 if ((FirstEntry & TT_TYPE_MASK) == TT_TYPE_TABLE_ENTRY) {
35 // Only valid for Levels 0, 1 and 2
36 ASSERT (TableLevel < 3);
37
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)))
42 {
43 return FirstEntry & TT_ATTR_INDX_MASK;
44 } else {
45 return TT_ATTR_INDX_INVALID;
46 }
47 }
48
49 STATIC
50 UINT64
51 GetNextEntryAttribute (
52 IN UINT64 *TableAddress,
53 IN UINTN EntryCount,
54 IN UINTN TableLevel,
55 IN UINT64 BaseAddress,
56 IN OUT UINT32 *PrevEntryAttribute,
57 IN OUT UINT64 *StartGcdRegion
58 )
59 {
60 UINTN Index;
61 UINT64 Entry;
62 UINT32 EntryAttribute;
63 UINT32 EntryType;
64 EFI_STATUS Status;
65 UINTN NumberOfDescriptors;
66 EFI_GCD_MEMORY_SPACE_DESCRIPTOR *MemorySpaceMap;
67
68 // Get the memory space map from GCD
69 MemorySpaceMap = NULL;
70 Status = gDS->GetMemorySpaceMap (&NumberOfDescriptors, &MemorySpaceMap);
71 ASSERT_EFI_ERROR (Status);
72
73 // We cannot get more than 3-level page table
74 ASSERT (TableLevel <= 3);
75
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;
82
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,
90 *StartGcdRegion,
91 (BaseAddress + (Index * TT_ADDRESS_AT_LEVEL(TableLevel)) - 1) - *StartGcdRegion,
92 PageAttributeToGcdAttribute (EntryAttribute));
93 }
94
95 // Start of the new region
96 *StartGcdRegion = BaseAddress + (Index * TT_ADDRESS_AT_LEVEL(TableLevel));
97 *PrevEntryAttribute = EntryAttribute;
98 } else {
99 continue;
100 }
101 } else if (EntryType == TT_TYPE_TABLE_ENTRY) {
102 // Table Entry type is only valid for Level 0, 1, 2
103 ASSERT (TableLevel < 3);
104
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);
110 } else {
111 if (*PrevEntryAttribute != TT_ATTR_INDX_INVALID) {
112 // Update GCD with the last region
113 SetGcdMemorySpaceAttributes (MemorySpaceMap, NumberOfDescriptors,
114 *StartGcdRegion,
115 (BaseAddress + (Index * TT_ADDRESS_AT_LEVEL(TableLevel)) - 1) - *StartGcdRegion,
116 PageAttributeToGcdAttribute (EntryAttribute));
117
118 // Start of the new region
119 *StartGcdRegion = BaseAddress + (Index * TT_ADDRESS_AT_LEVEL(TableLevel));
120 *PrevEntryAttribute = TT_ATTR_INDX_INVALID;
121 }
122 }
123 }
124
125 return BaseAddress + (EntryCount * TT_ADDRESS_AT_LEVEL(TableLevel));
126 }
127
128 EFI_STATUS
129 SyncCacheConfig (
130 IN EFI_CPU_ARCH_PROTOCOL *CpuProtocol
131 )
132 {
133 EFI_STATUS Status;
134 UINT32 PageAttribute = 0;
135 UINT64 *FirstLevelTableAddress;
136 UINTN TableLevel;
137 UINTN TableCount;
138 UINTN NumberOfDescriptors;
139 EFI_GCD_MEMORY_SPACE_DESCRIPTOR *MemorySpaceMap;
140 UINTN Tcr;
141 UINTN T0SZ;
142 UINT64 BaseAddressGcdRegion;
143 UINT64 EndAddressGcdRegion;
144
145 // This code assumes MMU is enabled and filed with section translations
146 ASSERT (ArmMmuEnabled ());
147
148 //
149 // Get the memory space map from GCD
150 //
151 MemorySpaceMap = NULL;
152 Status = gDS->GetMemorySpaceMap (&NumberOfDescriptors, &MemorySpaceMap);
153 ASSERT_EFI_ERROR (Status);
154
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.
160
161 // Obtain page table base
162 FirstLevelTableAddress = (UINT64*)(ArmGetTTBR0BaseAddress ());
163
164 // Get Translation Control Register value
165 Tcr = ArmGetTCR ();
166 // Get Address Region Size
167 T0SZ = Tcr & TCR_T0SZ_MASK;
168
169 // Get the level of the first table for the indicated Address Region Size
170 GetRootTranslationTableInfo (T0SZ, &TableLevel, &TableCount);
171
172 // First Attribute of the Page Tables
173 PageAttribute = GetFirstPageAttribute (FirstLevelTableAddress, TableLevel);
174
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);
181
182 // Update GCD with the last region
183 SetGcdMemorySpaceAttributes (MemorySpaceMap, NumberOfDescriptors,
184 BaseAddressGcdRegion,
185 EndAddressGcdRegion - BaseAddressGcdRegion,
186 PageAttributeToGcdAttribute (PageAttribute));
187
188 return EFI_SUCCESS;
189 }