kernel-hal: refactor for riscv bare-metal

This commit is contained in:
Yuekai Jia 2021-09-05 23:51:07 +08:00
parent 1097f4ac1e
commit 91f082ce18
30 changed files with 896 additions and 992 deletions

View File

@ -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" }

View File

@ -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;

View File

@ -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()
}
}
}

View File

@ -0,0 +1,8 @@
hal_fn_impl! {
impl mod crate::defs::cpu {
fn cpu_frequency() -> u16 {
const DEFAULT: u16 = 2600;
DEFAULT
}
}
}

View File

@ -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;

View File

@ -0,0 +1,3 @@
pub fn frame_flush(_target: crate::PhysAddr) {
unimplemented!()
}

View File

@ -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);
}
}

View File

@ -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) {
}
//设置中断源的优先级分07级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再次中断。

View File

@ -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;

View File

@ -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)*)));
}

View File

@ -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();
}
}
}

View File

@ -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();
}

View File

@ -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),
}
}

View File

@ -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
});
}

View File

@ -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());
}
}

View File

@ -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 {

View File

@ -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();

View File

@ -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) }
}

View File

@ -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);
}

View File

@ -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));
}
}

View File

@ -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);
}
}

View File

@ -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();

View File

@ -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> {

View File

@ -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"]

View File

@ -0,0 +1,2 @@
/* Generated by build.rs. DO NOT EDIT. */
PROVIDE_HIDDEN(BASE_ADDRESS = 0xffffffff80200000);

View File

@ -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;

View File

@ -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();
}
}

View File

@ -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;

View File

@ -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(())
}

View File

@ -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(())
}