feat(mm): add bitmap physical frame allocator
This commit is contained in:
1 parent
371b50a3a5
commit
ef45af5077
2 files changed
+183
No files matched your search
@@ -0,0 +1,18 @@
|
||||
#ifndef FROSTBYTE_PMM_H
|
||||
#define FROSTBYTE_PMM_H
|
||||
|
||||
#include "types.h"
|
||||
|
||||
#define frameSize 4096
|
||||
|
||||
void pmmInit(uint64 multibootInfo, uint64 protectedEnd);
|
||||
uint64 pmmAlloc(void);
|
||||
void pmmFree(uint64 frame);
|
||||
void pmmReserve(uint64 start, uint64 size);
|
||||
uint64 pmmReservedEnd(void);
|
||||
uint64 pmmTotalFrames(void);
|
||||
uint64 pmmUsedFrames(void);
|
||||
uint64 pmmFreeFrames(void);
|
||||
uint64 pmmTotalBytes(void);
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,165 @@
|
||||
#include "pmm.h"
|
||||
#include "multiboot2.h"
|
||||
#include "string.h"
|
||||
|
||||
extern uint8 kernelPhysEnd[];
|
||||
|
||||
static uint8* bitmap;
|
||||
static uint64 frameCount;
|
||||
static uint64 usedFrames;
|
||||
static uint64 totalMemoryBytes;
|
||||
static uint64 reservedEnd;
|
||||
static uint64 allocHint;
|
||||
|
||||
static void markUsed(uint64 frame)
|
||||
{
|
||||
if (frame >= frameCount)
|
||||
return;
|
||||
uint64 index = frame / 8;
|
||||
uint8 bit = (uint8)(1 << (frame % 8));
|
||||
if (!(bitmap[index] & bit)) {
|
||||
bitmap[index] |= bit;
|
||||
usedFrames++;
|
||||
}
|
||||
}
|
||||
|
||||
static void markFree(uint64 frame)
|
||||
{
|
||||
if (frame >= frameCount)
|
||||
return;
|
||||
uint64 index = frame / 8;
|
||||
uint8 bit = (uint8)(1 << (frame % 8));
|
||||
if (bitmap[index] & bit) {
|
||||
bitmap[index] &= (uint8)~bit;
|
||||
usedFrames--;
|
||||
}
|
||||
}
|
||||
|
||||
static bool isUsed(uint64 frame)
|
||||
{
|
||||
return (bitmap[frame / 8] & (1 << (frame % 8))) != 0;
|
||||
}
|
||||
|
||||
static uint64 alignUp(uint64 value, uint64 alignment)
|
||||
{
|
||||
return (value + alignment - 1) & ~(alignment - 1);
|
||||
}
|
||||
|
||||
void pmmReserve(uint64 start, uint64 size)
|
||||
{
|
||||
uint64 first = start / frameSize;
|
||||
uint64 last = (start + size + frameSize - 1) / frameSize;
|
||||
for (uint64 frame = first; frame < last; frame++)
|
||||
markUsed(frame);
|
||||
}
|
||||
|
||||
uint64 pmmReservedEnd(void)
|
||||
{
|
||||
return reservedEnd;
|
||||
}
|
||||
|
||||
void pmmInit(uint64 multibootInfo, uint64 protectedEnd)
|
||||
{
|
||||
uint32 totalSize = *(uint32*)multibootInfo;
|
||||
uint64 tagAddr = multibootInfo + 8;
|
||||
uint64 endAddr = multibootInfo + totalSize;
|
||||
|
||||
MultibootTagMmap* mmap = nullptr;
|
||||
uint64 highestAddr = 0;
|
||||
|
||||
while (tagAddr < endAddr) {
|
||||
MultibootTag* tag = (MultibootTag*)tagAddr;
|
||||
if (tag->type == multibootTagTypeEnd)
|
||||
break;
|
||||
if (tag->type == multibootTagTypeMmap)
|
||||
mmap = (MultibootTagMmap*)tag;
|
||||
tagAddr = alignUp(tagAddr + tag->size, 8);
|
||||
}
|
||||
|
||||
if (mmap) {
|
||||
uint64 entryAddr = (uint64)mmap->entries;
|
||||
uint64 mmapEnd = (uint64)mmap + mmap->size;
|
||||
while (entryAddr < mmapEnd) {
|
||||
MultibootMmapEntry* entry = (MultibootMmapEntry*)entryAddr;
|
||||
if (entry->type == multibootMemoryAvailable) {
|
||||
uint64 regionEnd = entry->baseAddr + entry->length;
|
||||
totalMemoryBytes += entry->length;
|
||||
if (regionEnd > highestAddr)
|
||||
highestAddr = regionEnd;
|
||||
}
|
||||
entryAddr += mmap->entrySize;
|
||||
}
|
||||
}
|
||||
|
||||
if (highestAddr == 0)
|
||||
highestAddr = 128 * 1024 * 1024;
|
||||
|
||||
frameCount = highestAddr / frameSize;
|
||||
|
||||
uint64 bitmapAnchor = (uint64)kernelPhysEnd;
|
||||
if (protectedEnd > bitmapAnchor)
|
||||
bitmapAnchor = protectedEnd;
|
||||
bitmap = (uint8*)alignUp(bitmapAnchor, frameSize);
|
||||
uint64 bitmapBytes = (frameCount + 7) / 8;
|
||||
memset(bitmap, 0xFF, bitmapBytes);
|
||||
usedFrames = frameCount;
|
||||
|
||||
if (mmap) {
|
||||
uint64 entryAddr = (uint64)mmap->entries;
|
||||
uint64 mmapEnd = (uint64)mmap + mmap->size;
|
||||
while (entryAddr < mmapEnd) {
|
||||
MultibootMmapEntry* entry = (MultibootMmapEntry*)entryAddr;
|
||||
if (entry->type == multibootMemoryAvailable) {
|
||||
uint64 first = alignUp(entry->baseAddr, frameSize) / frameSize;
|
||||
uint64 last = (entry->baseAddr + entry->length) / frameSize;
|
||||
for (uint64 frame = first; frame < last; frame++)
|
||||
markFree(frame);
|
||||
}
|
||||
entryAddr += mmap->entrySize;
|
||||
}
|
||||
}
|
||||
|
||||
reservedEnd = alignUp((uint64)bitmap + bitmapBytes, frameSize);
|
||||
pmmReserve(0, reservedEnd);
|
||||
allocHint = reservedEnd / frameSize;
|
||||
}
|
||||
|
||||
uint64 pmmAlloc(void)
|
||||
{
|
||||
for (uint64 offset = 0; offset < frameCount; offset++) {
|
||||
uint64 frame = allocHint + offset;
|
||||
if (frame >= frameCount)
|
||||
frame -= frameCount;
|
||||
if (!isUsed(frame)) {
|
||||
markUsed(frame);
|
||||
allocHint = frame + 1;
|
||||
return frame * frameSize;
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
void pmmFree(uint64 frame)
|
||||
{
|
||||
markFree(frame / frameSize);
|
||||
}
|
||||
|
||||
uint64 pmmTotalFrames(void)
|
||||
{
|
||||
return frameCount;
|
||||
}
|
||||
|
||||
uint64 pmmUsedFrames(void)
|
||||
{
|
||||
return usedFrames;
|
||||
}
|
||||
|
||||
uint64 pmmFreeFrames(void)
|
||||
{
|
||||
return frameCount - usedFrames;
|
||||
}
|
||||
|
||||
uint64 pmmTotalBytes(void)
|
||||
{
|
||||
return totalMemoryBytes;
|
||||
}
|
||||
Reference in new issue
Block a user