Home | History | Annotate | Download | only in GenPage
      1 /** @file
      2   Pre-Create a 4G page table (2M pages).
      3   It's used in DUET x64 build needed to enter LongMode.
      4 
      5   Create 4G page table (2M pages)
      6 
      7                               Linear Address
      8     63    48 47   39 38           30 29       21 20                          0
      9    +--------+-------+---------------+-----------+-----------------------------+
     10                PML4   Directory-Ptr   Directory                 Offset
     11 
     12    Paging-Structures :=
     13                         PML4
     14                         (
     15                           Directory-Ptr Directory {512}
     16                         ) {4}
     17 
     18 Copyright (c) 2006 - 2016, Intel Corporation. All rights reserved.<BR>
     19 This program and the accompanying materials
     20 are licensed and made available under the terms and conditions of the BSD License
     21 which accompanies this distribution.  The full text of the license may be found at
     22 http://opensource.org/licenses/bsd-license.php
     23 
     24 THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
     25 WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
     26 
     27 **/
     28 
     29 #include <stdio.h>
     30 #include <stdlib.h>
     31 #include <string.h>
     32 #include "VirtualMemory.h"
     33 #include "EfiUtilityMsgs.h"
     34 #include "ParseInf.h"
     35 
     36 #define EFI_PAGE_BASE_OFFSET_IN_LDR 0x70000
     37 #define EFI_PAGE_BASE_ADDRESS       (EFI_PAGE_BASE_OFFSET_IN_LDR + 0x20000)
     38 
     39 UINT32 gPageTableBaseAddress  = EFI_PAGE_BASE_ADDRESS;
     40 UINT32 gPageTableOffsetInFile = EFI_PAGE_BASE_OFFSET_IN_LDR;
     41 
     42 #define EFI_MAX_ENTRY_NUM     512
     43 
     44 #define EFI_PML4_ENTRY_NUM    1
     45 #define EFI_PDPTE_ENTRY_NUM   4
     46 #define EFI_PDE_ENTRY_NUM     EFI_MAX_ENTRY_NUM
     47 
     48 #define EFI_PML4_PAGE_NUM     1
     49 #define EFI_PDPTE_PAGE_NUM    EFI_PML4_ENTRY_NUM
     50 #define EFI_PDE_PAGE_NUM      (EFI_PML4_ENTRY_NUM * EFI_PDPTE_ENTRY_NUM)
     51 
     52 #define EFI_PAGE_NUMBER       (EFI_PML4_PAGE_NUM + EFI_PDPTE_PAGE_NUM + EFI_PDE_PAGE_NUM)
     53 
     54 #define EFI_SIZE_OF_PAGE      0x1000
     55 #define EFI_PAGE_SIZE_2M      0x200000
     56 
     57 #define CONVERT_BIN_PAGE_ADDRESS(a)  ((UINT8 *) a - PageTable + gPageTableBaseAddress)
     58 
     59 //
     60 // Utility Name
     61 //
     62 #define UTILITY_NAME  "GenPage"
     63 
     64 //
     65 // Utility version information
     66 //
     67 #define UTILITY_MAJOR_VERSION 0
     68 #define UTILITY_MINOR_VERSION 2
     69 
     70 void
     71 Version (
     72   void
     73   )
     74 /*++
     75 
     76 Routine Description:
     77 
     78   Displays the standard utility information to SDTOUT
     79 
     80 Arguments:
     81 
     82   None
     83 
     84 Returns:
     85 
     86   None
     87 
     88 --*/
     89 {
     90   printf ("%s Version %d.%d %s\n", UTILITY_NAME, UTILITY_MAJOR_VERSION, UTILITY_MINOR_VERSION, __BUILD_VERSION);
     91 }
     92 
     93 VOID
     94 Usage (
     95   void
     96   )
     97 {
     98   printf ("Usage: GenPage.exe [options] EfiLoaderImageName \n\n\
     99 Copyright (c) 2008 - 2014, Intel Corporation.  All rights reserved.\n\n\
    100   Utility to generate the EfiLoader image containing a page table.\n\n\
    101 optional arguments:\n\
    102   -h, --help            Show this help message and exit\n\
    103   --version             Show program's version number and exit\n\
    104   -d [DEBUG], --debug [DEBUG]\n\
    105                         Output DEBUG statements, where DEBUG_LEVEL is 0 (min)\n\
    106                         - 9 (max)\n\
    107   -v, --verbose         Print informational statements\n\
    108   -q, --quiet           Returns the exit code, error messages will be\n\
    109                         displayed\n\
    110   -s, --silent          Returns only the exit code; informational and error\n\
    111                         messages are not displayed\n\
    112   -o OUTPUT_FILENAME, --output OUTPUT_FILENAME\n\
    113                         Output file contain both the non-page table part and\n\
    114                         the page table\n\
    115   -b BASE_ADDRESS, --baseaddr BASE_ADDRESS\n\
    116                         The page table location\n\
    117   -f OFFSET, --offset OFFSET\n\
    118                         The position that the page table will appear in the\n\
    119                         output file\n\
    120   --sfo                 Reserved for future use\n");
    121 
    122 }
    123 
    124 void *
    125 CreateIdentityMappingPageTables (
    126   void
    127   )
    128 /*++
    129 
    130 Routine Description:
    131   To create 4G PAE 2M pagetable
    132 
    133 Return:
    134   void * - buffer containing created pagetable
    135 
    136 --*/
    137 {
    138   UINT64                                        PageAddress;
    139   UINT8                                         *PageTable;
    140   UINT8                                         *PageTablePtr;
    141   int                                           PML4Index;
    142   int                                           PDPTEIndex;
    143   int                                           PDEIndex;
    144   X64_PAGE_MAP_AND_DIRECTORY_POINTER_2MB_4K     *PageMapLevel4Entry;
    145   X64_PAGE_MAP_AND_DIRECTORY_POINTER_2MB_4K     *PageDirectoryPointerEntry;
    146   X64_PAGE_TABLE_ENTRY_2M                       *PageDirectoryEntry2MB;
    147 
    148   PageTable = (void *)malloc (EFI_PAGE_NUMBER * EFI_SIZE_OF_PAGE);
    149   if (PageTable == NULL) {
    150     Error (NULL, 0, 4001, "Resource", "memory cannot be allocated!");
    151     return NULL;
    152   }
    153   memset (PageTable, 0, (EFI_PAGE_NUMBER * EFI_SIZE_OF_PAGE));
    154   PageTablePtr = PageTable;
    155 
    156   PageAddress = 0;
    157 
    158   //
    159   //  Page Table structure 3 level 2MB.
    160   //
    161   //                   Page-Map-Level-4-Table        : bits 47-39
    162   //                   Page-Directory-Pointer-Table  : bits 38-30
    163   //
    164   //  Page Table 2MB : Page-Directory(2M)            : bits 29-21
    165   //
    166   //
    167 
    168   PageMapLevel4Entry = (X64_PAGE_MAP_AND_DIRECTORY_POINTER_2MB_4K *)PageTablePtr;
    169 
    170   for (PML4Index = 0; PML4Index < EFI_PML4_ENTRY_NUM; PML4Index++, PageMapLevel4Entry++) {
    171     //
    172     // Each Page-Map-Level-4-Table Entry points to the base address of a Page-Directory-Pointer-Table Entry
    173     //
    174     PageTablePtr += EFI_SIZE_OF_PAGE;
    175     PageDirectoryPointerEntry = (X64_PAGE_MAP_AND_DIRECTORY_POINTER_2MB_4K *)PageTablePtr;
    176 
    177     //
    178     // Make a Page-Map-Level-4-Table Entry
    179     //
    180     PageMapLevel4Entry->Uint64 = (UINT64)(UINT32)(CONVERT_BIN_PAGE_ADDRESS (PageDirectoryPointerEntry));
    181     PageMapLevel4Entry->Bits.ReadWrite = 1;
    182     PageMapLevel4Entry->Bits.Present = 1;
    183 
    184     for (PDPTEIndex = 0; PDPTEIndex < EFI_PDPTE_ENTRY_NUM; PDPTEIndex++, PageDirectoryPointerEntry++) {
    185       //
    186       // Each Page-Directory-Pointer-Table Entry points to the base address of a Page-Directory Entry
    187       //
    188       PageTablePtr += EFI_SIZE_OF_PAGE;
    189       PageDirectoryEntry2MB = (X64_PAGE_TABLE_ENTRY_2M *)PageTablePtr;
    190 
    191       //
    192       // Make a Page-Directory-Pointer-Table Entry
    193       //
    194       PageDirectoryPointerEntry->Uint64 = (UINT64)(UINT32)(CONVERT_BIN_PAGE_ADDRESS (PageDirectoryEntry2MB));
    195       PageDirectoryPointerEntry->Bits.ReadWrite = 1;
    196       PageDirectoryPointerEntry->Bits.Present = 1;
    197 
    198       for (PDEIndex = 0; PDEIndex < EFI_PDE_ENTRY_NUM; PDEIndex++, PageDirectoryEntry2MB++) {
    199         //
    200         // Make a Page-Directory Entry
    201         //
    202         PageDirectoryEntry2MB->Uint64 = (UINT64)PageAddress;
    203         PageDirectoryEntry2MB->Bits.ReadWrite = 1;
    204         PageDirectoryEntry2MB->Bits.Present = 1;
    205         PageDirectoryEntry2MB->Bits.MustBe1 = 1;
    206 
    207         PageAddress += EFI_PAGE_SIZE_2M;
    208       }
    209     }
    210   }
    211 
    212   return PageTable;
    213 }
    214 
    215 INT32
    216 GenBinPage (
    217   void *BaseMemory,
    218   char *NoPageFileName,
    219   char *PageFileName
    220   )
    221 /*++
    222 
    223 Routine Description:
    224   Write the buffer containing page table to file at a specified offset.
    225   Here the offset is defined as EFI_PAGE_BASE_OFFSET_IN_LDR.
    226 
    227 Arguments:
    228   BaseMemory     - buffer containing page table
    229   NoPageFileName - file to write page table
    230   PageFileName   - file save to after writing
    231 
    232 return:
    233   0  : successful
    234   -1 : failed
    235 
    236 --*/
    237 {
    238   FILE  *PageFile;
    239   FILE  *NoPageFile;
    240   UINT8 Data;
    241   unsigned long FileSize;
    242 
    243   //
    244   // Open files
    245   //
    246   PageFile = fopen (LongFilePath (PageFileName), "w+b");
    247   if (PageFile == NULL) {
    248     Error (NoPageFileName, 0, 0x4002, "Invalid parameter option", "Output File %s open failure", PageFileName);
    249     return -1;
    250   }
    251 
    252   NoPageFile = fopen (LongFilePath (NoPageFileName), "r+b");
    253   if (NoPageFile == NULL) {
    254     Error (NoPageFileName, 0, 0x4002, "Invalid parameter option", "Input File %s open failure", NoPageFileName);
    255     fclose (PageFile);
    256     return -1;
    257   }
    258 
    259   //
    260   // Check size - should not be great than EFI_PAGE_BASE_OFFSET_IN_LDR
    261   //
    262   fseek (NoPageFile, 0, SEEK_END);
    263   FileSize = ftell (NoPageFile);
    264   fseek (NoPageFile, 0, SEEK_SET);
    265   if (FileSize > gPageTableOffsetInFile) {
    266     Error (NoPageFileName, 0, 0x4002, "Invalid parameter option", "Input file size (0x%lx) exceeds the Page Table Offset (0x%x)", FileSize, (unsigned) gPageTableOffsetInFile);
    267     fclose (PageFile);
    268     fclose (NoPageFile);
    269     return -1;
    270   }
    271 
    272   //
    273   // Write data
    274   //
    275   while (fread (&Data, sizeof(UINT8), 1, NoPageFile)) {
    276     fwrite (&Data, sizeof(UINT8), 1, PageFile);
    277   }
    278 
    279   //
    280   // Write PageTable
    281   //
    282   fseek (PageFile, gPageTableOffsetInFile, SEEK_SET);
    283   fwrite (BaseMemory, (EFI_PAGE_NUMBER * EFI_SIZE_OF_PAGE), 1, PageFile);
    284 
    285   //
    286   // Close files
    287   //
    288   fclose (PageFile);
    289   fclose (NoPageFile);
    290 
    291   return 0;
    292 }
    293 
    294 int
    295 main (
    296   int argc,
    297   char **argv
    298   )
    299 {
    300   VOID        *BaseMemory;
    301   INTN        result;
    302   CHAR8       *OutputFile = NULL;
    303   CHAR8       *InputFile = NULL;
    304   EFI_STATUS  Status;
    305   UINT64      TempValue;
    306 
    307   SetUtilityName("GenPage");
    308 
    309   if (argc == 1) {
    310     Usage();
    311     return STATUS_ERROR;
    312   }
    313 
    314   argc --;
    315   argv ++;
    316 
    317   if ((stricmp (argv[0], "-h") == 0) || (stricmp (argv[0], "--help") == 0)) {
    318     Usage();
    319     return 0;
    320   }
    321 
    322   if (stricmp (argv[0], "--version") == 0) {
    323     Version();
    324     return 0;
    325   }
    326 
    327   while (argc > 0) {
    328     if ((stricmp (argv[0], "-o") == 0) || (stricmp (argv[0], "--output") == 0)) {
    329       if (argv[1] == NULL || argv[1][0] == '-') {
    330         Error (NULL, 0, 1003, "Invalid option value", "Output file is missing for -o option");
    331         return STATUS_ERROR;
    332       }
    333       OutputFile = argv[1];
    334       argc -= 2;
    335       argv += 2;
    336       continue;
    337     }
    338 
    339     if ((stricmp (argv[0], "-b") == 0) || (stricmp (argv[0], "--baseaddr") == 0)) {
    340       if (argv[1] == NULL || argv[1][0] == '-') {
    341         Error (NULL, 0, 1003, "Invalid option value", "Base address is missing for -b option");
    342         return STATUS_ERROR;
    343       }
    344       Status = AsciiStringToUint64 (argv[1], FALSE, &TempValue);
    345       if (EFI_ERROR (Status)) {
    346         Error (NULL, 0, 1003, "Invalid option value", "Base address is not valid intergrator");
    347         return STATUS_ERROR;
    348       }
    349       gPageTableBaseAddress = (UINT32) TempValue;
    350       argc -= 2;
    351       argv += 2;
    352       continue;
    353     }
    354 
    355     if ((stricmp (argv[0], "-f") == 0) || (stricmp (argv[0], "--offset") == 0)) {
    356       if (argv[1] == NULL || argv[1][0] == '-') {
    357         Error (NULL, 0, 1003, "Invalid option value", "Offset is missing for -f option");
    358         return STATUS_ERROR;
    359       }
    360       Status = AsciiStringToUint64 (argv[1], FALSE, &TempValue);
    361       if (EFI_ERROR (Status)) {
    362         Error (NULL, 0, 1003, "Invalid option value", "Offset is not valid intergrator");
    363         return STATUS_ERROR;
    364       }
    365       gPageTableOffsetInFile = (UINT32) TempValue;
    366       argc -= 2;
    367       argv += 2;
    368       continue;
    369     }
    370 
    371     if ((stricmp (argv[0], "-q") == 0) || (stricmp (argv[0], "--quiet") == 0)) {
    372       argc --;
    373       argv ++;
    374       continue;
    375     }
    376 
    377     if ((stricmp (argv[0], "-v") ==0) || (stricmp (argv[0], "--verbose") == 0)) {
    378       argc --;
    379       argv ++;
    380       continue;
    381     }
    382 
    383     if ((stricmp (argv[0], "-d") == 0) || (stricmp (argv[0], "--debug") == 0)) {
    384       if (argv[1] == NULL || argv[1][0] == '-') {
    385         Error (NULL, 0, 1003, "Invalid option value", "Debug Level is not specified.");
    386         return STATUS_ERROR;
    387       }
    388       Status = AsciiStringToUint64 (argv[1], FALSE, &TempValue);
    389       if (EFI_ERROR (Status)) {
    390         Error (NULL, 0, 1003, "Invalid option value", "Debug Level is not valid intergrator.");
    391         return STATUS_ERROR;
    392       }
    393       if (TempValue > 9) {
    394         Error (NULL, 0, 1003, "Invalid option value", "Debug Level range is 0-9, currnt input level is %d", (int) TempValue);
    395         return STATUS_ERROR;
    396       }
    397       argc -= 2;
    398       argv += 2;
    399       continue;
    400     }
    401 
    402     if (argv[0][0] == '-') {
    403       Error (NULL, 0, 1000, "Unknown option", argv[0]);
    404       return STATUS_ERROR;
    405     }
    406 
    407     //
    408     // Don't recognize the parameter.
    409     //
    410     InputFile = argv[0];
    411     argc--;
    412     argv++;
    413   }
    414 
    415   if (InputFile == NULL) {
    416     Error (NULL, 0, 1003, "Invalid option value", "Input file is not specified");
    417     return STATUS_ERROR;
    418   }
    419 
    420   //
    421   // Create X64 page table
    422   //
    423   BaseMemory = CreateIdentityMappingPageTables ();
    424   if (BaseMemory == NULL) {
    425     Error (NULL, 0, 4001, "Resource", "memory cannot be allocated!");
    426     return STATUS_ERROR;
    427   }
    428 
    429   //
    430   // Add page table to binary file
    431   //
    432   result = GenBinPage (BaseMemory, InputFile, OutputFile);
    433   if (result < 0) {
    434     free (BaseMemory);
    435     return STATUS_ERROR;
    436   }
    437 
    438   free (BaseMemory);
    439   return 0;
    440 }
    441 
    442