]> git.proxmox.com Git - mirror_edk2.git/blame - EdkModulePkg/Core/DxeIplX64Peim/x64/VirtualMemory.c
Identify SupArch for .msa
[mirror_edk2.git] / EdkModulePkg / Core / DxeIplX64Peim / x64 / VirtualMemory.c
CommitLineData
878ddf1f 1/*++\r
2\r
3Copyright (c) 2006, Intel Corporation \r
4All rights reserved. This program and the accompanying materials \r
5are licensed and made available under the terms and conditions of the BSD License \r
6which accompanies this distribution. The full text of the license may be found at \r
7http://opensource.org/licenses/bsd-license.php \r
8 \r
9THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, \r
10WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. \r
11\r
12Module Name:\r
13 VirtualMemory.c\r
14 \r
15Abstract:\r
16\r
17 x64 Virtual Memory Management Services in the form of an IA-32 driver. \r
18 Used to establish a 1:1 Virtual to Physical Mapping that is required to\r
19 enter Long Mode (x64 64-bit mode).\r
20\r
21 While we make a 1:1 mapping (identity mapping) for all physical pages \r
22 we still need to use the MTRR's to ensure that the cachability attirbutes\r
23 for all memory regions is correct.\r
24\r
25 The basic idea is to use 2MB page table entries where ever possible. If\r
26 more granularity of cachability is required then 4K page tables are used.\r
27\r
28 References:\r
29 1) IA-32 Intel(R) Atchitecture Software Developer's Manual Volume 1:Basic Architecture, Intel\r
30 2) IA-32 Intel(R) Atchitecture Software Developer's Manual Volume 2:Instruction Set Reference, Intel\r
31 3) IA-32 Intel(R) Atchitecture Software Developer's Manual Volume 3:System Programmer's Guide, Intel\r
32 \r
33--*/ \r
34\r
35#include "VirtualMemory.h"\r
36\r
37x64_MTRR_VARIABLE_RANGE *mMTRRVariableRange;\r
38x64_MTRR_FIXED_RANGE mMTRRFixedRange;\r
39\r
40\r
41//\r
42// Physial memory limit values for each of the 11 fixed MTRRs\r
43//\r
44UINTN mFixedRangeLimit[] = {\r
45 0x7FFFF, // Fixed MTRR #0 describes 0x00000..0x7FFFF\r
46 0x9FFFF, // Fixed MTRR #1 describes 0x80000..0x9FFFF\r
47 0xBFFFF, // Fixed MTRR #2 describes 0xA0000..0xBFFFF\r
48 0xC7FFF, // Fixed MTRR #3 describes 0xC0000..0xC7FFF\r
49 0xCFFFF, // Fixed MTRR #4 describes 0xC8000..0xCFFFF\r
50 0xD7FFF, // Fixed MTRR #5 describes 0xD0000..0xD7FFF\r
51 0xDFFFF, // Fixed MTRR #6 describes 0xD8000..0xDFFFF\r
52 0xE7FFF, // Fixed MTRR #7 describes 0xE0000..0xE7FFF\r
53 0xEFFFF, // Fixed MTRR #8 describes 0xE8000..0xEFFFF\r
54 0xF7FFF, // Fixed MTRR #9 describes 0xF0000..0xF7FFF\r
55 0xFFFFF // Fixed MTRR #10 describes 0xF8000..0xFFFFF\r
56};\r
57\r
58//\r
59// The size, in bits, of each of the 11 fixed MTRR.\r
60//\r
61UINTN mFixedRangeShift[] = {\r
62 16, // Fixed MTRR #0 describes 8, 64 KB ranges\r
63 14, // Fixed MTRR #1 describes 8, 16 KB ranges\r
64 14, // Fixed MTRR #2 describes 8, 16 KB ranges\r
65 12, // Fixed MTRR #3 describes 8, 4 KB ranges\r
66 12, // Fixed MTRR #4 describes 8, 4 KB ranges\r
67 12, // Fixed MTRR #5 describes 8, 4 KB ranges\r
68 12, // Fixed MTRR #6 describes 8, 4 KB ranges\r
69 12, // Fixed MTRR #7 describes 8, 4 KB ranges\r
70 12, // Fixed MTRR #8 describes 8, 4 KB ranges\r
71 12, // Fixed MTRR #9 describes 8, 4 KB ranges\r
72 12 // Fixed MTRR #10 describes 8, 4 KB ranges\r
73};\r
74\r
75\r
76UINTN mPowerOf2[] = {\r
77 1,\r
78 2,\r
79 4,\r
80 8,\r
81 16,\r
82 32,\r
83 64,\r
84 128,\r
85 256,\r
86 512\r
87};\r
88\r
89x64_MTRR_MEMORY_TYPE\r
90EfiGetMTRRMemoryType (\r
91 IN EFI_PHYSICAL_ADDRESS Address\r
92 )\r
93/*++\r
94\r
95Routine Description:\r
96\r
97 Retrieves the memory type from the MTRR that describes a physical address.\r
98\r
99Arguments:\r
100\r
101 VariableRange - Set of Variable MTRRs\r
102\r
103 FixedRange - Set of Fixed MTRRs\r
104\r
105 Address - The physical address for which the MTRR memory type is being retrieved\r
106\r
107Returns:\r
108\r
109 The MTRR Memory Type for the physical memory specified by Address.\r
110\r
111--*/\r
112{\r
113 UINTN Index;\r
114 UINTN TypeIndex;\r
115 BOOLEAN Found;\r
116 x64_MTRR_MEMORY_TYPE VariableType;\r
117 EFI_PHYSICAL_ADDRESS MaskBase;\r
118 EFI_PHYSICAL_ADDRESS PhysMask;\r
119\r
120 //\r
121 // If the MTRRs are disabled, then return the Uncached Memory Type\r
122 //\r
123 if (mMTRRFixedRange.DefaultType.Bits.E == 0) {\r
124 return Uncached;\r
125 }\r
126\r
127 //\r
128 // If the CPU supports Fixed MTRRs and the Fixed MTRRs are enabled, then \r
129 // see if Address falls into one of the Fixed MTRRs\r
130 //\r
131 if (mMTRRFixedRange.Capabilities.Bits.FIX && mMTRRFixedRange.DefaultType.Bits.FE) {\r
132 //\r
133 // Loop though 11 fixed MTRRs\r
134 //\r
135 for (Index = 0; Index < 11; Index++) {\r
136 //\r
137 // Check for a matching range\r
138 //\r
139 if (Address <= mFixedRangeLimit[Index]) {\r
140 //\r
141 // Compute the offset address into the MTRR bu subtrating the base address of the MTRR\r
142 //\r
143 if (Index > 0) {\r
144 Address = Address - (mFixedRangeLimit[Index-1] + 1);\r
145 }\r
146 //\r
147 // Retrieve the index into the MTRR to extract the memory type. The range is 0..7\r
148 //\r
149 TypeIndex = (UINTN)RShiftU64 (Address, mFixedRangeShift[Index]);\r
150 \r
151 //\r
152 // Retrieve and return the memory type for the matching range\r
153 //\r
154 return mMTRRFixedRange.Fixed[Index].Type[TypeIndex];\r
155 }\r
156 }\r
157 }\r
158\r
159 //\r
160 // If Address was not found in a Fixed MTRR, then search the Variable MTRRs\r
161 //\r
162 for (Index = 0, Found = FALSE, VariableType = WriteBack; Index < mMTRRFixedRange.Capabilities.Bits.VCNT; Index++) {\r
163 //\r
164 // BugBug: __aullshr complier error\r
165 //\r
166 if ((mMTRRVariableRange[Index].PhysMask.Uint64 & 0x800) == 0x800) { \r
167 //if (mMTRRVariableRange[Index].PhysMask.Bits.Valid == 1) {\r
168 PhysMask = mMTRRVariableRange[Index].PhysMask.Uint64 & ~0xfff;\r
169 MaskBase = PhysMask & (mMTRRVariableRange[Index].PhysBase.Uint64 & ~0xfff);\r
170 if (MaskBase == (PhysMask & Address)) {\r
171 //\r
172 // Check to see how many matches we find\r
173 //\r
174 Found = TRUE;\r
175 if ((mMTRRVariableRange[Index].PhysBase.Bits.Type == Uncached) || (VariableType == Uncached)) {\r
176 //\r
177 // If any matching region uses UC, the memory region is UC\r
178 //\r
179 VariableType = Uncached;\r
180 } else if ((mMTRRVariableRange[Index].PhysBase.Bits.Type == WriteThrough) || (VariableType == WriteThrough)){\r
181 //\r
182 // If it's WT and WB then set it to WT. If it's WT and other type it's undefined\r
183 //\r
184 VariableType = WriteThrough;\r
185 } else {\r
186 VariableType = mMTRRVariableRange[Index].PhysBase.Bits.Type;\r
187 }\r
188 }\r
189 }\r
190 }\r
191 \r
192 if (Found) {\r
193 return VariableType;\r
194 }\r
195\r
196 //\r
197 // Address was not found in the Fixed or Variable MTRRs, so return the default memory type\r
198 //\r
199 return mMTRRFixedRange.DefaultType.Bits.Type;\r
200}\r
201\r
202\r
203BOOLEAN\r
204CanNotUse2MBPage (\r
205 IN EFI_PHYSICAL_ADDRESS BaseAddress\r
206 )\r
207/*++\r
208\r
209Routine Description:\r
210 Test to see if a 2MB aligned page has all the same attributes. If a 2MB page\r
211 has more than one attibute type it needs to be split into multiple 4K pages.\r
212\r
213Arguments:\r
214 BaseAddress - 2MB aligned address to check out\r
215\r
216Returns:\r
217 TRUE - This 2MB address range (BaseAddress) can NOT be mapped by a 2MB page\r
218 FALSE - This 2MB address range can be mapped by a 2MB page\r
219\r
220--*/\r
221{\r
222 UINTN Index;\r
223 x64_MTRR_MEMORY_TYPE MemoryType;\r
224 x64_MTRR_MEMORY_TYPE PreviousMemoryType;\r
225 \r
226 //\r
227 // Address needs to be 2MB aligned\r
228 //\r
229 ASSERT ((BaseAddress & 0x1fffff) == 0);\r
230\r
231 PreviousMemoryType = -1;\r
232 for (Index = 0; Index < 512; Index++, BaseAddress += 0x1000) {\r
233 MemoryType = EfiGetMTRRMemoryType (BaseAddress);\r
234 if ((Index != 0) && (MemoryType != PreviousMemoryType)) {\r
235 return TRUE;\r
236 }\r
237\r
238 PreviousMemoryType = MemoryType;\r
239 }\r
240\r
241 //\r
242 // All the pages had the same type\r
243 //\r
244 return FALSE;\r
245}\r
246\r
247\r
248\r
249\r
250VOID\r
251Convert2MBPageTo4KPages ( \r
252 IN x64_PAGE_TABLE_ENTRY_2M *PageDirectoryEntry2MB, \r
253 IN EFI_PHYSICAL_ADDRESS PageAddress\r
254 )\r
255/*++\r
256\r
257Routine Description:\r
258 Convert a single 2MB page entry to 512 4K page entries. The attributes for \r
259 the 4K pages are read from the MTRR registers.\r
260\r
261Arguments:\r
262 PageDirectoryEntry2MB - Page directory entry for PageAddress\r
263 PageAddress - 2MB algined address of region to convert\r
264\r
265Returns:\r
266 None\r
267\r
268--*/\r
269{\r
270 EFI_PHYSICAL_ADDRESS Address;\r
271 x64_PAGE_DIRECTORY_ENTRY_4K *PageDirectoryEntry4k;\r
272 x64_PAGE_TABLE_ENTRY_4K *PageTableEntry;\r
273 UINTN Index1;\r
274\r
275 //\r
276 // Allocate the page table entry for the 4K pages\r
277 //\r
278 PageTableEntry = (x64_PAGE_TABLE_ENTRY_4K *) AllocatePages (1);\r
279\r
280 ASSERT (PageTableEntry != NULL);\r
281\r
282 //\r
283 // Convert PageDirectoryEntry2MB into a 4K Page Directory\r
284 //\r
285 PageDirectoryEntry4k = (x64_PAGE_DIRECTORY_ENTRY_4K *)PageDirectoryEntry2MB;\r
286 PageDirectoryEntry2MB->Uint64 = (UINT64)PageTableEntry;\r
287 PageDirectoryEntry2MB->Bits.ReadWrite = 1;\r
288 PageDirectoryEntry2MB->Bits.Present = 1;\r
289 \r
290 //\r
291 // Fill in the 4K page entries with the attributes from the MTRRs\r
292 //\r
293 for (Index1 = 0, Address = PageAddress; Index1 < 512; Index1++, PageTableEntry++, Address += 0x1000) {\r
294 PageTableEntry->Uint64 = (UINT64)Address;\r
295 PageTableEntry->Bits.ReadWrite = 1;\r
296 PageTableEntry->Bits.Present = 1;\r
297 }\r
298}\r
299\r
300\r
301EFI_PHYSICAL_ADDRESS\r
302CreateIdentityMappingPageTables (\r
303 IN UINT32 NumberOfProcessorPhysicalAddressBits\r
304 )\r
305/*++\r
306\r
307Routine Description:\r
308\r
309 Allocates and fills in the Page Directory and Page Table Entries to\r
310 establish a 1:1 Virtual to Physical mapping for physical memory from\r
311 0 to 4GB. Memory above 4GB is not mapped. The MTRRs are used to \r
312 determine the cachability of the physical memory regions\r
313\r
314Arguments:\r
315\r
316 NumberOfProcessorPhysicalAddressBits - Number of processor address bits to use.\r
317 Limits the number of page table entries \r
318 to the physical address space.\r
319\r
320Returns:\r
321 EFI_OUT_OF_RESOURCES There are not enough resources to allocate the Page Tables\r
322\r
323 EFI_SUCCESS The 1:1 Virtual to Physical identity mapping was created\r
324\r
325--*/\r
326{ \r
327 EFI_PHYSICAL_ADDRESS PageAddress;\r
328 UINTN Index;\r
329 UINTN MaxBitsSupported;\r
330 UINTN Index1;\r
331 UINTN Index2;\r
332 x64_PAGE_MAP_AND_DIRECTORY_POINTER_2MB_4K *PageMapLevel4Entry;\r
333 x64_PAGE_MAP_AND_DIRECTORY_POINTER_2MB_4K *PageMap;\r
334 x64_PAGE_MAP_AND_DIRECTORY_POINTER_2MB_4K *PageDirectoryPointerEntry;\r
335 x64_PAGE_TABLE_ENTRY_2M *PageDirectoryEntry2MB;\r
336\r
337\r
338 //\r
339 // Page Table structure 4 level 4K, 3 level 2MB.\r
340 //\r
341 // PageMapLevel4Entry : bits 47-39\r
342 // PageDirectoryPointerEntry : bits 38-30\r
343 // Page Table 2MB : PageDirectoryEntry2M : bits 29-21\r
344 // Page Table 4K : PageDirectoryEntry4K : bits 29 - 21\r
345 // PageTableEntry : bits 20 - 12\r
346 //\r
347 // Strategy is to map every thing in the processor address space using \r
348 // 2MB pages. If more granularity is required the 2MB page will get \r
349 // converted to set of 4K pages. \r
350 //\r
351\r
352 //\r
353 // By architecture only one PageMapLevel4 exists - so lets allocate storgage for it.\r
354 //\r
355 PageMap = PageMapLevel4Entry = (x64_PAGE_MAP_AND_DIRECTORY_POINTER_2MB_4K *) AllocatePages (1);\r
356 ASSERT (PageMap != NULL);\r
357 PageAddress = 0;\r
358\r
359 //\r
360 // The number of page-map Level-4 Offset entries is based on the number of \r
361 // physical address bits. Less than equal to 38 bits only takes one entry.\r
362 // 512 entries represents 48 address bits. \r
363 //\r
364 if (NumberOfProcessorPhysicalAddressBits <= 38) {\r
365 MaxBitsSupported = 1;\r
366 } else {\r
367 MaxBitsSupported = mPowerOf2[NumberOfProcessorPhysicalAddressBits - 39];\r
368 }\r
369\r
370 for (Index = 0; Index < MaxBitsSupported; Index++, PageMapLevel4Entry++) {\r
371 //\r
372 // Each PML4 entry points to a page of Page Directory Pointer entires.\r
373 // So lets allocate space for them and fill them in in the Index1 loop.\r
374 // \r
375 PageDirectoryPointerEntry = (x64_PAGE_MAP_AND_DIRECTORY_POINTER_2MB_4K *) AllocatePages (1);\r
376 ASSERT (PageDirectoryPointerEntry != NULL);\r
377\r
378 //\r
379 // Make a PML4 Entry\r
380 //\r
381 PageMapLevel4Entry->Uint64 = (UINT64)(UINTN)PageDirectoryPointerEntry;\r
382 PageMapLevel4Entry->Bits.ReadWrite = 1;\r
383 PageMapLevel4Entry->Bits.Present = 1;\r
384\r
385 for (Index1 = 0; Index1 < 512; Index1++, PageDirectoryPointerEntry++) {\r
386 //\r
387 // Each Directory Pointer entries points to a page of Page Directory entires.\r
388 // So lets allocate space for them and fill them in in the Index2 loop.\r
389 // \r
390 PageDirectoryEntry2MB = (x64_PAGE_TABLE_ENTRY_2M *) AllocatePages (1);\r
391 ASSERT (PageDirectoryEntry2MB != NULL);\r
392\r
393 //\r
394 // Fill in a Page Directory Pointer Entries\r
395 //\r
396 PageDirectoryPointerEntry->Uint64 = (UINT64)(UINTN)PageDirectoryEntry2MB;\r
397 PageDirectoryPointerEntry->Bits.ReadWrite = 1;\r
398 PageDirectoryPointerEntry->Bits.Present = 1;\r
399\r
400 for (Index2 = 0; Index2 < 512; Index2++, PageDirectoryEntry2MB++, PageAddress += 0x200000) {\r
401 //\r
402 // Fill in the Page Directory entries\r
403 //\r
404 PageDirectoryEntry2MB->Uint64 = (UINT64)PageAddress;\r
405 PageDirectoryEntry2MB->Bits.ReadWrite = 1;\r
406 PageDirectoryEntry2MB->Bits.Present = 1;\r
407 PageDirectoryEntry2MB->Bits.MustBe1 = 1;\r
408\r
409 if (CanNotUse2MBPage (PageAddress)) {\r
410 //\r
411 // Check to see if all 2MB has the same mapping. If not convert\r
412 // to 4K pages by adding the 4th level of page table entries\r
413 //\r
414 Convert2MBPageTo4KPages (PageDirectoryEntry2MB, PageAddress);\r
415 }\r
416 }\r
417 }\r
418 }\r
419\r
420 //\r
421 // For the PML4 entries we are not using fill in a null entry.\r
422 // for now we just copy the first entry.\r
423 //\r
424 for (; Index < 512; Index++, PageMapLevel4Entry++) {\r
425 // EfiCopyMem (PageMapLevel4Entry, PageMap, sizeof (x64_PAGE_MAP_AND_DIRECTORY_POINTER_2MB_4K));\r
426 CopyMem (PageMapLevel4Entry,\r
427 PageMap,\r
428 sizeof (x64_PAGE_MAP_AND_DIRECTORY_POINTER_2MB_4K)\r
429 );\r
430 }\r
431\r
432 return (EFI_PHYSICAL_ADDRESS)PageMap;\r
433}\r
434\r