it compiles now with the new x86 lib, triple faults when setting temp page to zero though

This commit is contained in:
Jack Halford 2018-03-14 18:59:17 +01:00
parent 0b38f701ed
commit 8cf793260c
8 changed files with 141 additions and 103 deletions

View file

@ -178,7 +178,7 @@ pub fn acpi_info() -> Result <(), &'static str> {
pub fn regs() -> Result <(), &'static str> { pub fn regs() -> Result <(), &'static str> {
use x86::registers::control::*; use x86::registers::control::*;
println!("cr0={:#b}", Cr0::read()); println!("cr0={:#b}", Cr0::read());
println!("cr3={:#x}", Cr3::read()); println!("cr3={:?}", Cr3::read());
// TODO implement cr4 flags in `x86` module // TODO implement cr4 flags in `x86` module
// println!("cr4={:#b}", Cr4::read()); // println!("cr4={:#b}", Cr4::read());
Ok(()) Ok(())

View file

@ -1,5 +1,6 @@
use memory::*; use memory::*;
use multiboot2::{MemoryAreaIter, MemoryArea}; use multiboot2::{MemoryAreaIter, MemoryArea};
use x86::*;
pub struct AreaFrameAllocator { pub struct AreaFrameAllocator {
next_free_frame: PhysFrame, next_free_frame: PhysFrame,
@ -16,13 +17,17 @@ impl AreaFrameAllocator {
multiboot_start: usize, multiboot_end: usize, multiboot_start: usize, multiboot_end: usize,
memory_areas: MemoryAreaIter) -> AreaFrameAllocator { memory_areas: MemoryAreaIter) -> AreaFrameAllocator {
let mut allocator = AreaFrameAllocator { let mut allocator = AreaFrameAllocator {
next_free_frame: PhysFrame::containing_address(0), next_free_frame: PhysFrame { number: 0 },
current_area: None, current_area: None,
areas: memory_areas, areas: memory_areas,
kernel_start: PhysFrame::containing_address(kernel_start), kernel_start: PhysFrame::containing_address(
kernel_end: PhysFrame::containing_address(kernel_end), PhysAddr::new(kernel_start as u32)),
multiboot_start: PhysFrame::containing_address(multiboot_start), kernel_end: PhysFrame::containing_address(
multiboot_end: PhysFrame::containing_address(multiboot_end), PhysAddr::new(kernel_end as u32)),
multiboot_start: PhysFrame::containing_address(
PhysAddr::new(multiboot_start as u32)),
multiboot_end: PhysFrame::containing_address(
PhysAddr::new(multiboot_end as u32)),
}; };
allocator.choose_next_area(); allocator.choose_next_area();
allocator allocator
@ -31,11 +36,12 @@ impl AreaFrameAllocator {
fn choose_next_area(&mut self) { fn choose_next_area(&mut self) {
// get next area with free frames // get next area with free frames
self.current_area = self.areas.clone().filter(|area| { self.current_area = self.areas.clone().filter(|area| {
PhysFrame::containing_address(area.end_address()) >= self.next_free_frame area.end_address() >= self.next_free_frame.start_address().as_u32() as usize
}).min_by_key(|area| area.start_address()); }).min_by_key(|area| area.start_address());
if let Some(area) = self.current_area { if let Some(area) = self.current_area {
let start_frame = PhysFrame::containing_address(area.start_address()); let start_frame = PhysFrame::containing_address(
PhysAddr::new(area.start_address() as u32));
if self.next_free_frame < start_frame { if self.next_free_frame < start_frame {
self.next_free_frame = start_frame; self.next_free_frame = start_frame;
} }
@ -45,9 +51,10 @@ impl AreaFrameAllocator {
impl FrameAllocator for AreaFrameAllocator { impl FrameAllocator for AreaFrameAllocator {
fn allocate_frame(&mut self) -> Option<PhysFrame> { fn allocate_frame(&mut self) -> Option<PhysFrame> {
if let Some(area) = self.current_arPhysea { if let Some(area) = self.current_area {
let frame = PhysFrame { number: self.next_free_frame.number }; let frame = PhysFrame { number: self.next_free_frame.number };
let current_area_last_frame = PhysFrame::containing_address(area.end_address()); let current_area_last_frame = PhysFrame::containing_address(
PhysAddr::new(area.end_address() as u32));
if frame > current_area_last_frame { if frame > current_area_last_frame {
// all frames are taken in this area // all frames are taken in this area
self.choose_next_area(); self.choose_next_area();

View file

@ -8,7 +8,7 @@ pub use self::area_allocator::*;
pub use self::heap_allocator::*; pub use self::heap_allocator::*;
pub use self::paging::remap_the_kernel; pub use self::paging::remap_the_kernel;
use multiboot2; use multiboot2;
use x86::*;
use x86::structures::paging::*; use x86::structures::paging::*;
pub trait FrameAllocator { pub trait FrameAllocator {
@ -16,25 +16,6 @@ pub trait FrameAllocator {
fn deallocate_frame(&mut self, frame: PhysFrame); fn deallocate_frame(&mut self, frame: PhysFrame);
} }
struct FrameIter {
start: PhysFrame,
end: PhysFrame,
}
impl Iterator for FrameIter {
type Item = PhysFrame;
fn next(&mut self) -> Option<PhysFrame> {
if self.start <= self.end {
let frame = self.start.clone();
self.start.number += 1;
Some(frame)
} else {
None
}
}
}
/// memory initialisation should only be called once /// memory initialisation should only be called once
pub fn init(boot_info: &multiboot2::BootInformation) { pub fn init(boot_info: &multiboot2::BootInformation) {
let elf_sections_tag = boot_info.elf_sections_tag().unwrap(); let elf_sections_tag = boot_info.elf_sections_tag().unwrap();
@ -59,10 +40,12 @@ pub fn init(boot_info: &multiboot2::BootInformation) {
boot_info); boot_info);
use {HEAP_START, HEAP_SIZE}; use {HEAP_START, HEAP_SIZE};
let heap_start_page = Page::containing_address(HEAP_START); let heap_start_page = Page::containing_address(
let heap_end_page = Page::containing_address(HEAP_START + HEAP_SIZE - 1); VirtAddr::new(HEAP_START as u32));
let heap_end_page = Page::containing_address(
VirtAddr::new(HEAP_START as u32 + HEAP_SIZE as u32 - 1));
for page in Page::range_inclusive(heap_start_page, heap_end_page) { for page in heap_start_page..heap_end_page {
active_table.map(page, PageTableFlags::WRITABLE, &mut frame_allocator); active_table.map(page, PageTableFlags::WRITABLE, &mut frame_allocator);
} }
} }

View file

@ -3,7 +3,8 @@ use core::ptr::Unique;
use x86::structures::paging::*; use x86::structures::paging::*;
use x86::instructions::tlb; use x86::instructions::tlb;
use x86::*; use x86::*;
// use super::paging::table::RecTable;
// virtual address of recursively mapped P2 // virtual address of recursively mapped P2
// for protected mode non PAE // for protected mode non PAE
// https://wiki.osdev.org/Page_Tables // https://wiki.osdev.org/Page_Tables
@ -29,6 +30,7 @@ impl Mapper {
unsafe { self.p2.as_mut() } unsafe { self.p2.as_mut() }
} }
/// virtual addr to physical addr translation
pub fn translate(&self, virtual_address: VirtAddr) -> Option<PhysAddr> pub fn translate(&self, virtual_address: VirtAddr) -> Option<PhysAddr>
{ {
let offset = virtual_address.as_u32() % PAGE_SIZE as u32; let offset = virtual_address.as_u32() % PAGE_SIZE as u32;
@ -37,15 +39,26 @@ impl Mapper {
} }
/// virtual page to physical frame translation
pub fn translate_page(&self, page: Page) -> Option<PhysFrame> { pub fn translate_page(&self, page: Page) -> Option<PhysFrame> {
let p1 = self.p2().next_table(page.p2_index());
let p1 = self.p2()[page.p2_index()].points_to() let huge_page = || {
.and_then(|paddr| PageTable::from(paddr)); let p2_entry = &self.p2()[page.p2_index()];
if let Some(start_frame) = p2_entry.pointed_frame() {
if p2_entry.flags().contains(PageTableFlags::HUGE_PAGE) {
// TODO 4MiB alignment check
return Some(start_frame + u32::from(page.p1_index()));
}
}
None
};
p1.and_then() p1.and_then(|p1| p1[page.p1_index()].pointed_frame())
.or_else(huge_page)
} }
/// map a virtual page to a physical frame in the page tables
pub fn map_to<A>(&mut self, page: Page, frame: PhysFrame, flags: PageTableFlags, pub fn map_to<A>(&mut self, page: Page, frame: PhysFrame, flags: PageTableFlags,
allocator: &mut A) allocator: &mut A)
where A: FrameAllocator where A: FrameAllocator

View file

@ -1,6 +1,6 @@
#![allow(dead_code)] #![allow(dead_code)]
// mod table; mod table;
mod temporary_page; mod temporary_page;
mod mapper; mod mapper;
@ -9,28 +9,9 @@ use self::mapper::Mapper;
use self::temporary_page::TemporaryPage; use self::temporary_page::TemporaryPage;
use core::ops::{Deref, DerefMut}; use core::ops::{Deref, DerefMut};
use multiboot2::BootInformation; use multiboot2::BootInformation;
use x86; use x86::*;
use x86::registers::control::Cr3; use x86::registers::control::Cr3;
use x86::instructions::tlb;
#[derive(Clone)]
pub struct PageIter {
start: Page,
end: Page,
}
impl Iterator for PageIter {
type Item = Page;
fn next(&mut self) -> Option<Page> {
if self.start <= self.end {
let page = self.start;
self.start.number += 1;
Some(page)
} else {
None
}
}
}
pub struct ActivePageTable { pub struct ActivePageTable {
mapper: Mapper, mapper: Mapper,
@ -63,14 +44,14 @@ impl ActivePageTable {
f: F) f: F)
where F: FnOnce(&mut Mapper) where F: FnOnce(&mut Mapper)
{ {
let (cr3_back, cr3flags_back) = Cr3::read(); let (cr3_back, _cr3flags_back) = Cr3::read();
// map temp page to current p2 // map temp page to current p2
let p2_table = temporary_page.map_table_frame(cr3_back.clone(), self); let p2_table = temporary_page.map_table_frame(cr3_back.clone(), self);
// overwrite recursive map // overwrite recursive map
self.p2_mut()[1023].set(table.p2_frame.clone(), PageTableFlags::PRESENT | PageTableFlags::WRITABLE); self.p2_mut()[1023].set(table.p2_frame.clone(), PageTableFlags::PRESENT | PageTableFlags::WRITABLE);
x86::instructions::tlb::flush_all(); tlb::flush_all();
// execute f in the new context // execute f in the new context
f(self); f(self);
@ -80,17 +61,9 @@ impl ActivePageTable {
} }
pub fn switch(&mut self, new_table: InactivePageTable) -> InactivePageTable { pub fn switch(&mut self, new_table: InactivePageTable) -> InactivePageTable {
let (p2_frame, cr3_flags) = Cr3::read();
let p2_frame = PhysFrame::containing_address(Cr3::read() as usize); let old_table = InactivePageTable { p2_frame };
unsafe { Cr3::write(new_table.p2_frame, cr3_flags); }
let old_table = InactivePageTable {
p2_frame,
};
unsafe {
let frame = PhysFrame::containing_address(new_table.p2_frame.start_address());
Cr3::write(frame.start_address());
}
old_table old_table
} }
@ -103,13 +76,21 @@ pub struct InactivePageTable {
impl InactivePageTable { impl InactivePageTable {
pub fn new(frame: PhysFrame, pub fn new(frame: PhysFrame,
active_table: &mut ActivePageTable, active_table: &mut ActivePageTable,
temporary_page: &mut TemporaryPage, temporary_page: &mut TemporaryPage)
) -> InactivePageTable { -> InactivePageTable {
{ {
let table = temporary_page.map_table_frame(frame.clone(), let table = temporary_page.map_table_frame(frame.clone(), active_table);
active_table);
table.zero();
// table.zero();
let iter = table.entries.iter_mut();
for entry in iter {
println!("entry = {:?}", entry as *const _);
// println!("entry = {:?}", entry.flags());
}
println!("frame = {:?}", frame);
flush!();
loop {}
// set up recursive mapping for the table // set up recursive mapping for the table
table[1023].set(frame.clone(), PageTableFlags::PRESENT | PageTableFlags::WRITABLE) table[1023].set(frame.clone(), PageTableFlags::PRESENT | PageTableFlags::WRITABLE)
} }
@ -133,7 +114,7 @@ pub fn remap_the_kernel<A>(allocator: &mut A, boot_info: &BootInformation)
active_table.with(&mut new_table, &mut temporary_page, |mapper| { active_table.with(&mut new_table, &mut temporary_page, |mapper| {
// identity map the VGA text buffer // identity map the VGA text buffer
let vga_buffer_frame = PhysFrame::containing_address(0xb8000); let vga_buffer_frame = PhysFrame::containing_address(PhysAddr::new(0xb8000));
mapper.identity_map(vga_buffer_frame, PageTableFlags::WRITABLE, allocator); mapper.identity_map(vga_buffer_frame, PageTableFlags::WRITABLE, allocator);
let elf_sections_tag = boot_info.elf_sections_tag() let elf_sections_tag = boot_info.elf_sections_tag()
@ -146,24 +127,53 @@ pub fn remap_the_kernel<A>(allocator: &mut A, boot_info: &BootInformation)
assert!(section.start_address() % PAGE_SIZE as u64 == 0, assert!(section.start_address() % PAGE_SIZE as u64 == 0,
"sections need to be page aligned"); "sections need to be page aligned");
let flags = PageTableFlags::from_elf_section_flags(&section); let flags = elf_to_pagetable_flags(&section.flags());
let start_frame = PhysFrame::containing_address(section.start_address() as usize); let start_frame = PhysFrame::containing_address(
let end_frame = PhysFrame::containing_address(section.end_address() as usize - 1); PhysAddr::new(section.start_address() as u32));
for frame in PhysFrame::range_inclusive(start_frame, end_frame) { let end_frame = PhysFrame::containing_address(
PhysAddr::new(section.end_address() as u32 - 1));
for frame in start_frame..end_frame {
mapper.identity_map(frame, flags, allocator); mapper.identity_map(frame, flags, allocator);
} }
} }
let multiboot_start = PhysFrame::containing_address(boot_info.start_address()); let multiboot_start = PhysFrame::containing_address(
let multiboot_end = PhysFrame::containing_address(boot_info.end_address() - 1); PhysAddr::new(boot_info.start_address() as u32));
for frame in PhysFrame::range_inclusive(multiboot_start, multiboot_end) { let multiboot_end = PhysFrame::containing_address(
PhysAddr::new(boot_info.end_address() as u32 - 1));
for frame in multiboot_start..multiboot_end {
mapper.identity_map(frame, PageTableFlags::PRESENT, allocator); mapper.identity_map(frame, PageTableFlags::PRESENT, allocator);
} }
}); });
let old_table = active_table.switch(new_table); let old_table = active_table.switch(new_table);
let old_p2_page = Page::containing_address(old_table.p2_frame.start_address()); let old_p2_page = Page::containing_address(
VirtAddr::new(old_table.p2_frame.start_address().as_u32()));
active_table.unmap(old_p2_page, allocator); active_table.unmap(old_p2_page, allocator);
active_table active_table
} }
fn elf_to_pagetable_flags(elf_flags: &multiboot2::ElfSectionFlags)
-> PageTableFlags
{
use multiboot2::ElfSectionFlags;
let mut flags = PageTableFlags::empty();
if elf_flags.contains(ElfSectionFlags::ALLOCATED) {
// section is loaded to memory
flags = flags | PageTableFlags::PRESENT;
}
if elf_flags.contains(ElfSectionFlags::WRITABLE) {
flags = flags | PageTableFlags::WRITABLE;
}
// LONG MODE STUFF
// if !elf_flags.contains(ELF_SECTION_EXECUTABLE) {
// flags = flags | PageTableFlags::NO_EXECUTE;
// }
flags
}

View file

@ -1,22 +1,42 @@
use memory::*; use memory::*;
use x86::structures::paging::*; use x86::structures::paging::*;
use x86::ux::*;
pub trait RecTable
pub trait TableNext<A>
where A: FrameAllocator
{ {
fn next_table_address(&self, index: usize) -> Option<usize>; fn next_table_address(&self, index: u10) -> Option<u32>;
fn next_table(&self, index: usize) -> Option<&PageTable>; fn next_table(&self, index: u10) -> Option<&PageTable>;
fn next_table_mut(&mut self, index: usize) -> Option<&mut PageTable>; fn next_table_mut(&mut self, index: u10) -> Option<&mut PageTable>;
fn next_table_create<A>(&mut self, fn next_table_create<A: FrameAllocator>(&mut self,
index: usize, index: u10,
allocator: &mut A) -> &mut PageTable; allocator: &mut A)
-> &mut PageTable;
} }
impl TableNext<> for PageTable impl RecTable for PageTable
{ {
fn next_table_address(&self, index: u10) -> Option<u32> {
let entry_flags = self[index].flags();
if entry_flags.contains(PageTableFlags::PRESENT) && !entry_flags.contains(PageTableFlags::HUGE_PAGE) {
let table_address = self as *const _ as u32;
Some(table_address << 10 | u32::from(index << 12))
} else {
None
}
}
fn next_table(&self, index: u10) -> Option<&PageTable> {
self.next_table_address(index)
.map(|address| unsafe { &*(address as *const _) })
}
fn next_table_mut(&mut self, index: u10) -> Option<&mut PageTable> {
self.next_table_address(index)
.map(|address| unsafe { &mut *(address as *mut _) })
}
fn next_table_create<A>(&mut self, fn next_table_create<A>(&mut self,
index: usize, index: u10,
allocator: &mut A) -> &mut PageTable allocator: &mut A) -> &mut PageTable
where A: FrameAllocator where A: FrameAllocator
{ {

View file

@ -4,7 +4,7 @@ use x86::*;
use x86::structures::paging::*; use x86::structures::paging::*;
pub struct TemporaryPage { pub struct TemporaryPage {
page: Page, pub page: Page,
allocator: TinyAllocator, allocator: TinyAllocator,
} }
@ -26,6 +26,11 @@ impl TemporaryPage {
assert!(active_table.translate_page(self.page).is_none(), assert!(active_table.translate_page(self.page).is_none(),
"temporary page is already mapped"); "temporary page is already mapped");
active_table.map_to(self.page, frame, PageTableFlags::WRITABLE, &mut self.allocator); active_table.map_to(self.page, frame, PageTableFlags::WRITABLE, &mut self.allocator);
// this kind of check should be done in a test routine
assert!(active_table.translate_page(self.page).is_some(),
"temporary page was not mapped");
println!("trans = {:?}", active_table.translate_page(self.page));
println!("page = {:?}", self.page.start_address());
self.page.start_address() self.page.start_address()
} }
@ -40,7 +45,7 @@ impl TemporaryPage {
frame: PhysFrame, frame: PhysFrame,
active_table: &mut ActivePageTable) active_table: &mut ActivePageTable)
-> &mut PageTable { -> &mut PageTable {
unsafe { &mut *(self.map(frame, active_table) as *mut PageTable) } unsafe { &mut *(self.map(frame, active_table).as_u32() as *mut PageTable) }
} }
} }

@ -1 +1 @@
Subproject commit dc9eb5ceb8981848d95e0ddd7040fb86ec9999e3 Subproject commit eae470839b1ff232dbc4af5389e9a0b4fffe4b30