WIP
This commit is contained in:
parent
e73d3e175a
commit
0b38f701ed
16 changed files with 133 additions and 366 deletions
3
kernel-rs/.gitmodules
vendored
3
kernel-rs/.gitmodules
vendored
|
|
@ -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
|
||||||
|
|
|
||||||
|
|
@ -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" }
|
||||||
|
|
|
||||||
|
|
@ -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::*;
|
||||||
|
|
||||||
|
|
@ -177,9 +176,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={:#x}", Cr3::read());
|
||||||
|
// TODO implement cr4 flags in `x86` module
|
||||||
|
// println!("cr4={:#b}", Cr4::read());
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -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;
|
||||||
|
|
||||||
#[no_mangle]
|
#[no_mangle]
|
||||||
pub extern fn kmain(multiboot_info_addr: usize) -> ! {
|
pub extern fn kmain(multiboot_info_addr: usize) -> ! {
|
||||||
|
|
@ -54,7 +55,8 @@ pub extern fn kmain(multiboot_info_addr: usize) -> ! {
|
||||||
}
|
}
|
||||||
|
|
||||||
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) };
|
||||||
}
|
}
|
||||||
|
|
||||||
#[lang = "eh_personality"] #[no_mangle]
|
#[lang = "eh_personality"] #[no_mangle]
|
||||||
|
|
|
||||||
|
|
@ -2,13 +2,13 @@ use memory::*;
|
||||||
use multiboot2::{MemoryAreaIter, MemoryArea};
|
use multiboot2::{MemoryAreaIter, MemoryArea};
|
||||||
|
|
||||||
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 +16,13 @@ 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::containing_address(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_start),
|
||||||
kernel_end: Frame::containing_address(kernel_end),
|
kernel_end: PhysFrame::containing_address(kernel_end),
|
||||||
multiboot_start: Frame::containing_address(multiboot_start),
|
multiboot_start: PhysFrame::containing_address(multiboot_start),
|
||||||
multiboot_end: Frame::containing_address(multiboot_end),
|
multiboot_end: PhysFrame::containing_address(multiboot_end),
|
||||||
};
|
};
|
||||||
allocator.choose_next_area();
|
allocator.choose_next_area();
|
||||||
allocator
|
allocator
|
||||||
|
|
@ -31,11 +31,11 @@ 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
|
PhysFrame::containing_address(area.end_address()) >= self.next_free_frame
|
||||||
}).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(area.start_address());
|
||||||
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 +44,21 @@ 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_arPhysea {
|
||||||
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(area.end_address());
|
||||||
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 +72,7 @@ impl FrameAllocator for AreaFrameAllocator {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn deallocate_frame(&mut self, frame: Frame) {
|
fn deallocate_frame(&mut self, frame: PhysFrame) {
|
||||||
unimplemented!();
|
unimplemented!();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -7,49 +7,24 @@ 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;
|
||||||
|
|
||||||
#[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 {
|
struct FrameIter {
|
||||||
start: Frame,
|
start: PhysFrame,
|
||||||
end: Frame,
|
end: PhysFrame,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Iterator for FrameIter {
|
impl Iterator for FrameIter {
|
||||||
type Item = Frame;
|
type Item = PhysFrame;
|
||||||
|
|
||||||
fn next(&mut self) -> Option<Frame> {
|
fn next(&mut self) -> Option<PhysFrame> {
|
||||||
if self.start <= self.end {
|
if self.start <= self.end {
|
||||||
let frame = self.start.clone();
|
let frame = self.start.clone();
|
||||||
self.start.number += 1;
|
self.start.number += 1;
|
||||||
|
|
@ -82,13 +57,12 @@ 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(HEAP_START);
|
||||||
let heap_end_page = Page::containing_address(HEAP_START + HEAP_SIZE - 1);
|
let heap_end_page = Page::containing_address(HEAP_START + HEAP_SIZE - 1);
|
||||||
|
|
||||||
for page in Page::range_inclusive(heap_start_page, heap_end_page) {
|
for page in Page::range_inclusive(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);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -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
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
@ -1,61 +1,52 @@
|
||||||
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::*;
|
||||||
|
//
|
||||||
|
// 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>
|
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> {
|
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()
|
||||||
|
.and_then(|paddr| PageTable::from(paddr));
|
||||||
|
|
||||||
let huge_page = || {
|
p1.and_then()
|
||||||
let p2_entry = &self.p2()[page.p2_index()];
|
|
||||||
if let Some(start_frame) = p2_entry.pointed_frame() {
|
|
||||||
if p2_entry.flags().contains(EntryFlags::HUGE_PAGE) {
|
|
||||||
// 4KiB alignment check
|
|
||||||
assert!(start_frame.number % ENTRY_COUNT == 0);
|
|
||||||
return Some(Frame {
|
|
||||||
number: start_frame.number + page.p1_index()
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
|
||||||
None
|
|
||||||
};
|
|
||||||
|
|
||||||
p1.and_then(|p1| p1[page.p1_index()].pointed_frame())
|
|
||||||
.or_else(huge_page)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
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
|
||||||
{
|
{
|
||||||
|
|
@ -63,20 +54,21 @@ impl Mapper {
|
||||||
let p1 = p2.next_table_create(page.p2_index(), allocator);
|
let p1 = p2.next_table_create(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);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -90,7 +82,7 @@ impl Mapper {
|
||||||
.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);
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,59 +1,16 @@
|
||||||
#![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::*;
|
|
||||||
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)]
|
#[derive(Clone)]
|
||||||
pub struct PageIter {
|
pub struct PageIter {
|
||||||
|
|
@ -106,33 +63,33 @@ 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();
|
x86::instructions::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 = PhysFrame::containing_address(Cr3::read() as usize);
|
||||||
|
|
||||||
let old_table = InactivePageTable {
|
let old_table = InactivePageTable {
|
||||||
p2_frame,
|
p2_frame,
|
||||||
};
|
};
|
||||||
|
|
||||||
unsafe {
|
unsafe {
|
||||||
let frame = Frame::containing_address(new_table.p2_frame.start_address());
|
let frame = PhysFrame::containing_address(new_table.p2_frame.start_address());
|
||||||
x86::cr3_write(frame.start_address());
|
Cr3::write(frame.start_address());
|
||||||
}
|
}
|
||||||
|
|
||||||
old_table
|
old_table
|
||||||
|
|
@ -140,11 +97,11 @@ impl ActivePageTable {
|
||||||
}
|
}
|
||||||
|
|
||||||
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 {
|
||||||
|
|
@ -154,7 +111,7 @@ impl InactivePageTable {
|
||||||
table.zero();
|
table.zero();
|
||||||
|
|
||||||
// set up recursive mapping for the table
|
// set up recursive mapping for the table
|
||||||
table[1023].set(frame.clone(), EntryFlags::PRESENT | EntryFlags:: WRITABLE)
|
table[1023].set(frame.clone(), PageTableFlags::PRESENT | PageTableFlags::WRITABLE)
|
||||||
}
|
}
|
||||||
temporary_page.unmap(active_table);
|
temporary_page.unmap(active_table);
|
||||||
InactivePageTable { p2_frame: frame }
|
InactivePageTable { p2_frame: frame }
|
||||||
|
|
@ -176,33 +133,31 @@ 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 = Frame::containing_address(0xb8000);
|
let vga_buffer_frame = PhysFrame::containing_address(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(§ion);
|
let flags = PageTableFlags::from_elf_section_flags(§ion);
|
||||||
let start_frame = Frame::containing_address(section.start_address() as usize);
|
let start_frame = PhysFrame::containing_address(section.start_address() as usize);
|
||||||
let end_frame = Frame::containing_address(section.end_address() as usize - 1);
|
let end_frame = PhysFrame::containing_address(section.end_address() as usize - 1);
|
||||||
for frame in Frame::range_inclusive(start_frame, end_frame) {
|
for frame in PhysFrame::range_inclusive(start_frame, end_frame) {
|
||||||
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(boot_info.start_address());
|
||||||
let multiboot_end = Frame::containing_address(boot_info.end_address() - 1);
|
let multiboot_end = PhysFrame::containing_address(boot_info.end_address() - 1);
|
||||||
for frame in Frame::range_inclusive(multiboot_start, multiboot_end) {
|
for frame in PhysFrame::range_inclusive(multiboot_start, multiboot_end) {
|
||||||
mapper.identity_map(frame, EntryFlags::PRESENT, allocator);
|
mapper.identity_map(frame, PageTableFlags::PRESENT, allocator);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,95 +1,32 @@
|
||||||
use memory::*;
|
use memory::*;
|
||||||
use memory::paging::*;
|
use x86::structures::paging::*;
|
||||||
|
|
||||||
use core::ops::{Index, IndexMut};
|
|
||||||
use core::marker::PhantomData;
|
|
||||||
|
|
||||||
// virtual address of P2 because its recursively mapped
|
pub trait TableNext<A>
|
||||||
// see protected mode Non-PAE
|
where A: FrameAllocator
|
||||||
// https://wiki.osdev.org/Page_Tables
|
|
||||||
pub const P2: *mut Table<Level2> = 0xffff_f000 as *mut _;
|
|
||||||
|
|
||||||
pub struct Table<L: TableLevel> {
|
|
||||||
entries: [Entry; ENTRY_COUNT],
|
|
||||||
level: PhantomData<L>,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<L> Table<L> where L: TableLevel
|
|
||||||
{
|
{
|
||||||
pub fn zero(&mut self) {
|
fn next_table_address(&self, index: usize) -> Option<usize>;
|
||||||
for entry in self.entries.iter_mut() {
|
fn next_table(&self, index: usize) -> Option<&PageTable>;
|
||||||
entry.set_unused();
|
fn next_table_mut(&mut self, index: usize) -> Option<&mut PageTable>;
|
||||||
}
|
fn next_table_create<A>(&mut self,
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<L> Table<L> where L: HierarchicalLevel
|
|
||||||
{
|
|
||||||
fn next_table_address(&self, index: usize) -> Option<usize> {
|
|
||||||
let entry_flags = self[index].flags();
|
|
||||||
if entry_flags.contains(EntryFlags::PRESENT) && !entry_flags.contains(EntryFlags::HUGE_PAGE) {
|
|
||||||
let table_address = self as *const _ as usize;
|
|
||||||
Some((table_address << 10) | (index << 12))
|
|
||||||
} else {
|
|
||||||
None
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn next_table(&self, index: usize) -> Option<&Table<L::NextLevel>> {
|
|
||||||
self.next_table_address(index)
|
|
||||||
.map(|address| unsafe { &*(address as *const _) })
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn next_table_mut(&mut self, index: usize) -> Option<&mut Table<L::NextLevel>> {
|
|
||||||
self.next_table_address(index)
|
|
||||||
.map(|address| unsafe { &mut *(address as *mut _) })
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn next_table_create<A>(&mut self,
|
|
||||||
index: usize,
|
index: usize,
|
||||||
allocator: &mut A) -> &mut Table<L::NextLevel>
|
allocator: &mut A) -> &mut PageTable;
|
||||||
|
}
|
||||||
|
|
||||||
|
impl TableNext<> for PageTable
|
||||||
|
{
|
||||||
|
fn next_table_create<A>(&mut self,
|
||||||
|
index: usize,
|
||||||
|
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; }
|
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,7 @@
|
||||||
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,
|
page: Page,
|
||||||
|
|
@ -19,14 +20,12 @@ 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);
|
||||||
self.page.start_address()
|
self.page.start_address()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -38,14 +37,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 *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 +57,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 +66,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);
|
||||||
|
|
|
||||||
|
|
@ -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");
|
|
||||||
}
|
|
||||||
4
kernel-rs/src/x86/structures/idt.rs
Normal file
4
kernel-rs/src/x86/structures/idt.rs
Normal file
|
|
@ -0,0 +1,4 @@
|
||||||
|
#[repr(C)]
|
||||||
|
pub struct Idt {
|
||||||
|
|
||||||
|
}
|
||||||
3
kernel-rs/src/x86/structures/mod.rs
Normal file
3
kernel-rs/src/x86/structures/mod.rs
Normal file
|
|
@ -0,0 +1,3 @@
|
||||||
|
pub mod idt;
|
||||||
|
// pub mod gdt;
|
||||||
|
// pub mod tss;
|
||||||
|
|
@ -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
1
kernel-rs/x86
Submodule
|
|
@ -0,0 +1 @@
|
||||||
|
Subproject commit dc9eb5ceb8981848d95e0ddd7040fb86ec9999e3
|
||||||
Loading…
Reference in a new issue