Files
slimbootloader/BootloaderCommonPkg/Library/PagingLib/PagingLib.c
T
Aiden Park 9193a72864 Support booting to 64-bit kernel entry point (#550)
This will allow OsLoader payload to boot to 64-bit kernel entry point.
If CPU supports 64-bit mode and a kernel image has 64-bit entry point,
OsLoader will switch to 64-bit long mode and jump to the 64-bit entry
point. Otherwise, continue to boot to 32-bit entry point.
- Ported necessary code from EDK2 VitualMemory.c in MdeModulePkg
- Moved PagingLib from BootloaderCorePkg to BootloaderCommonPkg
- Removed unused FlushCacheLine
- TBD: 64-bit IDT

Next step is to support 64-bit Payload.
- 32-bit compatible mode
- 64-bit CryptoLib
- etc.

Signed-off-by: Aiden Park <aiden.park@intel.com>
2020-02-04 10:44:45 -08:00

170 lines
6.1 KiB
C

/** @file
Copyright (c) 2017, Intel Corporation. All rights reserved.<BR>
SPDX-License-Identifier: BSD-2-Clause-Patent
**/
#include <Base.h>
#include <Library/DebugLib.h>
#include <Library/PagingLib.h>
//
// Page Table Entry 4KB
//
typedef union {
struct {
UINT32 Present: 1; // 0 = Not present in memory, 1 = Present in memory
UINT32 ReadWrite: 1; // 0 = Read-Only, 1= Read/Write
UINT32 UserSupervisor: 1; // 0 = Supervisor, 1=User
UINT32 WriteThrough: 1; // 0 = Write-Back caching, 1=Write-Through caching
UINT32 CacheDisabled: 1; // 0 = Cached, 1=Non-Cached
UINT32 Accessed: 1; // 0 = Not accessed, 1 = Accessed (set by CPU)
UINT32 Dirty: 1; // 0 = Not Dirty, 1 = written by processor on access to page
UINT32 Pat: 1; //
UINT32 Global: 1; // 0 = Not global page, 1 = global page TLB not cleared on CR3 write
UINT32 Available: 3; // Available for use by system software
UINT32 PageTableBaseAddress: 20; // Page frame address
} Bits;
UINT32 Uint32;
} PAGE_TABLE_ENTRY_4K;
//
// Page Table Entry 4MB
//
typedef union {
struct {
UINT32 Present: 1; // 0 = Not present in memory, 1 = Present in memory
UINT32 ReadWrite: 1; // 0 = Read-Only, 1= Read/Write
UINT32 UserSupervisor: 1; // 0 = Supervisor, 1=User
UINT32 WriteThrough: 1; // 0 = Write-Back caching, 1=Write-Through caching
UINT32 CacheDisabled: 1; // 0 = Cached, 1=Non-Cached
UINT32 Accessed: 1; // 0 = Not accessed, 1 = Accessed (set by CPU)
UINT32 Dirty: 1; // 0 = Not Dirty, 1 = written by processor on access to page
UINT32 MustBeOne: 1; // Must Be One
UINT32 Global: 1; // 0 = Not global page, 1 = global page TLB not cleared on CR3 write
UINT32 Available: 3; // Available for use by system software
UINT32 Pat: 1; //
UINT32 Reserved: 9; //
UINT32 PageTableBaseAddress: 10; // Page frame address
} Bits;
UINT32 Uint32;
} PAGE_TABLE_ENTRY_4M;
//
// Page Directory Entry 4MB
//
typedef union {
struct {
UINT32 Present: 1; // 0 = Not present in memory, 1 = Present in memory
UINT32 ReadWrite: 1; // 0 = Read-Only, 1= Read/Write
UINT32 UserSupervisor: 1; // 0 = Supervisor, 1=User
UINT32 WriteThrough: 1; // 0 = Write-Back caching, 1=Write-Through caching
UINT32 CacheDisabled: 1; // 0 = Cached, 1=Non-Cached
UINT32 Accessed: 1; // 0 = Not accessed, 1 = Accessed (set by CPU)
UINT32 Reserved: 1; // Reserved
UINT32 MustBeZero: 1; // Must Be Zero
UINT32 Available: 4; // Available for use by system software
UINT32 PageTableBaseAddress: 20; // Page Table Base Address
} Bits;
UINT32 Uint32;
} PAGE_DIRECTORY_ENTRY_4MB;
/**
Allocates and fills in the Page Directory and Page Table Entries to
establish a 1:1 Virtual to Physical mapping.
@param [in] Ranges
@param [in] PageTableMem
@retval The address of 4 level page map.
**/
UINT32
EFIAPI
Create4GbPageTablesAndRemapRange (
IN RANGE Ranges[1],
IN VOID *PageTableMem
)
{
UINTN IndexOfPageTableEntries;
PAGE_TABLE_ENTRY_4M *PageTableEntry;
PAGE_TABLE_ENTRY_4M *PageTableEntry4M;
PAGE_TABLE_ENTRY_4K *PageTableEntry4K;
PAGE_DIRECTORY_ENTRY_4MB *PageDirectoryEntry4M;
UINT32 PhysicalAddress4M;
UINT32 PhysicalAddress4K;
UINT32 BasePage4M;
//
// Define CAR region and memory mapping
//
BasePage4M = Ranges[0].Start & ~0x3FFFFF;
ASSERT ((Ranges[0].Start & 0xFFF) == 0);
ASSERT ((Ranges[0].Limit & 0xFFF) == 0xFFF);
ASSERT ((Ranges[0].Start & ~0x3FFFFF) == BasePage4M);
ASSERT ((Ranges[0].Limit & ~0x3FFFFF) == BasePage4M);
ASSERT (PageTableMem != 0);
PageTableEntry = (PAGE_TABLE_ENTRY_4M *)PageTableMem;
//
// Create 4MB pages from 0 to 4GB
//
PhysicalAddress4M = 0;
PageTableEntry4M = (PAGE_TABLE_ENTRY_4M *)PageTableEntry;
for (IndexOfPageTableEntries = 0; IndexOfPageTableEntries < 1024;
IndexOfPageTableEntries++, PageTableEntry4M++, PhysicalAddress4M += SIZE_4MB) {
//
// Fill in the Page Table entries
//
PageTableEntry4M->Uint32 = PhysicalAddress4M;
PageTableEntry4M->Bits.ReadWrite = 1;
PageTableEntry4M->Bits.Present = 1;
PageTableEntry4M->Bits.MustBeOne = 1;
}
//
// Split the 4MB page containing the CAR region into 4KB pages
//
PageTableEntry4K = (PAGE_TABLE_ENTRY_4K *)&PageTableEntry[1024];
PageDirectoryEntry4M = (PAGE_DIRECTORY_ENTRY_4MB *)&PageTableEntry[BasePage4M >> 22];
PageDirectoryEntry4M->Uint32 = (UINT32) (UINTN)PageTableEntry4K;
PageDirectoryEntry4M->Bits.ReadWrite = 1;
PageDirectoryEntry4M->Bits.Present = 1;
//
// Create 4KB pages and remap the CAR region into a different memory location
//
PhysicalAddress4K = BasePage4M & ~0x3FFFFF;
for (IndexOfPageTableEntries = 0; IndexOfPageTableEntries < 1024;
IndexOfPageTableEntries++, PageTableEntry4K++, PhysicalAddress4K += SIZE_4KB) {
//
// Fill in the Page Table entries
//
if ((PhysicalAddress4K >= Ranges[0].Start) && (PhysicalAddress4K <= Ranges[0].Limit)) {
PageTableEntry4K->Uint32 = Ranges[0].Mapping;
Ranges[0].Mapping += SIZE_4KB;
} else {
PageTableEntry4K->Uint32 = PhysicalAddress4K;
}
PageTableEntry4K->Bits.ReadWrite = 1;
PageTableEntry4K->Bits.Present = 1;
}
return (UINT32) (UINTN)PageTableEntry;
}
/**
This function returns page tables memory size (2 * SIZE_4KB).
**/
UINT32
EFIAPI
GetPageTablesMemorySize (
VOID
)
{
return 2 * SIZE_4KB;
}