Add first C user program
This commit is contained in:
@@ -0,0 +1,120 @@
|
||||
#include "src/kernel/memory.h"
|
||||
#include "src/kernel/panic.h"
|
||||
#include "src/lib/layout.h"
|
||||
#include "src/lib/memory.h"
|
||||
|
||||
#define MAP_UNIT 64
|
||||
#define FULL_UNIT 0xFFFFFFFFFFFFFFFF
|
||||
|
||||
// TODO keep aligned with `src/lib/layout.h`.
|
||||
static uint16_t free_page = MAP_UNIT * 12;
|
||||
static uint64_t allocation[PAGE_COUNT / MAP_UNIT] = {
|
||||
FULL_UNIT,
|
||||
FULL_UNIT,
|
||||
FULL_UNIT,
|
||||
FULL_UNIT,
|
||||
FULL_UNIT,
|
||||
FULL_UNIT,
|
||||
FULL_UNIT,
|
||||
FULL_UNIT,
|
||||
FULL_UNIT,
|
||||
FULL_UNIT,
|
||||
FULL_UNIT,
|
||||
FULL_UNIT,
|
||||
[59] = 0x8000000000000000ULL,
|
||||
};
|
||||
|
||||
static uint8_t get_allocated(uint16_t page) {
|
||||
return !!allocation[page / MAP_UNIT] & ((uint64_t)1 << (page % MAP_UNIT));
|
||||
}
|
||||
|
||||
static void set_allocated(uint16_t page, uint8_t allocated) {
|
||||
if (allocated) {
|
||||
allocation[page / MAP_UNIT] |= ((uint64_t)1 << (page % MAP_UNIT));
|
||||
} else {
|
||||
allocation[page / MAP_UNIT] &= ~((uint64_t)1 << (page % MAP_UNIT));
|
||||
}
|
||||
}
|
||||
|
||||
void *memory_page_allocate() {
|
||||
ASSERT(free_page < PAGE_COUNT, "memory_page_allocate: out of memory");
|
||||
const uint16_t page = free_page;
|
||||
set_allocated(page, 1);
|
||||
for (uint16_t unit = free_page / MAP_UNIT; unit < PAGE_COUNT / MAP_UNIT; unit++) {
|
||||
if (allocation[unit] != FULL_UNIT) {
|
||||
uint16_t bit = (uint16_t)__builtin_ctzll(~allocation[unit]);
|
||||
free_page = unit * MAP_UNIT + bit;
|
||||
break;
|
||||
}
|
||||
}
|
||||
return (void *)((uint64_t)page * PAGE_SIZE);
|
||||
}
|
||||
|
||||
void memory_page_free(void *address) {
|
||||
uint16_t page = (uint16_t)((uint64_t)address / PAGE_SIZE);
|
||||
ASSERT(get_allocated(page), "memory_page_free: page not allocated")
|
||||
set_allocated(page, 0);
|
||||
if (page < free_page) {
|
||||
free_page = page;
|
||||
}
|
||||
}
|
||||
|
||||
void memory_page_map(uint64_t *pml4, void *virt, void *phys, uint64_t flags) {
|
||||
const uint64_t ivirt = (uint64_t)virt;
|
||||
const uint64_t pml4_index = (ivirt >> 39) & 0x1FF;
|
||||
const uint64_t pdpt_index = (ivirt >> 30) & 0x1FF;
|
||||
const uint64_t pd_index = (ivirt >> 21) & 0x1FF;
|
||||
const uint64_t pt_index = (ivirt >> 12) & 0x1FF;
|
||||
|
||||
if (!(pml4[pml4_index] & PAGE_PRESENT)) {
|
||||
uint64_t *pdpt = memory_page_allocate();
|
||||
memory_set(0, PAGE_SIZE, PHYS_TO_VIRT(pdpt));
|
||||
pml4[pml4_index] = (uint64_t)pdpt | PAGE_PRESENT | PAGE_WRITABLE | PAGE_USER;
|
||||
}
|
||||
|
||||
uint64_t *pdpt = PHYS_TO_VIRT(pml4[pml4_index] & ~(uint64_t)0xFFF);
|
||||
if (!(pdpt[pdpt_index] & PAGE_PRESENT)) {
|
||||
uint64_t *pd = memory_page_allocate();
|
||||
memory_set(0, PAGE_SIZE, PHYS_TO_VIRT(pd));
|
||||
pdpt[pdpt_index] = (uint64_t)pd | PAGE_PRESENT | PAGE_WRITABLE | PAGE_USER;
|
||||
}
|
||||
|
||||
uint64_t *pd = PHYS_TO_VIRT(pdpt[pdpt_index] & ~(uint64_t)0xFFF);
|
||||
ASSERT(!(pd[pd_index] & 0x80), "memory_page_map: huge page in PD");
|
||||
if (!(pd[pd_index] & PAGE_PRESENT)) {
|
||||
uint64_t *pt = memory_page_allocate();
|
||||
memory_set(0, PAGE_SIZE, PHYS_TO_VIRT(pt));
|
||||
pd[pd_index] = (uint64_t)pt | PAGE_PRESENT | PAGE_WRITABLE | PAGE_USER;
|
||||
}
|
||||
|
||||
uint64_t *pt = PHYS_TO_VIRT(pd[pd_index] & ~(uint64_t)0xFFF);
|
||||
pt[pt_index] = (uint64_t)phys | flags | PAGE_PRESENT;
|
||||
}
|
||||
|
||||
void memory_page_unmap(uint64_t *pml4, void *virt) {
|
||||
const uint64_t ivirt = (uint64_t)virt;
|
||||
const uint64_t pml4_index = (ivirt >> 39) & 0x1FF;
|
||||
const uint64_t pdpt_index = (ivirt >> 30) & 0x1FF;
|
||||
const uint64_t pd_index = (ivirt >> 21) & 0x1FF;
|
||||
const uint64_t pt_index = (ivirt >> 12) & 0x1FF;
|
||||
|
||||
if (!(pml4[pml4_index] & PAGE_PRESENT)) {
|
||||
return;
|
||||
}
|
||||
|
||||
uint64_t *pdpt = PHYS_TO_VIRT(pml4[pml4_index] & ~(uint64_t)0xFFF);
|
||||
if (!(pdpt[pdpt_index] & PAGE_PRESENT)) {
|
||||
return;
|
||||
}
|
||||
|
||||
uint64_t *pd = PHYS_TO_VIRT(pdpt[pdpt_index] & ~(uint64_t)0xFFF);
|
||||
if (!(pd[pd_index] & PAGE_PRESENT)) {
|
||||
return;
|
||||
}
|
||||
|
||||
uint64_t *pt = PHYS_TO_VIRT(pd[pd_index] & ~(uint64_t)0xFFF);
|
||||
memory_page_free((void *)(pt[pt_index] & ~(uint64_t)0xFFF));
|
||||
pt[pt_index] = 0;
|
||||
|
||||
__asm__ volatile("invlpg (%0)" : : "r"(virt) : "memory");
|
||||
}
|
||||
Reference in New Issue
Block a user