Scoped VMM and PMM to arch/i686

This commit is contained in:
Arnau Camprubí 2022-07-24 18:35:30 +02:00
pare f2b4802db2
commit 707a87828b
S'han modificat 19 arxius amb 486 adicions i 486 eliminacions

Veure arxiu

@ -0,0 +1,33 @@
#include "pde.h"
void i686_pd_entry_add_attr(i686_pd_entry_t *entry, uint32_t attr){
*entry |= attr;
}
void i686_pd_entry_del_attr(i686_pd_entry_t *entry, uint32_t attr){
*entry &= ~attr;
}
void i686_pd_entry_set_frame(i686_pd_entry_t *entry, i686_phys_addr frame){
*entry = (*entry & ~i686_PDE_FRAME) | frame;
}
i686_phys_addr i686_pd_entry_get_frame(i686_pd_entry_t entry){
return entry & i686_PDE_FRAME;
}
bool i686_pd_entry_is_present(i686_pd_entry_t entry){
return entry & i686_PDE_PRESENT;
}
bool i686_pd_entry_is_user(i686_pd_entry_t entry){
return entry & i686_PDE_USER;
}
bool i686_pd_entry_is_4mb(i686_pd_entry_t entry){
return entry & i686_PDE_4MB;
}
bool i686_pd_entry_is_writable(i686_pd_entry_t entry){
return entry & i686_PDE_WRITABLE;
}

Veure arxiu

@ -0,0 +1,30 @@
#pragma once
#include <stdint.h>
#include <stdbool.h>
#include "pmm.h"
enum i686_PDE_PAGE_FLAGS{
i686_PDE_PRESENT = 0x0001,
i686_PDE_WRITABLE = 0x0002,
i686_PDE_USER = 0x0004,
i686_PDE_WRITETHROUGH = 0x0008,
i686_PDE_CACHE_DISABLED = 0x0010,
i686_PDE_ACCESSED = 0x0020,
i686_PDE_DIRTY = 0x0040,
i686_PDE_4MB = 0x0080,
i686_PDE_CPU_GLOBAL = 0x0100,
i686_PDE_LV4_GLOBAL = 0x0200,
i686_PDE_FRAME = 0x7FFFF000,
};
typedef uint32_t i686_pd_entry_t;
void i686_pd_entry_add_attr(i686_pd_entry_t *entry, uint32_t attr);
void i686_pd_entry_del_attr(i686_pd_entry_t *entry, uint32_t attr);
void i686_pd_entry_set_frame(i686_pd_entry_t *entry, i686_phys_addr frame);
i686_phys_addr i686_pd_entry_get_frame(i686_pd_entry_t entry);
bool i686_pd_entry_is_present(i686_pd_entry_t entry);
bool i686_pd_entry_is_user(i686_pd_entry_t entry);
bool i686_pd_entry_is_4mb(i686_pd_entry_t entry);
bool i686_pd_entry_is_writable(i686_pd_entry_t entry);

Veure arxiu

@ -1,5 +1,5 @@
global pmm_paging_enable global i686_pmm_paging_enable
pmm_paging_enable: i686_pmm_paging_enable:
[bits 32] [bits 32]
; New call frame ; New call frame
push ebp push ebp
@ -22,22 +22,22 @@ pmm_paging_enable:
pop ebp pop ebp
ret ret
global pmm_is_paging global i686_pmm_is_paging
pmm_is_paging: i686_pmm_is_paging:
[bits 32] [bits 32]
mov eax, cr0 mov eax, cr0
and eax, 0x80000000 and eax, 0x80000000
ret ret
global pmm_load_pdbr global i686_pmm_load_pdbr
pmm_load_pdbr: i686_pmm_load_pdbr:
[bits 32] [bits 32]
mov eax, [esp + 4] mov eax, [esp + 4]
mov cr3, eax mov cr3, eax
ret ret
global pmm_get_pdbr global i686_pmm_get_pdbr
pmm_get_pdbr: i686_pmm_get_pdbr:
[bits 32] [bits 32]
mov eax, cr3 mov eax, cr3
ret ret

Veure arxiu

@ -0,0 +1,152 @@
#include <stdint.h>
#include "pmm.h"
#include "../../../lib/memory.h"
static uint32_t g_pmm_memory_size = 0;
static uint32_t g_pmm_used_blocks = 0;
static uint32_t g_pmm_max_blocks = 0;
static uint32_t *g_pmm_memory_map = 0;
static inline void i686_pmm_map_set(int bit){
g_pmm_memory_map[bit / 32] |= (1 << (bit % 32));
}
static inline void i686_pmm_map_unset(int bit){
g_pmm_memory_map[bit / 32] &= ~(1 << (bit % 32));
}
static inline bool i686_pmm_map_get(int bit){
return g_pmm_memory_map[bit / 32] & (1 << (bit % 32));
}
int i686_pmm_map_first_free(){
for(uint32_t i = 0; i < i686_pmm_get_block_count() / 32; i++){
if(g_pmm_memory_map[i] != 0xffffffff){
for(int j = 0; j < 32; j++){
if(!(g_pmm_memory_map[i] & (1 << j))){
return i*4*8+j;
}
}
}
}
return -1;
}
int i686_pmm_map_first_free_s(size_t size){
if(size == 0) return -1;
if(size == 1) return i686_pmm_map_first_free();
for(uint32_t i = 0; i < i686_pmm_get_block_count() / 32; i++){
if(g_pmm_memory_map[i] != 0xffffffff){
for(int j = 0; j < 32; j++){
int bit = 1 << j;
if(!(g_pmm_memory_map[i] & bit)){
int start_bit = i*32;
start_bit+=bit;
uint32_t free = 0;
for(uint32_t count = 0; count <= size; count++){
if(!i686_pmm_map_get(start_bit+count)) free++;
if(free == size) return i*4*8+j;
}
}
}
}
}
return -1;
}
void i686_pmm_initialize(size_t mem_size, i686_phys_addr bitmap){
g_pmm_memory_size = mem_size;
g_pmm_memory_map = (uint32_t *)bitmap;
g_pmm_max_blocks = (i686_pmm_get_memory_size()*1024) / i686_PMM_BLOCK_SIZE;
g_pmm_used_blocks = g_pmm_max_blocks;
memset(g_pmm_memory_map, 0xFF, i686_pmm_get_block_count() / i686_PMM_BLOCKS_PER_BYTE);
}
void i686_pmm_init_region(i686_phys_addr base, size_t size){
int align = base / i686_PMM_BLOCK_SIZE;
int blocks = size / i686_PMM_BLOCK_SIZE;
for(; blocks >= 0; blocks--){
i686_pmm_map_unset(align++);
g_pmm_used_blocks--;
}
i686_pmm_map_set(0); // First block always set
}
void i686_pmm_deinit_region(i686_phys_addr base, size_t size){
int align = base / i686_PMM_BLOCK_SIZE;
int blocks = size / i686_PMM_BLOCK_SIZE;
for(; blocks >= 0; blocks--){
i686_pmm_map_set(align++);
g_pmm_used_blocks++;
}
i686_pmm_map_set(0); // First block always set
}
void *i686_pmm_alloc_block(){
if(i686_pmm_get_free_block_count() <= 0) return 0; // Out of memory
int frame = i686_pmm_map_first_free();
if(frame == -1) return 0; // Out of memory
i686_pmm_map_set(frame);
i686_phys_addr addr = frame * i686_PMM_BLOCK_SIZE;
g_pmm_used_blocks++;
return (void *)addr;
}
void i686_pmm_free_block(void *p){
i686_phys_addr addr = (i686_phys_addr)p;
int frame = addr / i686_PMM_BLOCK_SIZE;
i686_pmm_map_unset(frame);
g_pmm_used_blocks--;
}
void *i686_pmm_alloc_blocks(size_t size){
if(i686_pmm_get_free_block_count() <= size) return 0; // Out of memory
int frame = i686_pmm_map_first_free_s(size);
if(frame == -1) return 0; // Out of memory
for(uint32_t i = 0; i < size; i++) i686_pmm_map_set(frame+i);
i686_phys_addr addr = frame * i686_PMM_BLOCK_SIZE;
g_pmm_used_blocks += size;
return (void *)addr;
}
void i686_pmm_free_blocks(void *p, size_t size){
i686_phys_addr addr = (i686_phys_addr)p;
int frame = addr / i686_PMM_BLOCK_SIZE;
for(uint32_t i = 0; i < size; i++) i686_pmm_map_unset(frame+i);
g_pmm_used_blocks -= size;
}
size_t i686_pmm_get_memory_size(){
return g_pmm_memory_size;
}
uint32_t i686_pmm_get_block_count(){
return g_pmm_max_blocks;
}
uint32_t i686_pmm_get_used_block_count(){
return g_pmm_used_blocks;
}
uint32_t i686_pmm_get_free_block_count(){
return g_pmm_max_blocks - g_pmm_used_blocks;
}

Veure arxiu

@ -0,0 +1,28 @@
#pragma once
#include <stdbool.h>
#include <stddef.h>
#define i686_PMM_BLOCKS_PER_BYTE 8
#define i686_PMM_BLOCK_SIZE 4096
#define i686_PMM_BLOCK_ALIGN PMM_BLOCK_SIZE
typedef uint32_t i686_phys_addr;
int i686_pmm_map_first_free();
int i686_pmm_map_first_free_s(size_t size);
void i686_pmm_initialize(size_t mem_size, i686_phys_addr bitmap);
void i686_pmm_init_region(i686_phys_addr base, size_t size);
void i686_pmm_deinit_region(i686_phys_addr base, size_t size);
void *i686_pmm_alloc_block();
void i686_pmm_free_block(void *p);
void *i686_pmm_alloc_blocks(size_t size);
void i686_pmm_free_blocks(void *p, size_t size);
size_t i686_pmm_get_memory_size();
uint32_t i686_pmm_get_block_count();
uint32_t i686_pmm_get_used_block_count();
uint32_t i686_pmm_get_free_block_count();
void __attribute__((cdecl)) i686_pmm_paging_enable(bool enabled);
bool __attribute__((cdecl)) i686_pmm_is_paging();
void __attribute__((cdecl)) i686_pmm_load_pdbr(i686_phys_addr addr);
i686_phys_addr __attribute__((cdecl)) i686_pmm_get_pdbr();

Veure arxiu

@ -0,0 +1,25 @@
#include "pte.h"
void i686_pt_entry_add_attr(i686_pt_entry_t *entry, uint32_t attr){
*entry |= attr;
}
void i686_pt_entry_del_attr(i686_pt_entry_t *entry, uint32_t attr){
*entry &= ~attr;
}
void i686_pt_entry_set_frame(i686_pt_entry_t *entry, i686_phys_addr frame){
*entry = (*entry & ~i686_PTE_FRAME) | frame;
}
i686_phys_addr i686_pt_entry_get_frame(i686_pt_entry_t entry){
return entry & i686_PTE_FRAME;
}
bool i686_pt_entry_is_present(i686_pt_entry_t entry){
return entry & i686_PTE_PRESENT;
}
bool i686_pt_entry_is_writable(i686_pt_entry_t entry){
return entry & i686_PTE_WRITABLE;
}

Veure arxiu

@ -0,0 +1,27 @@
#pragma once
#include <stdint.h>
#include "pmm.h"
enum i686_PTE_PAGE_FLAGS{
i686_PTE_PRESENT = 0x0001,
i686_PTE_WRITABLE = 0x0002,
i686_PTE_USER = 0x0004,
i686_PTE_WRITETHROUGH = 0x0008,
i686_PTE_NOT_CACHEABLE = 0x0010,
i686_PTE_ACCESSED = 0x0020,
i686_PTE_DIRTY = 0x0040,
i686_PTE_PAT = 0x0080,
i686_PTE_CPU_GLOBAL = 0x0100,
i686_PTE_LV4_GLOBAL = 0x0200,
i686_PTE_FRAME = 0x7FFFF000
};
typedef uint32_t i686_pt_entry_t;
void i686_pt_entry_add_attr(i686_pt_entry_t *entry, uint32_t attr);
void i686_pt_entry_del_attr(i686_pt_entry_t *entry, uint32_t attr);
void i686_pt_entry_set_frame(i686_pt_entry_t *entry, i686_phys_addr frame);
i686_phys_addr i686_pt_entry_get_frame(i686_pt_entry_t entry);
bool i686_pt_entry_is_present(i686_pt_entry_t entry);
bool i686_pt_entry_is_writable(i686_pt_entry_t entry);

Veure arxiu

@ -1,5 +1,5 @@
global vmm_flush_tlb_entry global i686_vmm_flush_tlb_entry
vmm_flush_tlb_entry: i686_vmm_flush_tlb_entry:
[bits 32] [bits 32]
cli cli
invlpg [esp + 4] invlpg [esp + 4]

Veure arxiu

@ -0,0 +1,142 @@
#include "vmm.h"
#include "pmm.h"
#include "../../../lib/memory.h"
i686_vmm_page_directory_t *g_vmm_current_dir = 0;
i686_phys_addr g_vmm_current_pdbr = 0;
void __attribute__((cdecl)) i686_vmm_flush_tlb_entry(i686_virt_addr addr);
static inline i686_pt_entry_t *i686_vmm_ptable_lookup_entry(i686_vmm_page_table_t *p, i686_virt_addr addr){
if(p) return &p->entries[i686_PAGE_TABLE_INDEX(addr)];
return 0;
}
static inline i686_pd_entry_t *i686_vmm_pdirectory_lookup_entry(i686_vmm_page_directory_t *p, i686_virt_addr addr){
if(p) return &p->entries[i686_PAGE_DIRECTORY_INDEX(addr)];
return 0;
}
static inline bool i686_vmm_switch_pdirectory(i686_vmm_page_directory_t *dir){
if(!dir) return false;
g_vmm_current_dir = dir;
i686_pmm_load_pdbr(g_vmm_current_pdbr);
return true;
}
static inline i686_vmm_page_directory_t *i686_vmm_get_pdirectory(){
return g_vmm_current_dir;
}
bool i686_vmm_alloc_page(i686_pt_entry_t *entry){
void *p = i686_pmm_alloc_block();
if(!p) return false;
i686_pt_entry_set_frame(entry, (i686_phys_addr)p);
i686_pt_entry_add_attr(entry, i686_PTE_PRESENT);
return true;
}
void i686_vmm_free_page(i686_pt_entry_t *entry){
void *p = (void *)i686_pt_entry_get_frame(*entry);
if(p) i686_pmm_free_block(p);
i686_pt_entry_del_attr(entry, i686_PTE_PRESENT);
}
void i686_vmm_map_page(void *phys, void *virt){
// Get page directory
i686_vmm_page_directory_t *page_dir = i686_vmm_get_pdirectory();
// Get page table
i686_pd_entry_t *e = &page_dir->entries[i686_PAGE_DIRECTORY_INDEX((uint32_t)virt)];
if((*e & i686_PTE_PRESENT) != i686_PTE_PRESENT){
// Must allocate
i686_vmm_page_table_t *table = (i686_vmm_page_table_t *)i686_pmm_alloc_block();
if(!table) return;
// Clear page table
memset(table, 0, sizeof(i686_vmm_page_table_t));
// Create a new entry
i686_pd_entry_t *entry = &page_dir->entries[i686_PAGE_DIRECTORY_INDEX((uint32_t)virt)];
// Map in the table
i686_pd_entry_add_attr(entry, i686_PDE_PRESENT);
i686_pd_entry_add_attr(entry, i686_PDE_WRITABLE);
i686_pd_entry_set_frame(entry, (i686_phys_addr)table);
}
// Get table
i686_vmm_page_table_t *table = (i686_vmm_page_table_t *)i686_PAGE_GET_PHYS_ADDR(e);
// Get page
i686_pt_entry_t *page = &table->entries[i686_PAGE_TABLE_INDEX((uint32_t)virt)];
// Map it
i686_pt_entry_set_frame(page, (i686_phys_addr)phys);
i686_pt_entry_add_attr(page, i686_PTE_PRESENT);
}
void i686_vmm_initialize(){
// Allocate default page table
i686_vmm_page_table_t *table = (i686_vmm_page_table_t *)i686_pmm_alloc_block();
if(!table) return;
// Allocate 3GB page table
i686_vmm_page_table_t *table2 = (i686_vmm_page_table_t *)i686_pmm_alloc_block();
if(!table2) return;
// Clear default table
memset(table, 0, sizeof(i686_vmm_page_table_t));
// First 4MB are identity mapped
for(int i = 0, frame = 0x0, virt = 0x00000000; i<1024; i++, frame += 4096, virt += 4096){
// Create a new page
i686_pt_entry_t page = 0;
i686_pt_entry_add_attr(&page, i686_PTE_PRESENT);
i686_pt_entry_set_frame(&page, frame);
// Add the page to the page table
table2->entries[i686_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
i686_pt_entry_t page = 0;
i686_pt_entry_add_attr(&page, i686_PTE_PRESENT);
i686_pt_entry_set_frame(&page, frame);
// Add the page to the page table
table->entries[i686_PAGE_TABLE_INDEX(virt)] = page;
}
// Create default directory table
i686_vmm_page_directory_t *dir = (i686_vmm_page_directory_t *)i686_pmm_alloc_blocks(3);
if(!dir) return;
// Clear directory table and set it as current
memset(dir, 0, sizeof(i686_vmm_page_directory_t));
i686_pd_entry_t *entry = &dir->entries[i686_PAGE_DIRECTORY_INDEX(0xc0000000)];
i686_pd_entry_add_attr(entry, i686_PDE_PRESENT);
i686_pd_entry_add_attr(entry, i686_PDE_WRITABLE);
i686_pd_entry_set_frame(entry, (i686_phys_addr)table);
i686_pd_entry_t *entry2 = &dir->entries[i686_PAGE_DIRECTORY_INDEX(0x00000000)];
i686_pd_entry_add_attr(entry2, i686_PDE_PRESENT);
i686_pd_entry_add_attr(entry2, i686_PDE_WRITABLE);
i686_pd_entry_set_frame(entry2, (i686_phys_addr)table2);
// Store current PDBR
g_vmm_current_pdbr = (i686_phys_addr)&dir->entries;
// Switch to our page directory
i686_vmm_switch_pdirectory(dir);
// Enable paging
i686_pmm_paging_enable(true);
}

Veure arxiu

@ -0,0 +1,33 @@
#pragma once
#include <stdint.h>
#include <stdbool.h>
#include "pte.h"
#include "pde.h"
typedef uint32_t i686_virt_addr;
#define i686_PAGES_PER_TABLE 1024
#define i686_PAGES_PER_DIR 1024
#define i686_PAGE_DIRECTORY_INDEX(x) (((x) >> 22) & 0x3FF)
#define i686_PAGE_TABLE_INDEX(x) (((x) >> 12) & 0x3FF)
#define i686_PAGE_GET_PHYS_ADDR(x) (*(x) & ~0xFFF)
#define i686_PTABLE_ADDR_SPACE_SIZE 0x400000
#define i686_DTABLE_ADDR_SPACE_SIZE 0x100000000
#define i686_PAGE_SIZE 4096
typedef struct{
i686_pt_entry_t entries[i686_PAGES_PER_TABLE];
} i686_vmm_page_table_t;
typedef struct{
i686_pd_entry_t entries[i686_PAGES_PER_DIR];
} i686_vmm_page_directory_t;
bool i686_vmm_alloc_page(i686_pt_entry_t *entry);
void i686_vmm_free_page(i686_pt_entry_t *entry);
void i686_vmm_map_page(void *phys, void *virt);
void i686_vmm_initialize();

Veure arxiu

@ -5,8 +5,8 @@
#include "drivers/keyboard.h" #include "drivers/keyboard.h"
#include "drivers/serial.h" #include "drivers/serial.h"
#include "fs/vfs.h" #include "fs/vfs.h"
#include "mm/pmm.h" #include "arch/i686/mm/pmm.h"
#include "mm/vmm.h" #include "arch/i686/mm/vmm.h"
#include "multiboot.h" #include "multiboot.h"
extern uint8_t end; // Kernel end extern uint8_t end; // Kernel end
@ -21,21 +21,21 @@ void __attribute__((cdecl)) kmain(multiboot_info_t *multiboot_info){
// Initialize physical memory manager // Initialize physical memory manager
uint32_t mem_size = 1024 + multiboot_info->mem_lower + multiboot_info->mem_upper*64; uint32_t mem_size = 1024 + multiboot_info->mem_lower + multiboot_info->mem_upper*64;
pmm_initialize(mem_size, (int)(&end)); i686_pmm_initialize(mem_size, (int)(&end));
for(int i = 0; i < multiboot_info->mmap_length; i += sizeof(multiboot_memory_map_t)){ for(int i = 0; i < multiboot_info->mmap_length; i += sizeof(multiboot_memory_map_t)){
multiboot_memory_map_t *memory_map = (multiboot_memory_map_t *)(multiboot_info->mmap_addr + i); multiboot_memory_map_t *memory_map = (multiboot_memory_map_t *)(multiboot_info->mmap_addr + i);
printf("Start Addr: 0x%x%x | Length: 0x%x%x | Size: 0x%x | Type: %i\n", memory_map->addr_h, memory_map->addr_l, memory_map->len_h, memory_map->len_l, memory_map->size, memory_map->type); printf("Start Addr: 0x%x%x | Length: 0x%x%x | Size: 0x%x | Type: %i\n", memory_map->addr_h, memory_map->addr_l, memory_map->len_h, memory_map->len_l, memory_map->size, memory_map->type);
if(memory_map->type == 1){ if(memory_map->type == 1){
pmm_init_region(memory_map->addr_l, memory_map->len_l); i686_pmm_init_region(memory_map->addr_l, memory_map->len_l);
} }
} }
pmm_deinit_region(0x100000, (int)(&end) - 0x100000); // Deinit the section the kernel is in i686_pmm_deinit_region(0x100000, (int)(&end) - 0x100000); // Deinit the section the kernel is in
// Initialize virtual memory // Initialize virtual memory
vmm_initialize(); i686_vmm_initialize();
// Initialize drivers // Initialize drivers
timer_initialize(); timer_initialize();

Veure arxiu

@ -1,33 +0,0 @@
#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 = (*entry & ~PDE_FRAME) | frame;
}
phys_addr pd_entry_get_frame(pd_entry_t entry){
return entry & PDE_FRAME;
}
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;
}

Veure arxiu

@ -1,30 +0,0 @@
#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);

Veure arxiu

@ -1,152 +0,0 @@
#include <stdint.h>
#include "pmm.h"
#include "../lib/memory.h"
static uint32_t g_pmm_memory_size = 0;
static uint32_t g_pmm_used_blocks = 0;
static uint32_t g_pmm_max_blocks = 0;
static uint32_t *g_pmm_memory_map = 0;
static inline void pmm_map_set(int bit){
g_pmm_memory_map[bit / 32] |= (1 << (bit % 32));
}
static inline void pmm_map_unset(int bit){
g_pmm_memory_map[bit / 32] &= ~(1 << (bit % 32));
}
static inline bool pmm_map_get(int bit){
return g_pmm_memory_map[bit / 32] & (1 << (bit % 32));
}
int pmm_map_first_free(){
for(uint32_t i = 0; i < pmm_get_block_count() / 32; i++){
if(g_pmm_memory_map[i] != 0xffffffff){
for(int j = 0; j < 32; j++){
if(!(g_pmm_memory_map[i] & (1 << j))){
return i*4*8+j;
}
}
}
}
return -1;
}
int pmm_map_first_free_s(size_t size){
if(size == 0) return -1;
if(size == 1) return pmm_map_first_free();
for(uint32_t i = 0; i < pmm_get_block_count() / 32; i++){
if(g_pmm_memory_map[i] != 0xffffffff){
for(int j = 0; j < 32; j++){
int bit = 1 << j;
if(!(g_pmm_memory_map[i] & bit)){
int start_bit = i*32;
start_bit+=bit;
uint32_t free = 0;
for(uint32_t count = 0; count <= size; count++){
if(!pmm_map_get(start_bit+count)) free++;
if(free == size) return i*4*8+j;
}
}
}
}
}
return -1;
}
void pmm_initialize(size_t mem_size, phys_addr bitmap){
g_pmm_memory_size = mem_size;
g_pmm_memory_map = (uint32_t *)bitmap;
g_pmm_max_blocks = (pmm_get_memory_size()*1024) / PMM_BLOCK_SIZE;
g_pmm_used_blocks = g_pmm_max_blocks;
memset(g_pmm_memory_map, 0xFF, pmm_get_block_count() / PMM_BLOCKS_PER_BYTE);
}
void pmm_init_region(phys_addr base, size_t size){
int align = base / PMM_BLOCK_SIZE;
int blocks = size / PMM_BLOCK_SIZE;
for(; blocks >= 0; blocks--){
pmm_map_unset(align++);
g_pmm_used_blocks--;
}
pmm_map_set(0); // First block always set
}
void pmm_deinit_region(phys_addr base, size_t size){
int align = base / PMM_BLOCK_SIZE;
int blocks = size / PMM_BLOCK_SIZE;
for(; blocks >= 0; blocks--){
pmm_map_set(align++);
g_pmm_used_blocks++;
}
pmm_map_set(0); // First block always set
}
void *pmm_alloc_block(){
if(pmm_get_free_block_count() <= 0) return 0; // Out of memory
int frame = pmm_map_first_free();
if(frame == -1) return 0; // Out of memory
pmm_map_set(frame);
phys_addr addr = frame * PMM_BLOCK_SIZE;
g_pmm_used_blocks++;
return (void *)addr;
}
void pmm_free_block(void *p){
phys_addr addr = (phys_addr)p;
int frame = addr / PMM_BLOCK_SIZE;
pmm_map_unset(frame);
g_pmm_used_blocks--;
}
void *pmm_alloc_blocks(size_t size){
if(pmm_get_free_block_count() <= size) return 0; // Out of memory
int frame = pmm_map_first_free_s(size);
if(frame == -1) return 0; // Out of memory
for(uint32_t i = 0; i < size; i++) pmm_map_set(frame+i);
phys_addr addr = frame * PMM_BLOCK_SIZE;
g_pmm_used_blocks += size;
return (void *)addr;
}
void pmm_free_blocks(void *p, size_t size){
phys_addr addr = (phys_addr)p;
int frame = addr / PMM_BLOCK_SIZE;
for(uint32_t i = 0; i < size; i++) pmm_map_unset(frame+i);
g_pmm_used_blocks -= size;
}
size_t pmm_get_memory_size(){
return g_pmm_memory_size;
}
uint32_t pmm_get_block_count(){
return g_pmm_max_blocks;
}
uint32_t pmm_get_used_block_count(){
return g_pmm_used_blocks;
}
uint32_t pmm_get_free_block_count(){
return g_pmm_max_blocks - g_pmm_used_blocks;
}

Veure arxiu

@ -1,28 +0,0 @@
#pragma once
#include <stdbool.h>
#include <stddef.h>
#define PMM_BLOCKS_PER_BYTE 8
#define PMM_BLOCK_SIZE 4096
#define PMM_BLOCK_ALIGN PMM_BLOCK_SIZE
typedef uint32_t phys_addr;
int pmm_map_first_free();
int pmm_map_first_free_s(size_t size);
void pmm_initialize(size_t mem_size, phys_addr bitmap);
void pmm_init_region(phys_addr base, size_t size);
void pmm_deinit_region(phys_addr base, size_t size);
void *pmm_alloc_block();
void pmm_free_block(void *p);
void *pmm_alloc_blocks(size_t size);
void pmm_free_blocks(void *p, size_t size);
size_t pmm_get_memory_size();
uint32_t pmm_get_block_count();
uint32_t pmm_get_used_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();

Veure arxiu

@ -1,25 +0,0 @@
#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 = (*entry & ~PTE_FRAME) | frame;
}
phys_addr pt_entry_get_frame(pt_entry_t entry){
return entry & PTE_FRAME;
}
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;
}

Veure arxiu

@ -1,27 +0,0 @@
#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);

Veure arxiu

@ -1,142 +0,0 @@
#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 4MB 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);
}

Veure arxiu

@ -1,33 +0,0 @@
#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();