mirror of https://github.com/acidanthera/audk.git
239 lines
7.3 KiB
C
239 lines
7.3 KiB
C
/** @file
|
|
|
|
Copyright (c) 2006 - 2007, Intel Corporation
|
|
All rights reserved. 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.
|
|
|
|
Module Name:
|
|
Paging.c
|
|
|
|
Abstract:
|
|
|
|
Revision History:
|
|
|
|
**/
|
|
|
|
#include "HobGeneration.h"
|
|
#include "VirtualMemory.h"
|
|
|
|
//
|
|
// Create 2M-page table
|
|
// PML4 (47:39)
|
|
// PDPTE (38:30)
|
|
// PDE (29:21)
|
|
//
|
|
|
|
#define EFI_2M_PAGE_BITS_NUM 21
|
|
#define EFI_MAX_ENTRY_BITS_NUM 9
|
|
|
|
#define EFI_PAGE_SIZE_4K 0x1000
|
|
#define EFI_PAGE_SIZE_2M (1 << EFI_2M_PAGE_BITS_NUM)
|
|
|
|
#ifndef MIN
|
|
#define MIN(a, b) ((a) < (b) ? (a) : (b))
|
|
#endif
|
|
#define ENTRY_NUM(x) ((UINTN)1 << (x))
|
|
|
|
UINT8 gPML4BitsNum;
|
|
UINT8 gPDPTEBitsNum;
|
|
UINT8 gPDEBitsNum;
|
|
|
|
UINTN gPageNum2M;
|
|
UINTN gPageNum4K;
|
|
|
|
VOID
|
|
EnableNullPointerProtection (
|
|
UINT8 *PageTable
|
|
)
|
|
{
|
|
X64_PAGE_TABLE_ENTRY_4K *PageTableEntry4KB;
|
|
|
|
PageTableEntry4KB = (X64_PAGE_TABLE_ENTRY_4K *) (PageTable + gPageNum2M * EFI_PAGE_SIZE_4K);
|
|
//
|
|
// Fill in the Page Table entries
|
|
// Mark 0~4K as not present
|
|
//
|
|
PageTableEntry4KB->Bits.Present = 0;
|
|
|
|
return ;
|
|
}
|
|
|
|
VOID
|
|
X64Create4KPageTables (
|
|
UINT8 *PageTable
|
|
)
|
|
/*++
|
|
Routine Description:
|
|
Create 4K-Page-Table for the low 2M memory.
|
|
This will change the previously created 2M-Page-Table-Entry.
|
|
--*/
|
|
{
|
|
UINT64 PageAddress;
|
|
UINTN PTEIndex;
|
|
X64_PAGE_DIRECTORY_ENTRY_4K *PageDirectoryEntry4KB;
|
|
X64_PAGE_TABLE_ENTRY_4K *PageTableEntry4KB;
|
|
|
|
//
|
|
// Page Table structure 4 level 4K.
|
|
//
|
|
// PageMapLevel4Entry : bits 47-39
|
|
// PageDirectoryPointerEntry : bits 38-30
|
|
// Page Table 4K : PageDirectoryEntry4K : bits 29-21
|
|
// PageTableEntry : bits 20-12
|
|
//
|
|
|
|
PageTableEntry4KB = (X64_PAGE_TABLE_ENTRY_4K *)(PageTable + gPageNum2M * EFI_PAGE_SIZE_4K);
|
|
|
|
PageDirectoryEntry4KB = (X64_PAGE_DIRECTORY_ENTRY_4K *) (PageTable + 2 * EFI_PAGE_SIZE_4K);
|
|
PageDirectoryEntry4KB->Uint64 = (UINT64)(UINTN)PageTableEntry4KB;
|
|
PageDirectoryEntry4KB->Bits.ReadWrite = 1;
|
|
PageDirectoryEntry4KB->Bits.Present = 1;
|
|
PageDirectoryEntry4KB->Bits.MustBeZero = 0;
|
|
|
|
for (PTEIndex = 0, PageAddress = 0;
|
|
PTEIndex < ENTRY_NUM (EFI_MAX_ENTRY_BITS_NUM);
|
|
PTEIndex++, PageTableEntry4KB++, PageAddress += EFI_PAGE_SIZE_4K
|
|
) {
|
|
//
|
|
// Fill in the Page Table entries
|
|
//
|
|
PageTableEntry4KB->Uint64 = (UINT64)PageAddress;
|
|
PageTableEntry4KB->Bits.ReadWrite = 1;
|
|
PageTableEntry4KB->Bits.Present = 1;
|
|
}
|
|
|
|
return ;
|
|
}
|
|
|
|
VOID
|
|
X64Create2MPageTables (
|
|
UINT8 *PageTable
|
|
)
|
|
{
|
|
UINT64 PageAddress;
|
|
UINT8 *TempPageTable;
|
|
UINTN PML4Index;
|
|
UINTN PDPTEIndex;
|
|
UINTN 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;
|
|
|
|
TempPageTable = PageTable;
|
|
PageAddress = 0;
|
|
|
|
//
|
|
// Page Table structure 3 level 2MB.
|
|
//
|
|
// PageMapLevel4Entry : bits 47-39
|
|
// PageDirectoryPointerEntry : bits 38-30
|
|
// Page Table 2MB : PageDirectoryEntry2M : bits 29-21
|
|
//
|
|
|
|
PageMapLevel4Entry = (X64_PAGE_MAP_AND_DIRECTORY_POINTER_2MB_4K *)TempPageTable;
|
|
|
|
for (PML4Index = 0; PML4Index < ENTRY_NUM (gPML4BitsNum); PML4Index++, PageMapLevel4Entry++) {
|
|
//
|
|
// Each PML4 entry points to a page of Page Directory Pointer entires.
|
|
//
|
|
TempPageTable += EFI_PAGE_SIZE_4K;
|
|
PageDirectoryPointerEntry = (X64_PAGE_MAP_AND_DIRECTORY_POINTER_2MB_4K *)TempPageTable;
|
|
|
|
//
|
|
// Make a PML4 Entry
|
|
//
|
|
PageMapLevel4Entry->Uint64 = (UINT64)(UINTN)(TempPageTable);
|
|
PageMapLevel4Entry->Bits.ReadWrite = 1;
|
|
PageMapLevel4Entry->Bits.Present = 1;
|
|
|
|
for (PDPTEIndex = 0; PDPTEIndex < ENTRY_NUM (gPDPTEBitsNum); PDPTEIndex++, PageDirectoryPointerEntry++) {
|
|
//
|
|
// Each Directory Pointer entries points to a page of Page Directory entires.
|
|
//
|
|
TempPageTable += EFI_PAGE_SIZE_4K;
|
|
PageDirectoryEntry2MB = (X64_PAGE_TABLE_ENTRY_2M *)TempPageTable;
|
|
|
|
//
|
|
// Fill in a Page Directory Pointer Entries
|
|
//
|
|
PageDirectoryPointerEntry->Uint64 = (UINT64)(UINTN)(TempPageTable);
|
|
PageDirectoryPointerEntry->Bits.ReadWrite = 1;
|
|
PageDirectoryPointerEntry->Bits.Present = 1;
|
|
|
|
for (PDEIndex = 0; PDEIndex < ENTRY_NUM (gPDEBitsNum); PDEIndex++, PageDirectoryEntry2MB++) {
|
|
//
|
|
// Fill in the Page Directory entries
|
|
//
|
|
PageDirectoryEntry2MB->Uint64 = (UINT64)PageAddress;
|
|
PageDirectoryEntry2MB->Bits.ReadWrite = 1;
|
|
PageDirectoryEntry2MB->Bits.Present = 1;
|
|
PageDirectoryEntry2MB->Bits.MustBe1 = 1;
|
|
|
|
PageAddress += EFI_PAGE_SIZE_2M;
|
|
}
|
|
}
|
|
}
|
|
|
|
return ;
|
|
}
|
|
|
|
VOID *
|
|
PreparePageTable (
|
|
VOID *PageNumberTop,
|
|
UINT8 SizeOfMemorySpace
|
|
)
|
|
/*++
|
|
Description:
|
|
Generate pagetable below PageNumberTop,
|
|
and return the bottom address of pagetable for putting other things later.
|
|
--*/
|
|
{
|
|
VOID *PageNumberBase;
|
|
|
|
SizeOfMemorySpace -= EFI_2M_PAGE_BITS_NUM;
|
|
gPDEBitsNum = MIN (SizeOfMemorySpace, EFI_MAX_ENTRY_BITS_NUM);
|
|
SizeOfMemorySpace = SizeOfMemorySpace - gPDEBitsNum;
|
|
gPDPTEBitsNum = MIN (SizeOfMemorySpace, EFI_MAX_ENTRY_BITS_NUM);
|
|
SizeOfMemorySpace = SizeOfMemorySpace - gPDPTEBitsNum;
|
|
gPML4BitsNum = SizeOfMemorySpace;
|
|
if (gPML4BitsNum > EFI_MAX_ENTRY_BITS_NUM) {
|
|
return NULL;
|
|
}
|
|
|
|
//
|
|
// Suppose we have:
|
|
// 2MPage:
|
|
// Entry: PML4 -> PDPTE -> PDE -> Page
|
|
// EntryNum: a b c
|
|
// then
|
|
// Occupy4KPage: 1 a a*b
|
|
//
|
|
// 2M 4KPage:
|
|
// Entry: PTE -> Page
|
|
// EntryNum: 512
|
|
// then
|
|
// Occupy4KPage: 1
|
|
//
|
|
|
|
gPageNum2M = 1 + ENTRY_NUM (gPML4BitsNum) + ENTRY_NUM (gPML4BitsNum + gPDPTEBitsNum);
|
|
gPageNum4K = 1;
|
|
|
|
|
|
PageNumberBase = (VOID *)((UINTN)PageNumberTop - (gPageNum2M + gPageNum4K) * EFI_PAGE_SIZE_4K);
|
|
ZeroMem (PageNumberBase, (gPageNum2M + gPageNum4K) * EFI_PAGE_SIZE_4K);
|
|
|
|
X64Create2MPageTables (PageNumberBase);
|
|
X64Create4KPageTables (PageNumberBase);
|
|
//
|
|
// Not enable NULL Pointer Protection if using INTx call
|
|
//
|
|
// EnableNullPointerProtection (PageNumberBase);
|
|
|
|
return PageNumberBase;
|
|
}
|