Home | History | Annotate | Download | only in X64
      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
     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
     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
    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 *
    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