mirror of
https://github.com/Tom-on64/kern.git
synced 2026-11-04 02:23:10 +00:00
Implemented paging
This commit is contained in:
@@ -4,6 +4,17 @@
|
|||||||
// Null definition
|
// Null definition
|
||||||
#define NULL ((void*)0)
|
#define NULL ((void*)0)
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Virtual memory addresses
|
||||||
|
*/
|
||||||
|
#define USER_HEAP 0x10000000
|
||||||
|
#define USER_STACK 0xBF000000
|
||||||
|
#define USER_SHARED 0xA0000000
|
||||||
|
#define KERNEL_BASE 0xC0000000
|
||||||
|
#define KERNEL_HEAP 0xD0000000
|
||||||
|
#define KERNEL_SHARED 0xF0000000
|
||||||
|
#define KERNEL_FRAMEBUF 0xC8000000
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Variable arguments
|
* Variable arguments
|
||||||
*/
|
*/
|
||||||
|
|||||||
+20
-6
@@ -3,9 +3,13 @@
|
|||||||
|
|
||||||
#include <kernel.h>
|
#include <kernel.h>
|
||||||
|
|
||||||
#define PAGE_SIZE 4096
|
#define PHYS_ADDR(_a) ((_a) & ~0xFFF)
|
||||||
|
|
||||||
#define PHYS_ADDR(_a) ((_a) & ~0xfff)
|
// The kernels pagedir
|
||||||
|
#define PAGEDIR ((uint32_t*)(0xFFFFF000))
|
||||||
|
#define PAGETAB(_i) ((uint32_t*)(0xFFC00000 + ((_i) << 12)))
|
||||||
|
|
||||||
|
#define PAGE_SIZE 4096
|
||||||
|
|
||||||
#define PAGE_FLAG_PRESENT (1 << 0)
|
#define PAGE_FLAG_PRESENT (1 << 0)
|
||||||
#define PAGE_FLAG_WRITE (1 << 1)
|
#define PAGE_FLAG_WRITE (1 << 1)
|
||||||
@@ -13,13 +17,23 @@
|
|||||||
#define PAGE_FLAG_PWT (1 << 3)
|
#define PAGE_FLAG_PWT (1 << 3)
|
||||||
#define PAGE_FLAG_NOCACHE (1 << 4)
|
#define PAGE_FLAG_NOCACHE (1 << 4)
|
||||||
#define PAGE_FLAG_ACCESSED (1 << 5)
|
#define PAGE_FLAG_ACCESSED (1 << 5)
|
||||||
#define PAGE_FLAG_DIRTY (1 << 6)
|
#define PAGE_FLAG_DIRTY (1 << 6) // AVL in PDE where PS = 0
|
||||||
#define PAGE_FLAG_4MB (1 << 7)
|
#define PAGE_FLAG_PS (1 << 7) // If PS = 1 then directly maps a 4MB page
|
||||||
#define PAGE_FLAG_GLOBAL (1 << 8)
|
#define PAGE_FLAG_GLOBAL (1 << 8)
|
||||||
|
// bits 9-11 are AVL - OS is free to use these as its own flags
|
||||||
|
#define PAGE_FLAG_OWNER (1 << 9)
|
||||||
|
|
||||||
// Defined in entry.s for initial paging
|
extern uint32_t init_pagedir[1024]; // Defined in entry.s for initial paging
|
||||||
extern uint32_t init_pagedir[1024];
|
extern size_t pag_pageCount;
|
||||||
|
|
||||||
int pag_init(void);
|
int pag_init(void);
|
||||||
|
void pag_mapPage(uint32_t vaddr, uint32_t paddr, uint32_t flags);
|
||||||
|
uint32_t pag_umapPage(uint32_t vaddr);
|
||||||
|
void* pag_virtToPhys(uint32_t vaddr);
|
||||||
|
uint32_t* pag_getPagedir();
|
||||||
|
void pag_setPagedir(uint32_t* pagedir);
|
||||||
|
void pag_syncPagedir();
|
||||||
|
uint32_t* pag_allocPagedir();
|
||||||
|
void pag_freePagedir(uint32_t* pagedir);
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|||||||
+2
-1
@@ -62,8 +62,9 @@ section .data
|
|||||||
align 4096
|
align 4096
|
||||||
global init_pagedir
|
global init_pagedir
|
||||||
init_pagedir:
|
init_pagedir:
|
||||||
dd 0b10000011
|
dd 0b10000011 ; Identity map first 4MB
|
||||||
times 768-1 dd 0
|
times 768-1 dd 0
|
||||||
|
; Map first 16MB of kernel to 0xC0000000
|
||||||
dd (0 << 22) | 0b10000011
|
dd (0 << 22) | 0b10000011
|
||||||
dd (1 << 22) | 0b10000011
|
dd (1 << 22) | 0b10000011
|
||||||
dd (2 << 22) | 0b10000011
|
dd (2 << 22) | 0b10000011
|
||||||
|
|||||||
@@ -15,8 +15,6 @@ void kmain(void* ptr, uint32_t magic) {
|
|||||||
|
|
||||||
// Serial console for debugging
|
// Serial console for debugging
|
||||||
serial_init(COM1);
|
serial_init(COM1);
|
||||||
// ESC[H moves cursor to (0,0), ESC[J clears from cursor to end of screen
|
|
||||||
// ESC[<x>m sets graphics mode, 0 - reset, 36 - cyan
|
|
||||||
debugf("\x1b[H\x1b[J\x1b[0mkern. \x1b[36m(serial console)\x1b[0m\n\n");
|
debugf("\x1b[H\x1b[J\x1b[0mkern. \x1b[36m(serial console)\x1b[0m\n\n");
|
||||||
|
|
||||||
// VGA tty thingy
|
// VGA tty thingy
|
||||||
|
|||||||
+199
-1
@@ -1,7 +1,16 @@
|
|||||||
#include <kernel.h>
|
#include <kernel.h>
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
|
#include <pmm.h>
|
||||||
|
|
||||||
#include <paging.h>
|
#include <paging.h>
|
||||||
|
|
||||||
|
#define PAGE_DIR_COUNT 256
|
||||||
|
static uint32_t pagedirs[PAGE_DIR_COUNT][1024] __align(4096);
|
||||||
|
static uint8_t pagedirUsed[PAGE_DIR_COUNT];
|
||||||
|
|
||||||
|
// TODO: Should this be initialized? If so, to what?
|
||||||
|
size_t pag_pageCount;
|
||||||
|
|
||||||
// Invalidates the pagedir entry in the CPUs TLB cache
|
// Invalidates the pagedir entry in the CPUs TLB cache
|
||||||
static inline void invalidate(uint32_t vaddr) {
|
static inline void invalidate(uint32_t vaddr) {
|
||||||
__asm__ volatile ("invlpg %0" : : "m"(vaddr));
|
__asm__ volatile ("invlpg %0" : : "m"(vaddr));
|
||||||
@@ -18,10 +27,199 @@ int pag_init(void) {
|
|||||||
* as a pagetab even though it's a pagedir. This maps it to
|
* as a pagetab even though it's a pagedir. This maps it to
|
||||||
* the virtual address 0xFFFFF000.
|
* the virtual address 0xFFFFF000.
|
||||||
*/
|
*/
|
||||||
init_pagedir[1023] = ((uint32_t)init_pagedir - 0xC0000000) |
|
init_pagedir[1023] = ((uint32_t)init_pagedir - KERNEL_BASE) |
|
||||||
PAGE_FLAG_PRESENT | PAGE_FLAG_WRITE;
|
PAGE_FLAG_PRESENT | PAGE_FLAG_WRITE;
|
||||||
invalidate(0xFFFFF000);
|
invalidate(0xFFFFF000);
|
||||||
|
|
||||||
|
memset(pagedirs, 0, PAGE_SIZE * PAGE_DIR_COUNT);
|
||||||
|
memset(pagedirUsed, 0, PAGE_DIR_COUNT);
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void pag_mapPage(uint32_t vaddr, uint32_t paddr, uint32_t flags) {
|
||||||
|
// Save the pagedir we were in
|
||||||
|
uint32_t* prevpd = NULL;
|
||||||
|
|
||||||
|
// Switch to the init pagedir if in kernel memory
|
||||||
|
if (vaddr >= KERNEL_BASE) {
|
||||||
|
prevpd = pag_getPagedir();
|
||||||
|
|
||||||
|
if (prevpd != init_pagedir) pag_setPagedir(init_pagedir);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Extract indecies
|
||||||
|
size_t pdi = vaddr >> 22;
|
||||||
|
size_t pti = vaddr >> 12 & 0x3FF;
|
||||||
|
|
||||||
|
uint32_t* pagedir = PAGEDIR;
|
||||||
|
uint32_t* pagetab = PAGETAB(pdi);
|
||||||
|
|
||||||
|
// Allocate a pagetab if it didn't exist
|
||||||
|
if (!(pagedir[pdi] & PAGE_FLAG_PRESENT)) {
|
||||||
|
uint32_t tabaddr = (uint32_t)pmm_alloc(1);
|
||||||
|
pagedir[pdi] = tabaddr |
|
||||||
|
PAGE_FLAG_PRESENT | PAGE_FLAG_WRITE | PAGE_FLAG_OWNER | flags;
|
||||||
|
invalidate(vaddr);
|
||||||
|
|
||||||
|
for (size_t i = 0; i < 1024; i++) {
|
||||||
|
pagetab[i] = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// The actuall mapping
|
||||||
|
pagetab[pti] = paddr | PAGE_FLAG_PRESENT | flags;
|
||||||
|
pag_pageCount++;
|
||||||
|
invalidate(vaddr);
|
||||||
|
|
||||||
|
// Do we need to return to the original pagedir?
|
||||||
|
if (prevpd != NULL) {
|
||||||
|
pag_syncPagedir(); // Sync it to other pagedirs
|
||||||
|
if (prevpd != init_pagedir) pag_setPagedir(prevpd);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
uint32_t pag_umapPage(uint32_t vaddr) {
|
||||||
|
// Same saving as in pag_mapPage()
|
||||||
|
uint32_t* prevpd = NULL;
|
||||||
|
|
||||||
|
if (vaddr >= KERNEL_BASE) {
|
||||||
|
prevpd = pag_getPagedir();
|
||||||
|
|
||||||
|
if (prevpd != init_pagedir) pag_setPagedir(init_pagedir);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Extract indecies
|
||||||
|
size_t pdi = vaddr >> 22;
|
||||||
|
size_t pti = vaddr >> 12 & 0x3FF;
|
||||||
|
|
||||||
|
uint32_t* pagedir = PAGEDIR;
|
||||||
|
uint32_t* pagetab = PAGETAB(pdi);
|
||||||
|
|
||||||
|
uint32_t pte = pagetab[pti];
|
||||||
|
pagetab[pti] = 0;
|
||||||
|
pag_pageCount--;
|
||||||
|
|
||||||
|
// Look if we can free the pagetab
|
||||||
|
int remove = 1;
|
||||||
|
for (size_t i = 0; i < 1024; i++) {
|
||||||
|
if (!(pagetab[i] & PAGE_FLAG_PRESENT)) continue;
|
||||||
|
remove = 0;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Free the pagetab if possible
|
||||||
|
uint32_t pde = pagedir[pdi];
|
||||||
|
if (remove && pde & PAGE_FLAG_OWNER) {
|
||||||
|
uint32_t tabaddr = PHYS_ADDR(pde);
|
||||||
|
pmm_free((void*)tabaddr, 1);
|
||||||
|
pagedir[pdi] = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
invalidate(vaddr);
|
||||||
|
|
||||||
|
// Free the page frame
|
||||||
|
if (pte & PAGE_FLAG_OWNER) pmm_free((void*)PHYS_ADDR(pte), 1);
|
||||||
|
|
||||||
|
if (prevpd != NULL) {
|
||||||
|
pag_syncPagedir(); // Sync it to other pagedirs
|
||||||
|
if (prevpd != init_pagedir) pag_setPagedir(prevpd);
|
||||||
|
}
|
||||||
|
|
||||||
|
return pte;
|
||||||
|
}
|
||||||
|
|
||||||
|
void* pag_virtToPhys(uint32_t vaddr) {
|
||||||
|
uint32_t pdi = vaddr >> 22;
|
||||||
|
uint32_t pti = vaddr >> 12 & 0x3FF;
|
||||||
|
|
||||||
|
uint32_t* pagetab = PAGETAB(pdi);
|
||||||
|
|
||||||
|
return (void*)((pagetab[pti] & ~0xFFF) + ((uint32_t)vaddr & 0xFFF));
|
||||||
|
}
|
||||||
|
|
||||||
|
uint32_t* pag_getPagedir() {
|
||||||
|
uint32_t pagedir;
|
||||||
|
__asm__ volatile ("mov %%cr3, %0" : "=r"(pagedir));
|
||||||
|
pagedir += KERNEL_BASE;
|
||||||
|
return (uint32_t*)pagedir;
|
||||||
|
}
|
||||||
|
|
||||||
|
void pag_setPagedir(uint32_t* pagedir) {
|
||||||
|
pagedir = (uint32_t*)((uint32_t)pagedir - KERNEL_BASE);
|
||||||
|
__asm__ volatile (
|
||||||
|
"mov %0, %%eax\n"
|
||||||
|
"mov %%eax, %%cr3"
|
||||||
|
: : "m"(pagedir)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
void pag_syncPagedir() {
|
||||||
|
for (size_t i = 0; i < PAGE_DIR_COUNT; i++) {
|
||||||
|
if (!pagedirUsed[i]) continue;
|
||||||
|
|
||||||
|
uint32_t* pagedir = pagedirs[i];
|
||||||
|
|
||||||
|
// Sync ONLY the kernel pages so 768 has base at 0xC0000000
|
||||||
|
// Also don't sync the recursive mapping in the last page
|
||||||
|
for (size_t i = 768; i < 1023; i++) {
|
||||||
|
pagedir[i] = init_pagedir[i] & ~PAGE_FLAG_OWNER;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
uint32_t* pag_allocPagedir() {
|
||||||
|
// Find the first unused page
|
||||||
|
for (size_t i = 0; i < PAGE_DIR_COUNT; i++) {
|
||||||
|
if (pagedirUsed[i]) continue;
|
||||||
|
pagedirUsed[i] = 1;
|
||||||
|
|
||||||
|
uint32_t* pagedir = pagedirs[i];
|
||||||
|
memset(pagedir, 0, PAGE_SIZE);
|
||||||
|
|
||||||
|
// First 768 entries are user pagetabs (3:1 memory split)
|
||||||
|
for (size_t i = 0; i < 768; i++) pagedir[i] = 0;
|
||||||
|
|
||||||
|
// Next 255 are kernel space
|
||||||
|
for (size_t i = 768; i < 1023; i++) pagedir[i] = init_pagedir[i] & ~PAGE_FLAG_OWNER;
|
||||||
|
|
||||||
|
// Last page is the recursive table mapping
|
||||||
|
pagedir[1023] = ((uint32_t)pagedir - KERNEL_BASE) |
|
||||||
|
PAGE_FLAG_PRESENT | PAGE_FLAG_WRITE;
|
||||||
|
|
||||||
|
return pagedir;
|
||||||
|
}
|
||||||
|
|
||||||
|
// No pages left - out of memory
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
void pag_freePagedir(uint32_t* pagedir) {
|
||||||
|
uint32_t* prevpd = pag_getPagedir();
|
||||||
|
pag_setPagedir(pagedir);
|
||||||
|
|
||||||
|
uint32_t pdi = (uint32_t)pagedir - (uint32_t)pagedirs;
|
||||||
|
pdi /= PAGE_SIZE;
|
||||||
|
|
||||||
|
// Free all allocated page frames & pagetabs
|
||||||
|
uint32_t* pd = PAGEDIR;
|
||||||
|
for (int i = 0; i < 768; i++) {
|
||||||
|
uint32_t pde = pd[i];
|
||||||
|
if (pde == 0) continue;
|
||||||
|
|
||||||
|
uint32_t* pagetab = PAGETAB(i);
|
||||||
|
for (size_t j = 0; j < 1024; j++) {
|
||||||
|
uint32_t pte = pagetab[j];
|
||||||
|
|
||||||
|
if (pte & PAGE_FLAG_OWNER) pmm_free((void*)PHYS_ADDR(pte), 1);
|
||||||
|
}
|
||||||
|
memset(pagetab, 0, PAGE_SIZE);
|
||||||
|
|
||||||
|
if (pde & PAGE_FLAG_OWNER) pmm_free((void*)PHYS_ADDR(pde), 1);
|
||||||
|
pd[i] = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
pagedirUsed[pdi] = 0;
|
||||||
|
pag_setPagedir(prevpd);
|
||||||
|
}
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user