diff --git a/Cargo.lock b/Cargo.lock index f676a90a..83581011 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -31,7 +31,7 @@ name = "blog_os" version = "0.1.0" dependencies = [ "array-init 0.0.3 (registry+https://github.com/rust-lang/crates.io-index)", - "bootloader 0.3.12 (registry+https://github.com/rust-lang/crates.io-index)", + "bootloader 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)", "lazy_static 1.2.0 (registry+https://github.com/rust-lang/crates.io-index)", "pc-keyboard 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)", "pic8259_simple 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", @@ -43,13 +43,13 @@ dependencies = [ [[package]] name = "bootloader" -version = "0.3.12" +version = "0.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "fixedvec 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)", "font8x8 0.2.4 (registry+https://github.com/rust-lang/crates.io-index)", "usize_conversions 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)", - "x86_64 0.2.14 (registry+https://github.com/rust-lang/crates.io-index)", + "x86_64 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)", "xmas-elf 0.6.2 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -297,6 +297,19 @@ dependencies = [ "ux 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)", ] +[[package]] +name = "x86_64" +version = "0.3.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "array-init 0.0.4 (registry+https://github.com/rust-lang/crates.io-index)", + "bit_field 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)", + "bitflags 1.0.4 (registry+https://github.com/rust-lang/crates.io-index)", + "os_bootinfo 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)", + "usize_conversions 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)", + "ux 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)", +] + [[package]] name = "x86_64" version = "0.5.2" @@ -328,7 +341,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" "checksum array-init 0.0.4 (registry+https://github.com/rust-lang/crates.io-index)" = "23589ecb866b460d3a0f1278834750268c607e8e28a1b982c907219f3178cd72" "checksum bit_field 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)" = "ed8765909f9009617974ab6b7d332625b320b33c326b1e9321382ef1999b5d56" "checksum bitflags 1.0.4 (registry+https://github.com/rust-lang/crates.io-index)" = "228047a76f468627ca71776ecdebd732a3423081fcf5125585bcd7c49886ce12" -"checksum bootloader 0.3.12 (registry+https://github.com/rust-lang/crates.io-index)" = "2b498d7168288f3667f80aee93b4894e355dfce867803e1ccd5d9ee42a0b0e1a" +"checksum bootloader 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "a0808c55da932b82d3ababdaa0caa3f18522c5d2d06309b98f73adda849a3f03" "checksum cc 1.0.30 (registry+https://github.com/rust-lang/crates.io-index)" = "d01c69d08ff207f231f07196e30f84c70f1c815b04f980f8b7b01ff01f05eb92" "checksum cpuio 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "22b8e308ccfc5acf3b82f79c0eac444cf6114cb2ac67a230ca6c177210068daa" "checksum fixedvec 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)" = "7c6c16d316ccdac21a4dd648e314e76facbbaf316e83ca137d0857a9c07419d0" @@ -364,6 +377,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" "checksum winapi-i686-pc-windows-gnu 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6" "checksum winapi-x86_64-pc-windows-gnu 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" "checksum x86_64 0.2.14 (registry+https://github.com/rust-lang/crates.io-index)" = "2bd647af1614659e1febec1d681231aea4ebda4818bf55a578aff02f3e4db4b4" +"checksum x86_64 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)" = "f9258d7e2dd25008d69e8c9e9ee37865887a5e1e3d06a62f1cb3f6c209e6f177" "checksum x86_64 0.5.2 (registry+https://github.com/rust-lang/crates.io-index)" = "de155d368de1d32afc8f90838bf81986e4bd43a0cd5fcd7f7e9c85cb8f51dc7c" "checksum xmas-elf 0.6.2 (registry+https://github.com/rust-lang/crates.io-index)" = "22678df5df766e8d1e5d609da69f0c3132d794edf6ab5e75e7abcd2270d4cf58" "checksum zero 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)" = "5f1bc8a6b2005884962297587045002d8cfb8dcec9db332f4ca216ddc5de82c5" diff --git a/Cargo.toml b/Cargo.toml index c3be061b..a43c8998 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -5,7 +5,7 @@ authors = ["Philipp Oppermann "] edition = "2018" [dependencies] -bootloader = "0.3.12" +bootloader = { version = "0.4.0", features = ["map_physical_memory"]} volatile = "0.2.3" spin = "0.4.9" uart_16550 = "0.1.0" diff --git a/README.md b/README.md index a4087f75..7a6724cb 100644 --- a/README.md +++ b/README.md @@ -1,10 +1,10 @@ -# Blog OS (Advanced Paging) +# Blog OS (Paging Implementation) [![Build Status](https://travis-ci.org/phil-opp/blog_os.svg?branch=post-10)](https://travis-ci.org/phil-opp/blog_os/branches) -This repository contains the source code for the [Advanced Paging][post] post of the [Writing an OS in Rust](https://os.phil-opp.com) series. +This repository contains the source code for the [Paging Implementation][post] post of the [Writing an OS in Rust](https://os.phil-opp.com) series. -[post]: https://os.phil-opp.com/advanced-paging/ +[post]: https://os.phil-opp.com/paging-implementation/ **Check out the [master branch](https://github.com/phil-opp/blog_os) for more information.** diff --git a/src/main.rs b/src/main.rs index a6493875..d4d3269f 100644 --- a/src/main.rs +++ b/src/main.rs @@ -3,7 +3,7 @@ #![cfg_attr(test, allow(unused_imports))] use blog_os::println; -use bootloader::{bootinfo::BootInfo, entry_point}; +use bootloader::{entry_point, BootInfo}; use core::panic::PanicInfo; entry_point!(kernel_main); @@ -11,7 +11,8 @@ entry_point!(kernel_main); #[cfg(not(test))] fn kernel_main(boot_info: &'static BootInfo) -> ! { use blog_os::interrupts::PICS; - use blog_os::memory::{self, create_example_mapping}; + use blog_os::memory; + use x86_64::{structures::paging::Page, VirtAddr}; println!("Hello World{}", "!"); @@ -20,11 +21,16 @@ fn kernel_main(boot_info: &'static BootInfo) -> ! { unsafe { PICS.lock().initialize() }; x86_64::instructions::interrupts::enable(); - let mut recursive_page_table = unsafe { memory::init(boot_info.p4_table_addr as usize) }; + let mut mapper = unsafe { memory::init(boot_info.physical_memory_offset) }; let mut frame_allocator = memory::init_frame_allocator(&boot_info.memory_map); - create_example_mapping(&mut recursive_page_table, &mut frame_allocator); - unsafe { (0xdeadbeaf900 as *mut u64).write_volatile(0xf021f077f065f04e) }; + // map a previously unmapped page + let page = Page::containing_address(VirtAddr::new(0xdeadbeaf000)); + memory::create_example_mapping(page, &mut mapper, &mut frame_allocator); + + // write the string `New!` to the screen through the new mapping + let page_ptr: *mut u64 = page.start_address().as_mut_ptr(); + unsafe { page_ptr.offset(400).write_volatile(0x_f021_f077_f065_f04e) }; println!("It did not crash!"); blog_os::hlt_loop(); diff --git a/src/memory.rs b/src/memory.rs index ddf643be..0589fdd6 100644 --- a/src/memory.rs +++ b/src/memory.rs @@ -1,24 +1,26 @@ use bootloader::bootinfo::{MemoryMap, MemoryRegionType}; -use x86_64::structures::paging::{ - FrameAllocator, Mapper, Page, PageTable, PhysFrame, RecursivePageTable, Size4KiB, +use x86_64::{ + structures::paging::{ + FrameAllocator, MappedPageTable, Mapper, MapperAllSizes, Page, PageTable, PhysFrame, + Size4KiB, + }, + PhysAddr, VirtAddr, }; -use x86_64::{PhysAddr, VirtAddr}; -/// Creates a RecursivePageTable instance from the level 4 address. +/// Initialize a new MappedPageTable. /// -/// This function is unsafe because it can break memory safety if an invalid -/// address is passed. -pub unsafe fn init(level_4_table_addr: usize) -> RecursivePageTable<'static> { - /// Rust currently treats the whole body of unsafe functions as an unsafe - /// block, which makes it difficult to see which operations are unsafe. To - /// limit the scope of unsafe we use a safe inner function. - fn init_inner(level_4_table_addr: usize) -> RecursivePageTable<'static> { - let level_4_table_ptr = level_4_table_addr as *mut PageTable; - let level_4_table = unsafe { &mut *level_4_table_ptr }; - RecursivePageTable::new(level_4_table).unwrap() - } - - init_inner(level_4_table_addr) +/// This function is unsafe because the caller must guarantee that the +/// complete physical memory is mapped to virtual memory at the passed +/// `physical_memory_offset`. Also, this function must be only called once +/// to avoid aliasing `&mut` references (which is undefined behavior). +pub unsafe fn init(physical_memory_offset: u64) -> impl MapperAllSizes { + let level_4_table = active_level_4_table(physical_memory_offset); + let phys_to_virt = move |frame: PhysFrame| -> *mut PageTable { + let phys = frame.start_address().as_u64(); + let virt = VirtAddr::new(phys + physical_memory_offset); + virt.as_mut_ptr() + }; + MappedPageTable::new(level_4_table, phys_to_virt) } /// Create a FrameAllocator from the passed memory map @@ -39,17 +41,36 @@ pub fn init_frame_allocator( BootInfoFrameAllocator { frames } } +/// Returns a mutable reference to the active level 4 table. +/// +/// This function is unsafe because the caller must guarantee that the +/// complete physical memory is mapped to virtual memory at the passed +/// `physical_memory_offset`. Also, this function must be only called once +/// to avoid aliasing `&mut` references (which is undefined behavior). +unsafe fn active_level_4_table(physical_memory_offset: u64) -> &'static mut PageTable { + use x86_64::{registers::control::Cr3, VirtAddr}; + + let (level_4_table_frame, _) = Cr3::read(); + + let phys = level_4_table_frame.start_address(); + let virt = VirtAddr::new(phys.as_u64() + physical_memory_offset); + let page_table_ptr: *mut PageTable = virt.as_mut_ptr(); + + &mut *page_table_ptr // unsafe +} + +/// Creates an example mapping for the given page to frame `0xb8000`. pub fn create_example_mapping( - recursive_page_table: &mut RecursivePageTable, + page: Page, + mapper: &mut impl Mapper, frame_allocator: &mut impl FrameAllocator, ) { use x86_64::structures::paging::PageTableFlags as Flags; - let page: Page = Page::containing_address(VirtAddr::new(0xdeadbeaf000)); let frame = PhysFrame::containing_address(PhysAddr::new(0xb8000)); let flags = Flags::PRESENT | Flags::WRITABLE; - let map_to_result = unsafe { recursive_page_table.map_to(page, frame, flags, frame_allocator) }; + let map_to_result = unsafe { mapper.map_to(page, frame, flags, frame_allocator) }; map_to_result.expect("map_to failed").flush(); }