merge done, x86 is now a module

This commit is contained in:
Jack Halford 2018-03-19 12:23:42 +01:00
commit 0526b88859
14 changed files with 199 additions and 421 deletions

View file

@ -1,3 +1,6 @@
[submodule "multiboot2-elf64"] [submodule "multiboot2-elf64"]
path = multiboot2-elf64 path = multiboot2-elf64
url = git@github.com:jzck/multiboot2-elf64.git url = git@github.com:jzck/multiboot2-elf64.git
[submodule "x86"]
path = x86
url = https://github.com/jzck/x86.git

View file

@ -10,3 +10,4 @@ crate-type = ["staticlib"]
rlibc = "1.0" rlibc = "1.0"
bitflags = "1.0.1" bitflags = "1.0.1"
multiboot2 = { path = "multiboot2-elf64" } multiboot2 = { path = "multiboot2-elf64" }
x86 = { path = "x86" }

View file

@ -3,7 +3,6 @@ extern crate core;
use acpi; use acpi;
use cpuio; use cpuio;
use x86;
use core::char; use core::char;
use vga::*; use vga::*;
@ -178,9 +177,11 @@ pub fn acpi_info() -> Result <(), &'static str> {
} }
pub fn regs() -> Result <(), &'static str> { pub fn regs() -> Result <(), &'static str> {
println!("cr0={:#b}", x86::cr0()); use x86::registers::control::*;
println!("cr3={:#x}", x86::cr3()); println!("cr0={:#b}", Cr0::read());
println!("cr4={:#b}", x86::cr4()); println!("cr3={:?}", Cr3::read());
flush!();
// TODO implement cr4 flags in `x86` module
// println!("cr4={:#b}", Cr4::read());
Ok(()) Ok(())
} }

View file

@ -11,8 +11,9 @@
extern crate rlibc; extern crate rlibc;
extern crate multiboot2; extern crate multiboot2;
#[macro_use] extern crate bitflags; // #[macro_use] extern crate bitflags;
#[macro_use] extern crate alloc; #[macro_use] extern crate alloc;
extern crate x86;
/// 80x25 screen and simplistic terminal driver /// 80x25 screen and simplistic terminal driver
#[macro_use] pub mod vga; #[macro_use] pub mod vga;
@ -20,14 +21,14 @@ extern crate multiboot2;
pub mod keyboard; pub mod keyboard;
/// simplisitc kernel commands /// simplisitc kernel commands
pub mod console; pub mod console;
/// wrappers around the x86-family I/O instructions. /// rust wrappers around cpu I/O instructions.
pub mod cpuio; pub mod cpuio;
/// ACPI self-content module /// ACPI self-content module
pub mod acpi; pub mod acpi;
/// physical frame allocator + paging module /// physical frame allocator + paging module + heap allocator
pub mod memory; pub mod memory;
/// a few x86 register and instruction wrappers // x86 interruptions
pub mod x86; // pub mod interrupts;
fn init_kernel(multiboot_info_addr: usize) -> Result <(), &'static str> { fn init_kernel(multiboot_info_addr: usize) -> Result <(), &'static str> {
let boot_info = unsafe { multiboot2::load(multiboot_info_addr)}; let boot_info = unsafe { multiboot2::load(multiboot_info_addr)};
@ -40,6 +41,7 @@ fn init_kernel(multiboot_info_addr: usize) -> Result <(), &'static str> {
acpi::init()?; acpi::init()?;
} }
enable_paging(); enable_paging();
enable_write_protect_bit(); enable_write_protect_bit();
memory::init(&boot_info); memory::init(&boot_info);
vga::init(); vga::init();
@ -47,11 +49,13 @@ fn init_kernel(multiboot_info_addr: usize) -> Result <(), &'static str> {
} }
fn enable_paging() { fn enable_paging() {
unsafe { x86::cr0_write(x86::cr0() | (1 << 31)) }; use x86::registers::control::{Cr0, Cr0Flags};
unsafe { Cr0::write(Cr0::read() | Cr0Flags::PAGING) };
} }
fn enable_write_protect_bit() { fn enable_write_protect_bit() {
unsafe { x86::cr0_write(x86::cr0() | (1 << 16)) }; use x86::registers::control::{Cr0, Cr0Flags};
unsafe { Cr0::write(Cr0::read() | Cr0Flags::WRITE_PROTECT) };
} }
#[no_mangle] #[no_mangle]
@ -61,18 +65,6 @@ pub extern fn kmain(multiboot_info_addr: usize) -> ! {
cpuio::halt(); cpuio::halt();
} }
use alloc::boxed::Box;
let mut heap_test = Box::new(42);
*heap_test -= 15;
let heap_test2 = Box::new("Hello");
println!("{:?} {:?}", heap_test, heap_test2);
let mut vec_test = vec![1,2,3,4,5,6,7];
vec_test[3] = 42;
for i in &vec_test {
print!("{} ", i);
}
loop { keyboard::kbd_callback(); } loop { keyboard::kbd_callback(); }
} }
@ -89,7 +81,6 @@ pub extern fn panic_fmt(fmt: core::fmt::Arguments, file: &'static str, line: u32
println!("LINE: {}", line); println!("LINE: {}", line);
flush!(); flush!();
loop {} loop {}
} }
use memory::BumpAllocator; use memory::BumpAllocator;

View file

@ -1,14 +1,15 @@
use memory::*; use memory::*;
use multiboot2::{MemoryAreaIter, MemoryArea}; use multiboot2::{MemoryAreaIter, MemoryArea};
use x86::*;
pub struct AreaFrameAllocator { pub struct AreaFrameAllocator {
next_free_frame: Frame, next_free_frame: PhysFrame,
current_area: Option<&'static MemoryArea>, current_area: Option<&'static MemoryArea>,
areas: MemoryAreaIter, areas: MemoryAreaIter,
kernel_start: Frame, kernel_start: PhysFrame,
kernel_end: Frame, kernel_end: PhysFrame,
multiboot_start: Frame, multiboot_start: PhysFrame,
multiboot_end: Frame, multiboot_end: PhysFrame,
} }
impl AreaFrameAllocator { impl AreaFrameAllocator {
@ -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: Frame::containing_address(0), next_free_frame: PhysFrame { number: 0 },
current_area: None, current_area: None,
areas: memory_areas, areas: memory_areas,
kernel_start: Frame::containing_address(kernel_start), kernel_start: PhysFrame::containing_address(
kernel_end: Frame::containing_address(kernel_end), PhysAddr::new(kernel_start as u32)),
multiboot_start: Frame::containing_address(multiboot_start), kernel_end: PhysFrame::containing_address(
multiboot_end: Frame::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| {
Frame::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 = Frame::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;
} }
@ -44,21 +50,22 @@ impl AreaFrameAllocator {
} }
impl FrameAllocator for AreaFrameAllocator { impl FrameAllocator for AreaFrameAllocator {
fn allocate_frame(&mut self) -> Option<Frame> { fn allocate_frame(&mut self) -> Option<PhysFrame> {
if let Some(area) = self.current_area { if let Some(area) = self.current_area {
let frame = Frame { number: self.next_free_frame.number }; let frame = PhysFrame { number: self.next_free_frame.number };
let current_area_last_frame = Frame::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();
} else if frame >= self.kernel_start && frame <= self.kernel_end { } else if frame >= self.kernel_start && frame <= self.kernel_end {
// frame used by kernel // frame used by kernel
self.next_free_frame = Frame { self.next_free_frame = PhysFrame {
number: self.kernel_end.number + 1, number: self.kernel_end.number + 1,
} }
} else if frame >= self.multiboot_start && frame <= self.multiboot_end { } else if frame >= self.multiboot_start && frame <= self.multiboot_end {
// frame used by multiboot // frame used by multiboot
self.next_free_frame = Frame { self.next_free_frame = PhysFrame {
number: self.multiboot_end.number + 1, number: self.multiboot_end.number + 1,
} }
} else { } else {
@ -72,7 +79,7 @@ impl FrameAllocator for AreaFrameAllocator {
} }
} }
fn deallocate_frame(&mut self, frame: Frame) { fn deallocate_frame(&mut self, frame: PhysFrame) {
unimplemented!(); unimplemented!();
} }
} }

View file

@ -7,57 +7,13 @@ mod paging;
pub use self::area_allocator::*; 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 self::paging::PhysicalAddress;
use multiboot2; use multiboot2;
use x86::*;
#[derive(Debug, PartialEq, Eq, PartialOrd, Ord)] use x86::structures::paging::*;
pub struct Frame {
number: usize,
}
impl Frame {
fn containing_address(address: usize) -> Frame {
Frame{ number: address / PAGE_SIZE }
}
fn start_address(&self) -> PhysicalAddress {
self.number * PAGE_SIZE
}
fn clone(&self) ->Frame {
Frame { number: self.number }
}
fn range_inclusive(start: Frame, end: Frame) -> FrameIter {
FrameIter {
start,
end,
}
}
}
pub trait FrameAllocator { pub trait FrameAllocator {
fn allocate_frame(&mut self) -> Option<Frame>; fn allocate_frame(&mut self) -> Option<PhysFrame>;
fn deallocate_frame(&mut self, frame: Frame); fn deallocate_frame(&mut self, frame: PhysFrame);
}
struct FrameIter {
start: Frame,
end: Frame,
}
impl Iterator for FrameIter {
type Item = Frame;
fn next(&mut self) -> Option<Frame> {
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
@ -82,13 +38,14 @@ pub fn init(boot_info: &multiboot2::BootInformation) {
let mut active_table = paging::remap_the_kernel(&mut frame_allocator, let mut active_table = paging::remap_the_kernel(&mut frame_allocator,
boot_info); boot_info);
use self::paging::Page;
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, paging::EntryFlags::WRITABLE, &mut frame_allocator); active_table.map(page, PageTableFlags::WRITABLE, &mut frame_allocator);
} }
} }

View file

@ -1,66 +0,0 @@
use memory::Frame;
pub struct Entry(u32);
use multiboot2::ElfSection;
impl Entry {
pub fn is_unused(&self) -> bool {
self.0 == 0
}
pub fn set_unused(&mut self) {
self.0 = 0;
}
pub fn flags(&self) -> EntryFlags {
EntryFlags::from_bits_truncate(self.0)
}
pub fn pointed_frame(&self) -> Option<Frame> {
if self.flags().contains(EntryFlags::PRESENT) {
Some(Frame::containing_address(
self.0 as usize & 0xffff_f000))
} else {
None
}
}
pub fn set(&mut self, frame: Frame, flags: EntryFlags) {
assert!(frame.start_address() & !0xffff_f000 == 0);
self.0 = (frame.start_address() as u32) | flags.bits();
}
}
bitflags! {
pub struct EntryFlags: u32 {
const PRESENT = 1 << 0;
const WRITABLE = 1 << 1;
const USER_ACCESSIBLE = 1 << 2;
const WRITE_THROUGH = 1 << 3;
const NO_CACHE = 1 << 4;
const ACCESSED = 1 << 5;
const DIRTY = 1 << 6;
const HUGE_PAGE = 1 << 7;
const GLOBAL = 1 << 8;
// LONG MODE
// const NO_EXECUTE = 1 << 63;
}
}
impl EntryFlags {
pub fn from_elf_section_flags(section: &ElfSection) -> EntryFlags {
use multiboot2::ElfSectionFlags;
let mut flags = EntryFlags::empty();
if section.flags().contains(ElfSectionFlags::ALLOCATED) {
flags = flags | EntryFlags::PRESENT;
}
if section.flags().contains(ElfSectionFlags::WRITABLE) {
flags = flags | EntryFlags::WRITABLE;
}
// if !section.flags().contains(ElfSectionFlags::EXECUTABLE) {
// flags = flags | EntryFlags::NO_EXECUTE;
// }
flags
}
}

View file

@ -1,51 +1,56 @@
use super::{VirtualAddress, PhysicalAddress, Page, ENTRY_COUNT}; use memory::{PAGE_SIZE, FrameAllocator};
use super::entry::*;
use super::table::{self, Table, Level2};
use memory::{PAGE_SIZE, Frame, FrameAllocator};
use core::ptr::Unique; use core::ptr::Unique;
use x86; use x86::structures::paging::*;
use x86::instructions::tlb;
use x86::usize_conversions::usize_from;
use x86::*;
use super::paging::table::RecTable;
// virtual address of recursively mapped P2
// for protected mode non PAE
// https://wiki.osdev.org/Page_Tables
pub const P2: *mut PageTable = 0xffff_f000 as *mut _;
pub struct Mapper { pub struct Mapper {
p2: Unique<Table<Level2>>, p2: Unique<PageTable>,
} }
impl Mapper { impl Mapper {
pub unsafe fn new() -> Mapper { pub unsafe fn new() -> Mapper {
Mapper { Mapper {
p2: Unique::new_unchecked(table::P2), p2: Unique::new_unchecked(self::P2),
} }
} }
// the remaining mapping methods, all public // the remaining mapping methods, all public
pub fn p2(&self) -> &Table<Level2> { pub fn p2(&self) -> &PageTable {
unsafe { self.p2.as_ref() } unsafe { self.p2.as_ref() }
} }
pub fn p2_mut(&mut self) -> &mut Table<Level2> { pub fn p2_mut(&mut self) -> &mut PageTable {
unsafe { self.p2.as_mut() } unsafe { self.p2.as_mut() }
} }
pub fn translate(&self, virtual_address: VirtualAddress) -> Option<PhysicalAddress> /// virtual addr to physical addr translation
pub fn translate(&self, virtual_address: VirtAddr) -> Option<PhysAddr>
{ {
let offset = virtual_address % PAGE_SIZE; let offset = virtual_address.as_u32() % PAGE_SIZE as u32;
self.translate_page(Page::containing_address(virtual_address)) self.translate_page(Page::containing_address(virtual_address))
.map(|frame| frame.number * PAGE_SIZE + offset) .map(|frame| frame.start_address() + offset)
} }
pub fn translate_page(&self, page: Page) -> Option<Frame> { /// virtual page to physical frame translation
pub fn translate_page(&self, page: Page) -> Option<PhysFrame> {
let p1 = self.p2().next_table(page.p2_index()); let p1 = self.p2().next_table(usize_from(u32::from(page.p2_index())));
let huge_page = || { let huge_page = || {
let p2_entry = &self.p2()[page.p2_index()]; let p2_entry = &self.p2()[page.p2_index()];
if let Some(start_frame) = p2_entry.pointed_frame() { if let Some(start_frame) = p2_entry.pointed_frame() {
if p2_entry.flags().contains(EntryFlags::HUGE_PAGE) { if p2_entry.flags().contains(PageTableFlags::HUGE_PAGE) {
// 4KiB alignment check // TODO 4MiB alignment check
assert!(start_frame.number % ENTRY_COUNT == 0); return Some(start_frame + u32::from(page.p1_index()));
return Some(Frame { }
number: start_frame.number + page.p1_index()
});
}
} }
None None
}; };
@ -54,29 +59,29 @@ impl Mapper {
.or_else(huge_page) .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: Frame, flags: EntryFlags, 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
{ {
let p2 = self.p2_mut(); let p2 = self.p2_mut();
let p1 = p2.next_table_create(page.p2_index(), allocator); let p1 = p2.next_table_create(usize_from(u32::from(page.p2_index())), allocator);
assert!(p1[page.p1_index()].is_unused()); assert!(p1[page.p1_index()].is_unused());
p1[page.p1_index()].set(frame, flags | EntryFlags::PRESENT); p1[page.p1_index()].set(frame, flags | PageTableFlags::PRESENT);
} }
pub fn map<A>(&mut self, page: Page, flags: EntryFlags, allocator: &mut A) pub fn map<A>(&mut self, page: Page, flags: PageTableFlags, allocator: &mut A)
where A: FrameAllocator where A: FrameAllocator
{ {
let frame = allocator.allocate_frame().expect("out of memory"); let frame = allocator.allocate_frame().expect("out of memory");
self.map_to(page, frame, flags, allocator) self.map_to(page, frame, flags, allocator)
} }
pub fn identity_map<A>(&mut self, frame: Frame, flags: EntryFlags, allocator: &mut A) pub fn identity_map<A>(&mut self, frame: PhysFrame, flags: PageTableFlags, allocator: &mut A)
where A: FrameAllocator where A: FrameAllocator
{ {
let page = Page::containing_address(frame.start_address()); let virt_addr = VirtAddr::new(frame.start_address().as_u32());
let page = Page::containing_address(virt_addr);
self.map_to(page, frame, flags, allocator); self.map_to(page, frame, flags, allocator);
} }
@ -86,11 +91,11 @@ impl Mapper {
assert!(self.translate(page.start_address()).is_some()); assert!(self.translate(page.start_address()).is_some());
let p1 = self.p2_mut() let p1 = self.p2_mut()
.next_table_mut(page.p2_index()) .next_table_mut(usize_from(u32::from(page.p2_index())))
.expect("mapping code does not support huge pages"); .expect("mapping code does not support huge pages");
let frame = p1[page.p1_index()].pointed_frame().unwrap(); let frame = p1[page.p1_index()].pointed_frame().unwrap();
p1[page.p1_index()].set_unused(); p1[page.p1_index()].set_unused();
x86::tlb::flush(page.start_address()); tlb::flush(page.start_address());
// TODO // TODO
// allocator.deallocate_frame(frame); // allocator.deallocate_frame(frame);
} }

View file

@ -1,79 +1,17 @@
#![allow(dead_code)] #![allow(dead_code)]
mod entry;
mod table; mod table;
mod temporary_page; mod temporary_page;
mod mapper; mod mapper;
use memory::PAGE_SIZE;
use memory::*; use memory::*;
use self::mapper::Mapper; 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;
pub use self::entry::*; use x86::instructions::tlb;
pub use self::table::*;
// x86 non PAE has 1024 entries per table
const ENTRY_COUNT: usize = 1024;
pub type PhysicalAddress = usize;
pub type VirtualAddress = usize;
#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord)]
pub struct Page {
number: usize,
}
impl Page {
pub fn containing_address(address: VirtualAddress) -> Page {
// assert!(address < 0x0000_8000_0000_0000 ||
// address >= 0xffff_8000_0000_0000,
// "invalid addres: 0x{:x}", address);
Page { number: address / PAGE_SIZE }
}
fn start_address(&self) -> usize {
self.number * PAGE_SIZE
}
fn p2_index(&self) -> usize {
(self.number >> 10) & 0x3ff
}
fn p1_index(&self) -> usize {
(self.number >> 0) & 0x3ff
}
pub fn range_inclusive(start: Page, end: Page) -> PageIter {
PageIter {
start,
end,
}
}
}
#[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,
@ -106,109 +44,129 @@ impl ActivePageTable {
f: F) f: F)
where F: FnOnce(&mut Mapper) where F: FnOnce(&mut Mapper)
{ {
let backup = Frame::containing_address(x86::cr3()); 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(backup.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(), EntryFlags::PRESENT | EntryFlags::WRITABLE); self.p2_mut()[1023].set(table.p2_frame.clone(), PageTableFlags::PRESENT | PageTableFlags::WRITABLE);
x86::tlb::flush_all(); tlb::flush_all();
// execute f in the new context // execute f in the new context
f(self); f(self);
// restore recursive mapping to original p2 table // restore recursive mapping to original p2 table
p2_table[1023].set(backup, EntryFlags::PRESENT | EntryFlags::WRITABLE); p2_table[1023].set(cr3_back, PageTableFlags::PRESENT | PageTableFlags::WRITABLE);
} }
pub fn switch(&mut self, new_table: InactivePageTable) -> InactivePageTable { pub fn switch(&mut self, new_table: InactivePageTable) -> InactivePageTable {
let p2_frame = Frame::containing_address(x86::cr3() as usize); let (p2_frame, cr3_flags) = Cr3::read();
let old_table = InactivePageTable { p2_frame };
let old_table = InactivePageTable { unsafe { Cr3::write(new_table.p2_frame, cr3_flags); }
p2_frame,
};
unsafe {
let frame = Frame::containing_address(new_table.p2_frame.start_address());
x86::cr3_write(frame.start_address());
}
old_table old_table
} }
} }
pub struct InactivePageTable { pub struct InactivePageTable {
p2_frame: Frame, p2_frame: PhysFrame,
} }
impl InactivePageTable { impl InactivePageTable {
pub fn new(frame: Frame, 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();
// set up recursive mapping for the table table.zero();
table[1023].set(frame.clone(), EntryFlags::PRESENT | EntryFlags:: WRITABLE) // set up recursive mapping for the table
table[1023].set(frame.clone(), PageTableFlags::PRESENT | PageTableFlags::WRITABLE)
}
temporary_page.unmap(active_table);
InactivePageTable { p2_frame: frame }
} }
temporary_page.unmap(active_table);
InactivePageTable { p2_frame: frame }
}
} }
pub fn remap_the_kernel<A>(allocator: &mut A, boot_info: &BootInformation) pub fn remap_the_kernel<A>(allocator: &mut A, boot_info: &BootInformation)
-> ActivePageTable -> ActivePageTable
where A: FrameAllocator where A: FrameAllocator
{ {
let mut temporary_page = TemporaryPage::new(Page { number: 0xcafe }, let mut temporary_page = TemporaryPage::new(Page{number: 0xcafe}, allocator);
allocator);
let mut active_table = unsafe { ActivePageTable::new() }; let mut active_table = unsafe { ActivePageTable::new() };
let mut new_table = { let mut new_table = {
let frame = allocator.allocate_frame().expect("no more frames"); let frame = allocator.allocate_frame().expect("no more frames");
InactivePageTable::new(frame, &mut active_table, &mut temporary_page) InactivePageTable::new(frame, &mut active_table, &mut temporary_page)
}; };
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 = Frame::containing_address(0xb8000); let vga_buffer_frame = PhysFrame::containing_address(PhysAddr::new(0xb8000));
mapper.identity_map(vga_buffer_frame, EntryFlags::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()
.expect("Memory map tag required"); .expect("Memory map tag required");
for section in elf_sections_tag.sections() { for section in elf_sections_tag.sections() {
use self::entry::EntryFlags;
if !section.is_allocated() { if !section.is_allocated() {
continue; continue;
} }
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 = EntryFlags::from_elf_section_flags(&section); let flags = elf_to_pagetable_flags(&section.flags());
let start_frame = Frame::containing_address(section.start_address() as usize); let start_frame = PhysFrame::containing_address(
let end_frame = Frame::containing_address(section.end_address() as usize - 1); PhysAddr::new(section.start_address() as u32));
for frame in Frame::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 + 1 {
mapper.identity_map(frame, flags, allocator); mapper.identity_map(frame, flags, allocator);
} }
} }
let multiboot_start = Frame::containing_address(boot_info.start_address()); let multiboot_start = PhysFrame::containing_address(
let multiboot_end = Frame::containing_address(boot_info.end_address() - 1); PhysAddr::new(boot_info.start_address() as u32));
for frame in Frame::range_inclusive(multiboot_start, multiboot_end) { let multiboot_end = PhysFrame::containing_address(
mapper.identity_map(frame, EntryFlags::PRESENT, allocator); PhysAddr::new(boot_info.end_address() as u32 - 1));
for frame in multiboot_start..multiboot_end + 1 {
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,95 +1,52 @@
use memory::*; use memory::*;
use memory::paging::*; use x86::structures::paging::*;
use x86::ux::*;
use core::ops::{Index, IndexMut}; pub trait RecTable
use core::marker::PhantomData; {
fn next_table_address(&self, index: usize) -> Option<u32>;
// virtual address of P2 because its recursively mapped fn next_table(&self, index: usize) -> Option<&PageTable>;
// see protected mode Non-PAE fn next_table_mut(&mut self, index: usize) -> Option<&mut PageTable>;
// https://wiki.osdev.org/Page_Tables fn next_table_create<A: FrameAllocator>(&mut self,
pub const P2: *mut Table<Level2> = 0xffff_f000 as *mut _; index: usize,
allocator: &mut A)
pub struct Table<L: TableLevel> { -> &mut PageTable;
entries: [Entry; ENTRY_COUNT],
level: PhantomData<L>,
} }
impl<L> Table<L> where L: TableLevel impl RecTable for PageTable
{ {
pub fn zero(&mut self) { fn next_table_address(&self, index: usize) -> Option<u32> {
for entry in self.entries.iter_mut() {
entry.set_unused();
}
}
}
impl<L> Table<L> where L: HierarchicalLevel
{
fn next_table_address(&self, index: usize) -> Option<usize> {
let entry_flags = self[index].flags(); let entry_flags = self[index].flags();
if entry_flags.contains(EntryFlags::PRESENT) && !entry_flags.contains(EntryFlags::HUGE_PAGE) { if entry_flags.contains(PageTableFlags::PRESENT) && !entry_flags.contains(PageTableFlags::HUGE_PAGE) {
let table_address = self as *const _ as usize; let table_address = self as *const _ as usize;
Some((table_address << 10) | (index << 12)) Some((table_address << 10 | index << 12) as u32)
} else { } else {
None None
} }
} }
pub fn next_table(&self, index: usize) -> Option<&Table<L::NextLevel>> { fn next_table(&self, index: usize) -> Option<&PageTable> {
self.next_table_address(index) self.next_table_address(index)
.map(|address| unsafe { &*(address as *const _) }) .map(|address| unsafe { &*(address as *const _) })
} }
pub fn next_table_mut(&mut self, index: usize) -> Option<&mut Table<L::NextLevel>> { fn next_table_mut(&mut self, index: usize) -> Option<&mut PageTable> {
self.next_table_address(index) self.next_table_address(index)
.map(|address| unsafe { &mut *(address as *mut _) }) .map(|address| unsafe { &mut *(address as *mut _) })
} }
pub fn next_table_create<A>(&mut self, fn next_table_create<A>(&mut self,
index: usize, index: usize,
allocator: &mut A) -> &mut Table<L::NextLevel> allocator: &mut A) -> &mut PageTable
where A: FrameAllocator where A: FrameAllocator
{ {
if self.next_table(index).is_none() { if self.next_table(index).is_none() {
assert!(!self[index].flags().contains(EntryFlags::HUGE_PAGE), assert!(!self[index].flags().contains(PageTableFlags::HUGE_PAGE),
"mapping code does not support huge pages"); "mapping code does not support huge pages");
let frame = allocator.allocate_frame().expect("no frames available"); let frame = allocator.allocate_frame().expect("no frames available");
self[index].set(frame, EntryFlags::PRESENT | EntryFlags::WRITABLE); self[index].set(frame, PageTableFlags::PRESENT | PageTableFlags::WRITABLE);
self.next_table_mut(index).expect("next_table_mut gave None").zero() self.next_table_mut(index).expect("next_table_mut gave None").zero()
} }
self.next_table_mut(index).expect("no next table 2") self.next_table_mut(index).expect("no next table 2")
} }
} }
impl<L> Index<usize> for Table<L> where L: TableLevel
{
type Output = Entry;
fn index(&self, index: usize) -> &Entry {
&self.entries[index]
}
}
impl<L> IndexMut<usize> for Table<L> where L: TableLevel
{
fn index_mut(&mut self, index: usize) -> &mut Entry {
&mut self.entries[index]
}
}
pub trait TableLevel {}
pub enum Level4 {}
pub enum Level3 {}
pub enum Level2 {}
pub enum Level1 {}
impl TableLevel for Level4 {}
impl TableLevel for Level3 {}
impl TableLevel for Level2 {}
impl TableLevel for Level1 {}
pub trait HierarchicalLevel: TableLevel { type NextLevel: TableLevel; }
impl HierarchicalLevel for Level4 { type NextLevel = Level3; }
impl HierarchicalLevel for Level3 { type NextLevel = Level2; }
impl HierarchicalLevel for Level2 { type NextLevel = Level1; }

View file

@ -1,9 +1,10 @@
use super::{Page, ActivePageTable, VirtualAddress}; use super::ActivePageTable;
use super::table::{Table, Level1}; use memory::{FrameAllocator};
use memory::{Frame, FrameAllocator}; use x86::*;
use x86::structures::paging::*;
pub struct TemporaryPage { pub struct TemporaryPage {
page: Page, pub page: Page,
allocator: TinyAllocator, allocator: TinyAllocator,
} }
@ -19,14 +20,15 @@ impl TemporaryPage {
/// Maps the temporary page to the given frame in the active table. /// Maps the temporary page to the given frame in the active table.
/// Returns the start address of the temporary page. /// Returns the start address of the temporary page.
pub fn map(&mut self, frame: Frame, active_table: &mut ActivePageTable) pub fn map(&mut self, frame: PhysFrame, active_table: &mut ActivePageTable)
-> VirtualAddress -> VirtAddr
{ {
use super::entry::EntryFlags;
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, EntryFlags::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");
self.page.start_address() self.page.start_address()
} }
@ -38,14 +40,14 @@ impl TemporaryPage {
/// Maps the temporary page to the given page table frame in the active /// Maps the temporary page to the given page table frame in the active
/// table. Returns a reference to the now mapped table. /// table. Returns a reference to the now mapped table.
pub fn map_table_frame(&mut self, pub fn map_table_frame(&mut self,
frame: Frame, frame: PhysFrame,
active_table: &mut ActivePageTable) active_table: &mut ActivePageTable)
-> &mut Table<Level1> { -> &mut PageTable {
unsafe { &mut *(self.map(frame, active_table) as *mut Table<Level1>) } unsafe { &mut *(self.map(frame, active_table).as_u32() as *mut PageTable) }
} }
} }
struct TinyAllocator([Option<Frame>; 1]); struct TinyAllocator([Option<PhysFrame>; 1]);
impl TinyAllocator { impl TinyAllocator {
fn new<A>(allocator: &mut A) -> TinyAllocator fn new<A>(allocator: &mut A) -> TinyAllocator
@ -58,7 +60,7 @@ impl TinyAllocator {
} }
impl FrameAllocator for TinyAllocator { impl FrameAllocator for TinyAllocator {
fn allocate_frame(&mut self) -> Option<Frame> { fn allocate_frame(&mut self) -> Option<PhysFrame> {
for frame_option in &mut self.0 { for frame_option in &mut self.0 {
if frame_option.is_some() { if frame_option.is_some() {
return frame_option.take(); return frame_option.take();
@ -67,7 +69,7 @@ impl FrameAllocator for TinyAllocator {
None None
} }
fn deallocate_frame(&mut self, frame: Frame) { fn deallocate_frame(&mut self, frame: PhysFrame) {
for frame_option in &mut self.0 { for frame_option in &mut self.0 {
if frame_option.is_none() { if frame_option.is_none() {
*frame_option = Some(frame); *frame_option = Some(frame);

View file

@ -1,29 +0,0 @@
//! x86 (32 bit) only
pub mod tlb;
pub unsafe fn cr0_write(val: usize) {
asm!("mov $0, %cr0" :: "r"(val) : "memory");
}
pub fn cr0() -> usize {
let ret: usize;
unsafe { asm!("mov %cr0, $0" : "=r" (ret)) };
ret
}
pub fn cr3() -> usize {
let ret: usize;
unsafe { asm!("mov %cr3, $0" : "=r" (ret)) };
ret
}
pub fn cr4() -> usize {
let ret: usize;
unsafe { asm!("mov %cr4, $0" : "=r" (ret)) };
ret
}
pub unsafe fn cr3_write(val: usize) {
asm!("mov $0, %cr3" :: "r" (val) : "memory");
}

View file

@ -1,10 +0,0 @@
use super::*;
pub fn flush(addr: usize) {
unsafe { asm!("invlpg ($0)" :: "r"(addr) : "memory")}
}
pub fn flush_all() {
let cr3 = cr3();
unsafe { cr3_write(cr3); }
}

1
kernel-rs/x86 Submodule

@ -0,0 +1 @@
Subproject commit eae470839b1ff232dbc4af5389e9a0b4fffe4b30