réplica de
https://github.com/Arnau478/quark.git
synced 2024-11-23 12:58:07 +01:00
Virtual memory manager
This commit is contained in:
pare
1d64e83647
commit
3ff5e1fd08
S'han modificat 11 arxius amb 351 adicions i 7 eliminacions
|
@ -6,6 +6,7 @@
|
||||||
#include "drivers/serial.h"
|
#include "drivers/serial.h"
|
||||||
#include "fs/vfs.h"
|
#include "fs/vfs.h"
|
||||||
#include "mm/pmm.h"
|
#include "mm/pmm.h"
|
||||||
|
#include "mm/vmm.h"
|
||||||
#include "multiboot.h"
|
#include "multiboot.h"
|
||||||
|
|
||||||
extern uint8_t end; // Kernel end
|
extern uint8_t end; // Kernel end
|
||||||
|
@ -33,18 +34,15 @@ void __attribute__((cdecl)) kmain(multiboot_info_t *multiboot_info){
|
||||||
|
|
||||||
pmm_deinit_region(0x100000, (int)(&end) - 0x100000); // Deinit the section the kernel is in
|
pmm_deinit_region(0x100000, (int)(&end) - 0x100000); // Deinit the section the kernel is in
|
||||||
|
|
||||||
|
// Initialize virtual memory
|
||||||
|
vmm_initialize();
|
||||||
|
|
||||||
// Initialize drivers
|
// Initialize drivers
|
||||||
timer_initialize();
|
timer_initialize();
|
||||||
keyboard_initialize();
|
keyboard_initialize();
|
||||||
|
|
||||||
// Initialize FS
|
// Initialize FS
|
||||||
vfs_initialize();
|
vfs_initialize();
|
||||||
|
|
||||||
// PMM test code
|
|
||||||
uint32_t *p1 = (uint32_t *)pmm_alloc_block();
|
|
||||||
printf("Allocated p1 at: 0x%x\n", p1);
|
|
||||||
uint32_t *p2 = (uint32_t *)pmm_alloc_block();
|
|
||||||
printf("Allocated p2 at: 0x%x\n", p2);
|
|
||||||
|
|
||||||
for(;;);
|
for(;;);
|
||||||
}
|
}
|
||||||
|
|
34
src/kernel/mm/pde.c
Normal file
34
src/kernel/mm/pde.c
Normal file
|
@ -0,0 +1,34 @@
|
||||||
|
#include "pde.h"
|
||||||
|
|
||||||
|
void pd_entry_add_attr(pd_entry_t *entry, uint32_t attr){
|
||||||
|
*entry |= attr;
|
||||||
|
}
|
||||||
|
|
||||||
|
void pd_entry_del_attr(pd_entry_t *entry, uint32_t attr){
|
||||||
|
*entry &= ~attr;
|
||||||
|
}
|
||||||
|
|
||||||
|
void pd_entry_set_frame(pd_entry_t *entry, phys_addr frame){
|
||||||
|
*entry &= ~PDE_FRAME;
|
||||||
|
*entry |= frame << 12;
|
||||||
|
}
|
||||||
|
|
||||||
|
phys_addr pd_entry_get_frame(pd_entry_t entry){
|
||||||
|
return entry >> 12;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool pd_entry_is_present(pd_entry_t entry){
|
||||||
|
return entry & PDE_PRESENT;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool pd_entry_is_user(pd_entry_t entry){
|
||||||
|
return entry & PDE_USER;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool pd_entry_is_4mb(pd_entry_t entry){
|
||||||
|
return entry & PDE_4MB;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool pd_entry_is_writable(pd_entry_t entry){
|
||||||
|
return entry & PDE_WRITABLE;
|
||||||
|
}
|
30
src/kernel/mm/pde.h
Normal file
30
src/kernel/mm/pde.h
Normal file
|
@ -0,0 +1,30 @@
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <stdint.h>
|
||||||
|
#include <stdbool.h>
|
||||||
|
#include "pmm.h"
|
||||||
|
|
||||||
|
enum PDE_PAGE_FLAGS{
|
||||||
|
PDE_PRESENT = 0x0001,
|
||||||
|
PDE_WRITABLE = 0x0002,
|
||||||
|
PDE_USER = 0x0004,
|
||||||
|
PDE_WRITETHROUGH = 0x0008,
|
||||||
|
PDE_CACHE_DISABLED = 0x0010,
|
||||||
|
PDE_ACCESSED = 0x0020,
|
||||||
|
PDE_DIRTY = 0x0040,
|
||||||
|
PDE_4MB = 0x0080,
|
||||||
|
PDE_CPU_GLOBAL = 0x0100,
|
||||||
|
PDE_LV4_GLOBAL = 0x0200,
|
||||||
|
PDE_FRAME = 0x7FFFF000,
|
||||||
|
};
|
||||||
|
|
||||||
|
typedef uint32_t pd_entry_t;
|
||||||
|
|
||||||
|
void pd_entry_add_attr(pd_entry_t *entry, uint32_t attr);
|
||||||
|
void pd_entry_del_attr(pd_entry_t *entry, uint32_t attr);
|
||||||
|
void pd_entry_set_frame(pd_entry_t *entry, phys_addr frame);
|
||||||
|
phys_addr pd_entry_get_frame(pd_entry_t entry);
|
||||||
|
bool pd_entry_is_present(pd_entry_t entry);
|
||||||
|
bool pd_entry_is_user(pd_entry_t entry);
|
||||||
|
bool pd_entry_is_4mb(pd_entry_t entry);
|
||||||
|
bool pd_entry_is_writable(pd_entry_t entry);
|
43
src/kernel/mm/pmm.asm
Normal file
43
src/kernel/mm/pmm.asm
Normal file
|
@ -0,0 +1,43 @@
|
||||||
|
global pmm_paging_enable
|
||||||
|
pmm_paging_enable:
|
||||||
|
[bits 32]
|
||||||
|
; New call frame
|
||||||
|
push ebp
|
||||||
|
mov ebp, esp
|
||||||
|
|
||||||
|
mov eax, cr0
|
||||||
|
cmp byte [esp + 4], 0
|
||||||
|
jg .enable
|
||||||
|
jmp .disable
|
||||||
|
.enable:
|
||||||
|
or eax, 0x80000000 ; Set bit 31
|
||||||
|
jmp .done
|
||||||
|
.disable:
|
||||||
|
and eax, 0x7FFFFFFF ; Clear bit 31
|
||||||
|
.done:
|
||||||
|
mov cr0, eax
|
||||||
|
|
||||||
|
; Restore old call frame
|
||||||
|
mov esp, ebp
|
||||||
|
pop ebp
|
||||||
|
ret
|
||||||
|
|
||||||
|
global pmm_is_paging
|
||||||
|
pmm_is_paging:
|
||||||
|
[bits 32]
|
||||||
|
mov eax, cr0
|
||||||
|
and eax, 0x80000000
|
||||||
|
ret
|
||||||
|
|
||||||
|
global pmm_load_pdbr
|
||||||
|
pmm_load_pdbr:
|
||||||
|
[bits 32]
|
||||||
|
mov eax, [esp + 4]
|
||||||
|
mov cr3, eax
|
||||||
|
ret
|
||||||
|
|
||||||
|
global pmm_get_pdbr
|
||||||
|
pmm_get_pdbr:
|
||||||
|
[bits 32]
|
||||||
|
mov eax, cr3
|
||||||
|
ret
|
|
@ -62,7 +62,6 @@ void pmm_initialize(size_t mem_size, phys_addr bitmap){
|
||||||
g_pmm_max_blocks = (pmm_get_memory_size()*1024) / PMM_BLOCK_SIZE;
|
g_pmm_max_blocks = (pmm_get_memory_size()*1024) / PMM_BLOCK_SIZE;
|
||||||
g_pmm_used_blocks = g_pmm_max_blocks;
|
g_pmm_used_blocks = g_pmm_max_blocks;
|
||||||
|
|
||||||
// FIXME
|
|
||||||
memset(g_pmm_memory_map, 0xFF, pmm_get_block_count() / PMM_BLOCKS_PER_BYTE);
|
memset(g_pmm_memory_map, 0xFF, pmm_get_block_count() / PMM_BLOCKS_PER_BYTE);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -22,3 +22,7 @@ size_t pmm_get_memory_size();
|
||||||
uint32_t pmm_get_block_count();
|
uint32_t pmm_get_block_count();
|
||||||
uint32_t pmm_get_used_block_count();
|
uint32_t pmm_get_used_block_count();
|
||||||
uint32_t pmm_get_free_block_count();
|
uint32_t pmm_get_free_block_count();
|
||||||
|
void __attribute__((cdecl)) pmm_paging_enable(bool enabled);
|
||||||
|
bool __attribute__((cdecl)) pmm_is_paging();
|
||||||
|
void __attribute__((cdecl)) pmm_load_pdbr(phys_addr addr);
|
||||||
|
phys_addr __attribute__((cdecl)) pmm_get_pdbr();
|
||||||
|
|
26
src/kernel/mm/pte.c
Normal file
26
src/kernel/mm/pte.c
Normal file
|
@ -0,0 +1,26 @@
|
||||||
|
#include "pte.h"
|
||||||
|
|
||||||
|
void pt_entry_add_attr(pt_entry_t *entry, uint32_t attr){
|
||||||
|
*entry |= attr;
|
||||||
|
}
|
||||||
|
|
||||||
|
void pt_entry_del_attr(pt_entry_t *entry, uint32_t attr){
|
||||||
|
*entry &= ~attr;
|
||||||
|
}
|
||||||
|
|
||||||
|
void pt_entry_set_frame(pt_entry_t *entry, phys_addr frame){
|
||||||
|
*entry &= ~PTE_FRAME;
|
||||||
|
*entry |= frame << 12;
|
||||||
|
}
|
||||||
|
|
||||||
|
phys_addr pt_entry_get_frame(pt_entry_t entry){
|
||||||
|
return entry >> 12;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool pt_entry_is_present(pt_entry_t entry){
|
||||||
|
return entry & PTE_PRESENT;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool pt_entry_is_writable(pt_entry_t entry){
|
||||||
|
return entry & PTE_WRITABLE;
|
||||||
|
}
|
27
src/kernel/mm/pte.h
Normal file
27
src/kernel/mm/pte.h
Normal file
|
@ -0,0 +1,27 @@
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <stdint.h>
|
||||||
|
#include "pmm.h"
|
||||||
|
|
||||||
|
enum PTE_PAGE_FLAGS{
|
||||||
|
PTE_PRESENT = 0x0001,
|
||||||
|
PTE_WRITABLE = 0x0002,
|
||||||
|
PTE_USER = 0x0004,
|
||||||
|
PTE_WRITETHROUGH = 0x0008,
|
||||||
|
PTE_NOT_CACHEABLE = 0x0010,
|
||||||
|
PTE_ACCESSED = 0x0020,
|
||||||
|
PTE_DIRTY = 0x0040,
|
||||||
|
PTE_PAT = 0x0080,
|
||||||
|
PTE_CPU_GLOBAL = 0x0100,
|
||||||
|
PTE_LV4_GLOBAL = 0x0200,
|
||||||
|
PTE_FRAME = 0x7FFFF000
|
||||||
|
};
|
||||||
|
|
||||||
|
typedef uint32_t pt_entry_t;
|
||||||
|
|
||||||
|
void pt_entry_add_attr(pt_entry_t *entry, uint32_t attr);
|
||||||
|
void pt_entry_del_attr(pt_entry_t *entry, uint32_t attr);
|
||||||
|
void pt_entry_set_frame(pt_entry_t *entry, phys_addr frame);
|
||||||
|
phys_addr pt_entry_get_frame(pt_entry_t entry);
|
||||||
|
bool pt_entry_is_present(pt_entry_t entry);
|
||||||
|
bool pt_entry_is_writable(pt_entry_t entry);
|
8
src/kernel/mm/vmm.asm
Normal file
8
src/kernel/mm/vmm.asm
Normal file
|
@ -0,0 +1,8 @@
|
||||||
|
global vmm_flush_tlb_entry
|
||||||
|
vmm_flush_tlb_entry:
|
||||||
|
[bits 32]
|
||||||
|
cli
|
||||||
|
invlpg [esp + 4]
|
||||||
|
sti
|
||||||
|
|
||||||
|
ret
|
142
src/kernel/mm/vmm.c
Normal file
142
src/kernel/mm/vmm.c
Normal file
|
@ -0,0 +1,142 @@
|
||||||
|
#include "vmm.h"
|
||||||
|
#include "pmm.h"
|
||||||
|
#include "../lib/memory.h"
|
||||||
|
|
||||||
|
vmm_page_directory_t *g_vmm_current_dir = 0;
|
||||||
|
phys_addr g_vmm_current_pdbr = 0;
|
||||||
|
|
||||||
|
void __attribute__((cdecl)) vmm_flush_tlb_entry(virt_addr addr);
|
||||||
|
|
||||||
|
static inline pt_entry_t *vmm_ptable_lookup_entry(vmm_page_table_t *p, virt_addr addr){
|
||||||
|
if(p) return &p->entries[PAGE_TABLE_INDEX(addr)];
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline pd_entry_t *vmm_pdirectory_lookup_entry(vmm_page_directory_t *p, virt_addr addr){
|
||||||
|
if(p) return &p->entries[PAGE_DIRECTORY_INDEX(addr)];
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline bool vmm_switch_pdirectory(vmm_page_directory_t *dir){
|
||||||
|
if(!dir) return false;
|
||||||
|
|
||||||
|
g_vmm_current_dir = dir;
|
||||||
|
pmm_load_pdbr(g_vmm_current_pdbr);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline vmm_page_directory_t *vmm_get_pdirectory(){
|
||||||
|
return g_vmm_current_dir;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool vmm_alloc_page(pt_entry_t *entry){
|
||||||
|
void *p = pmm_alloc_block();
|
||||||
|
if(!p) return false;
|
||||||
|
|
||||||
|
pt_entry_set_frame(entry, (phys_addr)p);
|
||||||
|
pt_entry_add_attr(entry, PTE_PRESENT);
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
void vmm_free_page(pt_entry_t *entry){
|
||||||
|
void *p = (void *)pt_entry_get_frame(*entry);
|
||||||
|
if(p) pmm_free_block(p);
|
||||||
|
|
||||||
|
pt_entry_del_attr(entry, PTE_PRESENT);
|
||||||
|
}
|
||||||
|
|
||||||
|
void vmm_map_page(void *phys, void *virt){
|
||||||
|
// Get page directory
|
||||||
|
vmm_page_directory_t *page_dir = vmm_get_pdirectory();
|
||||||
|
|
||||||
|
// Get page table
|
||||||
|
pd_entry_t *e = &page_dir->entries[PAGE_DIRECTORY_INDEX((uint32_t)virt)];
|
||||||
|
if((*e & PTE_PRESENT) != PTE_PRESENT){
|
||||||
|
// Must allocate
|
||||||
|
vmm_page_table_t *table = (vmm_page_table_t *)pmm_alloc_block();
|
||||||
|
if(!table) return;
|
||||||
|
|
||||||
|
// Clear page table
|
||||||
|
memset(table, 0, sizeof(vmm_page_table_t));
|
||||||
|
|
||||||
|
// Create a new entry
|
||||||
|
pd_entry_t *entry = &page_dir->entries[PAGE_DIRECTORY_INDEX((uint32_t)virt)];
|
||||||
|
|
||||||
|
// Map in the table
|
||||||
|
pd_entry_add_attr(entry, PDE_PRESENT);
|
||||||
|
pd_entry_add_attr(entry, PDE_WRITABLE);
|
||||||
|
pd_entry_set_frame(entry, (phys_addr)table);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Get table
|
||||||
|
vmm_page_table_t *table = (vmm_page_table_t *)PAGE_GET_PHYS_ADDR(e);
|
||||||
|
|
||||||
|
// Get page
|
||||||
|
pt_entry_t *page = &table->entries[PAGE_TABLE_INDEX((uint32_t)virt)];
|
||||||
|
|
||||||
|
// Map it
|
||||||
|
pt_entry_set_frame(page, (phys_addr)phys);
|
||||||
|
pt_entry_add_attr(page, PTE_PRESENT);
|
||||||
|
}
|
||||||
|
|
||||||
|
void vmm_initialize(){
|
||||||
|
// Allocate default page table
|
||||||
|
vmm_page_table_t *table = (vmm_page_table_t *)pmm_alloc_block();
|
||||||
|
if(!table) return;
|
||||||
|
|
||||||
|
// Allocate 3GB page table
|
||||||
|
vmm_page_table_t *table2 = (vmm_page_table_t *)pmm_alloc_block();
|
||||||
|
if(!table2) return;
|
||||||
|
|
||||||
|
// Clear default table
|
||||||
|
memset(table, 0, sizeof(vmm_page_table_t));
|
||||||
|
|
||||||
|
// First 1MB are identity mapped
|
||||||
|
for(int i = 0, frame = 0x0, virt = 0x00000000; i<1024; i++, frame += 4096, virt += 4096){
|
||||||
|
// Create a new page
|
||||||
|
pt_entry_t page = 0;
|
||||||
|
pt_entry_add_attr(&page, PTE_PRESENT);
|
||||||
|
pt_entry_set_frame(&page, frame);
|
||||||
|
|
||||||
|
// Add the page to the page table
|
||||||
|
table2->entries[PAGE_TABLE_INDEX(virt)] = page;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Map 1MB to 3GB
|
||||||
|
for(int i = 0, frame = 0x100000, virt = 0xc0000000; i<1024; i++, frame += 4096, virt += 4096){
|
||||||
|
// Create a new page
|
||||||
|
pt_entry_t page = 0;
|
||||||
|
pt_entry_add_attr(&page, PTE_PRESENT);
|
||||||
|
pt_entry_set_frame(&page, frame);
|
||||||
|
|
||||||
|
// Add the page to the page table
|
||||||
|
table->entries[PAGE_TABLE_INDEX(virt)] = page;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Create default directory table
|
||||||
|
vmm_page_directory_t *dir = (vmm_page_directory_t *)pmm_alloc_blocks(3);
|
||||||
|
if(!dir) return;
|
||||||
|
|
||||||
|
// Clear directory table and set it as current
|
||||||
|
memset(dir, 0, sizeof(vmm_page_directory_t));
|
||||||
|
|
||||||
|
pd_entry_t *entry = &dir->entries[PAGE_DIRECTORY_INDEX(0xc0000000)];
|
||||||
|
pd_entry_add_attr(entry, PDE_PRESENT);
|
||||||
|
pd_entry_add_attr(entry, PDE_WRITABLE);
|
||||||
|
pd_entry_set_frame(entry, (phys_addr)table);
|
||||||
|
|
||||||
|
pd_entry_t *entry2 = &dir->entries[PAGE_DIRECTORY_INDEX(0x00000000)];
|
||||||
|
pd_entry_add_attr(entry2, PDE_PRESENT);
|
||||||
|
pd_entry_add_attr(entry2, PDE_WRITABLE);
|
||||||
|
pd_entry_set_frame(entry2, (phys_addr)table2);
|
||||||
|
|
||||||
|
// Store current PDBR
|
||||||
|
g_vmm_current_pdbr = (phys_addr)&dir->entries;
|
||||||
|
|
||||||
|
// Switch to our page directory
|
||||||
|
vmm_switch_pdirectory(dir);
|
||||||
|
|
||||||
|
// Enable paging
|
||||||
|
pmm_paging_enable(true);
|
||||||
|
}
|
33
src/kernel/mm/vmm.h
Normal file
33
src/kernel/mm/vmm.h
Normal file
|
@ -0,0 +1,33 @@
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <stdint.h>
|
||||||
|
#include <stdbool.h>
|
||||||
|
#include "pte.h"
|
||||||
|
#include "pde.h"
|
||||||
|
|
||||||
|
typedef uint32_t virt_addr;
|
||||||
|
|
||||||
|
#define PAGES_PER_TABLE 1024
|
||||||
|
#define PAGES_PER_DIR 1024
|
||||||
|
|
||||||
|
#define PAGE_DIRECTORY_INDEX(x) (((x) >> 22) & 0x3FF)
|
||||||
|
#define PAGE_TABLE_INDEX(x) (((x) >> 12) & 0x3FF)
|
||||||
|
#define PAGE_GET_PHYS_ADDR(x) (*(x) & ~0xFFF)
|
||||||
|
|
||||||
|
#define PTABLE_ADDR_SPACE_SIZE 0x400000
|
||||||
|
#define DTABLE_ADDR_SPACE_SIZE 0x100000000
|
||||||
|
|
||||||
|
#define PAGE_SIZE 4096
|
||||||
|
|
||||||
|
typedef struct{
|
||||||
|
pt_entry_t entries[PAGES_PER_TABLE];
|
||||||
|
} vmm_page_table_t;
|
||||||
|
|
||||||
|
typedef struct{
|
||||||
|
pd_entry_t entries[PAGES_PER_DIR];
|
||||||
|
} vmm_page_directory_t;
|
||||||
|
|
||||||
|
bool vmm_alloc_page(pt_entry_t *entry);
|
||||||
|
void vmm_free_page(pt_entry_t *entry);
|
||||||
|
void vmm_map_page(void *phys, void *virt);
|
||||||
|
void vmm_initialize();
|
Loading…
Referencia en una nova incidència