2020-02-06 20:20:58 +00:00
# include <kernel/chroma.h>
2020-04-11 21:59:39 +00:00
# include <kernel/system/heap.h>
2020-08-31 20:47:52 +00:00
# include <lainlib/lainlib.h>
2020-02-06 20:20:58 +00:00
2020-08-22 23:48:49 +00:00
/************************
* * * Team Kitty , 2020 * * *
* * * Chroma * * *
* * * * * * * * * * * * * * * * * * * * * * */
/* This file contains functions for physical memory management.
*
* This is also called blocking , or block memory allocation .
* It mostly deals with the memory map handed to us by the bootloader .
*
* It is useful in virtual memory management , because it allows us to map one block of physical memory to one page of virtual memory .
*
* Most of the processing here is done with a bitwise mapping of blocks to allocations , normally called a memory bitmap .
* See heap . h for the implementation .
*
* This file also contains memory manipulation functions , like memset and memcpy .
* //TODO: replace these functions with SSE2 equivalent.
*
*/
2020-08-31 20:47:52 +00:00
# define MIN_ORDER 3
# define PEEK(type, address) (*((volatile type*)(address)))
2020-11-09 18:43:59 +00:00
uint8_t * Memory = ( ( uint8_t * ) ( & memstart ) ) ;
2020-07-07 23:38:59 +00:00
uint8_t * MemoryStart ;
2020-04-11 21:59:39 +00:00
size_t MemoryBuckets ;
2020-08-31 20:47:52 +00:00
static buddy_t LowBuddy = {
. MaxOrder = 32 ,
. Base = ( directptr_t ) DIRECT_REGION ,
. List = ( directptr_t [ 32 - MIN_ORDER ] ) { 0 } ,
. Lock = { 0 } ,
} ;
static buddy_t HighBuddy = {
. MaxOrder = 64 ,
. Base = 0 ,
. List = ( directptr_t [ 64 - MIN_ORDER ] ) { 0 } ,
. Lock = { 0 } ,
} ;
static size_t MemoryLength ;
static bool CheckBuddies ( buddy_t * Buddy , directptr_t InputA , directptr_t InputB , size_t Size ) {
size_t LowerBuddy = MIN ( CAST ( size_t , InputA ) , CAST ( size_t , InputB ) ) - ( size_t ) Buddy - > Base ;
size_t HigherBuddy = MAX ( CAST ( size_t , InputA ) , CAST ( size_t , InputB ) ) - ( size_t ) Buddy - > Base ;
return ( LowerBuddy ^ Size ) = = HigherBuddy ;
}
static void AddToBuddyList ( buddy_t * Buddy , directptr_t Address , size_t Order , bool NewEntry ) {
directptr_t ListHead = Buddy - > List [ Order - MIN_ORDER ] ;
//SerialPrintf("Adding new entry to buddy: Address 0x%p with order %d, New Entry is %s\r\n", Address, Order, NewEntry ? "true" : "false");
/*
SerialPrintf ( " About to poke memory.. \r \n " ) ;
PEEK ( directptr_t , Address ) = 0 ;
SerialPrintf ( " Did it work? \r \n " ) ;
*/
size_t Size = 1ull < < Order ;
TicketAttemptLock ( & Buddy - > Lock ) ;
//SerialPrintf("Ticketlock engaged\r\n");
if ( ! NewEntry & & ListHead ! = 0 ) {
directptr_t ListPrevious = 0 ;
while ( true ) {
if ( CheckBuddies ( Buddy , ListHead , Address , Size ) ) {
if ( ListPrevious ! = 0 ) {
PEEK ( directptr_t , ListPrevious ) = PEEK ( directptr_t , ListHead ) ;
} else
Buddy - > List [ Order - MIN_ORDER ] = PEEK ( directptr_t , ListHead ) ;
AddToBuddyList ( Buddy , MIN ( ListHead , Address ) , Order + 1 , false ) ;
break ;
}
if ( PEEK ( directptr_t , ListHead ) = = 0 ) {
PEEK ( directptr_t , ListHead ) = Address ;
break ;
}
ListPrevious = ListHead ;
ListHead = PEEK ( directptr_t , ListHead ) ;
}
} else {
//SerialPrintf("\tAbout to poke memory 0x%p - current value is 0x%x\r\n", Address, *((size_t*)(Address)));
* ( ( size_t * ) ( Address ) ) = ( size_t ) ListHead ;
Buddy - > List [ Order - MIN_ORDER ] = Address ;
}
TicketUnlock ( & Buddy - > Lock ) ;
//SerialPrintf("Ticketlock Released.\r\n");
}
static void AddRangeToBuddy ( buddy_t * Buddy , directptr_t Base , size_t Size ) {
//SerialPrintf("Starting a new range addition.\r\n\t");
while ( Size > ( 1ull < < MIN_ORDER ) ) {
//SerialPrintf("New iteration. Current Size: 0x%x\r\n\t", Size);
for ( int Order = Buddy - > MaxOrder - 1 ; Order > = MIN_ORDER ; Order - - ) {
//SerialPrintf("New Loop. Current Order: %d\r\n\t", Order);
if ( Size > = ( 1ull < < Order ) ) {
//SerialPrintf("\tNew loop check passed.\r\n\t");
AddToBuddyList ( Buddy , Base , Order , true ) ;
//SerialPrintf("\tEntry added to current buddy. Moving onto memory operations..\r\n\t");
Base = ( void * ) ( ( ( ( char * ) Base ) + ( 1ull < < Order ) ) ) ;
Size - = 1ull < < Order ;
//SerialPrintf("\tMemory operations complete. Moving onto next iteration.\r\n");
break ;
}
}
}
}
static directptr_t BuddyAllocate ( buddy_t * Buddy , size_t Size ) {
int InitialOrder = MAX ( ( 64 - CLZ ( Size - 1 ) ) , MIN_ORDER ) ;
size_t WantedSize = 1ull < < InitialOrder ;
if ( InitialOrder > = Buddy - > MaxOrder ) {
SerialPrintf ( " Tried to allocate too much physical memory for buddy 0x%p \r \n " , Buddy ) ;
SerialPrintf ( " Buddy 0x%p has max order %d, but 0x%x bytes was requested. \r \n Initial Order: %d, Wanted Size: 0x%x \r \n " , Buddy , Buddy - > MaxOrder , Size , InitialOrder , WantedSize ) ;
return NULL ;
}
TicketAttemptLock ( & Buddy - > Lock ) ;
2020-11-09 18:43:59 +00:00
//SerialPrintf("Searching for a valid order to allocate into. Condition: {\r\n\tOrder: %d,\r\n\tSize: 0x%x\r\n}\r\n\n", InitialOrder, WantedSize);
2020-08-31 20:47:52 +00:00
for ( int Order = InitialOrder ; Order < Buddy - > MaxOrder ; Order + + ) {
2020-09-25 15:47:10 +00:00
//SerialPrintf("\tCurrent Order: %d, Buddy entry: %x\r\n", Order, Buddy->List[Order - MIN_ORDER]);
2020-08-31 20:47:52 +00:00
if ( Buddy - > List [ Order - MIN_ORDER ] ! = 0 ) {
2020-11-09 18:43:59 +00:00
//SerialPrintf("\tFound a valid Order!\r\n");
2020-08-31 20:47:52 +00:00
directptr_t Address = Buddy - > List [ Order - MIN_ORDER ] ;
Buddy - > List [ Order - MIN_ORDER ] = PEEK ( directptr_t , Address ) ;
TicketUnlock ( & Buddy - > Lock ) ;
size_t FoundSize = 1ull < < Order ;
2020-11-09 18:43:59 +00:00
//SerialPrintf("\tAdding area - Address 0x%p, Size 0x%x\r\n\n", Address, FoundSize);
2020-08-31 20:47:52 +00:00
AddRangeToBuddy ( Buddy , ( void * ) ( ( size_t ) Address + WantedSize ) , FoundSize - WantedSize ) ;
2020-11-09 18:43:59 +00:00
//SerialPrintf("\tArea added!\r\n");
2020-08-31 20:47:52 +00:00
return Address ;
}
}
2020-11-09 18:43:59 +00:00
//SerialPrintf("BuddyAllocate: Unable to find a valid order to allocate!\r\nInitial Order: %d, WantedSize: 0x%x\r\n\r\n", InitialOrder, WantedSize);
2020-08-31 20:47:52 +00:00
TicketUnlock ( & Buddy - > Lock ) ;
return NULL ;
}
2020-02-06 20:20:58 +00:00
void InitMemoryManager ( ) {
2020-11-09 18:43:59 +00:00
SerialPrintf ( " [ Mem] Counting memory.. \r \n " ) ;
2020-02-06 20:20:58 +00:00
2020-04-11 21:59:39 +00:00
MemorySize = 0 ;
size_t MemMapEntryCount = 0 ;
2020-02-06 20:20:58 +00:00
MMapEnt * MemMap = & bootldr . mmap ;
2020-11-09 18:43:59 +00:00
while ( ( size_t ) MemMap < ( ( size_t ) & bootldr ) + bootldr . size ) {
2020-02-06 20:20:58 +00:00
if ( MMapEnt_IsFree ( MemMap ) ) {
MemorySize + = MMapEnt_Size ( MemMap ) ;
}
MemMapEntryCount + + ;
MemMap + + ;
}
2020-11-09 18:43:59 +00:00
SerialPrintf ( " [ Mem] Counted %d entries in the memory map.. \r \n " , MemMapEntryCount ) ;
2020-02-06 20:20:58 +00:00
MemoryPages = MemorySize / PAGE_SIZE ;
2020-11-09 18:43:59 +00:00
SerialPrintf ( " [ Mem] %u MB of memory detected. \r \n " , ( MemorySize / 1024 ) / 1024 ) ;
2020-02-06 20:20:58 +00:00
}
2020-04-11 21:59:39 +00:00
void ListMemoryMap ( ) {
2020-11-09 18:43:59 +00:00
SerialPrintf ( " [ Mem] BIOS-Provided memory map: \r \n " ) ;
2020-04-11 21:59:39 +00:00
2020-11-09 18:43:59 +00:00
for ( MMapEnt * MapEntry = & bootldr . mmap ; ( size_t ) MapEntry < ( size_t ) & bootldr + bootldr . size ; MapEntry + + ) {
2020-04-11 21:59:39 +00:00
char EntryType [ 8 ] = { 0 } ;
switch ( MMapEnt_Type ( MapEntry ) ) {
case MMAP_FREE :
memcpy ( EntryType , " FREE " , 5 ) ;
break ;
case MMAP_USED :
memcpy ( EntryType , " RESERVED " , 8 ) ;
break ;
case MMAP_ACPI :
memcpy ( EntryType , " ACPI " , 4 ) ;
break ;
case MMAP_MMIO :
memcpy ( EntryType , " MMIO " , 4 ) ;
break ;
}
2020-08-23 01:32:47 +00:00
size_t entry_from = MMapEnt_Ptr ( MapEntry ) ;
size_t entry_to = MMapEnt_Ptr ( MapEntry ) + MMapEnt_Size ( MapEntry ) ;
if ( entry_from ! = 0 & & entry_to ! = 0 )
2020-11-09 18:43:59 +00:00
SerialPrintf ( " [ Mem] 0x%p-0x%p %s \r \n " , entry_from , entry_to , EntryType ) ;
2020-04-11 21:59:39 +00:00
2020-08-31 20:47:52 +00:00
if ( MMapEnt_Type ( MapEntry ) = = MMAP_FREE ) {
2020-11-09 18:43:59 +00:00
SerialPrintf ( " [ Mem] Adding this entry to the physical memory manager! \r \n " ) ;
2020-08-31 20:47:52 +00:00
AddRangeToPhysMem ( ( void * ) ( ( char * ) ( MMapEnt_Ptr ( MapEntry ) /* + DIRECT_REGION*/ ) ) , MMapEnt_Size ( MapEntry ) ) ;
}
}
}
void AddRangeToPhysMem ( directptr_t Base , size_t Size ) {
if ( Base < ( void * ) ( LOWER_REGION + DIRECT_REGION ) ) {
2020-11-09 18:43:59 +00:00
SerialPrintf ( " [ Mem] New range in lower memory: 0x%p, size 0x%x \r \n " , Base , Size ) ;
2020-08-31 20:47:52 +00:00
AddRangeToBuddy ( & LowBuddy , Base , Size ) ;
} else {
if ( HighBuddy . Base = = NULL ) {
HighBuddy . Base = Base ;
}
AddRangeToBuddy ( & HighBuddy , Base , Size ) ;
2020-04-11 21:59:39 +00:00
}
2020-08-31 20:47:52 +00:00
if ( MemoryLength < AlignUpwards ( ( size_t ) Base + Size , PAGE_SIZE ) / PAGE_SIZE ) {
MemoryLength = AlignUpwards ( ( size_t ) Base + Size , PAGE_SIZE ) / PAGE_SIZE ;
}
2020-04-11 21:59:39 +00:00
}
2020-08-31 20:47:52 +00:00
directptr_t PhysAllocateLowMem ( size_t Size ) {
directptr_t Pointer = BuddyAllocate ( & LowBuddy , Size ) ;
ASSERT ( Pointer ! = NULL , " PhysAllocateLowMem: Allocation failed! " ) ;
return Pointer ;
2020-02-06 20:20:58 +00:00
}
2020-08-31 20:47:52 +00:00
directptr_t PhysAllocateMem ( size_t Size ) {
directptr_t Pointer = NULL ;
2020-09-25 15:47:10 +00:00
if ( HighBuddy . Base = = 0 ) {
2020-11-09 18:43:59 +00:00
//SerialPrintf("Attempting allocation into high memory.\n");
2020-08-31 20:47:52 +00:00
Pointer = BuddyAllocate ( & HighBuddy , Size ) ;
2020-09-25 15:47:10 +00:00
}
2020-08-31 20:47:52 +00:00
2020-09-25 15:47:10 +00:00
if ( Pointer = = NULL ) {
2020-11-09 18:43:59 +00:00
//SerialPrintf("Attempting allocation into low memory.\n");
2020-08-31 20:47:52 +00:00
Pointer = BuddyAllocate ( & LowBuddy , Size ) ;
2020-09-25 15:47:10 +00:00
}
2020-08-31 20:47:52 +00:00
ASSERT ( Pointer ! = NULL , " PhysAllocateMem: Unable to allocate memory! " ) ;
return Pointer ;
2020-02-06 20:20:58 +00:00
}
2020-08-31 20:47:52 +00:00
directptr_t PhysAllocateZeroMem ( size_t Size ) {
directptr_t Pointer = PhysAllocateMem ( Size ) ;
memset ( Pointer , 0 , Size ) ;
return Pointer ;
}
directptr_t PhysAllocateLowZeroMem ( size_t Size ) {
directptr_t Pointer = PhysAllocateLowMem ( Size ) ;
memset ( Pointer , 0 , Size ) ;
return Pointer ;
2020-02-06 20:20:58 +00:00
}
2020-08-31 20:47:52 +00:00
void PhysFreeMem ( directptr_t Pointer , size_t Size ) {
2021-03-17 01:23:36 +00:00
//ASSERT(Pointer >= (directptr_t) DIRECT_REGION, "PhysFreeMem: Attempting to free memory not in the direct mapping region.");
2020-02-06 20:20:58 +00:00
2020-08-31 20:47:52 +00:00
buddy_t * Buddy ;
2021-03-17 01:23:36 +00:00
if ( Pointer < ( void * ) ( LOWER_REGION /* + DIRECT_REGION */ ) )
2020-08-31 20:47:52 +00:00
Buddy = & LowBuddy ;
else
Buddy = & HighBuddy ;
2020-02-06 20:20:58 +00:00
2020-08-31 20:47:52 +00:00
int Order = MAX ( 64 - CLZ ( Size - 1 ) , MIN_ORDER ) ;
AddToBuddyList ( Buddy , Pointer , Order , false ) ;
}
2020-02-06 20:20:58 +00:00
2020-08-31 20:47:52 +00:00
static _Atomic ( uint16_t ) * PageRefCount = NULL ;
2020-02-06 20:20:58 +00:00
2020-08-31 20:47:52 +00:00
void PhysAllocatorInit ( ) {
PageRefCount = PhysAllocateZeroMem ( sizeof ( uint16_t ) * MemoryPages ) ;
}
directptr_t PhysAllocatePage ( ) {
directptr_t Page = PhysAllocateMem ( PAGE_SIZE ) ;
PhysRefPage ( Page ) ;
return Page ;
}
2020-02-06 20:20:58 +00:00
2020-08-31 20:47:52 +00:00
void PhysRefPage ( directptr_t Page ) {
PageRefCount [ ( size_t ) Page > > PAGE_SHIFT ] + + ;
}
2020-02-06 20:20:58 +00:00
2020-08-31 20:47:52 +00:00
void PhysFreePage ( directptr_t Page ) {
if ( - - PageRefCount [ ( size_t ) Page > > PAGE_SHIFT ] = = 0 ) {
PhysFreeMem ( Page , PAGE_SIZE ) ;
2020-02-06 20:20:58 +00:00
}
}
void * memcpy ( void * dest , void const * src , size_t len ) {
unsigned char * dst = ( unsigned char * ) dest ;
const unsigned char * source = ( const unsigned char * ) src ;
for ( size_t i = 0 ; i < len ; i + + ) {
dst [ i ] = source [ i ] ;
}
return dest ;
}
void * memset ( void * dst , int src , size_t len ) {
unsigned char * buf = ( unsigned char * ) dst ;
for ( size_t i = 0 ; i < len ; i + + ) {
buf [ i ] = ( unsigned char ) src ;
}
return dst ;
}