forked from rcore-os/zCore
kernel-hal: refactor for riscv bare-metal
This commit is contained in:
parent
1097f4ac1e
commit
91f082ce18
|
@ -9,6 +9,8 @@ description = "Kernel HAL interface definations."
|
||||||
|
|
||||||
[features]
|
[features]
|
||||||
libos = ["async-std"]
|
libos = ["async-std"]
|
||||||
|
board_qemu = []
|
||||||
|
board_d1 = []
|
||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
log = "0.4"
|
log = "0.4"
|
||||||
|
@ -50,5 +52,4 @@ x86-smpboot = { git = "https://github.com/rcore-os/x86-smpboot", rev = "43ffedf"
|
||||||
|
|
||||||
# Bare-metal mode on riscv64
|
# Bare-metal mode on riscv64
|
||||||
[target.'cfg(all(target_os = "none", target_arch = "riscv64"))'.dependencies]
|
[target.'cfg(all(target_os = "none", target_arch = "riscv64"))'.dependencies]
|
||||||
# riscv = { git = "https://github.com/rcore-os/riscv", features = ["inline-asm"], rev = "0074cbc" }
|
riscv = { git = "https://github.com/rcore-os/riscv", features = ["inline-asm"], rev = "0074cbc" }
|
||||||
# volatile = "0.2"
|
|
||||||
|
|
|
@ -23,32 +23,31 @@ pub const MMIO_MTIMECMP0: *mut u64 = 0x0200_4000usize as *mut u64;
|
||||||
pub const MMIO_MTIME: *const u64 = 0x0200_BFF8 as *const u64;
|
pub const MMIO_MTIME: *const u64 = 0x0200_BFF8 as *const u64;
|
||||||
|
|
||||||
#[cfg(feature = "board_qemu")]
|
#[cfg(feature = "board_qemu")]
|
||||||
pub const UART_BASE: usize = 0x10000000;
|
pub const UART_BASE: usize = 0x10000000;
|
||||||
#[cfg(feature = "board_qemu")]
|
#[cfg(feature = "board_qemu")]
|
||||||
pub const UART0_INT_NUM: u32 = 10;
|
pub const UART0_INT_NUM: u32 = 10;
|
||||||
#[cfg(feature = "board_qemu")]
|
#[cfg(feature = "board_qemu")]
|
||||||
pub const PLIC_PRIORITY: usize = 0x0c000000;
|
pub const PLIC_PRIORITY: usize = 0x0c000000;
|
||||||
#[cfg(feature = "board_qemu")]
|
#[cfg(feature = "board_qemu")]
|
||||||
pub const PLIC_PENDING: usize = 0x0c001000;
|
pub const PLIC_PENDING: usize = 0x0c001000;
|
||||||
#[cfg(feature = "board_qemu")]
|
#[cfg(feature = "board_qemu")]
|
||||||
pub const PLIC_INT_ENABLE: usize = 0x0c002080;
|
pub const PLIC_INT_ENABLE: usize = 0x0c002080;
|
||||||
#[cfg(feature = "board_qemu")]
|
#[cfg(feature = "board_qemu")]
|
||||||
pub const PLIC_THRESHOLD: usize = 0x0c201000;
|
pub const PLIC_THRESHOLD: usize = 0x0c201000;
|
||||||
#[cfg(feature = "board_qemu")]
|
#[cfg(feature = "board_qemu")]
|
||||||
pub const PLIC_CLAIM: usize = 0x0c201004;
|
pub const PLIC_CLAIM: usize = 0x0c201004;
|
||||||
|
|
||||||
#[cfg(feature = "board_d1")]
|
#[cfg(feature = "board_d1")]
|
||||||
pub const UART_BASE: usize = 0x02500000;
|
pub const UART_BASE: usize = 0x02500000;
|
||||||
#[cfg(feature = "board_d1")]
|
#[cfg(feature = "board_d1")]
|
||||||
pub const UART0_INT_NUM: u32 = 18;
|
pub const UART0_INT_NUM: u32 = 18;
|
||||||
#[cfg(feature = "board_d1")]
|
#[cfg(feature = "board_d1")]
|
||||||
pub const PLIC_PRIORITY: usize = 0x1000_0000;
|
pub const PLIC_PRIORITY: usize = 0x1000_0000;
|
||||||
#[cfg(feature = "board_d1")]
|
#[cfg(feature = "board_d1")]
|
||||||
pub const PLIC_PENDING: usize = 0x1000_1000;
|
pub const PLIC_PENDING: usize = 0x1000_1000;
|
||||||
#[cfg(feature = "board_d1")]
|
#[cfg(feature = "board_d1")]
|
||||||
pub const PLIC_INT_ENABLE: usize = 0x1000_2080;
|
pub const PLIC_INT_ENABLE: usize = 0x1000_2080;
|
||||||
#[cfg(feature = "board_d1")]
|
#[cfg(feature = "board_d1")]
|
||||||
pub const PLIC_THRESHOLD: usize = 0x1020_1000;
|
pub const PLIC_THRESHOLD: usize = 0x1020_1000;
|
||||||
#[cfg(feature = "board_d1")]
|
#[cfg(feature = "board_d1")]
|
||||||
pub const PLIC_CLAIM: usize = 0x1020_1004;
|
pub const PLIC_CLAIM: usize = 0x1020_1004;
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,19 @@
|
||||||
|
use riscv::register::{scause, stval};
|
||||||
|
|
||||||
|
use crate::VirtAddr;
|
||||||
|
|
||||||
|
hal_fn_impl! {
|
||||||
|
impl mod crate::defs::context {
|
||||||
|
fn context_run(context: &mut UserContext) {
|
||||||
|
context.run();
|
||||||
|
}
|
||||||
|
|
||||||
|
fn fetch_fault_vaddr() -> VirtAddr {
|
||||||
|
stval::read() as _
|
||||||
|
}
|
||||||
|
|
||||||
|
fn fetch_trap_num(_context: &UserContext) -> usize {
|
||||||
|
scause::read().bits()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,8 @@
|
||||||
|
hal_fn_impl! {
|
||||||
|
impl mod crate::defs::cpu {
|
||||||
|
fn cpu_frequency() -> u16 {
|
||||||
|
const DEFAULT: u16 = 2600;
|
||||||
|
DEFAULT
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -1,94 +1,46 @@
|
||||||
use alloc::boxed::Box;
|
use alloc::{boxed::Box, vec::Vec};
|
||||||
use alloc::vec::Vec;
|
use riscv::register::{sie, sstatus};
|
||||||
use riscv::register::{
|
|
||||||
satp,
|
|
||||||
scause::{self, Exception, Interrupt, Trap},
|
|
||||||
sie, sstatus, stval,
|
|
||||||
};
|
|
||||||
use spin::Mutex;
|
use spin::Mutex;
|
||||||
use trapframe::{TrapFrame, UserContext};
|
|
||||||
|
|
||||||
use super::{plic, uart, sbi, timer_set_next};
|
use super::{consts, plic, serial, trap, uart};
|
||||||
use super::consts::{PHYSICAL_MEMORY_OFFSET, UART_BASE, UART0_INT_NUM};
|
|
||||||
use crate::{map_range, phys_to_virt, putfmt};
|
// IRQ
|
||||||
|
const TIMER: u8 = 5;
|
||||||
|
const U_PLIC: u8 = 8;
|
||||||
|
const S_PLIC: u8 = 9;
|
||||||
|
const M_PLIC: u8 = 11;
|
||||||
|
|
||||||
const TABLE_SIZE: usize = 256;
|
const TABLE_SIZE: usize = 256;
|
||||||
pub type InterruptHandle = Box<dyn Fn() + Send + Sync>;
|
|
||||||
lazy_static! {
|
type InterruptHandler = Box<dyn Fn() + Send + Sync>;
|
||||||
static ref IRQ_TABLE: Mutex<Vec<Option<InterruptHandle>>> = Default::default();
|
|
||||||
|
lazy_static::lazy_static! {
|
||||||
|
static ref IRQ_TABLE: Mutex<Vec<Option<InterruptHandler>>> = Default::default();
|
||||||
}
|
}
|
||||||
|
|
||||||
fn init_irq() {
|
#[allow(dead_code)]
|
||||||
init_irq_table();
|
fn init_soft() {
|
||||||
irq_add_handle(Timer, Box::new(super_timer)); //模拟参照了x86_64,把timer处理函数也放进去了
|
unsafe { sie::set_ssoft() };
|
||||||
//irq_add_handle(Keyboard, Box::new(keyboard));
|
sbi_println!("+++ setup soft int! +++");
|
||||||
irq_add_handle(S_PLIC, Box::new(plic::handle_interrupt));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn init() {
|
fn init_ext() {
|
||||||
unsafe {
|
unsafe { sie::set_sext() };
|
||||||
sstatus::set_sie();
|
plic::init();
|
||||||
|
sbi_println!("+++ Setting up PLIC +++");
|
||||||
init_uart();
|
|
||||||
|
|
||||||
sie::set_sext();
|
|
||||||
init_ext();
|
|
||||||
}
|
|
||||||
|
|
||||||
init_irq();
|
|
||||||
|
|
||||||
bare_println!("+++ setup interrupt +++");
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#[no_mangle]
|
fn init_uart() {
|
||||||
pub extern "C" fn trap_handler(tf: &mut TrapFrame) {
|
uart::init(consts::UART_BASE);
|
||||||
let sepc = tf.sepc;
|
|
||||||
let scause = scause::read();
|
|
||||||
let stval = stval::read();
|
|
||||||
let is_int = scause.bits() >> 63;
|
|
||||||
let code = scause.bits() & !(1 << 63);
|
|
||||||
|
|
||||||
match scause.cause() {
|
//但当没有SBI_CONSOLE_PUTCHAR时,却为什么不行?
|
||||||
Trap::Exception(Exception::Breakpoint) => breakpoint(&mut tf.sepc),
|
serial::uart_print_fmt(format_args!("UART output testing\n\r"));
|
||||||
Trap::Exception(Exception::IllegalInstruction) => {
|
|
||||||
panic!("IllegalInstruction: {:#x}->{:#x}", sepc, stval)
|
|
||||||
}
|
|
||||||
Trap::Exception(Exception::LoadFault) => {
|
|
||||||
panic!("Load access fault: {:#x}->{:#x}", sepc, stval)
|
|
||||||
}
|
|
||||||
Trap::Exception(Exception::StoreFault) => {
|
|
||||||
panic!("Store access fault: {:#x}->{:#x}", sepc, stval)
|
|
||||||
}
|
|
||||||
Trap::Exception(Exception::LoadPageFault) => page_fault(stval, tf),
|
|
||||||
Trap::Exception(Exception::StorePageFault) => page_fault(stval, tf),
|
|
||||||
Trap::Exception(Exception::InstructionPageFault) => page_fault(stval, tf),
|
|
||||||
Trap::Interrupt(Interrupt::SupervisorTimer) => super_timer(),
|
|
||||||
Trap::Interrupt(Interrupt::SupervisorSoft) => super_soft(),
|
|
||||||
Trap::Interrupt(Interrupt::SupervisorExternal) => plic::handle_interrupt(),
|
|
||||||
//Trap::Interrupt(Interrupt::SupervisorExternal) => irq_handle(code as u8),
|
|
||||||
_ => panic!("Undefined Trap: {:#x} {:#x}", is_int, code),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn init_irq_table() {
|
sbi_println!("+++ Setting up UART interrupts +++");
|
||||||
let mut table = IRQ_TABLE.lock();
|
|
||||||
for _ in 0..TABLE_SIZE {
|
|
||||||
table.push(None);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[export_name = "hal_irq_handle"]
|
|
||||||
pub fn irq_handle(irq: u8) {
|
|
||||||
debug!("PLIC handle: {:#x}", irq);
|
|
||||||
let table = IRQ_TABLE.lock();
|
|
||||||
match &table[irq as usize] {
|
|
||||||
Some(f) => f(),
|
|
||||||
None => panic!("unhandled U-mode external IRQ number: {}", irq),
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Add a handle to IRQ table. Return the specified irq or an allocated irq on success
|
/// Add a handle to IRQ table. Return the specified irq or an allocated irq on success
|
||||||
fn irq_add_handle(irq: u8, handle: InterruptHandle) -> Option<u8> {
|
fn irq_add_handle(irq: u8, handler: InterruptHandler) -> Option<u8> {
|
||||||
info!("IRQ add handle {:#x?}", irq);
|
info!("IRQ add handle {:#x?}", irq);
|
||||||
let mut table = IRQ_TABLE.lock();
|
let mut table = IRQ_TABLE.lock();
|
||||||
// allocate a valid irq number
|
// allocate a valid irq number
|
||||||
|
@ -97,7 +49,7 @@ fn irq_add_handle(irq: u8, handle: InterruptHandle) -> Option<u8> {
|
||||||
let mut id = 0x20;
|
let mut id = 0x20;
|
||||||
while id < table.len() {
|
while id < table.len() {
|
||||||
if table[id].is_none() {
|
if table[id].is_none() {
|
||||||
table[id] = Some(handle);
|
table[id] = Some(handler);
|
||||||
return Some(id as u8);
|
return Some(id as u8);
|
||||||
}
|
}
|
||||||
id += 1;
|
id += 1;
|
||||||
|
@ -108,206 +60,43 @@ fn irq_add_handle(irq: u8, handle: InterruptHandle) -> Option<u8> {
|
||||||
match table[irq as usize] {
|
match table[irq as usize] {
|
||||||
Some(_) => None,
|
Some(_) => None,
|
||||||
None => {
|
None => {
|
||||||
table[irq as usize] = Some(handle);
|
table[irq as usize] = Some(handler);
|
||||||
Some(irq)
|
Some(irq)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn irq_remove_handle(irq: u8) -> bool {
|
fn init_irq_table() {
|
||||||
info!("IRQ remove handle {:#x?}", irq);
|
|
||||||
let irq = irq as usize;
|
|
||||||
let mut table = IRQ_TABLE.lock();
|
let mut table = IRQ_TABLE.lock();
|
||||||
match table[irq] {
|
for _ in 0..TABLE_SIZE {
|
||||||
Some(_) => {
|
table.push(None);
|
||||||
table[irq] = None;
|
|
||||||
false
|
|
||||||
}
|
|
||||||
None => true,
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn breakpoint(sepc: &mut usize) {
|
fn init_irq() {
|
||||||
bare_println!("Exception::Breakpoint: A breakpoint set @0x{:x} ", sepc);
|
init_irq_table();
|
||||||
|
irq_add_handle(TIMER, Box::new(trap::super_timer)); //模拟参照了x86_64,把timer处理函数也放进去了
|
||||||
//sepc为触发中断指令ebreak的地址
|
//irq_add_handle(Keyboard, Box::new(keyboard));
|
||||||
//防止无限循环中断,让sret返回时跳转到sepc的下一条指令地址
|
irq_add_handle(S_PLIC, Box::new(plic::handle_interrupt));
|
||||||
*sepc += 2
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn page_fault(stval: usize, tf: &mut TrapFrame) {
|
pub(super) fn init() {
|
||||||
let this_scause = scause::read();
|
unsafe { sstatus::set_sie() };
|
||||||
info!(
|
init_uart();
|
||||||
"EXCEPTION Page Fault: {:?} @ {:#x}->{:#x}",
|
init_ext();
|
||||||
this_scause.cause(),
|
init_irq();
|
||||||
tf.sepc,
|
sbi_println!("+++ setup interrupt +++");
|
||||||
stval
|
|
||||||
);
|
|
||||||
let vaddr = stval;
|
|
||||||
|
|
||||||
use crate::PageTableImpl;
|
|
||||||
use kernel_hal::{MMUFlags, paging::PageTableTrait};
|
|
||||||
use riscv::addr::{Page, PhysAddr, VirtAddr};
|
|
||||||
use riscv::paging::{PageTableFlags as PTF, Rv39PageTable, *};
|
|
||||||
|
|
||||||
//let mut flags = PTF::VALID;
|
|
||||||
let code = this_scause.code();
|
|
||||||
let mut flags = if code == 15 {
|
|
||||||
//MMUFlags::WRITE ???
|
|
||||||
MMUFlags::READ | MMUFlags::WRITE
|
|
||||||
} else if code == 12 {
|
|
||||||
MMUFlags::EXECUTE
|
|
||||||
} else {
|
|
||||||
MMUFlags::READ
|
|
||||||
};
|
|
||||||
|
|
||||||
let linear_offset = if stval >= PHYSICAL_MEMORY_OFFSET {
|
|
||||||
// Kernel
|
|
||||||
PHYSICAL_MEMORY_OFFSET
|
|
||||||
} else {
|
|
||||||
// User
|
|
||||||
0
|
|
||||||
};
|
|
||||||
|
|
||||||
/*
|
|
||||||
let current =
|
|
||||||
unsafe { &mut *(phys_to_virt(satp::read().frame().start_address().as_usize()) as *mut PageTable) };
|
|
||||||
let mut pt = Rv39PageTable::new(current, PHYSICAL_MEMORY_OFFSET);
|
|
||||||
map_range(&mut pt, vaddr, vaddr, linear_offset, flags);
|
|
||||||
*/
|
|
||||||
|
|
||||||
let mut pti = PageTableImpl {
|
|
||||||
root_paddr: satp::read().frame().start_address().as_usize(),
|
|
||||||
};
|
|
||||||
|
|
||||||
let page = Page::of_addr(VirtAddr::new(vaddr));
|
|
||||||
if let Ok(pte) = pti.get().ref_entry(page) {
|
|
||||||
let pte = unsafe { &mut *(pte as *mut PageTableEntry) };
|
|
||||||
if !pte.is_unused() {
|
|
||||||
debug!(
|
|
||||||
"PageAlreadyMapped -> {:#x?}, {:?}",
|
|
||||||
pte.addr().as_usize(),
|
|
||||||
pte.flags()
|
|
||||||
);
|
|
||||||
//TODO update flags
|
|
||||||
|
|
||||||
pti.unmap(vaddr).unwrap();
|
|
||||||
}
|
|
||||||
};
|
|
||||||
pti.map(vaddr, vaddr - linear_offset, flags).unwrap();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn super_timer() {
|
hal_fn_impl! {
|
||||||
timer_set_next();
|
impl mod crate::defs::interrupt {
|
||||||
super::timer_tick();
|
fn handle_irq(irq: u32) {
|
||||||
|
debug!("PLIC handle: {:#x}", irq);
|
||||||
//bare_print!(".");
|
let table = IRQ_TABLE.lock();
|
||||||
|
match &table[irq as usize] {
|
||||||
//发生外界中断时,epc的指令还没有执行,故无需修改epc到下一条
|
Some(f) => f(),
|
||||||
}
|
None => panic!("unhandled U-mode external IRQ number: {}", irq),
|
||||||
|
|
||||||
fn init_uart() {
|
|
||||||
uart::Uart::new(phys_to_virt(UART_BASE)).simple_init();
|
|
||||||
|
|
||||||
//但当没有SBI_CONSOLE_PUTCHAR时,却为什么不行?
|
|
||||||
super::putfmt_uart(format_args!("{}", "UART output testing\n\r"));
|
|
||||||
|
|
||||||
bare_println!("+++ Setting up UART interrupts +++");
|
|
||||||
}
|
|
||||||
|
|
||||||
//被plic串口中断调用
|
|
||||||
pub fn try_process_serial() -> bool {
|
|
||||||
match super::getchar_option() {
|
|
||||||
Some(ch) => {
|
|
||||||
super::serial_put(ch);
|
|
||||||
true
|
|
||||||
}
|
|
||||||
None => false,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn init_ext() {
|
|
||||||
// Qemu virt UART0 = 10
|
|
||||||
// ALLWINNER D1 UART0 = 18
|
|
||||||
plic::set_priority(UART0_INT_NUM, 7);
|
|
||||||
plic::set_threshold(0);
|
|
||||||
plic::enable(UART0_INT_NUM);
|
|
||||||
|
|
||||||
bare_println!("+++ Setting up PLIC +++");
|
|
||||||
}
|
|
||||||
|
|
||||||
fn super_soft() {
|
|
||||||
sbi::clear_ipi();
|
|
||||||
bare_println!("Interrupt::SupervisorSoft!");
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn init_soft() {
|
|
||||||
unsafe {
|
|
||||||
sie::set_ssoft();
|
|
||||||
}
|
|
||||||
bare_println!("+++ setup soft int! +++");
|
|
||||||
}
|
|
||||||
|
|
||||||
#[export_name = "fetch_trap_num"]
|
|
||||||
pub fn fetch_trap_num(_context: &UserContext) -> usize {
|
|
||||||
scause::read().bits()
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn wait_for_interrupt() {
|
|
||||||
unsafe {
|
|
||||||
// enable interrupt and disable
|
|
||||||
let sie = riscv::register::sstatus::read().sie();
|
|
||||||
riscv::register::sstatus::set_sie();
|
|
||||||
riscv::asm::wfi();
|
|
||||||
if !sie {
|
|
||||||
riscv::register::sstatus::clear_sie();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn timer() {
|
|
||||||
super::timer_tick();
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
* 改道uart::handle_interrupt()中
|
|
||||||
*
|
|
||||||
fn com1() {
|
|
||||||
let c = super::COM1.lock().receive();
|
|
||||||
super::serial_put(c);
|
|
||||||
}
|
|
||||||
*/
|
|
||||||
|
|
||||||
/*
|
|
||||||
fn keyboard() {
|
|
||||||
use pc_keyboard::{DecodedKey, KeyCode};
|
|
||||||
if let Some(key) = super::keyboard::receive() {
|
|
||||||
match key {
|
|
||||||
DecodedKey::Unicode(c) => super::serial_put(c as u8),
|
|
||||||
DecodedKey::RawKey(code) => {
|
|
||||||
let s = match code {
|
|
||||||
KeyCode::ArrowUp => "\u{1b}[A",
|
|
||||||
KeyCode::ArrowDown => "\u{1b}[B",
|
|
||||||
KeyCode::ArrowRight => "\u{1b}[C",
|
|
||||||
KeyCode::ArrowLeft => "\u{1b}[D",
|
|
||||||
_ => "",
|
|
||||||
};
|
|
||||||
for c in s.bytes() {
|
|
||||||
super::serial_put(c);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
*/
|
|
||||||
|
|
||||||
// IRQ
|
|
||||||
const Timer: u8 = 5;
|
|
||||||
const U_PLIC: u8 = 8;
|
|
||||||
const S_PLIC: u8 = 9;
|
|
||||||
const M_PLIC: u8 = 11;
|
|
||||||
|
|
||||||
//const Keyboard: u8 = 1;
|
|
||||||
//const COM2: u8 = 3;
|
|
||||||
const COM1: u8 = 0;
|
|
||||||
//const IDE: u8 = 14;
|
|
||||||
|
|
|
@ -0,0 +1,3 @@
|
||||||
|
pub fn frame_flush(_target: crate::PhysAddr) {
|
||||||
|
unimplemented!()
|
||||||
|
}
|
|
@ -1,567 +1,36 @@
|
||||||
use super::super::*;
|
#![allow(dead_code)]
|
||||||
use kernel_hal::dev::fb::{ColorDepth, ColorFormat, FramebufferInfo, FRAME_BUFFER};
|
|
||||||
use kernel_hal::{HalError, PhysAddr, VirtAddr, paging::PageTableTrait};
|
|
||||||
use riscv::addr::Page;
|
|
||||||
use riscv::asm::sfence_vma_all;
|
|
||||||
use riscv::paging::{PageTableFlags as PTF, *};
|
|
||||||
use riscv::register::{satp, sie, stval, time};
|
|
||||||
//use crate::sbi;
|
|
||||||
use alloc::{collections::VecDeque, vec::Vec};
|
|
||||||
use core::fmt::{self, Write};
|
|
||||||
|
|
||||||
mod sbi;
|
use alloc::vec::Vec;
|
||||||
|
|
||||||
|
#[macro_use]
|
||||||
|
pub mod serial;
|
||||||
|
|
||||||
mod consts;
|
mod consts;
|
||||||
|
mod plic;
|
||||||
|
mod sbi;
|
||||||
|
mod trap;
|
||||||
|
mod uart;
|
||||||
|
|
||||||
use consts::*;
|
pub mod context;
|
||||||
|
pub mod cpu;
|
||||||
|
pub mod interrupt;
|
||||||
|
pub mod mem;
|
||||||
|
pub mod special;
|
||||||
|
pub mod timer;
|
||||||
|
pub mod vm;
|
||||||
|
|
||||||
// First core stores its SATP here.
|
|
||||||
static mut SATP: usize = 0;
|
|
||||||
|
|
||||||
/// remap kernel with 4K page
|
|
||||||
pub fn remap_the_kernel(dtb: usize) {
|
|
||||||
let root_frame = Frame::alloc().expect("failed to alloc frame");
|
|
||||||
let root_vaddr = phys_to_virt(root_frame.paddr);
|
|
||||||
let root = unsafe { &mut *(root_vaddr as *mut PageTable) };
|
|
||||||
root.zero();
|
|
||||||
let mut pt = Rv39PageTable::new(root, PHYSICAL_MEMORY_OFFSET);
|
|
||||||
|
|
||||||
let linear_offset = PHYSICAL_MEMORY_OFFSET;
|
|
||||||
//let mut flags = PTF::VALID | PTF::READABLE | PTF::WRITABLE | PTF::EXECUTABLE | PTF::USER;
|
|
||||||
|
|
||||||
map_range(
|
|
||||||
&mut pt,
|
|
||||||
stext as usize,
|
|
||||||
etext as usize - 1,
|
|
||||||
linear_offset,
|
|
||||||
PTF::VALID | PTF::READABLE | PTF::EXECUTABLE,
|
|
||||||
)
|
|
||||||
.unwrap();
|
|
||||||
map_range(
|
|
||||||
&mut pt,
|
|
||||||
srodata as usize,
|
|
||||||
erodata as usize,
|
|
||||||
linear_offset,
|
|
||||||
PTF::VALID | PTF::READABLE,
|
|
||||||
)
|
|
||||||
.unwrap();
|
|
||||||
map_range(
|
|
||||||
&mut pt,
|
|
||||||
sdata as usize,
|
|
||||||
edata as usize,
|
|
||||||
linear_offset,
|
|
||||||
PTF::VALID | PTF::READABLE | PTF::WRITABLE,
|
|
||||||
)
|
|
||||||
.unwrap();
|
|
||||||
|
|
||||||
// Stack
|
|
||||||
map_range(
|
|
||||||
&mut pt,
|
|
||||||
bootstack as usize,
|
|
||||||
bootstacktop as usize - 1,
|
|
||||||
linear_offset,
|
|
||||||
PTF::VALID | PTF::READABLE | PTF::WRITABLE,
|
|
||||||
)
|
|
||||||
.unwrap();
|
|
||||||
|
|
||||||
map_range(
|
|
||||||
&mut pt,
|
|
||||||
sbss as usize,
|
|
||||||
ebss as usize - 1,
|
|
||||||
linear_offset,
|
|
||||||
PTF::VALID | PTF::READABLE | PTF::WRITABLE,
|
|
||||||
)
|
|
||||||
.unwrap();
|
|
||||||
|
|
||||||
info!("map Heap ...");
|
|
||||||
// Heap
|
|
||||||
map_range(
|
|
||||||
&mut pt,
|
|
||||||
end as usize,
|
|
||||||
end as usize + PAGE_SIZE * 5120,
|
|
||||||
linear_offset,
|
|
||||||
PTF::VALID | PTF::READABLE | PTF::WRITABLE,
|
|
||||||
)
|
|
||||||
.unwrap();
|
|
||||||
info!("... Heap");
|
|
||||||
|
|
||||||
// Device Tree
|
|
||||||
#[cfg(feature = "board_qemu")]
|
|
||||||
map_range(
|
|
||||||
&mut pt,
|
|
||||||
dtb,
|
|
||||||
dtb + consts::MAX_DTB_SIZE,
|
|
||||||
linear_offset,
|
|
||||||
PTF::VALID | PTF::READABLE,
|
|
||||||
)
|
|
||||||
.unwrap();
|
|
||||||
|
|
||||||
// PLIC
|
|
||||||
map_range(
|
|
||||||
&mut pt,
|
|
||||||
phys_to_virt(PLIC_PRIORITY),
|
|
||||||
phys_to_virt(PLIC_PRIORITY) + PAGE_SIZE * 0xf,
|
|
||||||
linear_offset,
|
|
||||||
PTF::VALID | PTF::READABLE | PTF::WRITABLE,
|
|
||||||
)
|
|
||||||
.unwrap();
|
|
||||||
map_range(
|
|
||||||
&mut pt,
|
|
||||||
phys_to_virt(PLIC_THRESHOLD),
|
|
||||||
phys_to_virt(PLIC_THRESHOLD) + PAGE_SIZE * 0xf,
|
|
||||||
linear_offset,
|
|
||||||
PTF::VALID | PTF::READABLE | PTF::WRITABLE,
|
|
||||||
)
|
|
||||||
.unwrap();
|
|
||||||
|
|
||||||
// UART0, VIRTIO
|
|
||||||
map_range(
|
|
||||||
&mut pt,
|
|
||||||
phys_to_virt(UART_BASE),
|
|
||||||
phys_to_virt(UART_BASE) + PAGE_SIZE * 0xf,
|
|
||||||
linear_offset,
|
|
||||||
PTF::VALID | PTF::READABLE | PTF::WRITABLE,
|
|
||||||
)
|
|
||||||
.unwrap();
|
|
||||||
|
|
||||||
//写satp
|
|
||||||
let token = root_frame.paddr;
|
|
||||||
unsafe {
|
|
||||||
set_page_table(token);
|
|
||||||
SATP = token;
|
|
||||||
}
|
|
||||||
|
|
||||||
//use core::mem;
|
|
||||||
//mem::forget(pt);
|
|
||||||
|
|
||||||
info!("remap the kernel @ {:#x}", token);
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn map_range(
|
|
||||||
page_table: &mut Rv39PageTable,
|
|
||||||
mut start_addr: VirtAddr,
|
|
||||||
mut end_addr: VirtAddr,
|
|
||||||
linear_offset: usize,
|
|
||||||
flags: PageTableFlags,
|
|
||||||
) -> Result<(), ()> {
|
|
||||||
trace!("Mapping range addr: {:#x} ~ {:#x}", start_addr, end_addr);
|
|
||||||
|
|
||||||
start_addr = start_addr & !(PAGE_SIZE - 1);
|
|
||||||
let mut start_page = start_addr / PAGE_SIZE;
|
|
||||||
|
|
||||||
//end_addr = (end_addr + PAGE_SIZE - 1) & !(PAGE_SIZE -1);
|
|
||||||
//let end_page = (end_addr - 1) / PAGE_SIZE;
|
|
||||||
end_addr = end_addr & !(PAGE_SIZE - 1);
|
|
||||||
let end_page = end_addr / PAGE_SIZE;
|
|
||||||
|
|
||||||
while start_page <= end_page {
|
|
||||||
let vaddr: VirtAddr = start_page * PAGE_SIZE;
|
|
||||||
let page = riscv::addr::Page::of_addr(riscv::addr::VirtAddr::new(vaddr));
|
|
||||||
let frame = riscv::addr::Frame::of_addr(riscv::addr::PhysAddr::new(vaddr - linear_offset));
|
|
||||||
|
|
||||||
start_page += 1;
|
|
||||||
|
|
||||||
trace!(
|
|
||||||
"map_range: {:#x} -> {:#x}, flags={:?}",
|
|
||||||
vaddr,
|
|
||||||
vaddr - linear_offset,
|
|
||||||
flags
|
|
||||||
);
|
|
||||||
page_table
|
|
||||||
.map_to(page, frame, flags, &mut FrameAllocatorImpl)
|
|
||||||
.unwrap()
|
|
||||||
.flush();
|
|
||||||
}
|
|
||||||
info!(
|
|
||||||
"map range from {:#x} to {:#x}, flags: {:?}",
|
|
||||||
start_addr,
|
|
||||||
end_page * PAGE_SIZE,
|
|
||||||
flags
|
|
||||||
);
|
|
||||||
|
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
|
|
||||||
extern "C" {
|
|
||||||
fn start();
|
|
||||||
|
|
||||||
fn stext();
|
|
||||||
fn etext();
|
|
||||||
fn srodata();
|
|
||||||
fn erodata();
|
|
||||||
fn sdata();
|
|
||||||
fn edata();
|
|
||||||
|
|
||||||
fn bootstack();
|
|
||||||
fn bootstacktop();
|
|
||||||
|
|
||||||
fn sbss();
|
|
||||||
fn ebss();
|
|
||||||
|
|
||||||
fn end();
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Page Table
|
|
||||||
#[repr(C)]
|
#[repr(C)]
|
||||||
pub struct PageTableImpl {
|
#[derive(Debug, Copy, Clone)]
|
||||||
root_paddr: PhysAddr,
|
pub struct GraphicInfo {
|
||||||
|
/// Graphic mode
|
||||||
|
//pub mode: ModeInfo,
|
||||||
|
pub mode: u64,
|
||||||
|
/// Framebuffer base physical address
|
||||||
|
pub fb_addr: u64,
|
||||||
|
/// Framebuffer size
|
||||||
|
pub fb_size: u64,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl PageTableImpl {
|
|
||||||
/// Create a new `PageTable`.
|
|
||||||
#[allow(clippy::new_without_default)]
|
|
||||||
#[export_name = "hal_pt_new"]
|
|
||||||
pub fn new() -> Self {
|
|
||||||
let root_frame = Frame::alloc().expect("failed to alloc frame");
|
|
||||||
let root_vaddr = phys_to_virt(root_frame.paddr);
|
|
||||||
let root = unsafe { &mut *(root_vaddr as *mut PageTable) };
|
|
||||||
root.zero();
|
|
||||||
|
|
||||||
let current =
|
|
||||||
phys_to_virt(satp::read().frame().start_address().as_usize()) as *const PageTable;
|
|
||||||
map_kernel(root_vaddr as _, current as _);
|
|
||||||
trace!("create page table @ {:#x}", root_frame.paddr);
|
|
||||||
PageTableImpl {
|
|
||||||
root_paddr: root_frame.paddr,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[cfg(target_arch = "riscv32")]
|
|
||||||
fn get(&mut self) -> Rv32PageTable<'_> {
|
|
||||||
let root_vaddr = phys_to_virt(self.root_paddr);
|
|
||||||
let root = unsafe { &mut *(root_vaddr as *mut PageTable) };
|
|
||||||
Rv32PageTable::new(root, phys_to_virt(0))
|
|
||||||
}
|
|
||||||
|
|
||||||
#[cfg(target_arch = "riscv64")]
|
|
||||||
fn get(&mut self) -> Rv39PageTable<'_> {
|
|
||||||
let root_vaddr = phys_to_virt(self.root_paddr);
|
|
||||||
let root = unsafe { &mut *(root_vaddr as *mut PageTable) };
|
|
||||||
Rv39PageTable::new(root, phys_to_virt(0))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl PageTableTrait for PageTableImpl {
|
|
||||||
/// Map the page of `vaddr` to the frame of `paddr` with `flags`.
|
|
||||||
#[export_name = "hal_pt_map"]
|
|
||||||
fn map(&mut self, vaddr: VirtAddr, paddr: PhysAddr, flags: MMUFlags) -> Result<(), HalError> {
|
|
||||||
let mut pt = self.get();
|
|
||||||
let page = Page::of_addr(riscv::addr::VirtAddr::new(vaddr));
|
|
||||||
let frame = riscv::addr::Frame::of_addr(riscv::addr::PhysAddr::new(paddr));
|
|
||||||
pt.map_to(page, frame, flags.to_ptf(), &mut FrameAllocatorImpl)
|
|
||||||
.unwrap()
|
|
||||||
.flush();
|
|
||||||
|
|
||||||
trace!(
|
|
||||||
"PageTable: {:#X}, map: {:x?} -> {:x?}, flags={:?}",
|
|
||||||
self.table_phys() as usize,
|
|
||||||
vaddr,
|
|
||||||
paddr,
|
|
||||||
flags
|
|
||||||
);
|
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Unmap the page of `vaddr`.
|
|
||||||
#[export_name = "hal_pt_unmap"]
|
|
||||||
fn unmap(&mut self, vaddr: VirtAddr) -> Result<(), HalError> {
|
|
||||||
let mut pt = self.get();
|
|
||||||
let page = Page::of_addr(riscv::addr::VirtAddr::new(vaddr));
|
|
||||||
pt.unmap(page).unwrap().1.flush();
|
|
||||||
trace!(
|
|
||||||
"PageTable: {:#X}, unmap: {:x?}",
|
|
||||||
self.table_phys() as usize,
|
|
||||||
vaddr
|
|
||||||
);
|
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Change the `flags` of the page of `vaddr`.
|
|
||||||
#[export_name = "hal_pt_protect"]
|
|
||||||
fn protect(&mut self, vaddr: VirtAddr, flags: MMUFlags) -> Result<(), HalError> {
|
|
||||||
let mut pt = self.get();
|
|
||||||
let page = Page::of_addr(riscv::addr::VirtAddr::new(vaddr));
|
|
||||||
pt.update_flags(page, flags.to_ptf()).unwrap().flush();
|
|
||||||
|
|
||||||
trace!(
|
|
||||||
"PageTable: {:#X}, protect: {:x?}, flags={:?}",
|
|
||||||
self.table_phys() as usize,
|
|
||||||
vaddr,
|
|
||||||
flags
|
|
||||||
);
|
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Query the physical address which the page of `vaddr` maps to.
|
|
||||||
#[export_name = "hal_pt_query"]
|
|
||||||
fn query(&mut self, vaddr: VirtAddr) -> Result<PhysAddr, HalError> {
|
|
||||||
let mut pt = self.get();
|
|
||||||
let page = Page::of_addr(riscv::addr::VirtAddr::new(vaddr));
|
|
||||||
let res = pt.ref_entry(page);
|
|
||||||
trace!("query: {:x?} => {:#x?}", vaddr, res);
|
|
||||||
match res {
|
|
||||||
Ok(entry) => Ok(entry.addr().as_usize()),
|
|
||||||
Err(_) => Err(HalError),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Get the physical address of root page table.
|
|
||||||
#[export_name = "hal_pt_table_phys"]
|
|
||||||
fn table_phys(&self) -> PhysAddr {
|
|
||||||
self.root_paddr
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Activate this page table
|
|
||||||
#[export_name = "hal_pt_activate"]
|
|
||||||
fn activate(&self) {
|
|
||||||
let now_token = satp::read().bits();
|
|
||||||
let new_token = self.table_phys();
|
|
||||||
if now_token != new_token {
|
|
||||||
debug!("switch table {:x?} -> {:x?}", now_token, new_token);
|
|
||||||
unsafe {
|
|
||||||
set_page_table(new_token);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub unsafe fn set_page_table(vmtoken: usize) {
|
|
||||||
#[cfg(target_arch = "riscv32")]
|
|
||||||
let mode = satp::Mode::Sv32;
|
|
||||||
#[cfg(target_arch = "riscv64")]
|
|
||||||
let mode = satp::Mode::Sv39;
|
|
||||||
debug!("set user table: {:#x?}", vmtoken);
|
|
||||||
satp::set(mode, 0, vmtoken >> 12);
|
|
||||||
//刷TLB好像很重要
|
|
||||||
sfence_vma_all();
|
|
||||||
}
|
|
||||||
|
|
||||||
trait FlagsExt {
|
|
||||||
fn to_ptf(self) -> PTF;
|
|
||||||
}
|
|
||||||
|
|
||||||
impl FlagsExt for MMUFlags {
|
|
||||||
fn to_ptf(self) -> PTF {
|
|
||||||
let mut flags = PTF::VALID;
|
|
||||||
if self.contains(MMUFlags::READ) {
|
|
||||||
flags |= PTF::READABLE;
|
|
||||||
}
|
|
||||||
if self.contains(MMUFlags::WRITE) {
|
|
||||||
flags |= PTF::WRITABLE;
|
|
||||||
}
|
|
||||||
if self.contains(MMUFlags::EXECUTE) {
|
|
||||||
flags |= PTF::EXECUTABLE;
|
|
||||||
}
|
|
||||||
if self.contains(MMUFlags::USER) {
|
|
||||||
flags |= PTF::USER;
|
|
||||||
}
|
|
||||||
flags
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
struct FrameAllocatorImpl;
|
|
||||||
|
|
||||||
impl FrameAllocator for FrameAllocatorImpl {
|
|
||||||
fn alloc(&mut self) -> Option<riscv::addr::Frame> {
|
|
||||||
Frame::alloc().map(|f| {
|
|
||||||
let paddr = riscv::addr::PhysAddr::new(f.paddr);
|
|
||||||
riscv::addr::Frame::of_addr(paddr)
|
|
||||||
})
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl FrameDeallocator for FrameAllocatorImpl {
|
|
||||||
fn dealloc(&mut self, frame: riscv::addr::Frame) {
|
|
||||||
Frame {
|
|
||||||
paddr: frame.start_address().as_usize(),
|
|
||||||
}
|
|
||||||
.dealloc()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
lazy_static! {
|
|
||||||
static ref STDIN: Mutex<VecDeque<u8>> = Mutex::new(VecDeque::new());
|
|
||||||
static ref STDIN_CALLBACK: Mutex<Vec<Box<dyn Fn() -> bool + Send + Sync>>> =
|
|
||||||
Mutex::new(Vec::new());
|
|
||||||
}
|
|
||||||
|
|
||||||
//调用这里
|
|
||||||
/// Put a char by serial interrupt handler.
|
|
||||||
fn serial_put(mut x: u8) {
|
|
||||||
if (x == b'\r') || (x == b'\n') {
|
|
||||||
STDIN.lock().push_back(b'\n');
|
|
||||||
STDIN.lock().push_back(b'\r');
|
|
||||||
}else{
|
|
||||||
STDIN.lock().push_back(x);
|
|
||||||
}
|
|
||||||
STDIN_CALLBACK.lock().retain(|f| !f());
|
|
||||||
}
|
|
||||||
|
|
||||||
#[export_name = "hal_serial_set_callback"]
|
|
||||||
pub fn serial_set_callback(callback: Box<dyn Fn() -> bool + Send + Sync>) {
|
|
||||||
STDIN_CALLBACK.lock().push(callback);
|
|
||||||
}
|
|
||||||
|
|
||||||
#[export_name = "hal_serial_read"]
|
|
||||||
pub fn serial_read(buf: &mut [u8]) -> usize {
|
|
||||||
let mut stdin = STDIN.lock();
|
|
||||||
let len = stdin.len().min(buf.len());
|
|
||||||
for c in &mut buf[..len] {
|
|
||||||
*c = stdin.pop_front().unwrap();
|
|
||||||
}
|
|
||||||
len
|
|
||||||
}
|
|
||||||
|
|
||||||
#[export_name = "hal_serial_write"]
|
|
||||||
pub fn print_str(s: &str) {
|
|
||||||
//putfmt(format_args!("{}", s));
|
|
||||||
putfmt_uart(format_args!("{}", s));
|
|
||||||
}
|
|
||||||
|
|
||||||
// Get TSC frequency.
|
|
||||||
fn tsc_frequency() -> u16 {
|
|
||||||
const DEFAULT: u16 = 2600;
|
|
||||||
|
|
||||||
// FIXME: QEMU, AMD, VirtualBox
|
|
||||||
DEFAULT
|
|
||||||
}
|
|
||||||
|
|
||||||
#[export_name = "hal_apic_local_id"]
|
|
||||||
pub fn apic_local_id() -> u8 {
|
|
||||||
let lapic = 0;
|
|
||||||
lapic as u8
|
|
||||||
}
|
|
||||||
|
|
||||||
////////////
|
|
||||||
|
|
||||||
pub fn getchar_option() -> Option<u8> {
|
|
||||||
let c = sbi::console_getchar() as isize;
|
|
||||||
match c {
|
|
||||||
-1 => None,
|
|
||||||
c => Some(c as u8),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
////////////
|
|
||||||
|
|
||||||
pub fn putchar(ch: char) {
|
|
||||||
sbi::console_putchar(ch as u8 as usize);
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn puts(s: &str) {
|
|
||||||
for ch in s.chars() {
|
|
||||||
putchar(ch);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
struct Stdout;
|
|
||||||
|
|
||||||
impl fmt::Write for Stdout {
|
|
||||||
fn write_str(&mut self, s: &str) -> fmt::Result {
|
|
||||||
puts(s);
|
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn putfmt(fmt: fmt::Arguments) {
|
|
||||||
Stdout.write_fmt(fmt).unwrap();
|
|
||||||
}
|
|
||||||
////////////
|
|
||||||
|
|
||||||
struct Stdout1;
|
|
||||||
impl fmt::Write for Stdout1 {
|
|
||||||
fn write_str(&mut self, s: &str) -> fmt::Result {
|
|
||||||
//每次都创建一个新的Uart ? 内存位置始终相同
|
|
||||||
write!(
|
|
||||||
uart::Uart::new(phys_to_virt(UART_BASE)),
|
|
||||||
"{}", s
|
|
||||||
).unwrap();
|
|
||||||
|
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
}
|
|
||||||
pub fn putfmt_uart(fmt: fmt::Arguments) {
|
|
||||||
Stdout1.write_fmt(fmt).unwrap();
|
|
||||||
}
|
|
||||||
|
|
||||||
////////////
|
|
||||||
|
|
||||||
#[macro_export]
|
|
||||||
macro_rules! bare_print {
|
|
||||||
($($arg:tt)*) => ({
|
|
||||||
putfmt(format_args!($($arg)*));
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
#[macro_export]
|
|
||||||
macro_rules! bare_println {
|
|
||||||
() => (bare_print!("\n"));
|
|
||||||
($($arg:tt)*) => (bare_print!("{}\n", format_args!($($arg)*)));
|
|
||||||
}
|
|
||||||
|
|
||||||
fn get_cycle() -> u64 {
|
|
||||||
time::read() as u64
|
|
||||||
/*
|
|
||||||
unsafe {
|
|
||||||
MMIO_MTIME.read_volatile()
|
|
||||||
}
|
|
||||||
*/
|
|
||||||
}
|
|
||||||
|
|
||||||
#[export_name = "hal_timer_now"]
|
|
||||||
pub fn timer_now() -> Duration {
|
|
||||||
const FREQUENCY: u64 = 10_000_000; // ???
|
|
||||||
let time = get_cycle();
|
|
||||||
//bare_println!("timer_now(): {:?}", time);
|
|
||||||
Duration::from_nanos(time * 1_000_000_000 / FREQUENCY as u64)
|
|
||||||
}
|
|
||||||
|
|
||||||
#[export_name = "hal_timer_set_next"]
|
|
||||||
fn timer_set_next() {
|
|
||||||
//let TIMEBASE: u64 = 100000;
|
|
||||||
let TIMEBASE: u64 = 10_000_000;
|
|
||||||
sbi::set_timer(get_cycle() + TIMEBASE);
|
|
||||||
}
|
|
||||||
|
|
||||||
fn timer_init() {
|
|
||||||
unsafe {
|
|
||||||
sie::set_stimer();
|
|
||||||
}
|
|
||||||
timer_set_next();
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn init(config: Config) {
|
|
||||||
interrupt::init();
|
|
||||||
timer_init();
|
|
||||||
|
|
||||||
/*
|
|
||||||
interrupt::init_soft();
|
|
||||||
sbi::send_ipi(0);
|
|
||||||
*/
|
|
||||||
|
|
||||||
unsafe {
|
|
||||||
llvm_asm!("ebreak"::::"volatile");
|
|
||||||
}
|
|
||||||
|
|
||||||
#[cfg(feature = "board_qemu")]
|
|
||||||
{
|
|
||||||
bare_println!("Setup virtio @devicetree {:#x}", config.dtb);
|
|
||||||
drivers::virtio::device_tree::init(config.dtb);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub struct Config {
|
|
||||||
pub mconfig: u64,
|
|
||||||
pub dtb: usize,
|
|
||||||
}
|
|
||||||
|
|
||||||
#[export_name = "fetch_fault_vaddr"]
|
|
||||||
pub fn fetch_fault_vaddr() -> VirtAddr {
|
|
||||||
stval::read() as _
|
|
||||||
}
|
|
||||||
|
|
||||||
static mut CONFIG: Config = Config { mconfig: 0, dtb: 0 };
|
|
||||||
|
|
||||||
/// This structure represents the information that the bootloader passes to the kernel.
|
/// This structure represents the information that the bootloader passes to the kernel.
|
||||||
#[repr(C)]
|
#[repr(C)]
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
|
@ -588,55 +57,28 @@ pub struct BootInfo {
|
||||||
pub cmdline: &'static str,
|
pub cmdline: &'static str,
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Graphic output information
|
pub struct HalConfig {
|
||||||
#[derive(Debug, Copy, Clone)]
|
pub mconfig: u64,
|
||||||
#[repr(C)]
|
pub dtb: usize,
|
||||||
pub struct GraphicInfo {
|
|
||||||
/// Graphic mode
|
|
||||||
//pub mode: ModeInfo,
|
|
||||||
pub mode: u64,
|
|
||||||
/// Framebuffer base physical address
|
|
||||||
pub fb_addr: u64,
|
|
||||||
/// Framebuffer size
|
|
||||||
pub fb_size: u64,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub mod interrupt;
|
pub fn init(config: HalConfig) {
|
||||||
mod plic;
|
trace!("hal dtb: {:#x}", config.dtb);
|
||||||
mod uart;
|
|
||||||
|
|
||||||
#[export_name = "hal_current_pgtable"]
|
interrupt::init();
|
||||||
pub fn current_page_table() -> usize {
|
timer::init();
|
||||||
#[cfg(target_arch = "riscv32")]
|
|
||||||
let mode = satp::Mode::Sv32;
|
|
||||||
#[cfg(target_arch = "riscv64")]
|
|
||||||
let mode = satp::Mode::Sv39;
|
|
||||||
satp::read().ppn() << 12
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn init_framebuffer(width: u32, height: u32, addr: usize, size: usize) {
|
/*
|
||||||
let fb_info = FramebufferInfo {
|
interrupt::init_soft();
|
||||||
xres: width,
|
sbi::send_ipi(0);
|
||||||
yres: height,
|
*/
|
||||||
xres_virtual: width,
|
|
||||||
yres_virtual: height,
|
|
||||||
xoffset: 0,
|
|
||||||
yoffset: 0,
|
|
||||||
depth: ColorDepth::ColorDepth32,
|
|
||||||
format: ColorFormat::RGBA8888,
|
|
||||||
paddr: virt_to_phys(addr),
|
|
||||||
vaddr: addr,
|
|
||||||
screen_size: size,
|
|
||||||
};
|
|
||||||
*FRAME_BUFFER.write() = Some(fb_info);
|
|
||||||
}
|
|
||||||
|
|
||||||
#[export_name = "hal_mouse_set_callback"]
|
unsafe { asm!("ebreak") };
|
||||||
pub fn mouse_set_callback(_callback: Box<dyn Fn([u8; 3]) + Send + Sync>) {
|
|
||||||
//
|
|
||||||
}
|
|
||||||
|
|
||||||
#[export_name = "hal_kbd_set_callback"]
|
#[cfg(feature = "board_qemu")]
|
||||||
pub fn kbd_set_callback(_callback: Box<dyn Fn(u16, i32) + Send + Sync>) {
|
{
|
||||||
//
|
// TODO
|
||||||
|
// sbi_println!("Setup virtio @devicetree {:#x}", config.dtb);
|
||||||
|
// drivers::virtio::device_tree::init(config.dtb);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,6 +1,4 @@
|
||||||
use super::interrupt;
|
use super::super::mem::phys_to_virt;
|
||||||
use super::uart;
|
|
||||||
use crate::{putfmt, phys_to_virt};
|
|
||||||
use super::consts::*;
|
use super::consts::*;
|
||||||
|
|
||||||
//通过MMIO地址对平台级中断控制器PLIC的寄存器进行设置
|
//通过MMIO地址对平台级中断控制器PLIC的寄存器进行设置
|
||||||
|
@ -10,7 +8,7 @@ use super::consts::*;
|
||||||
//声明claim会清除中断源上的相应pending位。
|
//声明claim会清除中断源上的相应pending位。
|
||||||
//即使mip寄存器的MEIP位没有置位, 也可以claim; 声明不被阀值寄存器的设置影响;
|
//即使mip寄存器的MEIP位没有置位, 也可以claim; 声明不被阀值寄存器的设置影响;
|
||||||
//获取按优先级排序后的下一个可用的中断ID
|
//获取按优先级排序后的下一个可用的中断ID
|
||||||
pub fn next() -> Option<u32> {
|
fn next() -> Option<u32> {
|
||||||
let claim_reg = phys_to_virt(PLIC_CLAIM) as *const u32;
|
let claim_reg = phys_to_virt(PLIC_CLAIM) as *const u32;
|
||||||
let claim_no;
|
let claim_no;
|
||||||
unsafe {
|
unsafe {
|
||||||
|
@ -26,7 +24,7 @@ pub fn next() -> Option<u32> {
|
||||||
//claim时,PLIC不再从该相同设备监听中断
|
//claim时,PLIC不再从该相同设备监听中断
|
||||||
//写claim寄存器,告诉PLIC处理完成该中断
|
//写claim寄存器,告诉PLIC处理完成该中断
|
||||||
// id 应该来源于next()函数
|
// id 应该来源于next()函数
|
||||||
pub fn complete(id: u32) {
|
fn complete(id: u32) {
|
||||||
let complete_reg = phys_to_virt(PLIC_CLAIM) as *mut u32; //和claim相同寄存器,只是读或写的区别
|
let complete_reg = phys_to_virt(PLIC_CLAIM) as *mut u32; //和claim相同寄存器,只是读或写的区别
|
||||||
unsafe {
|
unsafe {
|
||||||
complete_reg.write_volatile(id);
|
complete_reg.write_volatile(id);
|
||||||
|
@ -46,7 +44,7 @@ pub fn is_pending(id: u32) -> bool {
|
||||||
|
|
||||||
//使能target中某个给定ID的中断
|
//使能target中某个给定ID的中断
|
||||||
//中断ID可查找qemu/include/hw/riscv/virt.h, 如:UART0_IRQ = 10
|
//中断ID可查找qemu/include/hw/riscv/virt.h, 如:UART0_IRQ = 10
|
||||||
pub fn enable(id: u32) {
|
fn enable(id: u32) {
|
||||||
let enables = phys_to_virt(PLIC_INT_ENABLE) as *mut u32; //32位的寄存器
|
let enables = phys_to_virt(PLIC_INT_ENABLE) as *mut u32; //32位的寄存器
|
||||||
let actual_id = 1 << id;
|
let actual_id = 1 << id;
|
||||||
unsafe {
|
unsafe {
|
||||||
|
@ -56,7 +54,7 @@ pub fn enable(id: u32) {
|
||||||
}
|
}
|
||||||
|
|
||||||
//设置中断源的优先级,分0~7级,7是最高级, eg:这里id=10, 表示第10个中断源的设置, prio=1
|
//设置中断源的优先级,分0~7级,7是最高级, eg:这里id=10, 表示第10个中断源的设置, prio=1
|
||||||
pub fn set_priority(id: u32, prio: u8) {
|
fn set_priority(id: u32, prio: u8) {
|
||||||
let actual_prio = prio as u32 & 7;
|
let actual_prio = prio as u32 & 7;
|
||||||
let prio_reg = phys_to_virt(PLIC_PRIORITY) as *mut u32;
|
let prio_reg = phys_to_virt(PLIC_PRIORITY) as *mut u32;
|
||||||
unsafe {
|
unsafe {
|
||||||
|
@ -65,7 +63,7 @@ pub fn set_priority(id: u32, prio: u8) {
|
||||||
}
|
}
|
||||||
|
|
||||||
//设置中断target的全局阀值[0..7], <= threshold会被屏蔽
|
//设置中断target的全局阀值[0..7], <= threshold会被屏蔽
|
||||||
pub fn set_threshold(tsh: u8) {
|
fn set_threshold(tsh: u8) {
|
||||||
let actual_tsh = tsh & 7; //使用0b111保留最后三位
|
let actual_tsh = tsh & 7; //使用0b111保留最后三位
|
||||||
let tsh_reg = phys_to_virt(PLIC_THRESHOLD) as *mut u32;
|
let tsh_reg = phys_to_virt(PLIC_THRESHOLD) as *mut u32;
|
||||||
unsafe {
|
unsafe {
|
||||||
|
@ -73,22 +71,30 @@ pub fn set_threshold(tsh: u8) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn handle_interrupt() {
|
pub(super) fn init() {
|
||||||
|
// Qemu virt UART0 = 10
|
||||||
|
// ALLWINNER D1 UART0 = 18
|
||||||
|
set_priority(UART0_INT_NUM, 7);
|
||||||
|
set_threshold(0);
|
||||||
|
enable(UART0_INT_NUM);
|
||||||
|
}
|
||||||
|
|
||||||
|
pub(super) fn handle_interrupt() {
|
||||||
if let Some(interrupt) = next() {
|
if let Some(interrupt) = next() {
|
||||||
match interrupt {
|
match interrupt {
|
||||||
1..=8 => {
|
1..=8 => {
|
||||||
//virtio::handle_interrupt(interrupt);
|
//virtio::handle_interrupt(interrupt);
|
||||||
bare_println!("plic virtio external interrupt: {}", interrupt);
|
sbi_println!("plic virtio external interrupt: {}", interrupt);
|
||||||
}
|
}
|
||||||
UART0_INT_NUM => {
|
UART0_INT_NUM => {
|
||||||
//UART中断ID是10
|
//UART中断ID是10
|
||||||
uart::handle_interrupt();
|
super::uart::handle_interrupt();
|
||||||
|
|
||||||
//换用sbi的方式获取字符
|
//换用sbi的方式获取字符
|
||||||
//interrupt::try_process_serial();
|
//interrupt::try_process_serial();
|
||||||
}
|
}
|
||||||
_ => {
|
_ => {
|
||||||
bare_println!("Unknown external interrupt: {}", interrupt);
|
sbi_println!("Unknown external interrupt: {}", interrupt);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
//这将复位pending的中断,允许UART再次中断。
|
//这将复位pending的中断,允许UART再次中断。
|
||||||
|
|
|
@ -1,3 +1,28 @@
|
||||||
|
const SBI_SET_TIMER: usize = 0;
|
||||||
|
const SBI_CONSOLE_PUTCHAR: usize = 1;
|
||||||
|
const SBI_CONSOLE_GETCHAR: usize = 2;
|
||||||
|
const SBI_CLEAR_IPI: usize = 3;
|
||||||
|
const SBI_SEND_IPI: usize = 4;
|
||||||
|
const SBI_REMOTE_FENCE_I: usize = 5;
|
||||||
|
const SBI_REMOTE_SFENCE_VMA: usize = 6;
|
||||||
|
const SBI_REMOTE_SFENCE_VMA_ASID: usize = 7;
|
||||||
|
const SBI_SHUTDOWN: usize = 8;
|
||||||
|
|
||||||
|
#[inline(always)]
|
||||||
|
fn sbi_call(which: usize, arg0: usize, arg1: usize, arg2: usize) -> usize {
|
||||||
|
let ret;
|
||||||
|
unsafe {
|
||||||
|
asm!("ecall",
|
||||||
|
in("a0") arg0,
|
||||||
|
in("a1") arg1,
|
||||||
|
in("a2") arg2,
|
||||||
|
in("a7") which,
|
||||||
|
lateout("a0") ret,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
ret
|
||||||
|
}
|
||||||
|
|
||||||
pub fn console_putchar(ch: usize) {
|
pub fn console_putchar(ch: usize) {
|
||||||
sbi_call(SBI_CONSOLE_PUTCHAR, ch, 0, 0);
|
sbi_call(SBI_CONSOLE_PUTCHAR, ch, 0, 0);
|
||||||
}
|
}
|
||||||
|
@ -6,18 +31,6 @@ pub fn console_getchar() -> usize {
|
||||||
return sbi_call(SBI_CONSOLE_GETCHAR, 0, 0, 0);
|
return sbi_call(SBI_CONSOLE_GETCHAR, 0, 0, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
fn sbi_call(which: usize, arg0: usize, arg1: usize, arg2: usize) -> usize {
|
|
||||||
let ret: usize;
|
|
||||||
unsafe {
|
|
||||||
llvm_asm!("ecall"
|
|
||||||
:"={x10}"(ret)
|
|
||||||
:"{x10}"(arg0), "{x11}"(arg1), "{x12}"(arg2), "{x17}"(which)
|
|
||||||
:"memory"
|
|
||||||
:"volatile");
|
|
||||||
}
|
|
||||||
ret
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn set_timer(stime_value: u64) {
|
pub fn set_timer(stime_value: u64) {
|
||||||
#[cfg(target_pointer_width = "32")]
|
#[cfg(target_pointer_width = "32")]
|
||||||
sbi_call(SBI_SET_TIMER, stime_value as usize, (stime_value >> 32), 0);
|
sbi_call(SBI_SET_TIMER, stime_value as usize, (stime_value >> 32), 0);
|
||||||
|
@ -33,13 +46,3 @@ pub fn clear_ipi() {
|
||||||
pub fn send_ipi(sipi_value: usize) {
|
pub fn send_ipi(sipi_value: usize) {
|
||||||
sbi_call(SBI_SEND_IPI, sipi_value, 0, 0);
|
sbi_call(SBI_SEND_IPI, sipi_value, 0, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
const SBI_SET_TIMER: usize = 0;
|
|
||||||
const SBI_CONSOLE_PUTCHAR: usize = 1;
|
|
||||||
const SBI_CONSOLE_GETCHAR: usize = 2;
|
|
||||||
const SBI_CLEAR_IPI: usize = 3;
|
|
||||||
const SBI_SEND_IPI: usize = 4;
|
|
||||||
const SBI_REMOTE_FENCE_I: usize = 5;
|
|
||||||
const SBI_REMOTE_SFENCE_VMA: usize = 6;
|
|
||||||
const SBI_REMOTE_SFENCE_VMA_ASID: usize = 7;
|
|
||||||
const SBI_SHUTDOWN: usize = 8;
|
|
||||||
|
|
|
@ -0,0 +1,85 @@
|
||||||
|
use alloc::{boxed::Box, collections::VecDeque, vec::Vec};
|
||||||
|
use core::fmt::{Arguments, Result, Write};
|
||||||
|
|
||||||
|
use spin::Mutex;
|
||||||
|
|
||||||
|
use super::{sbi, uart};
|
||||||
|
|
||||||
|
lazy_static::lazy_static! {
|
||||||
|
static ref STDIN: Mutex<VecDeque<u8>> = Mutex::new(VecDeque::new());
|
||||||
|
static ref STDIN_CALLBACK: Mutex<Vec<Box<dyn Fn() -> bool + Send + Sync>>> =
|
||||||
|
Mutex::new(Vec::new());
|
||||||
|
}
|
||||||
|
|
||||||
|
struct SbiConsole;
|
||||||
|
struct UartConsole;
|
||||||
|
|
||||||
|
impl Write for SbiConsole {
|
||||||
|
fn write_str(&mut self, s: &str) -> Result {
|
||||||
|
for ch in s.chars() {
|
||||||
|
sbi::console_putchar(ch as u8 as usize);
|
||||||
|
}
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Write for UartConsole {
|
||||||
|
fn write_str(&mut self, s: &str) -> Result {
|
||||||
|
if let Some(ref mut uart) = uart::UART.lock().get_mut() {
|
||||||
|
//每次都创建一个新的Uart ? 内存位置始终相同
|
||||||
|
write!(uart, "{}", s)
|
||||||
|
} else {
|
||||||
|
SbiConsole.write_str(s)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub(super) fn sbi_print_fmt(fmt: Arguments) {
|
||||||
|
SbiConsole.write_fmt(fmt).unwrap();
|
||||||
|
}
|
||||||
|
|
||||||
|
pub(super) fn uart_print_fmt(fmt: Arguments) {
|
||||||
|
UartConsole.write_fmt(fmt).unwrap();
|
||||||
|
}
|
||||||
|
|
||||||
|
hal_fn_impl! {
|
||||||
|
impl mod crate::defs::serial {
|
||||||
|
fn serial_put(x: u8) {
|
||||||
|
if (x == b'\r') || (x == b'\n') {
|
||||||
|
STDIN.lock().push_back(b'\n');
|
||||||
|
STDIN.lock().push_back(b'\r');
|
||||||
|
}else{
|
||||||
|
STDIN.lock().push_back(x);
|
||||||
|
}
|
||||||
|
STDIN_CALLBACK.lock().retain(|f| !f());
|
||||||
|
}
|
||||||
|
|
||||||
|
fn serial_set_callback(callback: Box<dyn Fn() -> bool + Send + Sync>) {
|
||||||
|
STDIN_CALLBACK.lock().push(callback);
|
||||||
|
}
|
||||||
|
|
||||||
|
fn serial_read(buf: &mut [u8]) -> usize {
|
||||||
|
let mut stdin = STDIN.lock();
|
||||||
|
let len = stdin.len().min(buf.len());
|
||||||
|
for c in &mut buf[..len] {
|
||||||
|
*c = stdin.pop_front().unwrap();
|
||||||
|
}
|
||||||
|
len
|
||||||
|
}
|
||||||
|
|
||||||
|
fn serial_write_fmt(fmt: Arguments) {
|
||||||
|
uart_print_fmt(fmt);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
macro_rules! sbi_print {
|
||||||
|
($($arg:tt)*) => ({
|
||||||
|
crate::serial::sbi_print_fmt(format_args!($($arg)*));
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
macro_rules! sbi_println {
|
||||||
|
() => (sbi_print!("\n"));
|
||||||
|
($($arg:tt)*) => (sbi_print!("{}\n", format_args!($($arg)*)));
|
||||||
|
}
|
|
@ -0,0 +1,11 @@
|
||||||
|
pub fn wait_for_interrupt() {
|
||||||
|
unsafe {
|
||||||
|
// enable interrupt and disable
|
||||||
|
let sie = riscv::register::sstatus::read().sie();
|
||||||
|
riscv::register::sstatus::set_sie();
|
||||||
|
riscv::asm::wfi();
|
||||||
|
if !sie {
|
||||||
|
riscv::register::sstatus::clear_sie();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,29 @@
|
||||||
|
use core::time::Duration;
|
||||||
|
use riscv::register::{sie, time};
|
||||||
|
|
||||||
|
fn get_cycle() -> u64 {
|
||||||
|
time::read() as u64
|
||||||
|
/*
|
||||||
|
unsafe {
|
||||||
|
MMIO_MTIME.read_volatile()
|
||||||
|
}
|
||||||
|
*/
|
||||||
|
}
|
||||||
|
|
||||||
|
pub(super) fn timer_set_next() {
|
||||||
|
//let TIMEBASE: u64 = 100000;
|
||||||
|
const TIMEBASE: u64 = 10_000_000;
|
||||||
|
super::sbi::set_timer(get_cycle() + TIMEBASE);
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn timer_now() -> Duration {
|
||||||
|
const FREQUENCY: u64 = 10_000_000; // ???
|
||||||
|
let time = get_cycle();
|
||||||
|
//bare_println!("timer_now(): {:?}", time);
|
||||||
|
Duration::from_nanos(time * 1_000_000_000 / FREQUENCY as u64)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub(super) fn init() {
|
||||||
|
unsafe { sie::set_stimer() };
|
||||||
|
timer_set_next();
|
||||||
|
}
|
|
@ -0,0 +1,119 @@
|
||||||
|
use riscv::register::scause::{self, Exception, Interrupt, Trap};
|
||||||
|
use riscv::register::{satp, stval};
|
||||||
|
use trapframe::TrapFrame;
|
||||||
|
|
||||||
|
use super::{consts, plic, sbi};
|
||||||
|
|
||||||
|
fn breakpoint(sepc: &mut usize) {
|
||||||
|
sbi_println!("Exception::Breakpoint: A breakpoint set @0x{:x} ", sepc);
|
||||||
|
|
||||||
|
//sepc为触发中断指令ebreak的地址
|
||||||
|
//防止无限循环中断,让sret返回时跳转到sepc的下一条指令地址
|
||||||
|
*sepc += 2
|
||||||
|
}
|
||||||
|
|
||||||
|
pub(super) fn super_timer() {
|
||||||
|
super::timer::timer_set_next();
|
||||||
|
crate::timer::timer_tick();
|
||||||
|
|
||||||
|
//sbi_print!(".");
|
||||||
|
|
||||||
|
//发生外界中断时,epc的指令还没有执行,故无需修改epc到下一条
|
||||||
|
}
|
||||||
|
|
||||||
|
fn super_soft() {
|
||||||
|
sbi::clear_ipi();
|
||||||
|
sbi_println!("Interrupt::SupervisorSoft!");
|
||||||
|
}
|
||||||
|
|
||||||
|
fn page_fault(stval: usize, tf: &mut TrapFrame) {
|
||||||
|
let this_scause = scause::read();
|
||||||
|
info!(
|
||||||
|
"EXCEPTION Page Fault: {:?} @ {:#x}->{:#x}",
|
||||||
|
this_scause.cause(),
|
||||||
|
tf.sepc,
|
||||||
|
stval
|
||||||
|
);
|
||||||
|
let vaddr = stval;
|
||||||
|
|
||||||
|
use crate::vm::{PageTable, PageTableTrait};
|
||||||
|
use crate::MMUFlags;
|
||||||
|
use riscv::addr::{Page, VirtAddr};
|
||||||
|
use riscv::paging::{Mapper, PageTableEntry as PTE};
|
||||||
|
|
||||||
|
//let mut flags = PTF::VALID;
|
||||||
|
let code = this_scause.code();
|
||||||
|
let flags = if code == 15 {
|
||||||
|
//MMUFlags::WRITE ???
|
||||||
|
MMUFlags::READ | MMUFlags::WRITE
|
||||||
|
} else if code == 12 {
|
||||||
|
MMUFlags::EXECUTE
|
||||||
|
} else {
|
||||||
|
MMUFlags::READ
|
||||||
|
};
|
||||||
|
|
||||||
|
let linear_offset = if stval >= consts::PHYSICAL_MEMORY_OFFSET {
|
||||||
|
// Kernel
|
||||||
|
consts::PHYSICAL_MEMORY_OFFSET
|
||||||
|
} else {
|
||||||
|
// User
|
||||||
|
0
|
||||||
|
};
|
||||||
|
|
||||||
|
/*
|
||||||
|
let current =
|
||||||
|
unsafe { &mut *(phys_to_virt(satp::read().frame().start_address().as_usize()) as *mut PageTable) };
|
||||||
|
let mut pt = Rv39PageTable::new(current, PHYSICAL_MEMORY_OFFSET);
|
||||||
|
map_range(&mut pt, vaddr, vaddr, linear_offset, flags);
|
||||||
|
*/
|
||||||
|
|
||||||
|
let mut pti = PageTable {
|
||||||
|
root_paddr: satp::read().frame().start_address().as_usize(),
|
||||||
|
};
|
||||||
|
|
||||||
|
let page = Page::of_addr(VirtAddr::new(vaddr));
|
||||||
|
if let Ok(pte) = pti.get().ref_entry(page) {
|
||||||
|
let pte = unsafe { &mut *(pte as *mut PTE) };
|
||||||
|
if !pte.is_unused() {
|
||||||
|
debug!(
|
||||||
|
"PageAlreadyMapped -> {:#x?}, {:?}",
|
||||||
|
pte.addr().as_usize(),
|
||||||
|
pte.flags()
|
||||||
|
);
|
||||||
|
//TODO update flags
|
||||||
|
|
||||||
|
pti.unmap(vaddr).unwrap();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
pti.map(vaddr, vaddr - linear_offset, flags).unwrap();
|
||||||
|
}
|
||||||
|
|
||||||
|
#[no_mangle]
|
||||||
|
pub extern "C" fn trap_handler(tf: &mut TrapFrame) {
|
||||||
|
let sepc = tf.sepc;
|
||||||
|
let scause = scause::read();
|
||||||
|
let stval = stval::read();
|
||||||
|
let is_int = scause.bits() >> 63;
|
||||||
|
let code = scause.bits() & !(1 << 63);
|
||||||
|
|
||||||
|
match scause.cause() {
|
||||||
|
Trap::Exception(Exception::Breakpoint) => breakpoint(&mut tf.sepc),
|
||||||
|
Trap::Exception(Exception::IllegalInstruction) => {
|
||||||
|
panic!("IllegalInstruction: {:#x}->{:#x}", sepc, stval)
|
||||||
|
}
|
||||||
|
Trap::Exception(Exception::LoadFault) => {
|
||||||
|
panic!("Load access fault: {:#x}->{:#x}", sepc, stval)
|
||||||
|
}
|
||||||
|
Trap::Exception(Exception::StoreFault) => {
|
||||||
|
panic!("Store access fault: {:#x}->{:#x}", sepc, stval)
|
||||||
|
}
|
||||||
|
Trap::Exception(Exception::LoadPageFault) => page_fault(stval, tf),
|
||||||
|
Trap::Exception(Exception::StorePageFault) => page_fault(stval, tf),
|
||||||
|
Trap::Exception(Exception::InstructionPageFault) => page_fault(stval, tf),
|
||||||
|
Trap::Interrupt(Interrupt::SupervisorTimer) => super_timer(),
|
||||||
|
Trap::Interrupt(Interrupt::SupervisorSoft) => super_soft(),
|
||||||
|
Trap::Interrupt(Interrupt::SupervisorExternal) => plic::handle_interrupt(),
|
||||||
|
//Trap::Interrupt(Interrupt::SupervisorExternal) => irq_handle(code as u8),
|
||||||
|
_ => panic!("Undefined Trap: {:#x} {:#x}", is_int, code),
|
||||||
|
}
|
||||||
|
}
|
|
@ -1,15 +1,18 @@
|
||||||
use super::consts::UART_BASE;
|
|
||||||
use crate::{putfmt, phys_to_virt};
|
|
||||||
use core::convert::TryInto;
|
|
||||||
use core::fmt::{Error, Write};
|
use core::fmt::{Error, Write};
|
||||||
|
use spin::{Mutex, Once};
|
||||||
|
|
||||||
pub struct Uart {
|
use super::super::mem::phys_to_virt;
|
||||||
base_address: usize,
|
use crate::{PhysAddr, VirtAddr};
|
||||||
|
|
||||||
|
pub(super) struct Uart {
|
||||||
|
base_address: VirtAddr,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub(super) static UART: Mutex<Once<Uart>> = Mutex::new(Once::new());
|
||||||
|
|
||||||
// 结构体Uart的实现块
|
// 结构体Uart的实现块
|
||||||
impl Uart {
|
impl Uart {
|
||||||
pub fn new(base_address: usize) -> Self {
|
pub fn new(base_address: VirtAddr) -> Self {
|
||||||
Uart { base_address }
|
Uart { base_address }
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -81,26 +84,35 @@ impl Write for Uart {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn handle_interrupt() {
|
pub(super) fn handle_interrupt() {
|
||||||
let mut my_uart = Uart::new(phys_to_virt(UART_BASE));
|
if let Some(ref mut uart) = UART.lock().get_mut() {
|
||||||
if let Some(c) = my_uart.get() {
|
if let Some(c) = uart.get() {
|
||||||
let c = c & 0xff;
|
let c = c & 0xff;
|
||||||
//CONSOLE
|
//CONSOLE
|
||||||
super::serial_put(c);
|
crate::serial::serial_put(c);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* 因serial_write()已可以被回调输出了,这里则不再需要了
|
* 因serial_write()已可以被回调输出了,这里则不再需要了
|
||||||
match c {
|
match c {
|
||||||
0x7f => { //0x8 [backspace] ; 而实际qemu运行,[backspace]键输出0x7f, 表示del
|
0x7f => { //0x8 [backspace] ; 而实际qemu运行,[backspace]键输出0x7f, 表示del
|
||||||
bare_print!("{} {}", 8 as char, 8 as char);
|
bare_print!("{} {}", 8 as char, 8 as char);
|
||||||
},
|
},
|
||||||
10 | 13 => { // 新行或回车
|
10 | 13 => { // 新行或回车
|
||||||
bare_println!();
|
bare_println!();
|
||||||
},
|
},
|
||||||
_ => {
|
_ => {
|
||||||
bare_print!("{}", c as char);
|
bare_print!("{}", c as char);
|
||||||
},
|
},
|
||||||
|
}
|
||||||
|
*/
|
||||||
}
|
}
|
||||||
*/
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub(super) fn init(base_paddr: PhysAddr) {
|
||||||
|
UART.lock().call_once(|| {
|
||||||
|
let mut uart = Uart::new(phys_to_virt(base_paddr));
|
||||||
|
uart.simple_init();
|
||||||
|
uart
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
|
@ -0,0 +1,382 @@
|
||||||
|
use riscv::{
|
||||||
|
addr::Page,
|
||||||
|
asm::sfence_vma_all,
|
||||||
|
paging::{
|
||||||
|
FrameAllocator, FrameDeallocator, Mapper, PageTable as PT, PageTableFlags as PTF,
|
||||||
|
Rv39PageTable,
|
||||||
|
},
|
||||||
|
register::satp,
|
||||||
|
};
|
||||||
|
|
||||||
|
use super::super::{ffi, mem::phys_to_virt};
|
||||||
|
use super::consts;
|
||||||
|
use crate::{HalError, MMUFlags, PhysAddr, VirtAddr, PAGE_SIZE};
|
||||||
|
|
||||||
|
pub use crate::common::vm::*;
|
||||||
|
|
||||||
|
// First core stores its SATP here.
|
||||||
|
static mut SATP: usize = 0;
|
||||||
|
|
||||||
|
pub(crate) unsafe fn set_page_table(vmtoken: usize) {
|
||||||
|
#[cfg(target_arch = "riscv32")]
|
||||||
|
let mode = satp::Mode::Sv32;
|
||||||
|
#[cfg(target_arch = "riscv64")]
|
||||||
|
let mode = satp::Mode::Sv39;
|
||||||
|
debug!("set user table: {:#x?}", vmtoken);
|
||||||
|
satp::set(mode, 0, vmtoken >> 12);
|
||||||
|
//刷TLB好像很重要
|
||||||
|
sfence_vma_all();
|
||||||
|
}
|
||||||
|
|
||||||
|
fn map_range(
|
||||||
|
page_table: &mut Rv39PageTable,
|
||||||
|
mut start_addr: VirtAddr,
|
||||||
|
mut end_addr: VirtAddr,
|
||||||
|
linear_offset: usize,
|
||||||
|
flags: PTF,
|
||||||
|
) -> Result<(), ()> {
|
||||||
|
trace!("Mapping range addr: {:#x} ~ {:#x}", start_addr, end_addr);
|
||||||
|
|
||||||
|
start_addr = start_addr & !(PAGE_SIZE - 1);
|
||||||
|
let mut start_page = start_addr / PAGE_SIZE;
|
||||||
|
|
||||||
|
//end_addr = (end_addr + PAGE_SIZE - 1) & !(PAGE_SIZE -1);
|
||||||
|
//let end_page = (end_addr - 1) / PAGE_SIZE;
|
||||||
|
end_addr = end_addr & !(PAGE_SIZE - 1);
|
||||||
|
let end_page = end_addr / PAGE_SIZE;
|
||||||
|
|
||||||
|
while start_page <= end_page {
|
||||||
|
let vaddr: VirtAddr = start_page * PAGE_SIZE;
|
||||||
|
let page = riscv::addr::Page::of_addr(riscv::addr::VirtAddr::new(vaddr));
|
||||||
|
let frame = riscv::addr::Frame::of_addr(riscv::addr::PhysAddr::new(vaddr - linear_offset));
|
||||||
|
|
||||||
|
start_page += 1;
|
||||||
|
|
||||||
|
trace!(
|
||||||
|
"map_range: {:#x} -> {:#x}, flags={:?}",
|
||||||
|
vaddr,
|
||||||
|
vaddr - linear_offset,
|
||||||
|
flags
|
||||||
|
);
|
||||||
|
page_table
|
||||||
|
.map_to(page, frame, flags, &mut FrameAllocatorImpl)
|
||||||
|
.unwrap()
|
||||||
|
.flush();
|
||||||
|
}
|
||||||
|
info!(
|
||||||
|
"map range from {:#x} to {:#x}, flags: {:?}",
|
||||||
|
start_addr,
|
||||||
|
end_page * PAGE_SIZE,
|
||||||
|
flags
|
||||||
|
);
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
/// remap kernel with 4K page
|
||||||
|
pub fn remap_the_kernel(dtb: usize) {
|
||||||
|
extern "C" {
|
||||||
|
fn start();
|
||||||
|
|
||||||
|
fn stext();
|
||||||
|
fn etext();
|
||||||
|
fn srodata();
|
||||||
|
fn erodata();
|
||||||
|
fn sdata();
|
||||||
|
fn edata();
|
||||||
|
|
||||||
|
fn bootstack();
|
||||||
|
fn bootstacktop();
|
||||||
|
|
||||||
|
fn sbss();
|
||||||
|
fn ebss();
|
||||||
|
|
||||||
|
fn end();
|
||||||
|
}
|
||||||
|
|
||||||
|
let root_paddr = crate::mem::frame_alloc().expect("failed to alloc frame");
|
||||||
|
let root_vaddr = phys_to_virt(root_paddr);
|
||||||
|
let root = unsafe { &mut *(root_vaddr as *mut PT) };
|
||||||
|
root.zero();
|
||||||
|
let mut pt = Rv39PageTable::new(root, consts::PHYSICAL_MEMORY_OFFSET);
|
||||||
|
|
||||||
|
let linear_offset = consts::PHYSICAL_MEMORY_OFFSET;
|
||||||
|
//let mut flags = PTF::VALID | PTF::READABLE | PTF::WRITABLE | PTF::EXECUTABLE | PTF::USER;
|
||||||
|
|
||||||
|
map_range(
|
||||||
|
&mut pt,
|
||||||
|
stext as usize,
|
||||||
|
etext as usize - 1,
|
||||||
|
linear_offset,
|
||||||
|
PTF::VALID | PTF::READABLE | PTF::EXECUTABLE,
|
||||||
|
)
|
||||||
|
.unwrap();
|
||||||
|
map_range(
|
||||||
|
&mut pt,
|
||||||
|
srodata as usize,
|
||||||
|
erodata as usize,
|
||||||
|
linear_offset,
|
||||||
|
PTF::VALID | PTF::READABLE,
|
||||||
|
)
|
||||||
|
.unwrap();
|
||||||
|
map_range(
|
||||||
|
&mut pt,
|
||||||
|
sdata as usize,
|
||||||
|
edata as usize,
|
||||||
|
linear_offset,
|
||||||
|
PTF::VALID | PTF::READABLE | PTF::WRITABLE,
|
||||||
|
)
|
||||||
|
.unwrap();
|
||||||
|
|
||||||
|
// Stack
|
||||||
|
map_range(
|
||||||
|
&mut pt,
|
||||||
|
bootstack as usize,
|
||||||
|
bootstacktop as usize - 1,
|
||||||
|
linear_offset,
|
||||||
|
PTF::VALID | PTF::READABLE | PTF::WRITABLE,
|
||||||
|
)
|
||||||
|
.unwrap();
|
||||||
|
|
||||||
|
map_range(
|
||||||
|
&mut pt,
|
||||||
|
sbss as usize,
|
||||||
|
ebss as usize - 1,
|
||||||
|
linear_offset,
|
||||||
|
PTF::VALID | PTF::READABLE | PTF::WRITABLE,
|
||||||
|
)
|
||||||
|
.unwrap();
|
||||||
|
|
||||||
|
info!("map Heap ...");
|
||||||
|
// Heap
|
||||||
|
map_range(
|
||||||
|
&mut pt,
|
||||||
|
end as usize,
|
||||||
|
end as usize + PAGE_SIZE * 5120,
|
||||||
|
linear_offset,
|
||||||
|
PTF::VALID | PTF::READABLE | PTF::WRITABLE,
|
||||||
|
)
|
||||||
|
.unwrap();
|
||||||
|
info!("... Heap");
|
||||||
|
|
||||||
|
// Device Tree
|
||||||
|
#[cfg(feature = "board_qemu")]
|
||||||
|
map_range(
|
||||||
|
&mut pt,
|
||||||
|
dtb,
|
||||||
|
dtb + consts::MAX_DTB_SIZE,
|
||||||
|
linear_offset,
|
||||||
|
PTF::VALID | PTF::READABLE,
|
||||||
|
)
|
||||||
|
.unwrap();
|
||||||
|
|
||||||
|
// PLIC
|
||||||
|
map_range(
|
||||||
|
&mut pt,
|
||||||
|
phys_to_virt(consts::PLIC_PRIORITY),
|
||||||
|
phys_to_virt(consts::PLIC_PRIORITY) + PAGE_SIZE * 0xf,
|
||||||
|
linear_offset,
|
||||||
|
PTF::VALID | PTF::READABLE | PTF::WRITABLE,
|
||||||
|
)
|
||||||
|
.unwrap();
|
||||||
|
map_range(
|
||||||
|
&mut pt,
|
||||||
|
phys_to_virt(consts::PLIC_THRESHOLD),
|
||||||
|
phys_to_virt(consts::PLIC_THRESHOLD) + PAGE_SIZE * 0xf,
|
||||||
|
linear_offset,
|
||||||
|
PTF::VALID | PTF::READABLE | PTF::WRITABLE,
|
||||||
|
)
|
||||||
|
.unwrap();
|
||||||
|
|
||||||
|
// UART0, VIRTIO
|
||||||
|
map_range(
|
||||||
|
&mut pt,
|
||||||
|
phys_to_virt(consts::UART_BASE),
|
||||||
|
phys_to_virt(consts::UART_BASE) + PAGE_SIZE * 0xf,
|
||||||
|
linear_offset,
|
||||||
|
PTF::VALID | PTF::READABLE | PTF::WRITABLE,
|
||||||
|
)
|
||||||
|
.unwrap();
|
||||||
|
|
||||||
|
//写satp
|
||||||
|
let token = root_paddr;
|
||||||
|
unsafe {
|
||||||
|
set_page_table(token);
|
||||||
|
SATP = token;
|
||||||
|
}
|
||||||
|
|
||||||
|
//use core::mem;
|
||||||
|
//mem::forget(pt);
|
||||||
|
|
||||||
|
info!("remap the kernel @ {:#x}", token);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Page Table
|
||||||
|
#[repr(C)]
|
||||||
|
pub struct PageTable {
|
||||||
|
pub(super) root_paddr: PhysAddr,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl PageTable {
|
||||||
|
/// Create a new `PageTable`.
|
||||||
|
#[allow(clippy::new_without_default)]
|
||||||
|
#[export_name = "hal_pt_new"]
|
||||||
|
pub fn new() -> Self {
|
||||||
|
let root_paddr = crate::mem::frame_alloc().expect("failed to alloc frame");
|
||||||
|
let root_vaddr = phys_to_virt(root_paddr);
|
||||||
|
let root = unsafe { &mut *(root_vaddr as *mut PT) };
|
||||||
|
root.zero();
|
||||||
|
|
||||||
|
let current = phys_to_virt(satp::read().frame().start_address().as_usize()) as *const PT;
|
||||||
|
unsafe { ffi::hal_pt_map_kernel(root_vaddr as _, current as _) };
|
||||||
|
trace!("create page table @ {:#x}", root_paddr);
|
||||||
|
PageTable { root_paddr }
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn current() -> Self {
|
||||||
|
#[cfg(target_arch = "riscv32")]
|
||||||
|
let _mode = satp::Mode::Sv32;
|
||||||
|
#[cfg(target_arch = "riscv64")]
|
||||||
|
let _mode = satp::Mode::Sv39;
|
||||||
|
let root_paddr = satp::read().ppn() << 12;
|
||||||
|
PageTable { root_paddr }
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(target_arch = "riscv32")]
|
||||||
|
pub(super) fn get(&mut self) -> Rv32PageTable<'_> {
|
||||||
|
let root_vaddr = phys_to_virt(self.root_paddr);
|
||||||
|
let root = unsafe { &mut *(root_vaddr as *mut PT) };
|
||||||
|
Rv32PageTable::new(root, phys_to_virt(0))
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(target_arch = "riscv64")]
|
||||||
|
pub(super) fn get(&mut self) -> Rv39PageTable<'_> {
|
||||||
|
let root_vaddr = phys_to_virt(self.root_paddr);
|
||||||
|
let root = unsafe { &mut *(root_vaddr as *mut PT) };
|
||||||
|
Rv39PageTable::new(root, phys_to_virt(0))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl PageTableTrait for PageTable {
|
||||||
|
/// Map the page of `vaddr` to the frame of `paddr` with `flags`.
|
||||||
|
#[export_name = "hal_pt_map"]
|
||||||
|
fn map(&mut self, vaddr: VirtAddr, paddr: PhysAddr, flags: MMUFlags) -> Result<(), HalError> {
|
||||||
|
let mut pt = self.get();
|
||||||
|
let page = Page::of_addr(riscv::addr::VirtAddr::new(vaddr));
|
||||||
|
let frame = riscv::addr::Frame::of_addr(riscv::addr::PhysAddr::new(paddr));
|
||||||
|
pt.map_to(page, frame, flags.to_ptf(), &mut FrameAllocatorImpl)
|
||||||
|
.unwrap()
|
||||||
|
.flush();
|
||||||
|
|
||||||
|
trace!(
|
||||||
|
"PageTable: {:#X}, map: {:x?} -> {:x?}, flags={:?}",
|
||||||
|
self.table_phys() as usize,
|
||||||
|
vaddr,
|
||||||
|
paddr,
|
||||||
|
flags
|
||||||
|
);
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Unmap the page of `vaddr`.
|
||||||
|
#[export_name = "hal_pt_unmap"]
|
||||||
|
fn unmap(&mut self, vaddr: VirtAddr) -> Result<(), HalError> {
|
||||||
|
let mut pt = self.get();
|
||||||
|
let page = Page::of_addr(riscv::addr::VirtAddr::new(vaddr));
|
||||||
|
pt.unmap(page).unwrap().1.flush();
|
||||||
|
trace!(
|
||||||
|
"PageTable: {:#X}, unmap: {:x?}",
|
||||||
|
self.table_phys() as usize,
|
||||||
|
vaddr
|
||||||
|
);
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Change the `flags` of the page of `vaddr`.
|
||||||
|
#[export_name = "hal_pt_protect"]
|
||||||
|
fn protect(&mut self, vaddr: VirtAddr, flags: MMUFlags) -> Result<(), HalError> {
|
||||||
|
let mut pt = self.get();
|
||||||
|
let page = Page::of_addr(riscv::addr::VirtAddr::new(vaddr));
|
||||||
|
pt.update_flags(page, flags.to_ptf()).unwrap().flush();
|
||||||
|
|
||||||
|
trace!(
|
||||||
|
"PageTable: {:#X}, protect: {:x?}, flags={:?}",
|
||||||
|
self.table_phys() as usize,
|
||||||
|
vaddr,
|
||||||
|
flags
|
||||||
|
);
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Query the physical address which the page of `vaddr` maps to.
|
||||||
|
#[export_name = "hal_pt_query"]
|
||||||
|
fn query(&mut self, vaddr: VirtAddr) -> Result<PhysAddr, HalError> {
|
||||||
|
let mut pt = self.get();
|
||||||
|
let page = Page::of_addr(riscv::addr::VirtAddr::new(vaddr));
|
||||||
|
let res = pt.ref_entry(page);
|
||||||
|
trace!("query: {:x?} => {:#x?}", vaddr, res);
|
||||||
|
match res {
|
||||||
|
Ok(entry) => Ok(entry.addr().as_usize()),
|
||||||
|
Err(_) => Err(HalError),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Get the physical address of root page table.
|
||||||
|
#[export_name = "hal_pt_table_phys"]
|
||||||
|
fn table_phys(&self) -> PhysAddr {
|
||||||
|
self.root_paddr
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Activate this page table
|
||||||
|
#[export_name = "hal_pt_activate"]
|
||||||
|
fn activate(&self) {
|
||||||
|
let now_token = satp::read().bits();
|
||||||
|
let new_token = self.table_phys();
|
||||||
|
if now_token != new_token {
|
||||||
|
debug!("switch table {:x?} -> {:x?}", now_token, new_token);
|
||||||
|
unsafe {
|
||||||
|
set_page_table(new_token);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
trait FlagsExt {
|
||||||
|
fn to_ptf(self) -> PTF;
|
||||||
|
}
|
||||||
|
|
||||||
|
impl FlagsExt for MMUFlags {
|
||||||
|
fn to_ptf(self) -> PTF {
|
||||||
|
let mut flags = PTF::VALID;
|
||||||
|
if self.contains(MMUFlags::READ) {
|
||||||
|
flags |= PTF::READABLE;
|
||||||
|
}
|
||||||
|
if self.contains(MMUFlags::WRITE) {
|
||||||
|
flags |= PTF::WRITABLE;
|
||||||
|
}
|
||||||
|
if self.contains(MMUFlags::EXECUTE) {
|
||||||
|
flags |= PTF::EXECUTABLE;
|
||||||
|
}
|
||||||
|
if self.contains(MMUFlags::USER) {
|
||||||
|
flags |= PTF::USER;
|
||||||
|
}
|
||||||
|
flags
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
struct FrameAllocatorImpl;
|
||||||
|
|
||||||
|
impl FrameAllocator for FrameAllocatorImpl {
|
||||||
|
fn alloc(&mut self) -> Option<riscv::addr::Frame> {
|
||||||
|
crate::mem::frame_alloc().map(|f| {
|
||||||
|
let paddr = riscv::addr::PhysAddr::new(f);
|
||||||
|
riscv::addr::Frame::of_addr(paddr)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl FrameDeallocator for FrameAllocatorImpl {
|
||||||
|
fn dealloc(&mut self, frame: riscv::addr::Frame) {
|
||||||
|
crate::mem::frame_dealloc(frame.start_address().as_usize());
|
||||||
|
}
|
||||||
|
}
|
|
@ -151,6 +151,13 @@ fn irq_overwrite_handler(irq: u8, handler: Box<dyn Fn() + Send + Sync>) -> bool
|
||||||
set
|
set
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn init_irq_table() {
|
||||||
|
let mut table = IRQ_TABLE.lock();
|
||||||
|
for _ in 0..TABLE_SIZE {
|
||||||
|
table.push(None);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
hal_fn_impl! {
|
hal_fn_impl! {
|
||||||
impl mod crate::defs::interrupt {
|
impl mod crate::defs::interrupt {
|
||||||
fn enable_irq(irq: u32) {
|
fn enable_irq(irq: u32) {
|
||||||
|
@ -337,13 +344,6 @@ fn keyboard() {
|
||||||
}
|
}
|
||||||
*/
|
*/
|
||||||
|
|
||||||
fn init_irq_table() {
|
|
||||||
let mut table = IRQ_TABLE.lock();
|
|
||||||
for _ in 0..TABLE_SIZE {
|
|
||||||
table.push(None);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn irq_enable_raw(irq: u8, vector: u8) {
|
fn irq_enable_raw(irq: u8, vector: u8) {
|
||||||
info!("irq_enable_raw: irq={:#x?}, vector={:#x?}", irq, vector);
|
info!("irq_enable_raw: irq={:#x?}, vector={:#x?}", irq, vector);
|
||||||
let mut ioapic = super::apic::get_ioapic();
|
let mut ioapic = super::apic::get_ioapic();
|
||||||
|
@ -351,7 +351,7 @@ fn irq_enable_raw(irq: u8, vector: u8) {
|
||||||
ioapic.enable(irq, 0)
|
ioapic.enable(irq, 0)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn init() {
|
pub(super) fn init() {
|
||||||
// MOUSE.lock().init().unwrap();
|
// MOUSE.lock().init().unwrap();
|
||||||
// MOUSE.lock().set_on_complete(mouse_on_complete);
|
// MOUSE.lock().set_on_complete(mouse_on_complete);
|
||||||
unsafe {
|
unsafe {
|
||||||
|
|
|
@ -37,7 +37,7 @@ hal_fn_impl! {
|
||||||
len
|
len
|
||||||
}
|
}
|
||||||
|
|
||||||
fn print_fmt(fmt: Arguments) {
|
fn serial_write_fmt(fmt: Arguments) {
|
||||||
COM1.lock().write_fmt(fmt).unwrap();
|
COM1.lock().write_fmt(fmt).unwrap();
|
||||||
// if let Some(console) = CONSOLE.lock().as_mut() {
|
// if let Some(console) = CONSOLE.lock().as_mut() {
|
||||||
// console.write_fmt(fmt).unwrap();
|
// console.write_fmt(fmt).unwrap();
|
||||||
|
|
|
@ -3,7 +3,7 @@ use core::convert::TryFrom;
|
||||||
use x86_64::{
|
use x86_64::{
|
||||||
registers::control::{Cr3, Cr3Flags},
|
registers::control::{Cr3, Cr3Flags},
|
||||||
structures::paging::{mapper, FrameAllocator, FrameDeallocator, Mapper, Translate},
|
structures::paging::{mapper, FrameAllocator, FrameDeallocator, Mapper, Translate},
|
||||||
structures::paging::{OffsetPageTable, PageTable as X86PageTable, PageTableFlags as PTF},
|
structures::paging::{OffsetPageTable, PageTable as PT, PageTableFlags as PTF},
|
||||||
structures::paging::{Page, PhysFrame, Size4KiB},
|
structures::paging::{Page, PhysFrame, Size4KiB},
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -25,9 +25,9 @@ pub(crate) unsafe fn set_page_table(vmtoken: usize) {
|
||||||
debug!("set page_table @ {:#x}", vmtoken);
|
debug!("set page_table @ {:#x}", vmtoken);
|
||||||
}
|
}
|
||||||
|
|
||||||
fn frame_to_page_table(frame: PhysFrame) -> *mut X86PageTable {
|
fn frame_to_page_table(frame: PhysFrame) -> *mut PT {
|
||||||
let vaddr = phys_to_virt(frame.start_address().as_u64() as usize);
|
let vaddr = phys_to_virt(frame.start_address().as_u64() as usize);
|
||||||
vaddr as *mut X86PageTable
|
vaddr as *mut PT
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Page Table
|
/// Page Table
|
||||||
|
@ -36,26 +36,26 @@ pub struct PageTable {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl PageTable {
|
impl PageTable {
|
||||||
pub fn current() -> Self {
|
|
||||||
PageTable {
|
|
||||||
root_paddr: Cr3::read().0.start_address().as_u64() as _,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Create a new `PageTable`.
|
/// Create a new `PageTable`.
|
||||||
pub fn new() -> Self {
|
pub fn new() -> Self {
|
||||||
let root_paddr = crate::mem::frame_alloc().expect("failed to alloc frame");
|
let root_paddr = crate::mem::frame_alloc().expect("failed to alloc frame");
|
||||||
let root_vaddr = phys_to_virt(root_paddr);
|
let root_vaddr = phys_to_virt(root_paddr);
|
||||||
let root = unsafe { &mut *(root_vaddr as *mut X86PageTable) };
|
let root = unsafe { &mut *(root_vaddr as *mut PT) };
|
||||||
root.zero();
|
root.zero();
|
||||||
unsafe { ffi::hal_pt_map_kernel(root_vaddr as _, frame_to_page_table(Cr3::read().0) as _) };
|
unsafe { ffi::hal_pt_map_kernel(root_vaddr as _, frame_to_page_table(Cr3::read().0) as _) };
|
||||||
trace!("create page table @ {:#x}", root_paddr);
|
trace!("create page table @ {:#x}", root_paddr);
|
||||||
PageTable { root_paddr }
|
PageTable { root_paddr }
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn current() -> Self {
|
||||||
|
PageTable {
|
||||||
|
root_paddr: Cr3::read().0.start_address().as_u64() as _,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
fn get(&mut self) -> OffsetPageTable<'_> {
|
fn get(&mut self) -> OffsetPageTable<'_> {
|
||||||
let root_vaddr = phys_to_virt(self.root_paddr);
|
let root_vaddr = phys_to_virt(self.root_paddr);
|
||||||
let root = unsafe { &mut *(root_vaddr as *mut X86PageTable) };
|
let root = unsafe { &mut *(root_vaddr as *mut PT) };
|
||||||
let offset = x86_64::VirtAddr::new(phys_to_virt(0) as u64);
|
let offset = x86_64::VirtAddr::new(phys_to_virt(0) as u64);
|
||||||
unsafe { OffsetPageTable::new(root, offset) }
|
unsafe { OffsetPageTable::new(root, offset) }
|
||||||
}
|
}
|
||||||
|
|
|
@ -6,7 +6,7 @@ cfg_if::cfg_if! {
|
||||||
mod arch;
|
mod arch;
|
||||||
pub use self::arch::special as x86_64;
|
pub use self::arch::special as x86_64;
|
||||||
} else if #[cfg(any(target_arch = "riscv32", target_arch = "riscv64"))] {
|
} else if #[cfg(any(target_arch = "riscv32", target_arch = "riscv64"))] {
|
||||||
#[path = "arch/x86_64/mod.rs"]
|
#[path = "arch/riscv/mod.rs"]
|
||||||
mod arch;
|
mod arch;
|
||||||
pub use self::arch::special as riscv;
|
pub use self::arch::special as riscv;
|
||||||
}
|
}
|
||||||
|
@ -22,16 +22,14 @@ hal_fn_impl_default!(rand, vdso, dev::fb, dev::input);
|
||||||
|
|
||||||
pub use self::arch::{context, cpu, interrupt, serial, vm, HalConfig};
|
pub use self::arch::{context, cpu, interrupt, serial, vm, HalConfig};
|
||||||
|
|
||||||
|
#[cfg(any(target_arch = "riscv32", target_arch = "riscv64"))]
|
||||||
|
pub use self::arch::{BootInfo, GraphicInfo};
|
||||||
|
|
||||||
/// Initialize the HAL.
|
/// Initialize the HAL.
|
||||||
///
|
///
|
||||||
/// This function must be called at the beginning.
|
/// This function must be called at the beginning.
|
||||||
pub fn init(config: HalConfig) {
|
pub fn init(config: HalConfig) {
|
||||||
unsafe {
|
unsafe { trapframe::init() };
|
||||||
trapframe::init();
|
|
||||||
}
|
|
||||||
|
|
||||||
#[cfg(target_arch = "riscv64")]
|
|
||||||
trace!("hal dtb: {:#x}", config.dtb);
|
|
||||||
|
|
||||||
self::arch::init(config);
|
self::arch::init(config);
|
||||||
}
|
}
|
||||||
|
|
|
@ -121,12 +121,12 @@ hal_fn_def! {
|
||||||
/// Read a string from serial buffer.
|
/// Read a string from serial buffer.
|
||||||
fn serial_read(buf: &mut [u8]) -> usize;
|
fn serial_read(buf: &mut [u8]) -> usize;
|
||||||
|
|
||||||
/// Print format string and its arguments to console.
|
/// Print format string and its arguments to serial.
|
||||||
fn print_fmt(fmt: Arguments);
|
fn serial_write_fmt(fmt: Arguments);
|
||||||
|
|
||||||
/// Print a string to console.
|
/// Print a string to serial.
|
||||||
fn print_str(s: &str) {
|
fn serial_write(s: &str) {
|
||||||
print_fmt(format_args!("{}", s));
|
serial_write_fmt(format_args!("{}", s));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -27,7 +27,7 @@ hal_fn_impl! {
|
||||||
len
|
len
|
||||||
}
|
}
|
||||||
|
|
||||||
fn print_fmt(fmt: core::fmt::Arguments) {
|
fn serial_write_fmt(fmt: core::fmt::Arguments) {
|
||||||
eprint!("{}", fmt);
|
eprint!("{}", fmt);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -122,7 +122,7 @@ async fn new_thread(thread: CurrentThread) {
|
||||||
// UserContext
|
// UserContext
|
||||||
#[cfg(target_arch = "riscv64")]
|
#[cfg(target_arch = "riscv64")]
|
||||||
{
|
{
|
||||||
let trap_num = kernel_hal::fetch_trap_num(&cx);
|
let trap_num = kernel_hal::context::fetch_trap_num(&cx);
|
||||||
let is_interrupt = ((trap_num >> 63) & 1) == 1;
|
let is_interrupt = ((trap_num >> 63) & 1) == 1;
|
||||||
let trap_num = trap_num & 0xfff;
|
let trap_num = trap_num & 0xfff;
|
||||||
let pid = thread.proc().id();
|
let pid = thread.proc().id();
|
||||||
|
|
|
@ -132,7 +132,7 @@ impl INode for Stdout {
|
||||||
fn write_at(&self, _offset: usize, buf: &[u8]) -> Result<usize> {
|
fn write_at(&self, _offset: usize, buf: &[u8]) -> Result<usize> {
|
||||||
// we do not care the utf-8 things, we just want to print it!
|
// we do not care the utf-8 things, we just want to print it!
|
||||||
let s = unsafe { core::str::from_utf8_unchecked(buf) };
|
let s = unsafe { core::str::from_utf8_unchecked(buf) };
|
||||||
kernel_hal::serial::print_str(s);
|
kernel_hal::serial::serial_write(s);
|
||||||
Ok(buf.len())
|
Ok(buf.len())
|
||||||
}
|
}
|
||||||
fn poll(&self) -> Result<PollStatus> {
|
fn poll(&self) -> Result<PollStatus> {
|
||||||
|
|
|
@ -8,8 +8,8 @@ edition = "2018"
|
||||||
|
|
||||||
[features]
|
[features]
|
||||||
graphic = []
|
graphic = []
|
||||||
board_qemu = [] # "kernel-hal-bare/board_qemu"]
|
board_qemu = ["link_user_img", "kernel-hal/board_qemu"]
|
||||||
board_d1 = ["link_user_img"] #, "kernel-hal-bare/board_d1"]
|
board_d1 = ["link_user_img", "kernel-hal/board_d1"]
|
||||||
link_user_img = []
|
link_user_img = []
|
||||||
zircon = ["zircon-loader"]
|
zircon = ["zircon-loader"]
|
||||||
linux = ["linux-loader", "linux-object", "rcore-fs-sfs"]
|
linux = ["linux-loader", "linux-object", "rcore-fs-sfs"]
|
||||||
|
|
|
@ -0,0 +1,2 @@
|
||||||
|
/* Generated by build.rs. DO NOT EDIT. */
|
||||||
|
PROVIDE_HIDDEN(BASE_ADDRESS = 0xffffffff80200000);
|
|
@ -37,12 +37,12 @@ macro_rules! with_color {
|
||||||
}
|
}
|
||||||
|
|
||||||
fn print_in_color(args: fmt::Arguments, color_code: u8) {
|
fn print_in_color(args: fmt::Arguments, color_code: u8) {
|
||||||
kernel_hal::serial::print_fmt(with_color!(args, color_code));
|
kernel_hal::serial::serial_write_fmt(with_color!(args, color_code));
|
||||||
}
|
}
|
||||||
|
|
||||||
#[allow(dead_code)]
|
#[allow(dead_code)]
|
||||||
pub fn print(args: fmt::Arguments) {
|
pub fn print(args: fmt::Arguments) {
|
||||||
kernel_hal::serial::print_fmt(args);
|
kernel_hal::serial::serial_write_fmt(args);
|
||||||
}
|
}
|
||||||
|
|
||||||
struct SimpleLogger;
|
struct SimpleLogger;
|
||||||
|
|
|
@ -32,10 +32,7 @@ mod fs;
|
||||||
use rboot::BootInfo;
|
use rboot::BootInfo;
|
||||||
|
|
||||||
#[cfg(target_arch = "riscv64")]
|
#[cfg(target_arch = "riscv64")]
|
||||||
use kernel_hal_bare::{
|
use kernel_hal::{vm::remap_the_kernel, BootInfo, GraphicInfo};
|
||||||
drivers::virtio::{CMDLINE, GPU_DRIVERS},
|
|
||||||
phys_to_virt, remap_the_kernel, BootInfo, GraphicInfo,
|
|
||||||
};
|
|
||||||
|
|
||||||
use alloc::{
|
use alloc::{
|
||||||
boxed::Box,
|
boxed::Box,
|
||||||
|
@ -103,7 +100,7 @@ pub extern "C" fn rust_main(hartid: usize, device_tree_paddr: usize) -> ! {
|
||||||
"zCore rust_main( hartid: {}, device_tree_paddr: {:#x} )",
|
"zCore rust_main( hartid: {}, device_tree_paddr: {:#x} )",
|
||||||
hartid, device_tree_paddr
|
hartid, device_tree_paddr
|
||||||
);
|
);
|
||||||
let device_tree_vaddr = phys_to_virt(device_tree_paddr);
|
let device_tree_vaddr = device_tree_paddr + arch::consts::PHYSICAL_MEMORY_OFFSET;
|
||||||
|
|
||||||
let boot_info = BootInfo {
|
let boot_info = BootInfo {
|
||||||
memory_map: Vec::new(),
|
memory_map: Vec::new(),
|
||||||
|
@ -132,7 +129,7 @@ pub extern "C" fn rust_main(hartid: usize, device_tree_paddr: usize) -> ! {
|
||||||
dtb: device_tree_vaddr,
|
dtb: device_tree_vaddr,
|
||||||
});
|
});
|
||||||
|
|
||||||
let cmdline_dt = CMDLINE.read();
|
let cmdline_dt = "";// FIXME: CMDLINE.read();
|
||||||
let mut cmdline = boot_info.cmdline.to_string();
|
let mut cmdline = boot_info.cmdline.to_string();
|
||||||
|
|
||||||
if !cmdline_dt.is_empty() {
|
if !cmdline_dt.is_empty() {
|
||||||
|
@ -150,7 +147,7 @@ pub extern "C" fn rust_main(hartid: usize, device_tree_paddr: usize) -> ! {
|
||||||
.clone();
|
.clone();
|
||||||
let (width, height) = gpu.resolution();
|
let (width, height) = gpu.resolution();
|
||||||
let (fb_vaddr, fb_size) = gpu.setup_framebuffer();
|
let (fb_vaddr, fb_size) = gpu.setup_framebuffer();
|
||||||
kernel_hal_bare::init_framebuffer(width, height, fb_vaddr, fb_size);
|
kernel_hal::deb::fb::init(width, height, fb_vaddr, fb_size);
|
||||||
}
|
}
|
||||||
|
|
||||||
// riscv64在之后使用ramfs或virtio, 而x86_64则由bootloader载入文件系统镜像到内存
|
// riscv64在之后使用ramfs或virtio, 而x86_64则由bootloader载入文件系统镜像到内存
|
||||||
|
@ -189,7 +186,7 @@ fn main(ramfs_data: &'static mut [u8], cmdline: &str) -> ! {
|
||||||
let len = kernel_hal::serial::serial_read(&mut buffer);
|
let len = kernel_hal::serial::serial_read(&mut buffer);
|
||||||
for c in &buffer[..len] {
|
for c in &buffer[..len] {
|
||||||
STDIN.push((*c).into());
|
STDIN.push((*c).into());
|
||||||
// kernel_hal_bare::print_str(alloc::format!("{}", *c as char).as_str());
|
// kernel_hal::serial::serial_write(alloc::format!("{}", *c as char).as_str());
|
||||||
}
|
}
|
||||||
false
|
false
|
||||||
}
|
}
|
||||||
|
@ -215,7 +212,7 @@ fn run() -> ! {
|
||||||
x86_64::instructions::interrupts::disable();
|
x86_64::instructions::interrupts::disable();
|
||||||
}
|
}
|
||||||
#[cfg(target_arch = "riscv64")]
|
#[cfg(target_arch = "riscv64")]
|
||||||
kernel_hal_bare::interrupt::wait_for_interrupt();
|
kernel_hal::riscv::wait_for_interrupt();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -15,6 +15,8 @@ use riscv::{
|
||||||
addr::Frame,
|
addr::Frame,
|
||||||
paging::{PageTable, PageTableFlags as EF},
|
paging::{PageTable, PageTableFlags as EF},
|
||||||
};
|
};
|
||||||
|
#[cfg(target_arch = "riscv64")]
|
||||||
|
use kernel_hal::BootInfo;
|
||||||
|
|
||||||
#[cfg(target_arch = "x86_64")]
|
#[cfg(target_arch = "x86_64")]
|
||||||
type FrameAlloc = bitmap_allocator::BitAlloc16M;
|
type FrameAlloc = bitmap_allocator::BitAlloc16M;
|
||||||
|
@ -37,9 +39,6 @@ pub fn init_frame_allocator(boot_info: &BootInfo) {
|
||||||
info!("Frame allocator init end");
|
info!("Frame allocator init end");
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(target_arch = "riscv64")]
|
|
||||||
use kernel_hal_bare::BootInfo;
|
|
||||||
|
|
||||||
#[cfg(target_arch = "riscv64")]
|
#[cfg(target_arch = "riscv64")]
|
||||||
pub fn init_frame_allocator(boot_info: &BootInfo) {
|
pub fn init_frame_allocator(boot_info: &BootInfo) {
|
||||||
use core::ops::Range;
|
use core::ops::Range;
|
||||||
|
|
|
@ -6,7 +6,7 @@ impl Syscall<'_> {
|
||||||
pub fn sys_debug_write(&self, buf: UserInPtr<u8>, len: usize) -> ZxResult {
|
pub fn sys_debug_write(&self, buf: UserInPtr<u8>, len: usize) -> ZxResult {
|
||||||
info!("debug.write: buf=({:?}; {:#x})", buf, len);
|
info!("debug.write: buf=({:?}; {:#x})", buf, len);
|
||||||
let data = buf.read_array(len)?;
|
let data = buf.read_array(len)?;
|
||||||
kernel_hal::serial::print_str(core::str::from_utf8(&data).unwrap());
|
kernel_hal::serial::serial_write(core::str::from_utf8(&data).unwrap());
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -54,9 +54,9 @@ impl Syscall<'_> {
|
||||||
let dlog = proc.get_object_with_rights::<DebugLog>(handle_value, Rights::WRITE)?;
|
let dlog = proc.get_object_with_rights::<DebugLog>(handle_value, Rights::WRITE)?;
|
||||||
dlog.write(Severity::Info, options, self.thread.id(), proc.id(), &data);
|
dlog.write(Severity::Info, options, self.thread.id(), proc.id(), &data);
|
||||||
// print to kernel console
|
// print to kernel console
|
||||||
kernel_hal::serial::print_str(&data);
|
kernel_hal::serial::serial_write(&data);
|
||||||
if data.as_bytes().last() != Some(&b'\n') {
|
if data.as_bytes().last() != Some(&b'\n') {
|
||||||
kernel_hal::serial::print_str("\n");
|
kernel_hal::serial::serial_write("\n");
|
||||||
}
|
}
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue