...
This commit is contained in:
@@ -1,55 +1,8 @@
|
|||||||
#include "console.h"
|
#include "console.h"
|
||||||
#include "multiboot2.h"
|
#include "pmm.h"
|
||||||
|
|
||||||
#include <def.h>
|
|
||||||
#include "console.h"
|
|
||||||
#include "multiboot2.h"
|
|
||||||
#include "panic.h"
|
|
||||||
#include "util.h"
|
|
||||||
|
|
||||||
#define MAX_REGIONS 64
|
|
||||||
|
|
||||||
typedef struct {
|
|
||||||
u64 base_addr;
|
|
||||||
u64 length;
|
|
||||||
} memory_region;
|
|
||||||
|
|
||||||
extern uptr kernel_start;
|
|
||||||
extern uptr kernel_end;
|
|
||||||
|
|
||||||
static memory_region memory_regions[MAX_REGIONS] = {0};
|
|
||||||
static size_t memory_region_count = 0;
|
|
||||||
|
|
||||||
static void find_memory_regions() {
|
|
||||||
multiboot_tag_mmap *tag = multiboot_get_mmap();
|
|
||||||
if (tag == NULL) {
|
|
||||||
boot_panic("Multiboot did not provide mmap tag");
|
|
||||||
}
|
|
||||||
|
|
||||||
u32 entry_count = (tag->size - 16) / tag->entry_size;
|
|
||||||
u8 *entry_ptr = (u8*)tag->entries;
|
|
||||||
|
|
||||||
for (u32 i = 0; i < entry_count; ++i) {
|
|
||||||
multiboot_mmap_entry *entry = (multiboot_mmap_entry*)entry_ptr;
|
|
||||||
|
|
||||||
if (entry->type == MULTIBOOT_MEMORY_AVAILABLE) {
|
|
||||||
if (memory_region_count >= MAX_REGIONS) {
|
|
||||||
boot_panic("Too many memory regions");
|
|
||||||
}
|
|
||||||
|
|
||||||
memory_regions[memory_region_count++] = (memory_region){ entry->base_addr, entry->length };
|
|
||||||
}
|
|
||||||
|
|
||||||
entry_ptr += tag->entry_size;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// We are now in long mode with kernel pages and vga buffer identity mapped
|
// We are now in long mode with kernel pages and vga buffer identity mapped
|
||||||
void x86_64_main() {
|
void x86_64_main() {
|
||||||
console_clear();
|
console_clear();
|
||||||
find_memory_regions();
|
pmm_init();
|
||||||
|
|
||||||
for (u32 i = 0; i < memory_region_count; ++i) {
|
|
||||||
kprintf("region: base_addr=0x%X, length=0x%X\n", memory_regions[i].base_addr, memory_regions[i].length);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
@@ -1,4 +1,5 @@
|
|||||||
#include "multiboot2.h"
|
#include "multiboot2.h"
|
||||||
|
#include "symbols.h"
|
||||||
|
|
||||||
// [size:4][reserved:4][data:N]
|
// [size:4][reserved:4][data:N]
|
||||||
#define INFO_DATA_OFFSET 8
|
#define INFO_DATA_OFFSET 8
|
||||||
@@ -6,10 +7,8 @@
|
|||||||
#define TAG_TYPE_OFFSET 0
|
#define TAG_TYPE_OFFSET 0
|
||||||
#define TAG_SIZE_OFFSET 4
|
#define TAG_SIZE_OFFSET 4
|
||||||
|
|
||||||
extern u8 multiboot_info[];
|
|
||||||
|
|
||||||
void *multiboot_get_tag(u32 type) {
|
void *multiboot_get_tag(u32 type) {
|
||||||
uptr current = (uptr)&multiboot_info + INFO_DATA_OFFSET;
|
uptr current = get_multiboot_info() + INFO_DATA_OFFSET;
|
||||||
|
|
||||||
while (true) {
|
while (true) {
|
||||||
u32 tag_type = *(u32*)(current + TAG_TYPE_OFFSET);
|
u32 tag_type = *(u32*)(current + TAG_TYPE_OFFSET);
|
||||||
@@ -24,7 +23,7 @@ void *multiboot_get_tag(u32 type) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// note(nub31): Each tag is aligned to 8 bytes
|
// note(nub31): Each tag is aligned to 8 bytes
|
||||||
current = align_up(current + tag_size, 8);
|
current = ALIGN_UP(current + tag_size, 8);
|
||||||
}
|
}
|
||||||
|
|
||||||
return NULL;
|
return NULL;
|
||||||
|
|||||||
@@ -265,6 +265,10 @@ static inline multiboot_tag_mmap *multiboot_get_mmap() {
|
|||||||
return multiboot_get_tag(MULTIBOOT_TAG_TYPE_MMAP);
|
return multiboot_get_tag(MULTIBOOT_TAG_TYPE_MMAP);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static inline size_t get_mmap_entry_count(multiboot_tag_mmap *mmap) {
|
||||||
|
return (mmap->size - 16) / mmap->entry_size;
|
||||||
|
}
|
||||||
|
|
||||||
static inline multiboot_tag_vbe *multiboot_get_vbe() {
|
static inline multiboot_tag_vbe *multiboot_get_vbe() {
|
||||||
return multiboot_get_tag(MULTIBOOT_TAG_TYPE_VBE);
|
return multiboot_get_tag(MULTIBOOT_TAG_TYPE_VBE);
|
||||||
}
|
}
|
||||||
|
|||||||
116
src/boot/pmm.c
Normal file
116
src/boot/pmm.c
Normal file
@@ -0,0 +1,116 @@
|
|||||||
|
#include "pmm.h"
|
||||||
|
#include "util.h"
|
||||||
|
#include "panic.h"
|
||||||
|
#include "multiboot2.h"
|
||||||
|
#include "symbols.h"
|
||||||
|
#include <def.h>
|
||||||
|
|
||||||
|
#define PAGE_SIZE 4096
|
||||||
|
#define MAX_PHYS_MEM GiB(128)
|
||||||
|
#define MAX_PAGES (MAX_PHYS_MEM / PAGE_SIZE)
|
||||||
|
#define BITMAP_SIZE ((MAX_PAGES + 63) / 64)
|
||||||
|
|
||||||
|
static u64 pmm_bitmap[BITMAP_SIZE];
|
||||||
|
|
||||||
|
static inline void bitmap_set(size_t bit) {
|
||||||
|
pmm_bitmap[bit / 64] |= (U64_C(1) << (bit % 64));
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline void bitmap_clear(size_t bit) {
|
||||||
|
pmm_bitmap[bit / 64] &= ~(U64_C(1) << (bit % 64));
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline int bitmap_test(size_t bit) {
|
||||||
|
return pmm_bitmap[bit / 64] & (U64_C(1) << (bit % 64));
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline size_t to_page(uptr addr) {
|
||||||
|
if (addr % PAGE_SIZE != 0) {
|
||||||
|
boot_panic("Address is not page aligned");
|
||||||
|
}
|
||||||
|
|
||||||
|
return addr / PAGE_SIZE;
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline uptr to_addr(size_t page) {
|
||||||
|
return page * PAGE_SIZE;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void clear_range(size_t start_page, size_t end_page) {
|
||||||
|
if (start_page >= MAX_PAGES) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (end_page > MAX_PAGES) {
|
||||||
|
end_page = MAX_PAGES;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (size_t j = start_page; j < end_page; ++j) {
|
||||||
|
bitmap_clear(j);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void set_range(size_t start_page, size_t end_page) {
|
||||||
|
if (start_page >= MAX_PAGES) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (end_page > MAX_PAGES) {
|
||||||
|
end_page = MAX_PAGES;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (size_t j = start_page; j < end_page; ++j) {
|
||||||
|
bitmap_set(j);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void pmm_init() {
|
||||||
|
for (size_t i = 0; i < BITMAP_SIZE; i++) {
|
||||||
|
pmm_bitmap[i] = U64_MAX;
|
||||||
|
}
|
||||||
|
|
||||||
|
multiboot_tag_mmap *mmap = multiboot_get_mmap();
|
||||||
|
if (mmap == NULL) {
|
||||||
|
boot_panic("No memory map found");
|
||||||
|
}
|
||||||
|
|
||||||
|
for (size_t i = 0; i < get_mmap_entry_count(mmap); ++i) {
|
||||||
|
multiboot_mmap_entry entry = mmap->entries[i];
|
||||||
|
if (entry.type == MULTIBOOT_MEMORY_AVAILABLE) {
|
||||||
|
size_t start_page = to_page(ALIGN_DOWN(entry.base_addr, PAGE_SIZE));
|
||||||
|
size_t end_page = to_page(ALIGN_UP(entry.base_addr + entry.length, PAGE_SIZE));
|
||||||
|
|
||||||
|
clear_range(start_page, end_page);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
size_t start_page = to_page(ALIGN_DOWN(get_kernel_start(), PAGE_SIZE));
|
||||||
|
size_t end_page = to_page(ALIGN_UP(get_kernel_end(), PAGE_SIZE));
|
||||||
|
|
||||||
|
set_range(start_page, end_page);
|
||||||
|
}
|
||||||
|
|
||||||
|
void *pmm_alloc_page() {
|
||||||
|
for (size_t i = 0; i < MAX_PAGES; ++i) {
|
||||||
|
if (!bitmap_test(i)) {
|
||||||
|
bitmap_set(i);
|
||||||
|
return (void*)to_addr(i);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
boot_panic("Out of physical memory");
|
||||||
|
}
|
||||||
|
|
||||||
|
void pmm_free_page(void *addr) {
|
||||||
|
size_t page = to_page((uptr)addr);
|
||||||
|
|
||||||
|
if (page >= MAX_PAGES) {
|
||||||
|
boot_panic("Trying to free page beyond physical memory limit");
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!bitmap_test(page)) {
|
||||||
|
boot_panic("Page is already free");
|
||||||
|
}
|
||||||
|
|
||||||
|
bitmap_clear(page);
|
||||||
|
}
|
||||||
3
src/boot/pmm.h
Normal file
3
src/boot/pmm.h
Normal file
@@ -0,0 +1,3 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
void pmm_init();
|
||||||
19
src/boot/symbols.c
Normal file
19
src/boot/symbols.c
Normal file
@@ -0,0 +1,19 @@
|
|||||||
|
#include "symbols.h"
|
||||||
|
|
||||||
|
extern u8 kernel_start[];
|
||||||
|
|
||||||
|
uptr get_kernel_start() {
|
||||||
|
return (uptr)&kernel_start;
|
||||||
|
}
|
||||||
|
|
||||||
|
extern u8 kernel_end[];
|
||||||
|
|
||||||
|
uptr get_kernel_end() {
|
||||||
|
return (uptr)&kernel_end;
|
||||||
|
}
|
||||||
|
|
||||||
|
extern u8 multiboot_info[];
|
||||||
|
|
||||||
|
uptr get_multiboot_info() {
|
||||||
|
return (uptr)&multiboot_info;
|
||||||
|
}
|
||||||
7
src/boot/symbols.h
Normal file
7
src/boot/symbols.h
Normal file
@@ -0,0 +1,7 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <def.h>
|
||||||
|
|
||||||
|
uptr get_kernel_start();
|
||||||
|
uptr get_kernel_end();
|
||||||
|
uptr get_multiboot_info();
|
||||||
@@ -1,12 +1,9 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
static inline uptr align_up(uptr value, size_t alignment) {
|
#include <def.h>
|
||||||
return (value + alignment - 1) / alignment * alignment;
|
|
||||||
}
|
|
||||||
|
|
||||||
static inline uptr align_down(uptr value, size_t alignment) {
|
#define ALIGN_UP(value, alignment) ((value + alignment - 1) / alignment * alignment)
|
||||||
return value - (value % alignment);
|
#define ALIGN_DOWN(value, alignment) (value - (value % alignment))
|
||||||
}
|
|
||||||
|
|
||||||
static inline void hlt() {
|
static inline void hlt() {
|
||||||
asm("hlt");
|
asm("hlt");
|
||||||
|
|||||||
Reference in New Issue
Block a user