paging.h
Code: Select all
/*
* paging.h
*
* Created on: Jul 2, 2016
* Author: alexander
*/
#ifndef INCLUDE_MEM_PAGING_H_
#define INCLUDE_MEM_PAGING_H_
typedef union {
struct {
uint16_t offset : 12;
uint16_t table_entry : 10;
uint16_t directory_entry : 10;
} __attribute__((packed)) page_addr;
uint32_t linear_addr;
} vaddr_t;
typedef struct {
uint8_t present : 1;
uint8_t read_write : 1;
uint8_t user_supervisor : 1;
uint8_t write_through : 1;
uint8_t cache_disabled : 1;
uint8_t accessed : 1;
} __attribute__((packed)) paging_common_flags_t;
typedef struct {
struct {
paging_common_flags_t common;
uint8_t zero : 1;
uint8_t page_size : 1;
uint8_t ignored : 1;
} flags;
uint8_t available : 3;
uint32_t page_table_addr : 20;
} __attribute__((packed)) page_directory_entry_t;
typedef struct {
struct {
paging_common_flags_t common;
uint8_t dirty : 1;
uint8_t zero : 1;
uint8_t ignored : 1;
} flags;
uint8_t available : 3;
uint32_t page_phys_addr;
} __attribute__((packed)) page_table_entry_t;
void init_paging();
void identity_page(void* addr, uint32_t frames, paging_common_flags_t flags);
void map_frame_range(vaddr_t virt_addr, void* phys_addr, uint32_t frames, paging_common_flags_t flags);
void map_page(vaddr_t virt_addr, void* phys_addr, paging_common_flags_t flags);
void* get_phys_addr(vaddr_t virt_addr);
#endif /* INCLUDE_MEM_PAGING_H_ */
Code: Select all
/*
* paging.c
*
* Created on: Jul 2, 2016
* Author: alexander
*/
#include "general/includes.h"
page_directory_entry_t* page_directory;
void init_paging() {
page_directory = kalloc(sizeof(page_directory_entry_t) * 1024, 0x1000); // kalloc() zeroes it
paging_common_flags_t flags;
flags.present = 1;
flags.user_supervisor = 1;
flags.read_write = 0;
identity_page(0, HEAP_START / 0x1000, flags);
flags.read_write = 1;
identity_page((void*) HEAP_START, HEAP_SIZE / 0x1000, flags);
__asm__(
"movl %0, %%cr3\n"
"movl %%cr0, %%eax\n"
"orl $0x80000000, %%eax\n"
"movl %%eax, %%cr0" :
:
"r"(page_directory)
);
}
void identity_page(void* addr, uint32_t frames, paging_common_flags_t flags) {
vaddr_t virt_addr;
virt_addr.linear_addr = (uint32_t)(size_t) addr;
map_frame_range(virt_addr, addr, frames, flags);
}
void map_frame_range(vaddr_t virt_addr, void* phys_addr, uint32_t frames, paging_common_flags_t flags) {
for(uint32_t frame = 0; frame < frames; frame++) {
map_page(virt_addr, (void*)((size_t) phys_addr + frame * 0x1000), flags);
virt_addr.linear_addr += 0x1000;
}
}
void map_page(vaddr_t virt_addr, void* phys_addr, paging_common_flags_t flags) {
uint32_t pd_entry_ix = virt_addr.page_addr.directory_entry;
page_directory_entry_t pd_entry = page_directory[pd_entry_ix];
page_table_entry_t* page_table;
if(!pd_entry.flags.common.present) {
page_table_entry_t* table = kalloc(1024 * sizeof(page_table_entry_t), 0x1000);
pd_entry.page_table_addr = (uint32_t)(size_t) table >> 12;
pd_entry.flags.common.read_write = 1;
pd_entry.flags.common.user_supervisor = 1;
pd_entry.flags.common.present = 1;
page_table = table;
page_directory[pd_entry_ix] = pd_entry;
} else {
page_table = (void*)(size_t)(pd_entry.page_table_addr << 12);
}
uint32_t pt_entry_ix = virt_addr.page_addr.table_entry;
page_table_entry_t pt_entry = page_table[pt_entry_ix];
pt_entry.page_phys_addr = (uint32_t)(size_t) phys_addr >> 12;
pt_entry.flags.common = flags;
page_table[pt_entry_ix] = pt_entry;
}
void* get_phys_addr(vaddr_t virt_addr) {
uint32_t pd_entry_ix = virt_addr.page_addr.directory_entry;
page_directory_entry_t pd_entry = page_directory[pd_entry_ix];
if(!pd_entry.flags.common.present) {
return NULL;
}
page_table_entry_t* page_table = (void*)(size_t)(pd_entry.page_table_addr << 12);
uint32_t pt_entry_ix = virt_addr.page_addr.table_entry;
page_table_entry_t pt_entry = page_table[pt_entry_ix];
if(!pt_entry.flags.common.present) {
return NULL;
}
uint32_t phys_offset = pt_entry.page_phys_addr << 12;
void* phys_addr = (void*)(size_t)(phys_offset + virt_addr.page_addr.offset);
return phys_addr;
}
Code: Select all
void* __heap = (void*) 2097152;
#define HEAP_SIZE (24 * 1048576)
void* kalloc(size_t size, size_t align) {
#ifdef DEBUG
printf("Allocating %d bytes aligned by 0x%x, __heap = 0x%x\n", size, align, __heap);
#endif // DEBUG
if(align != 0 && (size_t) __heap % align) {
__heap += align - (size_t) __heap % align;
}
void* addr = __heap;
__heap += size;
memset(addr, 0x00, size);
return addr;
}
Code: Select all
; EAX contains 2097152 (page directory is the first thing that gets allocated on heap)
<0x10113C> MOV CR3, EAX
<0x10113F> MOV EAX, CR0
; EAX contains 0x11
<0x101142> OR EAX, 0x80000000
; EAX contains 0x80000011
<0x101147> MOV CR0, EAX
; (gdb) Cannot access memory at address 0x101193
You can see the full OS at https://github.com/velikiyv4/VV4OS, branch 'paging'.