Memory management
This commit is contained in:
parent
5d790cadbb
commit
ec99fbf801
@ -30,17 +30,9 @@ void kmain(uint64_t multiboot_magic, void *multiboot_data)
|
|||||||
|
|
||||||
debug_info("Kernel loaded with command line: \"%s\" by <%s>\n", kernel_boot_data.commandline, kernel_boot_data.bootloader);
|
debug_info("Kernel loaded with command line: \"%s\" by <%s>\n", kernel_boot_data.commandline, kernel_boot_data.bootloader);
|
||||||
|
|
||||||
debug_info("Memory areas:\n");
|
memory_init();
|
||||||
size_t index = 0;
|
|
||||||
uintptr_t start, end;
|
|
||||||
uint32_t type;
|
|
||||||
while(!multiboot_get_memory_area(index++, &start, &end, &type))
|
|
||||||
{
|
|
||||||
debug_info("%d %x-%x\n", type, start, end);
|
|
||||||
}
|
|
||||||
bind_interrupt(0, divbyzero);
|
|
||||||
|
|
||||||
debug("Hello, world!");
|
bind_interrupt(0, divbyzero);
|
||||||
|
|
||||||
// Force a divide by zero error
|
// Force a divide by zero error
|
||||||
divide(5, 0);
|
divide(5, 0);
|
||||||
|
@ -2,31 +2,54 @@
|
|||||||
|
|
||||||
#define KERNEL_OFFSET 0xFFFFFF8000000000
|
#define KERNEL_OFFSET 0xFFFFFF8000000000
|
||||||
|
|
||||||
#ifdef __ASSEMBLER__
|
|
||||||
#define V2P(a) ((a) - KERNEL_OFFSET)
|
|
||||||
#define P2V(a) ((a) + KERNEL_OFFSET)
|
|
||||||
#else
|
|
||||||
#include <stdint.h>
|
|
||||||
#define V2P(a) ((uintptr_t)(a) &~KERNEL_OFFSET)
|
|
||||||
#define P2V(a) ((void *)((uintptr_t)(a) | KERNEL_OFFSET))
|
|
||||||
|
|
||||||
#define incptr(p, n) ((void *)(((uintptr_t)(p)) + (n)))
|
|
||||||
#endif
|
|
||||||
|
|
||||||
|
|
||||||
#define PAGE_PRESENT 0x001
|
#define PAGE_PRESENT 0x001
|
||||||
#define PAGE_WRITE 0x002
|
#define PAGE_WRITE 0x002
|
||||||
|
|
||||||
#define PAGE_SIZE 0x1000
|
#define PAGE_SIZE 0x1000
|
||||||
#define ENTRIES_PER_PT 512
|
#define ENTRIES_PER_PT 512
|
||||||
|
|
||||||
#ifndef __ASSEMBLER__
|
#ifdef __ASSEMBLER__
|
||||||
#include <stddef.h>
|
#define V2P(a) ((a) - KERNEL_OFFSET)
|
||||||
|
#define P2V(a) ((a) + KERNEL_OFFSET)
|
||||||
|
#else
|
||||||
|
#include <stdint.h>
|
||||||
|
#include <stddef.h>
|
||||||
|
#define V2P(a) ((uintptr_t)(a) &~KERNEL_OFFSET)
|
||||||
|
#define P2V(a) ((void *)((uintptr_t)(a) | KERNEL_OFFSET))
|
||||||
|
|
||||||
void *memcpy(void *dst, const void *src, size_t n);
|
#define incptr(p, n) ((void *)(((uintptr_t)(p)) + (n)))
|
||||||
void *memset(void *s, int c, size_t n);
|
|
||||||
void *memmove(void *dest, const void *src, size_t n);
|
#define P1_OFFSET(a) (((a)>>12) & 0x1FF)
|
||||||
int memcmp(const void *s1, const void *s2, size_t n);
|
#define P2_OFFSET(a) (((a)>>21) & 0x1FF)
|
||||||
size_t strlen(const char *s);
|
#define P3_OFFSET(a) (((a)>>30) & 0x1FF)
|
||||||
|
#define P4_OFFSET(a) (((a)>>39) & 0x1FF)
|
||||||
|
|
||||||
|
// memory/memory.c
|
||||||
|
void memory_init();
|
||||||
|
extern uint64_t kernel_P4;
|
||||||
|
|
||||||
|
// memory/vmm.c
|
||||||
|
void vmm_init();
|
||||||
|
uint64_t vmm_get_page(uint64_t P4, uint64_t addr);
|
||||||
|
int vmm_set_page(uint64_t P4, uint64_t addr, uint64_t page, uint16_t flags);
|
||||||
|
void vmm_clear_page(uint64_t P4, uint64_t addr, int free);
|
||||||
|
|
||||||
|
// memory/pmm.c
|
||||||
|
void pmm_free(uint64_t page);
|
||||||
|
uint64_t pmm_alloc();
|
||||||
|
uint64_t pmm_calloc();
|
||||||
|
|
||||||
|
// memory/string.c
|
||||||
|
void *memcpy(void *dst, const void *src, size_t n);
|
||||||
|
void *memset(void *s, int c, size_t n);
|
||||||
|
void *memmove(void *dest, const void *src, size_t n);
|
||||||
|
int memcmp(const void *s1, const void *s2, size_t n);
|
||||||
|
size_t strlen(const char *s);
|
||||||
|
|
||||||
|
// Link.ld
|
||||||
|
extern int kernel_start, kernel_end;
|
||||||
|
|
||||||
|
// boot/boot_PT.s
|
||||||
|
extern uint64_t BootP4;
|
||||||
|
|
||||||
#endif
|
#endif
|
@ -22,6 +22,8 @@ struct kernel_boot_data_st{
|
|||||||
void *mmap;
|
void *mmap;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
#define MMAP_FREE 1
|
||||||
|
|
||||||
extern struct kernel_boot_data_st kernel_boot_data;
|
extern struct kernel_boot_data_st kernel_boot_data;
|
||||||
|
|
||||||
int multiboot_init(uint64_t magic, void *mboot_info);
|
int multiboot_init(uint64_t magic, void *mboot_info);
|
||||||
|
37
src/kernel/memory/memory.c
Normal file
37
src/kernel/memory/memory.c
Normal file
@ -0,0 +1,37 @@
|
|||||||
|
#include <stdint.h>
|
||||||
|
#include <memory.h>
|
||||||
|
#include <debug.h>
|
||||||
|
#include <multiboot.h>
|
||||||
|
|
||||||
|
|
||||||
|
uint64_t kernel_P4;
|
||||||
|
|
||||||
|
void memory_init()
|
||||||
|
{
|
||||||
|
kernel_P4 = (uint64_t)&BootP4;
|
||||||
|
|
||||||
|
uint64_t start, end;
|
||||||
|
uint32_t type, i = 0;
|
||||||
|
debug_info("Parsing memory map\n");
|
||||||
|
while(!multiboot_get_memory_area(i++, &start, &end, &type))
|
||||||
|
{
|
||||||
|
debug("0x%016x-0x%016x (%d)\n", start, end, type);
|
||||||
|
|
||||||
|
for(uint64_t p = start; p < end; p += PAGE_SIZE)
|
||||||
|
{
|
||||||
|
if(p >= V2P(&kernel_start) && p < V2P(&kernel_end))
|
||||||
|
continue;
|
||||||
|
|
||||||
|
uint64_t vaddr = (uint64_t)P2V(p);
|
||||||
|
uint64_t page = vmm_get_page(kernel_P4, vaddr);
|
||||||
|
if(page == (uint64_t)-1 || !(page & PAGE_PRESENT))
|
||||||
|
{
|
||||||
|
uint16_t flags = PAGE_WRITE | PAGE_PRESENT;
|
||||||
|
vmm_set_page(kernel_P4, vaddr, p, flags);
|
||||||
|
}
|
||||||
|
|
||||||
|
if(type == MMAP_FREE)
|
||||||
|
pmm_free(p);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
26
src/kernel/memory/pmm.c
Normal file
26
src/kernel/memory/pmm.c
Normal file
@ -0,0 +1,26 @@
|
|||||||
|
#include <stdint.h>
|
||||||
|
#include <memory.h>
|
||||||
|
|
||||||
|
// Physical address of next page
|
||||||
|
uint64_t next = 0;
|
||||||
|
|
||||||
|
void pmm_free(uint64_t page)
|
||||||
|
{
|
||||||
|
*(uint64_t *)P2V(page) = next;
|
||||||
|
next = page;
|
||||||
|
}
|
||||||
|
|
||||||
|
uint64_t pmm_alloc()
|
||||||
|
{
|
||||||
|
if(!next) return 0;
|
||||||
|
uint64_t page = next;
|
||||||
|
next = *(uint64_t *)P2V(page);
|
||||||
|
return page;
|
||||||
|
}
|
||||||
|
|
||||||
|
uint64_t pmm_calloc()
|
||||||
|
{
|
||||||
|
uint64_t page = pmm_alloc();
|
||||||
|
memset(P2V(page), 0, PAGE_SIZE);
|
||||||
|
return page;
|
||||||
|
}
|
94
src/kernel/memory/vmm.c
Normal file
94
src/kernel/memory/vmm.c
Normal file
@ -0,0 +1,94 @@
|
|||||||
|
#include <stdint.h>
|
||||||
|
#include <memory.h>
|
||||||
|
#include <debug.h>
|
||||||
|
|
||||||
|
#define FLAGS_MASK (PAGE_SIZE-1)
|
||||||
|
#define MASK_FLAGS(addr) ((uint64_t)addr & ~FLAGS_MASK)
|
||||||
|
|
||||||
|
#define PRESENT(p) (p & PAGE_PRESENT)
|
||||||
|
|
||||||
|
#define PT(ptr) ((uint64_t *)P2V(MASK_FLAGS(ptr)))
|
||||||
|
|
||||||
|
#define P4E(P4, addr) (PT(P4)[P4_OFFSET(addr)])
|
||||||
|
#define P3E(P4, addr) (PT(P4E(P4, addr))[P3_OFFSET(addr)])
|
||||||
|
#define P2E(P4, addr) (PT(P3E(P4, addr))[P2_OFFSET(addr)])
|
||||||
|
#define P1E(P4, addr) (PT(P2E(P4, addr))[P1_OFFSET(addr)])
|
||||||
|
|
||||||
|
|
||||||
|
static int P1_exists(uint64_t P4, uint64_t addr)
|
||||||
|
{
|
||||||
|
|
||||||
|
if (P4 && PRESENT(P4E(P4, addr)) && PRESENT(P3E(P4, addr)) && PRESENT(P2E(P4, addr)))
|
||||||
|
return 1;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int touch_P1(uint64_t P4, uint64_t addr, uint16_t flags)
|
||||||
|
{
|
||||||
|
if (!P4) return -1;
|
||||||
|
|
||||||
|
if(!PRESENT(P4E(P4, addr)) && (!(P4E(P4,addr) = pmm_calloc())))
|
||||||
|
return -1;
|
||||||
|
P4E(P4, addr) |= flags | PAGE_PRESENT;
|
||||||
|
|
||||||
|
if(!PRESENT(P3E(P4, addr)) && (!(P3E(P4, addr) = pmm_calloc())))
|
||||||
|
return -1;
|
||||||
|
P3E(P4, addr) |= flags | PAGE_PRESENT;
|
||||||
|
|
||||||
|
if(!PRESENT(P2E(P4, addr)) && (!(P2E(P4, addr) = pmm_calloc())))
|
||||||
|
return -1;
|
||||||
|
P2E(P4, addr) |= flags | PAGE_PRESENT;
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
uint64_t vmm_get_page(uint64_t P4, uint64_t addr)
|
||||||
|
{
|
||||||
|
if(P1_exists(P4, addr))
|
||||||
|
return P1E(P4, addr);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
int vmm_set_page(uint64_t P4, uint64_t addr, uint64_t page, uint16_t flags)
|
||||||
|
{
|
||||||
|
if(!P1_exists(P4, addr))
|
||||||
|
if(touch_P1(P4, addr, flags))
|
||||||
|
return -1;
|
||||||
|
|
||||||
|
P1E(P4, addr) = page | flags;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
void vmm_clear_page(uint64_t P4, uint64_t addr, int free)
|
||||||
|
{
|
||||||
|
if(!P1_exists(P4, addr))
|
||||||
|
return;
|
||||||
|
|
||||||
|
uint64_t *pt;
|
||||||
|
|
||||||
|
P1E(P4, addr) = 0;
|
||||||
|
|
||||||
|
if(!free)
|
||||||
|
return;
|
||||||
|
|
||||||
|
pt = PT(P2E(P4, addr));
|
||||||
|
for(int i = 0; i < ENTRIES_PER_PT; i++)
|
||||||
|
if(pt[i])
|
||||||
|
return;
|
||||||
|
pmm_free(MASK_FLAGS(P2E(P4, addr)));
|
||||||
|
P2E(P4, addr) = 0;
|
||||||
|
|
||||||
|
pt = PT(P3E(P4, addr));
|
||||||
|
for(int i = 0; i < ENTRIES_PER_PT; i++)
|
||||||
|
if(pt[i])
|
||||||
|
return;
|
||||||
|
pmm_free(MASK_FLAGS(P3E(P4, addr)));
|
||||||
|
P3E(P4, addr) = 0;
|
||||||
|
|
||||||
|
pt = PT(P4E(P4, addr));
|
||||||
|
for(int i = 0; i < ENTRIES_PER_PT; i++)
|
||||||
|
if(pt[i])
|
||||||
|
return;
|
||||||
|
pmm_free(MASK_FLAGS(P4E(P4, addr)));
|
||||||
|
P4E(P4, addr) = 0;
|
||||||
|
}
|
Loading…
x
Reference in New Issue
Block a user