mirror of
				https://github.com/acidanthera/audk.git
				synced 2025-11-03 21:17:23 +01:00 
			
		
		
		
	Cc: Liming Gao <liming.gao@intel.com> Cc: Yonghong Zhu <yonghong.zhu@intel.com> Contributed-under: TianoCore Contribution Agreement 1.0 Signed-off-by: Hao Wu <hao.a.wu@intel.com> Reviewed-by: Liming Gao <liming.gao@intel.com>
		
			
				
	
	
		
			442 lines
		
	
	
		
			13 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
			
		
		
	
	
			442 lines
		
	
	
		
			13 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
/** @file
 | 
						|
  Pre-Create a 4G page table (2M pages).
 | 
						|
  It's used in DUET x64 build needed to enter LongMode.
 | 
						|
 
 | 
						|
  Create 4G page table (2M pages)
 | 
						|
 
 | 
						|
                              Linear Address
 | 
						|
    63    48 47   39 38           30 29       21 20                          0
 | 
						|
   +--------+-------+---------------+-----------+-----------------------------+
 | 
						|
               PML4   Directory-Ptr   Directory                 Offset
 | 
						|
 | 
						|
   Paging-Structures :=
 | 
						|
                        PML4
 | 
						|
                        (
 | 
						|
                          Directory-Ptr Directory {512}
 | 
						|
                        ) {4}
 | 
						|
 | 
						|
Copyright (c) 2006 - 2016, Intel Corporation. All rights reserved.<BR>
 | 
						|
This program and the accompanying materials                          
 | 
						|
are licensed and made available under the terms and conditions of the BSD License         
 | 
						|
which accompanies this distribution.  The full text of the license may be found at        
 | 
						|
http://opensource.org/licenses/bsd-license.php                                            
 | 
						|
                                                                                          
 | 
						|
THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,                     
 | 
						|
WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.             
 | 
						|
 | 
						|
**/
 | 
						|
 | 
						|
#include <stdio.h>
 | 
						|
#include <stdlib.h>
 | 
						|
#include <string.h>
 | 
						|
#include "VirtualMemory.h"
 | 
						|
#include "EfiUtilityMsgs.h"
 | 
						|
#include "ParseInf.h"
 | 
						|
 | 
						|
#define EFI_PAGE_BASE_OFFSET_IN_LDR 0x70000
 | 
						|
#define EFI_PAGE_BASE_ADDRESS       (EFI_PAGE_BASE_OFFSET_IN_LDR + 0x20000)
 | 
						|
 | 
						|
UINT32 gPageTableBaseAddress  = EFI_PAGE_BASE_ADDRESS;
 | 
						|
UINT32 gPageTableOffsetInFile = EFI_PAGE_BASE_OFFSET_IN_LDR;
 | 
						|
 | 
						|
#define EFI_MAX_ENTRY_NUM     512
 | 
						|
 | 
						|
#define EFI_PML4_ENTRY_NUM    1
 | 
						|
#define EFI_PDPTE_ENTRY_NUM   4
 | 
						|
#define EFI_PDE_ENTRY_NUM     EFI_MAX_ENTRY_NUM
 | 
						|
 | 
						|
#define EFI_PML4_PAGE_NUM     1
 | 
						|
#define EFI_PDPTE_PAGE_NUM    EFI_PML4_ENTRY_NUM
 | 
						|
#define EFI_PDE_PAGE_NUM      (EFI_PML4_ENTRY_NUM * EFI_PDPTE_ENTRY_NUM)
 | 
						|
 | 
						|
#define EFI_PAGE_NUMBER       (EFI_PML4_PAGE_NUM + EFI_PDPTE_PAGE_NUM + EFI_PDE_PAGE_NUM)
 | 
						|
 | 
						|
#define EFI_SIZE_OF_PAGE      0x1000
 | 
						|
#define EFI_PAGE_SIZE_2M      0x200000
 | 
						|
 | 
						|
#define CONVERT_BIN_PAGE_ADDRESS(a)  ((UINT8 *) a - PageTable + gPageTableBaseAddress)
 | 
						|
 | 
						|
//
 | 
						|
// Utility Name
 | 
						|
//
 | 
						|
#define UTILITY_NAME  "GenPage"
 | 
						|
 | 
						|
//
 | 
						|
// Utility version information
 | 
						|
//
 | 
						|
#define UTILITY_MAJOR_VERSION 0
 | 
						|
#define UTILITY_MINOR_VERSION 2
 | 
						|
 | 
						|
void
 | 
						|
Version (
 | 
						|
  void
 | 
						|
  )
 | 
						|
/*++
 | 
						|
 | 
						|
Routine Description:
 | 
						|
 | 
						|
  Displays the standard utility information to SDTOUT
 | 
						|
 | 
						|
Arguments:
 | 
						|
 | 
						|
  None
 | 
						|
 | 
						|
Returns:
 | 
						|
 | 
						|
  None
 | 
						|
 | 
						|
--*/
 | 
						|
{
 | 
						|
  printf ("%s Version %d.%d %s\n", UTILITY_NAME, UTILITY_MAJOR_VERSION, UTILITY_MINOR_VERSION, __BUILD_VERSION);
 | 
						|
}
 | 
						|
 | 
						|
VOID
 | 
						|
Usage (
 | 
						|
  void
 | 
						|
  )
 | 
						|
{
 | 
						|
  printf ("Usage: GenPage.exe [options] EfiLoaderImageName \n\n\
 | 
						|
Copyright (c) 2008 - 2014, Intel Corporation.  All rights reserved.\n\n\
 | 
						|
  Utility to generate the EfiLoader image containing a page table.\n\n\
 | 
						|
optional arguments:\n\
 | 
						|
  -h, --help            Show this help message and exit\n\
 | 
						|
  --version             Show program's version number and exit\n\
 | 
						|
  -d [DEBUG], --debug [DEBUG]\n\
 | 
						|
                        Output DEBUG statements, where DEBUG_LEVEL is 0 (min)\n\
 | 
						|
                        - 9 (max)\n\
 | 
						|
  -v, --verbose         Print informational statements\n\
 | 
						|
  -q, --quiet           Returns the exit code, error messages will be\n\
 | 
						|
                        displayed\n\
 | 
						|
  -s, --silent          Returns only the exit code; informational and error\n\
 | 
						|
                        messages are not displayed\n\
 | 
						|
  -o OUTPUT_FILENAME, --output OUTPUT_FILENAME\n\
 | 
						|
                        Output file contain both the non-page table part and\n\
 | 
						|
                        the page table\n\
 | 
						|
  -b BASE_ADDRESS, --baseaddr BASE_ADDRESS\n\
 | 
						|
                        The page table location\n\
 | 
						|
  -f OFFSET, --offset OFFSET\n\
 | 
						|
                        The position that the page table will appear in the\n\
 | 
						|
                        output file\n\
 | 
						|
  --sfo                 Reserved for future use\n");
 | 
						|
 | 
						|
}
 | 
						|
 | 
						|
void *
 | 
						|
CreateIdentityMappingPageTables (
 | 
						|
  void
 | 
						|
  )
 | 
						|
/*++
 | 
						|
 | 
						|
Routine Description:
 | 
						|
  To create 4G PAE 2M pagetable
 | 
						|
 | 
						|
Return:
 | 
						|
  void * - buffer containing created pagetable
 | 
						|
 | 
						|
--*/
 | 
						|
{
 | 
						|
  UINT64                                        PageAddress;
 | 
						|
  UINT8                                         *PageTable;
 | 
						|
  UINT8                                         *PageTablePtr;
 | 
						|
  int                                           PML4Index;
 | 
						|
  int                                           PDPTEIndex;
 | 
						|
  int                                           PDEIndex;
 | 
						|
  X64_PAGE_MAP_AND_DIRECTORY_POINTER_2MB_4K     *PageMapLevel4Entry;
 | 
						|
  X64_PAGE_MAP_AND_DIRECTORY_POINTER_2MB_4K     *PageDirectoryPointerEntry;
 | 
						|
  X64_PAGE_TABLE_ENTRY_2M                       *PageDirectoryEntry2MB;
 | 
						|
 | 
						|
  PageTable = (void *)malloc (EFI_PAGE_NUMBER * EFI_SIZE_OF_PAGE);
 | 
						|
  if (PageTable == NULL) {
 | 
						|
    Error (NULL, 0, 4001, "Resource", "memory cannot be allocated!");
 | 
						|
    return NULL;
 | 
						|
  }
 | 
						|
  memset (PageTable, 0, (EFI_PAGE_NUMBER * EFI_SIZE_OF_PAGE));
 | 
						|
  PageTablePtr = PageTable;
 | 
						|
 | 
						|
  PageAddress = 0;
 | 
						|
 | 
						|
  //
 | 
						|
  //  Page Table structure 3 level 2MB.
 | 
						|
  //
 | 
						|
  //                   Page-Map-Level-4-Table        : bits 47-39
 | 
						|
  //                   Page-Directory-Pointer-Table  : bits 38-30
 | 
						|
  //
 | 
						|
  //  Page Table 2MB : Page-Directory(2M)            : bits 29-21
 | 
						|
  //
 | 
						|
  //
 | 
						|
 | 
						|
  PageMapLevel4Entry = (X64_PAGE_MAP_AND_DIRECTORY_POINTER_2MB_4K *)PageTablePtr;
 | 
						|
 | 
						|
  for (PML4Index = 0; PML4Index < EFI_PML4_ENTRY_NUM; PML4Index++, PageMapLevel4Entry++) {
 | 
						|
    //
 | 
						|
    // Each Page-Map-Level-4-Table Entry points to the base address of a Page-Directory-Pointer-Table Entry
 | 
						|
    //  
 | 
						|
    PageTablePtr += EFI_SIZE_OF_PAGE;
 | 
						|
    PageDirectoryPointerEntry = (X64_PAGE_MAP_AND_DIRECTORY_POINTER_2MB_4K *)PageTablePtr;
 | 
						|
 | 
						|
    //
 | 
						|
    // Make a Page-Map-Level-4-Table Entry
 | 
						|
    //
 | 
						|
    PageMapLevel4Entry->Uint64 = (UINT64)(UINT32)(CONVERT_BIN_PAGE_ADDRESS (PageDirectoryPointerEntry));
 | 
						|
    PageMapLevel4Entry->Bits.ReadWrite = 1;
 | 
						|
    PageMapLevel4Entry->Bits.Present = 1;
 | 
						|
 | 
						|
    for (PDPTEIndex = 0; PDPTEIndex < EFI_PDPTE_ENTRY_NUM; PDPTEIndex++, PageDirectoryPointerEntry++) {
 | 
						|
      //
 | 
						|
      // Each Page-Directory-Pointer-Table Entry points to the base address of a Page-Directory Entry
 | 
						|
      //       
 | 
						|
      PageTablePtr += EFI_SIZE_OF_PAGE;
 | 
						|
      PageDirectoryEntry2MB = (X64_PAGE_TABLE_ENTRY_2M *)PageTablePtr;
 | 
						|
 | 
						|
      //
 | 
						|
      // Make a Page-Directory-Pointer-Table Entry
 | 
						|
      //
 | 
						|
      PageDirectoryPointerEntry->Uint64 = (UINT64)(UINT32)(CONVERT_BIN_PAGE_ADDRESS (PageDirectoryEntry2MB));
 | 
						|
      PageDirectoryPointerEntry->Bits.ReadWrite = 1;
 | 
						|
      PageDirectoryPointerEntry->Bits.Present = 1;
 | 
						|
 | 
						|
      for (PDEIndex = 0; PDEIndex < EFI_PDE_ENTRY_NUM; PDEIndex++, PageDirectoryEntry2MB++) {
 | 
						|
        //
 | 
						|
        // Make a Page-Directory Entry
 | 
						|
        //
 | 
						|
        PageDirectoryEntry2MB->Uint64 = (UINT64)PageAddress;
 | 
						|
        PageDirectoryEntry2MB->Bits.ReadWrite = 1;
 | 
						|
        PageDirectoryEntry2MB->Bits.Present = 1;
 | 
						|
        PageDirectoryEntry2MB->Bits.MustBe1 = 1;
 | 
						|
 | 
						|
        PageAddress += EFI_PAGE_SIZE_2M;
 | 
						|
      }
 | 
						|
    }
 | 
						|
  }
 | 
						|
 | 
						|
  return PageTable;
 | 
						|
}
 | 
						|
 | 
						|
INT32
 | 
						|
GenBinPage (
 | 
						|
  void *BaseMemory,
 | 
						|
  char *NoPageFileName,
 | 
						|
  char *PageFileName
 | 
						|
  )
 | 
						|
/*++
 | 
						|
 | 
						|
Routine Description:
 | 
						|
  Write the buffer containing page table to file at a specified offset.
 | 
						|
  Here the offset is defined as EFI_PAGE_BASE_OFFSET_IN_LDR.
 | 
						|
 | 
						|
Arguments:
 | 
						|
  BaseMemory     - buffer containing page table
 | 
						|
  NoPageFileName - file to write page table
 | 
						|
  PageFileName   - file save to after writing
 | 
						|
 | 
						|
return:
 | 
						|
  0  : successful
 | 
						|
  -1 : failed
 | 
						|
 | 
						|
--*/
 | 
						|
{
 | 
						|
  FILE  *PageFile;
 | 
						|
  FILE  *NoPageFile;
 | 
						|
  UINT8 Data;
 | 
						|
  unsigned long FileSize;
 | 
						|
 | 
						|
  //
 | 
						|
  // Open files
 | 
						|
  //
 | 
						|
  PageFile = fopen (LongFilePath (PageFileName), "w+b");
 | 
						|
  if (PageFile == NULL) {
 | 
						|
    Error (NoPageFileName, 0, 0x4002, "Invalid parameter option", "Output File %s open failure", PageFileName);
 | 
						|
    return -1;
 | 
						|
  }
 | 
						|
 | 
						|
  NoPageFile = fopen (LongFilePath (NoPageFileName), "r+b");
 | 
						|
  if (NoPageFile == NULL) {
 | 
						|
    Error (NoPageFileName, 0, 0x4002, "Invalid parameter option", "Input File %s open failure", NoPageFileName);
 | 
						|
    fclose (PageFile);
 | 
						|
    return -1;
 | 
						|
  }
 | 
						|
 | 
						|
  //
 | 
						|
  // Check size - should not be great than EFI_PAGE_BASE_OFFSET_IN_LDR
 | 
						|
  //
 | 
						|
  fseek (NoPageFile, 0, SEEK_END);
 | 
						|
  FileSize = ftell (NoPageFile);
 | 
						|
  fseek (NoPageFile, 0, SEEK_SET);
 | 
						|
  if (FileSize > gPageTableOffsetInFile) {
 | 
						|
    Error (NoPageFileName, 0, 0x4002, "Invalid parameter option", "Input file size (0x%lx) exceeds the Page Table Offset (0x%x)", FileSize, (unsigned) gPageTableOffsetInFile);
 | 
						|
    fclose (PageFile);
 | 
						|
    fclose (NoPageFile);
 | 
						|
    return -1;
 | 
						|
  }
 | 
						|
 | 
						|
  //
 | 
						|
  // Write data
 | 
						|
  //
 | 
						|
  while (fread (&Data, sizeof(UINT8), 1, NoPageFile)) {
 | 
						|
    fwrite (&Data, sizeof(UINT8), 1, PageFile);
 | 
						|
  }
 | 
						|
 | 
						|
  //
 | 
						|
  // Write PageTable
 | 
						|
  //
 | 
						|
  fseek (PageFile, gPageTableOffsetInFile, SEEK_SET);
 | 
						|
  fwrite (BaseMemory, (EFI_PAGE_NUMBER * EFI_SIZE_OF_PAGE), 1, PageFile);
 | 
						|
 | 
						|
  //
 | 
						|
  // Close files
 | 
						|
  //
 | 
						|
  fclose (PageFile);
 | 
						|
  fclose (NoPageFile);
 | 
						|
 | 
						|
  return 0;
 | 
						|
}
 | 
						|
 | 
						|
int
 | 
						|
main (
 | 
						|
  int argc,
 | 
						|
  char **argv
 | 
						|
  )
 | 
						|
{
 | 
						|
  VOID        *BaseMemory;
 | 
						|
  INTN        result;
 | 
						|
  CHAR8       *OutputFile = NULL;
 | 
						|
  CHAR8       *InputFile = NULL;
 | 
						|
  EFI_STATUS  Status;
 | 
						|
  UINT64      TempValue;
 | 
						|
 | 
						|
  SetUtilityName("GenPage");
 | 
						|
 | 
						|
  if (argc == 1) {
 | 
						|
    Usage();
 | 
						|
    return STATUS_ERROR;
 | 
						|
  }
 | 
						|
  
 | 
						|
  argc --;
 | 
						|
  argv ++;
 | 
						|
 | 
						|
  if ((stricmp (argv[0], "-h") == 0) || (stricmp (argv[0], "--help") == 0)) {
 | 
						|
    Usage();
 | 
						|
    return 0;    
 | 
						|
  }
 | 
						|
 | 
						|
  if (stricmp (argv[0], "--version") == 0) {
 | 
						|
    Version();
 | 
						|
    return 0;    
 | 
						|
  }
 | 
						|
  
 | 
						|
  while (argc > 0) {
 | 
						|
    if ((stricmp (argv[0], "-o") == 0) || (stricmp (argv[0], "--output") == 0)) {
 | 
						|
      if (argv[1] == NULL || argv[1][0] == '-') {
 | 
						|
        Error (NULL, 0, 1003, "Invalid option value", "Output file is missing for -o option");
 | 
						|
        return STATUS_ERROR;
 | 
						|
      }
 | 
						|
      OutputFile = argv[1];
 | 
						|
      argc -= 2;
 | 
						|
      argv += 2;
 | 
						|
      continue; 
 | 
						|
    }
 | 
						|
    
 | 
						|
    if ((stricmp (argv[0], "-b") == 0) || (stricmp (argv[0], "--baseaddr") == 0)) {
 | 
						|
      if (argv[1] == NULL || argv[1][0] == '-') {
 | 
						|
        Error (NULL, 0, 1003, "Invalid option value", "Base address is missing for -b option");
 | 
						|
        return STATUS_ERROR;
 | 
						|
      }
 | 
						|
      Status = AsciiStringToUint64 (argv[1], FALSE, &TempValue);
 | 
						|
      if (EFI_ERROR (Status)) {
 | 
						|
        Error (NULL, 0, 1003, "Invalid option value", "Base address is not valid intergrator");
 | 
						|
        return STATUS_ERROR;
 | 
						|
      }
 | 
						|
      gPageTableBaseAddress = (UINT32) TempValue;
 | 
						|
      argc -= 2;
 | 
						|
      argv += 2;
 | 
						|
      continue; 
 | 
						|
    }
 | 
						|
    
 | 
						|
    if ((stricmp (argv[0], "-f") == 0) || (stricmp (argv[0], "--offset") == 0)) {
 | 
						|
      if (argv[1] == NULL || argv[1][0] == '-') {
 | 
						|
        Error (NULL, 0, 1003, "Invalid option value", "Offset is missing for -f option");
 | 
						|
        return STATUS_ERROR;
 | 
						|
      }
 | 
						|
      Status = AsciiStringToUint64 (argv[1], FALSE, &TempValue);
 | 
						|
      if (EFI_ERROR (Status)) {
 | 
						|
        Error (NULL, 0, 1003, "Invalid option value", "Offset is not valid intergrator");
 | 
						|
        return STATUS_ERROR;
 | 
						|
      }
 | 
						|
      gPageTableOffsetInFile = (UINT32) TempValue;
 | 
						|
      argc -= 2;
 | 
						|
      argv += 2;
 | 
						|
      continue; 
 | 
						|
    }
 | 
						|
 | 
						|
    if ((stricmp (argv[0], "-q") == 0) || (stricmp (argv[0], "--quiet") == 0)) {
 | 
						|
      argc --;
 | 
						|
      argv ++;
 | 
						|
      continue; 
 | 
						|
    }
 | 
						|
    
 | 
						|
    if ((stricmp (argv[0], "-v") ==0) || (stricmp (argv[0], "--verbose") == 0)) {
 | 
						|
      argc --;
 | 
						|
      argv ++;
 | 
						|
      continue; 
 | 
						|
    }
 | 
						|
    
 | 
						|
    if ((stricmp (argv[0], "-d") == 0) || (stricmp (argv[0], "--debug") == 0)) {
 | 
						|
      if (argv[1] == NULL || argv[1][0] == '-') {
 | 
						|
        Error (NULL, 0, 1003, "Invalid option value", "Debug Level is not specified.");
 | 
						|
        return STATUS_ERROR;
 | 
						|
      }
 | 
						|
      Status = AsciiStringToUint64 (argv[1], FALSE, &TempValue);
 | 
						|
      if (EFI_ERROR (Status)) {
 | 
						|
        Error (NULL, 0, 1003, "Invalid option value", "Debug Level is not valid intergrator.");
 | 
						|
        return STATUS_ERROR;
 | 
						|
      }
 | 
						|
      if (TempValue > 9) {
 | 
						|
        Error (NULL, 0, 1003, "Invalid option value", "Debug Level range is 0-9, currnt input level is %d", (int) TempValue);
 | 
						|
        return STATUS_ERROR;
 | 
						|
      }
 | 
						|
      argc -= 2;
 | 
						|
      argv += 2;
 | 
						|
      continue; 
 | 
						|
    }
 | 
						|
 | 
						|
    if (argv[0][0] == '-') {
 | 
						|
      Error (NULL, 0, 1000, "Unknown option", argv[0]);
 | 
						|
      return STATUS_ERROR;
 | 
						|
    }
 | 
						|
    
 | 
						|
    //
 | 
						|
    // Don't recognize the parameter.
 | 
						|
    //
 | 
						|
    InputFile = argv[0];
 | 
						|
    argc--;
 | 
						|
    argv++;
 | 
						|
  }
 | 
						|
  
 | 
						|
  if (InputFile == NULL) {
 | 
						|
    Error (NULL, 0, 1003, "Invalid option value", "Input file is not specified");
 | 
						|
    return STATUS_ERROR;
 | 
						|
  }
 | 
						|
  
 | 
						|
  //
 | 
						|
  // Create X64 page table
 | 
						|
  //
 | 
						|
  BaseMemory = CreateIdentityMappingPageTables ();
 | 
						|
  if (BaseMemory == NULL) {
 | 
						|
    Error (NULL, 0, 4001, "Resource", "memory cannot be allocated!");
 | 
						|
    return STATUS_ERROR;
 | 
						|
  }
 | 
						|
 | 
						|
  //
 | 
						|
  // Add page table to binary file
 | 
						|
  //
 | 
						|
  result = GenBinPage (BaseMemory, InputFile, OutputFile);
 | 
						|
  if (result < 0) {
 | 
						|
    free (BaseMemory);
 | 
						|
    return STATUS_ERROR;
 | 
						|
  }
 | 
						|
 | 
						|
  free (BaseMemory);
 | 
						|
  return 0;
 | 
						|
}
 | 
						|
 |