Force flush of tables
This commit is contained in:
parent
e3635f37f6
commit
a627cb7fef
10 changed files with 223 additions and 172 deletions
|
@ -59,7 +59,8 @@ pub struct DmarDrhd {
|
|||
|
||||
impl DmarDrhd {
|
||||
pub fn get(&self, active_table: &mut ActivePageTable) -> &'static mut Drhd {
|
||||
active_table.identity_map(Frame::containing_address(PhysicalAddress::new(self.base as usize)), entry::PRESENT | entry::WRITABLE | entry::NO_EXECUTE);
|
||||
let result = active_table.identity_map(Frame::containing_address(PhysicalAddress::new(self.base as usize)), entry::PRESENT | entry::WRITABLE | entry::NO_EXECUTE);
|
||||
result.flush(active_table);
|
||||
unsafe { &mut *(self.base as *mut Drhd) }
|
||||
}
|
||||
}
|
||||
|
|
|
@ -52,8 +52,8 @@ pub fn init_sdt(sdt: &'static Sdt, active_table: &mut ActivePageTable) {
|
|||
let trampoline_page = Page::containing_address(VirtualAddress::new(TRAMPOLINE));
|
||||
|
||||
// Map trampoline
|
||||
active_table.map_to(trampoline_page, trampoline_frame, entry::PRESENT | entry::WRITABLE);
|
||||
active_table.flush(trampoline_page);
|
||||
let result = active_table.map_to(trampoline_page, trampoline_frame, entry::PRESENT | entry::WRITABLE);
|
||||
result.flush(active_table);
|
||||
|
||||
for madt_entry in madt.iter() {
|
||||
println!(" {:?}", madt_entry);
|
||||
|
@ -136,8 +136,8 @@ pub fn init_sdt(sdt: &'static Sdt, active_table: &mut ActivePageTable) {
|
|||
}
|
||||
|
||||
// Unmap trampoline
|
||||
active_table.unmap(trampoline_page);
|
||||
active_table.flush(trampoline_page);
|
||||
let result = active_table.unmap(trampoline_page);
|
||||
result.flush(active_table);
|
||||
} else if let Some(dmar) = Dmar::new(sdt) {
|
||||
println!(": {}: {}", dmar.addr_width, dmar.flags);
|
||||
|
||||
|
@ -173,8 +173,8 @@ pub unsafe fn init(active_table: &mut ActivePageTable) -> Option<Acpi> {
|
|||
let end_frame = Frame::containing_address(PhysicalAddress::new(end_addr));
|
||||
for frame in Frame::range_inclusive(start_frame, end_frame) {
|
||||
let page = Page::containing_address(VirtualAddress::new(frame.start_address().get()));
|
||||
active_table.map_to(page, frame, entry::PRESENT | entry::NO_EXECUTE);
|
||||
active_table.flush(page);
|
||||
let result = active_table.map_to(page, frame, entry::PRESENT | entry::NO_EXECUTE);
|
||||
result.flush(active_table);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -184,8 +184,8 @@ pub unsafe fn init(active_table: &mut ActivePageTable) -> Option<Acpi> {
|
|||
let mapped = if active_table.translate_page(Page::containing_address(VirtualAddress::new(sdt_address))).is_none() {
|
||||
let sdt_frame = Frame::containing_address(PhysicalAddress::new(sdt_address));
|
||||
let sdt_page = Page::containing_address(VirtualAddress::new(sdt_address));
|
||||
active_table.map_to(sdt_page, sdt_frame, entry::PRESENT | entry::NO_EXECUTE);
|
||||
active_table.flush(sdt_page);
|
||||
let result = active_table.map_to(sdt_page, sdt_frame, entry::PRESENT | entry::NO_EXECUTE);
|
||||
result.flush(active_table);
|
||||
true
|
||||
} else {
|
||||
false
|
||||
|
@ -198,8 +198,8 @@ pub unsafe fn init(active_table: &mut ActivePageTable) -> Option<Acpi> {
|
|||
drop(sdt);
|
||||
if mapped {
|
||||
let sdt_page = Page::containing_address(VirtualAddress::new(sdt_address));
|
||||
active_table.unmap(sdt_page);
|
||||
active_table.flush(sdt_page);
|
||||
let result = active_table.unmap(sdt_page);
|
||||
result.flush(active_table);
|
||||
}
|
||||
};
|
||||
|
||||
|
@ -236,8 +236,8 @@ pub unsafe fn init(active_table: &mut ActivePageTable) -> Option<Acpi> {
|
|||
let end_frame = Frame::containing_address(PhysicalAddress::new(end_addr));
|
||||
for frame in Frame::range_inclusive(start_frame, end_frame) {
|
||||
let page = Page::containing_address(VirtualAddress::new(frame.start_address().get()));
|
||||
active_table.unmap(page);
|
||||
active_table.flush(page);
|
||||
let result = active_table.unmap(page);
|
||||
result.flush(active_table);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -32,7 +32,8 @@ impl LocalApic {
|
|||
if ! self.x2 {
|
||||
let page = Page::containing_address(VirtualAddress::new(self.address));
|
||||
let frame = Frame::containing_address(PhysicalAddress::new(self.address - ::KERNEL_OFFSET));
|
||||
active_table.map_to(page, frame, entry::PRESENT | entry::WRITABLE | entry::NO_EXECUTE);
|
||||
let result = active_table.map_to(page, frame, entry::PRESENT | entry::WRITABLE | entry::NO_EXECUTE);
|
||||
result.flush(active_table);
|
||||
}
|
||||
|
||||
self.init_ap();
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
//! Architecture support for x86_64
|
||||
|
||||
#![deny(unused_must_use)]
|
||||
#![feature(asm)]
|
||||
#![feature(concat_idents)]
|
||||
#![feature(const_fn)]
|
||||
|
|
|
@ -1,11 +1,81 @@
|
|||
use core::mem;
|
||||
use core::ptr::Unique;
|
||||
|
||||
use memory::{allocate_frame, deallocate_frame, Frame};
|
||||
|
||||
use super::{Page, PAGE_SIZE, PhysicalAddress, VirtualAddress};
|
||||
use super::{ActivePageTable, Page, PAGE_SIZE, PhysicalAddress, VirtualAddress};
|
||||
use super::entry::{self, EntryFlags};
|
||||
use super::table::{self, Table, Level4};
|
||||
|
||||
/// In order to enforce correct paging operations in the kernel, these types
|
||||
/// are returned on any mapping operation to get the code involved to specify
|
||||
/// how it intends to flush changes to a page table
|
||||
#[must_use = "The page table must be flushed, or the changes unsafely ignored"]
|
||||
pub struct MapperFlush(Page);
|
||||
|
||||
impl MapperFlush {
|
||||
/// Create a new page flush promise
|
||||
pub fn new(page: Page) -> MapperFlush {
|
||||
MapperFlush(page)
|
||||
}
|
||||
|
||||
/// Flush this page in the active table
|
||||
pub fn flush(self, table: &mut ActivePageTable) {
|
||||
table.flush(self.0);
|
||||
mem::forget(self);
|
||||
}
|
||||
|
||||
/// Ignore the flush. This is unsafe, and a reason should be provided for use
|
||||
pub unsafe fn ignore(self) {
|
||||
mem::forget(self);
|
||||
}
|
||||
}
|
||||
|
||||
/// A flush cannot be dropped, it must be consumed
|
||||
impl Drop for MapperFlush {
|
||||
fn drop(&mut self) {
|
||||
panic!("Mapper flush was not utilized");
|
||||
}
|
||||
}
|
||||
|
||||
/// To allow for combining multiple flushes into one, we have a way of flushing
|
||||
/// the active table, which can consume MapperFlush structs
|
||||
#[must_use = "The page table must be flushed, or the changes unsafely ignored"]
|
||||
pub struct MapperFlushAll(bool);
|
||||
|
||||
impl MapperFlushAll {
|
||||
/// Create a new promise to flush all mappings
|
||||
pub fn new() -> MapperFlushAll {
|
||||
MapperFlushAll(false)
|
||||
}
|
||||
|
||||
/// Consume a single page flush
|
||||
pub fn consume(&mut self, flush: MapperFlush) {
|
||||
self.0 = true;
|
||||
mem::forget(flush);
|
||||
}
|
||||
|
||||
/// Flush the active page table
|
||||
pub fn flush(self, table: &mut ActivePageTable) {
|
||||
if self.0 {
|
||||
table.flush_all();
|
||||
}
|
||||
mem::forget(self);
|
||||
}
|
||||
|
||||
/// Ignore the flush. This is unsafe, and a reason should be provided for use
|
||||
pub unsafe fn ignore(self) {
|
||||
mem::forget(self);
|
||||
}
|
||||
}
|
||||
|
||||
/// A flush cannot be dropped, it must be consumed
|
||||
impl Drop for MapperFlushAll {
|
||||
fn drop(&mut self) {
|
||||
panic!("Mapper flush all was not utilized");
|
||||
}
|
||||
}
|
||||
|
||||
pub struct Mapper {
|
||||
p4: Unique<Table<Level4>>,
|
||||
}
|
||||
|
@ -27,7 +97,7 @@ impl Mapper {
|
|||
}
|
||||
|
||||
/// Map a page to a frame
|
||||
pub fn map_to(&mut self, page: Page, frame: Frame, flags: EntryFlags) {
|
||||
pub fn map_to(&mut self, page: Page, frame: Frame, flags: EntryFlags) -> MapperFlush {
|
||||
let mut p3 = self.p4_mut().next_table_create(page.p4_index());
|
||||
let mut p2 = p3.next_table_create(page.p3_index());
|
||||
let mut p1 = p2.next_table_create(page.p2_index());
|
||||
|
@ -38,31 +108,33 @@ impl Mapper {
|
|||
p1[page.p1_index()].address().get(), p1[page.p1_index()].flags(),
|
||||
frame.start_address().get(), flags);
|
||||
p1[page.p1_index()].set(frame, flags | entry::PRESENT);
|
||||
MapperFlush::new(page)
|
||||
}
|
||||
|
||||
/// Map a page to the next free frame
|
||||
pub fn map(&mut self, page: Page, flags: EntryFlags) {
|
||||
pub fn map(&mut self, page: Page, flags: EntryFlags) -> MapperFlush {
|
||||
let frame = allocate_frame().expect("out of frames");
|
||||
self.map_to(page, frame, flags)
|
||||
}
|
||||
|
||||
/// Update flags for a page
|
||||
pub fn remap(&mut self, page: Page, flags: EntryFlags) {
|
||||
pub fn remap(&mut self, page: Page, flags: EntryFlags) -> MapperFlush {
|
||||
let mut p3 = self.p4_mut().next_table_mut(page.p4_index()).expect("failed to remap: no p3");
|
||||
let mut p2 = p3.next_table_mut(page.p3_index()).expect("failed to remap: no p2");
|
||||
let mut p1 = p2.next_table_mut(page.p2_index()).expect("failed to remap: no p1");
|
||||
let frame = p1[page.p1_index()].pointed_frame().expect("failed to remap: not mapped");
|
||||
p1[page.p1_index()].set(frame, flags | entry::PRESENT);
|
||||
MapperFlush::new(page)
|
||||
}
|
||||
|
||||
/// Identity map a frame
|
||||
pub fn identity_map(&mut self, frame: Frame, flags: EntryFlags) {
|
||||
pub fn identity_map(&mut self, frame: Frame, flags: EntryFlags) -> MapperFlush {
|
||||
let page = Page::containing_address(VirtualAddress::new(frame.start_address().get()));
|
||||
self.map_to(page, frame, flags)
|
||||
}
|
||||
|
||||
/// Unmap a page
|
||||
pub fn unmap(&mut self, page: Page) {
|
||||
pub fn unmap(&mut self, page: Page) -> MapperFlush {
|
||||
let p1 = self.p4_mut()
|
||||
.next_table_mut(page.p4_index())
|
||||
.and_then(|p3| p3.next_table_mut(page.p3_index()))
|
||||
|
@ -72,10 +144,11 @@ impl Mapper {
|
|||
p1[page.p1_index()].set_unused();
|
||||
// TODO free p(1,2,3) table if empty
|
||||
deallocate_frame(frame);
|
||||
MapperFlush::new(page)
|
||||
}
|
||||
|
||||
/// Unmap a page, return frame without free
|
||||
pub fn unmap_return(&mut self, page: Page) -> Frame {
|
||||
pub fn unmap_return(&mut self, page: Page) -> (MapperFlush, Frame) {
|
||||
let p1 = self.p4_mut()
|
||||
.next_table_mut(page.p4_index())
|
||||
.and_then(|p3| p3.next_table_mut(page.p3_index()))
|
||||
|
@ -83,7 +156,7 @@ impl Mapper {
|
|||
.expect("unmap_return does not support huge pages");
|
||||
let frame = p1[page.p1_index()].pointed_frame().unwrap();
|
||||
p1[page.p1_index()].set_unused();
|
||||
frame
|
||||
(MapperFlush::new(page), frame)
|
||||
}
|
||||
|
||||
pub fn translate_page(&self, page: Page) -> Option<Frame> {
|
||||
|
|
|
@ -118,52 +118,56 @@ pub unsafe fn init(cpu_id: usize, stack_start: usize, stack_end: usize) -> (Acti
|
|||
};
|
||||
|
||||
active_table.with(&mut new_table, &mut temporary_page, |mapper| {
|
||||
// Map tdata and tbss
|
||||
{
|
||||
// Map tdata and tbss
|
||||
{
|
||||
let size = & __tbss_end as *const _ as usize - & __tdata_start as *const _ as usize;
|
||||
let size = & __tbss_end as *const _ as usize - & __tdata_start as *const _ as usize;
|
||||
|
||||
let start = ::KERNEL_PERCPU_OFFSET + ::KERNEL_PERCPU_SIZE * cpu_id;
|
||||
let end = start + size;
|
||||
let start = ::KERNEL_PERCPU_OFFSET + ::KERNEL_PERCPU_SIZE * cpu_id;
|
||||
let end = start + size;
|
||||
|
||||
let start_page = Page::containing_address(VirtualAddress::new(start));
|
||||
let end_page = Page::containing_address(VirtualAddress::new(end - 1));
|
||||
for page in Page::range_inclusive(start_page, end_page) {
|
||||
mapper.map(page, PRESENT | GLOBAL | NO_EXECUTE | WRITABLE);
|
||||
let start_page = Page::containing_address(VirtualAddress::new(start));
|
||||
let end_page = Page::containing_address(VirtualAddress::new(end - 1));
|
||||
for page in Page::range_inclusive(start_page, end_page) {
|
||||
let result = mapper.map(page, PRESENT | GLOBAL | NO_EXECUTE | WRITABLE);
|
||||
// The flush can be ignored as this is not the active table. See later active_table.switch
|
||||
unsafe { result.ignore(); }
|
||||
}
|
||||
}
|
||||
|
||||
let mut remap = |start: usize, end: usize, flags: EntryFlags| {
|
||||
if end > start {
|
||||
let start_frame = Frame::containing_address(PhysicalAddress::new(start));
|
||||
let end_frame = Frame::containing_address(PhysicalAddress::new(end - 1));
|
||||
for frame in Frame::range_inclusive(start_frame, end_frame) {
|
||||
let page = Page::containing_address(VirtualAddress::new(frame.start_address().get() + ::KERNEL_OFFSET));
|
||||
let result = mapper.map_to(page, frame, flags);
|
||||
// The flush can be ignored as this is not the active table. See later active_table.switch
|
||||
unsafe { result.ignore(); }
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
let mut remap = |start: usize, end: usize, flags: EntryFlags| {
|
||||
if end > start {
|
||||
let start_frame = Frame::containing_address(PhysicalAddress::new(start));
|
||||
let end_frame = Frame::containing_address(PhysicalAddress::new(end - 1));
|
||||
for frame in Frame::range_inclusive(start_frame, end_frame) {
|
||||
let page = Page::containing_address(VirtualAddress::new(frame.start_address().get() + ::KERNEL_OFFSET));
|
||||
mapper.map_to(page, frame, flags);
|
||||
}
|
||||
}
|
||||
};
|
||||
// Remap stack writable, no execute
|
||||
remap(stack_start - ::KERNEL_OFFSET, stack_end - ::KERNEL_OFFSET, PRESENT | GLOBAL | NO_EXECUTE | WRITABLE);
|
||||
|
||||
// Remap stack writable, no execute
|
||||
remap(stack_start - ::KERNEL_OFFSET, stack_end - ::KERNEL_OFFSET, PRESENT | GLOBAL | NO_EXECUTE | WRITABLE);
|
||||
|
||||
// Remap a section with `flags`
|
||||
let mut remap_section = |start: &u8, end: &u8, flags: EntryFlags| {
|
||||
remap(start as *const _ as usize - ::KERNEL_OFFSET, end as *const _ as usize - ::KERNEL_OFFSET, flags);
|
||||
};
|
||||
// Remap text read-only
|
||||
remap_section(& __text_start, & __text_end, PRESENT | GLOBAL);
|
||||
// Remap rodata read-only, no execute
|
||||
remap_section(& __rodata_start, & __rodata_end, PRESENT | GLOBAL | NO_EXECUTE);
|
||||
// Remap data writable, no execute
|
||||
remap_section(& __data_start, & __data_end, PRESENT | GLOBAL | NO_EXECUTE | WRITABLE);
|
||||
// Remap tdata master writable, no execute
|
||||
remap_section(& __tdata_start, & __tdata_end, PRESENT | GLOBAL | NO_EXECUTE);
|
||||
// Remap bss writable, no execute
|
||||
remap_section(& __bss_start, & __bss_end, PRESENT | GLOBAL | NO_EXECUTE | WRITABLE);
|
||||
}
|
||||
// Remap a section with `flags`
|
||||
let mut remap_section = |start: &u8, end: &u8, flags: EntryFlags| {
|
||||
remap(start as *const _ as usize - ::KERNEL_OFFSET, end as *const _ as usize - ::KERNEL_OFFSET, flags);
|
||||
};
|
||||
// Remap text read-only
|
||||
remap_section(& __text_start, & __text_end, PRESENT | GLOBAL);
|
||||
// Remap rodata read-only, no execute
|
||||
remap_section(& __rodata_start, & __rodata_end, PRESENT | GLOBAL | NO_EXECUTE);
|
||||
// Remap data writable, no execute
|
||||
remap_section(& __data_start, & __data_end, PRESENT | GLOBAL | NO_EXECUTE | WRITABLE);
|
||||
// Remap tdata master writable, no execute
|
||||
remap_section(& __tdata_start, & __tdata_end, PRESENT | GLOBAL | NO_EXECUTE);
|
||||
// Remap bss writable, no execute
|
||||
remap_section(& __bss_start, & __bss_end, PRESENT | GLOBAL | NO_EXECUTE | WRITABLE);
|
||||
});
|
||||
|
||||
// This switches the active table, which is setup by the bootloader, to a correct table
|
||||
// setup by the lambda above. This will also flush the TLB
|
||||
active_table.switch(new_table);
|
||||
|
||||
(active_table, init_tcb(cpu_id))
|
||||
|
@ -200,7 +204,9 @@ pub unsafe fn init_ap(cpu_id: usize, bsp_table: usize, stack_start: usize, stack
|
|||
let start_page = Page::containing_address(VirtualAddress::new(start));
|
||||
let end_page = Page::containing_address(VirtualAddress::new(end - 1));
|
||||
for page in Page::range_inclusive(start_page, end_page) {
|
||||
mapper.map(page, PRESENT | GLOBAL | NO_EXECUTE | WRITABLE);
|
||||
let result = mapper.map(page, PRESENT | GLOBAL | NO_EXECUTE | WRITABLE);
|
||||
// The flush can be ignored as this is not the active table. See later active_table.switch
|
||||
unsafe { result.ignore(); }
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -210,7 +216,9 @@ pub unsafe fn init_ap(cpu_id: usize, bsp_table: usize, stack_start: usize, stack
|
|||
let end_frame = Frame::containing_address(PhysicalAddress::new(end - 1));
|
||||
for frame in Frame::range_inclusive(start_frame, end_frame) {
|
||||
let page = Page::containing_address(VirtualAddress::new(frame.start_address().get() + ::KERNEL_OFFSET));
|
||||
mapper.map_to(page, frame, flags);
|
||||
let result = mapper.map_to(page, frame, flags);
|
||||
// The flush can be ignored as this is not the active table. See later active_table.switch
|
||||
unsafe { result.ignore(); }
|
||||
}
|
||||
}
|
||||
};
|
||||
|
@ -219,6 +227,8 @@ pub unsafe fn init_ap(cpu_id: usize, bsp_table: usize, stack_start: usize, stack
|
|||
remap(stack_start - ::KERNEL_OFFSET, stack_end - ::KERNEL_OFFSET, PRESENT | GLOBAL | NO_EXECUTE | WRITABLE);
|
||||
});
|
||||
|
||||
// This switches the active table, which is setup by the bootloader, to a correct table
|
||||
// setup by the lambda above. This will also flush the TLB
|
||||
active_table.switch(new_table);
|
||||
|
||||
init_tcb(cpu_id)
|
||||
|
|
|
@ -26,7 +26,8 @@ impl TemporaryPage {
|
|||
/// Returns the start address of the temporary page.
|
||||
pub fn map(&mut self, frame: Frame, flags: EntryFlags, active_table: &mut ActivePageTable) -> VirtualAddress {
|
||||
assert!(active_table.translate_page(self.page).is_none(), "temporary page is already mapped");
|
||||
active_table.map_to(self.page, frame, flags);
|
||||
let result = active_table.map_to(self.page, frame, flags);
|
||||
result.flush(active_table);
|
||||
self.page.start_address()
|
||||
}
|
||||
|
||||
|
@ -38,6 +39,7 @@ impl TemporaryPage {
|
|||
|
||||
/// Unmaps the temporary page in the active table.
|
||||
pub fn unmap(&mut self, active_table: &mut ActivePageTable) {
|
||||
active_table.unmap(self.page)
|
||||
let result = active_table.unmap(self.page);
|
||||
result.flush(active_table);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -14,6 +14,7 @@ use idt;
|
|||
use interrupt;
|
||||
use memory;
|
||||
use paging::{self, entry, Page, VirtualAddress};
|
||||
use paging::mapper::MapperFlushAll;
|
||||
|
||||
/// Test of zero values in BSS.
|
||||
static BSS_TEST_ZERO: usize = 0;
|
||||
|
@ -97,13 +98,18 @@ pub unsafe extern fn kstart() -> ! {
|
|||
|
||||
// Setup kernel heap
|
||||
{
|
||||
let mut flush_all = MapperFlushAll::new();
|
||||
|
||||
// Map heap pages
|
||||
let heap_start_page = Page::containing_address(VirtualAddress::new(::KERNEL_HEAP_OFFSET));
|
||||
let heap_end_page = Page::containing_address(VirtualAddress::new(::KERNEL_HEAP_OFFSET + ::KERNEL_HEAP_SIZE-1));
|
||||
for page in Page::range_inclusive(heap_start_page, heap_end_page) {
|
||||
active_table.map(page, entry::PRESENT | entry::GLOBAL | entry::WRITABLE | entry::NO_EXECUTE);
|
||||
let result = active_table.map(page, entry::PRESENT | entry::GLOBAL | entry::WRITABLE | entry::NO_EXECUTE);
|
||||
flush_all.consume(result);
|
||||
}
|
||||
|
||||
flush_all.flush(&mut active_table);
|
||||
|
||||
// Init the allocator
|
||||
allocator::init(::KERNEL_HEAP_OFFSET, ::KERNEL_HEAP_SIZE);
|
||||
}
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue