Attempt 2 #2

Open
seeseemelk wants to merge 56 commits from attempt-2 into master
5 changed files with 199 additions and 0 deletions
Showing only changes of commit cf3059747a - Show all commits

View File

@@ -7,6 +7,7 @@ add_executable(kernel
idt.c idt.c
isr.c isr.c
pic.c pic.c
pmm.c
interrupts.S interrupts.S
kernel.c kernel.c
) )

View File

@@ -5,6 +5,7 @@
#include "idt.h" #include "idt.h"
#include "pic.h" #include "pic.h"
#include "port_io.h" #include "port_io.h"
#include "pmm.h"
void offset_print(const char *str) void offset_print(const char *str)
{ {
@@ -46,6 +47,17 @@ void kernel_main(uint32_t magic, uint32_t addr) {
init_pic(); init_pic();
offset_print("PIC initialized\n"); offset_print("PIC initialized\n");
init_pmm(addr);
offset_print("PMM initialized\n");
phys_addr_t p1 = pmm_alloc_page(PMM_ZONE_NORMAL);
offset_print("Allocated page at: ");
print_hex(p1);
phys_addr_t p2 = pmm_alloc_page(PMM_ZONE_DMA);
offset_print("Allocated DMA page at: ");
print_hex(p2);
/* Enable interrupts */ /* Enable interrupts */
asm volatile("sti"); asm volatile("sti");

View File

@@ -4,6 +4,8 @@ SECTIONS
{ {
. = 1M; . = 1M;
_kernel_start = .;
.text BLOCK(4K) : ALIGN(4K) .text BLOCK(4K) : ALIGN(4K)
{ {
KEEP(*(.multiboot)) KEEP(*(.multiboot))
@@ -25,4 +27,6 @@ SECTIONS
*(COMMON) *(COMMON)
*(.bss) *(.bss)
} }
_kernel_end = .;
} }

146
src/pmm.c Normal file
View File

@@ -0,0 +1,146 @@
#include "pmm.h"
#include <multiboot2.h>
extern uint32_t _kernel_start;
extern uint32_t _kernel_end;
#define MAX_PHYSICAL_MEMORY 0xFFFFFFFF // 4GB
#define BITMAP_SIZE (MAX_PHYSICAL_MEMORY / PAGE_SIZE / 32)
#define FRAMES_PER_INDEX 32
static uint32_t memory_bitmap[BITMAP_SIZE];
static uint32_t memory_size = 0;
// static uint32_t used_frames = 0; // Unused for now
static void set_frame(phys_addr_t frame_addr) {
uint32_t frame = frame_addr / PAGE_SIZE;
uint32_t idx = frame / FRAMES_PER_INDEX;
uint32_t off = frame % FRAMES_PER_INDEX;
memory_bitmap[idx] |= (1 << off);
}
static void clear_frame(phys_addr_t frame_addr) {
uint32_t frame = frame_addr / PAGE_SIZE;
uint32_t idx = frame / FRAMES_PER_INDEX;
uint32_t off = frame % FRAMES_PER_INDEX;
memory_bitmap[idx] &= ~(1 << off);
}
static uint32_t first_free_frame(size_t start_frame, size_t end_frame) {
for (size_t i = start_frame; i < end_frame; i++) {
uint32_t idx = i / FRAMES_PER_INDEX;
uint32_t off = i % FRAMES_PER_INDEX;
if (!(memory_bitmap[idx] & (1 << off))) {
return i;
}
}
return (uint32_t)-1;
}
void init_pmm(uint32_t multiboot_addr) {
struct multiboot_tag *tag;
uint32_t addr = multiboot_addr;
/* Initialize all memory as used (1) initially */
for (int i = 0; i < BITMAP_SIZE; i++) {
memory_bitmap[i] = 0xFFFFFFFF;
}
if (addr & 7) {
// offset_print("Multiboot alignment error\n"); // Need offset_print here? No, kernel handles prints
return; // Alignment issue
}
uint32_t size = *(uint32_t *)addr;
for (tag = (struct multiboot_tag *)(addr + 8);
tag->type != MULTIBOOT_TAG_TYPE_END;
tag = (struct multiboot_tag *)((multiboot_uint8_t *)tag + ((tag->size + 7) & ~7))) {
if (tag->type == MULTIBOOT_TAG_TYPE_BASIC_MEMINFO) {
struct multiboot_tag_basic_meminfo *meminfo = (struct multiboot_tag_basic_meminfo *)tag;
memory_size = meminfo->mem_upper;
} else if (tag->type == MULTIBOOT_TAG_TYPE_MMAP) {
multiboot_memory_map_t *mmap;
struct multiboot_tag_mmap *tag_mmap = (struct multiboot_tag_mmap *)tag;
for (mmap = tag_mmap->entries;
(multiboot_uint8_t *)mmap < (multiboot_uint8_t *)tag + tag->size;
mmap = (multiboot_memory_map_t *)((unsigned long)mmap + tag_mmap->entry_size)) {
if (mmap->type == MULTIBOOT_MEMORY_AVAILABLE) {
uint64_t start = mmap->addr;
uint64_t len = mmap->len;
uint64_t end = start + len;
if (start % PAGE_SIZE != 0) {
start = (start + PAGE_SIZE) & ~(PAGE_SIZE - 1);
}
for (uint64_t addr_iter = start; addr_iter < end; addr_iter += PAGE_SIZE) {
if (addr_iter + PAGE_SIZE <= end && addr_iter < MAX_PHYSICAL_MEMORY) {
clear_frame((phys_addr_t)addr_iter);
}
}
}
}
}
}
uint32_t kstart = (uint32_t)&_kernel_start;
uint32_t kend = (uint32_t)&_kernel_end;
kstart &= ~(PAGE_SIZE - 1);
kend = (kend + PAGE_SIZE - 1) & ~(PAGE_SIZE - 1);
for (uint32_t i = kstart; i < kend; i += PAGE_SIZE) {
set_frame(i);
}
// Mark multiboot structure
uint32_t mb_start = multiboot_addr;
uint32_t mb_end = multiboot_addr + size;
mb_start &= ~(PAGE_SIZE - 1);
mb_end = (mb_end + PAGE_SIZE - 1) & ~(PAGE_SIZE - 1);
for (uint32_t i = mb_start; i < mb_end; i += PAGE_SIZE) {
set_frame(i);
}
// Mark first page as used to avoid returning 0 (NULL)
set_frame(0);
}
phys_addr_t pmm_alloc_page(pmm_zone_t zone) {
uint32_t start_frame = 0;
uint32_t end_frame = BITMAP_SIZE * FRAMES_PER_INDEX;
uint32_t frame = (uint32_t)-1;
// 16MB boundary is at 16*1024*1024 / 4096 = 4096 frames
uint32_t dma_limit = 4096;
if (zone == PMM_ZONE_DMA) {
end_frame = dma_limit;
frame = first_free_frame(start_frame, end_frame);
} else {
start_frame = dma_limit;
frame = first_free_frame(start_frame, end_frame);
// Fallback to DMA if NORMAL failed
if (frame == (uint32_t)-1) {
frame = first_free_frame(0, dma_limit);
}
}
if (frame != (uint32_t)-1) {
phys_addr_t addr = frame * PAGE_SIZE;
set_frame(addr);
return addr;
}
return 0; // OOM
}
void pmm_free_page(phys_addr_t addr) {
clear_frame(addr);
}

36
src/pmm.h Normal file
View File

@@ -0,0 +1,36 @@
#ifndef PMM_H
#define PMM_H
#include <stdint.h>
#include <stddef.h>
#define PAGE_SIZE 4096
typedef uintptr_t phys_addr_t;
typedef enum {
PMM_ZONE_DMA, // < 16 MB
PMM_ZONE_NORMAL, // Any other memory
PMM_ZONE_HIGHMEM // > 4 GB (if 64-bit or PAE, but we are 32-bit for now) - actually sticking to DMA and NORMAL is enough for 32-bit typically
} pmm_zone_t;
/*
* Initialize the physical memory manager.
* @param multiboot_addr Address of the multiboot info structure
*/
void init_pmm(uint32_t multiboot_addr);
/*
* Allocate a physical page.
* @param zone The preferred zone to allocate from.
* @return Physical address of the allocated page, or 0 if out of memory.
*/
phys_addr_t pmm_alloc_page(pmm_zone_t zone);
/*
* Free a physical page.
* @param addr Physical address of the page to free.
*/
void pmm_free_page(phys_addr_t addr);
#endif