• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /** @file
2 
3 Copyright (c) 2006 - 2007, Intel Corporation. All rights reserved.<BR>
4 This program and the accompanying materials
5 are licensed and made available under the terms and conditions of the BSD License
6 which accompanies this distribution.  The full text of the license may be found at
7 http://opensource.org/licenses/bsd-license.php
8 
9 THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
10 WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
11 
12 Module Name:
13   Paging.c
14 
15 Abstract:
16 
17 Revision History:
18 
19 **/
20 
21 #include "HobGeneration.h"
22 #include "VirtualMemory.h"
23 
24 //
25 // Create 2M-page table
26 // PML4 (47:39)
27 // PDPTE (38:30)
28 // PDE (29:21)
29 //
30 
31 #define EFI_2M_PAGE_BITS_NUM    21
32 #define EFI_MAX_ENTRY_BITS_NUM  9
33 
34 #define EFI_PAGE_SIZE_4K        0x1000
35 #define EFI_PAGE_SIZE_2M        (1 << EFI_2M_PAGE_BITS_NUM)
36 
37 #ifndef MIN
38   #define MIN(a, b)               ((a) < (b) ? (a) : (b))
39 #endif
40 #define ENTRY_NUM(x)            ((UINTN)1 << (x))
41 
42 UINT8 gPML4BitsNum;
43 UINT8 gPDPTEBitsNum;
44 UINT8 gPDEBitsNum;
45 
46 UINTN gPageNum2M;
47 UINTN gPageNum4K;
48 
49 VOID
EnableNullPointerProtection(UINT8 * PageTable)50 EnableNullPointerProtection (
51   UINT8                       *PageTable
52   )
53 {
54   X64_PAGE_TABLE_ENTRY_4K *PageTableEntry4KB;
55 
56   PageTableEntry4KB = (X64_PAGE_TABLE_ENTRY_4K *) (PageTable + gPageNum2M * EFI_PAGE_SIZE_4K);
57   //
58   // Fill in the Page Table entries
59   // Mark 0~4K as not present
60   //
61   PageTableEntry4KB->Bits.Present = 0;
62 
63   return ;
64 }
65 
66 VOID
X64Create4KPageTables(UINT8 * PageTable)67 X64Create4KPageTables (
68   UINT8                       *PageTable
69   )
70 /*++
71 Routine Description:
72   Create 4K-Page-Table for the low 2M memory.
73   This will change the previously created 2M-Page-Table-Entry.
74 --*/
75 {
76   UINT64                                        PageAddress;
77   UINTN                                         PTEIndex;
78   X64_PAGE_DIRECTORY_ENTRY_4K                   *PageDirectoryEntry4KB;
79   X64_PAGE_TABLE_ENTRY_4K                       *PageTableEntry4KB;
80 
81   //
82   //  Page Table structure 4 level 4K.
83   //
84   //                   PageMapLevel4Entry        : bits 47-39
85   //                   PageDirectoryPointerEntry : bits 38-30
86   //  Page Table 4K  : PageDirectoryEntry4K      : bits 29-21
87   //                   PageTableEntry            : bits 20-12
88   //
89 
90   PageTableEntry4KB = (X64_PAGE_TABLE_ENTRY_4K *)(PageTable + gPageNum2M * EFI_PAGE_SIZE_4K);
91 
92   PageDirectoryEntry4KB = (X64_PAGE_DIRECTORY_ENTRY_4K *) (PageTable + 2 * EFI_PAGE_SIZE_4K);
93   PageDirectoryEntry4KB->Uint64 = (UINT64)(UINTN)PageTableEntry4KB;
94   PageDirectoryEntry4KB->Bits.ReadWrite = 1;
95   PageDirectoryEntry4KB->Bits.Present = 1;
96   PageDirectoryEntry4KB->Bits.MustBeZero = 0;
97 
98   for (PTEIndex = 0, PageAddress = 0;
99        PTEIndex < ENTRY_NUM (EFI_MAX_ENTRY_BITS_NUM);
100        PTEIndex++, PageTableEntry4KB++, PageAddress += EFI_PAGE_SIZE_4K
101       ) {
102     //
103     // Fill in the Page Table entries
104     //
105     PageTableEntry4KB->Uint64 = (UINT64)PageAddress;
106     PageTableEntry4KB->Bits.ReadWrite = 1;
107     PageTableEntry4KB->Bits.Present = 1;
108   }
109 
110   return ;
111 }
112 
113 VOID
X64Create2MPageTables(UINT8 * PageTable)114 X64Create2MPageTables (
115   UINT8 *PageTable
116   )
117 {
118   UINT64                                        PageAddress;
119   UINT8                                         *TempPageTable;
120   UINTN                                         PML4Index;
121   UINTN                                         PDPTEIndex;
122   UINTN                                         PDEIndex;
123   X64_PAGE_MAP_AND_DIRECTORY_POINTER_2MB_4K     *PageMapLevel4Entry;
124   X64_PAGE_MAP_AND_DIRECTORY_POINTER_2MB_4K     *PageDirectoryPointerEntry;
125   X64_PAGE_TABLE_ENTRY_2M                       *PageDirectoryEntry2MB;
126 
127   TempPageTable = PageTable;
128   PageAddress   = 0;
129 
130   //
131   //  Page Table structure 3 level 2MB.
132   //
133   //                   PageMapLevel4Entry        : bits 47-39
134   //                   PageDirectoryPointerEntry : bits 38-30
135   //  Page Table 2MB : PageDirectoryEntry2M      : bits 29-21
136   //
137 
138   PageMapLevel4Entry = (X64_PAGE_MAP_AND_DIRECTORY_POINTER_2MB_4K *)TempPageTable;
139 
140   for (PML4Index = 0; PML4Index < ENTRY_NUM (gPML4BitsNum); PML4Index++, PageMapLevel4Entry++) {
141     //
142     // Each PML4 entry points to a page of Page Directory Pointer entires.
143     //
144     TempPageTable += EFI_PAGE_SIZE_4K;
145     PageDirectoryPointerEntry = (X64_PAGE_MAP_AND_DIRECTORY_POINTER_2MB_4K *)TempPageTable;
146 
147     //
148     // Make a PML4 Entry
149     //
150     PageMapLevel4Entry->Uint64 = (UINT64)(UINTN)(TempPageTable);
151     PageMapLevel4Entry->Bits.ReadWrite = 1;
152     PageMapLevel4Entry->Bits.Present = 1;
153 
154     for (PDPTEIndex = 0; PDPTEIndex < ENTRY_NUM (gPDPTEBitsNum); PDPTEIndex++, PageDirectoryPointerEntry++) {
155       //
156       // Each Directory Pointer entries points to a page of Page Directory entires.
157       //
158       TempPageTable += EFI_PAGE_SIZE_4K;
159       PageDirectoryEntry2MB = (X64_PAGE_TABLE_ENTRY_2M *)TempPageTable;
160 
161       //
162       // Fill in a Page Directory Pointer Entries
163       //
164       PageDirectoryPointerEntry->Uint64 = (UINT64)(UINTN)(TempPageTable);
165       PageDirectoryPointerEntry->Bits.ReadWrite = 1;
166       PageDirectoryPointerEntry->Bits.Present = 1;
167 
168       for (PDEIndex = 0; PDEIndex < ENTRY_NUM (gPDEBitsNum); PDEIndex++, PageDirectoryEntry2MB++) {
169         //
170         // Fill in the Page Directory entries
171         //
172         PageDirectoryEntry2MB->Uint64 = (UINT64)PageAddress;
173         PageDirectoryEntry2MB->Bits.ReadWrite = 1;
174         PageDirectoryEntry2MB->Bits.Present = 1;
175         PageDirectoryEntry2MB->Bits.MustBe1 = 1;
176 
177         PageAddress += EFI_PAGE_SIZE_2M;
178       }
179     }
180   }
181 
182   return ;
183 }
184 
185 VOID *
PreparePageTable(VOID * PageNumberTop,UINT8 SizeOfMemorySpace)186 PreparePageTable (
187   VOID  *PageNumberTop,
188   UINT8 SizeOfMemorySpace
189   )
190 /*++
191 Description:
192   Generate pagetable below PageNumberTop,
193   and return the bottom address of pagetable for putting other things later.
194 --*/
195 {
196   VOID  *PageNumberBase;
197 
198   SizeOfMemorySpace -= EFI_2M_PAGE_BITS_NUM;
199   gPDEBitsNum        = (UINT8) MIN (SizeOfMemorySpace, EFI_MAX_ENTRY_BITS_NUM);
200   SizeOfMemorySpace  = (UINT8) (SizeOfMemorySpace - gPDEBitsNum);
201   gPDPTEBitsNum      = (UINT8) MIN (SizeOfMemorySpace, EFI_MAX_ENTRY_BITS_NUM);
202   SizeOfMemorySpace  = (UINT8) (SizeOfMemorySpace - gPDPTEBitsNum);
203   gPML4BitsNum       = SizeOfMemorySpace;
204   if (gPML4BitsNum > EFI_MAX_ENTRY_BITS_NUM) {
205     return NULL;
206   }
207 
208   //
209   // Suppose we have:
210   // 2MPage:
211   //   Entry:       PML4   ->     PDPTE     ->     PDE    -> Page
212   //   EntryNum:     a              b               c
213   // then
214   //   Occupy4KPage: 1              a              a*b
215   //
216   // 2M 4KPage:
217   //   Entry:       PTE    ->     Page
218   //   EntryNum:    512
219   // then
220   //   Occupy4KPage: 1
221   //
222 
223   gPageNum2M = 1 + ENTRY_NUM (gPML4BitsNum) + ENTRY_NUM (gPML4BitsNum + gPDPTEBitsNum);
224   gPageNum4K = 1;
225 
226 
227   PageNumberBase = (VOID *)((UINTN)PageNumberTop - (gPageNum2M + gPageNum4K) * EFI_PAGE_SIZE_4K);
228   ZeroMem (PageNumberBase, (gPageNum2M + gPageNum4K) * EFI_PAGE_SIZE_4K);
229 
230   X64Create2MPageTables (PageNumberBase);
231   X64Create4KPageTables (PageNumberBase);
232   //
233   // Not enable NULL Pointer Protection if using INTx call
234   //
235 //  EnableNullPointerProtection (PageNumberBase);
236 
237   return PageNumberBase;
238 }
239