Skip to content

Commit

Permalink
Refactor paging to allow proper mapping
Browse files Browse the repository at this point in the history
  • Loading branch information
lexs committed Jan 19, 2014
1 parent 4cb2efb commit e053bf2
Show file tree
Hide file tree
Showing 5 changed files with 92 additions and 114 deletions.
2 changes: 1 addition & 1 deletion rost/exec/elf.rs
Original file line number Diff line number Diff line change
Expand Up @@ -158,7 +158,7 @@ fn write(msg: &str, value: u32) {

unsafe fn load_program_header(buffer: *u8, header: &ProgramHeader) {
console::write_str("load_program_header()\n");
paging::map(header.p_vaddr, header.p_memsz);
paging::map(header.p_vaddr, header.p_memsz, paging::FLAG_WRITE);
let vaddr = header.p_vaddr as *mut u8;
console::write_str("Loading data at ");
console::write_hex(vaddr as u32);
Expand Down
20 changes: 20 additions & 0 deletions rost/memory/allocator.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
static FRAME_SIZE: u32 = 0x1000;

static mut next_frame: u32 = 1024; // First 1MB is in use, TODO: Make this nicer


pub fn init() {
unsafe {
// Mark frames up to kernel_end as used
extern { static kernel_end: u32; }
next_frame = kernel_end % FRAME_SIZE + 1;
}
}

pub fn allocate_frame() -> u32 {
unsafe {
let frame = next_frame;
next_frame += 1;
frame * FRAME_SIZE
}
}
3 changes: 2 additions & 1 deletion rost/memory/mod.rs
Original file line number Diff line number Diff line change
@@ -1 +1,2 @@
pub mod paging;
pub mod allocator;
pub mod paging;
180 changes: 68 additions & 112 deletions rost/memory/paging.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,71 +2,78 @@ use core::mem::size_of;

use kernel::console;
use arch::idt;
use memory::allocator;

static PAGE_SIZE: u32 = 0x1000;

static NUM_ENTRIES: u32 = 1024;

#[packed]
struct Page(u32);

#[packed]
struct PageTable {
pages: [Page, ..1024]
entries: [Page, ..NUM_ENTRIES]
}

#[packed]
struct PageDirectory {
tables: [u32, ..1024]
}
static mut kernel_directory: *mut PageTable = 0xFFFFF000 as *mut PageTable;
static PAGES : u32 = 0xFFC00000;

static mut kernel_directory: *mut PageDirectory = 0 as *mut PageDirectory;
pub static FLAG_PRESENT: u32 = 1 << 0;
pub static FLAG_WRITE: u32 = 1 << 1;
pub static FLAG_USER: u32 = 1 << 2;

static NO_FLAGS: u32 = 0;
static FLAG_PRESENT: u32 = 1 << 0;
static FLAG_WRITE: u32 = 1 << 1;
static FLAG_USER: u32 = 1 << 2;

static mut next_frame: u32 = 0;
fn get_next_frame() -> u32 {
pub fn init() {
unsafe {
let frame = next_frame;
next_frame += 1;
frame
let directory = allocator::allocate_frame() as *mut PageTable;
*directory = PageTable::empty();

let table = allocator::allocate_frame() as *mut PageTable;
*table = PageTable::empty();

// Identity map table the whole table, 4MB
let mut i = 0;
while i < PAGE_SIZE * NUM_ENTRIES {
let page = (*table).get_page(i);
page.set(i, FLAG_PRESENT | FLAG_WRITE);
i += PAGE_SIZE;
}

(*directory).set_entry(0, table, FLAG_PRESENT | FLAG_WRITE);

// Map the directory itself as the last entry
(*directory).set_entry(dir_index(kernel_directory as u32), directory, FLAG_PRESENT | FLAG_WRITE);

idt::register_isr_handler(14, page_fault);

switch_page_directory(unsafe { directory });
}
}

pub fn init() {
pub fn map(addr: u32, size: u32, flags: u32) {
unsafe {
kernel_directory = box_alloc(PageDirectory::new());
}
// FIXME: We assume the table doesn't exist and it can hold the whole size
let directory_index = dir_index(addr);

// Identity map all currently used memory
let mut i = 0;
// We don't currently have a real malloc so just use some extra space
while i < unsafe { placement_address + PAGE_SIZE * 10 } {
let page = unsafe { (*kernel_directory).get_page(i) };
page.set(get_next_frame() * PAGE_SIZE, FLAG_PRESENT | FLAG_WRITE);
i += PAGE_SIZE;
}
let table_physical = allocator::allocate_frame() as *mut PageTable;
(*kernel_directory).set_entry(directory_index, table_physical, FLAG_PRESENT | flags);

idt::register_isr_handler(14, page_fault);
let table = page_table(directory_index);
// Flush table so we can write to its virtual address
flush_tlb(table);

switch_page_directory(unsafe { kernel_directory });
}
*table = PageTable::empty();

pub fn map(addr: u32, size: u32) {
let mut current_addr = addr;
while current_addr < addr + size {
let page = unsafe { (*kernel_directory).get_page(current_addr) };
page.set(get_next_frame() * PAGE_SIZE, FLAG_PRESENT | FLAG_WRITE);
flush_tlb(current_addr);
let mut current_addr = addr;
while current_addr < addr + size {
let page = (*table).get_page(current_addr);

current_addr += PAGE_SIZE;
}
page.set(allocator::allocate_frame(), FLAG_PRESENT | FLAG_WRITE);
flush_tlb(current_addr);

console::write_str("Mapping: ");
console::write_hex(addr);
console::write_newline();
//reload_page_directory();
current_addr += PAGE_SIZE;
}
}
}

fn page_fault(regs: &idt::Registers) {
Expand Down Expand Up @@ -110,66 +117,40 @@ impl Page {

impl PageTable {
fn empty() -> PageTable {
PageTable { pages: [Page::empty(), ..1024] }
PageTable { entries: [Page::empty(), ..NUM_ENTRIES] }
}
}

impl PageDirectory {
fn new() -> PageDirectory {
PageDirectory {
tables: [0, ..1024]
}
unsafe fn set_entry<T>(&mut self, index: u32, entry: *mut T, flags: u32) {
self.entries[index] = Page(entry as u32 | flags);
}

unsafe fn get_table(&mut self, address: u32) -> *mut PageTable {
let table_index = address / (4096 * 1024);

/*console::write_str("Table index: ");
console::write_num(table_index);
console::write_newline();*/

if to_addr(self.tables[table_index]) == 0 {
//console::write_str("does not exists\n");
let table = box_alloc(PageTable::empty());



self.tables[table_index] = table as u32 | FLAG_PRESENT | FLAG_WRITE | FLAG_USER;
table
} else {
//console::write_str("exists\n");
to_addr(self.tables[table_index]) as *mut PageTable
}
unsafe fn get_page<'a>(&'a mut self, addr: u32) -> &'a mut Page {
&'a mut self.entries[table_index(addr)]
}
}

unsafe fn get_page(&mut self, address: u32) -> &mut Page {
let table = self.get_table(address);

let page_index = address / 4096;

/*console::write_str("Page index: ");
console::write_num(page_index % 1024);
console::write_newline();*/
fn page_table(index: u32) -> *mut PageTable {
let size = size_of::<PageTable>() as u32;
(PAGES + index * size) as *mut PageTable
}

&mut (*table).pages[page_index % 1024]
}
fn dir_index(addr: u32) -> u32 {
addr / (PAGE_SIZE * NUM_ENTRIES)
}

unsafe fn get_physical(&mut self, address: u32) -> u32 {
let page = self.get_page(address);
page.addr() + (address % 1024)
}
fn table_index(addr: u32) -> u32 {
(addr / PAGE_SIZE) % NUM_ENTRIES
}

fn flush_tlb(addr: u32) {
fn flush_tlb<T>(addr: T) {
unsafe {
asm!("invlpg ($0)" :: "r"(addr) : "volatile memory");
asm!("invlpg ($0)" :: "r"(addr) : "volatile", "memory");

This comment has been minimized.

Copy link
@pczarn

This comment has been minimized.

Copy link
@lexs

lexs Feb 7, 2014

Author Owner

Damn it, would be nice if Rust complained if you did something stupid here.

This comment has been minimized.

Copy link
@pczarn

pczarn Mar 14, 2014

@lexs Fixed in rust-lang/rust#12798
Rust should give a warning: expected a clobber, but found an option.

}
}

fn switch_page_directory(directory: *mut PageDirectory) {
fn switch_page_directory(directory: *mut PageTable) {
unsafe {
let address = (*directory).get_physical(directory as u32);
write_cr3(address);
write_cr3(directory as u32);
// Set the paging bit in CR0 to 1
write_cr0(read_cr0() | 0x80000000);
}
Expand Down Expand Up @@ -202,28 +183,3 @@ unsafe fn read_cr0() -> u32 {
unsafe fn write_cr0(value: u32) {
asm!("mov $0, %cr0" :: "r"(value) :: "volatile");
}

#[inline]
unsafe fn box_alloc<T>(value: T) -> *mut T {
let size = size_of::<T>();
let ptr = alloc::<T>(size as u32);
*ptr = value;
ptr
}

static mut placement_address: u32 = 0;
unsafe fn alloc<T>(size: u32) -> *mut T {
if placement_address == 0 {
extern { static kernel_end: u32; }
placement_address = (&kernel_end as *u32) as u32;
}

if placement_address & !0xfff != 0 {
placement_address &= !0xfff;
placement_address += 0x1000;
}

let address = placement_address;
placement_address += size;
address as *mut T
}
1 change: 1 addition & 0 deletions rost/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@ pub extern fn kernel_main() {
arch::idt::init();
drivers::init();

memory::allocator::init();
memory::paging::init();

exec::syscalls::init();
Expand Down

0 comments on commit e053bf2

Please sign in to comment.