mirror of
https://github.com/rcore-os/rCore.git
synced 2024-11-23 00:16:17 +04:00
aarch64/mmu: can run on the real raspi3
This commit is contained in:
parent
a9de99d3a9
commit
bb1c1abaa4
@ -1,9 +1,9 @@
|
|||||||
use paging::PhysFrame;
|
use paging::PhysFrame;
|
||||||
use addr::PhysAddr;
|
use addr::{PhysAddr, VirtAddr};
|
||||||
use regs::*;
|
use regs::*;
|
||||||
|
|
||||||
#[inline(always)]
|
#[inline(always)]
|
||||||
pub fn tlb_invalidate() {
|
pub fn tlb_invalidate_all() {
|
||||||
unsafe {
|
unsafe {
|
||||||
asm!(
|
asm!(
|
||||||
"dsb ishst
|
"dsb ishst
|
||||||
@ -14,6 +14,18 @@ pub fn tlb_invalidate() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[inline(always)]
|
||||||
|
pub fn tlb_invalidate(vaddr: VirtAddr) {
|
||||||
|
unsafe {
|
||||||
|
asm!(
|
||||||
|
"dsb ishst
|
||||||
|
tlbi vaae1is, $0
|
||||||
|
dsb ish
|
||||||
|
isb" :: "r"(vaddr.as_u64() >> 12)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// Returns the current stack pointer.
|
/// Returns the current stack pointer.
|
||||||
#[inline(always)]
|
#[inline(always)]
|
||||||
pub fn sp() -> *const u8 {
|
pub fn sp() -> *const u8 {
|
||||||
|
@ -28,7 +28,7 @@ impl<S: PageSize> MapperFlush<S> {
|
|||||||
|
|
||||||
/// Flush the page from the TLB to ensure that the newest mapping is used.
|
/// Flush the page from the TLB to ensure that the newest mapping is used.
|
||||||
pub fn flush(self) {
|
pub fn flush(self) {
|
||||||
tlb_invalidate();
|
tlb_invalidate(self.0.start_address());
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Don't flush the TLB and silence the “must be used” warning.
|
/// Don't flush the TLB and silence the “must be used” warning.
|
||||||
@ -232,6 +232,7 @@ impl<'a> RecursivePageTable<'a> {
|
|||||||
let page_table_ptr = next_table_page.start_address().as_mut_ptr();
|
let page_table_ptr = next_table_page.start_address().as_mut_ptr();
|
||||||
let page_table: &mut PageTable = unsafe { &mut *(page_table_ptr) };
|
let page_table: &mut PageTable = unsafe { &mut *(page_table_ptr) };
|
||||||
if created {
|
if created {
|
||||||
|
tlb_invalidate(next_table_page.start_address());
|
||||||
page_table.zero();
|
page_table.zero();
|
||||||
}
|
}
|
||||||
Ok(page_table)
|
Ok(page_table)
|
||||||
|
@ -7,12 +7,9 @@ pub mod timer;
|
|||||||
pub mod serial;
|
pub mod serial;
|
||||||
|
|
||||||
pub fn init() {
|
pub fn init() {
|
||||||
// FIXME
|
assert_has_not_been_called!("board::init must be called only once");
|
||||||
// assert_has_not_been_called!("board::init must be called only once");
|
|
||||||
|
|
||||||
unsafe {
|
serial::SERIAL_PORT.lock().init();
|
||||||
serial::SERIAL_PORT.init();
|
|
||||||
}
|
|
||||||
|
|
||||||
println!("Hello Raspberry Pi!");
|
println!("Hello Raspberry Pi!");
|
||||||
}
|
}
|
||||||
|
@ -20,8 +20,7 @@ impl SerialPort {
|
|||||||
|
|
||||||
/// Init a newly created SerialPort, can only be called once.
|
/// Init a newly created SerialPort, can only be called once.
|
||||||
pub fn init(&mut self) {
|
pub fn init(&mut self) {
|
||||||
// FIXME
|
assert_has_not_been_called!("SerialPort::init must be called only once");
|
||||||
// assert_has_not_been_called!("SerialPort::init must be called only once");
|
|
||||||
self.mu = Some(MiniUart::new());
|
self.mu = Some(MiniUart::new());
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -71,7 +70,4 @@ impl fmt::Write for SerialPort {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// FIXME
|
pub static SERIAL_PORT: Mutex<SerialPort> = Mutex::new(SerialPort::new());
|
||||||
// pub static SERIAL_PORT: Mutex<SerialPort> = Mutex::new(SerialPort::new());
|
|
||||||
pub static mut SERIAL_PORT: SerialPort = SerialPort::new();
|
|
||||||
|
|
||||||
|
@ -4,15 +4,11 @@ use core::fmt::{Arguments, Write};
|
|||||||
use super::board::serial::{SerialRead, SERIAL_PORT};
|
use super::board::serial::{SerialRead, SERIAL_PORT};
|
||||||
|
|
||||||
pub fn getchar() -> char {
|
pub fn getchar() -> char {
|
||||||
// FIXME
|
unsafe { SERIAL_PORT.force_unlock(); }
|
||||||
unsafe {
|
SERIAL_PORT.lock().receive() as char
|
||||||
SERIAL_PORT.receive() as char
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn putfmt(fmt: Arguments) {
|
pub fn putfmt(fmt: Arguments) {
|
||||||
// FIXME
|
unsafe { SERIAL_PORT.force_unlock(); }
|
||||||
unsafe {
|
SERIAL_PORT.lock().write_fmt(fmt).unwrap()
|
||||||
SERIAL_PORT.write_fmt(fmt).unwrap()
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
@ -7,6 +7,14 @@ use aarch64::{barrier, regs::*, addr::*, paging::PhysFrame as Frame};
|
|||||||
|
|
||||||
/// Memory initialization.
|
/// Memory initialization.
|
||||||
pub fn init() {
|
pub fn init() {
|
||||||
|
init_frame_allocator();
|
||||||
|
init_heap();
|
||||||
|
remap_the_kernel();
|
||||||
|
info!("memory: init end");
|
||||||
|
}
|
||||||
|
|
||||||
|
/// initialize temporary paging and enable mmu immediately after boot. Serial port is disabled at this time.
|
||||||
|
pub fn init_mmu_early() {
|
||||||
#[repr(align(4096))]
|
#[repr(align(4096))]
|
||||||
struct PageData([u8; PAGE_SIZE]);
|
struct PageData([u8; PAGE_SIZE]);
|
||||||
static PAGE_TABLE_LVL4: PageData = PageData([0; PAGE_SIZE]);
|
static PAGE_TABLE_LVL4: PageData = PageData([0; PAGE_SIZE]);
|
||||||
@ -18,41 +26,6 @@ pub fn init() {
|
|||||||
let frame_lvl2 = Frame::containing_address(PhysAddr::new(&PAGE_TABLE_LVL2 as *const _ as u64));
|
let frame_lvl2 = Frame::containing_address(PhysAddr::new(&PAGE_TABLE_LVL2 as *const _ as u64));
|
||||||
super::paging::setup_page_table(frame_lvl4, frame_lvl3, frame_lvl2);
|
super::paging::setup_page_table(frame_lvl4, frame_lvl3, frame_lvl2);
|
||||||
|
|
||||||
init_mmu();
|
|
||||||
init_frame_allocator();
|
|
||||||
init_heap();
|
|
||||||
remap_the_kernel();
|
|
||||||
|
|
||||||
info!("memory: init end");
|
|
||||||
}
|
|
||||||
|
|
||||||
fn init_frame_allocator() {
|
|
||||||
use bit_allocator::BitAlloc;
|
|
||||||
use core::ops::Range;
|
|
||||||
use consts::{MEMORY_OFFSET};
|
|
||||||
|
|
||||||
let (start, end) = memory_map().expect("failed to find memory map");
|
|
||||||
let mut ba = FRAME_ALLOCATOR.lock();
|
|
||||||
ba.insert(to_range(start, end));
|
|
||||||
info!("FrameAllocator init end");
|
|
||||||
|
|
||||||
/*
|
|
||||||
* @param:
|
|
||||||
* start: start address
|
|
||||||
* end: end address
|
|
||||||
* @brief:
|
|
||||||
* transform the memory address to the page number
|
|
||||||
* @retval:
|
|
||||||
* the page number range from start address to end address
|
|
||||||
*/
|
|
||||||
fn to_range(start: usize, end: usize) -> Range<usize> {
|
|
||||||
let page_start = (start - MEMORY_OFFSET) / PAGE_SIZE;
|
|
||||||
let page_end = (end - MEMORY_OFFSET - 1) / PAGE_SIZE + 1;
|
|
||||||
page_start..page_end
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn init_mmu() {
|
|
||||||
// device.
|
// device.
|
||||||
MAIR_EL1.write(
|
MAIR_EL1.write(
|
||||||
// Attribute 1
|
// Attribute 1
|
||||||
@ -85,10 +58,35 @@ fn init_mmu() {
|
|||||||
|
|
||||||
// Force MMU init to complete before next instruction
|
// Force MMU init to complete before next instruction
|
||||||
unsafe { barrier::isb(barrier::SY); }
|
unsafe { barrier::isb(barrier::SY); }
|
||||||
|
|
||||||
info!("mmu enabled");
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn init_frame_allocator() {
|
||||||
|
use bit_allocator::BitAlloc;
|
||||||
|
use core::ops::Range;
|
||||||
|
use consts::{MEMORY_OFFSET};
|
||||||
|
|
||||||
|
let (start, end) = memory_map().expect("failed to find memory map");
|
||||||
|
let mut ba = FRAME_ALLOCATOR.lock();
|
||||||
|
ba.insert(to_range(start, end));
|
||||||
|
info!("FrameAllocator init end");
|
||||||
|
|
||||||
|
/*
|
||||||
|
* @param:
|
||||||
|
* start: start address
|
||||||
|
* end: end address
|
||||||
|
* @brief:
|
||||||
|
* transform the memory address to the page number
|
||||||
|
* @retval:
|
||||||
|
* the page number range from start address to end address
|
||||||
|
*/
|
||||||
|
fn to_range(start: usize, end: usize) -> Range<usize> {
|
||||||
|
let page_start = (start - MEMORY_OFFSET) / PAGE_SIZE;
|
||||||
|
let page_end = (end - MEMORY_OFFSET - 1) / PAGE_SIZE + 1;
|
||||||
|
page_start..page_end
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// remap kernel page table after all initialization.
|
||||||
fn remap_the_kernel() {
|
fn remap_the_kernel() {
|
||||||
let (bottom, top) = (0, bootstacktop as usize);
|
let (bottom, top) = (0, bootstacktop as usize);
|
||||||
let kstack = Stack {
|
let kstack = Stack {
|
||||||
|
@ -17,9 +17,13 @@ pub use self::board::timer;
|
|||||||
/// The entry point of kernel
|
/// The entry point of kernel
|
||||||
#[no_mangle] // don't mangle the name of this function
|
#[no_mangle] // don't mangle the name of this function
|
||||||
pub extern "C" fn rust_main() -> ! {
|
pub extern "C" fn rust_main() -> ! {
|
||||||
|
// Enable mmu and paging
|
||||||
|
memory::init_mmu_early();
|
||||||
|
|
||||||
// Init board to enable serial port.
|
// Init board to enable serial port.
|
||||||
board::init();
|
board::init();
|
||||||
::logging::init(); // FIXME
|
|
||||||
|
::logging::init();
|
||||||
interrupt::init();
|
interrupt::init();
|
||||||
memory::init();
|
memory::init();
|
||||||
timer::init();
|
timer::init();
|
||||||
|
@ -5,7 +5,7 @@ use memory::{active_table, alloc_frame, alloc_stack, dealloc_frame};
|
|||||||
use ucore_memory::memory_set::*;
|
use ucore_memory::memory_set::*;
|
||||||
use ucore_memory::PAGE_SIZE;
|
use ucore_memory::PAGE_SIZE;
|
||||||
use ucore_memory::paging::*;
|
use ucore_memory::paging::*;
|
||||||
use aarch64::asm::{tlb_invalidate, ttbr0_el1_read, ttbr0_el1_write};
|
use aarch64::asm::{tlb_invalidate, tlb_invalidate_all, ttbr0_el1_read, ttbr0_el1_write};
|
||||||
use aarch64::{PhysAddr, VirtAddr};
|
use aarch64::{PhysAddr, VirtAddr};
|
||||||
use aarch64::paging::{Mapper, PageTable as Aarch64PageTable, PageTableEntry, PageTableFlags as EF, RecursivePageTable};
|
use aarch64::paging::{Mapper, PageTable as Aarch64PageTable, PageTableEntry, PageTableFlags as EF, RecursivePageTable};
|
||||||
use aarch64::paging::{FrameAllocator, FrameDeallocator, Page, PageRange, PhysFrame as Frame, Size4KiB, Size2MiB};
|
use aarch64::paging::{FrameAllocator, FrameDeallocator, Page, PageRange, PhysFrame as Frame, Size4KiB, Size2MiB};
|
||||||
@ -123,9 +123,7 @@ pub fn setup_page_table(frame_lvl4: Frame, frame_lvl3: Frame, frame_lvl2: Frame)
|
|||||||
// }
|
// }
|
||||||
|
|
||||||
ttbr0_el1_write(frame_lvl4);
|
ttbr0_el1_write(frame_lvl4);
|
||||||
tlb_invalidate();
|
tlb_invalidate_all();
|
||||||
|
|
||||||
info!("setup init page table end");
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// map the range [start, end) as device memory, insert to the MemorySet
|
/// map the range [start, end) as device memory, insert to the MemorySet
|
||||||
@ -222,7 +220,8 @@ impl ActivePageTable {
|
|||||||
|
|
||||||
impl Entry for PageEntry {
|
impl Entry for PageEntry {
|
||||||
fn update(&mut self) {
|
fn update(&mut self) {
|
||||||
tlb_invalidate();
|
let addr = VirtAddr::new_unchecked((self as *const _ as u64) << 9);
|
||||||
|
tlb_invalidate(addr);
|
||||||
}
|
}
|
||||||
|
|
||||||
fn present(&self) -> bool { self.0.flags().contains(EF::PRESENT) }
|
fn present(&self) -> bool { self.0.flags().contains(EF::PRESENT) }
|
||||||
@ -314,14 +313,14 @@ impl InactivePageTable for InactivePageTable0 {
|
|||||||
|
|
||||||
// overwrite recursive mapping
|
// overwrite recursive mapping
|
||||||
p4_table[RECURSIVE_INDEX].set_frame(self.p4_frame.clone(), EF::PRESENT | EF::WRITE | EF::ACCESSED | EF::PAGE_BIT);
|
p4_table[RECURSIVE_INDEX].set_frame(self.p4_frame.clone(), EF::PRESENT | EF::WRITE | EF::ACCESSED | EF::PAGE_BIT);
|
||||||
tlb_invalidate();
|
tlb_invalidate_all();
|
||||||
|
|
||||||
// execute f in the new context
|
// execute f in the new context
|
||||||
f(active_table);
|
f(active_table);
|
||||||
|
|
||||||
// restore recursive mapping to original p4 table
|
// restore recursive mapping to original p4 table
|
||||||
p4_table[RECURSIVE_INDEX] = backup;
|
p4_table[RECURSIVE_INDEX] = backup;
|
||||||
tlb_invalidate();
|
tlb_invalidate_all();
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -331,7 +330,7 @@ impl InactivePageTable for InactivePageTable0 {
|
|||||||
debug!("switch table {:?} -> {:?}", old_frame, new_frame);
|
debug!("switch table {:?} -> {:?}", old_frame, new_frame);
|
||||||
if old_frame != new_frame {
|
if old_frame != new_frame {
|
||||||
ttbr0_el1_write(new_frame);
|
ttbr0_el1_write(new_frame);
|
||||||
tlb_invalidate();
|
tlb_invalidate_all();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -341,13 +340,13 @@ impl InactivePageTable for InactivePageTable0 {
|
|||||||
debug!("switch table {:?} -> {:?}", old_frame, new_frame);
|
debug!("switch table {:?} -> {:?}", old_frame, new_frame);
|
||||||
if old_frame != new_frame {
|
if old_frame != new_frame {
|
||||||
ttbr0_el1_write(new_frame);
|
ttbr0_el1_write(new_frame);
|
||||||
tlb_invalidate();
|
tlb_invalidate_all();
|
||||||
}
|
}
|
||||||
f();
|
f();
|
||||||
debug!("switch table {:?} -> {:?}", new_frame, old_frame);
|
debug!("switch table {:?} -> {:?}", new_frame, old_frame);
|
||||||
if old_frame != new_frame {
|
if old_frame != new_frame {
|
||||||
ttbr0_el1_write(old_frame);
|
ttbr0_el1_write(old_frame);
|
||||||
tlb_invalidate();
|
tlb_invalidate_all();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user