188 lines
4.8 KiB
C
188 lines
4.8 KiB
C
#include <lcrash/mm/kmalloc.h>
|
|
|
|
#include <lcrash/mm/phys.h>
|
|
|
|
/**
|
|
* A block in the kernel heap. the performance is abysmal, this structure may be larger
|
|
* than a lot of kernel objects so we'll have about half the memory we could have ^-^
|
|
*/
|
|
struct KernelHeapBlock {
|
|
/// Next block
|
|
struct KernelHeapBlock* Next;
|
|
|
|
/// Previous block
|
|
struct KernelHeapBlock* Prev;
|
|
|
|
/// Next free block
|
|
struct KernelHeapBlock* NextFree;
|
|
|
|
/// Previous free block
|
|
struct KernelHeapBlock* PrevFree;
|
|
|
|
/// Block size
|
|
u64 Size;
|
|
|
|
/// Block is free
|
|
bool Free;
|
|
};
|
|
|
|
/**
|
|
* A structure that describes a specific kernel heap, yes, we can have more than one and,
|
|
* yes, most will do the same thing
|
|
*/
|
|
struct KernelHeapZone {
|
|
/// Next heap zone
|
|
struct KernelHeapZone* Next;
|
|
|
|
/// Previous heap zone
|
|
struct KernelHeapZone* Prev;
|
|
|
|
/// First heap frame
|
|
struct KernelHeapFrame* FirstFrame;
|
|
|
|
/// Last heap frame
|
|
struct KernelHeapFrame* LastFrame;
|
|
|
|
/// First block
|
|
struct KernelHeapBlock* First;
|
|
|
|
/// Last block
|
|
struct KernelHeapBlock* Last;
|
|
|
|
/// First free block
|
|
struct KernelHeapBlock* FirstFree;
|
|
|
|
/// Last free block
|
|
struct KernelHeapBlock* LastFree;
|
|
};
|
|
|
|
/**
|
|
* A block of physical memory owned by a specific heap, where is it stored exactly? In
|
|
* the heap of course!
|
|
*/
|
|
struct KernelHeapFrame {
|
|
/// The block
|
|
struct PmemAllocation Block;
|
|
|
|
/// The block's size
|
|
u64 Size;
|
|
|
|
/// Linked list jumpscare
|
|
struct KernelHeapFrame* NextFrame;
|
|
|
|
/// I wonder if this is a pointer that points to the previous frame in a linked
|
|
/// list of the structure which stores kernel heap frames
|
|
struct KernelHeapFrame* PrevFrame;
|
|
};
|
|
|
|
struct KernelHeapZone* KernelHeapFirst = 0;
|
|
struct KernelHeapZone* KernelHeapLast = 0;
|
|
|
|
/**
|
|
* \todo Maybe split the zone allocation code out of the thing
|
|
*/
|
|
int KernelHeapInitialize() {
|
|
// Allocate uh this amount of memory for the heap
|
|
struct PmemAllocation Block;
|
|
if (PmemAllocateBlock(0x100000, &Block)) return -1;
|
|
|
|
// Make our zone
|
|
struct KernelHeapZone* Zone = Block.Address;
|
|
Zone->Next = 0;
|
|
Zone->Prev = 0;
|
|
KernelHeapFirst = Zone;
|
|
KernelHeapLast = Zone;
|
|
|
|
// Make the frame block
|
|
struct KernelHeapBlock* FrameBlock = Block.Address + sizeof(struct KernelHeapZone);
|
|
FrameBlock->Prev = 0;
|
|
FrameBlock->PrevFree = 0;
|
|
FrameBlock->Size = sizeof(struct KernelHeapFrame);
|
|
FrameBlock->Free = false;
|
|
|
|
// Make the frame structure
|
|
struct KernelHeapFrame* Frame = Block.Address
|
|
+ sizeof(struct KernelHeapZone)
|
|
+ sizeof(struct KernelHeapBlock);
|
|
Frame->Block = Block;
|
|
Frame->Size = 0x100000;
|
|
Frame->NextFrame = 0;
|
|
Frame->PrevFrame = 0;
|
|
|
|
// Make the root block
|
|
struct KernelHeapBlock* RootBlock = (struct KernelHeapBlock*)((void*)Frame + sizeof(struct KernelHeapFrame));
|
|
RootBlock->Prev = FrameBlock;
|
|
FrameBlock->Next = RootBlock;
|
|
FrameBlock->NextFree = RootBlock;
|
|
RootBlock->Next = 0;
|
|
RootBlock->PrevFree = 0;
|
|
RootBlock->NextFree = 0;
|
|
RootBlock->Free = true;
|
|
RootBlock->Size = 0x100000
|
|
- sizeof(struct KernelHeapZone)
|
|
- sizeof(struct KernelHeapBlock)
|
|
- sizeof(struct KernelHeapFrame)
|
|
- sizeof(struct KernelHeapBlock);
|
|
|
|
// Fill out the rest of the zone
|
|
Zone->FirstFrame = Frame;
|
|
Zone->LastFrame = Frame;
|
|
Zone->FirstFree = RootBlock;
|
|
Zone->LastFree = RootBlock;
|
|
Zone->First = FrameBlock;
|
|
Zone->Last = RootBlock;
|
|
|
|
// Tada!
|
|
return 0;
|
|
}
|
|
|
|
void* KernelHeapAlloc(u32 Size, u32 Flags) {
|
|
// Find a free block
|
|
for (struct KernelHeapZone* Zone = KernelHeapFirst; Zone != 0; Zone = Zone->Next) {
|
|
for (struct KernelHeapBlock* Block = Zone->FirstFree; Block != 0; Block = Block->NextFree) {
|
|
if (Block->Size >= Size) {
|
|
s64 SplitSize = (s64)Block->Size - Size - (sizeof(struct KernelHeapBlock) * 2) - 8;
|
|
|
|
if (SplitSize > 0) {
|
|
struct KernelHeapBlock* NewBlock = (struct KernelHeapBlock*)((void*)Block + sizeof(struct KernelHeapBlock) + Size);
|
|
NewBlock->Prev = Block;
|
|
NewBlock->Next = 0;
|
|
NewBlock->PrevFree = Block->PrevFree;
|
|
NewBlock->NextFree = Block->NextFree;
|
|
NewBlock->Free = true;
|
|
NewBlock->Size = (u64)SplitSize;
|
|
|
|
// Set zone stuff
|
|
if (Block->NextFree == 0) Zone->LastFree = NewBlock;
|
|
if (Block->PrevFree == 0) Zone->FirstFree = NewBlock;
|
|
if (Block->Next == 0) Zone->Last = NewBlock;
|
|
|
|
// Set next free in other blocks
|
|
for (struct KernelHeapBlock* ModBlock = Block->Prev; ModBlock != 0 && (Block->NextFree != 0 || Block->NextFree != Block); ModBlock = ModBlock->Prev) {
|
|
ModBlock->NextFree = NewBlock;
|
|
}
|
|
|
|
// Set prev free in other blocks
|
|
for (struct KernelHeapBlock* ModBlock = Block->Next; ModBlock != 0 && (Block->PrevFree != 0 || Block->PrevFree != Block); ModBlock = ModBlock->Next) {
|
|
ModBlock->PrevFree = NewBlock;
|
|
}
|
|
|
|
// Block stuff
|
|
Block->Next = NewBlock;
|
|
}
|
|
|
|
Block->Free = 0;
|
|
Block->Size = Size;
|
|
|
|
return (void*)Block + sizeof(struct KernelHeapBlock);
|
|
}
|
|
}
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
void KernelHeapFree(void* Address) {
|
|
|
|
}
|