diff options
author | raywu <raywu0301@gmail.com> | 2018-06-15 00:00:50 +0800 |
---|---|---|
committer | raywu <raywu0301@gmail.com> | 2018-06-15 00:00:50 +0800 |
commit | b7c51c9cf4864df6aabb99a1ae843becd577237c (patch) | |
tree | eebe9b0d0ca03062955223097e57da84dd618b9a /Library/Memory.c | |
download | zprj-b7c51c9cf4864df6aabb99a1ae843becd577237c.tar.xz |
Diffstat (limited to 'Library/Memory.c')
-rw-r--r-- | Library/Memory.c | 340 |
1 files changed, 340 insertions, 0 deletions
diff --git a/Library/Memory.c b/Library/Memory.c new file mode 100644 index 0000000..387474f --- /dev/null +++ b/Library/Memory.c @@ -0,0 +1,340 @@ +//************************************************************************* +//************************************************************************* +//** ** +//** (C)Copyright 1985-2011, American Megatrends, Inc. ** +//** ** +//** All Rights Reserved. ** +//** ** +//** 5555 Oakbrook Parkway, Suite 200, Norcross, GA 30093 ** +//** ** +//** Phone: (770)-246-8600 ** +//** ** +//************************************************************************* +//************************************************************************* + +//************************************************************************* +// $Header: /Alaska/SOURCE/Core/Library/Memory.c 10 1/19/12 5:00p Markw $ +// +// $Revision: 10 $ +// +// $Date: 1/19/12 5:00p $ +//************************************************************************* +// Revision History +// ---------------- +// $Log: /Alaska/SOURCE/Core/Library/Memory.c $ +// +// 10 1/19/12 5:00p Markw +// [TAG] EIP81447 +// [Category] Improvement +// [Description] Update page tables to use only 2 MB page tables below 4 +// GB. +// Vista/Win7/Win2008 server doesn't parse 1 GB page tables correctly. +// [Files] memory.c +// +// 9 4/26/11 10:45p Markw +// [TAG] EIP58991 +// [Category] Improvement +// [Description] Support 1 GB page table size in 64-bit mode in DXE. +// [Files] memory.c +// +// 8 7/10/09 3:49p Felixp +// Function headers added +// +// 7 5/02/08 9:57a Felixp +// Bug fix in FillPageTable (Systems with x64 firmware and more than 4GB +// of memory were resetting during transition to DXE) +// +// 6 4/17/08 3:27p Markw +// Add paging functions. +// +// 5 8/24/06 9:26a Felixp +// Preliminary x64 support (work in progress): +// 1. Processor architecture specific functions moved to a processor +// library +// 2. Makefile removed (AmiLib files are build by the AmiPeiLib and +// AmeDxeLib makefile) +// 3. Tokens.c added +// +// 4 6/22/05 12:52p Felixp +// MemSet changes: bug fix (problem with Counter<4); comments added +// +// 3 3/04/05 10:50a Mandal +// +//************************************************************************* +//<AMI_FHDR_START> +// +// Name: Memory.c +// +// Description: +// Contains memory related library functions. +// +//<AMI_FHDR_END> +//************************************************************************* +#include <efi.h> +#include <AmiLib.h> + +//************************************************************************* +//<AMI_GHDR_START> +// +// Name: Memory_Functions +// +// Description: +// Memory functions defined in the AMI library. Note some may only be +// available in DXE. +// +// Fields: Header Function Description +// ------------------------------------------------------------------ +// AmiLib MemSet Fills a buffer with a user provided value. +// AmiLib MemCmp Compare two buffers for equality. +// AmiLIb MemCpy Copy a buffer into another buffer. +// AmiDxeLib Malloc Allocate memory from EfiBootServicesData. +// AmiDxeLib MallocZ Allocate memory from EfiBootServicesData that has been cleared with zeros. +// +// Notes: +// Header details which header file contains the function prototype for +// the above functions. Append .h to the given name. +// +//<AMI_GHDR_END> +//************************************************************************* + +VOID CPULib_CpuID(IN UINT32 CpuIDIndex, OUT UINT32 *RegEAX, OUT UINT32 *RegEBX, + IN OUT UINT32 *RegECX, OUT UINT32 *RegEDX); + +//************************************************************************* +//<AMI_PHDR_START> +// +// Name: MemCmp +// +// Description: +// INTN MemCmp(IN VOID* pDestination, IN VOID* pSource, IN UINTN Count) +// compares Length bytes of pDestination to Length bytes of pSource. If all +// Length bytes of the two buffers are identical, then 0 is returned. +// Otherwise, the value returned is the first mismatched byte in pSource +// subtracted from the first mismatched byte in pDestination. +// +// Input: +// IN VOID* pDestination +// Pointer to the first buffer to compare. +// +// IN VOID* pSource +// Pointer to the second buffer to compare. +// +// IN UINTN Count +// Number of bytes to compare. +// +// Output: +// INTN value of first mismatched byte in pSource subtracted from the first +// mismatched byte in pDestination (pDestination - pSource). Returns 0 if +// both buffers are the same. +// +// Modified: +// +// Referrals: +// +// Notes: +// +//<AMI_PHDR_END> +//************************************************************************* +INTN MemCmp(VOID* pDestination, VOID* pSource, UINTN Count){ + INT8 *d = (UINT8*)pDestination, *s = (UINT8*)pSource; + INT8 *end=d+Count; + UINTN r; +//////////////////////////////////////////////////////////// +// NOTE: in order to increase the comparison speed we will +// compare sizeof(UINTN) bytes at a time if possible. +// Once inequality is found, we will go to the last while loop +// to do a byte by byte comparison to get proper results. +// We have to do it because of the following: +// Let's say we are trying to compare values: 0x1234 and 0x4321: +// If we compare them as double words the second value will be greater. +// If we compare them byte by byte the first value wiill be greater +// (because of little endian architecture of x86) +//////////////////////////////////////////////////////////// + if (Count >= sizeof(UINTN)){ + r = (UINTN)d & (sizeof(UINTN)-1); + if (r && r== ((UINTN)s & (sizeof(UINTN)-1))){ + r = sizeof(UINTN)-r; + Count-=r; + for(;r;r--) + if (*d==*s){d++;s++;} + //the values are not equal + //let's break to do a byte by byte comparison + //to figure out which one is greater + else break; + } + while(d<=end-sizeof(UINTN)) + if (*(UINTN*)d==*(UINTN*)s){ + d+=sizeof(UINTN);s+=sizeof(UINTN); + } + //the values are not equal + //let's break to do a byte by byte comparison + //to figure out which one is greater + else break; + } + while(d<end) + if (*d==*s){d++;s++;} + else return *d-*s; + return 0; +} + +//************************************************************************* +//<AMI_PHDR_START> +// +// Name: GetPageTableNumPages +// +// Description: +// UINT32 GetPageTableNumPages(IN UINT8 NumberMemoryBits) gets the number +// of pages to allocate for paging. +// Unlimited if 1 GB page tables is supported. Otherwise, limit 512 MB address space. +// +// Input: +// IN UINT8 NumberMemoryBits +// Number of memory bits to map. +// +// Output: +// UINT32 number of pages. +// +// Modified: +// +// Referrals: +// Shl64 +// CPULib_CpuID +// +// Notes: +// +//<AMI_PHDR_END> +//************************************************************************* +UINT32 GetPageTableNumPages( + IN UINT8 NumberMemoryBits +) +{ + BOOLEAN GigPageSupport; + UINT32 RegEax, RegEbx, RegEcx, RegEdx; + UINT32 NumPages; + + CPULib_CpuID(0x80000001, &RegEax, &RegEbx, &RegEcx, &RegEdx); + GigPageSupport = !!(RegEdx & BIT26); + + //Limit number of memory bits to 39 (512 GB) if no support for GB page-tables. + if (!GigPageSupport && NumberMemoryBits > 39) NumberMemoryBits = 39; + + if (GigPageSupport) { + //1 page for PML4E Table. + //4 page for for Directory. First 4GB of 2MB pages. + //1 Page for Page-Table Entries for 1st 2MB of 4k pages. + NumPages = 6; + + //Allocate pages for directory pointers. + NumPages += 1 << (NumberMemoryBits > 39 ? NumberMemoryBits - 39 : 0); + } else { + //Allocate at least 7 pages to cover Identity Mapping for 32 bits. + //1 page for PML4E Table + //1 page for Page-Directory Pointer + //Pages for Directory allocated later--one for each directory. + //1 page for Page-Table Entries for 1st 2MB. This must be 4k blocks. + NumPages = 3; + + //Allocate pages for page directories. + NumPages += 1 << (NumberMemoryBits - 30); + } + return NumPages; +} + +//************************************************************************* +//<AMI_PHDR_START> +// +// Name: FillPageTable +// +// Description: +// VOID FillPageTable(IN UINT8 NumberMemoryBits, IN VOID *PageTable) fills a +// provided page table with an identity map. +// +// Input: +// IN UINT8 NumberMemoryBits +// Number of memory bits to map. +// +// IN VOID *PageTable +// Page table to fill. +// +// Output: +// VOID. +// +// Modified: +// +// Referrals: +// Shl64 +// MemSet +// CPULib_CpuID +// +// Notes: +// +//<AMI_PHDR_END> +//************************************************************************* +VOID FillPageTable( + IN UINT8 NumberMemoryBits, + IN VOID *PageTable +) +{ + BOOLEAN GigPageSupport; + UINT32 RegEax, RegEbx, RegEcx, RegEdx; + UINT64 *Pml4eTable = (UINT64*)PageTable; + UINT64 *PdpTable = (UINT64*)((UINT8*)PageTable + 0x1000); + UINT64 *PDir; + UINT64 *PTableEntry; + UINT32 NumPml4Entries; + UINT32 NumPgDirPtrEntries; + UINT32 NumPgDirEntries; + UINT32 i; + + CPULib_CpuID(0x80000001, &RegEax, &RegEbx, &RegEcx, &RegEdx); + GigPageSupport = !!(RegEdx & BIT26); + + //Limit number of memory bits to 39 (512 GB) if no support for GB page-tables. + if (!GigPageSupport && NumberMemoryBits > 39) NumberMemoryBits = 39; + + // Update Page-Map Level-4 tables. + NumPml4Entries = 1 << (NumberMemoryBits > 39 ? NumberMemoryBits - 39 : 0); + for (i = 0; i < NumPml4Entries; ++i) Pml4eTable[i] = BIT0 + BIT1 + (i << 12) + (UINT64)(UINTN)PdpTable; + MemSet(Pml4eTable + i, 4096 - 8 * i, 0); //Clear unused entries. + + //Update Page Pointer Directories. + NumPgDirPtrEntries = 1 << (NumberMemoryBits - 30); + PDir = PdpTable + (NumPgDirPtrEntries <= 512 ? 512 : NumPgDirPtrEntries); + if (GigPageSupport) { + //1st 4 pages must point to a Page directory + PdpTable[0] = BIT0 + BIT1 + (0 << 12) + (UINT64)(UINTN)PDir; + PdpTable[1] = BIT0 + BIT1 + (1 << 12) + (UINT64)(UINTN)PDir; + PdpTable[2] = BIT0 + BIT1 + (2 << 12) + (UINT64)(UINTN)PDir; + PdpTable[3] = BIT0 + BIT1 + (3 << 12) + (UINT64)(UINTN)PDir; + for (i = 4; i < NumPgDirPtrEntries; ++i) + PdpTable[i] = BIT0 + BIT1 + BIT7 + Shl64(i, 30); + } else { + for (i = 0; i < NumPgDirPtrEntries; ++i) + PdpTable[i] = BIT0 + BIT1 + (i << 12) + (UINT64)(UINTN)PDir; + } + if (i < 512) MemSet(PdpTable + i, 4096 - 8 * i, 0); //Clear unused entries. + + //Initialize Page Directores. + if (GigPageSupport) NumPgDirEntries = 2048; //First 4 GB + else NumPgDirEntries = 1 << (NumberMemoryBits - 21); //Number of 2MB pages. + PTableEntry = PDir + NumPgDirEntries; + PDir[0] = BIT0 + BIT1 + (UINT64)(UINTN)PTableEntry; //4K Page Table for first 2MB. + for(i = 1; i < NumPgDirEntries; ++i) PDir[i] = 0x83 + Shl64(i, 21); + + //Initialize 4k page entries for first 2MB. + for(i = 0; i < 512; ++i) PTableEntry[i] = BIT0 + BIT1 + (i << 12); +} + +//************************************************************************* +//************************************************************************* +//** ** +//** (C)Copyright 1985-2011, American Megatrends, Inc. ** +//** ** +//** All Rights Reserved. ** +//** ** +//** 5555 Oakbrook Parkway, Suite 200, Norcross, GA 30093 ** +//** ** +//** Phone: (770)-246-8600 ** +//** ** +//************************************************************************* +//************************************************************************* |