81 lines
2.6 KiB
C
81 lines
2.6 KiB
C
//
|
|
// Created by rick on 21-02-21.
|
|
//
|
|
|
|
#include <sys/types.h>
|
|
#include <attributes.h>
|
|
|
|
#include <myke/mem/paging.h>
|
|
#include <sys/param.h>
|
|
|
|
#define PAGING_DIR_INDEX(virt) ((virt) >> 22)
|
|
#define PAGING_TABLE_INDEX(virt) ((virt) >> 12 & 0x03FF)
|
|
|
|
#define KERNEL_OFFSET 0xC0000000
|
|
|
|
// One page table, only 4M
|
|
#define PAGING_STATE_EARLY 0
|
|
#define PAGING_STATE_FULL 60
|
|
|
|
page_directory_entry att_aligned(4096) kernel_page_directory[DIRECTORY_SIZE] = {0};
|
|
|
|
int paging_state = PAGING_STATE_EARLY;
|
|
|
|
void paging_load_directory(uintptr_t physical_address) {
|
|
asm volatile("mov %%eax, %%cr3" : : "a" (physical_address));
|
|
}
|
|
|
|
uintptr_t paging_get_current_directory_physical() {
|
|
uintptr_t directory_address;
|
|
asm volatile("mov %%cr3, %%eax" : "=a" (directory_address));
|
|
return directory_address;
|
|
}
|
|
|
|
page_directory_entry *paging_get_current() {
|
|
return kernel_page_directory;
|
|
}
|
|
|
|
int paging_map_4m(uintptr_t physical_address, uintptr_t virtual_address, int count, int mode) {
|
|
if (virtual_address & ~PAGING_MASK_4M || physical_address & PAGING_MASK_4M) {
|
|
// address not 4M aligned
|
|
return PAGING_RESULT_ALIGN;
|
|
}
|
|
page_directory_entry *dir = paging_get_current();
|
|
for (int i = 0; i < count; ++i) {
|
|
page_directory_entry current_val = dir[PAGING_DIR_INDEX(virtual_address) + i];
|
|
if (current_val & DIRECTORY_PRESENT_MASK) {
|
|
return PAGING_RESULT_INUSE;
|
|
}
|
|
}
|
|
page_directory_entry mask = DIRECTORY_PAGE_SIZE_MASK;
|
|
if (mode & PAGING_MODE_RW) {
|
|
mask |= DIRECTORY_RW_MASK;
|
|
}
|
|
if (mode & PAGING_MODE_US) {
|
|
mask |= DIRECTORY_US_MASK;
|
|
}
|
|
for (int i = 0; i < count; ++i) {
|
|
dir[PAGING_DIR_INDEX(virtual_address) + i] = physical_address & mask;
|
|
}
|
|
paging_load_directory((uintptr_t) dir);
|
|
return PAGING_RESULT_OK;
|
|
}
|
|
|
|
int paging_map_memory(uintptr_t physical_address, uintptr_t virtual_address, int count, int mode) {
|
|
if (mode & PAGING_MODE_4M) {
|
|
return paging_map_4m(physical_address, virtual_address, count, mode);
|
|
}
|
|
if (paging_state < PAGING_STATE_FULL) {
|
|
// can't allocate 4K pages yet
|
|
if ((virtual_address & ~PAGING_MASK_4M) != (physical_address & ~PAGING_MASK_4M)) {
|
|
return PAGING_RESULT_ERR; // not in same pos in 4M page
|
|
}
|
|
int table_index = PAGING_TABLE_INDEX(virtual_address);
|
|
int pages = DIV_ROUND_UP(table_index + count, 1024);
|
|
return paging_map_4m(physical_address & PAGING_MASK_4M,
|
|
virtual_address & PAGING_MASK_4M,
|
|
pages,
|
|
mode | PAGING_MODE_4M);
|
|
}
|
|
return PAGING_RESULT_ERR;
|
|
} |