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]
|
||||
libos = ["async-std"]
|
||||
board_qemu = []
|
||||
board_d1 = []
|
||||
|
||||
[dependencies]
|
||||
log = "0.4"
|
||||
|
@ -50,5 +52,4 @@ x86-smpboot = { git = "https://github.com/rcore-os/x86-smpboot", rev = "43ffedf"
|
|||
|
||||
# Bare-metal mode on riscv64
|
||||
[target.'cfg(all(target_os = "none", target_arch = "riscv64"))'.dependencies]
|
||||
# riscv = { git = "https://github.com/rcore-os/riscv", features = ["inline-asm"], rev = "0074cbc" }
|
||||
# volatile = "0.2"
|
||||
riscv = { git = "https://github.com/rcore-os/riscv", features = ["inline-asm"], rev = "0074cbc" }
|
||||
|
|
|
@ -51,4 +51,3 @@ pub const PLIC_INT_ENABLE: usize = 0x1000_2080;
|
|||
pub const PLIC_THRESHOLD: usize = 0x1020_1000;
|
||||
#[cfg(feature = "board_d1")]
|
||||
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::vec::Vec;
|
||||
use riscv::register::{
|
||||
satp,
|
||||
scause::{self, Exception, Interrupt, Trap},
|
||||
sie, sstatus, stval,
|
||||
};
|
||||
use alloc::{boxed::Box, vec::Vec};
|
||||
use riscv::register::{sie, sstatus};
|
||||
use spin::Mutex;
|
||||
use trapframe::{TrapFrame, UserContext};
|
||||
|
||||
use super::{plic, uart, sbi, timer_set_next};
|
||||
use super::consts::{PHYSICAL_MEMORY_OFFSET, UART_BASE, UART0_INT_NUM};
|
||||
use crate::{map_range, phys_to_virt, putfmt};
|
||||
use super::{consts, plic, serial, trap, uart};
|
||||
|
||||
// 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;
|
||||
pub type InterruptHandle = Box<dyn Fn() + Send + Sync>;
|
||||
lazy_static! {
|
||||
static ref IRQ_TABLE: Mutex<Vec<Option<InterruptHandle>>> = Default::default();
|
||||
|
||||
type InterruptHandler = Box<dyn Fn() + Send + Sync>;
|
||||
|
||||
lazy_static::lazy_static! {
|
||||
static ref IRQ_TABLE: Mutex<Vec<Option<InterruptHandler>>> = Default::default();
|
||||
}
|
||||
|
||||
fn init_irq() {
|
||||
init_irq_table();
|
||||
irq_add_handle(Timer, Box::new(super_timer)); //模拟参照了x86_64,把timer处理函数也放进去了
|
||||
//irq_add_handle(Keyboard, Box::new(keyboard));
|
||||
irq_add_handle(S_PLIC, Box::new(plic::handle_interrupt));
|
||||
#[allow(dead_code)]
|
||||
fn init_soft() {
|
||||
unsafe { sie::set_ssoft() };
|
||||
sbi_println!("+++ setup soft int! +++");
|
||||
}
|
||||
|
||||
pub fn init() {
|
||||
unsafe {
|
||||
sstatus::set_sie();
|
||||
|
||||
init_uart();
|
||||
|
||||
sie::set_sext();
|
||||
init_ext();
|
||||
fn init_ext() {
|
||||
unsafe { sie::set_sext() };
|
||||
plic::init();
|
||||
sbi_println!("+++ Setting up PLIC +++");
|
||||
}
|
||||
|
||||
init_irq();
|
||||
fn init_uart() {
|
||||
uart::init(consts::UART_BASE);
|
||||
|
||||
bare_println!("+++ setup interrupt +++");
|
||||
}
|
||||
//但当没有SBI_CONSOLE_PUTCHAR时,却为什么不行?
|
||||
serial::uart_print_fmt(format_args!("UART output testing\n\r"));
|
||||
|
||||
#[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),
|
||||
}
|
||||
}
|
||||
|
||||
fn init_irq_table() {
|
||||
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),
|
||||
}
|
||||
sbi_println!("+++ Setting up UART interrupts +++");
|
||||
}
|
||||
|
||||
/// 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);
|
||||
let mut table = IRQ_TABLE.lock();
|
||||
// allocate a valid irq number
|
||||
|
@ -97,7 +49,7 @@ fn irq_add_handle(irq: u8, handle: InterruptHandle) -> Option<u8> {
|
|||
let mut id = 0x20;
|
||||
while id < table.len() {
|
||||
if table[id].is_none() {
|
||||
table[id] = Some(handle);
|
||||
table[id] = Some(handler);
|
||||
return Some(id as u8);
|
||||
}
|
||||
id += 1;
|
||||
|
@ -108,206 +60,43 @@ fn irq_add_handle(irq: u8, handle: InterruptHandle) -> Option<u8> {
|
|||
match table[irq as usize] {
|
||||
Some(_) => None,
|
||||
None => {
|
||||
table[irq as usize] = Some(handle);
|
||||
table[irq as usize] = Some(handler);
|
||||
Some(irq)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn irq_remove_handle(irq: u8) -> bool {
|
||||
info!("IRQ remove handle {:#x?}", irq);
|
||||
let irq = irq as usize;
|
||||
fn init_irq_table() {
|
||||
let mut table = IRQ_TABLE.lock();
|
||||
match table[irq] {
|
||||
Some(_) => {
|
||||
table[irq] = None;
|
||||
false
|
||||
}
|
||||
None => true,
|
||||
for _ in 0..TABLE_SIZE {
|
||||
table.push(None);
|
||||
}
|
||||
}
|
||||
|
||||
fn breakpoint(sepc: &mut usize) {
|
||||
bare_println!("Exception::Breakpoint: A breakpoint set @0x{:x} ", sepc);
|
||||
|
||||
//sepc为触发中断指令ebreak的地址
|
||||
//防止无限循环中断,让sret返回时跳转到sepc的下一条指令地址
|
||||
*sepc += 2
|
||||
fn init_irq() {
|
||||
init_irq_table();
|
||||
irq_add_handle(TIMER, Box::new(trap::super_timer)); //模拟参照了x86_64,把timer处理函数也放进去了
|
||||
//irq_add_handle(Keyboard, Box::new(keyboard));
|
||||
irq_add_handle(S_PLIC, Box::new(plic::handle_interrupt));
|
||||
}
|
||||
|
||||
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::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();
|
||||
pub(super) fn init() {
|
||||
unsafe { sstatus::set_sie() };
|
||||
init_uart();
|
||||
init_ext();
|
||||
init_irq();
|
||||
sbi_println!("+++ setup interrupt +++");
|
||||
}
|
||||
|
||||
fn super_timer() {
|
||||
timer_set_next();
|
||||
super::timer_tick();
|
||||
|
||||
//bare_print!(".");
|
||||
|
||||
//发生外界中断时,epc的指令还没有执行,故无需修改epc到下一条
|
||||
}
|
||||
|
||||
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);
|
||||
hal_fn_impl! {
|
||||
impl mod crate::defs::interrupt {
|
||||
fn handle_irq(irq: u32) {
|
||||
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),
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
*/
|
||||
|
||||
// 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::*;
|
||||
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};
|
||||
#![allow(dead_code)]
|
||||
|
||||
mod sbi;
|
||||
use alloc::vec::Vec;
|
||||
|
||||
#[macro_use]
|
||||
pub mod serial;
|
||||
|
||||
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)]
|
||||
pub struct PageTableImpl {
|
||||
root_paddr: PhysAddr,
|
||||
#[derive(Debug, Copy, Clone)]
|
||||
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.
|
||||
#[repr(C)]
|
||||
#[derive(Debug)]
|
||||
|
@ -588,55 +57,28 @@ pub struct BootInfo {
|
|||
pub cmdline: &'static str,
|
||||
}
|
||||
|
||||
/// Graphic output information
|
||||
#[derive(Debug, Copy, Clone)]
|
||||
#[repr(C)]
|
||||
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 struct HalConfig {
|
||||
pub mconfig: u64,
|
||||
pub dtb: usize,
|
||||
}
|
||||
|
||||
pub mod interrupt;
|
||||
mod plic;
|
||||
mod uart;
|
||||
pub fn init(config: HalConfig) {
|
||||
trace!("hal dtb: {:#x}", config.dtb);
|
||||
|
||||
#[export_name = "hal_current_pgtable"]
|
||||
pub fn current_page_table() -> usize {
|
||||
#[cfg(target_arch = "riscv32")]
|
||||
let mode = satp::Mode::Sv32;
|
||||
#[cfg(target_arch = "riscv64")]
|
||||
let mode = satp::Mode::Sv39;
|
||||
satp::read().ppn() << 12
|
||||
}
|
||||
interrupt::init();
|
||||
timer::init();
|
||||
|
||||
pub fn init_framebuffer(width: u32, height: u32, addr: usize, size: usize) {
|
||||
let fb_info = FramebufferInfo {
|
||||
xres: width,
|
||||
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);
|
||||
}
|
||||
/*
|
||||
interrupt::init_soft();
|
||||
sbi::send_ipi(0);
|
||||
*/
|
||||
|
||||
#[export_name = "hal_mouse_set_callback"]
|
||||
pub fn mouse_set_callback(_callback: Box<dyn Fn([u8; 3]) + Send + Sync>) {
|
||||
//
|
||||
}
|
||||
unsafe { asm!("ebreak") };
|
||||
|
||||
#[export_name = "hal_kbd_set_callback"]
|
||||
pub fn kbd_set_callback(_callback: Box<dyn Fn(u16, i32) + Send + Sync>) {
|
||||
//
|
||||
#[cfg(feature = "board_qemu")]
|
||||
{
|
||||
// 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::uart;
|
||||
use crate::{putfmt, phys_to_virt};
|
||||
use super::super::mem::phys_to_virt;
|
||||
use super::consts::*;
|
||||
|
||||
//通过MMIO地址对平台级中断控制器PLIC的寄存器进行设置
|
||||
|
@ -10,7 +8,7 @@ use super::consts::*;
|
|||
//声明claim会清除中断源上的相应pending位。
|
||||
//即使mip寄存器的MEIP位没有置位, 也可以claim; 声明不被阀值寄存器的设置影响;
|
||||
//获取按优先级排序后的下一个可用的中断ID
|
||||
pub fn next() -> Option<u32> {
|
||||
fn next() -> Option<u32> {
|
||||
let claim_reg = phys_to_virt(PLIC_CLAIM) as *const u32;
|
||||
let claim_no;
|
||||
unsafe {
|
||||
|
@ -26,7 +24,7 @@ pub fn next() -> Option<u32> {
|
|||
//claim时,PLIC不再从该相同设备监听中断
|
||||
//写claim寄存器,告诉PLIC处理完成该中断
|
||||
// id 应该来源于next()函数
|
||||
pub fn complete(id: u32) {
|
||||
fn complete(id: u32) {
|
||||
let complete_reg = phys_to_virt(PLIC_CLAIM) as *mut u32; //和claim相同寄存器,只是读或写的区别
|
||||
unsafe {
|
||||
complete_reg.write_volatile(id);
|
||||
|
@ -46,7 +44,7 @@ pub fn is_pending(id: u32) -> bool {
|
|||
|
||||
//使能target中某个给定ID的中断
|
||||
//中断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 actual_id = 1 << id;
|
||||
unsafe {
|
||||
|
@ -56,7 +54,7 @@ pub fn enable(id: u32) {
|
|||
}
|
||||
|
||||
//设置中断源的优先级,分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 prio_reg = phys_to_virt(PLIC_PRIORITY) as *mut u32;
|
||||
unsafe {
|
||||
|
@ -65,7 +63,7 @@ pub fn set_priority(id: u32, prio: u8) {
|
|||
}
|
||||
|
||||
//设置中断target的全局阀值[0..7], <= threshold会被屏蔽
|
||||
pub fn set_threshold(tsh: u8) {
|
||||
fn set_threshold(tsh: u8) {
|
||||
let actual_tsh = tsh & 7; //使用0b111保留最后三位
|
||||
let tsh_reg = phys_to_virt(PLIC_THRESHOLD) as *mut u32;
|
||||
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() {
|
||||
match interrupt {
|
||||
1..=8 => {
|
||||
//virtio::handle_interrupt(interrupt);
|
||||
bare_println!("plic virtio external interrupt: {}", interrupt);
|
||||
sbi_println!("plic virtio external interrupt: {}", interrupt);
|
||||
}
|
||||
UART0_INT_NUM => {
|
||||
//UART中断ID是10
|
||||
uart::handle_interrupt();
|
||||
super::uart::handle_interrupt();
|
||||
|
||||
//换用sbi的方式获取字符
|
||||
//interrupt::try_process_serial();
|
||||
}
|
||||
_ => {
|
||||
bare_println!("Unknown external interrupt: {}", interrupt);
|
||||
sbi_println!("Unknown external interrupt: {}", interrupt);
|
||||
}
|
||||
}
|
||||
//这将复位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) {
|
||||
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);
|
||||
}
|
||||
|
||||
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) {
|
||||
#[cfg(target_pointer_width = "32")]
|
||||
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) {
|
||||
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 spin::{Mutex, Once};
|
||||
|
||||
pub struct Uart {
|
||||
base_address: usize,
|
||||
use super::super::mem::phys_to_virt;
|
||||
use crate::{PhysAddr, VirtAddr};
|
||||
|
||||
pub(super) struct Uart {
|
||||
base_address: VirtAddr,
|
||||
}
|
||||
|
||||
pub(super) static UART: Mutex<Once<Uart>> = Mutex::new(Once::new());
|
||||
|
||||
// 结构体Uart的实现块
|
||||
impl Uart {
|
||||
pub fn new(base_address: usize) -> Self {
|
||||
pub fn new(base_address: VirtAddr) -> Self {
|
||||
Uart { base_address }
|
||||
}
|
||||
|
||||
|
@ -81,12 +84,12 @@ impl Write for Uart {
|
|||
}
|
||||
}
|
||||
|
||||
pub fn handle_interrupt() {
|
||||
let mut my_uart = Uart::new(phys_to_virt(UART_BASE));
|
||||
if let Some(c) = my_uart.get() {
|
||||
pub(super) fn handle_interrupt() {
|
||||
if let Some(ref mut uart) = UART.lock().get_mut() {
|
||||
if let Some(c) = uart.get() {
|
||||
let c = c & 0xff;
|
||||
//CONSOLE
|
||||
super::serial_put(c);
|
||||
crate::serial::serial_put(c);
|
||||
|
||||
/*
|
||||
* 因serial_write()已可以被回调输出了,这里则不再需要了
|
||||
|
@ -104,3 +107,12 @@ pub fn handle_interrupt() {
|
|||
*/
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
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
|
||||
}
|
||||
|
||||
fn init_irq_table() {
|
||||
let mut table = IRQ_TABLE.lock();
|
||||
for _ in 0..TABLE_SIZE {
|
||||
table.push(None);
|
||||
}
|
||||
}
|
||||
|
||||
hal_fn_impl! {
|
||||
impl mod crate::defs::interrupt {
|
||||
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) {
|
||||
info!("irq_enable_raw: irq={:#x?}, vector={:#x?}", irq, vector);
|
||||
let mut ioapic = super::apic::get_ioapic();
|
||||
|
@ -351,7 +351,7 @@ fn irq_enable_raw(irq: u8, vector: u8) {
|
|||
ioapic.enable(irq, 0)
|
||||
}
|
||||
|
||||
pub fn init() {
|
||||
pub(super) fn init() {
|
||||
// MOUSE.lock().init().unwrap();
|
||||
// MOUSE.lock().set_on_complete(mouse_on_complete);
|
||||
unsafe {
|
||||
|
|
|
@ -37,7 +37,7 @@ hal_fn_impl! {
|
|||
len
|
||||
}
|
||||
|
||||
fn print_fmt(fmt: Arguments) {
|
||||
fn serial_write_fmt(fmt: Arguments) {
|
||||
COM1.lock().write_fmt(fmt).unwrap();
|
||||
// if let Some(console) = CONSOLE.lock().as_mut() {
|
||||
// console.write_fmt(fmt).unwrap();
|
||||
|
|
|
@ -3,7 +3,7 @@ use core::convert::TryFrom;
|
|||
use x86_64::{
|
||||
registers::control::{Cr3, Cr3Flags},
|
||||
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},
|
||||
};
|
||||
|
||||
|
@ -25,9 +25,9 @@ pub(crate) unsafe fn set_page_table(vmtoken: usize) {
|
|||
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);
|
||||
vaddr as *mut X86PageTable
|
||||
vaddr as *mut PT
|
||||
}
|
||||
|
||||
/// Page Table
|
||||
|
@ -36,26 +36,26 @@ pub struct PageTable {
|
|||
}
|
||||
|
||||
impl PageTable {
|
||||
pub fn current() -> Self {
|
||||
PageTable {
|
||||
root_paddr: Cr3::read().0.start_address().as_u64() as _,
|
||||
}
|
||||
}
|
||||
|
||||
/// Create a new `PageTable`.
|
||||
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 X86PageTable) };
|
||||
let root = unsafe { &mut *(root_vaddr as *mut PT) };
|
||||
root.zero();
|
||||
unsafe { ffi::hal_pt_map_kernel(root_vaddr as _, frame_to_page_table(Cr3::read().0) as _) };
|
||||
trace!("create page table @ {:#x}", 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<'_> {
|
||||
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);
|
||||
unsafe { OffsetPageTable::new(root, offset) }
|
||||
}
|
||||
|
|
|
@ -6,7 +6,7 @@ cfg_if::cfg_if! {
|
|||
mod arch;
|
||||
pub use self::arch::special as x86_64;
|
||||
} else if #[cfg(any(target_arch = "riscv32", target_arch = "riscv64"))] {
|
||||
#[path = "arch/x86_64/mod.rs"]
|
||||
#[path = "arch/riscv/mod.rs"]
|
||||
mod arch;
|
||||
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};
|
||||
|
||||
#[cfg(any(target_arch = "riscv32", target_arch = "riscv64"))]
|
||||
pub use self::arch::{BootInfo, GraphicInfo};
|
||||
|
||||
/// Initialize the HAL.
|
||||
///
|
||||
/// This function must be called at the beginning.
|
||||
pub fn init(config: HalConfig) {
|
||||
unsafe {
|
||||
trapframe::init();
|
||||
}
|
||||
|
||||
#[cfg(target_arch = "riscv64")]
|
||||
trace!("hal dtb: {:#x}", config.dtb);
|
||||
unsafe { trapframe::init() };
|
||||
|
||||
self::arch::init(config);
|
||||
}
|
||||
|
|
|
@ -121,12 +121,12 @@ hal_fn_def! {
|
|||
/// Read a string from serial buffer.
|
||||
fn serial_read(buf: &mut [u8]) -> usize;
|
||||
|
||||
/// Print format string and its arguments to console.
|
||||
fn print_fmt(fmt: Arguments);
|
||||
/// Print format string and its arguments to serial.
|
||||
fn serial_write_fmt(fmt: Arguments);
|
||||
|
||||
/// Print a string to console.
|
||||
fn print_str(s: &str) {
|
||||
print_fmt(format_args!("{}", s));
|
||||
/// Print a string to serial.
|
||||
fn serial_write(s: &str) {
|
||||
serial_write_fmt(format_args!("{}", s));
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -27,7 +27,7 @@ hal_fn_impl! {
|
|||
len
|
||||
}
|
||||
|
||||
fn print_fmt(fmt: core::fmt::Arguments) {
|
||||
fn serial_write_fmt(fmt: core::fmt::Arguments) {
|
||||
eprint!("{}", fmt);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -122,7 +122,7 @@ async fn new_thread(thread: CurrentThread) {
|
|||
// UserContext
|
||||
#[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 trap_num = trap_num & 0xfff;
|
||||
let pid = thread.proc().id();
|
||||
|
|
|
@ -132,7 +132,7 @@ impl INode for Stdout {
|
|||
fn write_at(&self, _offset: usize, buf: &[u8]) -> Result<usize> {
|
||||
// we do not care the utf-8 things, we just want to print it!
|
||||
let s = unsafe { core::str::from_utf8_unchecked(buf) };
|
||||
kernel_hal::serial::print_str(s);
|
||||
kernel_hal::serial::serial_write(s);
|
||||
Ok(buf.len())
|
||||
}
|
||||
fn poll(&self) -> Result<PollStatus> {
|
||||
|
|
|
@ -8,8 +8,8 @@ edition = "2018"
|
|||
|
||||
[features]
|
||||
graphic = []
|
||||
board_qemu = [] # "kernel-hal-bare/board_qemu"]
|
||||
board_d1 = ["link_user_img"] #, "kernel-hal-bare/board_d1"]
|
||||
board_qemu = ["link_user_img", "kernel-hal/board_qemu"]
|
||||
board_d1 = ["link_user_img", "kernel-hal/board_d1"]
|
||||
link_user_img = []
|
||||
zircon = ["zircon-loader"]
|
||||
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) {
|
||||
kernel_hal::serial::print_fmt(with_color!(args, color_code));
|
||||
kernel_hal::serial::serial_write_fmt(with_color!(args, color_code));
|
||||
}
|
||||
|
||||
#[allow(dead_code)]
|
||||
pub fn print(args: fmt::Arguments) {
|
||||
kernel_hal::serial::print_fmt(args);
|
||||
kernel_hal::serial::serial_write_fmt(args);
|
||||
}
|
||||
|
||||
struct SimpleLogger;
|
||||
|
|
|
@ -32,10 +32,7 @@ mod fs;
|
|||
use rboot::BootInfo;
|
||||
|
||||
#[cfg(target_arch = "riscv64")]
|
||||
use kernel_hal_bare::{
|
||||
drivers::virtio::{CMDLINE, GPU_DRIVERS},
|
||||
phys_to_virt, remap_the_kernel, BootInfo, GraphicInfo,
|
||||
};
|
||||
use kernel_hal::{vm::remap_the_kernel, BootInfo, GraphicInfo};
|
||||
|
||||
use alloc::{
|
||||
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} )",
|
||||
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 {
|
||||
memory_map: Vec::new(),
|
||||
|
@ -132,7 +129,7 @@ pub extern "C" fn rust_main(hartid: usize, device_tree_paddr: usize) -> ! {
|
|||
dtb: device_tree_vaddr,
|
||||
});
|
||||
|
||||
let cmdline_dt = CMDLINE.read();
|
||||
let cmdline_dt = "";// FIXME: CMDLINE.read();
|
||||
let mut cmdline = boot_info.cmdline.to_string();
|
||||
|
||||
if !cmdline_dt.is_empty() {
|
||||
|
@ -150,7 +147,7 @@ pub extern "C" fn rust_main(hartid: usize, device_tree_paddr: usize) -> ! {
|
|||
.clone();
|
||||
let (width, height) = gpu.resolution();
|
||||
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载入文件系统镜像到内存
|
||||
|
@ -189,7 +186,7 @@ fn main(ramfs_data: &'static mut [u8], cmdline: &str) -> ! {
|
|||
let len = kernel_hal::serial::serial_read(&mut buffer);
|
||||
for c in &buffer[..len] {
|
||||
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
|
||||
}
|
||||
|
@ -215,7 +212,7 @@ fn run() -> ! {
|
|||
x86_64::instructions::interrupts::disable();
|
||||
}
|
||||
#[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,
|
||||
paging::{PageTable, PageTableFlags as EF},
|
||||
};
|
||||
#[cfg(target_arch = "riscv64")]
|
||||
use kernel_hal::BootInfo;
|
||||
|
||||
#[cfg(target_arch = "x86_64")]
|
||||
type FrameAlloc = bitmap_allocator::BitAlloc16M;
|
||||
|
@ -37,9 +39,6 @@ pub fn init_frame_allocator(boot_info: &BootInfo) {
|
|||
info!("Frame allocator init end");
|
||||
}
|
||||
|
||||
#[cfg(target_arch = "riscv64")]
|
||||
use kernel_hal_bare::BootInfo;
|
||||
|
||||
#[cfg(target_arch = "riscv64")]
|
||||
pub fn init_frame_allocator(boot_info: &BootInfo) {
|
||||
use core::ops::Range;
|
||||
|
|
|
@ -6,7 +6,7 @@ impl Syscall<'_> {
|
|||
pub fn sys_debug_write(&self, buf: UserInPtr<u8>, len: usize) -> ZxResult {
|
||||
info!("debug.write: buf=({:?}; {:#x})", buf, 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(())
|
||||
}
|
||||
|
||||
|
|
|
@ -54,9 +54,9 @@ impl Syscall<'_> {
|
|||
let dlog = proc.get_object_with_rights::<DebugLog>(handle_value, Rights::WRITE)?;
|
||||
dlog.write(Severity::Info, options, self.thread.id(), proc.id(), &data);
|
||||
// print to kernel console
|
||||
kernel_hal::serial::print_str(&data);
|
||||
kernel_hal::serial::serial_write(&data);
|
||||
if data.as_bytes().last() != Some(&b'\n') {
|
||||
kernel_hal::serial::print_str("\n");
|
||||
kernel_hal::serial::serial_write("\n");
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue