Compare commits

..

3 Commits

Author SHA1 Message Date
debd7ef91a Slight kernel.h cleanup. 2019-07-24 15:54:32 +01:00
f74809718a Slight cleanup of utils.c
Also added the missing memX functions needed for compilation.
Interrupts next, I do believe.
2019-07-24 15:54:14 +01:00
e4500c27e3 Finish basic memory management.
This won't compile, as it's missing the xAVX functions.
I have a sort-of implementation of them, but it's brutal.
5400 lines total.

For now, they can be substituted with the x functions (remove AVX) to compile the kernel.
2019-07-24 15:53:39 +01:00
3 changed files with 774 additions and 5 deletions

View File

@ -21,6 +21,7 @@
#include <stdint.h>
#include <stdbool.h>
#include <float.h>
#include <x86intrin.h>
#include <efibind.h>
#include <efitypes.h>
@ -626,7 +627,7 @@ void PrepareSystem(FILELOADER_PARAMS* FLOP);
/* System Utilities */
size_t ClockTick(void);
void Halt(void);
void panic(void);
void PrepareAVX(void);
void AVXStub(void);
void PrepareMaskableInterrupts(void);
@ -730,6 +731,13 @@ void timer_install();
/* ==================== Memory ==================== */
// Standard GCC reqs
void* memmove (void* dest, const void* src, size_t len);
void memset(void* src, int chr, size_t n);
void memcpy(void* dest, void* src, size_t n);
int memcmp (const void* str1, const void* str2, size_t count);
uint8_t VerifyZero(size_t Length, size_t Start);
size_t FetchMemoryLimit(void);
@ -755,9 +763,10 @@ EFI_PHYSICAL_ADDRESS AllocatePagetable(size_t PagetableSize);
/* AVX */
void* memmoveAVX(void* Dest, void* Source, size_t Length);
void* memcpyAVX(void* Dest, void* Source, size_t Length);
void* memsetAVX(void* Dest, void* Source, size_t Length);
void* memsetAVX_By4Bytes(void* Dest, void* Source, size_t Length);
void* memsetAVX(void* Dest, const uint8_t Source, size_t Length);
void* memsetAVX_By4Bytes(void* Dest, const uint32_t Source, size_t Length);
uint8_t memcmpAVX(const void* String1, const void* String2, size_t Length);
#define CACHESIZE 3*1024*1024
/* Physical Addresses */

View File

@ -7,8 +7,734 @@
/* Bear with me.
* The plan for this file is to contain all of the memory management, as you can probably tell.
* That means alloc, free, move, set, and AVX of all the above.
*
* Also, this system will be paged. That means virtual address management.
* That means a lot of work, and a lot of commenting.
*
* TODO: The above.
*/
#include <kernel.h>
// malloc. Allocates relative to the nearest alignment value.
__attribute__((malloc)) void* kalloc(size_t Bytes) {
if(Bytes <= 16) {
return kalloc_16(Bytes);
} else if(Bytes <= 32) {
return kalloc_32(Bytes);
} else if(Bytes < 4096) {
return kalloc_64(Bytes);
} else {
return kalloc_pages(EFI_SIZE_TO_PAGES(Bytes));
}
}
// Alignment allocation
__attribute__((malloc)) void* kalloc_16(size_t Bytes) {
EFI_PHYSICAL_ADDRESS Buffer = AllocateFreeAddress_By16Bytes(Bytes, Buffer);
return (void*)Buffer;
}
__attribute__((malloc)) void* kalloc_32(size_t Bytes) {
EFI_PHYSICAL_ADDRESS Buffer = AllocateFreeAddress_By32Bytes(Bytes, Buffer);
return (void*)Buffer;
}
__attribute__((malloc)) void* kalloc_64(size_t Bytes) {
EFI_PHYSICAL_ADDRESS Buffer = AllocateFreeAddress_By64Bytes(Bytes, Buffer);
return (void*)Buffer;
}
__attribute__((malloc)) void* kalloc_pages(size_t Pages) {
EFI_PHYSICAL_ADDRESS Buffer = AllocateFreeAddress_ByPage(Pages, Buffer);
return (void*)Buffer;
}
uint8_t VerifyZero(size_t Length, size_t Base) {
for(size_t i = 0; i < Length; i++) {
if ( *(uint8_t* )(Base + i) != 0) {
return 1;
}
}
return 0;
}
// Returns the byte after the last mapped byte of memory.
// AKA, tells you exactly how much RAM is installed.
size_t FetchMemoryLimit() {
EFI_MEMORY_DESCRIPTOR* Piece;
size_t CurrentAddress = 0, MaxAddress = 0;
for(Piece = Memory_Info.MemoryMap;
Piece < (EFI_MEMORY_DESCRIPTOR*)((uint8_t*) Memory_Info.MemoryMap + Memory_Info.MemoryMapSize);
Piece = (EFI_MEMORY_DESCRIPTOR*)((uint8_t* )Piece + Memory_Info.MemoryMapDescriptorSize)) {
CurrentAddress = Piece->PhysicalStart + EFI_PAGES_TO_SIZE(Piece->NumberOfPages);
if(CurrentAddress > MaxAddress) {
MaxAddress = CurrentAddress;
}
}
return MaxAddress;
}
// Calculates how much RAM is visible to the kernel (EG. Not taken by GPU or UEFI)
size_t FetchVisibleMemory() {
EFI_MEMORY_DESCRIPTOR* Piece;
size_t Total = 0;
for(Piece = Memory_Info.MemoryMap;
Piece < (EFI_MEMORY_DESCRIPTOR*)((uint8_t*) Memory_Info.MemoryMap + Memory_Info.MemoryMapSize);
Piece = (EFI_MEMORY_DESCRIPTOR*)((uint8_t* )Piece + Memory_Info.MemoryMapDescriptorSize)) {
if( (Piece->Type != EfiMemoryMappedIO) &&
(Piece->Type != EfiMemoryMappedIOPortSpace) &&
(Piece->Type != EfiPalCode) &&
(Piece->Type != EfiPersistentMemory) &&
(Piece->Type != EfiMaxMemoryType)) {
Total += EFI_PAGES_TO_SIZE(Piece->NumberOfPages);
}
}
return Total;
}
// Calulcate the total EfiConventionalMemory
size_t FetchAvailableMemory() {
EFI_MEMORY_DESCRIPTOR* Piece;
size_t Total = 0;
for(Piece = Memory_Info.MemoryMap;
Piece < (EFI_MEMORY_DESCRIPTOR*)((uint8_t*) Memory_Info.MemoryMap + Memory_Info.MemoryMapSize);
Piece = (EFI_MEMORY_DESCRIPTOR*)((uint8_t* )Piece + Memory_Info.MemoryMapDescriptorSize)) {
if(Piece->Type == EfiConventionalMemory) {
Total += EFI_PAGES_TO_SIZE(Piece->NumberOfPages);
}
}
return Total;
}
// Calculates the total EfiPersistentMemory
size_t FetchAvailablePMemory() {
EFI_MEMORY_DESCRIPTOR* Piece;
size_t Total;
for(Piece = Memory_Info.MemoryMap;
Piece < (EFI_MEMORY_DESCRIPTOR*)((uint8_t*) Memory_Info.MemoryMap + Memory_Info.MemoryMapSize);
Piece = (EFI_MEMORY_DESCRIPTOR*)((uint8_t* )Piece + Memory_Info.MemoryMapDescriptorSize)) {
if(Piece->Type == EfiPersistentMemory) {
Total += EFI_PAGES_TO_SIZE(Piece->NumberOfPages);
}
}
return Total;
}
size_t FetchInstalledMemory() {
size_t Total = FetchVisibleMemory();
Total += (63 << 20); // DDR3 min is 64MB
return (Total & ~((64 << 20) - 1));
}
// From Syncboot/memory.c
static const char Memory_Segments[16][27] = {
"EfiReservedMemoryType ",
"EfiLoaderCode ",
"EfiLoaderData ",
"EfiBootServicesCode ",
"EfiBootServicesData ",
"EfiRuntimeServicesCode ",
"EfiRuntimeServicesData ",
"EfiConventionalMemory ",
"EfiUnusableMemory ",
"EfiACPIReclaimMemory ",
"EfiACPIMemoryNVS ",
"EfiMemoryMappedIO ",
"EfiMemoryMappedIOPortSpace",
"EfiPalCode ",
"EfiPersistentMemory ",
"EfiMaxMemoryType ",
"malloc ", // EfiMaxMemoryType + 1
"vmalloc ", // EfiMaxMemoryType + 2
"MemMap ", // EfiMaxMemoryType + 3
"PageTables " // EfiMaxMemoryType + 4
};
void PrintMemoryMap() {
EFI_MEMORY_DESCRIPTOR* Piece;
uint16_t line = 0;
printf(L"MemMapSize: %qx, MemMapDescriptorSize: %1u, MemMapDescriptorVersion: %u\r\n", Memory_Info.MemoryMapSize, Memory_Info.MemoryMapDescriptorSize, Memory_Info.MemoryMapDescriptorVersion);
for (Piece = Memory_Info.MemoryMap;
Piece < (EFI_MEMORY_DESCRIPTOR*)((uint8_t*)Memory_Info.MemoryMap + Memory_Info.MemoryMapSize);
Piece = (EFI_MEMORY_DESCRIPTOR*)((UINT8*)Piece + Memory_Info.MemoryMapDescriptorSize)) {
if (line % 20 == 0) {
printf(L"# Memory Type Phys Addr Start Num Of Pages Attr\r\n");
}
printf(L"%2hu: %s 0x%016qx 0x%qx 0x%qx\r\n", line, Memory_Segments[Piece->Type], Piece->PhysicalStart, Piece->NumberOfPages, Piece->Attribute);
line++;
}
}
EFI_MEMORY_DESCRIPTOR* SetIdentityMap(EFI_RUNTIME_SERVICES* RT) {
EFI_MEMORY_DESCRIPTOR* Piece;
for (Piece = Memory_Info.MemoryMap;
Piece < (EFI_MEMORY_DESCRIPTOR*)((uint8_t*)Memory_Info.MemoryMap + Memory_Info.MemoryMapSize);
Piece = (EFI_MEMORY_DESCRIPTOR*)((UINT8*)Piece + Memory_Info.MemoryMapDescriptorSize)) {
Piece->VirtualStart = Piece->PhysicalStart;
}
if(EFI_ERROR(RT->SetVirtualAddressMap(Memory_Info.MemoryMapSize, Memory_Info.MemoryMapDescriptorSize, Memory_Info.MemoryMapDescriptorVersion, Memory_Info.MemoryMap))) {
return NULL;
}
return Memory_Info.MemoryMap;
}
// This installs the memory map into itself.
// Sounds crazy, but it works.
void InstallMemoryMap() {
EFI_MEMORY_DESCRIPTOR* Piece;
size_t Pages = EFI_SIZE_TO_PAGES(Memory_Info.MemoryMapSize + Memory_Info.MemoryMapDescriptorSize);
EFI_PHYSICAL_ADDRESS NewMapBase = FindFreeAddress(Pages, 0);
if(NewMapBase == ~0ULL) {
printf("Can't move memory map to embiggen it. Ergo, kalloc is not available.\r\n");
} else {
// Start moving.
EFI_MEMORY_DESCRIPTOR* NewMap = (EFI_MEMORY_DESCRIPTOR* )NewMapBase;
// Clear out the space for the new map.
memsetAVX(NewMap, 0, Pages << EFI_PAGE_SHIFT);
// Move the old map to where the new one is.
memmoveAVX(NewMap, Memory_Info.MemoryMap, Memory_Info.MemoryMapSize);
// Remove the old map.
memsetAVX(Memory_Info.MemoryMap, 0, Memory_Info.MemoryMapSize);
// Set the global map to the new one.
Memory_Info.MemoryMap = NewMap;
// Start expanding.
// First, find the PhysicalStart place.
for (Piece = Memory_Info.MemoryMap;
Piece < (EFI_MEMORY_DESCRIPTOR*)((uint8_t*)Memory_Info.MemoryMap + Memory_Info.MemoryMapSize);
Piece = (EFI_MEMORY_DESCRIPTOR*)((UINT8*)Piece + Memory_Info.MemoryMapDescriptorSize)) {
if(Piece->PhysicalStart == NewMapBase) {
break;
}
}
if((uint8_t*) Piece == ((uint8_t*)Memory_Info.MemoryMap + Memory_Info.MemoryMapSize)) {
printf("Memory Map not found.\r\n");
} else {
// Piece now contains PhysicalStart
// Mark the new area as containing the memory map.
if(Piece->NumberOfPages == Pages) {
Piece->Type = EfiMaxMemoryType + 3; // Memory Map
} else {
// We need to tell the memory map that there's now a section *in* the memory map *for* the memory map.
// so, temporarily store the current Piece.
EFI_MEMORY_DESCRIPTOR NewDescriptor;
NewDescriptor.Type = EfiMaxMemoryType + 3;
NewDescriptor.Pad = Piece->Pad;
NewDescriptor.PhysicalStart = Piece->PhysicalStart;
NewDescriptor.VirtualStart = Piece->VirtualStart;
NewDescriptor.NumberOfPages = Pages;
NewDescriptor.Attribute = Piece->Attribute;
// Shrink the descriptor; ew've added things.
Piece->PhysicalStart += (Pages << EFI_PAGE_SHIFT);
Piece->VirtualStart += (Pages << EFI_PAGE_SHIFT);
Piece->NumberOfPages -= Pages;
// Move things about
memmoveAVX((uint8_t*)Piece + Memory_Info.MemoryMapDescriptorSize, Piece, ((uint8_t*)Memory_Info.MemoryMap + Memory_Info.MemoryMapSize) - (uint8_t*)Piece);
// And move the old piece back
Piece->Type = NewDescriptor.Type;
Piece->Pad = NewDescriptor.Pad;
Piece->PhysicalStart = NewDescriptor.PhysicalStart;
Piece->VirtualStart = NewDescriptor.VirtualStart;
Piece->NumberOfPages = NewDescriptor.NumberOfPages;
Piece->Attribute = NewDescriptor.Attribute;
// We added a descriptor, so tell the map that it's now bigger.
Memory_Info.MemoryMapSize += Memory_Info.MemoryMapDescriptorSize;
}
}
}
}
EFI_PHYSICAL_ADDRESS AllocatePagetable(size_t PageTableSize) {
EFI_MEMORY_DESCRIPTOR* Piece;
size_t Pages = EFI_SIZE_TO_PAGES(PageTableSize);
EFI_PHYSICAL_ADDRESS PagetableAddress = FindFreeAddress(Pages, 0);
if(PagetableAddress == ~0ULL) {
printf("Not enough space for page tables.\r\n");
panic();
} else {
memsetAVX((void*)PagetableAddress, 0, Pages << EFI_PAGE_SHIFT);
for (Piece = Memory_Info.MemoryMap;
Piece < (EFI_MEMORY_DESCRIPTOR*)((uint8_t*)Memory_Info.MemoryMap + Memory_Info.MemoryMapSize);
Piece = (EFI_MEMORY_DESCRIPTOR*)((UINT8*)Piece + Memory_Info.MemoryMapDescriptorSize)) {
if(Piece->PhysicalStart == PagetableAddress) {
break;
}
}
if((uint8_t* )Piece == ((uint8_t* )Memory_Info.MemoryMap + Memory_Info.MemoryMapSize)) {
printf("Pagetable space not found.\r\n");
panic();
} else {
if(Piece->NumberOfPages == Pages) {
Piece->Type = EfiMaxMemoryType + 4; // Pagetables
} else {
// We need to tell the memory map that there's now a section *in* the memory map *for* the memory map.
// so, temporarily store the current Piece.
EFI_MEMORY_DESCRIPTOR NewDescriptor;
NewDescriptor.Type = EfiMaxMemoryType + 4;
NewDescriptor.Pad = Piece->Pad;
NewDescriptor.PhysicalStart = Piece->PhysicalStart;
NewDescriptor.VirtualStart = Piece->VirtualStart;
NewDescriptor.NumberOfPages = Pages;
NewDescriptor.Attribute = Piece->Attribute;
// Shrink the descriptor; ew've added things.
Piece->PhysicalStart += (Pages << EFI_PAGE_SHIFT);
Piece->VirtualStart += (Pages << EFI_PAGE_SHIFT);
Piece->NumberOfPages -= Pages;
// Move things about
memmoveAVX((uint8_t*)Piece + Memory_Info.MemoryMapDescriptorSize, Piece, ((uint8_t*)Memory_Info.MemoryMap + Memory_Info.MemoryMapSize) - (uint8_t*)Piece);
// And move the old piece back
Piece->Type = NewDescriptor.Type;
Piece->Pad = NewDescriptor.Pad;
Piece->PhysicalStart = NewDescriptor.PhysicalStart;
Piece->VirtualStart = NewDescriptor.VirtualStart;
Piece->NumberOfPages = NewDescriptor.NumberOfPages;
Piece->Attribute = NewDescriptor.Attribute;
// We added a descriptor, so tell the map that it's now bigger.
Memory_Info.MemoryMapSize += Memory_Info.MemoryMapDescriptorSize;
}
}
}
return PagetableAddress;
}
EFI_PHYSICAL_ADDRESS FindFreeAddress(size_t pages, EFI_PHYSICAL_ADDRESS OldAddress) {
EFI_MEMORY_DESCRIPTOR* Piece;
for (Piece = Memory_Info.MemoryMap;
Piece < (EFI_MEMORY_DESCRIPTOR*)((uint8_t*)Memory_Info.MemoryMap + Memory_Info.MemoryMapSize);
Piece = (EFI_MEMORY_DESCRIPTOR*)((uint8_t*)Piece + Memory_Info.MemoryMapDescriptorSize)) {
if ((Piece->Type == EfiConventionalMemory) && (Piece->NumberOfPages >= pages) && (Piece->PhysicalStart > OldAddress))
break;
}
if (Piece >= (EFI_MEMORY_DESCRIPTOR*)((uint8_t*)Memory_Info.MemoryMap + Memory_Info.MemoryMapSize)) {
printf("Out of available memory!\r\n");
return ~0ULL;
}
return Piece->PhysicalStart;
}
EFI_PHYSICAL_ADDRESS FindFreeAddress_ByPage(size_t pages, EFI_PHYSICAL_ADDRESS OldAddress) {
EFI_MEMORY_DESCRIPTOR* Piece;
EFI_PHYSICAL_ADDRESS PhysicalEnd;
EFI_PHYSICAL_ADDRESS DiscoveredAddress;
for (Piece = Memory_Info.MemoryMap;
Piece < (EFI_MEMORY_DESCRIPTOR*)((uint8_t*)Memory_Info.MemoryMap + Memory_Info.MemoryMapSize);
Piece = (EFI_MEMORY_DESCRIPTOR*)((uint8_t*)Piece + Memory_Info.MemoryMapDescriptorSize)) {
if ((Piece->Type == EfiConventionalMemory) && (Piece->NumberOfPages >= pages)) {
PhysicalEnd = Piece->PhysicalStart + (Piece->NumberOfPages << EFI_PAGE_SHIFT) - EFI_PAGE_MASK; // Get the end of this range, and use it to set a bound on the range (define a max returnable address).
if ((OldAddress >= Piece->PhysicalStart) && ((OldAddress + (pages << EFI_PAGE_SHIFT)) < PhysicalEnd)) {
DiscoveredAddress = OldAddress + EFI_PAGE_SIZE;
break;
}
else if (Piece->PhysicalStart > OldAddress) {
DiscoveredAddress = Piece->PhysicalStart;
break;
}
}
}
if (Piece >= (EFI_MEMORY_DESCRIPTOR*)((uint8_t*)Memory_Info.MemoryMap + Memory_Info.MemoryMapSize)) {
printf(L"No more free addresses by page...\r\n");
return ~0ULL;
}
return DiscoveredAddress;
}
EFI_PHYSICAL_ADDRESS AllocateFreeAddress_By16Bytes(size_t Bytes, EFI_PHYSICAL_ADDRESS OldAddress) {
EFI_MEMORY_DESCRIPTOR* Piece;
EFI_PHYSICAL_ADDRESS PhysicalEnd;
EFI_PHYSICAL_ADDRESS DiscoveredAddress;
size_t X16Bytes = Bytes >> 4;
if(Bytes & 0xF) {
X16Bytes++;
}
for(Piece = Memory_Info.MemoryMap;
Piece < (EFI_MEMORY_DESCRIPTOR*)((uint8_t*)Memory_Info.MemoryMap + Memory_Info.MemoryMapSize);
Piece = (EFI_MEMORY_DESCRIPTOR*)((uint8_t*)Piece + Memory_Info.MemoryMapDescriptorSize)) {
if((Piece->Type == EfiConventionalMemory) && ((Piece->NumberOfPages << EFI_PAGE_SHIFT) >= X16Bytes)) {
// Found a range big enough.
// Get the end of this range for bounds checking
PhysicalEnd = Piece->PhysicalStart + (Piece->NumberOfPages << EFI_PAGE_SHIFT) - 1;
if((OldAddress >= Piece->PhysicalStart) && ((OldAddress + (X16Bytes << 4)) < PhysicalEnd)) { // Bounds check on OldAddress
// OldAddress + offset is [still] in-bounds, so return the next available x-byte aligned address in the range.
DiscoveredAddress = OldAddress + X16Bytes; // Left shift num_x_bytes by 1 or 2 to check every 0x10 or 0x100 sets of bytes (must also modify the above PhysicalEnd bound check)
break;
// If we would run over PhysicalEnd, we need to go to the next EfiConventionalMemory range
}
else if(Piece->PhysicalStart > OldAddress) { // Turns out the nearest compatible PhysicalStart is > OldAddress. Use that, then.
DiscoveredAddress = Piece->PhysicalStart;
break;
}
}
}
// Loop ended without a DiscoveredAddress
if(Piece >= (EFI_MEMORY_DESCRIPTOR*)((uint8_t*)Memory_Info.MemoryMap + Memory_Info.MemoryMapSize))
{
// Return address -1, which will cause AllocatePages to fail
printf("No more free physical addresses by 16 bytes...\r\n");
return ~0ULL;
}
return DiscoveredAddress;
}
EFI_PHYSICAL_ADDRESS AllocateFreeAddress_By32Bytes(size_t Bytes, EFI_PHYSICAL_ADDRESS OldAddress) {
EFI_MEMORY_DESCRIPTOR* Piece;
EFI_PHYSICAL_ADDRESS PhysicalEnd;
EFI_PHYSICAL_ADDRESS DiscoveredAddress;
size_t X32Bytes = Bytes >> 5;
if(Bytes & 0x1F) {
X32Bytes++;
}
for(Piece = Memory_Info.MemoryMap;
Piece < (EFI_MEMORY_DESCRIPTOR*)((uint8_t*)Memory_Info.MemoryMap + Memory_Info.MemoryMapSize);
Piece = (EFI_MEMORY_DESCRIPTOR*)((uint8_t*)Piece + Memory_Info.MemoryMapDescriptorSize)) {
if((Piece->Type == EfiConventionalMemory) && ((Piece->NumberOfPages << EFI_PAGE_SHIFT) >= X32Bytes)) {
// Found a range big enough.
// Get the end of this range for bounds checking
PhysicalEnd = Piece->PhysicalStart + (Piece->NumberOfPages << EFI_PAGE_SHIFT) - 1;
if((OldAddress >= Piece->PhysicalStart) && ((OldAddress + (X32Bytes << 5)) < PhysicalEnd)) { // Bounds check on OldAddress
// OldAddress + offset is [still] in-bounds, so return the next available x-byte aligned address in the range.
DiscoveredAddress = OldAddress + X32Bytes; // Left shift num_x_bytes by 1 or 2 to check every 0x10 or 0x100 sets of bytes (must also modify the above PhysicalEnd bound check)
break;
// If we would run over PhysicalEnd, we need to go to the next EfiConventionalMemory range
}
else if(Piece->PhysicalStart > OldAddress) { // Turns out the nearest compatible PhysicalStart is > OldAddress. Use that, then.
DiscoveredAddress = Piece->PhysicalStart;
break;
}
}
}
// Loop ended without a DiscoveredAddress
if(Piece >= (EFI_MEMORY_DESCRIPTOR*)((uint8_t*)Memory_Info.MemoryMap + Memory_Info.MemoryMapSize))
{
// Return address -1, which will cause AllocatePages to fail
printf("No more free physical addresses by 32 bytes...\r\n");
return ~0ULL;
}
return DiscoveredAddress;
}
EFI_PHYSICAL_ADDRESS AllocateFreeAddress_By64Bytes(size_t Bytes, EFI_PHYSICAL_ADDRESS OldAddress) {
EFI_MEMORY_DESCRIPTOR* Piece;
EFI_PHYSICAL_ADDRESS PhysicalEnd;
EFI_PHYSICAL_ADDRESS DiscoveredAddress;
size_t X64Bytes = Bytes >> 6;
if(Bytes & 0x3F) {
X64Bytes++;
}
for(Piece = Memory_Info.MemoryMap;
Piece < (EFI_MEMORY_DESCRIPTOR*)((uint8_t*)Memory_Info.MemoryMap + Memory_Info.MemoryMapSize);
Piece = (EFI_MEMORY_DESCRIPTOR*)((uint8_t*)Piece + Memory_Info.MemoryMapDescriptorSize)) {
if((Piece->Type == EfiConventionalMemory) && ((Piece->NumberOfPages << EFI_PAGE_SHIFT) >= X64Bytes)) {
// Found a range big enough.
// Get the end of this range for bounds checking
PhysicalEnd = Piece->PhysicalStart + (Piece->NumberOfPages << EFI_PAGE_SHIFT) - 1;
if((OldAddress >= Piece->PhysicalStart) && ((OldAddress + (X64Bytes << 6)) < PhysicalEnd)) { // Bounds check on OldAddress
// OldAddress + offset is [still] in-bounds, so return the next available x-byte aligned address in the range.
DiscoveredAddress = OldAddress + X64Bytes; // Left shift num_x_bytes by 1 or 2 to check every 0x10 or 0x100 sets of bytes (must also modify the above PhysicalEnd bound check)
break;
// If we would run over PhysicalEnd, we need to go to the next EfiConventionalMemory range
}
else if(Piece->PhysicalStart > OldAddress) { // Turns out the nearest compatible PhysicalStart is > OldAddress. Use that, then.
DiscoveredAddress = Piece->PhysicalStart;
break;
}
}
}
// Loop ended without a DiscoveredAddress
if(Piece >= (EFI_MEMORY_DESCRIPTOR*)((uint8_t*)Memory_Info.MemoryMap + Memory_Info.MemoryMapSize))
{
// Return address -1, which will cause AllocatePages to fail
printf("No more free physical addresses by 16 bytes...\r\n");
return ~0ULL;
}
return DiscoveredAddress;
}
// per the UEFI Specification (2.7A), EfiBootServicesCode and EfiBootServicesData should be free.
// This function is safe, meaning that calling it more than once doesn't change anything.
void ReclaimEfiBootServicesMemory() {
EFI_MEMORY_DESCRIPTOR* Piece;
for (Piece = Memory_Info.MemoryMap;
Piece < (EFI_MEMORY_DESCRIPTOR*)((uint8_t*)Memory_Info.MemoryMap + Memory_Info.MemoryMapSize);
Piece = (EFI_MEMORY_DESCRIPTOR*)((UINT8*)Piece + Memory_Info.MemoryMapDescriptorSize)) {
if((Piece->Type == EfiBootServicesCode) || (Piece->Type == EfiBootServicesData)) {
Piece->Type = EfiConventionalMemory;
}
}
MergeFragmentedMemory();
}
// This function does the above, but for EfiLoaderData (Syncboot data)
// This is not recommended, as this stored the FILELOADER_PARAMS.
// Before calling this, make a copy.
void ReclaimEfiLoaderCodeMemory() {
EFI_MEMORY_DESCRIPTOR* Piece;
for (Piece = Memory_Info.MemoryMap;
Piece < (EFI_MEMORY_DESCRIPTOR*)((uint8_t*)Memory_Info.MemoryMap + Memory_Info.MemoryMapSize);
Piece = (EFI_MEMORY_DESCRIPTOR*)((UINT8*)Piece + Memory_Info.MemoryMapDescriptorSize)) {
if(Piece->Type == EfiLoaderData) {
Piece->Type = EfiConventionalMemory;
}
}
MergeFragmentedMemory();
}
// Cleans up the memory map, merging adjacent EfiConventionalMemory entries.
void MergeFragmentedMemory() {
EFI_MEMORY_DESCRIPTOR* Piece;
EFI_MEMORY_DESCRIPTOR* Piece2;
EFI_PHYSICAL_ADDRESS PhysicalEnd;
size_t Pages = 1;
for (Piece = Memory_Info.MemoryMap;
Piece < (EFI_MEMORY_DESCRIPTOR*)((uint8_t*)Memory_Info.MemoryMap + Memory_Info.MemoryMapSize);
Piece = (EFI_MEMORY_DESCRIPTOR*)((UINT8*)Piece + Memory_Info.MemoryMapDescriptorSize)) {
if(Piece->Type == EfiConventionalMemory) {
PhysicalEnd = Piece->PhysicalStart + (Piece->NumberOfPages << EFI_PAGE_SHIFT);
for (Piece2 = Memory_Info.MemoryMap;
Piece2 < (EFI_MEMORY_DESCRIPTOR*)((uint8_t*)Memory_Info.MemoryMap + Memory_Info.MemoryMapSize);
Piece2 = (EFI_MEMORY_DESCRIPTOR*)((UINT8*)Piece2 + Memory_Info.MemoryMapDescriptorSize)) {
if((Piece2->Type == EfiConventionalMemory) && (PhysicalEnd == Piece2->PhysicalStart)) { // If this segment is adjacent to the last one (Piece)
Piece->NumberOfPages += Piece2->NumberOfPages;
memsetAVX(Piece2, 0, Memory_Info.MemoryMapDescriptorSize);
// Move the memory down a page
memmoveAVX(Piece2, (uint8_t* )Piece2 + Memory_Info.MemoryMapDescriptorSize, ((uint8_t* )Memory_Info.MemoryMap + Memory_Info.MemoryMapSize) - ((uint8_t* )Piece2 + Memory_Info.MemoryMapDescriptorSize));
Memory_Info.MemoryMapSize -= Memory_Info.MemoryMapDescriptorSize;
memsetAVX((uint8_t* )Memory_Info.MemoryMap + Memory_Info.MemoryMapSize, 0, Memory_Info.MemoryMapDescriptorSize);
Piece2 = (EFI_MEMORY_DESCRIPTOR* )((uint8_t* )Piece2 - Memory_Info.MemoryMapDescriptorSize);
PhysicalEnd = Piece->PhysicalStart + (Piece->NumberOfPages << EFI_PAGE_SHIFT);
}
}
} else if(Piece->Type == EfiMaxMemoryType + 3 ) {
Pages = Piece->NumberOfPages;
}
}
size_t Pages2 = (Memory_Info.MemoryMapSize + EFI_PAGE_MASK) >> EFI_PAGE_SHIFT;
if(Pages2 < Pages) {
for (Piece = Memory_Info.MemoryMap;
Piece < (EFI_MEMORY_DESCRIPTOR*)((uint8_t*)Memory_Info.MemoryMap + Memory_Info.MemoryMapSize);
Piece = (EFI_MEMORY_DESCRIPTOR*)((UINT8*)Piece + Memory_Info.MemoryMapDescriptorSize)) {
if((Piece->Type == EfiMaxMemoryType + 3)) {
if( ((EFI_MEMORY_DESCRIPTOR* )((uint8_t* )Piece + Memory_Info.MemoryMapDescriptorSize))->Type == EfiConventionalMemory ) {
size_t FreePages = Pages - Pages2;
Piece->NumberOfPages = Pages2;
((EFI_MEMORY_DESCRIPTOR* )((uint8_t* )Piece + Memory_Info.MemoryMapDescriptorSize))->NumberOfPages += FreePages;
((EFI_MEMORY_DESCRIPTOR* )((uint8_t* )Piece + Memory_Info.MemoryMapDescriptorSize))->PhysicalStart -= (FreePages << EFI_PAGE_SHIFT);
((EFI_MEMORY_DESCRIPTOR* )((uint8_t* )Piece + Memory_Info.MemoryMapDescriptorSize))->VirtualStart -= (FreePages << EFI_PAGE_SHIFT);
} else if ((Memory_Info.MemoryMapSize + Memory_Info.MemoryMapDescriptorSize) <= (Pages2 << EFI_PAGE_SHIFT)) {
EFI_MEMORY_DESCRIPTOR NewDescriptor;
NewDescriptor.Type = Piece->Type;
NewDescriptor.Pad = Piece->Pad;
NewDescriptor.PhysicalStart = Piece->PhysicalStart;
NewDescriptor.VirtualStart = Piece->VirtualStart;
NewDescriptor.NumberOfPages = Pages2;
NewDescriptor.Attribute = Piece->Attribute;
Piece->Type = EfiConventionalMemory;
// Shrink the descriptor; ew've added things.
Piece->PhysicalStart += (Pages2 << EFI_PAGE_SHIFT);
Piece->VirtualStart += (Pages2 << EFI_PAGE_SHIFT);
Piece->NumberOfPages = Pages - Pages2;
// Move things about
memmoveAVX((uint8_t*)Piece + Memory_Info.MemoryMapDescriptorSize, Piece, ((uint8_t*)Memory_Info.MemoryMap + Memory_Info.MemoryMapSize) - (uint8_t*)Piece);
// And move the old piece back
Piece->Type = NewDescriptor.Type;
Piece->Pad = NewDescriptor.Pad;
Piece->PhysicalStart = NewDescriptor.PhysicalStart;
Piece->VirtualStart = NewDescriptor.VirtualStart;
Piece->NumberOfPages = NewDescriptor.NumberOfPages;
Piece->Attribute = NewDescriptor.Attribute;
// We added a descriptor, so tell the map that it's now bigger.
Memory_Info.MemoryMapSize += Memory_Info.MemoryMapDescriptorSize;
} else {
size_t PagesPerDescriptor = (Memory_Info.MemoryMapDescriptorSize + EFI_PAGE_MASK) >> EFI_PAGE_SHIFT;
if((Pages2 + PagesPerDescriptor) < Pages) {
size_t FreePages = Pages - Pages2 - PagesPerDescriptor;
EFI_MEMORY_DESCRIPTOR NewDescriptor;
NewDescriptor.Type = Piece->Type;
NewDescriptor.Pad = Piece->Pad;
NewDescriptor.PhysicalStart = Piece->PhysicalStart;
NewDescriptor.VirtualStart = Piece->VirtualStart;
NewDescriptor.NumberOfPages = Pages2 + PagesPerDescriptor;
NewDescriptor.Attribute = Piece->Attribute;
Piece->Type = EfiConventionalMemory;
// Shrink the descriptor; ew've added things.
Piece->PhysicalStart += ((Pages2 + PagesPerDescriptor) << EFI_PAGE_SHIFT);
Piece->VirtualStart += ((Pages2 + PagesPerDescriptor) << EFI_PAGE_SHIFT);
Piece->NumberOfPages = FreePages;
// Move things about
memmoveAVX((uint8_t*)Piece + Memory_Info.MemoryMapDescriptorSize, Piece, ((uint8_t*)Memory_Info.MemoryMap + Memory_Info.MemoryMapSize) - (uint8_t*)Piece);
// And move the old piece back
Piece->Type = NewDescriptor.Type;
Piece->Pad = NewDescriptor.Pad;
Piece->PhysicalStart = NewDescriptor.PhysicalStart;
Piece->VirtualStart = NewDescriptor.VirtualStart;
Piece->NumberOfPages = NewDescriptor.NumberOfPages;
Piece->Attribute = NewDescriptor.Attribute;
// We added a descriptor, so tell the map that it's now bigger.
Memory_Info.MemoryMapSize += Memory_Info.MemoryMapDescriptorSize;
}
}
break;
}
}
}
}
EFI_PHYSICAL_ADDRESS PurgeAllMemory() {
EFI_MEMORY_DESCRIPTOR* Piece;
EFI_PHYSICAL_ADDRESS Exit = 0;
for (Piece = Memory_Info.MemoryMap;
Piece < (EFI_MEMORY_DESCRIPTOR*)((uint8_t*)Memory_Info.MemoryMap + Memory_Info.MemoryMapSize);
Piece = (EFI_MEMORY_DESCRIPTOR*)((UINT8*)Piece + Memory_Info.MemoryMapDescriptorSize)) {
if(Piece->Type == EfiConventionalMemory) {
memsetAVX( (void* )Piece->PhysicalStart, 0, EFI_PAGES_TO_SIZE(Piece->NumberOfPages));
Exit = VerifyZero(EFI_PAGES_TO_SIZE(Piece->NumberOfPages), Piece->PhysicalStart);
if(Exit) {
printf("Unable to clear memory. First populated address is %#qx. Memory Descriptor starts at %#qx.\r\n", Exit, Piece->PhysicalStart);
} else {
printf("Zeroed memory.\r\n");
}
}
}
return Exit;
}
EFI_PHYSICAL_ADDRESS AllocateFreeAddress_ByPage(size_t Pages, EFI_PHYSICAL_ADDRESS SearchStart) {
EFI_MEMORY_DESCRIPTOR* Piece;
EFI_PHYSICAL_ADDRESS End, Address;
for (Piece = Memory_Info.MemoryMap;
Piece < (EFI_MEMORY_DESCRIPTOR*)((uint8_t*)Memory_Info.MemoryMap + Memory_Info.MemoryMapSize);
Piece = (EFI_MEMORY_DESCRIPTOR*)((UINT8*)Piece + Memory_Info.MemoryMapDescriptorSize)) {
if((Piece->Type == EfiConventionalMemory) && (Piece->NumberOfPages >= Pages)) {
End = Piece->PhysicalStart + (Piece->NumberOfPages << EFI_PAGE_SHIFT) - 1;
if((SearchStart >= Piece->PhysicalStart) && ((SearchStart + (Pages << EFI_PAGE_SHIFT)) << End)) {
Address = SearchStart + EFI_PAGE_SIZE;
break;
} else if(Piece->PhysicalStart > SearchStart) {
Address = Piece->PhysicalStart;
if(Piece->NumberOfPages - Pages == 0) {
Piece->Type = EfiMaxMemoryType + 1;
}
// TODO: Allocate a new page
break;
}
}
}
if(Piece >= (EFI_MEMORY_DESCRIPTOR* )((uint8_t* )Memory_Info.MemoryMap + Memory_Info.MemoryMapSize)) {
printf("Out of pages!\r\n");
return ~0ULL;
}
return Address;
}
// Here we go.
// This is going to be a mess.
// This abuses AVX (SSE3) to do simultaneous memory operations.
// I expect this to be useful in graphics - we can move up to 16 pixels with one - one! CPU cycle.

View File

@ -39,8 +39,29 @@ void memcpy(void* dest, void* src, size_t n) {
}
}
void* memmove (void *dest, const void *src, size_t len) {
const char *s = (char *)src;
char *d = (char *)dest;
const char *nexts = s + len;
char *nextd = d + len;
if (d < s) {
while (d != nextd) {
*d++ = *s++;
}
}
else {
while (nextd != d) {
*--nextd = *--nexts;
}
}
return dest;
}
/*
Memory Set. Required by GCC>
Memory Set. Required by GCC.
* @param src: The data to be overwritten.
* @param chr: The byte to overwrite the source with.
* @param n: How many bytes to overwrite.
@ -52,6 +73,19 @@ void memset(void* src, int chr, size_t n) {
}
}
int memcmp (const void *str1, const void *str2, size_t count) {
const unsigned char *s1 = (unsigned char *)str1;
const unsigned char *s2 = (unsigned char *)str2;
while (count-- > 0) {
if (*s1++ != *s2++) {
return s1[-1] < s2[-1] ? -1 : 1;
}
}
return 0;
}
/*
Turns an integer into a C-str.
* @note Inefficient and unsafe.
@ -165,7 +199,7 @@ void empty_string(char* string) {
* @param cause: A string, telling the basic reason for the crash.
*/
void panic(char* cause) {
void panic() {
printf("Kernel Halted.");
for(;;);