diff --git a/.github/workflows/rustc20210727.yml b/.github/workflows/rustc20210727.yml index 4605ef711..7349d1eba 100644 --- a/.github/workflows/rustc20210727.yml +++ b/.github/workflows/rustc20210727.yml @@ -1,6 +1,6 @@ name: current CI -on: +on: push: pull_request: schedule: @@ -11,21 +11,29 @@ jobs: runs-on: ubuntu-20.04 steps: - uses: actions/checkout@v2 + with: + submodules: 'recursive' - uses: actions-rs/toolchain@v1 with: profile: minimal toolchain: nightly-2021-07-27 override: true - components: rustfmt, clippy + components: rust-src, rustfmt, clippy - name: Check code format uses: actions-rs/cargo@v1 with: command: fmt args: --all -- --check - - name: Clippy x86_64 + - name: Clippy LibOS run: arch=x86_64 cargo clippy - - name: Clippy riscv64 - run: arch=riscv64 cargo clippy + - name: Clippy x86_64 bare-metal + run: | + cd zCore + make clippy arch=x86_64 + - name: Clippy riscv64 bare-metal + run: | + cd zCore + make clippy arch=riscv64 linux=1 # uses: actions-rs/cargo@v1 # with: # command: clippy @@ -52,7 +60,7 @@ jobs: - name: Build zCore run: | cd zCore - make build arch=x86_64 + make build arch=x86_64 # FIX LATER # - name: Build zCore with hypervisor # run: | @@ -203,6 +211,7 @@ jobs: - name: Run libc-tests run: | cd scripts + pip3 install -r requirements.txt python3 libc-tests.py cat linux/test-result.txt @@ -275,6 +284,8 @@ jobs: tar xJf qemu-share.tar.xz && sudo cp -r qemu /usr/local/share/ - name: Prepare rootfs and oscomp run: make riscv-image + - name: Build kernel + run: cd zCore && make build mode=release linux=1 arch=riscv64 - name: Run baremetal-libc-test run: | cd scripts diff --git a/.github/workflows/rustcnightly.yml b/.github/workflows/rustcnightly.yml index fae6ab0b5..f97ee6648 100644 --- a/.github/workflows/rustcnightly.yml +++ b/.github/workflows/rustcnightly.yml @@ -1,6 +1,6 @@ name: rustcnightly CI -on: +on: push: pull_request: schedule: @@ -55,7 +55,7 @@ jobs: - name: Build zCore run: | cd zCore - make build arch=x86_64 + make build arch=x86_64 # FIX LATER # - name: Build zCore with hypervisor # run: | @@ -212,6 +212,7 @@ jobs: - name: Run libc-tests run: | cd scripts + pip3 install -r requirements.txt python3 libc-tests.py cat linux/test-result.txt @@ -289,6 +290,8 @@ jobs: tar xJf qemu-share.tar.xz && sudo cp -r qemu /usr/local/share/ - name: Prepare rootfs and oscomp run: make riscv-image + - name: Build kernel + run: cd zCore && make build mode=release linux=1 arch=riscv64 - name: Run baremetal-libc-test run: | cd scripts diff --git a/.gitignore b/.gitignore index f685b6d7e..ebf176ba7 100644 --- a/.gitignore +++ b/.gitignore @@ -8,6 +8,8 @@ Cargo.lock /prebuilt/linux/riscv64/prebuild* .idea scripts/linux/test-result.txt +scripts/zircon/test-result.txt +scripts/zircon/test-output.txt rusty-tags.vi *.img zCore/src/link_user.S @@ -17,4 +19,3 @@ stdout-zcore scripts/script.sh stdout-baremetal-test-rv64 stdout-rv64 - diff --git a/Cargo.toml b/Cargo.toml index d499aa0ef..f42ca523a 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,11 +1,11 @@ [workspace] members = [ "zircon-object", + "zircon-syscall", "zircon-loader", "linux-object", - "zircon-syscall", + "linux-syscall", "linux-loader", - "kernel-hal-unix", "kernel-hal", ] @@ -13,6 +13,4 @@ exclude = [ "zircon-user", "zCore", "rboot", - "linux-syscall", - "kernel-hal-bare", ] diff --git a/Makefile b/Makefile index 2198f39ac..f8a958692 100644 --- a/Makefile +++ b/Makefile @@ -67,7 +67,7 @@ riscv-image: rcore-fs-fuse riscv-rootfs @echo building riscv.img @rcore-fs-fuse zCore/riscv64.img riscv_rootfs zip @qemu-img resize -f raw zCore/riscv64.img +5M - + clean: cargo clean find zCore -maxdepth 1 -name "*.img" -delete diff --git a/kernel-hal-bare/Cargo.toml b/kernel-hal-bare/Cargo.toml deleted file mode 100644 index 687ac8a2d..000000000 --- a/kernel-hal-bare/Cargo.toml +++ /dev/null @@ -1,45 +0,0 @@ -[package] -name = "kernel-hal-bare" -version = "0.1.0" -authors = ["Runji Wang "] -edition = "2018" -description = "Kernel HAL implementation for bare metal environment." - -# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html - -[features] -board_qemu = [] -board_d1 = [] - -[dependencies] -log = "0.4" -spin = "0.7" -git-version = "0.3" -executor = { git = "https://github.com/rcore-os/executor.git", rev = "a2d02ee9" } -trapframe = "0.8.0" -kernel-hal = { path = "../kernel-hal" } -naive-timer = "0.1.0" -lazy_static = { version = "1.4", features = ["spin_no_std"] } -rcore-fs = { git = "https://github.com/rcore-os/rcore-fs", rev = "6df6cd2" } -device_tree = { git = "https://github.com/rcore-os/device_tree-rs" } -virtio-drivers = { git = "https://github.com/rcore-os/virtio-drivers", rev = "568276" } - -[target.'cfg(target_arch = "x86_64")'.dependencies] -x86_64 = "0.14" -uart_16550 = "=0.2.15" -raw-cpuid = "9.0" -pc-keyboard = "0.5" -apic = { git = "https://github.com/rcore-os/apic-rs", rev = "fb86bd7" } -x86-smpboot = { git = "https://github.com/rcore-os/x86-smpboot", rev = "43ffedf" } -rcore-console = { git = "https://github.com/rcore-os/rcore-console", default-features = false, rev = "a980897b" } -acpi = "1.1" -ps2-mouse = { git = "https://github.com/YXL76/ps2-mouse", branch = "feat" } - -[target.'cfg(any(target_arch = "riscv32", target_arch = "riscv64"))'.dependencies] -riscv = { git = "https://github.com/rcore-os/riscv", features = [ - "inline-asm", -], rev = "0074cbc" } -# 注意rev版本号必须与其他组件的完全一致,不可多字符 - -bitflags = "1.0" -volatile = "0.2" diff --git a/kernel-hal-bare/src/arch/mod.rs b/kernel-hal-bare/src/arch/mod.rs deleted file mode 100644 index 3594da354..000000000 --- a/kernel-hal-bare/src/arch/mod.rs +++ /dev/null @@ -1,9 +0,0 @@ -#[cfg(any(target_arch = "riscv32", target_arch = "riscv64"))] -mod riscv; -#[cfg(target_arch = "x86_64")] -mod x86_64; - -#[cfg(any(target_arch = "riscv32", target_arch = "riscv64"))] -pub use self::riscv::*; -#[cfg(target_arch = "x86_64")] -pub use self::x86_64::*; diff --git a/kernel-hal-bare/src/arch/riscv/consts.rs b/kernel-hal-bare/src/arch/riscv/consts.rs deleted file mode 100644 index cdd650763..000000000 --- a/kernel-hal-bare/src/arch/riscv/consts.rs +++ /dev/null @@ -1,54 +0,0 @@ -// RISCV -// Linear mapping - -#[cfg(feature = "board_qemu")] -pub const KERNEL_OFFSET: usize = 0xFFFF_FFFF_8000_0000; -#[cfg(feature = "board_qemu")] -pub const MEMORY_OFFSET: usize = 0x8000_0000; -#[cfg(feature = "board_qemu")] -pub const MEMORY_END: usize = 0x8800_0000; // TODO: get memory end from device tree - -#[cfg(feature = "board_d1")] -pub const KERNEL_OFFSET: usize = 0xFFFFFFFF_C0000000; -#[cfg(feature = "board_d1")] -pub const MEMORY_OFFSET: usize = 0x40000000; -#[cfg(feature = "board_d1")] -pub const MEMORY_END: usize = 0x60000000; // 512M - -pub const PHYSICAL_MEMORY_OFFSET: usize = KERNEL_OFFSET - MEMORY_OFFSET; - -pub const MAX_DTB_SIZE: usize = 0x2000; - -pub const MMIO_MTIMECMP0: *mut u64 = 0x0200_4000usize as *mut u64; -pub const MMIO_MTIME: *const u64 = 0x0200_BFF8 as *const u64; - -#[cfg(feature = "board_qemu")] -pub const UART_BASE: usize = 0x10000000; -#[cfg(feature = "board_qemu")] -pub const UART0_INT_NUM: u32 = 10; -#[cfg(feature = "board_qemu")] -pub const PLIC_PRIORITY: usize = 0x0c000000; -#[cfg(feature = "board_qemu")] -pub const PLIC_PENDING: usize = 0x0c001000; -#[cfg(feature = "board_qemu")] -pub const PLIC_INT_ENABLE: usize = 0x0c002080; -#[cfg(feature = "board_qemu")] -pub const PLIC_THRESHOLD: usize = 0x0c201000; -#[cfg(feature = "board_qemu")] -pub const PLIC_CLAIM: usize = 0x0c201004; - -#[cfg(feature = "board_d1")] -pub const UART_BASE: usize = 0x02500000; -#[cfg(feature = "board_d1")] -pub const UART0_INT_NUM: u32 = 18; -#[cfg(feature = "board_d1")] -pub const PLIC_PRIORITY: usize = 0x1000_0000; -#[cfg(feature = "board_d1")] -pub const PLIC_PENDING: usize = 0x1000_1000; -#[cfg(feature = "board_d1")] -pub const PLIC_INT_ENABLE: usize = 0x1000_2080; -#[cfg(feature = "board_d1")] -pub const PLIC_THRESHOLD: usize = 0x1020_1000; -#[cfg(feature = "board_d1")] -pub const PLIC_CLAIM: usize = 0x1020_1004; - diff --git a/kernel-hal-bare/src/arch/riscv/interrupt.rs b/kernel-hal-bare/src/arch/riscv/interrupt.rs deleted file mode 100644 index 04a0f3c12..000000000 --- a/kernel-hal-bare/src/arch/riscv/interrupt.rs +++ /dev/null @@ -1,313 +0,0 @@ -use alloc::boxed::Box; -use alloc::vec::Vec; -use riscv::register::{ - satp, - scause::{self, Exception, Interrupt, Trap}, - sie, sstatus, stval, -}; -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}; - -const TABLE_SIZE: usize = 256; -pub type InterruptHandle = Box; -lazy_static! { - static ref IRQ_TABLE: Mutex>> = 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)); -} - -pub fn init() { - unsafe { - sstatus::set_sie(); - - init_uart(); - - sie::set_sext(); - init_ext(); - } - - init_irq(); - - bare_println!("+++ setup interrupt +++"); -} - -#[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), - } -} - -/// 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 { - info!("IRQ add handle {:#x?}", irq); - let mut table = IRQ_TABLE.lock(); - // allocate a valid irq number - // why? - if irq == 0 { - let mut id = 0x20; - while id < table.len() { - if table[id].is_none() { - table[id] = Some(handle); - return Some(id as u8); - } - id += 1; - } - return None; - } - - match table[irq as usize] { - Some(_) => None, - None => { - table[irq as usize] = Some(handle); - Some(irq) - } - } -} - -fn irq_remove_handle(irq: u8) -> bool { - info!("IRQ remove handle {:#x?}", irq); - let irq = irq as usize; - let mut table = IRQ_TABLE.lock(); - match table[irq] { - Some(_) => { - table[irq] = None; - false - } - None => true, - } -} - -fn breakpoint(sepc: &mut usize) { - bare_println!("Exception::Breakpoint: A breakpoint set @0x{:x} ", sepc); - - //sepc为触发中断指令ebreak的地址 - //防止无限循环中断,让sret返回时跳转到sepc的下一条指令地址 - *sepc += 2 -} - -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, PageTableTrait}; - use riscv::addr::{Page, PhysAddr, VirtAddr}; - use riscv::paging::{PageTableFlags as PTF, Rv39PageTable, *}; - - //let mut flags = PTF::VALID; - let code = this_scause.code(); - let mut flags = if code == 15 { - //MMUFlags::WRITE ??? - MMUFlags::READ | MMUFlags::WRITE - } else if code == 12 { - MMUFlags::EXECUTE - } else { - MMUFlags::READ - }; - - let linear_offset = if stval >= PHYSICAL_MEMORY_OFFSET { - // Kernel - PHYSICAL_MEMORY_OFFSET - } else { - // User - 0 - }; - - /* - let current = - unsafe { &mut *(phys_to_virt(satp::read().frame().start_address().as_usize()) as *mut PageTable) }; - let mut pt = Rv39PageTable::new(current, PHYSICAL_MEMORY_OFFSET); - map_range(&mut pt, vaddr, vaddr, linear_offset, flags); - */ - - let mut pti = PageTableImpl { - root_paddr: satp::read().frame().start_address().as_usize(), - }; - - let page = Page::of_addr(VirtAddr::new(vaddr)); - if let Ok(pte) = pti.get().ref_entry(page) { - let pte = unsafe { &mut *(pte as *mut PageTableEntry) }; - if !pte.is_unused() { - debug!( - "PageAlreadyMapped -> {:#x?}, {:?}", - pte.addr().as_usize(), - pte.flags() - ); - //TODO update flags - - pti.unmap(vaddr).unwrap(); - } - }; - pti.map(vaddr, vaddr - linear_offset, flags).unwrap(); -} - -fn super_timer() { - 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); - } - } - } - } -} -*/ - -// 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; diff --git a/kernel-hal-bare/src/arch/riscv/mod.rs b/kernel-hal-bare/src/arch/riscv/mod.rs deleted file mode 100644 index 4fd3854d9..000000000 --- a/kernel-hal-bare/src/arch/riscv/mod.rs +++ /dev/null @@ -1,644 +0,0 @@ -use super::super::*; -use kernel_hal::{ - ColorDepth, ColorFormat, FramebufferInfo, HalError, PageTableTrait, PhysAddr, VirtAddr, - FRAME_BUFFER, -}; -use riscv::addr::Page; -use riscv::asm::sfence_vma_all; -use riscv::paging::{PageTableFlags as PTF, *}; -use riscv::register::{satp, sie, stval, time}; -//use crate::sbi; -use alloc::{collections::VecDeque, vec::Vec}; -use core::fmt::{self, Write}; - -mod sbi; - -mod consts; - -use consts::*; - -// 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, -} - -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 { - 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 { - 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> = Mutex::new(VecDeque::new()); - static ref STDIN_CALLBACK: Mutex 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 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 serial_write(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 { - 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)] -pub struct BootInfo { - pub memory_map: Vec, - //pub memory_map: Vec<&'static MemoryDescriptor>, - /// The offset into the virtual address space where the physical memory is mapped. - pub physical_memory_offset: u64, - /// The graphic output information - pub graphic_info: GraphicInfo, - - /// Physical address of ACPI2 RSDP, 启动的系统信息表的入口指针 - //pub acpi2_rsdp_addr: u64, - /// Physical address of SMBIOS, 产品管理信息的结构表 - //pub smbios_addr: u64, - pub hartid: u64, - pub dtb_addr: u64, - - /// The start physical address of initramfs - pub initramfs_addr: u64, - /// The size of initramfs - pub initramfs_size: u64, - /// Kernel command line - 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 mod interrupt; -mod plic; -mod uart; - -#[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 -} - -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); -} - -#[export_name = "hal_mice_set_callback"] -pub fn mice_set_callback(_callback: Box) { - // -} - -#[export_name = "hal_kbd_set_callback"] -pub fn kbd_set_callback(_callback: Box) { - // -} diff --git a/kernel-hal-bare/src/arch/x86_64/interrupt.rs b/kernel-hal-bare/src/arch/x86_64/interrupt.rs deleted file mode 100644 index 61ea73353..000000000 --- a/kernel-hal-bare/src/arch/x86_64/interrupt.rs +++ /dev/null @@ -1,413 +0,0 @@ -#![allow(dead_code)] -#![allow(non_upper_case_globals)] - -use super::{acpi_table::*, phys_to_virt}; -use alloc::boxed::Box; -use alloc::vec::Vec; -use apic::IoApic; -use ps2_mouse::{Mouse, MouseState}; -use spin::Mutex; -use trapframe::TrapFrame; - -const IO_APIC_NUM_REDIRECTIONS: u8 = 120; -const TABLE_SIZE: usize = 256; -pub type InterruptHandle = Box; -lazy_static! { - static ref IRQ_TABLE: Mutex>> = Default::default(); -} - -lazy_static! { - static ref MOUSE: Mutex = Mutex::new(Mouse::new()); - static ref MOUSE_CALLBACK: Mutex>> = - Mutex::new(Vec::new()); -} - -#[export_name = "hal_mice_set_callback"] -pub fn mice_set_callback(callback: Box) { - MOUSE_CALLBACK.lock().push(callback); -} - -fn mouse_on_complete(mouse_state: MouseState) { - debug!("mouse state: {:?}", mouse_state); - MOUSE_CALLBACK.lock().iter().for_each(|callback| { - callback([ - mouse_state.get_flags().bits(), - mouse_state.get_x() as u8, - mouse_state.get_y() as u8, - ]); - }); -} - -fn mouse() { - use x86_64::instructions::port::PortReadOnly; - let mut port = PortReadOnly::new(0x60); - let packet = unsafe { port.read() }; - MOUSE.lock().process_packet(packet); -} - -pub fn init() { - MOUSE.lock().init().unwrap(); - MOUSE.lock().set_on_complete(mouse_on_complete); - unsafe { - init_ioapic(); - } - init_irq_table(); - irq_add_handle(Timer + IRQ0, Box::new(timer)); - irq_add_handle(Keyboard + IRQ0, Box::new(keyboard)); - irq_add_handle(Mouse + IRQ0, Box::new(mouse)); - irq_add_handle(COM1 + IRQ0, Box::new(com1)); - irq_enable_raw(Keyboard, Keyboard + IRQ0); - irq_enable_raw(Mouse, Mouse + IRQ0); - irq_enable_raw(COM1, COM1 + IRQ0); -} - -fn init_irq_table() { - let mut table = IRQ_TABLE.lock(); - for _ in 0..TABLE_SIZE { - table.push(None); - } -} - -unsafe fn init_ioapic() { - for ioapic in AcpiTable::get_ioapic() { - info!("Ioapic found: {:#x?}", ioapic); - let mut ip = IoApic::new(phys_to_virt(ioapic.address as usize)); - ip.disable_all(); - } - let mut ip = IoApic::new(phys_to_virt(super::IOAPIC_ADDR)); - ip.disable_all(); -} - -fn get_ioapic(irq: u32) -> Option { - for i in AcpiTable::get_ioapic() { - let num_instr = core::cmp::min( - ioapic_maxinstr(i.address).unwrap(), - IO_APIC_NUM_REDIRECTIONS - 1, - ); - if i.global_system_interrupt_base <= irq - && irq <= i.global_system_interrupt_base + num_instr as u32 - { - return Some(i); - } - } - None -} - -fn ioapic_controller(i: &acpi::interrupt::IoApic) -> IoApic { - unsafe { IoApic::new(phys_to_virt(i.address as usize)) } -} - -#[no_mangle] -pub extern "C" fn trap_handler(tf: &mut TrapFrame) { - trace!("Interrupt: {:#x} @ CPU{}", tf.trap_num, 0); // TODO 0 should replace in multi-core case - match tf.trap_num as u8 { - Breakpoint => breakpoint(), - DoubleFault => double_fault(tf), - PageFault => page_fault(tf), - IRQ0..=63 => irq_handle(tf.trap_num as u8), - _ => panic!("Unhandled interrupt {:x} {:#x?}", tf.trap_num, tf), - } -} - -#[export_name = "hal_irq_handle"] -pub fn irq_handle(irq: u8) { - use super::{LocalApic, XApic, LAPIC_ADDR}; - let mut lapic = unsafe { XApic::new(phys_to_virt(LAPIC_ADDR)) }; - lapic.eoi(); - let table = IRQ_TABLE.lock(); - match &table[irq as usize] { - Some(f) => f(), - None => panic!("unhandled external IRQ number: {}", irq), - } -} - -#[export_name = "hal_irq_register_handler"] -pub fn register_irq_handler(global_irq: u32, handle: InterruptHandle) -> Option { - info!("set_handle irq={:#x?}", global_irq); - // if global_irq == 1 { - // irq_add_handle(global_irq as u8 + IRQ0, handle); - // return Some(global_irq as u8 + IRQ0); - // } - let ioapic_info = get_ioapic(global_irq)?; - let mut ioapic = ioapic_controller(&ioapic_info); - let offset = (global_irq - ioapic_info.global_system_interrupt_base) as u8; - let irq = ioapic.irq_vector(offset); - let new_handle = if global_irq == 0x1 { - Box::new(move || { - handle(); - keyboard(); - mouse(); - }) - } else { - handle - }; - irq_add_handle(irq, new_handle).map(|x| { - info!( - "irq_set_handle: mapping from {:#x?} to {:#x?}", - global_irq, x - ); - ioapic.set_irq_vector(offset, x); - x as u32 - }) -} - -#[export_name = "hal_irq_unregister_handler"] -pub fn unregister_irq_handler(global_irq: u32) -> bool { - info!("reset_handle"); - let ioapic_info = if let Some(x) = get_ioapic(global_irq) { - x - } else { - return false; - }; - let mut ioapic = ioapic_controller(&ioapic_info); - let offset = (global_irq - ioapic_info.global_system_interrupt_base) as u8; - let irq = ioapic.irq_vector(offset); - if !irq_remove_handle(irq) { - ioapic.set_irq_vector(offset, 0); - true - } else { - false - } -} - -/// 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 { - info!("IRQ add handle {:#x?}", irq); - let mut table = IRQ_TABLE.lock(); - // allocate a valid irq number - if irq == 0 { - let mut id = 0x20; - while id < table.len() { - if table[id].is_none() { - table[id] = Some(handle); - return Some(id as u8); - } - id += 1; - } - return None; - } - match table[irq as usize] { - Some(_) => None, - None => { - table[irq as usize] = Some(handle); - Some(irq) - } - } -} - -fn irq_remove_handle(irq: u8) -> bool { - // TODO: ioapic redirection entries associated with this should be reset. - info!("IRQ remove handle {:#x?}", irq); - let irq = irq as usize; - let mut table = IRQ_TABLE.lock(); - match table[irq] { - Some(_) => { - table[irq] = None; - false - } - None => true, - } -} - -fn irq_overwrite_handler(irq: u8, handle: Box) -> bool { - info!("IRQ overwrite handle {:#x?}", irq); - let mut table = IRQ_TABLE.lock(); - let set = table[irq as usize].is_none(); - table[irq as usize] = Some(handle); - set -} - -#[export_name = "hal_msi_allocate_block"] -pub fn msi_allocate_block(irq_num: u32) -> Option<(usize, usize)> { - info!("hal_irq_allocate_block: count={:#x?}", irq_num); - let irq_num = u32::next_power_of_two(irq_num) as usize; - let mut irq_start = 0x20; - let mut irq_cur = irq_start; - let mut table = IRQ_TABLE.lock(); - while irq_cur < TABLE_SIZE && irq_cur < irq_start + irq_num { - if table[irq_cur].is_none() { - irq_cur += 1; - } else { - irq_start = (irq_cur - irq_cur % irq_num) + irq_num; - irq_cur = irq_start; - } - } - for i in irq_start..irq_start + irq_num { - table[i] = Some(Box::new(|| {})); - } - info!( - "hal_irq_allocate_block: start={:#x?} num={:#x?}", - irq_start, irq_num - ); - Some((irq_start, irq_num)) -} - -#[export_name = "hal_msi_free_block"] -pub fn msi_free_block(irq_start: u32, irq_num: u32) { - let mut table = IRQ_TABLE.lock(); - for i in irq_start..irq_start + irq_num { - table[i as usize] = None; - } -} - -#[export_name = "hal_msi_register_handler"] -pub fn msi_register_handler( - irq_start: u32, - _irq_num: u32, - msi_id: u32, - handle: Box, -) { - irq_overwrite_handler((irq_start + msi_id) as u8, handle); -} - -#[export_name = "hal_irq_enable"] -pub fn irq_enable(irq: u32) { - info!("irq_enable irq={:#x?}", irq); - // if irq == 1 { - // irq_enable_raw(irq as u8, irq as u8 + IRQ0); - // return; - // } - if let Some(x) = get_ioapic(irq) { - let mut ioapic = ioapic_controller(&x); - ioapic.enable((irq - x.global_system_interrupt_base) as u8, 0); - } -} - -fn irq_enable_raw(irq: u8, vector: u8) { - info!("irq_enable_raw: irq={:#x?}, vector={:#x?}", irq, vector); - let mut ioapic = unsafe { IoApic::new(phys_to_virt(super::IOAPIC_ADDR)) }; - ioapic.set_irq_vector(irq, vector); - ioapic.enable(irq, 0) -} - -#[export_name = "hal_irq_disable"] -pub fn irq_disable(irq: u32) { - info!("irq_disable"); - if let Some(x) = get_ioapic(irq) { - let mut ioapic = ioapic_controller(&x); - ioapic.disable((irq - x.global_system_interrupt_base) as u8); - } -} - -#[export_name = "hal_irq_configure"] -pub fn irq_configure(vector: u32, trig_mode: bool, polarity: bool) -> bool { - info!( - "irq_configure: vector={:#x?}, trig_mode={:#x?}, polarity={:#x?}", - vector, trig_mode, polarity - ); - let dest = super::apic_local_id(); - get_ioapic(vector) - .map(|x| { - let mut ioapic = ioapic_controller(&x); - ioapic.config( - (vector - x.global_system_interrupt_base) as u8, - 0, - dest, - trig_mode, - polarity, - false, /* physical */ - true, /* mask */ - ); - }) - .is_some() -} - -fn ioapic_maxinstr(ioapic_addr: u32) -> Option { - let mut table = MAX_INSTR_TABLE.lock(); - for (addr, v) in table.iter() { - if *addr == ioapic_addr as usize { - return Some(*v); - } - } - let mut ioapic = unsafe { IoApic::new(phys_to_virt(ioapic_addr as usize)) }; - let v = ioapic.maxintr(); - table.push((ioapic_addr as usize, v)); - Some(v) -} - -lazy_static! { - static ref MAX_INSTR_TABLE: Mutex> = Mutex::default(); -} - -#[export_name = "hal_irq_isvalid"] -pub fn is_valid_irq(irq: u32) -> bool { - trace!("irq_is_valid: irq={:#x?}", irq); - get_ioapic(irq).is_some() -} - -fn breakpoint() { - panic!("\nEXCEPTION: Breakpoint"); -} - -fn double_fault(tf: &TrapFrame) { - panic!("\nEXCEPTION: Double Fault\n{:#x?}", tf); -} - -fn page_fault(tf: &mut TrapFrame) { - panic!("\nEXCEPTION: Page Fault\n{:#x?}", tf); -} - -fn timer() { - super::timer_tick(); -} - -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); - } - } - } - } -} - -// Reference: https://wiki.osdev.org/Exceptions -const DivideError: u8 = 0; -const Debug: u8 = 1; -const NonMaskableInterrupt: u8 = 2; -const Breakpoint: u8 = 3; -const Overflow: u8 = 4; -const BoundRangeExceeded: u8 = 5; -const InvalidOpcode: u8 = 6; -const DeviceNotAvailable: u8 = 7; -const DoubleFault: u8 = 8; -const CoprocessorSegmentOverrun: u8 = 9; -const InvalidTSS: u8 = 10; -const SegmentNotPresent: u8 = 11; -const StackSegmentFault: u8 = 12; -const GeneralProtectionFault: u8 = 13; -const PageFault: u8 = 14; -const FloatingPointException: u8 = 16; -const AlignmentCheck: u8 = 17; -const MachineCheck: u8 = 18; -const SIMDFloatingPointException: u8 = 19; -const VirtualizationException: u8 = 20; -const SecurityException: u8 = 30; - -const IRQ0: u8 = 32; - -// IRQ -const Timer: u8 = 0; -const Keyboard: u8 = 1; -const COM2: u8 = 3; -const COM1: u8 = 4; -const Mouse: u8 = 12; -const IDE: u8 = 14; -const Error: u8 = 19; -const Spurious: u8 = 31; diff --git a/kernel-hal-bare/src/arch/x86_64/mod.rs b/kernel-hal-bare/src/arch/x86_64/mod.rs deleted file mode 100644 index 4b8d3bf46..000000000 --- a/kernel-hal-bare/src/arch/x86_64/mod.rs +++ /dev/null @@ -1,525 +0,0 @@ -use { - super::super::*, - acpi::{parse_rsdp, Acpi, AcpiHandler, PhysicalMapping}, - alloc::{collections::VecDeque, vec::Vec}, - apic::{LocalApic, XApic}, - core::arch::x86_64::{__cpuid, _mm_clflush, _mm_mfence}, - core::convert::TryFrom, - core::fmt::{Arguments, Write}, - core::ptr::NonNull, - core::time::Duration, - git_version::git_version, - kernel_hal::{ - ColorDepth, ColorFormat, FramebufferInfo, HalError, PageTableTrait, Result, FRAME_BUFFER, - }, - rcore_console::{Console, ConsoleOnGraphic, DrawTarget, Pixel, Rgb888, Size}, - spin::Mutex, - uart_16550::SerialPort, - x86_64::{ - instructions::port::Port, - registers::control::{Cr2, Cr3, Cr3Flags, Cr4, Cr4Flags}, - structures::paging::{PageTableFlags as PTF, *}, - }, -}; - -mod acpi_table; -mod interrupt; -mod keyboard; - -/// Page Table -#[repr(C)] -pub struct PageTableImpl { - root_paddr: PhysAddr, -} - -impl PageTableImpl { - #[export_name = "hal_pt_current"] - pub fn current() -> Self { - PageTableImpl { - root_paddr: Cr3::read().0.start_address().as_u64() as _, - } - } - - /// 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(); - map_kernel(root_vaddr as _, frame_to_page_table(Cr3::read().0) as _); - trace!("create page table @ {:#x}", root_frame.paddr); - PageTableImpl { - root_paddr: root_frame.paddr, - } - } - - fn get(&mut self) -> OffsetPageTable<'_> { - let root_vaddr = phys_to_virt(self.root_paddr); - let root = unsafe { &mut *(root_vaddr as *mut PageTable) }; - let offset = x86_64::VirtAddr::new(phys_to_virt(0) as u64); - unsafe { OffsetPageTable::new(root, offset) } - } -} - -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<()> { - let mut pt = self.get(); - unsafe { - pt.map_to_with_table_flags( - Page::::from_start_address(x86_64::VirtAddr::new(vaddr as u64)).unwrap(), - PhysFrame::from_start_address(x86_64::PhysAddr::new(paddr as u64)).unwrap(), - flags.to_ptf(), - PTF::PRESENT | PTF::WRITABLE | PTF::USER_ACCESSIBLE, - &mut FrameAllocatorImpl, - ) - .unwrap() - .flush(); - }; - debug!( - "map: {:x?} -> {:x?}, flags={:?} in {:#x?}", - vaddr, paddr, flags, self.root_paddr - ); - Ok(()) - } - - /// Unmap the page of `vaddr`. - #[export_name = "hal_pt_unmap"] - fn unmap(&mut self, vaddr: VirtAddr) -> Result<()> { - let mut pt = self.get(); - let page = - Page::::from_start_address(x86_64::VirtAddr::new(vaddr as u64)).unwrap(); - // This is a workaround to an issue in the x86-64 crate - // A page without PRESENT bit is not unmappable AND mapable - // So we add PRESENT bit here - unsafe { - pt.update_flags(page, PTF::PRESENT | PTF::NO_EXECUTE).ok(); - } - match pt.unmap(page) { - Ok((_, flush)) => { - flush.flush(); - trace!("unmap: {:x?} in {:#x?}", vaddr, self.root_paddr); - } - Err(mapper::UnmapError::PageNotMapped) => { - trace!( - "unmap not mapped, skip: {:x?} in {:#x?}", - vaddr, - self.root_paddr - ); - return Ok(()); - } - Err(err) => { - debug!( - "unmap failed: {:x?} err={:x?} in {:#x?}", - vaddr, err, self.root_paddr - ); - return Err(HalError); - } - } - Ok(()) - } - - /// Change the `flags` of the page of `vaddr`. - #[export_name = "hal_pt_protect"] - fn protect(&mut self, vaddr: VirtAddr, flags: MMUFlags) -> Result<()> { - let mut pt = self.get(); - let page = - Page::::from_start_address(x86_64::VirtAddr::new(vaddr as u64)).unwrap(); - if let Ok(flush) = unsafe { pt.update_flags(page, flags.to_ptf()) } { - flush.flush(); - } - trace!("protect: {:x?}, flags={:?}", 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 { - let pt = self.get(); - let ret = pt - .translate_addr(x86_64::VirtAddr::new(vaddr as u64)) - .map(|addr| addr.as_u64() as PhysAddr) - .ok_or(HalError); - trace!("query: {:x?} => {:x?}", vaddr, ret); - ret - } - - /// 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) { - // unimplemented!() - // } -} - -/// Set page table. -/// -/// # Safety -/// This function will set CR3 to `vmtoken`. -pub unsafe fn set_page_table(vmtoken: usize) { - let frame = PhysFrame::containing_address(x86_64::PhysAddr::new(vmtoken as _)); - if Cr3::read().0 == frame { - return; - } - Cr3::write(frame, Cr3Flags::empty()); - debug!("set page_table @ {:#x}", vmtoken); -} - -fn frame_to_page_table(frame: PhysFrame) -> *mut PageTable { - let vaddr = phys_to_virt(frame.start_address().as_u64() as usize); - vaddr as *mut PageTable -} - -trait FlagsExt { - fn to_ptf(self) -> PTF; -} - -impl FlagsExt for MMUFlags { - fn to_ptf(self) -> PTF { - let mut flags = PTF::empty(); - if self.contains(MMUFlags::READ) { - flags |= PTF::PRESENT; - } - if self.contains(MMUFlags::WRITE) { - flags |= PTF::WRITABLE; - } - if !self.contains(MMUFlags::EXECUTE) { - flags |= PTF::NO_EXECUTE; - } - if self.contains(MMUFlags::USER) { - flags |= PTF::USER_ACCESSIBLE; - } - let cache_policy = (self.bits() & 3) as u32; // 最低三位用于储存缓存策略 - match CachePolicy::try_from(cache_policy) { - Ok(CachePolicy::Cached) => { - flags.remove(PTF::WRITE_THROUGH); - } - Ok(CachePolicy::Uncached) | Ok(CachePolicy::UncachedDevice) => { - flags |= PTF::NO_CACHE | PTF::WRITE_THROUGH; - } - Ok(CachePolicy::WriteCombining) => { - flags |= PTF::NO_CACHE | PTF::WRITE_THROUGH; - // 当位于level=1时,页面更大,在1<<12位上(0x100)为1 - // 但是bitflags里面没有这一位。由页表自行管理标记位去吧 - } - Err(_) => unreachable!("invalid cache policy"), - } - flags - } -} - -struct FrameAllocatorImpl; - -unsafe impl FrameAllocator for FrameAllocatorImpl { - fn allocate_frame(&mut self) -> Option { - Frame::alloc().map(|f| { - let paddr = x86_64::PhysAddr::new(f.paddr as u64); - PhysFrame::from_start_address(paddr).unwrap() - }) - } -} - -impl FrameDeallocator for FrameAllocatorImpl { - unsafe fn deallocate_frame(&mut self, frame: PhysFrame) { - Frame { - paddr: frame.start_address().as_u64() as usize, - } - .dealloc() - } -} - -static CONSOLE: Mutex>> = Mutex::new(None); - -struct Framebuffer { - width: u32, - height: u32, - buf: &'static mut [u32], -} - -impl DrawTarget for Framebuffer { - type Error = core::convert::Infallible; - - fn draw_pixel(&mut self, item: Pixel) -> core::result::Result<(), Self::Error> { - let idx = (item.0.x as u32 + item.0.y as u32 * self.width) as usize; - self.buf[idx] = unsafe { core::mem::transmute(item.1) }; - Ok(()) - } - - fn size(&self) -> Size { - Size::new(self.width, self.height) - } -} - -/// Initialize console on framebuffer. -pub fn init_framebuffer(width: u32, height: u32, addr: usize, size: usize) { - let vaddr = phys_to_virt(addr); - 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: addr, - vaddr, - screen_size: size, - }; - *FRAME_BUFFER.write() = Some(fb_info); - let console = Console::on_frame_buffer(Framebuffer { - width, - height, - buf: unsafe { - core::slice::from_raw_parts_mut(vaddr as *mut u32, (width * height) as usize) - }, - }); - *CONSOLE.lock() = Some(console); -} - -static COM1: Mutex = Mutex::new(unsafe { SerialPort::new(0x3F8) }); - -pub fn putfmt(fmt: Arguments) { - COM1.lock().write_fmt(fmt).unwrap(); - if let Some(console) = CONSOLE.lock().as_mut() { - console.write_fmt(fmt).unwrap(); - } -} - -lazy_static! { - static ref STDIN: Mutex> = Mutex::new(VecDeque::new()); - static ref STDIN_CALLBACK: Mutex 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(x); - STDIN_CALLBACK.lock().retain(|f| !f()); -} - -#[export_name = "hal_serial_set_callback"] -pub fn serial_set_callback(callback: Box 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 serial_write(s: &str) { - putfmt(format_args!("{}", s)); -} - -/// Get TSC frequency. -/// -/// WARN: This will be very slow on virtual machine since it uses CPUID instruction. -fn tsc_frequency() -> u16 { - const DEFAULT: u16 = 2600; - if let Some(info) = raw_cpuid::CpuId::new().get_processor_frequency_info() { - let f = info.processor_base_frequency(); - return if f == 0 { DEFAULT } else { f }; - } - // FIXME: QEMU, AMD, VirtualBox - DEFAULT -} - -#[export_name = "hal_timer_now"] -pub fn timer_now() -> Duration { - let tsc = unsafe { core::arch::x86_64::_rdtsc() }; - Duration::from_nanos(tsc * 1000 / unsafe { TSC_FREQUENCY } as u64) -} - -fn timer_init() { - let mut lapic = unsafe { XApic::new(phys_to_virt(LAPIC_ADDR)) }; - lapic.cpu_init(); -} - -#[export_name = "hal_apic_local_id"] -pub fn apic_local_id() -> u8 { - let lapic = unsafe { XApic::new(phys_to_virt(LAPIC_ADDR)) }; - lapic.id() as u8 -} - -const LAPIC_ADDR: usize = 0xfee0_0000; -const IOAPIC_ADDR: usize = 0xfec0_0000; - -#[export_name = "hal_vdso_constants"] -fn vdso_constants() -> VdsoConstants { - let tsc_frequency = unsafe { TSC_FREQUENCY }; - let mut constants = VdsoConstants { - max_num_cpus: 1, - features: Features { - cpu: 0, - hw_breakpoint_count: 0, - hw_watchpoint_count: 0, - }, - dcache_line_size: 0, - icache_line_size: 0, - ticks_per_second: tsc_frequency as u64 * 1_000_000, - ticks_to_mono_numerator: 1000, - ticks_to_mono_denominator: tsc_frequency as u32, - physmem: 0, - version_string_len: 0, - version_string: Default::default(), - }; - constants.set_version_string(git_version!( - prefix = "git-", - args = ["--always", "--abbrev=40", "--dirty=-dirty"] - )); - constants -} - -/// Initialize the HAL. -pub fn init(config: Config) { - timer_init(); - interrupt::init(); - COM1.lock().init(); - unsafe { - // enable global page - Cr4::update(|f| f.insert(Cr4Flags::PAGE_GLOBAL)); - // store config - CONFIG = config; - // get tsc frequency - TSC_FREQUENCY = tsc_frequency(); - - // start multi-processors - fn ap_main() { - info!("processor {} started", apic_local_id()); - unsafe { - trapframe::init(); - } - timer_init(); - let ap_fn = unsafe { CONFIG.ap_fn }; - ap_fn() - } - fn stack_fn(pid: usize) -> usize { - // split and reuse the current stack - unsafe { - let mut stack: usize; - asm!("mov {}, rsp", out(reg) stack); - stack -= 0x4000 * pid; - stack - } - } - x86_smpboot::start_application_processors(ap_main, stack_fn, phys_to_virt); - } -} - -/// Configuration of HAL. -pub struct Config { - pub acpi_rsdp: u64, - pub smbios: u64, - pub ap_fn: fn() -> !, -} - -#[export_name = "fetch_fault_vaddr"] -pub fn fetch_fault_vaddr() -> VirtAddr { - Cr2::read().as_u64() as _ -} - -/// Get physical address of `acpi_rsdp` and `smbios` on x86_64. -#[export_name = "hal_pc_firmware_tables"] -pub fn pc_firmware_tables() -> (u64, u64) { - unsafe { (CONFIG.acpi_rsdp, CONFIG.smbios) } -} - -static mut CONFIG: Config = Config { - acpi_rsdp: 0, - smbios: 0, - ap_fn: || unreachable!(), -}; - -static mut TSC_FREQUENCY: u16 = 2600; - -/// Build ACPI Table -struct AcpiHelper {} -impl AcpiHandler for AcpiHelper { - unsafe fn map_physical_region( - &mut self, - physical_address: usize, - size: usize, - ) -> PhysicalMapping { - #[allow(non_snake_case)] - let OFFSET = 0; - let page_start = physical_address / PAGE_SIZE; - let page_end = (physical_address + size + PAGE_SIZE - 1) / PAGE_SIZE; - PhysicalMapping:: { - physical_start: physical_address, - virtual_start: NonNull::new_unchecked(phys_to_virt(physical_address + OFFSET) as *mut T), - mapped_length: size, - region_length: PAGE_SIZE * (page_end - page_start), - } - } - fn unmap_physical_region(&mut self, _region: PhysicalMapping) {} -} - -#[export_name = "hal_acpi_table"] -pub fn get_acpi_table() -> Option { - #[cfg(target_arch = "x86_64")] - { - let mut handler = AcpiHelper {}; - match unsafe { parse_rsdp(&mut handler, pc_firmware_tables().0 as usize) } { - Ok(table) => Some(table), - Err(info) => { - warn!("get_acpi_table error: {:#x?}", info); - None - } - } - } - #[cfg(not(target_arch = "x86_64"))] - None -} - -/// IO Port in/out instruction -#[export_name = "hal_outpd"] -pub fn outpd(port: u16, value: u32) { - unsafe { - Port::new(port).write(value); - } -} - -#[export_name = "hal_inpd"] -pub fn inpd(port: u16) -> u32 { - unsafe { Port::new(port).read() } -} - -/// Flush the physical frame. -#[export_name = "hal_frame_flush"] -pub fn frame_flush(target: PhysAddr) { - unsafe { - for paddr in (target..target + PAGE_SIZE).step_by(cacheline_size()) { - _mm_clflush(phys_to_virt(paddr) as *const u8); - } - _mm_mfence(); - } -} - -/// Get cache line size in bytes. -fn cacheline_size() -> usize { - let leaf = unsafe { __cpuid(1).ebx }; - (((leaf >> 8) & 0xff) << 3) as usize -} - -#[export_name = "hal_current_pgtable"] -pub fn current_page_table() -> usize { - PageTableImpl::current().root_paddr -} diff --git a/kernel-hal-bare/src/lib.rs b/kernel-hal-bare/src/lib.rs deleted file mode 100644 index 2851eeb49..000000000 --- a/kernel-hal-bare/src/lib.rs +++ /dev/null @@ -1,252 +0,0 @@ -//! Zircon HAL implementation for bare metal environment. -//! -//! This crate implements the following interfaces: -//! - `hal_pt_new` -//! - `hal_pt_map` -//! - `hal_pt_unmap` -//! - `hal_pt_protect` -//! - `hal_pt_query` -//! - `hal_pmem_read` -//! - `hal_pmem_write` -//! -//! And you have to implement these interfaces in addition: -//! - `hal_pt_map_kernel` -//! - `hal_pmem_base` - -#![no_std] -#![feature(asm)] -#![feature(llvm_asm)] -#![feature(global_asm)] -#![feature(linkage)] -//#![deny(warnings)] - -#[macro_use] -extern crate log; - -extern crate alloc; - -#[macro_use] -extern crate lazy_static; - -use alloc::boxed::Box; -use core::time::Duration; -use core::{ - future::Future, - pin::Pin, - task::{Context, Poll}, -}; -use kernel_hal::defs::*; -use kernel_hal::vdso::*; -use kernel_hal::UserContext; -use naive_timer::Timer; -use spin::Mutex; - -pub mod arch; -pub mod drivers; - -pub use self::arch::*; - -#[allow(improper_ctypes)] -extern "C" { - fn hal_pt_map_kernel(pt: *mut u8, current: *const u8); - fn frame_alloc() -> Option; - fn hal_frame_alloc_contiguous(page_num: usize, align_log2: usize) -> Option; - fn frame_dealloc(paddr: &usize); - #[link_name = "hal_pmem_base"] - static PMEM_BASE: usize; -} - -#[repr(C)] -pub struct Thread { - thread: usize, -} - -impl Thread { - #[export_name = "hal_thread_spawn"] - pub fn spawn( - future: Pin + Send + 'static>>, - vmtoken: usize, - ) -> Self { - struct PageTableSwitchWrapper { - inner: Mutex + Send>>>, - vmtoken: usize, - } - impl Future for PageTableSwitchWrapper { - type Output = (); - fn poll(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll { - unsafe { - arch::set_page_table(self.vmtoken); - } - self.inner.lock().as_mut().poll(cx) - } - } - - executor::spawn(PageTableSwitchWrapper { - inner: Mutex::new(future), - vmtoken, - }); - - Thread { thread: 0 } - } - - #[export_name = "hal_thread_set_tid"] - pub fn set_tid(_tid: u64, _pid: u64) {} - - #[export_name = "hal_thread_get_tid"] - pub fn get_tid() -> (u64, u64) { - (0, 0) - } -} - -#[export_name = "hal_context_run"] -pub fn context_run(context: &mut UserContext) { - context.run(); -} - -/// Map kernel for the new page table. -/// -/// `pt` is a page-aligned pointer to the root page table. -#[allow(clippy::not_unsafe_ptr_arg_deref)] -pub fn map_kernel(pt: *mut u8, current: *const u8) { - unsafe { - hal_pt_map_kernel(pt, current); - } -} - -#[repr(C)] -pub struct Frame { - paddr: PhysAddr, -} - -impl Frame { - #[export_name = "hal_frame_alloc"] - pub fn alloc() -> Option { - unsafe { frame_alloc().map(|paddr| Frame { paddr }) } - } - - #[export_name = "hal_frame_dealloc"] - pub fn dealloc(&mut self) { - unsafe { - frame_dealloc(&self.paddr); - } - } - - #[export_name = "hal_zero_frame_paddr"] - pub fn zero_frame_addr() -> PhysAddr { - #[repr(align(0x1000))] - struct Page([u8; PAGE_SIZE]); - static ZERO_PAGE: Page = Page([0u8; PAGE_SIZE]); - unsafe { ZERO_PAGE.0.as_ptr() as usize - PMEM_BASE } - } -} - -pub fn phys_to_virt(paddr: PhysAddr) -> VirtAddr { - unsafe { PMEM_BASE + paddr } -} - -pub fn virt_to_phys(vaddr: VirtAddr) -> PhysAddr { - unsafe { vaddr - PMEM_BASE } -} - -/// Read physical memory from `paddr` to `buf`. -#[export_name = "hal_pmem_read"] -pub fn pmem_read(paddr: PhysAddr, buf: &mut [u8]) { - trace!("pmem_read: addr={:#x}, len={:#x}", paddr, buf.len()); - unsafe { - (phys_to_virt(paddr) as *const u8).copy_to_nonoverlapping(buf.as_mut_ptr(), buf.len()); - } -} - -/// Write physical memory to `paddr` from `buf`. -#[export_name = "hal_pmem_write"] -pub fn pmem_write(paddr: PhysAddr, buf: &[u8]) { - trace!( - "pmem_write: addr={:#x}, len={:#x}, vaddr = {:#x}", - paddr, - buf.len(), - phys_to_virt(paddr) - ); - unsafe { - buf.as_ptr() - .copy_to_nonoverlapping(phys_to_virt(paddr) as _, buf.len()); - } -} - -/// Zero physical memory at `[paddr, paddr + len)` -#[export_name = "hal_pmem_zero"] -pub fn pmem_zero(paddr: PhysAddr, len: usize) { - trace!("pmem_zero: addr={:#x}, len={:#x}", paddr, len); - unsafe { - core::ptr::write_bytes(phys_to_virt(paddr) as *mut u8, 0, len); - } -} - -/// Copy content of `src` frame to `target` frame -#[export_name = "hal_frame_copy"] -pub fn frame_copy(src: PhysAddr, target: PhysAddr) { - trace!("frame_copy: {:#x} <- {:#x}", target, src); - unsafe { - let buf = phys_to_virt(src) as *const u8; - buf.copy_to_nonoverlapping(phys_to_virt(target) as _, PAGE_SIZE); - } -} - -/// Zero `target` frame. -#[export_name = "hal_frame_zero"] -pub fn frame_zero_in_range(target: PhysAddr, start: usize, end: usize) { - assert!(start < PAGE_SIZE && end <= PAGE_SIZE); - trace!("frame_zero: {:#x?}", target); - unsafe { - core::ptr::write_bytes(phys_to_virt(target + start) as *mut u8, 0, end - start); - } -} - -lazy_static! { - pub static ref NAIVE_TIMER: Mutex = Mutex::new(Timer::default()); -} - -#[export_name = "hal_timer_set"] -pub fn timer_set(deadline: Duration, callback: Box) { - NAIVE_TIMER.lock().add(deadline, callback); -} - -#[export_name = "hal_timer_tick"] -pub fn timer_tick() { - let now = arch::timer_now(); - NAIVE_TIMER.lock().expire(now); -} - -/// Initialize the HAL. -pub fn init(config: Config) { - unsafe { - trapframe::init(); - } - - #[cfg(target_arch = "riscv64")] - trace!("hal dtb: {:#x}", config.dtb); - - arch::init(config); -} - -#[cfg(test)] -mod tests { - use super::*; - - #[no_mangle] - extern "C" fn hal_pt_map_kernel(_pt: *mut u8, _current: *const u8) { - unimplemented!() - } - - #[no_mangle] - extern "C" fn hal_frame_alloc() -> Option { - unimplemented!() - } - - #[no_mangle] - extern "C" fn hal_frame_dealloc(_paddr: &PhysAddr) { - unimplemented!() - } - - #[export_name = "hal_pmem_base"] - static PMEM_BASE: usize = 0; -} diff --git a/kernel-hal-unix/Cargo.toml b/kernel-hal-unix/Cargo.toml deleted file mode 100644 index 057bc1414..000000000 --- a/kernel-hal-unix/Cargo.toml +++ /dev/null @@ -1,19 +0,0 @@ -[package] -name = "kernel-hal-unix" -version = "0.1.0" -authors = ["Runji Wang "] -edition = "2018" -description = "Kernel HAL implementation on Linux and macOS." - -# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html - -[dependencies] -log = "0.4" -libc = "0.2" -tempfile = "3" -bitflags = "1.2" -lazy_static = "1.4" -kernel-hal = { path = "../kernel-hal" } -async-std = "1.9" -git-version = "0.3" -trapframe = "0.8.0" diff --git a/kernel-hal-unix/src/lib.rs b/kernel-hal-unix/src/lib.rs deleted file mode 100644 index 84e095372..000000000 --- a/kernel-hal-unix/src/lib.rs +++ /dev/null @@ -1,676 +0,0 @@ -#![feature(asm)] -#![feature(linkage)] -#![deny(warnings)] - -#[macro_use] -extern crate log; - -extern crate alloc; - -use { - alloc::collections::VecDeque, - async_std::task_local, - core::{cell::Cell, future::Future, pin::Pin}, - git_version::git_version, - kernel_hal::PageTableTrait, - lazy_static::lazy_static, - std::fmt::{Debug, Formatter}, - std::fs::{File, OpenOptions}, - std::io::Error, - std::os::unix::io::AsRawFd, - std::sync::Mutex, - std::time::{Duration, SystemTime}, - tempfile::tempdir, -}; - -pub use kernel_hal::defs::*; -use kernel_hal::vdso::*; -pub use kernel_hal::*; -use std::io::Read; -pub use trapframe::syscall_fn_entry as syscall_entry; - -#[cfg(target_os = "macos")] -include!("macos.rs"); - -#[repr(C)] -pub struct Thread { - thread: usize, -} - -impl Thread { - #[export_name = "hal_thread_spawn"] - pub fn spawn( - future: Pin + Send + 'static>>, - _vmtoken: usize, - ) -> Self { - async_std::task::spawn(future); - Thread { thread: 0 } - } - - #[export_name = "hal_thread_set_tid"] - pub fn set_tid(tid: u64, pid: u64) { - TID.with(|x| x.set(tid)); - PID.with(|x| x.set(pid)); - } - - #[export_name = "hal_thread_get_tid"] - pub fn get_tid() -> (u64, u64) { - (TID.with(|x| x.get()), PID.with(|x| x.get())) - } -} - -task_local! { - static TID: Cell = Cell::new(0); - static PID: Cell = Cell::new(0); -} - -#[export_name = "hal_context_run"] -unsafe fn context_run(context: &mut UserContext) { - context.run_fncall(); -} - -/// Page Table -#[repr(C)] -pub struct PageTable { - table_phys: PhysAddr, -} - -impl PageTable { - /// Create a new `PageTable`. - #[allow(clippy::new_without_default)] - #[export_name = "hal_pt_new"] - pub fn new() -> Self { - PageTable { table_phys: 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<()> { - debug_assert!(page_aligned(vaddr)); - debug_assert!(page_aligned(paddr)); - let prot = flags.to_mmap_prot(); - mmap(FRAME_FILE.as_raw_fd(), paddr, PAGE_SIZE, vaddr, prot); - Ok(()) - } - - /// Unmap the page of `vaddr`. - #[export_name = "hal_pt_unmap"] - fn unmap(&mut self, vaddr: VirtAddr) -> Result<()> { - self.unmap_cont(vaddr, 1) - } - - /// Change the `flags` of the page of `vaddr`. - #[export_name = "hal_pt_protect"] - fn protect(&mut self, vaddr: VirtAddr, flags: MMUFlags) -> Result<()> { - debug_assert!(page_aligned(vaddr)); - let prot = flags.to_mmap_prot(); - let ret = unsafe { libc::mprotect(vaddr as _, PAGE_SIZE, prot) }; - assert_eq!(ret, 0, "failed to mprotect: {:?}", Error::last_os_error()); - Ok(()) - } - - /// Query the physical address which the page of `vaddr` maps to. - #[export_name = "hal_pt_query"] - fn query(&mut self, vaddr: VirtAddr) -> Result { - debug_assert!(page_aligned(vaddr)); - unimplemented!() - } - - /// Get the physical address of root page table. - #[export_name = "hal_pt_table_phys"] - fn table_phys(&self) -> PhysAddr { - self.table_phys - } - - #[export_name = "hal_pt_unmap_cont"] - fn unmap_cont(&mut self, vaddr: VirtAddr, pages: usize) -> Result<()> { - if pages == 0 { - return Ok(()); - } - debug_assert!(page_aligned(vaddr)); - let ret = unsafe { libc::munmap(vaddr as _, PAGE_SIZE * pages) }; - assert_eq!(ret, 0, "failed to munmap: {:?}", Error::last_os_error()); - Ok(()) - } -} - -#[repr(C)] -pub struct PhysFrame { - paddr: PhysAddr, -} - -impl Debug for PhysFrame { - fn fmt(&self, f: &mut Formatter<'_>) -> core::result::Result<(), std::fmt::Error> { - write!(f, "PhysFrame({:#x})", self.paddr) - } -} - -lazy_static! { - static ref AVAILABLE_FRAMES: Mutex> = - Mutex::new((PAGE_SIZE..PMEM_SIZE).step_by(PAGE_SIZE).collect()); -} - -impl PhysFrame { - #[export_name = "hal_frame_alloc"] - pub fn alloc() -> Option { - let ret = AVAILABLE_FRAMES - .lock() - .unwrap() - .pop_front() - .map(|paddr| PhysFrame { paddr }); - trace!("frame alloc: {:?}", ret); - ret - } - #[export_name = "hal_zero_frame_paddr"] - pub fn zero_frame_addr() -> PhysAddr { - 0 - } -} - -impl Drop for PhysFrame { - #[export_name = "hal_frame_dealloc"] - fn drop(&mut self) { - trace!("frame dealloc: {:?}", self); - AVAILABLE_FRAMES.lock().unwrap().push_back(self.paddr); - } -} - -fn phys_to_virt(paddr: PhysAddr) -> VirtAddr { - /// Map physical memory from here. - const PMEM_BASE: VirtAddr = 0x8_0000_0000; - - PMEM_BASE + paddr -} - -/// Ensure physical memory are mmapped and accessible. -fn ensure_mmap_pmem() { - FRAME_FILE.as_raw_fd(); -} - -/// Read physical memory from `paddr` to `buf`. -#[export_name = "hal_pmem_read"] -pub fn pmem_read(paddr: PhysAddr, buf: &mut [u8]) { - trace!("pmem read: paddr={:#x}, len={:#x}", paddr, buf.len()); - assert!(paddr + buf.len() <= PMEM_SIZE); - ensure_mmap_pmem(); - unsafe { - (phys_to_virt(paddr) as *const u8).copy_to_nonoverlapping(buf.as_mut_ptr(), buf.len()); - } -} - -/// Write physical memory to `paddr` from `buf`. -#[export_name = "hal_pmem_write"] -pub fn pmem_write(paddr: PhysAddr, buf: &[u8]) { - trace!("pmem write: paddr={:#x}, len={:#x}", paddr, buf.len()); - assert!(paddr + buf.len() <= PMEM_SIZE); - ensure_mmap_pmem(); - unsafe { - buf.as_ptr() - .copy_to_nonoverlapping(phys_to_virt(paddr) as _, buf.len()); - } -} - -/// Zero physical memory at `[paddr, paddr + len)` -#[export_name = "hal_pmem_zero"] -pub fn pmem_zero(paddr: PhysAddr, len: usize) { - trace!("pmem_zero: addr={:#x}, len={:#x}", paddr, len); - assert!(paddr + len <= PMEM_SIZE); - ensure_mmap_pmem(); - unsafe { - core::ptr::write_bytes(phys_to_virt(paddr) as *mut u8, 0, len); - } -} - -/// Copy content of `src` frame to `target` frame -#[export_name = "hal_frame_copy"] -pub fn frame_copy(src: PhysAddr, target: PhysAddr) { - trace!("frame_copy: {:#x} <- {:#x}", target, src); - assert!(src + PAGE_SIZE <= PMEM_SIZE && target + PAGE_SIZE <= PMEM_SIZE); - ensure_mmap_pmem(); - unsafe { - let buf = phys_to_virt(src) as *const u8; - buf.copy_to_nonoverlapping(phys_to_virt(target) as _, PAGE_SIZE); - } -} - -/// Flush the physical frame. -#[export_name = "hal_frame_flush"] -pub fn frame_flush(_target: PhysAddr) { - // do nothing -} - -const PAGE_SIZE: usize = 0x1000; - -fn page_aligned(x: VirtAddr) -> bool { - x % PAGE_SIZE == 0 -} - -const PMEM_SIZE: usize = 0x4000_0000; // 1GiB - -lazy_static! { - static ref FRAME_FILE: File = create_pmem_file(); -} - -fn create_pmem_file() -> File { - let dir = tempdir().expect("failed to create pmem dir"); - let path = dir.path().join("pmem"); - - // workaround on macOS to avoid permission denied. - // see https://jiege.ch/software/2020/02/07/macos-mmap-exec/ for analysis on this problem. - #[cfg(target_os = "macos")] - std::mem::forget(dir); - - let file = OpenOptions::new() - .read(true) - .write(true) - .create(true) - .open(&path) - .expect("failed to create pmem file"); - file.set_len(PMEM_SIZE as u64) - .expect("failed to resize file"); - trace!("create pmem file: path={:?}, size={:#x}", path, PMEM_SIZE); - let prot = libc::PROT_READ | libc::PROT_WRITE; - mmap(file.as_raw_fd(), 0, PMEM_SIZE, phys_to_virt(0), prot); - file -} - -/// Mmap frame file `fd` to `vaddr`. -fn mmap(fd: libc::c_int, offset: usize, len: usize, vaddr: VirtAddr, prot: libc::c_int) { - // workaround on macOS to write text section. - #[cfg(target_os = "macos")] - let prot = if prot & libc::PROT_EXEC != 0 { - prot | libc::PROT_WRITE - } else { - prot - }; - - let ret = unsafe { - let flags = libc::MAP_SHARED | libc::MAP_FIXED; - libc::mmap(vaddr as _, len, prot, flags, fd, offset as _) - } as usize; - trace!( - "mmap file: fd={}, offset={:#x}, len={:#x}, vaddr={:#x}, prot={:#b}", - fd, - offset, - len, - vaddr, - prot, - ); - assert_eq!(ret, vaddr, "failed to mmap: {:?}", Error::last_os_error()); -} - -trait FlagsExt { - fn to_mmap_prot(&self) -> libc::c_int; -} - -impl FlagsExt for MMUFlags { - fn to_mmap_prot(&self) -> libc::c_int { - let mut flags = 0; - if self.contains(MMUFlags::READ) { - flags |= libc::PROT_READ; - } - if self.contains(MMUFlags::WRITE) { - flags |= libc::PROT_WRITE; - } - if self.contains(MMUFlags::EXECUTE) { - flags |= libc::PROT_EXEC; - } - flags - } -} - -lazy_static! { - static ref STDIN: Mutex> = Mutex::new(VecDeque::new()); - static ref STDIN_CALLBACK: Mutex bool + Send + Sync>>> = - Mutex::new(Vec::new()); -} - -/// Put a char by serial interrupt handler. -fn serial_put(x: u8) { - STDIN.lock().unwrap().push_back(x); - STDIN_CALLBACK.lock().unwrap().retain(|f| !f()); -} - -#[export_name = "hal_serial_set_callback"] -pub fn serial_set_callback(callback: Box bool + Send + Sync>) { - STDIN_CALLBACK.lock().unwrap().push(callback); -} - -#[export_name = "hal_serial_read"] -pub fn serial_read(buf: &mut [u8]) -> usize { - let mut stdin = STDIN.lock().unwrap(); - let len = stdin.len().min(buf.len()); - for c in &mut buf[..len] { - *c = stdin.pop_front().unwrap(); - } - len -} - -/// Output a char to console. -#[export_name = "hal_serial_write"] -pub fn serial_write(s: &str) { - eprint!("{}", s); -} - -/// Get current time. -#[export_name = "hal_timer_now"] -pub fn timer_now() -> Duration { - SystemTime::now() - .duration_since(SystemTime::UNIX_EPOCH) - .unwrap() -} - -/// Set a new timer. -/// -/// After `deadline`, the `callback` will be called. -#[export_name = "hal_timer_set"] -pub fn timer_set(deadline: Duration, callback: Box) { - std::thread::spawn(move || { - let now = timer_now(); - if deadline > now { - std::thread::sleep(deadline - now); - } - callback(timer_now()); - }); -} - -#[export_name = "hal_vdso_constants"] -pub fn vdso_constants() -> VdsoConstants { - let tsc_frequency = 3000u16; - let mut constants = VdsoConstants { - max_num_cpus: 1, - features: Features { - cpu: 0, - hw_breakpoint_count: 0, - hw_watchpoint_count: 0, - }, - dcache_line_size: 0, - icache_line_size: 0, - ticks_per_second: tsc_frequency as u64 * 1_000_000, - ticks_to_mono_numerator: 1000, - ticks_to_mono_denominator: tsc_frequency as u32, - physmem: PMEM_SIZE as u64, - version_string_len: 0, - version_string: Default::default(), - }; - constants.set_version_string(git_version!( - prefix = "git-", - args = ["--always", "--abbrev=40", "--dirty=-dirty"] - )); - constants -} - -#[export_name = "hal_current_pgtable"] -pub fn current_page_table() -> usize { - 0 -} - -/// Initialize the HAL. -/// -/// This function must be called at the beginning. -pub fn init() { - #[cfg(target_os = "macos")] - unsafe { - register_sigsegv_handler(); - } - // spawn a thread to read stdin - // TODO: raw mode - std::thread::spawn(|| { - for i in std::io::stdin().bytes() { - serial_put(i.unwrap()); - } - }); -} - -pub fn init_framebuffer() { - const FBIOGET_VSCREENINFO: u64 = 0x4600; - const FBIOGET_FSCREENINFO: u64 = 0x4602; - - #[cfg(target_arch = "aarch64")] - let fbfd = unsafe { libc::open("/dev/fb0".as_ptr(), libc::O_RDWR) }; - #[cfg(not(target_arch = "aarch64"))] - let fbfd = unsafe { libc::open("/dev/fb0".as_ptr() as *const i8, libc::O_RDWR) }; - if fbfd < 0 { - return; - } - - #[repr(C)] - #[derive(Debug, Default)] - struct FbFixScreeninfo { - id: [u8; 16], - smem_start: u64, - smem_len: u32, - type_: u32, - type_aux: u32, - visual: u32, - xpanstep: u16, - ypanstep: u16, - ywrapstep: u16, - line_length: u32, - mmio_start: u64, - mmio_len: u32, - accel: u32, - capabilities: u16, - reserved: [u16; 2], - } - - impl FbFixScreeninfo { - pub fn size(&self) -> u32 { - self.smem_len - } - } - - #[repr(C)] - #[derive(Debug, Default)] - struct FbVarScreeninfo { - xres: u32, - yres: u32, - xres_virtual: u32, - yres_virtual: u32, - xoffset: u32, - yoffset: u32, - bits_per_pixel: u32, - grayscale: u32, - red: FbBitfield, - green: FbBitfield, - blue: FbBitfield, - transp: FbBitfield, - nonstd: u32, - activate: u32, - height: u32, - width: u32, - accel_flags: u32, - pixclock: u32, - left_margin: u32, - right_margin: u32, - upper_margin: u32, - lower_margin: u32, - hsync_len: u32, - vsync_len: u32, - sync: u32, - vmode: u32, - rotate: u32, - colorspace: u32, - reserved: [u32; 4], - } - - impl FbVarScreeninfo { - pub fn resolution(&self) -> (u32, u32) { - (self.xres, self.yres) - } - } - - #[repr(C)] - #[derive(Debug, Default)] - pub struct FbBitfield { - offset: u32, - length: u32, - msb_right: u32, - } - - let mut vinfo = FbVarScreeninfo::default(); - if unsafe { libc::ioctl(fbfd, FBIOGET_VSCREENINFO, &mut vinfo) } < 0 { - return; - } - - let mut finfo = FbFixScreeninfo::default(); - if unsafe { libc::ioctl(fbfd, FBIOGET_FSCREENINFO, &mut finfo) } < 0 { - return; - } - - let size = finfo.size() as usize; - let addr = unsafe { - libc::mmap( - std::ptr::null_mut::(), - size, - libc::PROT_READ | libc::PROT_WRITE, - libc::MAP_SHARED, - fbfd, - 0, - ) - }; - if (addr as isize) < 0 { - return; - } - - let (width, height) = vinfo.resolution(); - let addr = addr as 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), - paddr: addr, - vaddr: addr, - screen_size: size, - }; - *FRAME_BUFFER.write() = Some(fb_info); -} - -type MouseCallbackFn = dyn Fn([u8; 3]) + Send + Sync; -type KBDCallbackFn = dyn Fn(u16, i32) + Send + Sync; - -lazy_static! { - static ref MOUSE_CALLBACK: Mutex>> = Mutex::new(Vec::new()); - static ref KBD_CALLBACK: Mutex>> = Mutex::new(Vec::new()); -} - -#[export_name = "hal_mice_set_callback"] -pub fn mice_set_callback(callback: Box) { - MOUSE_CALLBACK.lock().unwrap().push(callback); -} - -#[export_name = "hal_kbd_set_callback"] -pub fn kbd_set_callback(callback: Box) { - KBD_CALLBACK.lock().unwrap().push(callback); -} - -fn init_kbd() { - let fd = std::fs::File::open("/dev/input/event1").expect("Failed to open input event device."); - // ?? - /* let inputfd = unsafe { - libc::open( - "/dev/input/event1".as_ptr() as *const i8, - libc::O_RDONLY /* | libc::O_NONBLOCK */, - ) - }; */ - if fd.as_raw_fd() < 0 { - return; - } - - #[repr(C)] - #[derive(Debug, Copy, Clone, Default)] - pub struct TimeVal { - pub sec: usize, - pub usec: usize, - } - #[repr(C)] - #[derive(Debug, Copy, Clone, Default)] - struct InputEvent { - time: TimeVal, - type_: u16, - code: u16, - value: i32, - } - - std::thread::spawn(move || { - use core::mem::{size_of, transmute, transmute_copy}; - let ev = InputEvent::default(); - const LEN: usize = size_of::(); - let mut buf: [u8; LEN] = unsafe { transmute(ev) }; - loop { - std::thread::sleep(std::time::Duration::from_millis(8)); - let ret = - unsafe { libc::read(fd.as_raw_fd(), buf.as_mut_ptr() as *mut libc::c_void, LEN) }; - if ret < 0 { - break; - } - let ev: InputEvent = unsafe { transmute_copy(&buf) }; - if ev.type_ == 1 { - KBD_CALLBACK.lock().unwrap().iter().for_each(|callback| { - callback(ev.code, ev.value); - }); - } - } - }); -} - -fn init_mice() { - let fd = std::fs::File::open("/dev/input/mice").expect("Failed to open input event device."); - if fd.as_raw_fd() < 0 { - return; - } - - std::thread::spawn(move || { - let mut buf = [0u8; 3]; - loop { - std::thread::sleep(std::time::Duration::from_millis(8)); - let ret = - unsafe { libc::read(fd.as_raw_fd(), buf.as_mut_ptr() as *mut libc::c_void, 3) }; - if ret < 0 { - break; - } - MOUSE_CALLBACK.lock().unwrap().iter().for_each(|callback| { - callback(buf); - }); - } - }); -} - -pub fn init_input() { - init_kbd(); - init_mice(); -} - -#[cfg(test)] -mod tests { - use super::*; - - /// A valid virtual address base to mmap. - const VBASE: VirtAddr = 0x2_00000000; - - #[test] - fn map_unmap() { - let mut pt = PageTable::new(); - let flags = MMUFlags::READ | MMUFlags::WRITE; - // map 2 pages to 1 frame - pt.map(VBASE, 0x1000, flags).unwrap(); - pt.map(VBASE + 0x1000, 0x1000, flags).unwrap(); - - unsafe { - const MAGIC: usize = 0xdead_beaf; - (VBASE as *mut usize).write(MAGIC); - assert_eq!(((VBASE + 0x1000) as *mut usize).read(), MAGIC); - } - - pt.unmap(VBASE + 0x1000).unwrap(); - } -} diff --git a/kernel-hal/Cargo.toml b/kernel-hal/Cargo.toml index 5262300ef..955ea312b 100644 --- a/kernel-hal/Cargo.toml +++ b/kernel-hal/Cargo.toml @@ -1,18 +1,56 @@ [package] name = "kernel-hal" version = "0.1.0" -authors = ["Runji Wang "] +authors = ["Runji Wang ", "Yuekai Jia "] edition = "2018" description = "Kernel HAL interface definations." # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html +[features] +libos = ["async-std"] +board_qemu = [] +board_d1 = [] + [dependencies] +log = "0.4" bitflags = "1.2" trapframe = "0.8.0" numeric-enum-macro = "0.2" -acpi = "1.1" spin = "0.7" +git-version = "0.3" +cfg-if = "1.0" +acpi = "1.1" + +# LibOS mode +[target.'cfg(not(target_os = "none"))'.dependencies] +riscv = { git = "https://github.com/rcore-os/riscv", features = ["inline-asm"], rev = "0074cbc" } +libc = "0.2" +tempfile = "3" +lazy_static = "1.4" +async-std = { version = "1.9", optional = true } + +# Bare-metal mode +[target.'cfg(target_os = "none")'.dependencies] +executor = { git = "https://github.com/rcore-os/executor.git", rev = "a2d02ee9" } +naive-timer = "0.2.0" +lazy_static = { version = "1.4", features = ["spin_no_std"] } +bitmap-allocator = { git = "https://github.com/rcore-os/bitmap-allocator", rev = "b3f9f51" } +# rcore-fs = { git = "https://github.com/rcore-os/rcore-fs", rev = "6df6cd2" } +# device_tree = { git = "https://github.com/rcore-os/device_tree-rs" } +# virtio-drivers = { git = "https://github.com/rcore-os/virtio-drivers", rev = "568276" } + +# Bare-metal mode on x86_64 +[target.'cfg(all(target_os = "none", target_arch = "x86_64"))'.dependencies] +x86_64 = "0.14" +uart_16550 = "=0.2.15" +raw-cpuid = "9.0" +apic = { git = "https://github.com/rcore-os/apic-rs", rev = "fb86bd7" } +x86-smpboot = { git = "https://github.com/rcore-os/x86-smpboot", rev = "43ffedf" } +# pc-keyboard = "0.5" +# rcore-console = { git = "https://github.com/rcore-os/rcore-console", default-features = false, rev = "a980897b" } +# ps2-mouse = { git = "https://github.com/YXL76/ps2-mouse", branch = "feat" } -#[patch.crates-io] -#trapframe = { path = "/home/xly/rust/arch-lib/trapframe-rs" } +# 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" } diff --git a/kernel-hal/src/bare/arch/riscv/config.rs b/kernel-hal/src/bare/arch/riscv/config.rs new file mode 100644 index 000000000..43aca0164 --- /dev/null +++ b/kernel-hal/src/bare/arch/riscv/config.rs @@ -0,0 +1,9 @@ +/// Configuration of HAL. +#[derive(Debug)] +pub struct KernelConfig { + pub kernel_offset: usize, + pub phys_mem_start: usize, + pub phys_mem_end: usize, + pub phys_to_virt_offset: usize, + pub dtb_paddr: usize, +} diff --git a/kernel-hal/src/bare/arch/riscv/consts.rs b/kernel-hal/src/bare/arch/riscv/consts.rs new file mode 100644 index 000000000..2bd9d4e70 --- /dev/null +++ b/kernel-hal/src/bare/arch/riscv/consts.rs @@ -0,0 +1,17 @@ +cfg_if! { + if #[cfg(feature = "board_qemu")] { + pub const UART_BASE: usize = 0x1000_0000; + pub const PLIC_BASE: usize = 0x0C00_0000; + pub const UART0_INT_NUM: u32 = 10; + } else if #[cfg(feature = "board_d1")] { + pub const UART_BASE: usize = 0x0250_0000; + pub const PLIC_BASE: usize = 0x1000_0000; + pub const UART0_INT_NUM: u32 = 18; + } +} + +pub const PLIC_PRIORITY: usize = PLIC_BASE + 0x0; +pub const PLIC_PENDING: usize = PLIC_BASE + 0x1000; +pub const PLIC_INT_ENABLE: usize = PLIC_BASE + 0x2080; +pub const PLIC_THRESHOLD: usize = PLIC_BASE + 0x20_1000; +pub const PLIC_CLAIM: usize = PLIC_BASE + 0x20_1004; diff --git a/kernel-hal/src/bare/arch/riscv/context.rs b/kernel-hal/src/bare/arch/riscv/context.rs new file mode 100644 index 000000000..ca7ea1de4 --- /dev/null +++ b/kernel-hal/src/bare/arch/riscv/context.rs @@ -0,0 +1,23 @@ +use riscv::register::scause::{Exception, Trap}; +use riscv::register::{scause, stval}; + +use crate::{MMUFlags, VirtAddr}; + +hal_fn_impl! { + impl mod crate::hal_fn::context { + fn fetch_trap_num(_context: &UserContext) -> usize { + scause::read().bits() + } + + fn fetch_page_fault_info(_scause: usize) -> (VirtAddr, MMUFlags) { + let fault_vaddr = stval::read() as _; + let flags = match scause::read().cause() { + Trap::Exception(Exception::LoadPageFault) => MMUFlags::READ, + Trap::Exception(Exception::StorePageFault) => MMUFlags::WRITE, + Trap::Exception(Exception::InstructionPageFault) => MMUFlags::EXECUTE, + _ => unreachable!(), + }; + (fault_vaddr, flags) + } + } +} diff --git a/kernel-hal/src/bare/arch/riscv/cpu.rs b/kernel-hal/src/bare/arch/riscv/cpu.rs new file mode 100644 index 000000000..4fa884fbc --- /dev/null +++ b/kernel-hal/src/bare/arch/riscv/cpu.rs @@ -0,0 +1,8 @@ +hal_fn_impl! { + impl mod crate::hal_fn::cpu { + fn cpu_frequency() -> u16 { + const DEFAULT: u16 = 2600; + DEFAULT + } + } +} diff --git a/kernel-hal/src/bare/arch/riscv/interrupt.rs b/kernel-hal/src/bare/arch/riscv/interrupt.rs new file mode 100644 index 000000000..b2e65f12f --- /dev/null +++ b/kernel-hal/src/bare/arch/riscv/interrupt.rs @@ -0,0 +1,53 @@ +use alloc::boxed::Box; +use riscv::register::{sie, sstatus}; +use spin::Mutex; + +use super::{plic, trap}; +use crate::utils::irq_manager::IrqManager; + +// IRQ +const TIMER: u32 = 5; +const U_PLIC: u32 = 8; +const S_PLIC: u32 = 9; +const M_PLIC: u32 = 11; + +lazy_static::lazy_static! { + static ref IRQ_MANAGER: Mutex = Mutex::new(IrqManager::new(1, 15)); +} + +#[allow(dead_code)] +fn init_soft() { + unsafe { sie::set_ssoft() }; + info!("+++ setup soft int! +++"); +} + +fn init_ext() { + unsafe { sie::set_sext() }; + plic::init(); + info!("+++ Setting up PLIC +++"); +} + +fn init_irq() { + let mut im = IRQ_MANAGER.lock(); + // 模拟参照了x86_64,把timer处理函数也放进去了 + im.register_handler(TIMER, Box::new(trap::super_timer)).ok(); + // im.register_handler(Keyboard, Box::new(keyboard)); + im.register_handler(S_PLIC, Box::new(plic::handle_interrupt)) + .ok(); +} + +pub(super) fn init() { + unsafe { sstatus::set_sie() }; + init_ext(); + init_irq(); + info!("+++ setup interrupt OK +++"); +} + +hal_fn_impl! { + impl mod crate::hal_fn::interrupt { + fn handle_irq(vector: u32) { + debug!("PLIC handle: {:#x}", vector); + IRQ_MANAGER.lock().handle(vector); + } + } +} diff --git a/kernel-hal/src/bare/arch/riscv/mem.rs b/kernel-hal/src/bare/arch/riscv/mem.rs new file mode 100644 index 000000000..1fc9724ee --- /dev/null +++ b/kernel-hal/src/bare/arch/riscv/mem.rs @@ -0,0 +1,3 @@ +pub fn frame_flush(_target: crate::PhysAddr) { + unimplemented!() +} diff --git a/kernel-hal/src/bare/arch/riscv/mod.rs b/kernel-hal/src/bare/arch/riscv/mod.rs new file mode 100644 index 000000000..96576e7be --- /dev/null +++ b/kernel-hal/src/bare/arch/riscv/mod.rs @@ -0,0 +1,31 @@ +#![allow(dead_code)] + +mod consts; +mod plic; +mod sbi; +mod trap; +mod uart; + +pub mod config; +pub mod context; +pub mod cpu; +pub mod interrupt; +pub mod mem; +pub mod serial; +pub mod special; +pub mod timer; +pub mod vm; + +pub fn init() { + vm::remap_the_kernel().unwrap(); + interrupt::init(); + timer::init(); + uart::init(consts::UART_BASE); + + #[cfg(feature = "board_qemu")] + { + // TODO + // sbi_println!("Setup virtio @devicetree {:#x}", cfg.dtb); + // drivers::virtio::device_tree::init(cfg.dtb); + } +} diff --git a/kernel-hal-bare/src/arch/riscv/plic.rs b/kernel-hal/src/bare/arch/riscv/plic.rs similarity index 83% rename from kernel-hal-bare/src/arch/riscv/plic.rs rename to kernel-hal/src/bare/arch/riscv/plic.rs index f97675a81..fc1b1eedb 100644 --- a/kernel-hal-bare/src/arch/riscv/plic.rs +++ b/kernel-hal/src/bare/arch/riscv/plic.rs @@ -1,7 +1,5 @@ -use super::interrupt; -use super::uart; -use crate::{putfmt, phys_to_virt}; use super::consts::*; +use crate::mem::phys_to_virt; //通过MMIO地址对平台级中断控制器PLIC的寄存器进行设置 //基于opensbi后一般运行于Hart0 S态,为Target1 @@ -10,7 +8,7 @@ use super::consts::*; //声明claim会清除中断源上的相应pending位。 //即使mip寄存器的MEIP位没有置位, 也可以claim; 声明不被阀值寄存器的设置影响; //获取按优先级排序后的下一个可用的中断ID -pub fn next() -> Option { +fn next() -> Option { let claim_reg = phys_to_virt(PLIC_CLAIM) as *const u32; let claim_no; unsafe { @@ -26,7 +24,7 @@ pub fn next() -> Option { //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); + info!("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); + info!("Unknown external interrupt: {}", interrupt); } } //这将复位pending的中断,允许UART再次中断。 diff --git a/kernel-hal-bare/src/arch/riscv/sbi.rs b/kernel-hal/src/bare/arch/riscv/sbi.rs similarity index 79% rename from kernel-hal-bare/src/arch/riscv/sbi.rs rename to kernel-hal/src/bare/arch/riscv/sbi.rs index 67ce257e7..8d20f73d0 100644 --- a/kernel-hal-bare/src/arch/riscv/sbi.rs +++ b/kernel-hal/src/bare/arch/riscv/sbi.rs @@ -1,23 +1,36 @@ -pub fn console_putchar(ch: usize) { - sbi_call(SBI_CONSOLE_PUTCHAR, ch, 0, 0); -} - -pub fn console_getchar() -> usize { - return sbi_call(SBI_CONSOLE_GETCHAR, 0, 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; +#[inline(always)] fn sbi_call(which: usize, arg0: usize, arg1: usize, arg2: usize) -> usize { - let ret: usize; + let ret; unsafe { - llvm_asm!("ecall" - :"={x10}"(ret) - :"{x10}"(arg0), "{x11}"(arg1), "{x12}"(arg2), "{x17}"(which) - :"memory" - :"volatile"); + 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); +} + +pub fn console_getchar() -> usize { + sbi_call(SBI_CONSOLE_GETCHAR, 0, 0, 0) +} + 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; diff --git a/kernel-hal/src/bare/arch/riscv/serial.rs b/kernel-hal/src/bare/arch/riscv/serial.rs new file mode 100644 index 000000000..bdf1e33e3 --- /dev/null +++ b/kernel-hal/src/bare/arch/riscv/serial.rs @@ -0,0 +1,34 @@ +use core::fmt::{Arguments, Result, Write}; + +use super::{sbi, uart}; + +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(uart) = uart::UART.try_get() { + //每次都创建一个新的Uart ? 内存位置始终相同 + write!(uart.lock(), "{}", s) + } else { + SbiConsole.write_str(s) + } + } +} + +hal_fn_impl! { + impl mod crate::hal_fn::serial { + fn serial_write_fmt(fmt: Arguments) { + UartConsole.write_fmt(fmt).unwrap(); + } + } +} diff --git a/kernel-hal/src/bare/arch/riscv/special.rs b/kernel-hal/src/bare/arch/riscv/special.rs new file mode 100644 index 000000000..26549ac7b --- /dev/null +++ b/kernel-hal/src/bare/arch/riscv/special.rs @@ -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(); + } + } +} diff --git a/kernel-hal/src/bare/arch/riscv/timer.rs b/kernel-hal/src/bare/arch/riscv/timer.rs new file mode 100644 index 000000000..486a1d7ca --- /dev/null +++ b/kernel-hal/src/bare/arch/riscv/timer.rs @@ -0,0 +1,23 @@ +use core::time::Duration; +use riscv::register::{sie, time}; + +fn get_cycle() -> u64 { + time::read() as u64 +} + +pub(super) fn timer_set_next() { + //let TIMEBASE: u64 = 100000; + const TIMEBASE: u64 = 10_000_000; + super::sbi::set_timer(get_cycle() + TIMEBASE); +} + +pub(super) fn init() { + unsafe { sie::set_stimer() }; + timer_set_next(); +} + +pub(crate) fn timer_now() -> Duration { + const FREQUENCY: u64 = 10_000_000; // ??? + let time = get_cycle(); + Duration::from_nanos(time * 1_000_000_000 / FREQUENCY as u64) +} diff --git a/kernel-hal/src/bare/arch/riscv/trap.rs b/kernel-hal/src/bare/arch/riscv/trap.rs new file mode 100644 index 000000000..e0d341adb --- /dev/null +++ b/kernel-hal/src/bare/arch/riscv/trap.rs @@ -0,0 +1,56 @@ +use riscv::register::scause::{self, Exception, Interrupt, Trap}; +use riscv::register::stval; +use trapframe::TrapFrame; + +use super::{plic, sbi}; +use crate::MMUFlags; + +fn breakpoint(sepc: &mut usize) { + info!("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(); + + //发生外界中断时,epc的指令还没有执行,故无需修改epc到下一条 +} + +fn super_soft() { + sbi::clear_ipi(); + info!("Interrupt::SupervisorSoft!"); +} + +fn page_fault(access_flags: MMUFlags) { + crate::KHANDLER.handle_page_fault(stval::read(), access_flags); +} + +#[no_mangle] +pub extern "C" fn trap_handler(tf: &mut TrapFrame) { + let sepc = tf.sepc; + let scause = scause::read(); + match scause.cause() { + Trap::Exception(Exception::Breakpoint) => breakpoint(&mut tf.sepc), + Trap::Exception(Exception::IllegalInstruction) => { + panic!("IllegalInstruction: {:#x}->{:#x}", sepc, stval::read()) + } + Trap::Exception(Exception::LoadFault) => { + panic!("Load access fault: {:#x}->{:#x}", sepc, stval::read()) + } + Trap::Exception(Exception::StoreFault) => { + panic!("Store access fault: {:#x}->{:#x}", sepc, stval::read()) + } + Trap::Exception(Exception::LoadPageFault) => page_fault(MMUFlags::READ), + Trap::Exception(Exception::StorePageFault) => page_fault(MMUFlags::WRITE), + Trap::Exception(Exception::InstructionPageFault) => page_fault(MMUFlags::EXECUTE), + 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: {:?}", scause.cause()), + } +} diff --git a/kernel-hal-bare/src/arch/riscv/uart.rs b/kernel-hal/src/bare/arch/riscv/uart.rs similarity index 67% rename from kernel-hal-bare/src/arch/riscv/uart.rs rename to kernel-hal/src/bare/arch/riscv/uart.rs index ce714af2b..dea493e13 100644 --- a/kernel-hal-bare/src/arch/riscv/uart.rs +++ b/kernel-hal/src/bare/arch/riscv/uart.rs @@ -1,15 +1,17 @@ -use super::consts::UART_BASE; -use crate::{putfmt, phys_to_virt}; -use core::convert::TryInto; use core::fmt::{Error, Write}; +use spin::Mutex; -pub struct Uart { - base_address: usize, +use crate::{mem::phys_to_virt, utils::init_once::InitOnce, PhysAddr, VirtAddr}; + +pub(super) struct Uart { + base_address: VirtAddr, } +pub(super) static UART: InitOnce> = InitOnce::new(); + // 结构体Uart的实现块 impl Uart { - pub fn new(base_address: usize) -> Self { + pub fn new(base_address: VirtAddr) -> Self { Uart { base_address } } @@ -57,7 +59,7 @@ impl Uart { if ptr.add(5).read_volatile() & 0b1 == 0 { None } else { - Some((ptr.add(0).read_volatile() & 0xff) as u8) + Some(ptr.add(0).read_volatile() as u8) } } } @@ -81,26 +83,19 @@ 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() { - let c = c & 0xff; - //CONSOLE - super::serial_put(c); - - /* - * 因serial_write()已可以被回调输出了,这里则不再需要了 - match c { - 0x7f => { //0x8 [backspace] ; 而实际qemu运行,[backspace]键输出0x7f, 表示del - bare_print!("{} {}", 8 as char, 8 as char); - }, - 10 | 13 => { // 新行或回车 - bare_println!(); - }, - _ => { - bare_print!("{}", c as char); - }, +pub(super) fn handle_interrupt() { + if let Some(uart) = UART.try_get() { + if let Some(c) = uart.lock().get() { + //CONSOLE + crate::serial::serial_put(c); } - */ } } + +pub(super) fn init(base_paddr: PhysAddr) { + UART.init(|| { + let mut uart = Uart::new(phys_to_virt(base_paddr)); + uart.simple_init(); + Mutex::new(uart) + }); +} diff --git a/kernel-hal/src/bare/arch/riscv/vm.rs b/kernel-hal/src/bare/arch/riscv/vm.rs new file mode 100644 index 000000000..513bee800 --- /dev/null +++ b/kernel-hal/src/bare/arch/riscv/vm.rs @@ -0,0 +1,225 @@ +use core::fmt::{Debug, Formatter, Result}; +use core::slice; + +use riscv::{asm, paging::PageTableFlags as PTF, register::satp}; + +use super::consts; +use crate::addr::{align_down, align_up}; +use crate::utils::page_table::{GenericPTE, PageTableImpl, PageTableLevel3}; +use crate::{mem::phys_to_virt, MMUFlags, PhysAddr, VirtAddr, KCONFIG, PAGE_SIZE}; + +#[cfg(target_arch = "riscv32")] +type RvPageTable<'a> = riscv::paging::Rv32PageTable<'a>; +#[cfg(target_arch = "riscv64")] +type RvPageTable<'a> = riscv::paging::Rv39PageTable<'a>; + +/// remap kernel with 4K page +pub(super) fn remap_the_kernel() -> PagingResult { + extern "C" { + fn stext(); + fn etext(); + fn srodata(); + fn erodata(); + fn sdata(); + fn edata(); + fn sbss(); + fn ebss(); + + fn bootstack(); + fn bootstacktop(); + + fn end(); + } + + let mut pt = PageTable::new(); + let root_paddr = pt.table_phys(); + let mut map_range = |start: VirtAddr, end: VirtAddr, flags: MMUFlags| -> PagingResult { + pt.map_cont( + start, + crate::addr::align_up(end - start), + start - KCONFIG.phys_to_virt_offset, + flags | MMUFlags::HUGE_PAGE, + ) + }; + + map_range( + stext as usize, + etext as usize, + MMUFlags::READ | MMUFlags::EXECUTE, + )?; + map_range(srodata as usize, erodata as usize, MMUFlags::READ)?; + map_range( + sdata as usize, + edata as usize, + MMUFlags::READ | MMUFlags::WRITE, + )?; + map_range( + sbss as usize, + ebss as usize, + MMUFlags::READ | MMUFlags::WRITE, + )?; + // stack + map_range( + bootstack as usize, + bootstacktop as usize, + MMUFlags::READ | MMUFlags::WRITE, + )?; + // physical frames + map_range( + align_up(end as usize + PAGE_SIZE), + phys_to_virt(align_down(KCONFIG.phys_mem_end)), + MMUFlags::READ | MMUFlags::WRITE, + )?; + // PLIC + map_range( + phys_to_virt(consts::PLIC_BASE), + phys_to_virt(consts::PLIC_BASE + 0x40_0000), // 4M + MMUFlags::READ | MMUFlags::WRITE, + )?; + // UART0, VIRTIO + map_range( + phys_to_virt(consts::UART_BASE), + phys_to_virt(consts::UART_BASE + 0x1000), + MMUFlags::READ | MMUFlags::WRITE, + )?; + + unsafe { + pt.activate(); + core::mem::forget(pt); + } + + info!("remap the kernel @ {:#x}", root_paddr); + Ok(()) +} + +hal_fn_impl! { + impl mod crate::hal_fn::vm { + fn activate_paging(vmtoken: PhysAddr) { + let old_token = current_vmtoken(); + if old_token != vmtoken { + #[cfg(target_arch = "riscv64")] + let mode = satp::Mode::Sv39; + debug!("switch table {:x?} -> {:x?}", old_token, vmtoken); + unsafe { + satp::set(mode, 0, vmtoken >> 12); + asm::sfence_vma_all(); + } + } + } + + fn current_vmtoken() -> PhysAddr { + satp::read().ppn() << 12 + } + + fn flush_tlb(vaddr: Option) { + unsafe { + if let Some(vaddr) = vaddr { + asm::sfence_vma(0, vaddr) + } else { + asm::sfence_vma_all(); + } + } + } + + fn pt_clone_kernel_space(dst_pt_root: PhysAddr, src_pt_root: PhysAddr) { + let entry_range = 0x100..0x200; // 0xFFFF_FFC0_0000_0000 .. 0xFFFF_FFFF_FFFF_FFFF + let dst_table = unsafe { slice::from_raw_parts_mut(phys_to_virt(dst_pt_root) as *mut Rv64PTE, 512) }; + let src_table = unsafe { slice::from_raw_parts(phys_to_virt(src_pt_root) as *const Rv64PTE, 512) }; + for i in entry_range { + dst_table[i] = src_table[i]; + if !dst_table[i].is_unused() { + dst_table[i].0 |= PTF::GLOBAL.bits() as u64; + } + } + } + } +} + +impl From for PTF { + fn from(f: MMUFlags) -> Self { + let mut flags = PTF::VALID; + if f.contains(MMUFlags::READ) { + flags |= PTF::READABLE; + } + if f.contains(MMUFlags::WRITE) { + flags |= PTF::WRITABLE; + } + if f.contains(MMUFlags::EXECUTE) { + flags |= PTF::EXECUTABLE; + } + if f.contains(MMUFlags::USER) { + flags |= PTF::USER; + } + flags + } +} + +impl From for MMUFlags { + fn from(f: PTF) -> Self { + let mut ret = Self::empty(); + if f.contains(PTF::READABLE) { + ret |= Self::READ; + } + if f.contains(PTF::WRITABLE) { + ret |= Self::WRITE; + } + if f.contains(PTF::EXECUTABLE) { + ret |= Self::EXECUTE; + } + if f.contains(PTF::USER) { + ret |= Self::USER; + } + ret + } +} + +const PHYS_ADDR_MASK: u64 = 0x003f_ffff_ffff_fc00; // 10..54 + +#[derive(Clone, Copy)] +#[repr(transparent)] +pub struct Rv64PTE(u64); + +impl GenericPTE for Rv64PTE { + fn addr(&self) -> PhysAddr { + ((self.0 & PHYS_ADDR_MASK) << 2) as _ + } + fn flags(&self) -> MMUFlags { + PTF::from_bits_truncate(self.0 as usize).into() + } + fn is_unused(&self) -> bool { + self.0 == 0 + } + fn is_present(&self) -> bool { + PTF::from_bits_truncate(self.0 as usize).contains(PTF::VALID) + } + fn is_leaf(&self) -> bool { + PTF::from_bits_truncate(self.0 as usize).contains(PTF::READABLE | PTF::EXECUTABLE) + } + + fn set_addr(&mut self, paddr: PhysAddr) { + self.0 = (self.0 & !PHYS_ADDR_MASK) | ((paddr as u64 >> 2) & PHYS_ADDR_MASK); + } + fn set_flags(&mut self, flags: MMUFlags, _is_huge: bool) { + let flags = PTF::from(flags) | PTF::ACCESSED | PTF::DIRTY; + debug_assert!(flags.contains(PTF::READABLE | PTF::EXECUTABLE)); + self.0 = (self.0 & PHYS_ADDR_MASK) | flags.bits() as u64; + } + fn set_table(&mut self, paddr: PhysAddr) { + self.0 = ((paddr as u64 >> 2) & PHYS_ADDR_MASK) | PTF::VALID.bits() as u64; + } + fn clear(&mut self) { + self.0 = 0 + } +} + +impl Debug for Rv64PTE { + fn fmt(&self, f: &mut Formatter) -> Result { + let mut f = f.debug_struct("Rv64PTE"); + f.field("raw", &self.0); + f.field("addr", &self.addr()); + f.field("flags", &self.flags()); + f.finish() + } +} + +pub type PageTable = PageTableImpl; diff --git a/kernel-hal-bare/src/arch/x86_64/acpi_table.rs b/kernel-hal/src/bare/arch/x86_64/acpi_table.rs similarity index 62% rename from kernel-hal-bare/src/arch/x86_64/acpi_table.rs rename to kernel-hal/src/bare/arch/x86_64/acpi_table.rs index b477021fb..c9facb2d3 100644 --- a/kernel-hal-bare/src/arch/x86_64/acpi_table.rs +++ b/kernel-hal/src/bare/arch/x86_64/acpi_table.rs @@ -1,20 +1,61 @@ #![allow(dead_code)] -use crate::get_acpi_table; -pub use acpi::{ - interrupt::{InterruptModel, InterruptSourceOverride, IoApic, Polarity, TriggerMode}, - Acpi, -}; + use alloc::vec::Vec; -use lazy_static::*; +use core::ptr::NonNull; + +use acpi::interrupt::{InterruptModel, InterruptSourceOverride, IoApic, Polarity, TriggerMode}; +use acpi::{parse_rsdp, Acpi, AcpiHandler, PhysicalMapping}; use spin::Mutex; + +use crate::{mem::phys_to_virt, PAGE_SIZE}; + pub struct AcpiTable { inner: Acpi, } -lazy_static! { +lazy_static::lazy_static! { static ref ACPI_TABLE: Mutex> = Mutex::default(); } +/// Build ACPI Table +struct AcpiHelper; + +impl AcpiHandler for AcpiHelper { + unsafe fn map_physical_region( + &mut self, + physical_address: usize, + size: usize, + ) -> PhysicalMapping { + #[allow(non_snake_case)] + let OFFSET = 0; + let page_start = physical_address / PAGE_SIZE; + let page_end = (physical_address + size + PAGE_SIZE - 1) / PAGE_SIZE; + PhysicalMapping:: { + physical_start: physical_address, + virtual_start: NonNull::new_unchecked(phys_to_virt(physical_address + OFFSET) as *mut T), + mapped_length: size, + region_length: PAGE_SIZE * (page_end - page_start), + } + } + fn unmap_physical_region(&mut self, _region: PhysicalMapping) {} +} + +fn get_acpi_table() -> Option { + let mut handler = AcpiHelper; + match unsafe { + parse_rsdp( + &mut handler, + super::special::pc_firmware_tables().0 as usize, + ) + } { + Ok(table) => Some(table), + Err(info) => { + warn!("get_acpi_table error: {:#x?}", info); + None + } + } +} + impl AcpiTable { fn initialize_check() { #[cfg(target_arch = "x86_64")] diff --git a/kernel-hal/src/bare/arch/x86_64/apic.rs b/kernel-hal/src/bare/arch/x86_64/apic.rs new file mode 100644 index 000000000..e6de89299 --- /dev/null +++ b/kernel-hal/src/bare/arch/x86_64/apic.rs @@ -0,0 +1,22 @@ +use apic::{IoApic, LocalApic, XApic}; + +use crate::mem::phys_to_virt; + +const LAPIC_ADDR: usize = 0xfee0_0000; +const IOAPIC_ADDR: usize = 0xfec0_0000; + +pub fn get_lapic() -> XApic { + unsafe { XApic::new(phys_to_virt(LAPIC_ADDR)) } +} + +pub fn get_ioapic() -> IoApic { + unsafe { IoApic::new(phys_to_virt(IOAPIC_ADDR)) } +} + +pub fn lapic_id() -> u8 { + get_lapic().id() as u8 +} + +pub fn init() { + get_lapic().cpu_init(); +} diff --git a/kernel-hal/src/bare/arch/x86_64/config.rs b/kernel-hal/src/bare/arch/x86_64/config.rs new file mode 100644 index 000000000..c07e247c4 --- /dev/null +++ b/kernel-hal/src/bare/arch/x86_64/config.rs @@ -0,0 +1,11 @@ +/// Configuration of HAL. +#[derive(Debug)] +pub struct KernelConfig { + pub kernel_offset: usize, + pub phys_mem_start: usize, + pub phys_to_virt_offset: usize, + + pub acpi_rsdp: u64, + pub smbios: u64, + pub ap_fn: fn() -> !, +} diff --git a/kernel-hal/src/bare/arch/x86_64/context.rs b/kernel-hal/src/bare/arch/x86_64/context.rs new file mode 100644 index 000000000..36562c3ad --- /dev/null +++ b/kernel-hal/src/bare/arch/x86_64/context.rs @@ -0,0 +1,39 @@ +use bitflags::bitflags; +use x86_64::registers::control::Cr2; + +use crate::{MMUFlags, VirtAddr}; + +bitflags! { + struct PageFaultErrorCode: u32 { + const PRESENT = 1 << 0; + const WRITE = 1 << 1; + const USER = 1 << 2; + const RESERVED = 1 << 3; + const INST = 1 << 4; + } +} + +hal_fn_impl! { + impl mod crate::hal_fn::context { + fn fetch_page_fault_info(error_code: usize) -> (VirtAddr, MMUFlags) { + let fault_vaddr = Cr2::read().as_u64() as _; + let mut flags = MMUFlags::empty(); + let code = PageFaultErrorCode::from_bits_truncate(error_code as u32); + if code.contains(PageFaultErrorCode::WRITE) { + flags |= MMUFlags::WRITE + } else { + flags |= MMUFlags::READ + } + if code.contains(PageFaultErrorCode::USER) { + flags |= MMUFlags::USER + } + if code.contains(PageFaultErrorCode::INST) { + flags |= MMUFlags::EXECUTE + } + if code.contains(PageFaultErrorCode::RESERVED) { + error!("page table entry has reserved bits set!") + } + (fault_vaddr, flags) + } + } +} diff --git a/kernel-hal/src/bare/arch/x86_64/cpu.rs b/kernel-hal/src/bare/arch/x86_64/cpu.rs new file mode 100644 index 000000000..cc911c220 --- /dev/null +++ b/kernel-hal/src/bare/arch/x86_64/cpu.rs @@ -0,0 +1,23 @@ +lazy_static::lazy_static! { + static ref TSC_FREQUENCY: u16 = { + const DEFAULT: u16 = 2600; + if let Some(info) = raw_cpuid::CpuId::new().get_processor_frequency_info() { + let f = info.processor_base_frequency(); + return if f == 0 { DEFAULT } else { f }; + } + // FIXME: QEMU, AMD, VirtualBox + DEFAULT + }; +} + +hal_fn_impl! { + impl mod crate::hal_fn::cpu { + fn cpu_id() -> u8 { + super::apic::lapic_id() + } + + fn cpu_frequency() -> u16 { + *TSC_FREQUENCY + } + } +} diff --git a/kernel-hal/src/bare/arch/x86_64/interrupt.rs b/kernel-hal/src/bare/arch/x86_64/interrupt.rs new file mode 100644 index 000000000..0d9a09128 --- /dev/null +++ b/kernel-hal/src/bare/arch/x86_64/interrupt.rs @@ -0,0 +1,294 @@ +#![allow(dead_code)] +#![allow(non_upper_case_globals)] + +use alloc::{boxed::Box, vec::Vec}; +use core::ops::Range; + +use apic::IoApic; +use spin::Mutex; + +use super::acpi_table::AcpiTable; +use crate::utils::irq_manager::{IrqHandler, IrqManager}; +use crate::{mem::phys_to_virt, HalError, HalResult}; + +const IRQ0: u32 = 32; + +const IRQ_MIN_ID: u32 = 0x20; +const IRQ_MAX_ID: u32 = 0xff; + +// IRQ +const Timer: u32 = 0; +const Keyboard: u32 = 1; +const COM2: u32 = 3; +const COM1: u32 = 4; +const Mouse: u32 = 12; +const IDE: u32 = 14; +const Error: u32 = 19; +const Spurious: u32 = 31; + +const IO_APIC_NUM_REDIRECTIONS: u8 = 120; + +lazy_static::lazy_static! { + static ref IRQ_MANAGER: Mutex = Mutex::new(IrqManager::new(0x20, 0xff)); + static ref MAX_INSTR_TABLE: Mutex> = Mutex::default(); +} + +/* +lazy_static! { + static ref MOUSE: Mutex = Mutex::new(Mouse::new()); + static ref MOUSE_CALLBACK: Mutex>> = + Mutex::new(Vec::new()); +} + +#[export_name = "hal_mouse_set_callback"] +pub fn mouse_set_callback(callback: Box) { + MOUSE_CALLBACK.lock().push(callback); +} + +fn mouse_on_complete(mouse_state: MouseState) { + debug!("mouse state: {:?}", mouse_state); + MOUSE_CALLBACK.lock().iter().for_each(|callback| { + callback([ + mouse_state.get_flags().bits(), + mouse_state.get_x() as u8, + mouse_state.get_y() as u8, + ]); + }); +} + +fn mouse() { + use x86_64::instructions::port::PortReadOnly; + let mut port = PortReadOnly::new(0x60); + let packet = unsafe { port.read() }; + MOUSE.lock().process_packet(packet); +} +*/ + +fn ioapic_maxinstr(ioapic_addr: u32) -> Option { + let mut table = MAX_INSTR_TABLE.lock(); + for (addr, v) in table.iter() { + if *addr == ioapic_addr as usize { + return Some(*v); + } + } + let mut ioapic = unsafe { IoApic::new(phys_to_virt(ioapic_addr as usize)) }; + let v = ioapic.maxintr(); + table.push((ioapic_addr as usize, v)); + Some(v) +} + +unsafe fn init_ioapic() { + for ioapic in AcpiTable::get_ioapic() { + info!("Ioapic found: {:#x?}", ioapic); + let mut ip = IoApic::new(phys_to_virt(ioapic.address as usize)); + ip.disable_all(); + } + let mut ip = super::apic::get_ioapic(); + ip.disable_all(); +} + +fn get_ioapic(irq: u32) -> Option { + for i in AcpiTable::get_ioapic() { + let num_instr = core::cmp::min( + ioapic_maxinstr(i.address).unwrap(), + IO_APIC_NUM_REDIRECTIONS - 1, + ); + if i.global_system_interrupt_base <= irq + && irq <= i.global_system_interrupt_base + num_instr as u32 + { + return Some(i); + } + } + None +} + +fn ioapic_controller(i: &acpi::interrupt::IoApic) -> IoApic { + unsafe { IoApic::new(phys_to_virt(i.address as usize)) } +} + +hal_fn_impl! { + impl mod crate::hal_fn::interrupt { + fn enable_irq(irq: u32) { + info!("enable_irq irq={:#x?}", irq); + // if irq == 1 { + // irq_enable_raw(irq as u8, irq as u8 + IRQ0); + // return; + // } + if let Some(x) = get_ioapic(irq) { + let mut ioapic = ioapic_controller(&x); + ioapic.enable((irq - x.global_system_interrupt_base) as u8, 0); + } + } + + fn disable_irq(irq: u32) { + info!("disable_irq"); + if let Some(x) = get_ioapic(irq) { + let mut ioapic = ioapic_controller(&x); + ioapic.disable((irq - x.global_system_interrupt_base) as u8); + } + } + + fn is_valid_irq(irq: u32) -> bool { + trace!("is_valid_irq: irq={:#x?}", irq); + get_ioapic(irq).is_some() + } + + fn configure_irq(vector: u32, trig_mode: bool, polarity: bool) -> HalResult { + info!( + "configure_irq: vector={:#x?}, trig_mode={:#x?}, polarity={:#x?}", + vector, trig_mode, polarity + ); + let dest = super::apic::lapic_id(); + get_ioapic(vector) + .map(|x| { + let mut ioapic = ioapic_controller(&x); + ioapic.config( + (vector - x.global_system_interrupt_base) as u8, + 0, + dest, + trig_mode, + polarity, + false, /* physical */ + true, /* mask */ + ); + }) + .ok_or(HalError) + } + + fn register_irq_handler(global_irq: u32, handler: IrqHandler) -> HalResult { + info!("register_irq_handler irq={:#x?}", global_irq); + // if global_irq == 1 { + // irq_add_handler(global_irq as u8 + IRQ0, handler); + // return Some(global_irq as u8 + IRQ0); + // } + let ioapic_info = get_ioapic(global_irq).ok_or(HalError)?; + let mut ioapic = ioapic_controller(&ioapic_info); + let offset = (global_irq - ioapic_info.global_system_interrupt_base) as u8; + let x86_vector = ioapic.irq_vector(offset); + let new_handler = if global_irq == 0x1 { + Box::new(move || { + handler(); + // keyboard(); + // mouse(); + }) + } else { + handler + }; + let x86_vector = IRQ_MANAGER + .lock() + .register_handler(x86_vector as u32, new_handler)?; + info!( + "irq_set_handle: mapping from {:#x?} to {:#x?}", + global_irq, x86_vector + ); + ioapic.set_irq_vector(offset, x86_vector as u8); + Ok(x86_vector) + } + + fn unregister_irq_handler(global_irq: u32) -> HalResult { + info!("unregister_irq_handler irq={:#x}", global_irq); + let ioapic_info = if let Some(x) = get_ioapic(global_irq) { + x + } else { + return Err(HalError); + }; + let mut ioapic = ioapic_controller(&ioapic_info); + let offset = (global_irq - ioapic_info.global_system_interrupt_base) as u8; + let x86_vector = ioapic.irq_vector(offset); + // TODO: ioapic redirection entries associated with this should be reset. + IRQ_MANAGER.lock().unregister_handler(x86_vector as u32) + } + + fn handle_irq(vector: u32) { + use apic::LocalApic; + let mut lapic = super::apic::get_lapic(); + lapic.eoi(); + IRQ_MANAGER.lock().handle(vector); + } + + fn msi_allocate_block(requested_irqs: u32) -> HalResult> { + let alloc_size = requested_irqs.next_power_of_two(); + let start = IRQ_MANAGER.lock().alloc_block(alloc_size)?; + Ok(start..start + alloc_size) + } + + fn msi_free_block(block: Range) -> HalResult { + IRQ_MANAGER + .lock() + .free_block(block.start, block.len() as u32) + } + + fn msi_register_handler( + block: Range, + msi_id: u32, + handler: Box, + ) -> HalResult { + IRQ_MANAGER + .lock() + .overwrite_handler(block.start + msi_id, handler) + } + } +} + +fn irq57test() { + warn!("irq 57"); + // poll_ifaces(); +} + +fn timer() { + crate::timer::timer_tick(); +} + +fn com1() { + let c = super::serial::COM1.lock().receive(); + crate::serial::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); + } + } + } + } +} +*/ + +fn irq_enable_raw(irq: u32, vector: u32) { + info!("irq_enable_raw: irq={:#x?}, vector={:#x?}", irq, vector); + let mut ioapic = super::apic::get_ioapic(); + ioapic.set_irq_vector(irq as u8, vector as u8); + ioapic.enable(irq as u8, 0) +} + +pub(super) fn init() { + // MOUSE.lock().init().unwrap(); + // MOUSE.lock().set_on_complete(mouse_on_complete); + unsafe { + init_ioapic(); + } + + let mut im = IRQ_MANAGER.lock(); + im.register_handler(Timer + IRQ_MIN_ID, Box::new(timer)) + .ok(); + // im.register_handler(Keyboard + IRQ_MIN_ID, Box::new(keyboard)); + // im.register_handler(Mouse + IRQ_MIN_ID, Box::new(mouse)); + im.register_handler(COM1 + IRQ_MIN_ID, Box::new(com1)).ok(); + im.register_handler(57u32, Box::new(irq57test)).ok(); + // register_handler(Keyboard, Keyboard + IRQ_MIN_ID); + // register_handler(Mouse, Mouse + IRQ_MIN_ID); + irq_enable_raw(COM1, COM1 + IRQ_MIN_ID); +} diff --git a/kernel-hal-bare/src/arch/x86_64/keyboard.rs b/kernel-hal/src/bare/arch/x86_64/keyboard.rs similarity index 100% rename from kernel-hal-bare/src/arch/x86_64/keyboard.rs rename to kernel-hal/src/bare/arch/x86_64/keyboard.rs diff --git a/kernel-hal/src/bare/arch/x86_64/mem.rs b/kernel-hal/src/bare/arch/x86_64/mem.rs new file mode 100644 index 000000000..9484b0a9c --- /dev/null +++ b/kernel-hal/src/bare/arch/x86_64/mem.rs @@ -0,0 +1,19 @@ +use core::arch::x86_64::{__cpuid, _mm_clflush, _mm_mfence}; + +use crate::{mem::phys_to_virt, PhysAddr, PAGE_SIZE}; + +// Get cache line size in bytes. +fn cacheline_size() -> usize { + let leaf = unsafe { __cpuid(1).ebx }; + (((leaf >> 8) & 0xff) << 3) as usize +} + +/// Flush the physical frame. +pub fn frame_flush(target: PhysAddr) { + unsafe { + for paddr in (target..target + PAGE_SIZE).step_by(cacheline_size()) { + _mm_clflush(phys_to_virt(paddr) as *const u8); + } + _mm_mfence(); + } +} diff --git a/kernel-hal/src/bare/arch/x86_64/mod.rs b/kernel-hal/src/bare/arch/x86_64/mod.rs new file mode 100644 index 000000000..c7c5683b4 --- /dev/null +++ b/kernel-hal/src/bare/arch/x86_64/mod.rs @@ -0,0 +1,44 @@ +mod acpi_table; +mod apic; +mod trap; + +pub mod config; +pub mod context; +pub mod cpu; +pub mod interrupt; +pub mod mem; +pub mod serial; +pub mod special; +pub mod timer; +pub mod vm; + +use x86_64::registers::control::{Cr4, Cr4Flags}; + +pub fn init() { + apic::init(); + interrupt::init(); + serial::init(); + + fn ap_main() { + info!("processor {} started", cpu::cpu_id()); + unsafe { trapframe::init() }; + apic::init(); + let ap_fn = crate::KCONFIG.ap_fn; + ap_fn(); + } + + fn stack_fn(pid: usize) -> usize { + // split and reuse the current stack + let mut stack: usize; + unsafe { asm!("mov {}, rsp", out(reg) stack) }; + stack -= 0x4000 * pid; + stack + } + + unsafe { + // enable global page + Cr4::update(|f| f.insert(Cr4Flags::PAGE_GLOBAL)); + // start multi-processors + x86_smpboot::start_application_processors(ap_main, stack_fn, crate::mem::phys_to_virt); + } +} diff --git a/kernel-hal/src/bare/arch/x86_64/serial.rs b/kernel-hal/src/bare/arch/x86_64/serial.rs new file mode 100644 index 000000000..b8533458c --- /dev/null +++ b/kernel-hal/src/bare/arch/x86_64/serial.rs @@ -0,0 +1,25 @@ +use alloc::{boxed::Box, collections::VecDeque, vec::Vec}; +use core::fmt::{Arguments, Write}; + +use spin::Mutex; +use uart_16550::SerialPort; + +lazy_static::lazy_static! { + static ref STDIN: Mutex> = Mutex::new(VecDeque::new()); + static ref STDIN_CALLBACK: Mutex bool + Send + Sync>>> = + Mutex::new(Vec::new()); +} + +pub(super) static COM1: Mutex = Mutex::new(unsafe { SerialPort::new(0x3F8) }); + +pub(super) fn init() { + COM1.lock().init(); +} + +hal_fn_impl! { + impl mod crate::hal_fn::serial { + fn serial_write_fmt(fmt: Arguments) { + COM1.lock().write_fmt(fmt).unwrap(); + } + } +} diff --git a/kernel-hal/src/bare/arch/x86_64/special.rs b/kernel-hal/src/bare/arch/x86_64/special.rs new file mode 100644 index 000000000..08f83e820 --- /dev/null +++ b/kernel-hal/src/bare/arch/x86_64/special.rs @@ -0,0 +1,16 @@ +use x86_64::instructions::port::Port; + +/// IO Port in instruction +pub fn pio_read(port: u16) -> u32 { + unsafe { Port::new(port).read() } +} + +/// IO Port out instruction +pub fn pio_write(port: u16, value: u32) { + unsafe { Port::new(port).write(value) } +} + +/// Get physical address of `acpi_rsdp` and `smbios` on x86_64. +pub fn pc_firmware_tables() -> (u64, u64) { + (crate::KCONFIG.acpi_rsdp, crate::KCONFIG.smbios) +} diff --git a/kernel-hal/src/bare/arch/x86_64/timer.rs b/kernel-hal/src/bare/arch/x86_64/timer.rs new file mode 100644 index 000000000..ac3424151 --- /dev/null +++ b/kernel-hal/src/bare/arch/x86_64/timer.rs @@ -0,0 +1,6 @@ +use core::time::Duration; + +pub fn timer_now() -> Duration { + let tsc = unsafe { core::arch::x86_64::_rdtsc() }; + Duration::from_nanos(tsc * 1000 / super::cpu::cpu_frequency() as u64) +} diff --git a/kernel-hal/src/bare/arch/x86_64/trap.rs b/kernel-hal/src/bare/arch/x86_64/trap.rs new file mode 100644 index 000000000..50c527b86 --- /dev/null +++ b/kernel-hal/src/bare/arch/x86_64/trap.rs @@ -0,0 +1,54 @@ +#![allow(dead_code)] +#![allow(non_upper_case_globals)] + +use trapframe::TrapFrame; + +// Reference: https://wiki.osdev.org/Exceptions +const DivideError: u8 = 0; +const Debug: u8 = 1; +const NonMaskableInterrupt: u8 = 2; +const Breakpoint: u8 = 3; +const Overflow: u8 = 4; +const BoundRangeExceeded: u8 = 5; +const InvalidOpcode: u8 = 6; +const DeviceNotAvailable: u8 = 7; +const DoubleFault: u8 = 8; +const CoprocessorSegmentOverrun: u8 = 9; +const InvalidTSS: u8 = 10; +const SegmentNotPresent: u8 = 11; +const StackSegmentFault: u8 = 12; +const GeneralProtectionFault: u8 = 13; +const PageFault: u8 = 14; +const FloatingPointException: u8 = 16; +const AlignmentCheck: u8 = 17; +const MachineCheck: u8 = 18; +const SIMDFloatingPointException: u8 = 19; +const VirtualizationException: u8 = 20; +const SecurityException: u8 = 30; + +const IRQ0: u8 = 32; + +fn breakpoint() { + panic!("\nEXCEPTION: Breakpoint"); +} + +fn double_fault(tf: &TrapFrame) { + panic!("\nEXCEPTION: Double Fault\n{:#x?}", tf); +} + +fn page_fault(tf: &mut TrapFrame) { + let (fault_vaddr, access_flags) = crate::context::fetch_page_fault_info(tf.error_code); + crate::KHANDLER.handle_page_fault(fault_vaddr, access_flags); +} + +#[no_mangle] +pub extern "C" fn trap_handler(tf: &mut TrapFrame) { + trace!("Interrupt: {:#x} @ CPU{}", tf.trap_num, 0); // TODO 0 should replace in multi-core case + match tf.trap_num as u8 { + Breakpoint => breakpoint(), + DoubleFault => double_fault(tf), + PageFault => page_fault(tf), + IRQ0..=63 => crate::interrupt::handle_irq(tf.trap_num as u32), + _ => panic!("Unhandled interrupt {:x} {:#x?}", tf.trap_num, tf), + } +} diff --git a/kernel-hal/src/bare/arch/x86_64/vm.rs b/kernel-hal/src/bare/arch/x86_64/vm.rs new file mode 100644 index 000000000..b37628e2e --- /dev/null +++ b/kernel-hal/src/bare/arch/x86_64/vm.rs @@ -0,0 +1,158 @@ +use core::fmt::{Debug, Formatter, Result}; +use core::{convert::TryFrom, slice}; + +use x86_64::{ + instructions::tlb, + registers::control::{Cr3, Cr3Flags}, + structures::paging::page_table::PageTableFlags as PTF, +}; + +use crate::utils::page_table::{GenericPTE, PageTableImpl, PageTableLevel4}; +use crate::{mem::phys_to_virt, CachePolicy, MMUFlags, PhysAddr, VirtAddr}; + +hal_fn_impl! { + impl mod crate::hal_fn::vm { + fn activate_paging(vmtoken: PhysAddr) { + use x86_64::structures::paging::PhysFrame; + let frame = PhysFrame::containing_address(x86_64::PhysAddr::new(vmtoken as _)); + if Cr3::read().0 != frame { + unsafe { Cr3::write(frame, Cr3Flags::empty()) }; + debug!("set page_table @ {:#x}", vmtoken); + } + } + + fn current_vmtoken() -> PhysAddr { + Cr3::read().0.start_address().as_u64() as _ + } + + fn flush_tlb(vaddr: Option) { + if let Some(vaddr) = vaddr { + tlb::flush(x86_64::VirtAddr::new(vaddr as u64)) + } else { + tlb::flush_all() + } + } + + fn pt_clone_kernel_space(dst_pt_root: PhysAddr, src_pt_root: PhysAddr) { + let entry_range = 0x100..0x200; // 0xFFFF_8000_0000_0000 .. 0xFFFF_FFFF_FFFF_FFFF + let dst_table = unsafe { slice::from_raw_parts_mut(phys_to_virt(dst_pt_root) as *mut X86PTE, 512) }; + let src_table = unsafe { slice::from_raw_parts(phys_to_virt(src_pt_root) as *const X86PTE, 512) }; + for i in entry_range { + dst_table[i] = src_table[i]; + if !dst_table[i].is_unused() { + dst_table[i].0 |= PTF::GLOBAL.bits(); + } + } + } + } +} + +impl From for PTF { + fn from(f: MMUFlags) -> Self { + let mut flags = PTF::empty(); + if f.contains(MMUFlags::READ) { + flags |= PTF::PRESENT; + } + if f.contains(MMUFlags::WRITE) { + flags |= PTF::WRITABLE; + } + if !f.contains(MMUFlags::EXECUTE) { + flags |= PTF::NO_EXECUTE; + } + if f.contains(MMUFlags::USER) { + flags |= PTF::USER_ACCESSIBLE; + } + let cache_policy = (f.bits() & 3) as u32; // 最低三位用于储存缓存策略 + match CachePolicy::try_from(cache_policy) { + Ok(CachePolicy::Cached) => { + flags.remove(PTF::WRITE_THROUGH); + } + Ok(CachePolicy::Uncached) | Ok(CachePolicy::UncachedDevice) => { + flags |= PTF::NO_CACHE | PTF::WRITE_THROUGH; + } + Ok(CachePolicy::WriteCombining) => { + flags |= PTF::NO_CACHE | PTF::WRITE_THROUGH; + // 当位于level=1时,页面更大,在1<<12位上(0x100)为1 + // 但是bitflags里面没有这一位。由页表自行管理标记位去吧 + } + Err(_) => unreachable!("invalid cache policy"), + } + flags + } +} + +impl From for MMUFlags { + fn from(f: PTF) -> Self { + let mut ret = Self::empty(); + if f.contains(PTF::PRESENT) { + ret |= Self::READ; + } + if f.contains(PTF::WRITABLE) { + ret |= Self::WRITE; + } + if !f.contains(PTF::NO_EXECUTE) { + ret |= Self::EXECUTE; + } + if f.contains(PTF::USER_ACCESSIBLE) { + ret |= Self::USER; + } + if f.contains(PTF::NO_CACHE | PTF::WRITE_THROUGH) { + ret |= Self::CACHE_1; + } + ret + } +} + +const PHYS_ADDR_MASK: u64 = 0x000f_ffff_ffff_f000; // 12..52 + +#[derive(Clone, Copy)] +#[repr(transparent)] +pub struct X86PTE(u64); + +impl GenericPTE for X86PTE { + fn addr(&self) -> PhysAddr { + (self.0 & PHYS_ADDR_MASK) as _ + } + fn flags(&self) -> MMUFlags { + PTF::from_bits_truncate(self.0).into() + } + fn is_unused(&self) -> bool { + self.0 == 0 + } + fn is_present(&self) -> bool { + PTF::from_bits_truncate(self.0).contains(PTF::PRESENT) + } + fn is_leaf(&self) -> bool { + PTF::from_bits_truncate(self.0).contains(PTF::HUGE_PAGE) + } + + fn set_addr(&mut self, paddr: PhysAddr) { + self.0 = (self.0 & !PHYS_ADDR_MASK) | (paddr as u64 & PHYS_ADDR_MASK); + } + fn set_flags(&mut self, flags: MMUFlags, is_huge: bool) { + let mut flags: PTF = flags.into(); + if is_huge { + flags |= PTF::HUGE_PAGE; + } + self.0 = self.addr() as u64 | flags.bits(); + } + fn set_table(&mut self, paddr: PhysAddr) { + self.0 = (paddr as u64 & PHYS_ADDR_MASK) + | (PTF::PRESENT | PTF::WRITABLE | PTF::USER_ACCESSIBLE).bits(); + } + fn clear(&mut self) { + self.0 = 0 + } +} + +impl Debug for X86PTE { + fn fmt(&self, f: &mut Formatter) -> Result { + let mut f = f.debug_struct("X86PTE"); + f.field("raw", &self.0); + f.field("addr", &self.addr()); + f.field("flags", &self.flags()); + f.finish() + } +} + +pub type PageTable = PageTableImpl; diff --git a/kernel-hal-bare/src/drivers/mod.rs b/kernel-hal/src/bare/drivers/mod.rs similarity index 100% rename from kernel-hal-bare/src/drivers/mod.rs rename to kernel-hal/src/bare/drivers/mod.rs diff --git a/kernel-hal-bare/src/drivers/virtio/device_tree.rs b/kernel-hal/src/bare/drivers/virtio/device_tree.rs similarity index 100% rename from kernel-hal-bare/src/drivers/virtio/device_tree.rs rename to kernel-hal/src/bare/drivers/virtio/device_tree.rs diff --git a/kernel-hal-bare/src/drivers/virtio/mod.rs b/kernel-hal/src/bare/drivers/virtio/mod.rs similarity index 100% rename from kernel-hal-bare/src/drivers/virtio/mod.rs rename to kernel-hal/src/bare/drivers/virtio/mod.rs diff --git a/kernel-hal-bare/src/drivers/virtio/virtio.rs b/kernel-hal/src/bare/drivers/virtio/virtio.rs similarity index 100% rename from kernel-hal-bare/src/drivers/virtio/virtio.rs rename to kernel-hal/src/bare/drivers/virtio/virtio.rs diff --git a/kernel-hal/src/bare/mem.rs b/kernel-hal/src/bare/mem.rs new file mode 100644 index 000000000..a62d9c860 --- /dev/null +++ b/kernel-hal/src/bare/mem.rs @@ -0,0 +1,36 @@ +use crate::{PhysAddr, VirtAddr, KCONFIG}; + +hal_fn_impl! { + impl mod crate::hal_fn::mem { + fn phys_to_virt(paddr: PhysAddr) -> VirtAddr { + KCONFIG.phys_to_virt_offset + paddr + } + + fn pmem_read(paddr: PhysAddr, buf: &mut [u8]) { + trace!("pmem_read: paddr={:#x}, len={:#x}", paddr, buf.len()); + let src = phys_to_virt(paddr) as _; + unsafe { buf.as_mut_ptr().copy_from_nonoverlapping(src, buf.len()) }; + } + + fn pmem_write(paddr: PhysAddr, buf: &[u8]) { + trace!("pmem_write: paddr={:#x}, len={:#x}", paddr, buf.len()); + let dst = phys_to_virt(paddr) as *mut u8; + unsafe { dst.copy_from_nonoverlapping(buf.as_ptr(), buf.len()) }; + } + + fn pmem_zero(paddr: PhysAddr, len: usize) { + trace!("pmem_zero: paddr={:#x}, len={:#x}", paddr, len); + unsafe { core::ptr::write_bytes(phys_to_virt(paddr) as *mut u8, 0, len) }; + } + + fn pmem_copy(dst: PhysAddr, src: PhysAddr, len: usize) { + trace!("pmem_copy: {:#x} <- {:#x}, len={:#x}", dst, src, len); + let dst = phys_to_virt(dst) as *mut u8; + unsafe { dst.copy_from_nonoverlapping(phys_to_virt(src) as _, len) }; + } + + fn frame_flush(target: PhysAddr) { + super::arch::mem::frame_flush(target) + } + } +} diff --git a/kernel-hal/src/bare/mod.rs b/kernel-hal/src/bare/mod.rs new file mode 100644 index 000000000..00f81f4c4 --- /dev/null +++ b/kernel-hal/src/bare/mod.rs @@ -0,0 +1,33 @@ +cfg_if! { + if #[cfg(target_arch = "x86_64")] { + #[path = "arch/x86_64/mod.rs"] + mod arch; + pub use self::arch::special as x86_64; + } else if #[cfg(any(target_arch = "riscv32", target_arch = "riscv64"))] { + #[path = "arch/riscv/mod.rs"] + mod arch; + pub use self::arch::special as riscv; + } +} + +pub mod mem; +pub mod thread; +pub mod timer; + +pub use self::arch::{config, context, cpu, interrupt, serial, vm}; +pub use super::hal_fn::{dev, rand, vdso}; + +hal_fn_impl_default!(rand, vdso, dev::fb, dev::input); + +use crate::{KernelConfig, KernelHandler, KCONFIG, KHANDLER}; + +/// Initialize the HAL. +/// +/// This function must be called at the beginning. +pub fn init(cfg: KernelConfig, handler: &'static impl KernelHandler) { + KCONFIG.init_by(cfg); + KHANDLER.init_by(handler); + + unsafe { trapframe::init() }; + self::arch::init(); +} diff --git a/kernel-hal/src/bare/thread.rs b/kernel-hal/src/bare/thread.rs new file mode 100644 index 000000000..6645be61d --- /dev/null +++ b/kernel-hal/src/bare/thread.rs @@ -0,0 +1,34 @@ +use alloc::boxed::Box; +use core::task::{Context, Poll}; +use core::{future::Future, pin::Pin}; + +use spin::Mutex; + +hal_fn_impl! { + impl mod crate::hal_fn::thread { + fn spawn(future: Pin + Send + 'static>>, vmtoken: usize) { + struct PageTableSwitchWrapper { + inner: Mutex + Send>>>, + vmtoken: usize, + } + impl Future for PageTableSwitchWrapper { + type Output = (); + fn poll(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll { + crate::vm::activate_paging(self.vmtoken); + self.inner.lock().as_mut().poll(cx) + } + } + + executor::spawn(PageTableSwitchWrapper { + inner: Mutex::new(future), + vmtoken, + }); + } + + fn set_tid(_tid: u64, _pid: u64) {} + + fn get_tid() -> (u64, u64) { + (0, 0) + } + } +} diff --git a/kernel-hal/src/bare/timer.rs b/kernel-hal/src/bare/timer.rs new file mode 100644 index 000000000..4f5cf0f53 --- /dev/null +++ b/kernel-hal/src/bare/timer.rs @@ -0,0 +1,26 @@ +use alloc::boxed::Box; +use core::time::Duration; + +use naive_timer::Timer; +use spin::Mutex; + +lazy_static::lazy_static! { + pub static ref NAIVE_TIMER: Mutex = Mutex::new(Timer::default()); +} + +hal_fn_impl! { + impl mod crate::hal_fn::timer { + fn timer_now() -> Duration { + super::arch::timer::timer_now() + } + + fn timer_set(deadline: Duration, callback: Box) { + NAIVE_TIMER.lock().add(deadline, callback); + } + + fn timer_tick() { + let now = timer_now(); + NAIVE_TIMER.lock().expire(now); + } + } +} diff --git a/kernel-hal/src/common/addr.rs b/kernel-hal/src/common/addr.rs new file mode 100644 index 000000000..a45fd96b4 --- /dev/null +++ b/kernel-hal/src/common/addr.rs @@ -0,0 +1,27 @@ +//! Definition of phyical, virtual addresses and helper functions. + +use crate::PAGE_SIZE; + +pub type PhysAddr = usize; +pub type VirtAddr = usize; +pub type DevVAddr = usize; + +pub const fn align_down(addr: usize) -> usize { + addr & !(PAGE_SIZE - 1) +} + +pub const fn align_up(addr: usize) -> usize { + (addr + PAGE_SIZE - 1) & !(PAGE_SIZE - 1) +} + +pub const fn is_aligned(addr: usize) -> bool { + page_offset(addr) == 0 +} + +pub const fn page_count(size: usize) -> usize { + align_up(size) / PAGE_SIZE +} + +pub const fn page_offset(addr: usize) -> usize { + addr & (PAGE_SIZE - 1) +} diff --git a/kernel-hal/src/context.rs b/kernel-hal/src/common/context.rs similarity index 88% rename from kernel-hal/src/context.rs rename to kernel-hal/src/common/context.rs index fba3d4154..46b8bfec0 100644 --- a/kernel-hal/src/context.rs +++ b/kernel-hal/src/common/context.rs @@ -1,5 +1,7 @@ use core::fmt; +pub use trapframe::{GeneralRegs, UserContext}; + #[repr(C, align(16))] #[derive(Debug, Copy, Clone)] pub struct VectorRegs { @@ -45,3 +47,6 @@ impl fmt::Debug for U128 { write!(f, "{:#016x}{:016x}", self.0[1], self.0[0]) } } + +#[cfg(feature = "libos")] +pub use trapframe::syscall_fn_entry as syscall_entry; diff --git a/kernel-hal/src/common/defs.rs b/kernel-hal/src/common/defs.rs new file mode 100644 index 000000000..7dd7e45fb --- /dev/null +++ b/kernel-hal/src/common/defs.rs @@ -0,0 +1,38 @@ +use bitflags::bitflags; +use numeric_enum_macro::numeric_enum; + +/// The error type which is returned from HAL functions. +#[derive(Debug)] +pub struct HalError; + +/// The result type returned by HAL functions. +pub type HalResult = core::result::Result; + +bitflags! { + pub struct MMUFlags: usize { + #[allow(clippy::identity_op)] + const CACHE_1 = 1 << 0; + const CACHE_2 = 1 << 1; + const READ = 1 << 2; + const WRITE = 1 << 3; + const EXECUTE = 1 << 4; + const USER = 1 << 5; + const HUGE_PAGE = 1 << 6; + const RXW = Self::READ.bits | Self::WRITE.bits | Self::EXECUTE.bits; + } +} +numeric_enum! { + #[repr(u32)] + #[derive(Debug, PartialEq, Clone, Copy)] + pub enum CachePolicy { + Cached = 0, + Uncached = 1, + UncachedDevice = 2, + WriteCombining = 3, + } +} +pub const CACHE_POLICY_MASK: u32 = 3; + +pub const PAGE_SIZE: usize = super::vm::PageSize::Size4K as usize; + +pub use super::addr::{DevVAddr, PhysAddr, VirtAddr}; diff --git a/kernel-hal/src/fb.rs b/kernel-hal/src/common/fb.rs similarity index 100% rename from kernel-hal/src/fb.rs rename to kernel-hal/src/common/fb.rs diff --git a/kernel-hal/src/future.rs b/kernel-hal/src/common/future.rs similarity index 88% rename from kernel-hal/src/future.rs rename to kernel-hal/src/common/future.rs index 1a3bcc8e2..41c5ea182 100644 --- a/kernel-hal/src/future.rs +++ b/kernel-hal/src/common/future.rs @@ -1,4 +1,3 @@ -use crate::timer_now; use alloc::boxed::Box; use core::future::Future; use core::pin::Pin; @@ -44,12 +43,12 @@ impl Future for SleepFuture { type Output = (); fn poll(self: Pin<&mut Self>, cx: &mut Context) -> Poll { - if timer_now() >= self.deadline { + if crate::timer::timer_now() >= self.deadline { return Poll::Ready(()); } if self.deadline.as_nanos() < i64::max_value() as u128 { let waker = cx.waker().clone(); - crate::timer_set(self.deadline, Box::new(move |_| waker.wake())); + crate::timer::timer_set(self.deadline, Box::new(move |_| waker.wake())); } Poll::Pending } @@ -68,11 +67,11 @@ impl Future for SerialFuture { fn poll(self: Pin<&mut Self>, cx: &mut Context) -> Poll { let mut buf = [0u8]; - if crate::serial_read(&mut buf) != 0 { + if crate::serial::serial_read(&mut buf) != 0 { return Poll::Ready(buf[0]); } let waker = cx.waker().clone(); - crate::serial_set_callback(Box::new({ + crate::serial::serial_set_callback(Box::new({ move || { waker.wake_by_ref(); true diff --git a/kernel-hal/src/common/mem.rs b/kernel-hal/src/common/mem.rs new file mode 100644 index 000000000..361a92d4d --- /dev/null +++ b/kernel-hal/src/common/mem.rs @@ -0,0 +1,78 @@ +use alloc::vec::Vec; + +use crate::{PhysAddr, KHANDLER, PAGE_SIZE}; + +#[derive(Debug)] +pub struct PhysFrame { + paddr: PhysAddr, + allocated: bool, +} + +impl PhysFrame { + /// Allocate one physical frame. + pub fn new() -> Option { + KHANDLER.frame_alloc().map(|paddr| Self { + paddr, + allocated: true, + }) + } + + /// Allocate one physical frame and fill with zero. + pub fn new_zero() -> Option { + Self::new().map(|mut f| { + f.zero(); + f + }) + } + + fn alloc_contiguous_base(frame_count: usize, align_log2: usize) -> Option { + KHANDLER.frame_alloc_contiguous(frame_count, align_log2) + } + + /// Allocate contiguous physical frames. + pub fn new_contiguous(frame_count: usize, align_log2: usize) -> Vec { + Self::alloc_contiguous_base(frame_count, align_log2).map_or(Vec::new(), |base| { + (0..frame_count) + .map(|i| Self { + paddr: base + i * PAGE_SIZE, + allocated: true, + }) + .collect() + }) + } + + /// # Safety + /// + /// This function is unsafe because the user must ensure that this is an available physical + /// frame. + pub unsafe fn from_paddr(paddr: PhysAddr) -> Self { + assert!(crate::addr::is_aligned(paddr)); + Self { + paddr, + allocated: false, + } + } + + /// Get the start physical address of this frame. + pub fn paddr(&self) -> PhysAddr { + self.paddr + } + + /// Fill `self` with zero. + pub fn zero(&mut self) { + crate::mem::pmem_zero(self.paddr, PAGE_SIZE); + } +} + +impl Drop for PhysFrame { + fn drop(&mut self) { + if self.allocated { + KHANDLER.frame_dealloc(self.paddr) + } + } +} + +lazy_static::lazy_static! { + /// The global physical frame contains all zeros. + pub static ref ZERO_FRAME: PhysFrame = PhysFrame::new_zero().expect("failed to alloc zero frame"); +} diff --git a/kernel-hal/src/common/mod.rs b/kernel-hal/src/common/mod.rs new file mode 100644 index 000000000..886c57c7a --- /dev/null +++ b/kernel-hal/src/common/mod.rs @@ -0,0 +1,11 @@ +pub(super) mod defs; +pub(super) mod fb; + +pub mod addr; +pub mod context; +pub mod future; +pub mod mem; +pub mod serial; +pub mod user; +pub mod vdso; +pub mod vm; diff --git a/kernel-hal/src/common/serial.rs b/kernel-hal/src/common/serial.rs new file mode 100644 index 000000000..9c6faf49f --- /dev/null +++ b/kernel-hal/src/common/serial.rs @@ -0,0 +1,36 @@ +use alloc::{boxed::Box, collections::VecDeque, vec::Vec}; + +use spin::Mutex; + +lazy_static::lazy_static! { + static ref STDIN: Mutex> = Mutex::new(VecDeque::new()); + static ref STDIN_CALLBACK: Mutex bool + Send + Sync>>> = + Mutex::new(Vec::new()); +} + +/// Put a char to serial buffer. +pub fn serial_put(x: u8) { + let x = if x == b'\r' { b'\n' } else { x }; + STDIN.lock().push_back(x); + STDIN_CALLBACK.lock().retain(|f| !f()); +} + +/// Register a callback of serial readable event. +pub fn serial_set_callback(callback: Box bool + Send + Sync>) { + STDIN_CALLBACK.lock().push(callback); +} + +/// Read a string from serial buffer. +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 +} + +/// Print a string to serial. +pub fn serial_write(s: &str) { + crate::serial::serial_write_fmt(format_args!("{}", s)); +} diff --git a/kernel-hal/src/user.rs b/kernel-hal/src/common/user.rs similarity index 100% rename from kernel-hal/src/user.rs rename to kernel-hal/src/common/user.rs diff --git a/kernel-hal/src/vdso.rs b/kernel-hal/src/common/vdso.rs similarity index 73% rename from kernel-hal/src/vdso.rs rename to kernel-hal/src/common/vdso.rs index fa4b1b7b0..e1bf1e5d3 100644 --- a/kernel-hal/src/vdso.rs +++ b/kernel-hal/src/common/vdso.rs @@ -1,4 +1,5 @@ use core::fmt::{Debug, Error, Formatter}; +use git_version::git_version; /// This struct contains constants that are initialized by the kernel /// once at boot time. From the vDSO code's perspective, they are @@ -69,3 +70,28 @@ impl Debug for VersionString { Ok(()) } } + +pub(crate) fn vdso_constants_template() -> VdsoConstants { + let frequency = crate::cpu::cpu_frequency(); + let mut constants = VdsoConstants { + max_num_cpus: 1, + features: Features { + cpu: 0, + hw_breakpoint_count: 0, + hw_watchpoint_count: 0, + }, + dcache_line_size: 0, + icache_line_size: 0, + ticks_per_second: frequency as u64 * 1_000_000, + ticks_to_mono_numerator: 1000, + ticks_to_mono_denominator: frequency as u32, + physmem: 0, + version_string_len: 0, + version_string: Default::default(), + }; + constants.set_version_string(git_version!( + prefix = "git-", + args = ["--always", "--abbrev=40", "--dirty=-dirty"] + )); + constants +} diff --git a/kernel-hal/src/common/vm.rs b/kernel-hal/src/common/vm.rs new file mode 100644 index 000000000..e997a5667 --- /dev/null +++ b/kernel-hal/src/common/vm.rs @@ -0,0 +1,157 @@ +use crate::{addr::is_aligned, MMUFlags, PhysAddr, VirtAddr}; + +#[derive(Debug)] +pub enum PagingError { + NoMemory, + NotMapped, + AlreadyMapped, +} + +pub type PagingResult = Result; + +pub trait IgnoreNotMappedErr { + fn ignore(self) -> PagingResult; +} + +impl IgnoreNotMappedErr for PagingResult { + fn ignore(self) -> PagingResult { + match self { + Ok(_) | Err(PagingError::NotMapped) => Ok(()), + Err(e) => Err(e), + } + } +} + +#[repr(usize)] +#[derive(Debug, Copy, Clone, Eq, PartialEq)] +pub enum PageSize { + Size4K = 0x1000, + Size2M = 0x20_0000, + Size1G = 0x4000_0000, +} + +#[derive(Debug, Copy, Clone)] +pub struct Page { + pub vaddr: VirtAddr, + pub size: PageSize, +} + +impl PageSize { + pub const fn is_aligned(self, addr: usize) -> bool { + self.page_offset(addr) == 0 + } + + pub const fn align_down(self, addr: usize) -> usize { + addr & !(self as usize - 1) + } + + pub const fn page_offset(self, addr: usize) -> usize { + addr & (self as usize - 1) + } + + pub const fn is_huge(self) -> bool { + matches!(self, Self::Size1G | Self::Size2M) + } +} + +impl Page { + pub fn new_aligned(vaddr: VirtAddr, size: PageSize) -> Self { + debug_assert!(size.is_aligned(vaddr)); + Self { vaddr, size } + } +} + +pub trait GenericPageTable: Sync + Send { + /// Get the physical address of root page table. + fn table_phys(&self) -> PhysAddr; + + /// Map the `page` to the frame of `paddr` with `flags`. + fn map(&mut self, page: Page, paddr: PhysAddr, flags: MMUFlags) -> PagingResult; + + /// Unmap the page of `vaddr`. + fn unmap(&mut self, vaddr: VirtAddr) -> PagingResult<(PhysAddr, PageSize)>; + + /// Change the `flags` of the page of `vaddr`. + fn update( + &mut self, + vaddr: VirtAddr, + paddr: Option, + flags: Option, + ) -> PagingResult; + + /// Query the physical address which the page of `vaddr` maps to. + fn query(&self, vaddr: VirtAddr) -> PagingResult<(PhysAddr, MMUFlags, PageSize)>; + + fn map_cont( + &mut self, + start_vaddr: VirtAddr, + size: usize, + start_paddr: PhysAddr, + flags: MMUFlags, + ) -> PagingResult { + assert!(is_aligned(start_vaddr)); + assert!(is_aligned(start_vaddr)); + assert!(is_aligned(size)); + debug!( + "map_cont: {:#x?} => {:#x}, flags={:?}", + start_vaddr..start_vaddr + size, + start_paddr, + flags + ); + let mut vaddr = start_vaddr; + let mut paddr = start_paddr; + let end_vaddr = vaddr + size; + if flags.contains(MMUFlags::HUGE_PAGE) { + while vaddr < end_vaddr { + let remains = end_vaddr - vaddr; + let page_size = if remains >= PageSize::Size1G as usize + && PageSize::Size1G.is_aligned(vaddr) + && PageSize::Size1G.is_aligned(paddr) + { + PageSize::Size1G + } else if remains >= PageSize::Size2M as usize + && PageSize::Size2M.is_aligned(vaddr) + && PageSize::Size2M.is_aligned(paddr) + { + PageSize::Size2M + } else { + PageSize::Size4K + }; + let page = Page::new_aligned(vaddr, page_size); + self.map(page, paddr, flags)?; + vaddr += page_size as usize; + paddr += page_size as usize; + } + } else { + while vaddr < end_vaddr { + let page_size = PageSize::Size4K; + let page = Page::new_aligned(vaddr, page_size); + self.map(page, paddr, flags)?; + vaddr += page_size as usize; + paddr += page_size as usize; + } + } + Ok(()) + } + + fn unmap_cont(&mut self, start_vaddr: VirtAddr, size: usize) -> PagingResult { + assert!(is_aligned(start_vaddr)); + assert!(is_aligned(size)); + debug!("unmap_cont: {:#x?}", start_vaddr..start_vaddr + size,); + let mut vaddr = start_vaddr; + let end_vaddr = vaddr + size; + while vaddr < end_vaddr { + let page_size = match self.unmap(vaddr) { + Ok((_, s)) => { + assert!(s.is_aligned(vaddr)); + s as usize + } + Err(PagingError::NotMapped) => PageSize::Size4K as usize, + Err(e) => return Err(e), + }; + vaddr += page_size; + assert!(vaddr <= end_vaddr); + } + Ok(()) + } +} diff --git a/kernel-hal/src/config.rs b/kernel-hal/src/config.rs new file mode 100644 index 000000000..472381e1e --- /dev/null +++ b/kernel-hal/src/config.rs @@ -0,0 +1,6 @@ +use crate::utils::init_once::InitOnce; + +pub use super::imp::config::KernelConfig; + +#[allow(dead_code)] +pub(crate) static KCONFIG: InitOnce = InitOnce::new(); diff --git a/kernel-hal/src/dummy.rs b/kernel-hal/src/dummy.rs deleted file mode 100644 index 235f9d467..000000000 --- a/kernel-hal/src/dummy.rs +++ /dev/null @@ -1,485 +0,0 @@ -use super::*; -use crate::vdso::VdsoConstants; -use acpi::Acpi; -use alloc::boxed::Box; -use alloc::vec::Vec; -use core::future::Future; -use core::ops::FnOnce; -use core::pin::Pin; -use core::time::Duration; - -type ThreadId = usize; - -/// The error type which is returned from HAL functions. -#[derive(Debug)] -pub struct HalError; - -/// The result type returned by HAL functions. -pub type Result = core::result::Result; - -#[repr(C)] -pub struct Thread { - id: ThreadId, -} - -impl Thread { - /// Spawn a new thread. - #[linkage = "weak"] - #[export_name = "hal_thread_spawn"] - pub fn spawn( - _future: Pin + Send + 'static>>, - _vmtoken: usize, - ) -> Self { - unimplemented!() - } - - /// Set tid and pid of current task. - #[linkage = "weak"] - #[export_name = "hal_thread_set_tid"] - pub fn set_tid(_tid: u64, _pid: u64) { - unimplemented!() - } - - /// Get tid and pid of current task. - #[linkage = "weak"] - #[export_name = "hal_thread_get_tid"] - pub fn get_tid() -> (u64, u64) { - unimplemented!() - } -} - -#[linkage = "weak"] -#[export_name = "hal_context_run"] -pub fn context_run(_context: &mut UserContext) { - unimplemented!() -} - -pub trait PageTableTrait: Sync + Send { - /// Map the page of `vaddr` to the frame of `paddr` with `flags`. - fn map(&mut self, _vaddr: VirtAddr, _paddr: PhysAddr, _flags: MMUFlags) -> Result<()>; - - /// Unmap the page of `vaddr`. - fn unmap(&mut self, _vaddr: VirtAddr) -> Result<()>; - - /// Change the `flags` of the page of `vaddr`. - fn protect(&mut self, _vaddr: VirtAddr, _flags: MMUFlags) -> Result<()>; - - /// Query the physical address which the page of `vaddr` maps to. - fn query(&mut self, _vaddr: VirtAddr) -> Result; - - /// Get the physical address of root page table. - fn table_phys(&self) -> PhysAddr; - - #[cfg(target_arch = "riscv64")] - /// Activate this page table - fn activate(&self); - - fn map_many( - &mut self, - mut vaddr: VirtAddr, - paddrs: &[PhysAddr], - flags: MMUFlags, - ) -> Result<()> { - for &paddr in paddrs { - self.map(vaddr, paddr, flags)?; - vaddr += PAGE_SIZE; - } - Ok(()) - } - - fn map_cont( - &mut self, - mut vaddr: VirtAddr, - paddr: PhysAddr, - pages: usize, - flags: MMUFlags, - ) -> Result<()> { - for i in 0..pages { - let paddr = paddr + i * PAGE_SIZE; - self.map(vaddr, paddr, flags)?; - vaddr += PAGE_SIZE; - } - Ok(()) - } - - fn unmap_cont(&mut self, vaddr: VirtAddr, pages: usize) -> Result<()> { - for i in 0..pages { - self.unmap(vaddr + i * PAGE_SIZE)?; - } - Ok(()) - } -} - -/// Page Table -#[repr(C)] -pub struct PageTable { - table_phys: PhysAddr, -} - -impl PageTable { - /// Get current page table - #[linkage = "weak"] - #[export_name = "hal_pt_current"] - pub fn current() -> Self { - unimplemented!() - } - - /// Create a new `PageTable`. - #[allow(clippy::new_without_default)] - #[linkage = "weak"] - #[export_name = "hal_pt_new"] - pub fn new() -> Self { - unimplemented!() - } -} - -impl PageTableTrait for PageTable { - /// Map the page of `vaddr` to the frame of `paddr` with `flags`. - #[linkage = "weak"] - #[export_name = "hal_pt_map"] - fn map(&mut self, _vaddr: VirtAddr, _paddr: PhysAddr, _flags: MMUFlags) -> Result<()> { - unimplemented!() - } - /// Unmap the page of `vaddr`. - #[linkage = "weak"] - #[export_name = "hal_pt_unmap"] - fn unmap(&mut self, _vaddr: VirtAddr) -> Result<()> { - unimplemented!() - } - /// Change the `flags` of the page of `vaddr`. - #[linkage = "weak"] - #[export_name = "hal_pt_protect"] - fn protect(&mut self, _vaddr: VirtAddr, _flags: MMUFlags) -> Result<()> { - unimplemented!() - } - /// Query the physical address which the page of `vaddr` maps to. - #[linkage = "weak"] - #[export_name = "hal_pt_query"] - fn query(&mut self, _vaddr: VirtAddr) -> Result { - unimplemented!() - } - /// Get the physical address of root page table. - #[linkage = "weak"] - #[export_name = "hal_pt_table_phys"] - fn table_phys(&self) -> PhysAddr { - self.table_phys - } - - /// Activate this page table - #[cfg(target_arch = "riscv64")] - #[linkage = "weak"] - #[export_name = "hal_pt_activate"] - fn activate(&self) { - unimplemented!() - } - - #[linkage = "weak"] - #[export_name = "hal_pt_unmap_cont"] - fn unmap_cont(&mut self, vaddr: VirtAddr, pages: usize) -> Result<()> { - for i in 0..pages { - self.unmap(vaddr + i * PAGE_SIZE)?; - } - Ok(()) - } -} - -#[repr(C)] -pub struct PhysFrame { - paddr: PhysAddr, -} - -impl PhysFrame { - #[linkage = "weak"] - #[export_name = "hal_frame_alloc"] - pub fn alloc() -> Option { - unimplemented!() - } - - #[linkage = "weak"] - #[export_name = "hal_frame_alloc_contiguous"] - pub fn alloc_contiguous_base(_size: usize, _align_log2: usize) -> Option { - unimplemented!() - } - - pub fn alloc_contiguous(size: usize, align_log2: usize) -> Vec { - PhysFrame::alloc_contiguous_base(size, align_log2).map_or(Vec::new(), |base| { - (0..size) - .map(|i| PhysFrame { - paddr: base + i * PAGE_SIZE, - }) - .collect() - }) - } - - pub fn addr(&self) -> PhysAddr { - self.paddr - } - - #[linkage = "weak"] - #[export_name = "hal_zero_frame_paddr"] - pub fn zero_frame_addr() -> PhysAddr { - unimplemented!() - } -} - -impl Drop for PhysFrame { - #[linkage = "weak"] - #[export_name = "hal_frame_dealloc"] - fn drop(&mut self) { - unimplemented!() - } -} - -/// Read physical memory from `paddr` to `buf`. -#[linkage = "weak"] -#[export_name = "hal_pmem_read"] -pub fn pmem_read(_paddr: PhysAddr, _buf: &mut [u8]) { - unimplemented!() -} - -/// Write physical memory to `paddr` from `buf`. -#[linkage = "weak"] -#[export_name = "hal_pmem_write"] -pub fn pmem_write(_paddr: PhysAddr, _buf: &[u8]) { - unimplemented!() -} - -/// Zero physical memory at `[paddr, paddr + len)` -#[linkage = "weak"] -#[export_name = "hal_pmem_zero"] -pub fn pmem_zero(_paddr: PhysAddr, _len: usize) { - unimplemented!() -} - -/// Copy content of `src` frame to `target` frame. -#[linkage = "weak"] -#[export_name = "hal_frame_copy"] -pub fn frame_copy(_src: PhysAddr, _target: PhysAddr) { - unimplemented!() -} - -/// Flush the physical frame. -#[linkage = "weak"] -#[export_name = "hal_frame_flush"] -pub fn frame_flush(_target: PhysAddr) { - unimplemented!() -} - -/// Register a callback of serial readable event. -#[linkage = "weak"] -#[export_name = "hal_serial_set_callback"] -pub fn serial_set_callback(_callback: Box bool + Send + Sync>) { - unimplemented!() -} - -/// Read a string from console. -#[linkage = "weak"] -#[export_name = "hal_serial_read"] -pub fn serial_read(_buf: &mut [u8]) -> usize { - unimplemented!() -} - -/// Output a string to console. -#[linkage = "weak"] -#[export_name = "hal_serial_write"] -pub fn serial_write(_s: &str) { - unimplemented!() -} - -/// Get current time. -#[linkage = "weak"] -#[export_name = "hal_timer_now"] -pub fn timer_now() -> Duration { - unimplemented!() -} - -/// Set a new timer. After `deadline`, the `callback` will be called. -#[linkage = "weak"] -#[export_name = "hal_timer_set"] -pub fn timer_set(_deadline: Duration, _callback: Box) { - unimplemented!() -} - -#[linkage = "weak"] -#[export_name = "hal_timer_set_next"] -pub fn timer_set_next() { - unimplemented!() -} - -/// Check timers, call when timer interrupt happened. -#[linkage = "weak"] -#[export_name = "hal_timer_tick"] -pub fn timer_tick() { - unimplemented!() -} - -pub struct InterruptManager {} -impl InterruptManager { - /// Enable IRQ. - #[linkage = "weak"] - #[export_name = "hal_irq_enable"] - pub fn enable_irq(_vector: u32) { - unimplemented!() - } - /// Disable IRQ. - #[linkage = "weak"] - #[export_name = "hal_irq_disable"] - pub fn disable_irq(_vector: u32) { - unimplemented!() - } - /// Is a valid IRQ number. - #[linkage = "weak"] - #[export_name = "hal_irq_isvalid"] - pub fn is_valid_irq(_vector: u32) -> bool { - unimplemented!() - } - - /// Configure the specified interrupt vector. If it is invoked, it muust be - /// invoked prior to interrupt registration. - #[linkage = "weak"] - #[export_name = "hal_irq_configure"] - pub fn configure_irq(_vector: u32, _trig_mode: bool, _polarity: bool) -> bool { - unimplemented!() - } - /// Add an interrupt handle to an IRQ - #[linkage = "weak"] - #[export_name = "hal_irq_register_handler"] - pub fn register_irq_handler(_vector: u32, _handle: Box) -> Option { - unimplemented!() - } - /// Remove the interrupt handle to an IRQ - #[linkage = "weak"] - #[export_name = "hal_irq_unregister_handler"] - pub fn unregister_irq_handler(_vector: u32) -> bool { - unimplemented!() - } - /// Handle IRQ. - #[linkage = "weak"] - #[export_name = "hal_irq_handle"] - pub fn handle_irq(_vector: u32) { - unimplemented!() - } - - /// Method used for platform allocation of blocks of MSI and MSI-X compatible - /// IRQ targets. - #[linkage = "weak"] - #[export_name = "hal_msi_allocate_block"] - pub fn msi_allocate_block(_irq_num: u32) -> Option<(usize, usize)> { - unimplemented!() - } - /// Method used to free a block of MSI IRQs previously allocated by msi_alloc_block(). - /// This does not unregister IRQ handlers. - #[linkage = "weak"] - #[export_name = "hal_msi_free_block"] - pub fn msi_free_block(_irq_start: u32, _irq_num: u32) { - unimplemented!() - } - /// Register a handler function for a given msi_id within an msi_block_t. Passing a - /// NULL handler will effectively unregister a handler for a given msi_id within the - /// block. - #[linkage = "weak"] - #[export_name = "hal_msi_register_handler"] - pub fn msi_register_handler( - _irq_start: u32, - _irq_num: u32, - _msi_id: u32, - _handle: Box, - ) { - unimplemented!() - } -} - -/// Get platform specific information. -#[linkage = "weak"] -#[export_name = "hal_vdso_constants"] -pub fn vdso_constants() -> VdsoConstants { - unimplemented!() -} - -/// Get fault address of the last page fault. -#[linkage = "weak"] -#[export_name = "fetch_fault_vaddr"] -pub fn fetch_fault_vaddr() -> VirtAddr { - unimplemented!() -} - -#[linkage = "weak"] -#[export_name = "fetch_trap_num"] -pub fn fetch_trap_num(_context: &UserContext) -> usize { - unimplemented!() -} - -/// Get physical address of `acpi_rsdp` and `smbios` on x86_64. -#[linkage = "weak"] -#[export_name = "hal_pc_firmware_tables"] -pub fn pc_firmware_tables() -> (u64, u64) { - unimplemented!() -} - -/// Get ACPI Table -#[linkage = "weak"] -#[export_name = "hal_acpi_table"] -pub fn get_acpi_table() -> Option { - unimplemented!() -} - -/// IO Ports access on x86 platform -#[linkage = "weak"] -#[export_name = "hal_outpd"] -pub fn outpd(_port: u16, _value: u32) { - unimplemented!() -} - -#[linkage = "weak"] -#[export_name = "hal_inpd"] -pub fn inpd(_port: u16) -> u32 { - unimplemented!() -} - -/// Get local APIC ID -#[linkage = "weak"] -#[export_name = "hal_apic_local_id"] -pub fn apic_local_id() -> u8 { - unimplemented!() -} - -/// Fill random bytes to the buffer -#[cfg(target_arch = "x86_64")] -pub fn fill_random(buf: &mut [u8]) { - // TODO: optimize - for x in buf.iter_mut() { - let mut r = 0; - unsafe { - core::arch::x86_64::_rdrand16_step(&mut r); - } - *x = r as _; - } -} - -#[cfg(target_arch = "aarch64")] -pub fn fill_random(_buf: &mut [u8]) { - // TODO -} - -#[cfg(target_arch = "riscv64")] -pub fn fill_random(_buf: &mut [u8]) { - // TODO -} - -#[linkage = "weak"] -#[export_name = "hal_current_pgtable"] -pub fn current_page_table() -> usize { - unimplemented!() -} - -#[linkage = "weak"] -#[export_name = "hal_mice_set_callback"] -pub fn mice_set_callback(_callback: Box) { - unimplemented!() -} - -#[linkage = "weak"] -#[export_name = "hal_kbd_set_callback"] -pub fn kbd_set_callback(_callback: Box) { - unimplemented!() -} diff --git a/kernel-hal/src/hal_fn.rs b/kernel-hal/src/hal_fn.rs new file mode 100644 index 000000000..c1823b0b6 --- /dev/null +++ b/kernel-hal/src/hal_fn.rs @@ -0,0 +1,182 @@ +use alloc::boxed::Box; +use core::{fmt::Arguments, future::Future, ops::Range, pin::Pin, time::Duration}; + +use crate::{common, HalResult, MMUFlags, PhysAddr, VirtAddr}; + +hal_fn_def! { + pub mod cpu { + /// Current CPU ID. + pub fn cpu_id() -> u8 { 0 } + + /// Current CPU frequency. + pub fn cpu_frequency() -> u16 { 3000 } + } + + pub mod mem: common::mem { + /// Convert physical address to virtual address. + pub(crate) fn phys_to_virt(paddr: PhysAddr) -> VirtAddr; + + /// Read physical memory from `paddr` to `buf`. + pub fn pmem_read(paddr: PhysAddr, buf: &mut [u8]); + + /// Write physical memory to `paddr` from `buf`. + pub fn pmem_write(paddr: PhysAddr, buf: &[u8]); + + /// Zero physical memory at `[paddr, paddr + len)`. + pub fn pmem_zero(paddr: PhysAddr, len: usize); + + /// Copy content of physical memory `src` to `dst` with `len` bytes. + pub fn pmem_copy(dst: PhysAddr, src: PhysAddr, len: usize); + + /// Flush the physical frame. + pub fn frame_flush(target: PhysAddr); + } + + pub mod vm: common::vm { + /// Activate this page table by given `vmtoken`. + pub(crate) fn activate_paging(vmtoken: PhysAddr); + + /// Read current VM token. (e.g. CR3, SATP, ...) + pub(crate) fn current_vmtoken() -> PhysAddr; + + /// Flush TLB by the associated `vaddr`, or flush the entire TLB. (`vaddr` is `None`). + pub(crate) fn flush_tlb(vaddr: Option); + + /// Clone kernel space entries (top level only) from `src` page table to `dst` page table. + pub(crate) fn pt_clone_kernel_space(dst_pt_root: PhysAddr, src_pt_root: PhysAddr); + } + + pub mod interrupt { + /// Enable IRQ. + pub fn enable_irq(vector: u32); + + /// Disable IRQ. + pub fn disable_irq(vector: u32); + + /// Is a valid IRQ number. + pub fn is_valid_irq(vector: u32) -> bool; + + /// Configure the specified interrupt vector. If it is invoked, it muust be + /// invoked prior to interrupt registration. + pub fn configure_irq(vector: u32, trig_mode: bool, polarity: bool) -> HalResult; + + /// Add an interrupt handle to an IRQ + pub fn register_irq_handler(vector: u32, handler: Box) -> HalResult; + + /// Remove the interrupt handle to an IRQ + pub fn unregister_irq_handler(vector: u32) -> HalResult; + + /// Handle IRQ. + pub fn handle_irq(vector: u32); + + /// Method used for platform allocation of blocks of MSI and MSI-X compatible + /// IRQ targets. + pub fn msi_allocate_block(requested_irqs: u32) -> HalResult>; + + /// Method used to free a block of MSI IRQs previously allocated by msi_alloc_block(). + /// This does not unregister IRQ handlers. + pub fn msi_free_block(block: Range) -> HalResult; + + /// Register a handler function for a given msi_id within an msi_block_t. Passing a + /// NULL handler will effectively unregister a handler for a given msi_id within the + /// block. + pub fn msi_register_handler(block: Range, msi_id: u32, handler: Box) -> HalResult; + } + + pub mod context: common::context { + /// Enter user mode. + pub fn context_run(context: &mut UserContext) { + cfg_if! { + if #[cfg(feature = "libos")] { + context.run_fncall() + } else { + context.run() + } + } + } + + /// Get the trap number when trap. + pub fn fetch_trap_num(context: &UserContext) -> usize; + + /// Get the fault virtual address and access type of the last page fault by `info_reg` + /// (`error_code` for x86, `scause` for riscv). + pub fn fetch_page_fault_info(info_reg: usize) -> (VirtAddr, MMUFlags); + } + + pub mod thread { + /// Spawn a new thread. + pub fn spawn(future: Pin + Send + 'static>>, vmtoken: usize); + + /// Set tid and pid of current task. + pub fn set_tid(tid: u64, pid: u64); + + /// Get tid and pid of current task.] + pub fn get_tid() -> (u64, u64); + } + + pub mod timer { + /// Get current time. + pub fn timer_now() -> Duration; + + /// Set a new timer. After `deadline`, the `callback` will be called. + pub fn timer_set(deadline: Duration, callback: Box); + + /// Check timers, call when timer interrupt happened. + pub(crate) fn timer_tick(); + } + + pub mod serial: common::serial { + /// Print format string and its arguments to serial. + pub fn serial_write_fmt(fmt: Arguments); + } + + pub mod rand { + /// Fill random bytes to the buffer + #[allow(unused_variables)] + pub fn fill_random(buf: &mut [u8]) { + cfg_if! { + if #[cfg(target_arch = "x86_64")] { + // TODO: optimize + for x in buf.iter_mut() { + let mut r = 0; + unsafe { + core::arch::x86_64::_rdrand16_step(&mut r); + } + *x = r as _; + } + } else { + unimplemented!() + } + } + } + } + + pub mod vdso: common::vdso { + /// Get platform specific information. + pub fn vdso_constants() -> VdsoConstants { + vdso_constants_template() + } + } +} + +pub mod dev { + use super::*; + + hal_fn_def! { + pub mod fb: common::fb { + /// Initialize framebuffer. + pub fn init(); + } + + pub mod input { + /// Initialize input devices. + pub fn init(); + + /// Setup the callback when a keyboard event occurs. + pub fn kbd_set_callback(callback: Box); + + /// Setup the callback when a mouse event occurs. + pub fn mouse_set_callback(callback: Box); + } + } +} diff --git a/kernel-hal/src/kernel_handler.rs b/kernel-hal/src/kernel_handler.rs new file mode 100644 index 000000000..a369047e7 --- /dev/null +++ b/kernel-hal/src/kernel_handler.rs @@ -0,0 +1,35 @@ +//! Handlers implemented in kernel and called by HAL. + +use crate::{utils::init_once::InitOnce, MMUFlags, PhysAddr, VirtAddr}; + +pub trait KernelHandler: Send + Sync + 'static { + /// Allocate one physical frame. + fn frame_alloc(&self) -> Option { + unimplemented!() + } + + /// Allocate contiguous `frame_count` physical frames. + fn frame_alloc_contiguous(&self, _frame_count: usize, _align_log2: usize) -> Option { + unimplemented!() + } + + /// Deallocate a physical frame. + fn frame_dealloc(&self, _paddr: PhysAddr) { + unimplemented!() + } + + /// Handle kernel mode page fault. + fn handle_page_fault(&self, _fault_vaddr: VirtAddr, _access_flags: MMUFlags) { + // do nothing + } +} + +#[allow(dead_code)] +pub(crate) struct DummyKernelHandler; + +#[cfg(feature = "libos")] +pub(crate) static KHANDLER: InitOnce<&dyn KernelHandler> = + InitOnce::new_with_default(&DummyKernelHandler); + +#[cfg(not(feature = "libos"))] +pub(crate) static KHANDLER: InitOnce<&dyn KernelHandler> = InitOnce::new(); diff --git a/kernel-hal/src/lib.rs b/kernel-hal/src/lib.rs index a2009143b..dd0efa8ac 100644 --- a/kernel-hal/src/lib.rs +++ b/kernel-hal/src/lib.rs @@ -1,55 +1,37 @@ //! Hardware Abstraction Layer -#![no_std] -#![feature(linkage)] +#![cfg_attr(not(feature = "libos"), no_std)] +#![feature(asm)] #![deny(warnings)] extern crate alloc; -pub mod defs { - use bitflags::bitflags; - use numeric_enum_macro::numeric_enum; - - bitflags! { - pub struct MMUFlags: usize { - #[allow(clippy::identity_op)] - const CACHE_1 = 1 << 0; - const CACHE_2 = 1 << 1; - const READ = 1 << 2; - const WRITE = 1 << 3; - const EXECUTE = 1 << 4; - const USER = 1 << 5; - const RXW = Self::READ.bits | Self::WRITE.bits | Self::EXECUTE.bits; - } - } - numeric_enum! { - #[repr(u32)] - #[derive(Debug, PartialEq, Clone, Copy)] - pub enum CachePolicy { - Cached = 0, - Uncached = 1, - UncachedDevice = 2, - WriteCombining = 3, - } - } - pub const CACHE_POLICY_MASK: u32 = 3; +#[macro_use] +extern crate log; + +#[macro_use] +extern crate cfg_if; - pub type PhysAddr = usize; - pub type VirtAddr = usize; - pub type DevVAddr = usize; - pub const PAGE_SIZE: usize = 0x1000; +#[macro_use] +mod macros; + +mod common; +mod config; +mod hal_fn; +mod kernel_handler; +mod utils; + +cfg_if! { + if #[cfg(feature = "libos")] { + #[path = "libos/mod.rs"] + mod imp; + } else { + #[path = "bare/mod.rs"] + mod imp; + } } -mod context; -mod dummy; -mod fb; -mod future; -pub mod user; -pub mod vdso; - -pub use self::context::*; -pub use self::defs::*; -pub use self::dummy::*; -pub use self::fb::*; -pub use self::future::*; -pub use trapframe::{GeneralRegs, UserContext}; +pub use common::{addr, defs::*, future, user}; +pub use config::*; +pub use imp::*; +pub use kernel_handler::*; diff --git a/kernel-hal/src/libos/config.rs b/kernel-hal/src/libos/config.rs new file mode 100644 index 000000000..50aa18402 --- /dev/null +++ b/kernel-hal/src/libos/config.rs @@ -0,0 +1,3 @@ +/// Configuration of HAL. +#[derive(Debug)] +pub struct KernelConfig; diff --git a/kernel-hal/src/libos/dev/fb.rs b/kernel-hal/src/libos/dev/fb.rs new file mode 100644 index 000000000..7e07d4c0c --- /dev/null +++ b/kernel-hal/src/libos/dev/fb.rs @@ -0,0 +1,136 @@ +pub use crate::common::fb::*; + +#[repr(C)] +#[derive(Debug, Default)] +struct FbFixScreeninfo { + id: [u8; 16], + smem_start: u64, + smem_len: u32, + type_: u32, + type_aux: u32, + visual: u32, + xpanstep: u16, + ypanstep: u16, + ywrapstep: u16, + line_length: u32, + mmio_start: u64, + mmio_len: u32, + accel: u32, + capabilities: u16, + reserved: [u16; 2], +} + +impl FbFixScreeninfo { + pub fn size(&self) -> u32 { + self.smem_len + } +} + +#[repr(C)] +#[derive(Debug, Default)] +struct FbVarScreeninfo { + xres: u32, + yres: u32, + xres_virtual: u32, + yres_virtual: u32, + xoffset: u32, + yoffset: u32, + bits_per_pixel: u32, + grayscale: u32, + red: FbBitfield, + green: FbBitfield, + blue: FbBitfield, + transp: FbBitfield, + nonstd: u32, + activate: u32, + height: u32, + width: u32, + accel_flags: u32, + pixclock: u32, + left_margin: u32, + right_margin: u32, + upper_margin: u32, + lower_margin: u32, + hsync_len: u32, + vsync_len: u32, + sync: u32, + vmode: u32, + rotate: u32, + colorspace: u32, + reserved: [u32; 4], +} + +impl FbVarScreeninfo { + pub fn resolution(&self) -> (u32, u32) { + (self.xres, self.yres) + } +} + +#[repr(C)] +#[derive(Debug, Default)] +struct FbBitfield { + offset: u32, + length: u32, + msb_right: u32, +} + +hal_fn_impl! { + impl mod crate::hal_fn::dev::fb { + fn init() { + const FBIOGET_VSCREENINFO: u64 = 0x4600; + const FBIOGET_FSCREENINFO: u64 = 0x4602; + + #[cfg(target_arch = "aarch64")] + let fbfd = unsafe { libc::open("/dev/fb0".as_ptr(), libc::O_RDWR) }; + #[cfg(not(target_arch = "aarch64"))] + let fbfd = unsafe { libc::open("/dev/fb0".as_ptr() as *const i8, libc::O_RDWR) }; + if fbfd < 0 { + return; + } + + let mut vinfo = FbVarScreeninfo::default(); + if unsafe { libc::ioctl(fbfd, FBIOGET_VSCREENINFO, &mut vinfo) } < 0 { + return; + } + + let mut finfo = FbFixScreeninfo::default(); + if unsafe { libc::ioctl(fbfd, FBIOGET_FSCREENINFO, &mut finfo) } < 0 { + return; + } + + let size = finfo.size() as usize; + let addr = unsafe { + libc::mmap( + std::ptr::null_mut::(), + size, + libc::PROT_READ | libc::PROT_WRITE, + libc::MAP_SHARED, + fbfd, + 0, + ) + }; + if (addr as isize) < 0 { + return; + } + + let (width, height) = vinfo.resolution(); + let addr = addr as 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), + paddr: addr, + vaddr: addr, + screen_size: size, + }; + *FRAME_BUFFER.write() = Some(fb_info); + } + } +} diff --git a/kernel-hal/src/libos/dev/input.rs b/kernel-hal/src/libos/dev/input.rs new file mode 100644 index 000000000..a21e79184 --- /dev/null +++ b/kernel-hal/src/libos/dev/input.rs @@ -0,0 +1,100 @@ +use std::os::unix::io::AsRawFd; +use std::sync::Mutex; + +type MouseCallbackFn = dyn Fn([u8; 3]) + Send + Sync; +type KBDCallbackFn = dyn Fn(u16, i32) + Send + Sync; + +#[repr(C)] +#[derive(Debug, Copy, Clone, Default)] +struct TimeVal { + pub sec: usize, + pub usec: usize, +} + +#[repr(C)] +#[derive(Debug, Copy, Clone, Default)] +struct InputEvent { + time: TimeVal, + type_: u16, + code: u16, + value: i32, +} + +lazy_static::lazy_static! { + static ref MOUSE_CALLBACK: Mutex>> = Mutex::new(Vec::new()); + static ref KBD_CALLBACK: Mutex>> = Mutex::new(Vec::new()); +} + +fn init_kbd() { + let fd = std::fs::File::open("/dev/input/event1").expect("Failed to open input event device."); + // ?? + /* let inputfd = unsafe { + libc::open( + "/dev/input/event1".as_ptr() as *const i8, + libc::O_RDONLY /* | libc::O_NONBLOCK */, + ) + }; */ + if fd.as_raw_fd() < 0 { + return; + } + + std::thread::spawn(move || { + use core::mem::{size_of, transmute, transmute_copy}; + let ev = InputEvent::default(); + const LEN: usize = size_of::(); + let mut buf: [u8; LEN] = unsafe { transmute(ev) }; + loop { + std::thread::sleep(std::time::Duration::from_millis(8)); + let ret = + unsafe { libc::read(fd.as_raw_fd(), buf.as_mut_ptr() as *mut libc::c_void, LEN) }; + if ret < 0 { + break; + } + let ev: InputEvent = unsafe { transmute_copy(&buf) }; + if ev.type_ == 1 { + KBD_CALLBACK.lock().unwrap().iter().for_each(|callback| { + callback(ev.code, ev.value); + }); + } + } + }); +} + +fn init_mice() { + let fd = std::fs::File::open("/dev/input/mice").expect("Failed to open input event device."); + if fd.as_raw_fd() < 0 { + return; + } + + std::thread::spawn(move || { + let mut buf = [0u8; 3]; + loop { + std::thread::sleep(std::time::Duration::from_millis(8)); + let ret = + unsafe { libc::read(fd.as_raw_fd(), buf.as_mut_ptr() as *mut libc::c_void, 3) }; + if ret < 0 { + break; + } + MOUSE_CALLBACK.lock().unwrap().iter().for_each(|callback| { + callback(buf); + }); + } + }); +} + +hal_fn_impl! { + impl mod crate::hal_fn::dev::input { + fn kbd_set_callback(callback: Box) { + KBD_CALLBACK.lock().unwrap().push(callback); + } + + fn mouse_set_callback(callback: Box) { + MOUSE_CALLBACK.lock().unwrap().push(callback); + } + + fn init() { + init_kbd(); + init_mice(); + } + } +} diff --git a/kernel-hal/src/libos/dev/mod.rs b/kernel-hal/src/libos/dev/mod.rs new file mode 100644 index 000000000..087d38672 --- /dev/null +++ b/kernel-hal/src/libos/dev/mod.rs @@ -0,0 +1,2 @@ +pub mod fb; +pub mod input; diff --git a/kernel-hal/src/libos/dummy.rs b/kernel-hal/src/libos/dummy.rs new file mode 100644 index 000000000..ca98a398a --- /dev/null +++ b/kernel-hal/src/libos/dummy.rs @@ -0,0 +1,15 @@ +use super::mem_common::AVAILABLE_FRAMES; +use crate::{KernelHandler, PhysAddr}; + +impl KernelHandler for crate::DummyKernelHandler { + fn frame_alloc(&self) -> Option { + let ret = AVAILABLE_FRAMES.lock().unwrap().pop_front(); + trace!("frame alloc: {:?}", ret); + ret + } + + fn frame_dealloc(&self, paddr: PhysAddr) { + trace!("frame dealloc: {:?}", paddr); + AVAILABLE_FRAMES.lock().unwrap().push_back(paddr); + } +} diff --git a/kernel-hal-unix/src/macos.rs b/kernel-hal/src/libos/macos.rs similarity index 100% rename from kernel-hal-unix/src/macos.rs rename to kernel-hal/src/libos/macos.rs diff --git a/kernel-hal/src/libos/mem.rs b/kernel-hal/src/libos/mem.rs new file mode 100644 index 000000000..b1ccea0f5 --- /dev/null +++ b/kernel-hal/src/libos/mem.rs @@ -0,0 +1,45 @@ +use super::mem_common::{ensure_mmap_pmem, PMEM_BASE, PMEM_SIZE}; +use crate::{PhysAddr, VirtAddr}; + +hal_fn_impl! { + impl mod crate::hal_fn::mem { + fn phys_to_virt(paddr: PhysAddr) -> VirtAddr { + PMEM_BASE + paddr + } + + fn pmem_read(paddr: PhysAddr, buf: &mut [u8]) { + trace!("pmem read: paddr={:#x}, len={:#x}", paddr, buf.len()); + assert!(paddr + buf.len() <= PMEM_SIZE); + ensure_mmap_pmem(); + let src = phys_to_virt(paddr) as _; + unsafe { buf.as_mut_ptr().copy_from_nonoverlapping(src, buf.len()) }; + } + + fn pmem_write(paddr: PhysAddr, buf: &[u8]) { + trace!("pmem write: paddr={:#x}, len={:#x}", paddr, buf.len()); + assert!(paddr + buf.len() <= PMEM_SIZE); + ensure_mmap_pmem(); + let dst = phys_to_virt(paddr) as *mut u8; + unsafe { dst.copy_from_nonoverlapping(buf.as_ptr(), buf.len()) }; + } + + fn pmem_zero(paddr: PhysAddr, len: usize) { + trace!("pmem_zero: addr={:#x}, len={:#x}", paddr, len); + assert!(paddr + len <= PMEM_SIZE); + ensure_mmap_pmem(); + unsafe { core::ptr::write_bytes(phys_to_virt(paddr) as *mut u8, 0, len) }; + } + + fn pmem_copy(dst: PhysAddr, src: PhysAddr, len: usize) { + trace!("pmem_copy: {:#x} <- {:#x}, len={:#x}", dst, src, len); + assert!(src + len <= PMEM_SIZE && dst + len <= PMEM_SIZE); + ensure_mmap_pmem(); + let dst = phys_to_virt(dst) as *mut u8; + unsafe { dst.copy_from_nonoverlapping(phys_to_virt(src) as _, len) }; + } + + fn frame_flush(_target: PhysAddr) { + // do nothing + } + } +} diff --git a/kernel-hal/src/libos/mem_common.rs b/kernel-hal/src/libos/mem_common.rs new file mode 100644 index 000000000..f1c1a7ab3 --- /dev/null +++ b/kernel-hal/src/libos/mem_common.rs @@ -0,0 +1,70 @@ +use alloc::collections::VecDeque; +use std::fs::{File, OpenOptions}; +use std::io::Error; +use std::os::unix::io::AsRawFd; +use std::sync::Mutex; + +use crate::{mem::phys_to_virt, VirtAddr, PAGE_SIZE}; + +/// Map physical memory from here. +pub(super) const PMEM_BASE: VirtAddr = 0x8_0000_0000; +pub(super) const PMEM_SIZE: usize = 0x4000_0000; // 1GiB + +lazy_static::lazy_static! { + pub(super) static ref FRAME_FILE: File = create_pmem_file(); + pub(super) static ref AVAILABLE_FRAMES: Mutex> = + Mutex::new((PAGE_SIZE..PMEM_SIZE).step_by(PAGE_SIZE).collect()); +} + +/// Ensure physical memory are mmapped and accessible. +pub(super) fn ensure_mmap_pmem() { + FRAME_FILE.as_raw_fd(); +} + +pub(super) fn create_pmem_file() -> File { + let dir = tempfile::tempdir().expect("failed to create pmem dir"); + let path = dir.path().join("pmem"); + + // workaround on macOS to avoid permission denied. + // see https://jiege.ch/software/2020/02/07/macos-mmap-exec/ for analysis on this problem. + #[cfg(target_os = "macos")] + std::mem::forget(dir); + + let file = OpenOptions::new() + .read(true) + .write(true) + .create(true) + .open(&path) + .expect("failed to create pmem file"); + file.set_len(PMEM_SIZE as u64) + .expect("failed to resize file"); + trace!("create pmem file: path={:?}, size={:#x}", path, PMEM_SIZE); + let prot = libc::PROT_READ | libc::PROT_WRITE; + mmap(file.as_raw_fd(), 0, PMEM_SIZE, phys_to_virt(0), prot); + file +} + +/// Mmap frame file `fd` to `vaddr`. +pub(super) fn mmap(fd: libc::c_int, offset: usize, len: usize, vaddr: VirtAddr, prot: libc::c_int) { + // workaround on macOS to write text section. + #[cfg(target_os = "macos")] + let prot = if prot & libc::PROT_EXEC != 0 { + prot | libc::PROT_WRITE + } else { + prot + }; + + let ret = unsafe { + let flags = libc::MAP_SHARED | libc::MAP_FIXED; + libc::mmap(vaddr as _, len, prot, flags, fd, offset as _) + } as usize; + trace!( + "mmap file: fd={}, offset={:#x}, len={:#x}, vaddr={:#x}, prot={:#b}", + fd, + offset, + len, + vaddr, + prot, + ); + assert_eq!(ret, vaddr, "failed to mmap: {:?}", Error::last_os_error()); +} diff --git a/kernel-hal/src/libos/mod.rs b/kernel-hal/src/libos/mod.rs new file mode 100644 index 000000000..4415a0db3 --- /dev/null +++ b/kernel-hal/src/libos/mod.rs @@ -0,0 +1,47 @@ +mod mem_common; + +pub(super) mod dummy; + +pub mod config; +pub mod mem; +pub mod serial; +pub mod thread; +pub mod timer; +pub mod vdso; +pub mod vm; + +pub use super::hal_fn::{context, cpu, interrupt, rand}; + +hal_fn_impl_default!(context, cpu, interrupt, rand); + +cfg_if! { + if #[cfg(target_os = "linux")] { + pub mod dev; + } else { + pub use super::hal_fn::dev; + hal_fn_impl_default!(dev::fb, dev::input); + } +} + +#[cfg(target_os = "macos")] +include!("macos.rs"); + +/// Initialize the HAL. +/// +/// This function must be called at the beginning. +pub fn init() { + crate::KHANDLER.init_by(&crate::DummyKernelHandler); + + #[cfg(target_os = "macos")] + unsafe { + register_sigsegv_handler(); + } + // spawn a thread to read stdin + // TODO: raw mode + use std::io::Read; + std::thread::spawn(|| { + for i in std::io::stdin().bytes() { + serial::serial_put(i.unwrap()); + } + }); +} diff --git a/kernel-hal/src/libos/serial.rs b/kernel-hal/src/libos/serial.rs new file mode 100644 index 000000000..abefd20e6 --- /dev/null +++ b/kernel-hal/src/libos/serial.rs @@ -0,0 +1,7 @@ +hal_fn_impl! { + impl mod crate::hal_fn::serial { + fn serial_write_fmt(fmt: core::fmt::Arguments) { + eprint!("{}", fmt); + } + } +} diff --git a/kernel-hal/src/libos/thread.rs b/kernel-hal/src/libos/thread.rs new file mode 100644 index 000000000..c3157327e --- /dev/null +++ b/kernel-hal/src/libos/thread.rs @@ -0,0 +1,24 @@ +use async_std::task_local; +use core::{cell::Cell, future::Future, pin::Pin}; + +task_local! { + static TID: Cell = Cell::new(0); + static PID: Cell = Cell::new(0); +} + +hal_fn_impl! { + impl mod crate::hal_fn::thread { + fn spawn(future: Pin + Send + 'static>>, _vmtoken: usize) { + async_std::task::spawn(future); + } + + fn set_tid(tid: u64, pid: u64) { + TID.with(|x| x.set(tid)); + PID.with(|x| x.set(pid)); + } + + fn get_tid() -> (u64, u64) { + (TID.with(|x| x.get()), PID.with(|x| x.get())) + } + } +} diff --git a/kernel-hal/src/libos/timer.rs b/kernel-hal/src/libos/timer.rs new file mode 100644 index 000000000..66097dbf4 --- /dev/null +++ b/kernel-hal/src/libos/timer.rs @@ -0,0 +1,21 @@ +use std::time::{Duration, SystemTime}; + +hal_fn_impl! { + impl mod crate::hal_fn::timer { + fn timer_now() -> Duration { + SystemTime::now() + .duration_since(SystemTime::UNIX_EPOCH) + .unwrap() + } + + fn timer_set(deadline: Duration, callback: Box) { + std::thread::spawn(move || { + let now = timer_now(); + if deadline > now { + std::thread::sleep(deadline - now); + } + callback(timer_now()); + }); + } + } +} diff --git a/kernel-hal/src/libos/vdso.rs b/kernel-hal/src/libos/vdso.rs new file mode 100644 index 000000000..4169cb68c --- /dev/null +++ b/kernel-hal/src/libos/vdso.rs @@ -0,0 +1,9 @@ +hal_fn_impl! { + impl mod crate::hal_fn::vdso { + fn vdso_constants() -> VdsoConstants { + let mut constants = vdso_constants_template(); + constants.physmem = super::mem_common::PMEM_SIZE as u64; + constants + } + } +} diff --git a/kernel-hal/src/libos/vm.rs b/kernel-hal/src/libos/vm.rs new file mode 100644 index 000000000..4cb4a42ee --- /dev/null +++ b/kernel-hal/src/libos/vm.rs @@ -0,0 +1,132 @@ +use std::io::Error; +use std::os::unix::io::AsRawFd; + +use super::mem_common::{mmap, FRAME_FILE}; +use crate::{addr::is_aligned, MMUFlags, PhysAddr, VirtAddr, PAGE_SIZE}; + +hal_fn_impl! { + impl mod crate::hal_fn::vm { + fn current_vmtoken() -> PhysAddr { + 0 + } + } +} + +/// Page Table +pub struct PageTable; + +impl PageTable { + #[allow(clippy::new_without_default)] + pub fn new() -> Self { + Self + } + + pub fn from_current() -> Self { + Self + } + + pub fn clone_kernel(&self) -> Self { + Self::new() + } +} + +impl GenericPageTable for PageTable { + fn table_phys(&self) -> PhysAddr { + 0 + } + + fn map(&mut self, page: Page, paddr: PhysAddr, flags: MMUFlags) -> PagingResult { + debug_assert!(page.size as usize == PAGE_SIZE); + debug_assert!(is_aligned(paddr)); + mmap( + FRAME_FILE.as_raw_fd(), + paddr, + PAGE_SIZE, + page.vaddr, + flags.into(), + ); + Ok(()) + } + + fn unmap(&mut self, vaddr: VirtAddr) -> PagingResult<(PhysAddr, PageSize)> { + println!("unmap_page {:x?}", vaddr); + self.unmap_cont(vaddr, PAGE_SIZE)?; + Ok((0, PageSize::Size4K)) + } + + fn update( + &mut self, + vaddr: VirtAddr, + _paddr: Option, + flags: Option, + ) -> PagingResult { + debug_assert!(is_aligned(vaddr)); + if let Some(flags) = flags { + let ret = unsafe { libc::mprotect(vaddr as _, PAGE_SIZE, flags.into()) }; + assert_eq!(ret, 0, "failed to mprotect: {:?}", Error::last_os_error()); + } + Ok(PageSize::Size4K) + } + + fn query(&self, vaddr: VirtAddr) -> PagingResult<(PhysAddr, MMUFlags, PageSize)> { + debug_assert!(is_aligned(vaddr)); + unimplemented!() + } + + fn unmap_cont(&mut self, vaddr: VirtAddr, size: usize) -> PagingResult { + if size == 0 { + return Ok(()); + } + debug_assert!(is_aligned(vaddr)); + let ret = unsafe { libc::munmap(vaddr as _, size) }; + assert_eq!(ret, 0, "failed to munmap: {:?}", Error::last_os_error()); + Ok(()) + } +} + +impl From for libc::c_int { + fn from(f: MMUFlags) -> libc::c_int { + let mut flags = 0; + if f.contains(MMUFlags::READ) { + flags |= libc::PROT_READ; + } + if f.contains(MMUFlags::WRITE) { + flags |= libc::PROT_WRITE; + } + if f.contains(MMUFlags::EXECUTE) { + flags |= libc::PROT_EXEC; + } + flags + } +} + +#[cfg(test)] +mod tests { + use super::*; + + /// A valid virtual address base to mmap. + const VBASE: VirtAddr = 0x2_00000000; + + #[test] + fn map_unmap() { + let mut pt = PageTable::new(); + let flags = MMUFlags::READ | MMUFlags::WRITE; + // map 2 pages to 1 frame + pt.map(Page::new_aligned(VBASE, PageSize::Size4K), 0x1000, flags) + .unwrap(); + pt.map( + Page::new_aligned(VBASE + 0x1000, PageSize::Size4K), + 0x1000, + flags, + ) + .unwrap(); + + unsafe { + const MAGIC: usize = 0xdead_beaf; + (VBASE as *mut usize).write(MAGIC); + assert_eq!(((VBASE + 0x1000) as *mut usize).read(), MAGIC); + } + + pt.unmap(VBASE + 0x1000).unwrap(); + } +} diff --git a/kernel-hal/src/macros.rs b/kernel-hal/src/macros.rs new file mode 100644 index 000000000..1935037bd --- /dev/null +++ b/kernel-hal/src/macros.rs @@ -0,0 +1,173 @@ +macro_rules! hal_fn_def { + ( + $( + $vis:vis mod $mod_name:ident $( : $base:path )? { + $($fn:tt)* + } + )+ + ) => { + $( + $vis mod $mod_name { + #![allow(unused_imports)] + $( pub use $base::*; )? + use super::*; + pub(crate) trait __HalTrait { + __hal_fn_unimpl! { + mod $mod_name; + $($fn)* + } + } + pub(crate) struct __HalImpl; + __hal_fn_export! { + $($fn)* + } + } + )+ + }; + () => {}; +} + +macro_rules! hal_fn_impl { + ( + $( + impl mod $mod_name:ident$(::$mod_name_more:ident)* { + $($fn:item)* + } + )+ + ) => { + $( + __hal_fn_impl_no_export! { + impl mod $mod_name$(::$mod_name_more)* { + $($fn)* + } + } + #[allow(unused_imports)] + pub use $mod_name$(::$mod_name_more)*::*; + )+ + }; + () => {}; +} + +macro_rules! hal_fn_impl_default { + ( + $( $mod_name:ident$(::$mod_name_more:ident)* ),* + ) => { + __hal_fn_impl_no_export! { + $( impl mod $mod_name$(::$mod_name_more)* {} )* + } + } +} + +macro_rules! __hal_fn_unimpl { + ( + mod $mod_name:ident; + $(#[$inner:ident $($args:tt)*])* + $vis:vis fn $fn:ident ( $($arg:ident : $type:ty),* ) $( -> $ret:ty )?; + $($tail:tt)* + ) => { + $(#[$inner $($args)*])* + #[allow(unused_variables)] + fn $fn ( $($arg : $type),* ) $( -> $ret )? { + unimplemented!("{}::{}()", stringify!($mod_name), stringify!($fn)); + } + __hal_fn_unimpl! { + mod $mod_name; + $($tail)* + } + }; + ( + mod $mod_name:ident; + $(#[$inner:ident $($args:tt)*])* + $vis:vis fn $fn:ident ( $($arg:ident : $type:ty),* ) $( -> $ret:ty )? $body:block + $($tail:tt)* + ) => { + $(#[$inner $($args)*])* + fn $fn ( $($arg : $type),* ) $( -> $ret )? $body + __hal_fn_unimpl! { + mod $mod_name; + $($tail)* + } + }; + ( mod $mod_name:ident; ) => {}; +} + +macro_rules! __hal_fn_export { + ( + $(#[$inner:ident $($args:tt)*])* + $vis:vis fn $fn:ident ( $($arg:ident : $type:ty),* ) $( -> $ret:ty )?; + $($tail:tt)* + ) => { + $(#[$inner $($args)*])* + #[allow(dead_code)] + $vis fn $fn ( $($arg : $type),* ) $( -> $ret )? { + __HalImpl::$fn( $($arg),* ) + } + __hal_fn_export! { + $($tail)* + } + }; + ( + $(#[$inner:ident $($args:tt)*])* + $vis:vis fn $fn:ident ( $($arg:ident : $type:ty),* ) $( -> $ret:ty )? $body:block + $($tail:tt)* + ) => { + $(#[$inner $($args)*])* + #[allow(dead_code)] + $vis fn $fn ( $($arg : $type),* ) $( -> $ret )? { + __HalImpl::$fn( $($arg),* ) + } + __hal_fn_export! { + $($tail)* + } + }; + () => {}; +} + +macro_rules! __hal_fn_impl_no_export { + ( + $( + impl mod $mod_name:ident$(::$mod_name_more:ident)* { + $($fn:item)* + } + )+ + ) => { + $( + impl $mod_name$(::$mod_name_more)*::__HalTrait for $mod_name$(::$mod_name_more)*::__HalImpl { + $($fn)* + } + )+ + }; + () => {}; +} + +#[cfg(test)] +mod test { + mod base { + pub const BASE: usize = 0x2333; + } + hal_fn_def! { + mod mod0: self::base { + pub fn test() -> f32 { 1.0 } + } + mod mod1 { + pub fn foo() -> usize { 0 } + pub fn bar(a: usize) -> usize { a } + pub fn unimp(); + } + } + hal_fn_impl! { + impl mod self::mod1 { + fn foo() -> usize { 233 } + } + } + hal_fn_impl_default!(mod0); + + #[test] + fn test_hal_fn_marco() { + assert_eq!(mod0::BASE, 0x2333); + assert_eq!(mod0::test(), 1.0); + assert_eq!(mod1::foo(), 233); + assert_eq!(mod1::bar(0), 0); + // base::unimp(); // unimplemented! + } +} diff --git a/kernel-hal/src/utils/init_once.rs b/kernel-hal/src/utils/init_once.rs new file mode 100644 index 000000000..f9756efa8 --- /dev/null +++ b/kernel-hal/src/utils/init_once.rs @@ -0,0 +1,51 @@ +use spin::Once; + +pub struct InitOnce { + inner: Once, + default: Option, +} + +impl InitOnce { + pub const fn new() -> Self { + Self { + inner: Once::new(), + default: None, + } + } + + pub const fn new_with_default(value: T) -> Self { + Self { + inner: Once::new(), + default: Some(value), + } + } + + pub fn init_by(&self, value: T) { + self.inner.call_once(|| value); + } + + pub fn init(&self, f: F) + where + F: FnOnce() -> T, + { + self.inner.call_once(f); + } + + pub fn default(&self) -> Option<&T> { + self.default.as_ref() + } + + pub fn try_get(&self) -> Option<&T> { + self.inner.get() + } +} + +impl core::ops::Deref for InitOnce { + type Target = T; + fn deref(&self) -> &Self::Target { + self.inner + .get() + .or_else(|| self.default()) + .unwrap_or_else(|| panic!("uninitialized InitOnce<{}>", core::any::type_name::())) + } +} diff --git a/kernel-hal/src/utils/irq_manager.rs b/kernel-hal/src/utils/irq_manager.rs new file mode 100644 index 000000000..422ee5a31 --- /dev/null +++ b/kernel-hal/src/utils/irq_manager.rs @@ -0,0 +1,87 @@ +use alloc::boxed::Box; +use bitmap_allocator::{BitAlloc, BitAlloc256}; +use core::ops::Range; + +use crate::{HalError, HalResult}; + +pub type IrqHandler = Box; + +const IRQ_COUNT: usize = 256; + +pub struct IrqManager { + irq_range: Range, + table: [Option; IRQ_COUNT], + allocator: BitAlloc256, +} + +impl IrqManager { + pub fn new(irq_min_id: u32, irq_max_id: u32) -> Self { + const EMPTY_HANDLER: Option> = None; + let mut allocator = BitAlloc256::DEFAULT; + allocator.insert(irq_min_id as usize..irq_max_id as usize + 1); + Self { + irq_range: irq_min_id..irq_max_id + 1, + table: [EMPTY_HANDLER; IRQ_COUNT], + allocator, + } + } + + pub fn alloc_block(&mut self, count: u32) -> HalResult { + debug_assert!(count.is_power_of_two()); + let align_log2 = 31 - count.leading_zeros(); + self.allocator + .alloc_contiguous(count as usize, align_log2 as usize) + .map(|start| start as u32) + .ok_or(HalError) + } + + pub fn free_block(&mut self, start: u32, count: u32) -> HalResult { + self.allocator + .insert(start as usize..(start + count) as usize); + Ok(()) + } + + /// Add a handler to IRQ table. Return the specified irq or an allocated irq on success + pub fn register_handler(&mut self, vector: u32, handler: IrqHandler) -> HalResult { + info!("IRQ add handler {:#x?}", vector); + let vector = if !self.irq_range.contains(&vector) { + // allocate a valid irq number + self.alloc_block(1)? + } else if self.allocator.test(vector as usize) { + self.allocator.remove(vector as usize..vector as usize + 1); + vector + } else { + return Err(HalError); + }; + self.table[vector as usize] = Some(handler); + Ok(vector) + } + + pub fn unregister_handler(&mut self, vector: u32) -> HalResult { + info!("IRQ remove handler {:#x?}", vector); + if self.allocator.test(vector as usize) { + Err(HalError) + } else { + self.free_block(vector, 1)?; + self.table[vector as usize] = None; + Ok(()) + } + } + + pub fn overwrite_handler(&mut self, vector: u32, handler: IrqHandler) -> HalResult { + info!("IRQ overwrite handle {:#x?}", vector); + if self.allocator.test(vector as usize) { + Err(HalError) + } else { + self.table[vector as usize] = Some(handler); + Ok(()) + } + } + + pub fn handle(&self, vector: u32) { + match &self.table[vector as usize] { + Some(f) => f(), + None => panic!("unhandled external IRQ number: {}", vector), + } + } +} diff --git a/kernel-hal/src/utils/mod.rs b/kernel-hal/src/utils/mod.rs new file mode 100644 index 000000000..e8232c8cf --- /dev/null +++ b/kernel-hal/src/utils/mod.rs @@ -0,0 +1,10 @@ +#![allow(dead_code)] + +cfg_if! { + if #[cfg(not(feature = "libos"))] { + pub(crate) mod irq_manager; + pub(crate) mod page_table; + } +} + +pub(crate) mod init_once; diff --git a/kernel-hal/src/utils/page_table.rs b/kernel-hal/src/utils/page_table.rs new file mode 100644 index 000000000..ddee63e65 --- /dev/null +++ b/kernel-hal/src/utils/page_table.rs @@ -0,0 +1,319 @@ +use alloc::vec::Vec; +use core::{fmt::Debug, marker::PhantomData, slice}; + +use crate::common::vm::*; +use crate::{mem::PhysFrame, MMUFlags, PhysAddr, VirtAddr}; + +pub trait PageTableLevel: Sync + Send { + const LEVEL: usize; +} + +pub struct PageTableLevel3; +pub struct PageTableLevel4; + +impl PageTableLevel for PageTableLevel3 { + const LEVEL: usize = 3; +} + +impl PageTableLevel for PageTableLevel4 { + const LEVEL: usize = 4; +} + +pub trait GenericPTE: Debug + Clone + Copy + Sync + Send { + /// Returns the physical address mapped by this entry. + fn addr(&self) -> PhysAddr; + /// Returns the flags of this entry. + fn flags(&self) -> MMUFlags; + /// Returns whether this entry is zero. + fn is_unused(&self) -> bool; + /// Returns whether this entry flag indicates present. + fn is_present(&self) -> bool; + /// Returns whether this entry maps to a huge frame (or it's a terminal entry). + fn is_leaf(&self) -> bool; + + /// Set flags for all types of entries. + fn set_flags(&mut self, flags: MMUFlags, is_huge: bool); + /// Set physical address for terminal entries. + fn set_addr(&mut self, paddr: PhysAddr); + /// Set physical address and flags for intermediate table entries. + fn set_table(&mut self, paddr: PhysAddr); + /// Set this entry to zero. + fn clear(&mut self); +} + +pub struct PageTableImpl { + /// Root table frame. + root: PhysFrame, + /// Intermediate level table frames. + intrm_tables: Vec, + /// Phantom data. + _phantom: PhantomData<(L, PTE)>, +} + +/// Private implementation. +impl PageTableImpl { + unsafe fn from_root(root_paddr: PhysAddr) -> Self { + Self { + root: PhysFrame::from_paddr(root_paddr), + intrm_tables: Vec::new(), + _phantom: PhantomData, + } + } + + fn alloc_intrm_table(&mut self) -> Option { + let frame = PhysFrame::new_zero()?; + let paddr = frame.paddr(); + self.intrm_tables.push(frame); + Some(paddr) + } + + fn get_entry_mut(&self, vaddr: VirtAddr) -> PagingResult<(&mut PTE, PageSize)> { + let p3 = if L::LEVEL == 3 { + table_of_mut::(self.table_phys()) + } else if L::LEVEL == 4 { + let p4 = table_of_mut::(self.table_phys()); + let p4e = &mut p4[p4_index(vaddr)]; + next_table_mut(p4e)? + } else { + unreachable!() + }; + + let p3e = &mut p3[p3_index(vaddr)]; + if p3e.is_leaf() { + return Ok((p3e, PageSize::Size1G)); + } + + let p2 = next_table_mut(p3e)?; + let p2e = &mut p2[p2_index(vaddr)]; + if p2e.is_leaf() { + return Ok((p2e, PageSize::Size2M)); + } + + let p1 = next_table_mut(p2e)?; + let p1e = &mut p1[p1_index(vaddr)]; + Ok((p1e, PageSize::Size4K)) + } + + fn get_entry_mut_or_create(&mut self, page: Page) -> PagingResult<&mut PTE> { + let vaddr = page.vaddr; + let p3 = if L::LEVEL == 3 { + table_of_mut::(self.table_phys()) + } else if L::LEVEL == 4 { + let p4 = table_of_mut::(self.table_phys()); + let p4e = &mut p4[p4_index(vaddr)]; + next_table_mut_or_create(p4e, || self.alloc_intrm_table())? + } else { + unreachable!() + }; + + let p3e = &mut p3[p3_index(vaddr)]; + if page.size == PageSize::Size1G { + return Ok(p3e); + } + + let p2 = next_table_mut_or_create(p3e, || self.alloc_intrm_table())?; + let p2e = &mut p2[p2_index(vaddr)]; + if page.size == PageSize::Size2M { + return Ok(p2e); + } + + let p1 = next_table_mut_or_create(p2e, || self.alloc_intrm_table())?; + let p1e = &mut p1[p1_index(vaddr)]; + Ok(p1e) + } + + fn walk( + &self, + table: &[PTE], + level: usize, + start_vaddr: usize, + limit: usize, + func: &impl Fn(usize, usize, usize, &PTE), + ) { + let mut n = 0; + for (i, entry) in table.iter().enumerate() { + let vaddr = start_vaddr + (i << (12 + (3 - level) * 9)); + if entry.is_present() { + func(level, i, vaddr, entry); + if level < 3 && !entry.is_leaf() { + let table_entry = next_table_mut(entry).unwrap(); + self.walk(table_entry, level + 1, vaddr, limit, func); + } + n += 1; + if n >= limit { + break; + } + } + } + } + + fn dump(&self, limit: usize, print_fn: impl Fn(core::fmt::Arguments)) { + static LOCK: spin::Mutex<()> = spin::Mutex::new(()); + let _lock = LOCK.lock(); + + print_fn(format_args!("Root: {:x?}\n", self.table_phys())); + self.walk( + table_of(self.table_phys()), + 0, + 0, + limit, + &|level: usize, idx: usize, vaddr: usize, entry: &PTE| { + for _ in 0..level { + print_fn(format_args!(" ")); + } + print_fn(format_args!( + "[{} - {:x}], {:08x?}: {:x?}\n", + level, idx, vaddr, entry + )); + }, + ); + } + + pub(crate) unsafe fn activate(&mut self) { + crate::vm::activate_paging(self.table_phys()); + } +} + +/// Public implementation. +impl PageTableImpl { + #[allow(clippy::new_without_default)] + pub fn new() -> Self { + let root = PhysFrame::new_zero().expect("failed to alloc frame"); + Self { + root, + intrm_tables: Vec::new(), + _phantom: PhantomData, + } + } + + /// Create a new `PageTable` from current VM token. (e.g. CR3, SATP, ...) + pub fn from_current() -> Self { + unsafe { Self::from_root(crate::vm::current_vmtoken()) } + } + + pub fn clone_kernel(&self) -> Self { + let pt = Self::new(); + crate::vm::pt_clone_kernel_space(pt.table_phys(), self.table_phys()); + pt + } +} + +impl GenericPageTable for PageTableImpl { + fn table_phys(&self) -> PhysAddr { + self.root.paddr() + } + + fn map(&mut self, page: Page, paddr: PhysAddr, flags: MMUFlags) -> PagingResult { + let entry = self.get_entry_mut_or_create(page)?; + if !entry.is_unused() { + return Err(PagingError::AlreadyMapped); + } + entry.set_addr(page.size.align_down(paddr)); + entry.set_flags(flags, page.size.is_huge()); + crate::vm::flush_tlb(Some(page.vaddr)); + trace!( + "PageTable map: {:x?} -> {:x?}, flags={:?} in {:#x?}", + page, + paddr, + flags, + self.table_phys() + ); + Ok(()) + } + + fn unmap(&mut self, vaddr: VirtAddr) -> PagingResult<(PhysAddr, PageSize)> { + let (entry, size) = self.get_entry_mut(vaddr)?; + if entry.is_unused() { + return Err(PagingError::NotMapped); + } + let paddr = entry.addr(); + entry.clear(); + crate::vm::flush_tlb(Some(vaddr)); + trace!("PageTable unmap: {:x?} in {:#x?}", vaddr, self.table_phys()); + Ok((paddr, size)) + } + + fn update( + &mut self, + vaddr: VirtAddr, + paddr: Option, + flags: Option, + ) -> PagingResult { + let (entry, size) = self.get_entry_mut(vaddr)?; + if let Some(paddr) = paddr { + entry.set_addr(paddr); + } + if let Some(flags) = flags { + entry.set_flags(flags, size.is_huge()); + } + crate::vm::flush_tlb(Some(vaddr)); + trace!( + "PageTable update: {:x?}, flags={:?} in {:#x?}", + vaddr, + flags, + self.table_phys() + ); + Ok(size) + } + + fn query(&self, vaddr: VirtAddr) -> PagingResult<(PhysAddr, MMUFlags, PageSize)> { + let (entry, size) = self.get_entry_mut(vaddr)?; + if entry.is_unused() { + return Err(PagingError::NotMapped); + } + let off = size.page_offset(vaddr); + let ret = (entry.addr() + off, entry.flags(), size); + trace!("PageTable query: {:x?} => {:x?}", vaddr, ret); + Ok(ret) + } +} + +const ENTRY_COUNT: usize = 512; + +const fn p4_index(vaddr: usize) -> usize { + (vaddr >> (12 + 27)) & (ENTRY_COUNT - 1) +} + +const fn p3_index(vaddr: usize) -> usize { + (vaddr >> (12 + 18)) & (ENTRY_COUNT - 1) +} + +const fn p2_index(vaddr: usize) -> usize { + (vaddr >> (12 + 9)) & (ENTRY_COUNT - 1) +} + +const fn p1_index(vaddr: usize) -> usize { + (vaddr >> 12) & (ENTRY_COUNT - 1) +} + +fn table_of<'a, E>(paddr: PhysAddr) -> &'a [E] { + let ptr = crate::mem::phys_to_virt(paddr) as *const E; + unsafe { slice::from_raw_parts(ptr, ENTRY_COUNT) } +} + +fn table_of_mut<'a, E>(paddr: PhysAddr) -> &'a mut [E] { + let ptr = crate::mem::phys_to_virt(paddr) as *mut E; + unsafe { slice::from_raw_parts_mut(ptr, ENTRY_COUNT) } +} + +fn next_table_mut<'a, E: GenericPTE>(entry: &E) -> PagingResult<&'a mut [E]> { + if !entry.is_present() { + Err(PagingError::NotMapped) + } else { + debug_assert!(!entry.is_leaf()); + Ok(table_of_mut(entry.addr())) + } +} + +fn next_table_mut_or_create<'a, E: GenericPTE>( + entry: &mut E, + mut allocator: impl FnMut() -> Option, +) -> PagingResult<&'a mut [E]> { + if entry.is_unused() { + let paddr = allocator().ok_or(PagingError::NoMemory)?; + entry.set_table(paddr); + Ok(table_of_mut(paddr)) + } else { + next_table_mut(entry) + } +} diff --git a/linux-loader/Cargo.toml b/linux-loader/Cargo.toml index d0ae18d40..ff99230c2 100644 --- a/linux-loader/Cargo.toml +++ b/linux-loader/Cargo.toml @@ -16,10 +16,10 @@ zircon-object = { path = "../zircon-object" } kernel-hal = { path = "../kernel-hal" } rcore-fs-hostfs = { git = "https://github.com/rcore-os/rcore-fs", rev = "6df6cd2", optional = true } env_logger = { version = "0.8", optional = true } -kernel-hal-unix = { path = "../kernel-hal-unix", optional = true } async-std = { version = "1.9", features = ["attributes"], optional = true } [features] -default = ["std"] -std = ["env_logger", "async-std", "kernel-hal-unix", "rcore-fs-hostfs", "zircon-object/aspace-separate"] -graphic = ["std"] +default = ["std", "libos"] +libos = ["kernel-hal/libos"] +std = ["env_logger", "async-std", "rcore-fs-hostfs", "zircon-object/aspace-separate"] +graphic = ["std", "linux-object/graphic"] diff --git a/linux-loader/src/lib.rs b/linux-loader/src/lib.rs index e4c35c72b..ab8ec8362 100644 --- a/linux-loader/src/lib.rs +++ b/linux-loader/src/lib.rs @@ -11,7 +11,6 @@ extern crate log; use { alloc::{boxed::Box, string::String, sync::Arc, vec::Vec}, core::{future::Future, pin::Pin}, - kernel_hal::MMUFlags, linux_object::{ fs::{vfs::FileSystem, INodeExt}, loader::LinuxElfLoader, @@ -23,10 +22,10 @@ use { }; #[cfg(target_arch = "riscv64")] -use {kernel_hal::UserContext, zircon_object::object::KernelObject}; +use {kernel_hal::context::UserContext, zircon_object::object::KernelObject}; #[cfg(target_arch = "x86_64")] -use kernel_hal::GeneralRegs; +use kernel_hal::context::GeneralRegs; /// Create and run main Linux process pub fn run(args: Vec, envs: Vec, rootfs: Arc) -> Arc { @@ -35,7 +34,7 @@ pub fn run(args: Vec, envs: Vec, rootfs: Arc) -> let thread = Thread::create_linux(&proc).unwrap(); let loader = LinuxElfLoader { #[cfg(feature = "std")] - syscall_entry: kernel_hal_unix::syscall_entry as usize, + syscall_entry: kernel_hal::context::syscall_entry as usize, #[cfg(not(feature = "std"))] syscall_entry: 0, stack_pages: 8, @@ -57,7 +56,8 @@ pub fn run(args: Vec, envs: Vec, rootfs: Arc) -> let path = args[0].clone(); debug!("Linux process: {:?}", path); - let pg_token = kernel_hal::current_page_table(); + use kernel_hal::vm::{GenericPageTable, PageTable}; + let pg_token = PageTable::from_current().table_phys(); debug!("current pgt = {:#x}", pg_token); //调用zircon-object/src/task/thread.start设置好要执行的thread let (entry, sp) = loader.load(&proc.vmar(), &data, args, envs, path).unwrap(); @@ -86,7 +86,7 @@ async fn new_thread(thread: CurrentThread) { // run trace!("go to user: {:#x?}", cx); - kernel_hal::context_run(&mut cx); + kernel_hal::context::context_run(&mut cx); trace!("back from user: {:#x?}", cx); // handle trap/interrupt/syscall @@ -94,24 +94,22 @@ async fn new_thread(thread: CurrentThread) { match cx.trap_num { 0x100 => handle_syscall(&thread, &mut cx.general).await, 0x20..=0x3f => { - kernel_hal::InterruptManager::handle_irq(cx.trap_num as u32); + kernel_hal::interrupt::handle_irq(cx.trap_num as u32); if cx.trap_num == 0x20 { - kernel_hal::yield_now().await; + kernel_hal::future::yield_now().await; } } 0xe => { - let vaddr = kernel_hal::fetch_fault_vaddr(); - let flags = if cx.error_code & 0x2 == 0 { - MMUFlags::READ - } else { - MMUFlags::WRITE - }; - error!("page fualt from user mode {:#x} {:#x?}", vaddr, flags); + let (vaddr, flags) = kernel_hal::context::fetch_page_fault_info(cx.error_code); + error!("page fault from user mode @ {:#x}({:?})", vaddr, flags); let vmar = thread.proc().vmar(); match vmar.handle_page_fault(vaddr, flags) { Ok(()) => {} - Err(_) => { - panic!("Page Fault from user mode {:#x?}", cx); + Err(err) => { + panic!( + "Handle page fault from user mode error @ {:#x}({:?}): {:?}\n{:#x?}", + vaddr, flags, err, cx + ); } } } @@ -121,7 +119,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(); @@ -129,22 +127,16 @@ async fn new_thread(thread: CurrentThread) { match trap_num { //Irq 0 | 4 | 5 | 8 | 9 => { - kernel_hal::InterruptManager::handle_irq(trap_num as u32); + kernel_hal::interrupt::handle_irq(trap_num as u32); //Timer if trap_num == 4 || trap_num == 5 { debug!("Timer interrupt: {}", trap_num); - /* - * 已在irq_handle里加入了timer处理函数 - kernel_hal::timer_set_next(); - kernel_hal::timer_tick(); - */ - - kernel_hal::yield_now().await; + kernel_hal::future::yield_now().await; } - //kernel_hal::InterruptManager::handle_irq(trap_num as u32); + //kernel_hal::interrupt::handle_irq(trap_num as u32); } _ => panic!( "not supported pid: {} interrupt {} from user mode. {:#x?}", @@ -157,26 +149,19 @@ async fn new_thread(thread: CurrentThread) { 8 => handle_syscall(&thread, &mut cx).await, // PageFault 12 | 13 | 15 => { - let vaddr = kernel_hal::fetch_fault_vaddr(); - - //注意这里flags没有包含WRITE权限,后面handle会移除写权限 - let flags = if trap_num == 15 { - MMUFlags::WRITE - } else if trap_num == 12 { - MMUFlags::EXECUTE - } else { - MMUFlags::READ - }; - + let (vaddr, flags) = kernel_hal::context::fetch_page_fault_info(trap_num); info!( - "page fualt from pid: {} user mode, vaddr:{:#x}, trap:{}", + "page fault from pid: {} user mode, vaddr:{:#x}, trap:{}", pid, vaddr, trap_num ); let vmar = thread.proc().vmar(); match vmar.handle_page_fault(vaddr, flags) { Ok(()) => {} Err(error) => { - panic!("{:?} Page Fault from user mode {:#x?}", error, cx); + panic!( + "Page Fault from user mode @ {:#x}({:?}): {:?}\n{:#x?}", + vaddr, flags, error, cx + ); } } } @@ -204,7 +189,7 @@ async fn handle_syscall(thread: &CurrentThread, regs: &mut GeneralRegs) { let mut syscall = Syscall { thread, #[cfg(feature = "std")] - syscall_entry: kernel_hal_unix::syscall_entry as usize, + syscall_entry: kernel_hal::context::syscall_entry as usize, #[cfg(not(feature = "std"))] syscall_entry: 0, thread_fn, @@ -234,7 +219,7 @@ async fn handle_syscall(thread: &CurrentThread, cx: &mut UserContext) { let mut syscall = Syscall { thread, #[cfg(feature = "std")] - syscall_entry: kernel_hal_unix::syscall_entry as usize, + syscall_entry: kernel_hal::context::syscall_entry as usize, #[cfg(not(feature = "std"))] syscall_entry: 0, context: cx, diff --git a/linux-loader/src/main.rs b/linux-loader/src/main.rs index 614799b8b..5e3802603 100644 --- a/linux-loader/src/main.rs +++ b/linux-loader/src/main.rs @@ -15,16 +15,16 @@ async fn main() { // init loggger for debug init_logger(); // init HAL implementation on unix - kernel_hal_unix::init(); + kernel_hal::init(); #[cfg(feature = "graphic")] { - kernel_hal_unix::init_framebuffer(); - kernel_hal_unix::init_input(); + kernel_hal::dev::fb::init(); + kernel_hal::dev::input::init(); } - kernel_hal::serial_set_callback(Box::new({ + kernel_hal::serial::serial_set_callback(Box::new({ move || { let mut buffer = [0; 255]; - let len = kernel_hal::serial_read(&mut buffer); + let len = kernel_hal::serial::serial_read(&mut buffer); for c in &buffer[..len] { STDIN.push((*c).into()); } @@ -70,7 +70,7 @@ mod tests { /// test with cmd line async fn test(cmdline: &str) -> i64 { - kernel_hal_unix::init(); + kernel_hal::init(); let args: Vec = cmdline.split(' ').map(|s| s.into()).collect(); let envs = diff --git a/linux-object/Cargo.toml b/linux-object/Cargo.toml index d4ddcbd0f..73b44ac9f 100644 --- a/linux-object/Cargo.toml +++ b/linux-object/Cargo.toml @@ -7,6 +7,9 @@ description = "Linux kernel objects" # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html +[features] +graphic = [] + [dependencies] async-trait = "0.1" log = "0.4" @@ -24,3 +27,4 @@ rcore-fs-sfs = { git = "https://github.com/rcore-os/rcore-fs", rev = "6df6cd2" } rcore-fs-ramfs = { git = "https://github.com/rcore-os/rcore-fs", rev = "6df6cd2" } rcore-fs-mountfs = { git = "https://github.com/rcore-os/rcore-fs", rev = "6df6cd2" } rcore-fs-devfs = { git = "https://github.com/rcore-os/rcore-fs", rev = "6df6cd2" } +cfg-if = "1.0" diff --git a/linux-object/src/fs/fbdev.rs b/linux-object/src/fs/fbdev.rs index 85ed662a0..571ff3afd 100644 --- a/linux-object/src/fs/fbdev.rs +++ b/linux-object/src/fs/fbdev.rs @@ -1,7 +1,7 @@ //! Implement INode for framebuffer use core::any::Any; -use kernel_hal::{ColorFormat, FramebufferInfo, FRAME_BUFFER}; +use kernel_hal::dev::fb::{ColorFormat, FramebufferInfo, FRAME_BUFFER}; use rcore_fs::vfs::*; diff --git a/linux-object/src/fs/input/event.rs b/linux-object/src/fs/input/event.rs index a98fb06ce..64a090d93 100644 --- a/linux-object/src/fs/input/event.rs +++ b/linux-object/src/fs/input/event.rs @@ -3,6 +3,7 @@ use alloc::{boxed::Box, collections::VecDeque, sync::Arc}; use core::any::Any; use spin::Mutex; +use kernel_hal::dev::input; use rcore_fs::vfs::*; /// input device @@ -18,7 +19,7 @@ impl InputEventInode { pub fn new(id: usize) -> Self { let data = Arc::new(Mutex::new(VecDeque::with_capacity(MAX_QUEUE))); let data_clone = data.clone(); - kernel_hal::kbd_set_callback(Box::new(move |code, value| { + input::kbd_set_callback(Box::new(move |code, value| { let mut queue = data_clone.lock(); while queue.len() >= MAX_QUEUE { queue.pop_front(); diff --git a/linux-object/src/fs/input/mice.rs b/linux-object/src/fs/input/mice.rs index 0e4361ae9..0c3defdc7 100644 --- a/linux-object/src/fs/input/mice.rs +++ b/linux-object/src/fs/input/mice.rs @@ -2,6 +2,7 @@ use alloc::{boxed::Box, collections::VecDeque, sync::Arc}; use core::any::Any; use spin::Mutex; +use kernel_hal::dev::input; use rcore_fs::vfs::*; /// mice device @@ -15,7 +16,7 @@ impl InputMiceInode { pub fn new() -> Self { let data = Arc::new(Mutex::new(VecDeque::with_capacity(MAX_QUEUE))); let data_clone = data.clone(); - kernel_hal::mice_set_callback(Box::new(move |data| { + input::mouse_set_callback(Box::new(move |data| { let mut queue = data_clone.lock(); while queue.len() >= MAX_QUEUE { queue.pop_front(); diff --git a/linux-object/src/fs/mod.rs b/linux-object/src/fs/mod.rs index b4cf5d15d..986d72155 100644 --- a/linux-object/src/fs/mod.rs +++ b/linux-object/src/fs/mod.rs @@ -8,10 +8,8 @@ use rcore_fs_mountfs::MountFS; use rcore_fs_ramfs::RamFS; pub use self::device::*; -pub use self::fbdev::*; pub use self::fcntl::*; pub use self::file::*; -pub use self::input::*; pub use self::pipe::*; pub use self::pseudo::*; pub use self::random::*; @@ -26,16 +24,23 @@ use downcast_rs::impl_downcast; use zircon_object::object::*; mod device; -mod fbdev; mod fcntl; mod file; -mod input; mod ioctl; mod pipe; mod pseudo; mod random; mod stdio; +cfg_if::cfg_if! { + if #[cfg(feature = "graphic")] { + mod fbdev; + mod input; + pub use self::input::*; + pub use self::fbdev::*; + } +} + #[async_trait] /// Generic file interface /// @@ -123,17 +128,21 @@ pub fn create_root_fs(rootfs: Arc) -> Arc { devfs .add("urandom", Arc::new(RandomINode::new(true))) .expect("failed to mknod /dev/urandom"); - devfs - .add("fb0", Arc::new(Fbdev::default())) - .expect("failed to mknod /dev/fb0"); - // TODO /dev/input/event0 - devfs - .add("input-event0", Arc::new(InputEventInode::new(0))) - .expect("failed to mknod /dev/input-event0"); - // TODO /dev/input/mice - devfs - .add("input-mice", Arc::new(InputMiceInode::default())) - .expect("failed to mknod /dev/input-mice"); + + #[cfg(feature = "graphic")] + { + devfs + .add("fb0", Arc::new(Fbdev::default())) + .expect("failed to mknod /dev/fb0"); + // TODO /dev/input/event0 + devfs + .add("input-event0", Arc::new(InputEventInode::new(0))) + .expect("failed to mknod /dev/input-event0"); + // TODO /dev/input/mice + devfs + .add("input-mice", Arc::new(InputMiceInode::default())) + .expect("failed to mknod /dev/input-mice"); + } // mount DevFS at /dev let dev = root.find(true, "dev").unwrap_or_else(|_| { diff --git a/linux-object/src/fs/stdio.rs b/linux-object/src/fs/stdio.rs index 308443755..8a3af3663 100644 --- a/linux-object/src/fs/stdio.rs +++ b/linux-object/src/fs/stdio.rs @@ -132,7 +132,7 @@ impl INode for Stdout { fn write_at(&self, _offset: usize, buf: &[u8]) -> Result { // 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_write(s); + kernel_hal::serial::serial_write(s); Ok(buf.len()) } fn poll(&self) -> Result { diff --git a/linux-object/src/time.rs b/linux-object/src/time.rs index b0a721143..2874d3b84 100644 --- a/linux-object/src/time.rs +++ b/linux-object/src/time.rs @@ -2,7 +2,6 @@ use alloc::sync::Arc; use core::time::Duration; -use kernel_hal::timer_now; use rcore_fs::vfs::*; /// TimeSpec struct for clock_gettime, similar to Timespec @@ -39,7 +38,7 @@ impl TimeVal { impl TimeSpec { /// create TimeSpec pub fn now() -> TimeSpec { - let time = timer_now(); + let time = kernel_hal::timer::timer_now(); TimeSpec { sec: time.as_secs() as usize, nsec: (time.as_nanos() % 1_000_000_000) as usize, diff --git a/linux-syscall/src/file/poll.rs b/linux-syscall/src/file/poll.rs index 6084fd896..3ca11c643 100644 --- a/linux-syscall/src/file/poll.rs +++ b/linux-syscall/src/file/poll.rs @@ -12,7 +12,7 @@ use core::mem::size_of; use core::pin::Pin; use core::task::{Context, Poll}; use core::time::Duration; -use kernel_hal::timer_set; +use kernel_hal::timer::timer_set; use linux_object::fs::FileDesc; use linux_object::time::*; diff --git a/linux-syscall/src/lib.rs b/linux-syscall/src/lib.rs index cae97a537..8671fcab9 100644 --- a/linux-syscall/src/lib.rs +++ b/linux-syscall/src/lib.rs @@ -8,7 +8,7 @@ //! let mut syscall = Syscall { //! thread, //! #[cfg(feature = "std")] -//! syscall_entry: kernel_hal_unix::syscall_entry as usize, +//! syscall_entry: kernel_hal::context::syscall_entry as usize, //! #[cfg(not(feature = "std"))] //! syscall_entry: 0, //! thread_fn, @@ -32,13 +32,13 @@ use { self::consts::SyscallType as Sys, alloc::sync::Arc, core::convert::TryFrom, - kernel_hal::{user::*, GeneralRegs}, + kernel_hal::{context::GeneralRegs, user::*}, linux_object::{error::*, fs::FileDesc, process::*}, zircon_object::{object::*, task::*, vm::VirtAddr}, }; #[cfg(target_arch = "riscv64")] -use kernel_hal::UserContext; +use kernel_hal::context::UserContext; mod consts { // generated from syscall.h.in diff --git a/linux-syscall/src/misc.rs b/linux-syscall/src/misc.rs index 4bf873885..fb340915e 100644 --- a/linux-syscall/src/misc.rs +++ b/linux-syscall/src/misc.rs @@ -132,7 +132,7 @@ impl Syscall<'_> { pub fn sys_getrandom(&mut self, mut buf: UserOutPtr, len: usize, flag: u32) -> SysResult { info!("getrandom: buf: {:?}, len: {:?}, flag {:?}", buf, len, flag); let mut buffer = vec![0u8; len]; - kernel_hal::fill_random(&mut buffer); + kernel_hal::rand::fill_random(&mut buffer); buf.write_array(&buffer[..len])?; Ok(len) } diff --git a/linux-syscall/src/task.rs b/linux-syscall/src/task.rs index d6b4c0a51..0fd79f5aa 100644 --- a/linux-syscall/src/task.rs +++ b/linux-syscall/src/task.rs @@ -297,7 +297,7 @@ impl Syscall<'_> { pub async fn sys_nanosleep(&self, req: UserInPtr) -> SysResult { info!("nanosleep: deadline={:?}", req); let req = req.read()?; - kernel_hal::sleep_until(req.into()).await; + kernel_hal::future::sleep_until(req.into()).await; Ok(0) } diff --git a/scripts/libc-tests.py b/scripts/libc-tests.py index e716ed87f..9f97535cc 100755 --- a/scripts/libc-tests.py +++ b/scripts/libc-tests.py @@ -1,15 +1,17 @@ import os +import time import glob import subprocess +from termcolor import colored # ===============Must Config======================== -TIMEOUT = 5 # seconds +TIMEOUT = 10 # seconds ZCORE_PATH = '../zCore' BASE = 'linux/' OUTPUT_FILE = BASE + 'test-output.txt' RESULT_FILE = BASE + 'test-result.txt' -CHECK_FILE = BASE + 'test-allow-failed.txt' +CHECK_FILE = BASE + 'libos-test-allow-failed.txt' # ============================================== @@ -17,41 +19,58 @@ failed = set() timeout = set() -for path in glob.glob("../rootfs/libc-test/src/*/*.exe"): + +def print_cases(cases, file=None): + for case in sorted(cases): + print(case, file=file) + + +subprocess.run("cd .. && cargo build --release -p linux-loader", + shell=True, check=True) + +for path in sorted(glob.glob("../rootfs/libc-test/src/*/*.exe")): path = path[len('../rootfs'):] # ignore static linked tests if path.endswith('-static.exe'): continue try: - subprocess.run("cd .. && cargo run --release -p linux-loader -- " + path, + time_start = time.time() + subprocess.run("cd .. && ./target/release/linux-loader " + path, shell=True, timeout=TIMEOUT, check=True) + time_end = time.time() passed.add(path) + print(colored('PASSED in %.3fs: %s' % (time_end - time_start, path), 'green')) except subprocess.CalledProcessError: failed.add(path) + print(colored('FAILED: %s' % path, 'red')) except subprocess.TimeoutExpired: timeout.add(path) + print(colored('TIMEOUT: %s' % path, 'yellow')) with open(RESULT_FILE, "w") as f: print('PASSED:', file=f) - for case in passed: - print(case, file=f) + print_cases(passed, file=f) print('FAILED:', file=f) - for case in failed: - print(case, file=f) + print_cases(failed, file=f) print('TIMEOUT:', file=f) - for case in timeout: - print(case, file=f) + print_cases(timeout, file=f) with open(CHECK_FILE, 'r') as f: allow_failed = set([case.strip() for case in f.readlines()]) +more_passed = passed & allow_failed +if more_passed: + print(colored('=== Passed more cases ===', 'green')) + print_cases(more_passed) + check_failed = (failed | timeout) - allow_failed if check_failed: - print('=== Failed cases ===') - for case in check_failed: - print(case) + print(colored('=== Failed cases ===', 'red')) + print_cases(failed - allow_failed) + print(colored('=== Timeout cases ===', 'yellow')) + print_cases(timeout - allow_failed) exit(1) else: - print('All checked case passed!') + print(colored('All checked case passed!', 'green')) os.system('killall linux-loader') diff --git a/scripts/linux/test-allow-failed.txt b/scripts/linux/libos-test-allow-failed.txt similarity index 76% rename from scripts/linux/test-allow-failed.txt rename to scripts/linux/libos-test-allow-failed.txt index ddfd69af9..76c27b55e 100644 --- a/scripts/linux/test-allow-failed.txt +++ b/scripts/linux/libos-test-allow-failed.txt @@ -1,51 +1,39 @@ /libc-test/src/common/runtest.exe -/libc-test/src/regression/getpwnam_r-errno.exe -/libc-test/src/regression/pthread_atfork-errno-clobber.exe -/libc-test/src/regression/sigreturn.exe -/libc-test/src/regression/pthread-robust-detach.exe -/libc-test/src/regression/fflush-exit.exe -/libc-test/src/regression/daemon-failure.exe -/libc-test/src/regression/rewind-clear-error.exe -/libc-test/src/regression/statvfs.exe -/libc-test/src/regression/pthread_exit-dtor.exe -/libc-test/src/regression/rlimit-open-files.exe -/libc-test/src/regression/getpwnam_r-crash.exe -/libc-test/src/functional/strptime.exe -/libc-test/src/functional/pthread_cancel-points.exe -/libc-test/src/functional/tls_align_dlopen.exe -/libc-test/src/functional/sem_open.exe -/libc-test/src/functional/tls_init_dlopen.exe -/libc-test/src/functional/ipc_shm.exe -/libc-test/src/functional/vfork.exe -/libc-test/src/functional/strtod_long.exe -/libc-test/src/functional/utime.exe -/libc-test/src/functional/setjmp.exe -/libc-test/src/functional/ipc_sem.exe /libc-test/src/functional/fcntl.exe /libc-test/src/functional/ipc_msg.exe +/libc-test/src/functional/ipc_sem.exe +/libc-test/src/functional/ipc_shm.exe +/libc-test/src/functional/popen.exe +/libc-test/src/functional/pthread_cancel-points.exe +/libc-test/src/functional/pthread_robust.exe +/libc-test/src/functional/sem_open.exe /libc-test/src/functional/socket.exe +/libc-test/src/functional/spawn.exe +/libc-test/src/functional/strptime.exe +/libc-test/src/functional/strtod_long.exe /libc-test/src/functional/tls_align.exe -/libc-test/src/functional/pthread_robust.exe -/libc-test/src/math/powf.exe +/libc-test/src/functional/tls_align_dlopen.exe +/libc-test/src/functional/tls_init_dlopen.exe +/libc-test/src/functional/utime.exe +/libc-test/src/functional/vfork.exe /libc-test/src/math/fmal.exe -/libc-test/src/math/modfl.exe -/libc-test/src/math/roundl.exe -/libc-test/src/regression/pthread_cond_wait-cancel_ignored.exe -/libc-test/src/regression/raise-race.exe -/libc-test/src/regression/pthread_once-deadlock.exe -/libc-test/src/regression/pthread_cond-smasher.exe -/libc-test/src/regression/pthread_condattr_setclock.exe -/libc-test/src/functional/pthread_mutex_pi.exe -/libc-test/src/functional/pthread_cancel.exe -/libc-test/src/functional/pthread_mutex.exe -/libc-test/src/functional/spawn.exe -/libc-test/src/functional/popen.exe +/libc-test/src/math/powf.exe +/libc-test/src/regression/daemon-failure.exe /libc-test/src/regression/execle-env.exe -/libc-test/src/regression/malloc-oom.exe -/libc-test/src/regression/pthread_create-oom.exe -/libc-test/src/regression/setenv-oom.exe -/libc-test/src/regression/flockfile-list.exe -/libc-test/src/regression/malloc-brk-fail.exe -/libc-test/src/regression/iconv-roundtrips.exe +/libc-test/src/regression/fflush-exit.exe +/libc-test/src/regression/getpwnam_r-crash.exe +/libc-test/src/regression/getpwnam_r-errno.exe +/libc-test/src/regression/pthread-robust-detach.exe +/libc-test/src/regression/pthread_atfork-errno-clobber.exe +/libc-test/src/regression/pthread_exit-dtor.exe /libc-test/src/regression/sem_close-unmap.exe -/libc-test/src/regression/fgets-eof.exe \ No newline at end of file +/libc-test/src/regression/sigreturn.exe +/libc-test/src/regression/statvfs.exe +/libc-test/src/functional/pthread_cancel.exe +/libc-test/src/functional/pthread_mutex.exe +/libc-test/src/functional/pthread_mutex_pi.exe +/libc-test/src/regression/pthread_cond-smasher.exe +/libc-test/src/regression/pthread_cond_wait-cancel_ignored.exe +/libc-test/src/regression/pthread_condattr_setclock.exe +/libc-test/src/regression/pthread_once-deadlock.exe +/libc-test/src/regression/raise-race.exe diff --git a/scripts/requirements.txt b/scripts/requirements.txt new file mode 100644 index 000000000..f08cca141 --- /dev/null +++ b/scripts/requirements.txt @@ -0,0 +1 @@ +termcolor diff --git a/scripts/zircon/test-check-passed.txt b/scripts/zircon/test-check-passed.txt index b6485a17d..5f18a5b5a 100644 --- a/scripts/zircon/test-check-passed.txt +++ b/scripts/zircon/test-check-passed.txt @@ -1,482 +1,511 @@ -ConditionalVariableTest.BroadcastSignalThreadWait -ConditionalVariableTest.SignalThreadWait -ConditionalVariableTest.ConditionalVariablesTimeout -C11MutexTest.MultiThreadedContention -C11MutexTest.TryMutexMultiThreadedContention +Bti.Clone +Bti.Create +Bti.GetInfoTest +Bti.Pin +Bti.PinContigFlag +Bti.PinContiguous +Bti.Resize C11MutexTest.InitalizeLocalMutex +C11MutexTest.MultiThreadedContention C11MutexTest.StaticInitalizerSameBytesAsAuto C11MutexTest.TimeoutElapsed -C11ThreadTest.ThreadLocalErrno -C11ThreadTest.NullNameThreadShouldSucceed +C11MutexTest.TryMutexMultiThreadedContention C11ThreadTest.CreateAndVerifyThreadHandle C11ThreadTest.DetachedThreadKeepsRunning C11ThreadTest.LongNameSucceeds +C11ThreadTest.NullNameThreadShouldSucceed C11ThreadTest.SelfDetachAndFree -CppThreadTest.CreateAndVerifyThreadHandle +C11ThreadTest.ThreadLocalErrno ChannelInternalTest.CallFinishWithoutPreviouslyCallingCallReturnsBadState ChannelInternalTest.TransferChannelWithPendingCallInSourceProcess -ChannelTest.CreateIsOkAndEndpointsAreRelated -ChannelTest.IsWriteableByDefault -ChannelTest.WriteToEndpointCausesOtherToBecomeReadable -ChannelTest.WriteConsumesAllHandles -ChannelTest.WaitManyIsSignaledOnAnyElementWrite -ChannelTest.WaitManyIsSignaledForBothWrites -ChannelTest.ReadWhenEmptyReturnsShouldWait -ChannelTest.ReadWhenEmptyAndClosedReturnsPeerClosed -ChannelTest.ReadRemainingMessagesWhenPeerIsClosed -ChannelTest.CloseSignalsPeerClosed -ChannelTest.CloseClearsSignalsWriteable -ChannelTest.CloseSignalsPeerReturnsPeerClosed -ChannelTest.OnFlightHandlesSignalledWhenPeerIsClosed -ChannelTest.WriteNonTransferableHandleReturnsAccessDeniedAndClosesHandle -ChannelTest.WriteRepeatedHandlesReturnsBadHandlesAndClosesHandle -ChannelTest.ConcurrentReadsConsumeUniqueElements -ChannelTest.ReadMayDiscardWithNullBuffersReturnsBufferTooSmall -ChannelTest.ReadMayDiscardWithNullBufferDiscardsDataReturnsBufferTooSmall -ChannelTest.ReadMayDiscardWithNullBufferDiscardHandlesReturnsBufferTooSmall -ChannelTest.ReadMayDiscardWithZeroSizeBuffersDiscardHandlesAndDataReturnsBufferTooSmall -ChannelTest.ReadMayDiscardWithSmallerBufferDiscardHandlesAndDateReturnsBufferTooSmall -ChannelTest.CallWrittenBytesSmallerThanZxTxIdReturnsInvalidArgs -ChannelTest.CallResponseBiggerThanRdNumBytesReturnsBufferTooSmall -ChannelTest.CallResponseBiggerThanRdNumHandlesReturnsBufferTooSmall ChannelTest.CallBytesFitIsOk -ChannelTest.CallHandlesFitIsOk +ChannelTest.CallConsumesHandlesOnError +ChannelTest.CallConsumesHandlesOnSuccess +ChannelTest.CallDeadlineExceededReturnsTimedOut ChannelTest.CallHandleAndBytesFitsIsOk +ChannelTest.CallHandlesFitIsOk +ChannelTest.CallNotifiedOnPeerClosed ChannelTest.CallNullptrNumBytesIsInvalidArgs ChannelTest.CallNullptrNumHandlesInvalidArgs ChannelTest.CallPendingTransactionsUseDifferentIds -ChannelTest.CallDeadlineExceededReturnsTimedOut -ChannelTest.CallConsumesHandlesOnSuccess -ChannelTest.CallConsumesHandlesOnError -ChannelTest.CallNotifiedOnPeerClosed +ChannelTest.CallResponseBiggerThanRdNumBytesReturnsBufferTooSmall +ChannelTest.CallResponseBiggerThanRdNumHandlesReturnsBufferTooSmall +ChannelTest.CallWrittenBytesSmallerThanZxTxIdReturnsInvalidArgs +ChannelTest.CloseClearsSignalsWriteable +ChannelTest.CloseSignalsPeerClosed +ChannelTest.CloseSignalsPeerReturnsPeerClosed +ChannelTest.ConcurrentReadsConsumeUniqueElements +ChannelTest.CreateIsOkAndEndpointsAreRelated +ChannelTest.IsWriteableByDefault ChannelTest.NestingIsOk -ChannelTest.WriteSelfHandleReturnsNotSupported -ChannelTest.ReadEtcHandleInfoValidation +ChannelTest.OnFlightHandlesSignalledWhenPeerIsClosed ChannelTest.ReadAndWriteWithMultipleSizes -ChannelWriteEtcTest.MultipleHandlesSomeInvalidResultsReportedCorrectly -ChannelWriteEtcTest.ImproperlyInitalizedResultsArgReportedBackAsOriginallyInitalized -ChannelWriteEtcTest.FailureDoesNotResultInReceivedPacket -ChannelWriteEtcTest.SentHandleReferrsToSameObject -ChannelWriteEtcTest.InvalidOpArgShouldFail -ChannelWriteEtcTest.HandleArgNotAChannelHandleShouldFail +ChannelTest.ReadEtcHandleInfoValidation +ChannelTest.ReadMayDiscardWithNullBufferDiscardHandlesReturnsBufferTooSmall +ChannelTest.ReadMayDiscardWithNullBufferDiscardsDataReturnsBufferTooSmall +ChannelTest.ReadMayDiscardWithNullBuffersReturnsBufferTooSmall +ChannelTest.ReadMayDiscardWithSmallerBufferDiscardHandlesAndDateReturnsBufferTooSmall +ChannelTest.ReadMayDiscardWithZeroSizeBuffersDiscardHandlesAndDataReturnsBufferTooSmall +ChannelTest.ReadRemainingMessagesWhenPeerIsClosed +ChannelTest.ReadWhenEmptyAndClosedReturnsPeerClosed +ChannelTest.ReadWhenEmptyReturnsShouldWait +ChannelTest.WaitManyIsSignaledForBothWrites +ChannelTest.WaitManyIsSignaledOnAnyElementWrite +ChannelTest.WriteConsumesAllHandles +ChannelTest.WriteNonTransferableHandleReturnsAccessDeniedAndClosesHandle +ChannelTest.WriteRepeatedHandlesReturnsBadHandlesAndClosesHandle +ChannelTest.WriteSelfHandleReturnsNotSupported +ChannelTest.WriteToEndpointCausesOtherToBecomeReadable +ChannelWriteEtcTest.ByteCountIsMaxPlusOneShouldFail +ChannelWriteEtcTest.ByteCountIsMaxShouldSucceed +ChannelWriteEtcTest.ChannelHandleInTransferredHandlesShouldFail ChannelWriteEtcTest.ChannelHandleNotValidShouldFail ChannelWriteEtcTest.ChannelHandleWithoutWriteRightShouldFail -ChannelWriteEtcTest.HandleWithoutTransferRightShouldFail -ChannelWriteEtcTest.InvalidHandleInTransferredHandlesShouldFail -ChannelWriteEtcTest.RepeatedHandlesWithOpMoveHandlesShouldFail ChannelWriteEtcTest.DuplicateHandlesInTransferredHandlesShouldSucceed -ChannelWriteEtcTest.HandleDoesNotMatchTypeShouldFail -ChannelWriteEtcTest.OptionsArgNonZeroShouldFail -ChannelWriteEtcTest.ChannelHandleInTransferredHandlesShouldFail -ChannelWriteEtcTest.OppositeChannelEndClosedShouldFail -ChannelWriteEtcTest.HandleCountBoundaryChecks +ChannelWriteEtcTest.FailureDoesNotResultInReceivedPacket +ChannelWriteEtcTest.HandleArgNotAChannelHandleShouldFail ChannelWriteEtcTest.HandleCountAndDataCountBothZeroShouldSucceed +ChannelWriteEtcTest.HandleCountBoundaryChecks +ChannelWriteEtcTest.HandleDoesNotMatchTypeShouldFail +ChannelWriteEtcTest.HandleWithoutDuplicateRightsMoveOpSucceedsDuplicateOpFails +ChannelWriteEtcTest.HandleWithoutTransferRightShouldFail +ChannelWriteEtcTest.ImproperlyInitalizedResultsArgReportedBackAsOriginallyInitalized +ChannelWriteEtcTest.InvalidHandleInTransferredHandlesShouldFail +ChannelWriteEtcTest.InvalidOpArgShouldFail ChannelWriteEtcTest.MaximumNumberHandlesWithZeroCountArrayArgShouldSucceed -ChannelWriteEtcTest.ByteCountIsMaxShouldSucceed -ChannelWriteEtcTest.ByteCountIsMaxPlusOneShouldFail +ChannelWriteEtcTest.MultipleHandlesSomeInvalidResultsReportedCorrectly ChannelWriteEtcTest.NullptrArgWhenSizeNonZeroShouldFail +ChannelWriteEtcTest.OppositeChannelEndClosedShouldFail +ChannelWriteEtcTest.OptionsArgNonZeroShouldFail ChannelWriteEtcTest.RemoveAllHandleRightsShouldSucceed ChannelWriteEtcTest.RemovingSomeHandleRightsShouldSucceed +ChannelWriteEtcTest.RepeatedHandlesWithOpMoveHandlesShouldFail ChannelWriteEtcTest.SameHandleRightsBitsShouldSucceed ChannelWriteEtcTest.SameHandleRightsFlagShouldSucceed -ChannelWriteEtcTest.HandleWithoutDuplicateRightsMoveOpSucceedsDuplicateOpFails +ChannelWriteEtcTest.SentHandleReferrsToSameObject ClockTest.ClockMonotonic ClockTest.DeadlineAfter +ConditionalVariableTest.BroadcastSignalThreadWait +ConditionalVariableTest.ConditionalVariablesTimeout +ConditionalVariableTest.SignalThreadWait +CppThreadTest.CreateAndVerifyThreadHandle +DebugLogTest.WriteRead DefaultExceptionHandlerTest.UnhandledHardwareException -ProcessDebugUtilsTest.XorShiftIsOk -ProcessDebugTest.ReadMemoryAtOffsetIsOk -ProcessDebugTest.WriteMemoryAtOffsetIsOk -ExecutableTlsTest.BasicInitalizersInThread -ExecutableTlsTest.BasicInitalizersInMain -ExecutableTlsTest.ArrayInitializerInThread -ExecutableTlsTest.ArrayInitializerInMain -ExecutableTlsTest.BigArrayInitializerInThread -ExecutableTlsTest.BigArrayInitializerInMain -ExecutableTlsTest.StructureInitializerInThread -ExecutableTlsTest.StructureInitalizierInMain -ExecutableTlsTest.AlignmentInitializerInThread -ExecutableTlsTest.AlignmentInitializierInMain -ExecutableTlsTest.ArrayInitializierSpamMain -EventPairTest.HandlesNotInvalid +EventPairTest.CheckNoFlagsSupported EventPairTest.HandleRightsAreCorrect +EventPairTest.HandlesNotInvalid EventPairTest.KoidsAreCorrect -EventPairTest.CheckNoFlagsSupported EventPairTest.SignalEventPairAndClearVerifySignals +EventPairTest.SignalingClosedPeerReturnsPeerClosed EventPairTest.SignalPeerAndVerifyRecived EventPairTest.SignalPeerThenCloseAndVerifySignalReceived -EventPairTest.SignalingClosedPeerReturnsPeerClosed -FifoTest.InvalidParametersReturnOutOfRange -FifoTest.EndpointsAreRelated -FifoTest.EmptyQueueReturnsErrShouldWait -FifoTest.ReadAndWriteValidatesSizeAndElementCount +ExecutableTlsTest.AlignmentInitializerInThread +ExecutableTlsTest.AlignmentInitializierInMain +ExecutableTlsTest.ArrayInitializerInMain +ExecutableTlsTest.ArrayInitializerInThread +ExecutableTlsTest.ArrayInitializerSpamThread +ExecutableTlsTest.ArrayInitializierSpamMain +ExecutableTlsTest.BasicInitalizersInMain +ExecutableTlsTest.BasicInitalizersInThread +ExecutableTlsTest.BigArrayInitializerInMain +ExecutableTlsTest.BigArrayInitializerInThread +ExecutableTlsTest.StructureInitalizierInMain +ExecutableTlsTest.StructureInitializerInThread FifoTest.DequeueSignalsWriteable +FifoTest.EmptyQueueReturnsErrShouldWait +FifoTest.EndpointCloseSignalsPeerClosed +FifoTest.EndpointsAreRelated FifoTest.FifoOrderIsPreserved -FifoTest.PartialWriteQueuesElementsThatFit FifoTest.IndividualReadsPreserveOrder -FifoTest.EndpointCloseSignalsPeerClosed +FifoTest.InvalidParametersReturnOutOfRange +FifoTest.PartialWriteQueuesElementsThatFit +FifoTest.ReadAndWriteValidatesSizeAndElementCount FPUTest.LongComputeLoop -FutexTest.WaitValueMismatch +FutexTest.EventSignaling +FutexTest.MisalignedFutextAddr +FutexTest.Requeue +FutexTest.RequeueSameAddr +FutexTest.RequeueUnqueuedOnTimeout +FutexTest.RequeueValueMismatch +FutexTest.ThreadSuspended +FutexTest.WaitBadAddress FutexTest.WaitTimeout FutexTest.WaitTimeoutElapsed -FutexTest.WaitBadAddress +FutexTest.WaitValueMismatch FutexTest.Wakeup -FutexTest.WakeupLimit FutexTest.WakeupAddress -FutexTest.RequeueValueMismatch -FutexTest.RequeueSameAddr -FutexTest.Requeue -FutexTest.RequeueUnqueuedOnTimeout -FutexTest.ThreadSuspended -FutexTest.MisalignedFutextAddr -FutexTest.EventSignaling +FutexTest.WakeupLimit HandleCloseTest.Many HandleCloseTest.ManyInvalidHandlesShouldNotFail -HandleDup.ReplaceSuccessOrigInvalid -HandleDup.ReplaceFailureBothInvalid -HandleDup.Replace HandleDup.Duplicate +HandleDup.Replace +HandleDup.ReplaceFailureBothInvalid +HandleDup.ReplaceSuccessOrigInvalid HandleInfoTest.DupAndInfoRights -HandleInfoTest.RelatedKoid HandleInfoTest.DuplicateRights +HandleInfoTest.RelatedKoid HandleInfoTest.ReplaceRights -HandleTransferTest.OverChannelThenRead HandleTransferTest.CancelsWait -HandleWaitTest.HandleWaitTest +HandleTransferTest.OverChannelThenRead HandleWaitTest.HandleWaitMultipleThreads -MemoryMappingTest.MmapZerofilledTest +HandleWaitTest.HandleWaitTest +InterruptTest.BindPort +InterruptTest.NonBindablePort +InterruptTest.NullOutputTimestamp +InterruptTest.UnableToBindVirtualInterruptToVcpu +InterruptTest.UnBindPort +InterruptTest.VirtualInterrupts +JobGetInfoTest.InfoHandleBasicBadActualgIsInvalidArg +JobGetInfoTest.InfoHandleBasicBadAvailIsInvalidArg +JobGetInfoTest.InfoHandleBasicInvalidBufferPointerFails +JobGetInfoTest.InfoHandleBasicInvalidHandleFails +JobGetInfoTest.InfoHandleBasicNullActualAndAvailSucceeds +JobGetInfoTest.InfoHandleBasicNullActualSucceeds +JobGetInfoTest.InfoHandleBasicNullAvailSucceeds +JobGetInfoTest.InfoHandleBasicOnSelfSuceeds +JobGetInfoTest.InfoJobChildJobsGetChild +JobGetInfoTest.InfoJobChildrenInvalidHandleFails +JobGetInfoTest.InfoJobChildrenJobHandleIsBadHandle +JobGetInfoTest.InfoJobChildrenOnSelfSuceeds +JobGetInfoTest.InfoJobChildrenRequiresEnumerateRights +JobGetInfoTest.InfoJobChildrenSmallBufferIsOk +JobGetInfoTest.InfoJobChildrenThreadHandleIsBadHandle +JobGetInfoTest.InfoJobChildrenZeroSizedBufferIsOk +JobGetInfoTest.InfoJobProcessesGetChild +JobGetInfoTest.InfoJobProcessesInvalidHandleFails +JobGetInfoTest.InfoJobProcessesOnSelfSuceeds +JobGetInfoTest.InfoJobProcessesProcessbHandleIsBadHandle +JobGetInfoTest.InfoJobProcessesRequiresEnumerateRights +JobGetInfoTest.InfoJobProcessesSmallBufferIsOk +JobGetInfoTest.InfoJobProcessesThreadHandleIsBadHandle +JobGetInfoTest.InfoJobProcessesZeroSizedBufferIsOk +MemoryMappingTest.MmapFlagsTest MemoryMappingTest.MmapLenTest MemoryMappingTest.MmapOffsetTest -MemoryMappingTest.MmapFlagsTest +MemoryMappingTest.MmapZerofilledTest +MsiTest.AllocateSyscall +MsiTest.CreateSyscallArgs +MsiTest.Msi ObjectChildTest.InvalidHandleReturnsBadHandle -ObjectGetInfoTest.OpenValidHandleSuceeds ObjectGetInfoTest.ClosedValidHandleFails ObjectGetInfoTest.HandleCountCorrectness ObjectGetInfoTest.InvalidHandleFails -JobGetInfoTest.InfoJobProcessesGetChild -JobGetInfoTest.InfoJobChildJobsGetChild -JobGetInfoTest.InfoJobProcessesOnSelfSuceeds -JobGetInfoTest.InfoJobProcessesInvalidHandleFails -JobGetInfoTest.InfoJobProcessesZeroSizedBufferIsOk -JobGetInfoTest.InfoJobProcessesSmallBufferIsOk -JobGetInfoTest.InfoJobProcessesRequiresEnumerateRights -JobGetInfoTest.InfoJobProcessesProcessbHandleIsBadHandle -JobGetInfoTest.InfoJobProcessesThreadHandleIsBadHandle -JobGetInfoTest.InfoJobChildrenOnSelfSuceeds -JobGetInfoTest.InfoJobChildrenInvalidHandleFails -JobGetInfoTest.InfoJobChildrenZeroSizedBufferIsOk -JobGetInfoTest.InfoJobChildrenSmallBufferIsOk -JobGetInfoTest.InfoJobChildrenRequiresEnumerateRights -JobGetInfoTest.InfoJobChildrenJobHandleIsBadHandle -JobGetInfoTest.InfoJobChildrenThreadHandleIsBadHandle -JobGetInfoTest.InfoHandleBasicOnSelfSuceeds -JobGetInfoTest.InfoHandleBasicInvalidHandleFails -JobGetInfoTest.InfoHandleBasicNullAvailSucceeds -JobGetInfoTest.InfoHandleBasicNullActualSucceeds -JobGetInfoTest.InfoHandleBasicNullActualAndAvailSucceeds -JobGetInfoTest.InfoHandleBasicInvalidBufferPointerFails -JobGetInfoTest.InfoHandleBasicBadActualgIsInvalidArg -JobGetInfoTest.InfoHandleBasicBadAvailIsInvalidArg -ProcessGetInfoTest.InfoHandleBasicOnSelfSuceeds -ProcessGetInfoTest.InfoHandleBasicInvalidHandleFails -ProcessGetInfoTest.InfoHandleBasicNullAvailSucceeds -ProcessGetInfoTest.InfoHandleBasicNullActualSucceeds -ProcessGetInfoTest.InfoHandleBasicNullActualAndAvailSucceeds -ProcessGetInfoTest.InfoHandleBasicInvalidBufferPointerFails -ProcessGetInfoTest.InfoHandleBasicBadActualgIsInvalidArg -ProcessGetInfoTest.InfoHandleBasicBadAvailIsInvalidArg -ProcessGetInfoTest.InfoProcessOnSelfSuceeds -ProcessGetInfoTest.InfoProcessInvalidHandleFails -ProcessGetInfoTest.InfoProcessNullAvailSucceeds -ProcessGetInfoTest.InfoProcessNullActualSucceeds -ProcessGetInfoTest.InfoProcessNullActualAndAvailSucceeds -ProcessGetInfoTest.InfoProcessInvalidBufferPointerFails -ProcessGetInfoTest.InfoProcessBadActualgIsInvalidArg -ProcessGetInfoTest.InfoProcessBadAvailIsInvalidArg -ProcessGetInfoTest.InfoProcessJobHandleIsBadHandle -ProcessGetInfoTest.InfoProcessThreadHandleIsBadHandle -ProcessGetInfoTest.InfoProcessThreadsSelfSuceeds -ProcessGetInfoTest.InfoProcessThreadsInvalidHandleFails -ProcessGetInfoTest.InfoProcessThreadsZeroSizedBufferSucceeds -TaskGetInfoTest.InfoStatsUnstartedSuceeds -TaskGetInfoTest.InfoStatsSmokeTest -TaskGetInfoTest.InfoTaskStatsInvalidHandleFails -TaskGetInfoTest.InfoTaskStatsNullAvailSucceeds -TaskGetInfoTest.InfoTaskStatsNullActualSucceeds -TaskGetInfoTest.InfoTaskStatsNullActualAndAvailSucceeds -TaskGetInfoTest.InfoTaskStatsInvalidBufferPointerFails -TaskGetInfoTest.InfoTaskStatsBadActualgIsInvalidArg -TaskGetInfoTest.InfoTaskStatsBadAvailIsInvalidArg -TaskGetInfoTest.InfoTaskStatsJobHandleIsBadHandle -TaskGetInfoTest.InfoTaskStatsThreadHandleIsBadHandle -TaskGetInfoTest.InfoTaskRuntimeWrongType -ThreadGetInfoTest.InfoHandleBasicOnSelfSuceeds -ThreadGetInfoTest.InfoHandleBasicInvalidHandleFails -ThreadGetInfoTest.InfoHandleBasicNullAvailSucceeds -ThreadGetInfoTest.InfoHandleBasicNullActualSucceeds -ThreadGetInfoTest.InfoHandleBasicNullActualAndAvailSucceeds -ThreadGetInfoTest.InfoHandleBasicInvalidBufferPointerFails -ThreadGetInfoTest.InfoHandleBasicBadActualgIsInvalidArg -ThreadGetInfoTest.InfoHandleBasicBadAvailIsInvalidArg -ThreadGetInfoTest.InfoHandleCountOnSelfSuceeds -ThreadGetInfoTest.InfoHandleCountInvalidHandleFails -ThreadGetInfoTest.InfoHandleCountNullAvailSucceeds -ThreadGetInfoTest.InfoHandleCountNullActualSucceeds -ThreadGetInfoTest.InfoHandleCountNullActualAndAvailSucceeds -ThreadGetInfoTest.InfoHandleCountInvalidBufferPointerFails -ThreadGetInfoTest.InfoHandleCountBadActualgIsInvalidArg -ThreadGetInfoTest.InfoHandleCountBadAvailIsInvalidArg -ThreadGetInfoTest.InfoThreadOnSelfSuceeds -ThreadGetInfoTest.InfoThreadInvalidHandleFails -ThreadGetInfoTest.InfoThreadNullAvailSucceeds -ThreadGetInfoTest.InfoThreadNullActualSucceeds -ThreadGetInfoTest.InfoThreadNullActualAndAvailSucceeds -ThreadGetInfoTest.InfoThreadInvalidBufferPointerFails -ThreadGetInfoTest.InfoThreadBadActualgIsInvalidArg -ThreadGetInfoTest.InfoThreadBadAvailIsInvalidArg -ThreadGetInfoTest.InfoThreadJobHandleIsBadHandle -ThreadGetInfoTest.InfoThreadProcessHandleIsBadHandle -VmarGetInfoTest.InfoHandleBasicOnSelfSuceeds -VmarGetInfoTest.InfoHandleBasicInvalidHandleFails -VmarGetInfoTest.InfoHandleBasicNullAvailSucceeds -VmarGetInfoTest.InfoHandleBasicNullActualSucceeds -VmarGetInfoTest.InfoHandleBasicNullActualAndAvailSucceeds -VmarGetInfoTest.InfoHandleBasicInvalidBufferPointerFails -VmarGetInfoTest.InfoHandleBasicBadActualgIsInvalidArg -VmarGetInfoTest.InfoHandleBasicBadAvailIsInvalidArg -VmarGetInfoTest.InfoVmarOnSelfFails -VmarGetInfoTest.InfoVmarInvalidHandleFails -VmarGetInfoTest.InfoVmarNullAvailSucceeds -VmarGetInfoTest.InfoVmarNullActualSucceeds -VmarGetInfoTest.InfoVmarNullActualAndAvailSucceeds -VmarGetInfoTest.InfoVmarInvalidBufferPointerFails -VmarGetInfoTest.InfoVmarBadActualgIsInvalidArg -VmarGetInfoTest.InfoVmarBadAvailIsInvalidArg -VmarGetInfoTest.InfoVmarJobHandleIsBadHandle -VmarGetInfoTest.InfoVmarProcessHandleIsBadHandle -VmarGetInfoTest.InfoVmarThreadHandleIsBadHandle -ObjectWaitOneTest.WaitForEventSignaled -ObjectWaitOneTest.WaitForEventTimeout -ObjectWaitOneTest.WaitForEventTimeoutPreSignalClear -ObjectWaitOneTest.WaitForEventThenSignal -ObjectWaitOneTest.TransientSignalsNotReturned -ObjectWaitManyTest.TooManyObjects +ObjectGetInfoTest.OpenValidHandleSuceeds ObjectWaitManyTest.InvalidHandle +ObjectWaitManyTest.TooManyObjects +ObjectWaitManyTest.TransientSignalsNotReturned ObjectWaitManyTest.WaitForEventsSignaled ObjectWaitManyTest.WaitForEventsThenSignal -ObjectWaitManyTest.TransientSignalsNotReturned -PortTest.QueueNullPtrReturnsInvalidArgs -PortTest.QueueWaitVerifyUserPacket -PortTest.PortTimeout -PortTest.QueueAndClose -PortTest.QueueTooMany -PortTest.AsyncWaitChannelTimedOut +ObjectWaitOneTest.EmptySignalSet +ObjectWaitOneTest.TransientSignalsNotReturned +ObjectWaitOneTest.WaitForEventSignaled +ObjectWaitOneTest.WaitForEventThenSignal +ObjectWaitOneTest.WaitForEventTimeout +ObjectWaitOneTest.WaitForEventTimeoutPreSignalClear +PortStressTest.CloseWaitRace PortTest.AsyncWaitChannel +PortTest.AsyncWaitChannelTimedOut PortTest.AsyncWaitCloseOrder -PortTest.AsyncWaitEventRepeat PortTest.AsyncWaitEventManyAllProcessed +PortTest.AsyncWaitEventRepeat PortTest.ChannelAsyncWaitOnExistingStateIsNotified -PortTest.ThreadEvents PortTest.CloseQueueRace -PortStressTest.CloseWaitRace -ProcessTest.LongNameSucceeds +PortTest.PortTimeout +PortTest.QueueAndClose +PortTest.QueueNullPtrReturnsInvalidArgs +PortTest.QueueTooMany +PortTest.QueueWaitVerifyUserPacket +PortTest.ThreadEvents +ProcessDebugTest.ReadMemoryAtOffsetIsOk +ProcessDebugTest.WriteMemoryAtOffsetIsOk +ProcessDebugUtilsTest.XorShiftIsOk +ProcessGetInfoTest.InfoHandleBasicBadActualgIsInvalidArg +ProcessGetInfoTest.InfoHandleBasicBadAvailIsInvalidArg +ProcessGetInfoTest.InfoHandleBasicInvalidBufferPointerFails +ProcessGetInfoTest.InfoHandleBasicInvalidHandleFails +ProcessGetInfoTest.InfoHandleBasicNullActualAndAvailSucceeds +ProcessGetInfoTest.InfoHandleBasicNullActualSucceeds +ProcessGetInfoTest.InfoHandleBasicNullAvailSucceeds +ProcessGetInfoTest.InfoHandleBasicOnSelfSuceeds +ProcessGetInfoTest.InfoProcessBadActualgIsInvalidArg +ProcessGetInfoTest.InfoProcessBadAvailIsInvalidArg +ProcessGetInfoTest.InfoProcessInvalidBufferPointerFails +ProcessGetInfoTest.InfoProcessInvalidHandleFails +ProcessGetInfoTest.InfoProcessJobHandleIsBadHandle +ProcessGetInfoTest.InfoProcessMapsJobHandleIsBadHandle +ProcessGetInfoTest.InfoProcessMapsThreadHandleIsBadHandle +ProcessGetInfoTest.InfoProcessNullActualAndAvailSucceeds +ProcessGetInfoTest.InfoProcessNullActualSucceeds +ProcessGetInfoTest.InfoProcessNullAvailSucceeds +ProcessGetInfoTest.InfoProcessOnSelfSuceeds +ProcessGetInfoTest.InfoProcessThreadHandleIsBadHandle +ProcessGetInfoTest.InfoProcessThreadsInvalidHandleFails +ProcessGetInfoTest.InfoProcessThreadsSelfSuceeds +ProcessGetInfoTest.InfoProcessThreadsZeroSizedBufferSucceeds +ProcessGetInfoTest.InfoProcessVmosOnSelfFails +ProcessTest.CreateAndKillJobRaceStress ProcessTest.EmptyNameSucceeds +ProcessTest.KillChannelHandleCycle +ProcessTest.KillProcessViaThreadKill +ProcessTest.LongNameSucceeds ProcessTest.MiniProcessSanity -ProcessTest.ProcessStartNoHandle -ProcessTest.ProcessStartFail -ProcessTest.ProcessNotKilledViaThreadClose ProcessTest.ProcessNotKilledViaProcessClose -ProcessTest.KillProcessViaThreadKill -ProcessTest.KillChannelHandleCycle +ProcessTest.ProcessNotKilledViaThreadClose +ProcessTest.ProcessStartFail +ProcessTest.ProcessStartNoHandle +ProcessTest.ProcessStartWriteThreadState ProcessTest.SuspendSelf -ProcessTest.CreateAndKillJobRaceStress -PThreadBarrierTest.SingleThreadWinsBarrierObject +ProgressiveCloneDiscardTests.ProgressiveCloneClose +ProgressiveCloneDiscardTests.ProgressiveCloneTruncate PThreadBarrierTest.InitWithNoThreadsReturnsInval +PThreadBarrierTest.SingleThreadWinsBarrierObject PthreadTls.PthreadTls -SocketTest.EndpointsAreRelated -SocketTest.EmptySocketShouldWait -SocketTest.WriteReadDataVerify -SocketTest.PeerClosedError -SocketTest.PeekingLeavesData -SocketTest.PeekingIntoEmpty -SocketTest.Signals -SocketTest.SetThreshholdsProp -SocketTest.SetThreshholdsAndCheckSignals -SocketTest.SignalClosedPeer -SocketTest.PeerClosedSetProperty -SocketTest.ShutdownWrite -SocketTest.ShutdownRead SocketTest.BytesOutstanding -SocketTest.ShutdownWriteBytesOutstanding -SocketTest.ShutdownReadBytesOutstanding -SocketTest.ShortWrite SocketTest.Datagram +SocketTest.DatagramNoShortWrite SocketTest.DatagramPeek SocketTest.DatagramPeekEmpty -SocketTest.DatagramNoShortWrite -SocketTest.ZeroSize +SocketTest.EmptySocketShouldWait +SocketTest.EndpointsAreRelated +SocketTest.PeekingIntoEmpty +SocketTest.PeekingLeavesData +SocketTest.PeerClosedError +SocketTest.PeerClosedSetProperty SocketTest.ReadIntoNullBuffer +SocketTest.SetThreshholdsAndCheckSignals +SocketTest.SetThreshholdsProp +SocketTest.ShortWrite +SocketTest.ShutdownRead +SocketTest.ShutdownReadBytesOutstanding +SocketTest.ShutdownWrite +SocketTest.ShutdownWriteBytesOutstanding +SocketTest.SignalClosedPeer +SocketTest.Signals SocketTest.WriteFromNullBuffer +SocketTest.WriteReadDataVerify +SocketTest.ZeroSize StackTest.MainThreadStack StackTest.ThreadStack +StreamTestCase.Append +StreamTestCase.Create +StreamTestCase.ExtendFillsWithZeros +StreamTestCase.ReadV +StreamTestCase.ReadVAt +StreamTestCase.ReadVectorAlias +StreamTestCase.Seek +StreamTestCase.WriteExtendsContentSize +StreamTestCase.WriteExtendsVMOSize +StreamTestCase.WriteV +StreamTestCase.WriteVAt SyncCompletionTest.Initializer -SyncCompletionTest.SingleWait SyncCompletionTest.MultiWait -SyncCompletionTest.TimeoutSingleWait -SyncCompletionTest.TimeoutMultiWait -SyncCompletionTest.PresignalSingleWait SyncCompletionTest.PresignalMultiWait -SyncCompletionTest.ResetCycleSingleWait +SyncCompletionTest.PresignalSingleWait SyncCompletionTest.ResetCycleMultiWait +SyncCompletionTest.ResetCycleSingleWait SyncCompletionTest.SignalRequeue +SyncCompletionTest.SingleWait SyncCompletionTest.SpuriousWakeupHandled +SyncCompletionTest.TimeoutMultiWait +SyncCompletionTest.TimeoutSingleWait SyncCondition.ConditionTest SyncCondition.TimeoutTest SyncMutex.Mutexes -SyncMutex.TryMutexes SyncMutex.TimeoutElapsed +SyncMutex.TryMutexes +TaskGetInfoTest.InfoStatsSmokeTest +TaskGetInfoTest.InfoStatsUnstartedSuceeds +TaskGetInfoTest.InfoTaskRuntimeWrongType +TaskGetInfoTest.InfoTaskStatsBadActualgIsInvalidArg +TaskGetInfoTest.InfoTaskStatsBadAvailIsInvalidArg +TaskGetInfoTest.InfoTaskStatsInvalidBufferPointerFails +TaskGetInfoTest.InfoTaskStatsInvalidHandleFails +TaskGetInfoTest.InfoTaskStatsJobHandleIsBadHandle +TaskGetInfoTest.InfoTaskStatsNullActualAndAvailSucceeds +TaskGetInfoTest.InfoTaskStatsNullActualSucceeds +TaskGetInfoTest.InfoTaskStatsNullAvailSucceeds +TaskGetInfoTest.InfoTaskStatsThreadHandleIsBadHandle +Thread.SuspendAfterDeath +ThreadGetInfoTest.InfoHandleBasicBadActualgIsInvalidArg +ThreadGetInfoTest.InfoHandleBasicBadAvailIsInvalidArg +ThreadGetInfoTest.InfoHandleBasicInvalidBufferPointerFails +ThreadGetInfoTest.InfoHandleBasicInvalidHandleFails +ThreadGetInfoTest.InfoHandleBasicNullActualAndAvailSucceeds +ThreadGetInfoTest.InfoHandleBasicNullActualSucceeds +ThreadGetInfoTest.InfoHandleBasicNullAvailSucceeds +ThreadGetInfoTest.InfoHandleBasicOnSelfSuceeds +ThreadGetInfoTest.InfoHandleCountBadActualgIsInvalidArg +ThreadGetInfoTest.InfoHandleCountBadAvailIsInvalidArg +ThreadGetInfoTest.InfoHandleCountInvalidBufferPointerFails +ThreadGetInfoTest.InfoHandleCountInvalidHandleFails +ThreadGetInfoTest.InfoHandleCountNullActualAndAvailSucceeds +ThreadGetInfoTest.InfoHandleCountNullActualSucceeds +ThreadGetInfoTest.InfoHandleCountNullAvailSucceeds +ThreadGetInfoTest.InfoHandleCountOnSelfSuceeds +ThreadGetInfoTest.InfoThreadBadActualgIsInvalidArg +ThreadGetInfoTest.InfoThreadBadAvailIsInvalidArg +ThreadGetInfoTest.InfoThreadExceptionReportInvalidHandleFails +ThreadGetInfoTest.InfoThreadInvalidBufferPointerFails +ThreadGetInfoTest.InfoThreadInvalidHandleFails +ThreadGetInfoTest.InfoThreadJobHandleIsBadHandle +ThreadGetInfoTest.InfoThreadNullActualAndAvailSucceeds +ThreadGetInfoTest.InfoThreadNullActualSucceeds +ThreadGetInfoTest.InfoThreadNullAvailSucceeds +ThreadGetInfoTest.InfoThreadOnSelfSuceeds +ThreadGetInfoTest.InfoThreadProcessHandleIsBadHandle +ThreadGetInfoTest.InfoThreadStatsJobHandleIsBadHandle +ThreadGetInfoTest.InfoThreadStatsProcessHandleIsBadHandle Threads.Basics -Threads.InvalidRights Threads.Detach Threads.EmptyNameSucceeds +Threads.InfoTaskStatsFails +Threads.InvalidRights +Threads.KillSuspendedThread Threads.LongNameSucceeds -Threads.ThreadStartOnInitialThread -Threads.ThreadStartWithZeroInstructionPointer Threads.NonstartedThread -Threads.InfoTaskStatsFails Threads.ResumeSuspended -Threads.SuspendSleeping +Threads.StartSuspendedAndResumedThread Threads.SuspendChannelCall -Threads.SuspendPortCall -Threads.SuspendStopsThread Threads.SuspendMultiple +Threads.SuspendPortCall Threads.SuspendSelf -Threads.KillSuspendedThread -Threads.StartSuspendedAndResumedThread -Threads.WritingGeneralRegisterState +Threads.SuspendSleeping +Threads.SuspendStopsThread Threads.ThreadLocalRegisterState +Threads.ThreadStartOnInitialThread +Threads.ThreadStartWithZeroInstructionPointer Threads.WritingArmFlagsRegister -Thread.SuspendAfterDeath +Threads.WritingGeneralRegisterState TicksTest.ElapsedTimeUsingTicks -Vmar.DestroyTest -Vmar.BasicAllocateTest -Vmar.MapInCompactTest Vmar.AllocateOobTest Vmar.AllocateUnsatisfiableTest +Vmar.AllowFaultsTest +Vmar.BasicAllocateTest +Vmar.ConcurrentUnmapReadMemory Vmar.DestroyedVmarTest -Vmar.VmarMapRangeOffsetTest -Vmar.UnalignedLenTest -Vmar.UnalignedLenMapTest -Vmar.RightsDropTest -Vmar.ProtectTest -Vmar.VmarMapRangeOffsetTest +Vmar.DestroyTest +Vmar.MapInCompactTest Vmar.ObjectInfoTest -Vmar.UnmapSplitTest -Vmar.UnmapMultipleTest -Vmar.UnmapBaseNotMappedTest -Vmar.ProtectSplitTest -Vmar.ProtectMultipleTest Vmar.PartialUnmapAndRead Vmar.PartialUnmapAndWrite Vmar.PartialUnmapWithVmarOffset -Vmar.AllowFaultsTest -Vmar.ConcurrentUnmapReadMemory -VmoCloneTestCase.SizeAlign -VmoCloneTestCase.NameProperty -VmoCloneTestCase.Decommit -VmoCloneTestCase.Rights -VmoCloneTestCase.NoResize -VmoClone2TestCase.Info -VmoClone2TestCase.Read -VmoClone2TestCase.CloneVmoWrite -VmoClone2TestCase.ParentVmoWrite +Vmar.ProtectMultipleTest +Vmar.ProtectSplitTest +Vmar.ProtectTest +Vmar.RightsDropTest +Vmar.UnalignedLenMapTest +Vmar.UnalignedLenTest +Vmar.UnmapBaseNotMappedTest +Vmar.UnmapMultipleTest +Vmar.UnmapSplitTest +Vmar.VmarMapRangeOffsetTest +Vmar.VmarMapRangeOffsetTest +VmarGetInfoTest.InfoHandleBasicBadActualgIsInvalidArg +VmarGetInfoTest.InfoHandleBasicBadAvailIsInvalidArg +VmarGetInfoTest.InfoHandleBasicInvalidBufferPointerFails +VmarGetInfoTest.InfoHandleBasicInvalidHandleFails +VmarGetInfoTest.InfoHandleBasicNullActualAndAvailSucceeds +VmarGetInfoTest.InfoHandleBasicNullActualSucceeds +VmarGetInfoTest.InfoHandleBasicNullAvailSucceeds +VmarGetInfoTest.InfoHandleBasicOnSelfSuceeds +VmarGetInfoTest.InfoVmarBadActualgIsInvalidArg +VmarGetInfoTest.InfoVmarBadAvailIsInvalidArg +VmarGetInfoTest.InfoVmarInvalidBufferPointerFails +VmarGetInfoTest.InfoVmarInvalidHandleFails +VmarGetInfoTest.InfoVmarJobHandleIsBadHandle +VmarGetInfoTest.InfoVmarNullActualAndAvailSucceeds +VmarGetInfoTest.InfoVmarNullActualSucceeds +VmarGetInfoTest.InfoVmarNullAvailSucceeds +VmarGetInfoTest.InfoVmarOnSelfFails +VmarGetInfoTest.InfoVmarProcessHandleIsBadHandle +VmarGetInfoTest.InfoVmarThreadHandleIsBadHandle +VmoClone2TestCase.Children VmoClone2TestCase.CloneVmarWrite -VmoClone2TestCase.CloseOriginal +VmoClone2TestCase.CloneVmoWrite VmoClone2TestCase.CloseClone +VmoClone2TestCase.CloseOriginal +VmoClone2TestCase.DisjointCloneProgressive +VmoClone2TestCase.DisjointCloneTest2 +VmoClone2TestCase.ForbidContiguousVmo +VmoClone2TestCase.Info +VmoClone2TestCase.ManyChildren +VmoClone2TestCase.ManyChildrenRevClose +VmoClone2TestCase.ManyCloneMapping +VmoClone2TestCase.ManyCloneMappingOffset +VmoClone2TestCase.ManyCloneOffset VmoClone2TestCase.ObjMemAccounting -VmoClone2TestCase.ZeroPageWrite -VmoClone2TestCase.SplitPageClosure VmoClone2TestCase.Offset -VmoClone2TestCase.OffsetTest2 VmoClone2TestCase.OffsetProgressiveWrite -VmoClone2TestCase.Overflow +VmoClone2TestCase.OffsetTest2 VmoClone2TestCase.OutOfBounds +VmoClone2TestCase.Overflow +VmoClone2TestCase.ParentStartLimitRegression +VmoClone2TestCase.ParentVmarWrite +VmoClone2TestCase.ParentVmoWrite +VmoClone2TestCase.PinBeforeCreateFailure +VmoClone2TestCase.Read +VmoClone2TestCase.ResizeDisjointChild +VmoClone2TestCase.ResizeGrow +VmoClone2TestCase.ResizeMultipleProgressive +VmoClone2TestCase.ResizeOffsetChild +VmoClone2TestCase.ResizeOverSiblingRange VmoClone2TestCase.SmallClone VmoClone2TestCase.SmallCloneChild VmoClone2TestCase.SmallClones -VmoClone2TestCase.DisjointCloneTest2 -VmoClone2TestCase.DisjointCloneProgressive -VmoClone2TestCase.ResizeGrow -VmoClone2TestCase.ResizeOffsetChild -VmoClone2TestCase.ResizeDisjointChild -VmoClone2TestCase.ResizeMultipleProgressive -VmoClone2TestCase.Children -VmoClone2TestCase.ManyChildren -VmoClone2TestCase.ManyChildrenRevClose -VmoClone2TestCase.ManyCloneMapping -VmoClone2TestCase.ManyCloneOffset -VmoClone2TestCase.ManyCloneMappingOffset -VmoClone2TestCase.ForbidContiguousVmo -VmoClone2TestCase.PinBeforeCreateFailure +VmoClone2TestCase.SplitPageClosure VmoClone2TestCase.Uncached -VmoClone2TestCase.ParentStartLimitRegression +VmoClone2TestCase.ZeroPageWrite VmoCloneDisjointClonesTests.DisjointCloneEarlyClose VmoCloneDisjointClonesTests.DisjointCloneLateClose VmoCloneResizeTests.ResizeChild VmoCloneResizeTests.ResizeOriginal -ProgressiveCloneDiscardTests.ProgressiveCloneClose -ProgressiveCloneDiscardTests.ProgressiveCloneTruncate -VmoSignalTestCase.SignalSanity +VmoCloneTestCase.Decommit +VmoCloneTestCase.NameProperty +VmoCloneTestCase.NoResize +VmoCloneTestCase.Rights +VmoCloneTestCase.SizeAlign VmoSignalTestCase.ChildSignalClone VmoSignalTestCase.ChildSignalMap -VmoSliceTestCase.WriteThrough +VmoSignalTestCase.SignalSanity +VmoSliceTestCase.ChildSliceOfContiguousParentIsContiguous +VmoSliceTestCase.CommitChild +VmoSliceTestCase.CowPageSourceThroughSlices +VmoSliceTestCase.DecommitChild VmoSliceTestCase.DecommitParent VmoSliceTestCase.Nested -VmoSliceTestCase.NonSlice VmoSliceTestCase.NonResizable -VmoSliceTestCase.CommitChild -VmoSliceTestCase.DecommitChild -VmoSliceTestCase.ZeroSized -VmoSliceTestCase.ChildSliceOfContiguousParentIsContiguous +VmoSliceTestCase.NonSlice +VmoSliceTestCase.NotCoWType +VmoSliceTestCase.RoundUpSize +VmoSliceTestCase.RoundUpSizePhysical +VmoSliceTestCase.WriteThrough VmoSliceTestCase.ZeroChildren VmoSliceTestCase.ZeroChildrenGrandchildClosedLast -VmoSliceTestCase.CowPageSourceThroughSlices -VmoSliceTestCase.RoundUpSizePhysical -VmoSliceTestCase.RoundUpSize -VmoSliceTestCase.NotCoWType -VmoZeroTestCase.UnalignedSubPage -VmoZeroTestCase.UnalignedCommitted -VmoZeroTestCase.UnalignedUnCommitted -VmoZeroTestCase.DecommitMiddle -VmoZeroTestCase.Contiguous -VmoZeroTestCase.ContentInParentAndChild -VmoZeroTestCase.EmptyCowChildren -VmoZeroTestCase.MergeZeroChildren -VmoZeroTestCase.AllocateAfterMerge -VmoZeroTestCase.AllocateAfterMergeHiddenChild -VmoZeroTestCase.WriteCowParent -VmoZeroTestCase.ChildZeroThenWrite -VmoZeroTestCase.Nested -VmoZeroTestCase.ZeroLengths +VmoSliceTestCase.ZeroSized +VmoTestCase.ContentSize VmoTestCase.Create +VmoTestCase.Map +VmoTestCase.NoResize +VmoTestCase.ReadWrite VmoTestCase.ReadWriteBadLen VmoTestCase.ReadWriteRange -VmoTestCase.Map VmoTestCase.Resize -VmoTestCase.NoResize -VmoTestCase.SizeAlign VmoTestCase.ResizeAlign +VmoTestCase.SizeAlign VmoTestCase.UncachedContiguous -Bti.Create -Bti.Pin -Bti.PinContiguous -Bti.PinContigFlag -Bti.Resize -Bti.Clone -Bti.GetInfoTest -InterruptTest.NonBindablePort -InterruptTest.BindPort -InterruptTest.UnBindPort -InterruptTest.VirtualInterrupts -InterruptTest.UnableToBindVirtualInterruptToVcpu -InterruptTest.NullOutputTimestamp -DebugLogTest.WriteRead +VmoZeroTestCase.AllocateAfterMerge +VmoZeroTestCase.AllocateAfterMergeHiddenChild +VmoZeroTestCase.ChildZeroThenWrite +VmoZeroTestCase.ContentInParentAndChild +VmoZeroTestCase.Contiguous +VmoZeroTestCase.DecommitMiddle +VmoZeroTestCase.EmptyCowChildren +VmoZeroTestCase.MergeZeroChildren +VmoZeroTestCase.Nested +VmoZeroTestCase.ResizeOverHiddenMarkers +VmoZeroTestCase.UnalignedCommitted +VmoZeroTestCase.UnalignedSubPage +VmoZeroTestCase.UnalignedUnCommitted +VmoZeroTestCase.WriteCowParent +VmoZeroTestcase.ZeroFreesAndAllocates +VmoZeroTestCase.ZeroLengths diff --git a/scripts/zircon/test-output.txt b/scripts/zircon/test-output.txt deleted file mode 100644 index 080885fbc..000000000 --- a/scripts/zircon/test-output.txt +++ /dev/null @@ -1,6 +0,0 @@ - Finished dev [unoptimized + debuginfo] target(s) in 0.04s - Running `/home/deathwish/Append/code/ZCORE/zCore/target/debug/zircon-loader ../prebuilt/zircon/x64 'LOG=warn:userboot=test/core-standalone-test:userboot.shutdown:core-tests=*,-Bti.NoDelayedUnpin,Bti.DecommitRace,ProcessDebugVDSO.*,HandleCloseTest.ManyDuplicateTest*,JobTest.*,JobGetInfoTest.InfoJobProcessesPartiallyUnmappedBufferIsInvalidArgs,JobGetInfoTest.InfoJobChildrenPartiallyUnmappedBufferIsInvalidArgs,PortTest.AsyncWaitInvalidOption,PortTest.Timestamp,PortStressTest.WaitSignalCancel,PortStressTest.SignalCloseWait,ProcessTest.ProcessWaitAsyncCancelSelf,Pthread.*,PThreadBarrierTest.SingleThreadWinsBarrierObjectResetsBetweenIterations,SyncMutex.NoRecursion,Threads.Reading*State,Threads.DebugRegistersValidation,Threads.NoncanonicalRipAddressIRETQ,Threads.StartSuspendedThread,Threads.X86AcFlagUserCopy,Vmar.ProtectOverDemandPagedTest,Vmar.ProtectLargeUncomittedTest,Vmar.UnmapLargeUncommittedTest,Vmar.NestedRegionPermsTest,Vmar.MapSpecificOverwriteTest,Vmar.MapOverDestroyedTest,MemoryMappingTest.MprotectTest,MemoryMappingTest.MmapProtExecTest,MemoryMappingTest.MmapProtTest,VmoTestCase.ReadOnlyMap,VmoTestCase.MapRead,VmoTestCase.ParallelRead,VmoTestCase.NoPermMap,VmoTestCase.NoPermProtect,VmoTestCase.Commit,VmoTestCase.CacheOp,VmoTestCase.ResizeHazard,VmoTestCase.Cache*,VmoTestCase.ZeroPage,VmoTestCase.PinTests,VmoCloneTestCase.Commit,VmoClone2TestCase.PinClonePages,SocketTest.ReadIntoBadBuffer,SocketTest.WriteFromBadBuffer,VersionTest.*,BadAccessTest.*,InterruptTest.BindTriggeredIrqToPort,InterruptTest.WaitThreadFunctionsAfterSuspendResume,*Profile*,SystemEvent.*,Resource.*' --debug` -userboot: option "LOG=warn" -userboot: option "userboot=test/core-standalone-test" -userboot: option "userboot.shutdown" -userboot: option "core-tests=*,-Bti.NoDelayedUnpin,Bti.DecommitRace,ProcessDebugVDSO.*,HandleCloseTest.ManyDuplicateTest*,JobTest.*,JobGetInfoTest.InfoJobProcessesPartiallyUnmappedBufferIsInvalidArgs,JobGetInfoTest.InfoJobCh diff --git a/scripts/zircon/test-result.txt b/scripts/zircon/test-result.txt deleted file mode 100644 index e69de29bb..000000000 diff --git a/zCore/Cargo.toml b/zCore/Cargo.toml index f21931c6f..bd2391c94 100644 --- a/zCore/Cargo.toml +++ b/zCore/Cargo.toml @@ -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"] @@ -21,10 +21,11 @@ lto = true [dependencies] log = "0.4" spin = "0.7" +cfg-if = "1.0" buddy_system_allocator = "0.7" -kernel-hal-bare = { path = "../kernel-hal-bare" } +kernel-hal = { path = "../kernel-hal" } lazy_static = { version = "1.4", features = ["spin_no_std" ] } -bitmap-allocator = { git = "https://github.com/rcore-os/bitmap-allocator", rev = "03bd9909" } +bitmap-allocator = { git = "https://github.com/rcore-os/bitmap-allocator", rev = "b3f9f51" } trapframe = "0.8.0" executor = { git = "https://github.com/rcore-os/executor.git", rev = "a2d02ee9" } zircon-loader = { path = "../zircon-loader", default-features = false, optional = true } diff --git a/zCore/Makefile b/zCore/Makefile index 6de632b4d..0e7bb7a20 100644 --- a/zCore/Makefile +++ b/zCore/Makefile @@ -1,6 +1,7 @@ arch ?= x86_64 board ?= qemu mode ?= debug +log ?= warn zbi_file ?= bringup graphic ?= accel ?= @@ -18,7 +19,7 @@ kernel_bin := $(build_path)/zcore.bin ESP := $(build_path)/esp OVMF := ../rboot/OVMF.fd qemu := qemu-system-$(arch) -OBJDUMP := rust-objdump -print-imm-hex -x86-asm-syntax=intel +OBJDUMP := rust-objdump --print-imm-hex --x86-asm-syntax=intel OBJCOPY := rust-objcopy --binary-architecture=$(arch) VMDISK := $(build_path)/boot.vdi QEMU_DISK := $(build_path)/disk.qcow2 @@ -127,13 +128,13 @@ justrun: $(QEMU_DISK) build-test: build cp ../prebuilt/zircon/x64/core-tests.zbi $(ESP)/EFI/zCore/fuchsia.zbi - echo 'cmdline=LOG=warn:userboot=test/core-standalone-test:userboot.shutdown:core-tests=$(test_filter)' >> $(ESP)/EFI/Boot/rboot.conf + echo 'cmdline=LOG=$(log):userboot=test/core-standalone-test:userboot.shutdown:core-tests=$(test_filter)' >> $(ESP)/EFI/Boot/rboot.conf build: $(kernel_img) build-parallel-test: build $(QEMU_DISK) cp ../prebuilt/zircon/x64/core-tests.zbi $(ESP)/EFI/zCore/fuchsia.zbi - echo 'cmdline=LOG=warn:userboot=test/core-standalone-test:userboot.shutdown:core-tests=$(test_filter)' >> $(ESP)/EFI/Boot/rboot.conf + echo 'cmdline=LOG=$(log):userboot=test/core-standalone-test:userboot.shutdown:core-tests=$(test_filter)' >> $(ESP)/EFI/Boot/rboot.conf ifeq ($(arch), riscv64) $(kernel_img): $(kernel_bin) @@ -168,6 +169,9 @@ kernel: echo Building zCore kenel cargo build $(build_args) +clippy: + cargo clippy $(build_args) + bootloader: cd ../rboot && make build @@ -185,7 +189,7 @@ image: header: $(OBJDUMP) -x $(kernel) | less -asm: +disasm: $(OBJDUMP) -d $(kernel) | less vbox: build @@ -224,4 +228,3 @@ baremetal-test: baremetal-test-rv64: build $(QEMU_DISK) timeout --foreground 8s $(qemu) $(qemu_opts) -append ROOTPROC=$(ROOTPROC) - diff --git a/zCore/build.rs b/zCore/build.rs index 8726ef215..475bbf92b 100644 --- a/zCore/build.rs +++ b/zCore/build.rs @@ -7,10 +7,8 @@ fn main() { let board = std::env::var("BOARD").unwrap(); let kernel_base_addr: u64 = if board.contains("d1") { 0xffffffffc0020000 - } else if board.contains("qemu") { - // opensbi仍旧把kernel放在0x80200000物理内存中 - 0xffffffff80200000 } else { + // opensbi仍旧把kernel放在0x80200000物理内存中 0xffffffff80200000 }; diff --git a/zCore/src/arch/mod.rs b/zCore/src/arch/mod.rs index 3d01206cb..ccfa86130 100644 --- a/zCore/src/arch/mod.rs +++ b/zCore/src/arch/mod.rs @@ -7,4 +7,3 @@ pub use self::x86_64::*; pub mod riscv; #[cfg(target_arch = "riscv64")] pub use self::riscv::*; - diff --git a/zCore/src/arch/riscv/boot/kernel-vars.ld b/zCore/src/arch/riscv/boot/kernel-vars.ld new file mode 100644 index 000000000..d2a331363 --- /dev/null +++ b/zCore/src/arch/riscv/boot/kernel-vars.ld @@ -0,0 +1,2 @@ +/* Generated by build.rs. DO NOT EDIT. */ +PROVIDE_HIDDEN(BASE_ADDRESS = 0xffffffff80200000); diff --git a/zCore/src/arch/riscv/consts.rs b/zCore/src/arch/riscv/consts.rs index 11a4cb67f..ad2801418 100644 --- a/zCore/src/arch/riscv/consts.rs +++ b/zCore/src/arch/riscv/consts.rs @@ -1,23 +1,18 @@ // RISCV -#[cfg(feature = "board_qemu")] -pub const KERNEL_OFFSET: usize = 0xFFFF_FFFF_8000_0000; -#[cfg(feature = "board_qemu")] -pub const MEMORY_OFFSET: usize = 0x8000_0000; -#[cfg(feature = "board_qemu")] -pub const MEMORY_END: usize = 0x8800_0000; // TODO: get memory end from device tree - -#[cfg(feature = "board_d1")] -pub const KERNEL_OFFSET: usize = 0xFFFFFFFF_C0000000; -#[cfg(feature = "board_d1")] -pub const MEMORY_OFFSET: usize = 0x40000000; -#[cfg(feature = "board_d1")] -pub const MEMORY_END: usize = 0x60000000; // 512M +cfg_if::cfg_if! { + if #[cfg(feature = "board_qemu")] { + pub const KERNEL_OFFSET: usize = 0xFFFF_FFFF_8000_0000; + pub const MEMORY_OFFSET: usize = 0x8000_0000; + pub const MEMORY_END: usize = 0x8800_0000; // TODO: get memory end from device tree + } else if #[cfg(feature = "board_d1")] { + pub const KERNEL_OFFSET: usize = 0xFFFF_FFFF_C000_0000; + pub const MEMORY_OFFSET: usize = 0x4000_0000; + pub const MEMORY_END: usize = 0x6000_0000; // 512M + } +} pub const PHYSICAL_MEMORY_OFFSET: usize = KERNEL_OFFSET - MEMORY_OFFSET; pub const KERNEL_HEAP_SIZE: usize = 8 * 1024 * 1024; // 8 MB pub const PAGE_SIZE: usize = 1 << 12; - -pub const KERNEL_L2: usize = (KERNEL_OFFSET >> 30) & 0o777; -pub const PHYSICAL_MEMORY_L2: usize = (PHYSICAL_MEMORY_OFFSET >> 30) & 0o777; diff --git a/zCore/src/arch/x86_64/consts.rs b/zCore/src/arch/x86_64/consts.rs index 8607c266b..21c77806b 100644 --- a/zCore/src/arch/x86_64/consts.rs +++ b/zCore/src/arch/x86_64/consts.rs @@ -1,10 +1,7 @@ // x86_64 pub const MEMORY_OFFSET: usize = 0; -pub const KERNEL_OFFSET: usize = 0xffffff00_00000000; -pub const PHYSICAL_MEMORY_OFFSET: usize = 0xffff8000_00000000; +pub const KERNEL_OFFSET: usize = 0xffff_ff00_0000_0000; +pub const PHYSICAL_MEMORY_OFFSET: usize = 0xffff_8000_0000_0000; pub const KERNEL_HEAP_SIZE: usize = 16 * 1024 * 1024; // 16 MB pub const PAGE_SIZE: usize = 1 << 12; - -pub const KERNEL_PM4: usize = (KERNEL_OFFSET >> 39) & 0o777; -pub const PHYSICAL_MEMORY_PM4: usize = (PHYSICAL_MEMORY_OFFSET >> 39) & 0o777; diff --git a/zCore/src/fs.rs b/zCore/src/fs.rs index ac25a7dab..5ec0f514e 100644 --- a/zCore/src/fs.rs +++ b/zCore/src/fs.rs @@ -1,7 +1,6 @@ use alloc::sync::Arc; -use rcore_fs::vfs::FileSystem; use linux_object::fs::MemBuf; -use kernel_hal_bare::drivers::virtio::{BlockDriverWrapper, BLK_DRIVERS}; +use rcore_fs::vfs::FileSystem; pub fn init_filesystem(ramfs_data: &'static mut [u8]) -> Arc { #[cfg(target_arch = "x86_64")] @@ -9,7 +8,7 @@ pub fn init_filesystem(ramfs_data: &'static mut [u8]) -> Arc { #[cfg(feature = "link_user_img")] let ramfs_data = unsafe { - extern { + extern "C" { fn _user_img_start(); fn _user_img_end(); } @@ -23,8 +22,9 @@ pub fn init_filesystem(ramfs_data: &'static mut [u8]) -> Arc { #[cfg(feature = "link_user_img")] let device = Arc::new(MemBuf::new(ramfs_data)); - #[cfg(all(target_arch="riscv64", not(feature="link_user_img")))] + #[cfg(all(target_arch = "riscv64", not(feature = "link_user_img")))] let device = { + use kernel_hal::drivers::virtio::{BlockDriverWrapper, BLK_DRIVERS}; let driver = BlockDriverWrapper( BLK_DRIVERS .read() @@ -38,10 +38,7 @@ pub fn init_filesystem(ramfs_data: &'static mut [u8]) -> Arc { info!("Opening the rootfs ..."); // 输入类型: Arc - let rootfs = - rcore_fs_sfs::SimpleFileSystem::open(device).expect("failed to open device SimpleFS"); - - rootfs + rcore_fs_sfs::SimpleFileSystem::open(device).expect("failed to open device SimpleFS") } // Hard link rootfs img diff --git a/zCore/src/logging.rs b/zCore/src/logging.rs index 30dd687df..6a038a0c8 100644 --- a/zCore/src/logging.rs +++ b/zCore/src/logging.rs @@ -37,12 +37,12 @@ macro_rules! with_color { } fn print_in_color(args: fmt::Arguments, color_code: u8) { - kernel_hal_bare::arch::putfmt(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_bare::arch::putfmt(args); + kernel_hal::serial::serial_write_fmt(args); } struct SimpleLogger; @@ -56,13 +56,13 @@ impl Log for SimpleLogger { return; } - let (tid, pid) = kernel_hal_bare::Thread::get_tid(); + let (tid, pid) = kernel_hal::thread::get_tid(); print_in_color( format_args!( "[{:?} {:>5} {} {}:{}] {}\n", - kernel_hal_bare::timer_now(), + kernel_hal::timer::timer_now(), record.level(), - kernel_hal_bare::apic_local_id(), + kernel_hal::cpu::cpu_id(), pid, tid, record.args() diff --git a/zCore/src/main.rs b/zCore/src/main.rs index 87b7f7f41..6662c9892 100644 --- a/zCore/src/main.rs +++ b/zCore/src/main.rs @@ -21,8 +21,8 @@ extern crate rlibc_opt; //Only for x86_64 #[macro_use] mod logging; -mod lang; mod arch; +mod lang; mod memory; #[cfg(feature = "linux")] @@ -31,19 +31,11 @@ mod fs; #[cfg(target_arch = "x86_64")] use rboot::BootInfo; -#[cfg(target_arch = "riscv64")] -use kernel_hal_bare::{ - phys_to_virt, remap_the_kernel, - drivers::virtio::{GPU_DRIVERS, CMDLINE}, - BootInfo, GraphicInfo, -}; - -use alloc::{ - format,vec, - vec::Vec, - boxed::Box, - string::{String, ToString}, -}; +use kernel_hal::{KernelConfig, KernelHandler, MMUFlags}; + +use alloc::{boxed::Box, string::String, vec, vec::Vec}; + +use crate::arch::consts::*; #[cfg(feature = "board_qemu")] global_asm!(include_str!("arch/riscv/boot/boot_qemu.asm")); @@ -61,18 +53,24 @@ pub extern "C" fn _start(boot_info: &BootInfo) -> ! { trace!("{:#x?}", boot_info); - kernel_hal_bare::init(kernel_hal_bare::Config { + let config = KernelConfig { + kernel_offset: KERNEL_OFFSET, + phys_mem_start: PHYSICAL_MEMORY_OFFSET, + phys_to_virt_offset: PHYSICAL_MEMORY_OFFSET, + acpi_rsdp: boot_info.acpi2_rsdp_addr, smbios: boot_info.smbios_addr, ap_fn: run, - }); + }; + info!("{:#x?}", config); + kernel_hal::init(config, &ZcoreKernelHandler); #[cfg(feature = "graphic")] { let (width, height) = boot_info.graphic_info.mode.resolution(); let fb_addr = boot_info.graphic_info.fb_addr as usize; let fb_size = boot_info.graphic_info.fb_size as usize; - kernel_hal_bare::init_framebuffer(width as u32, height as u32, fb_addr, fb_size); + kernel_hal::dev::fb::init(width as u32, height as u32, fb_addr, fb_size); } let ramfs_data = unsafe { @@ -99,41 +97,32 @@ fn main(ramfs_data: &[u8], cmdline: &str) -> ! { #[cfg(target_arch = "riscv64")] #[no_mangle] pub extern "C" fn rust_main(hartid: usize, device_tree_paddr: usize) -> ! { - println!("zCore rust_main( hartid: {}, device_tree_paddr: {:#x} )", hartid, device_tree_paddr); - let device_tree_vaddr = phys_to_virt(device_tree_paddr); - - let boot_info = BootInfo { - memory_map: Vec::new(), - physical_memory_offset: 0, - graphic_info: GraphicInfo { - mode: 0, - fb_addr: 0, - fb_size: 0, - }, - hartid: hartid as u64, - dtb_addr: device_tree_paddr as u64, - initramfs_addr: 0, - initramfs_size: 0, - cmdline: "LOG=warn:TERM=xterm-256color:console.shell=true:virtcon.disable=true", + println!( + "zCore rust_main( hartid: {}, device_tree_paddr: {:#x} )", + hartid, device_tree_paddr + ); + let cmdline = "LOG=warn:TERM=xterm-256color:console.shell=true:virtcon.disable=true"; + let config = KernelConfig { + kernel_offset: KERNEL_OFFSET, + phys_mem_start: MEMORY_OFFSET, + phys_mem_end: MEMORY_END, + phys_to_virt_offset: PHYSICAL_MEMORY_OFFSET, + dtb_paddr: device_tree_paddr, }; - logging::init(get_log_level(boot_info.cmdline)); + logging::init(get_log_level(cmdline)); memory::init_heap(); - memory::init_frame_allocator(&boot_info); - remap_the_kernel(device_tree_vaddr); - - info!("{:#x?}", boot_info); - - kernel_hal_bare::init(kernel_hal_bare::Config { - mconfig: 0, - dtb: device_tree_vaddr, - }); + memory::init_frame_allocator(); - let cmdline_dt = CMDLINE.read(); - let mut cmdline = boot_info.cmdline.to_string(); + info!("{:#x?}", config); + kernel_hal::init(config, &ZcoreKernelHandler); - if !cmdline_dt.is_empty() { - cmdline = format!("{}:{}", boot_info.cmdline, cmdline_dt); + let cmdline_dt = ""; // FIXME: CMDLINE.read(); + let cmdline = if !cmdline_dt.is_empty() { + alloc::format!("{}:{}", cmdline, cmdline_dt) + } else { + use alloc::string::ToString; + cmdline.to_string() }; warn!("cmdline: {:?}", cmdline); @@ -147,7 +136,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载入文件系统镜像到内存 @@ -166,7 +155,7 @@ fn get_rootproc(cmdline: &str) -> Vec { let mut iter = value.trim().splitn(2, '?'); let k1 = iter.next().expect("failed to parse k1"); let v1 = iter.next().expect("failed to parse v1"); - if v1 == "" { + if v1.is_empty() { return vec![k1.into()]; } else { return vec![k1.into(), v1.into()]; @@ -180,13 +169,13 @@ fn get_rootproc(cmdline: &str) -> Vec { fn main(ramfs_data: &'static mut [u8], cmdline: &str) -> ! { use linux_object::fs::STDIN; - kernel_hal_bare::serial_set_callback(Box::new({ + kernel_hal::serial::serial_set_callback(Box::new({ move || { let mut buffer = [0; 255]; - let len = kernel_hal_bare::serial_read(&mut buffer); + let len = kernel_hal::serial::serial_read(&mut buffer); for c in &buffer[..len] { STDIN.push((*c).into()); - // kernel_hal_bare::serial_write(alloc::format!("{}", *c as char).as_str()); + // kernel_hal::serial::serial_write(alloc::format!("{}", *c as char).as_str()); } false } @@ -212,7 +201,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(); } } @@ -228,3 +217,23 @@ fn get_log_level(cmdline: &str) -> &str { } "" } + +struct ZcoreKernelHandler; + +impl KernelHandler for ZcoreKernelHandler { + fn frame_alloc(&self) -> Option { + memory::frame_alloc() + } + + fn frame_alloc_contiguous(&self, frame_count: usize, align_log2: usize) -> Option { + memory::frame_alloc_contiguous(frame_count, align_log2) + } + + fn frame_dealloc(&self, paddr: usize) { + memory::frame_dealloc(paddr) + } + + fn handle_page_fault(&self, fault_vaddr: usize, access_flags: MMUFlags) { + panic!("page fault from kernel mode @ {:#x}({:?})", fault_vaddr, access_flags); + } +} diff --git a/zCore/src/memory.rs b/zCore/src/memory.rs index e2c74f15a..213fccada 100644 --- a/zCore/src/memory.rs +++ b/zCore/src/memory.rs @@ -1,20 +1,11 @@ //! Define the FrameAllocator for physical memory //! x86_64 -- 64GB -use {bitmap_allocator::BitAlloc, buddy_system_allocator::LockedHeap, spin::Mutex}; use crate::arch::consts::*; +use {bitmap_allocator::BitAlloc, buddy_system_allocator::LockedHeap, spin::Mutex}; #[cfg(target_arch = "x86_64")] -use { - rboot::{BootInfo, MemoryType}, - x86_64::structures::paging::page_table::{PageTable, PageTableFlags as EF}, -}; - -#[cfg(target_arch = "riscv64")] -use riscv::{ - addr::Frame, - paging::{PageTable, PageTableFlags as EF}, -}; +use rboot::{BootInfo, MemoryType}; #[cfg(target_arch = "x86_64")] type FrameAlloc = bitmap_allocator::BitAlloc16M; @@ -24,10 +15,6 @@ type FrameAlloc = bitmap_allocator::BitAlloc1M; static FRAME_ALLOCATOR: Mutex = Mutex::new(FrameAlloc::DEFAULT); -#[used] -#[export_name = "hal_pmem_base"] -static PMEM_BASE: usize = PHYSICAL_MEMORY_OFFSET; - #[cfg(target_arch = "x86_64")] pub fn init_frame_allocator(boot_info: &BootInfo) { let mut ba = FRAME_ALLOCATOR.lock(); @@ -36,34 +23,35 @@ pub fn init_frame_allocator(boot_info: &BootInfo) { let start_frame = region.phys_start as usize / PAGE_SIZE; let end_frame = start_frame + region.page_count as usize; ba.insert(start_frame..end_frame); + info!( + "Frame allocator add range: {:#x?}", + region.phys_start..region.phys_start + region.page_count * PAGE_SIZE as u64, + ); } } 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) { +pub fn init_frame_allocator() { use core::ops::Range; - - let mut ba = FRAME_ALLOCATOR.lock(); - let range = to_range( - (end as usize) - KERNEL_OFFSET + MEMORY_OFFSET + PAGE_SIZE, - MEMORY_END, - ); - ba.insert(range); - - info!("frame allocator: init end"); + use kernel_hal::addr::{align_down, align_up}; /// Transform memory area `[start, end)` to integer range for `FrameAllocator` fn to_range(start: usize, end: usize) -> Range { + info!("Frame allocator add range: {:#x?}", start..end); let page_start = (start - MEMORY_OFFSET) / PAGE_SIZE; - let page_end = (end - MEMORY_OFFSET - 1) / PAGE_SIZE + 1; + let page_end = (end - MEMORY_OFFSET) / PAGE_SIZE; assert!(page_start < page_end, "illegal range for frame allocator"); page_start..page_end } + + let mut ba = FRAME_ALLOCATOR.lock(); + let mem_pool_start = align_up(end as usize + PAGE_SIZE - KERNEL_OFFSET + MEMORY_OFFSET); + let mem_pool_end = align_down(MEMORY_END); + ba.insert(to_range(mem_pool_start, mem_pool_end)); + + info!("Frame allocator: init end"); } pub fn init_heap() { @@ -78,9 +66,7 @@ pub fn init_heap() { info!("heap init end"); } -#[no_mangle] -#[allow(improper_ctypes_definitions)] -pub extern "C" fn frame_alloc() -> Option { +pub fn frame_alloc() -> Option { // get the real address of the alloc frame let ret = FRAME_ALLOCATOR .lock() @@ -90,60 +76,26 @@ pub extern "C" fn frame_alloc() -> Option { ret } -#[no_mangle] -#[allow(improper_ctypes_definitions)] -pub extern "C" fn hal_frame_alloc_contiguous(page_num: usize, align_log2: usize) -> Option { +pub fn frame_alloc_contiguous(frame_count: usize, align_log2: usize) -> Option { let ret = FRAME_ALLOCATOR .lock() - .alloc_contiguous(page_num, align_log2) + .alloc_contiguous(frame_count, align_log2) .map(|id| id * PAGE_SIZE + MEMORY_OFFSET); trace!( "Allocate contiguous frames: {:x?} ~ {:x?}", ret, - ret.map(|x| x + page_num) + ret.map(|x| x + frame_count) ); ret } -#[no_mangle] -pub extern "C" fn frame_dealloc(target: &usize) { - trace!("Deallocate frame: {:x}", *target); +pub fn frame_dealloc(target: usize) { + trace!("Deallocate frame: {:x}", target); FRAME_ALLOCATOR .lock() - .dealloc((*target - MEMORY_OFFSET) / PAGE_SIZE); -} - -#[no_mangle] -#[cfg(target_arch = "x86_64")] -pub extern "C" fn hal_pt_map_kernel(pt: &mut PageTable, current: &PageTable) { - //复制旧的Kernel起始虚拟地址和物理内存起始虚拟地址的, Level3及以下级的页表, - //分别可覆盖500G虚拟空间 - let ekernel = current[KERNEL_PM4].clone(); - let ephysical = current[PHYSICAL_MEMORY_PM4].clone(); - pt[KERNEL_PM4].set_addr(ekernel.addr(), ekernel.flags() | EF::GLOBAL); - pt[PHYSICAL_MEMORY_PM4].set_addr(ephysical.addr(), ephysical.flags() | EF::GLOBAL); + .dealloc((target - MEMORY_OFFSET) / PAGE_SIZE); } -#[no_mangle] -#[cfg(target_arch = "riscv64")] -pub extern "C" fn hal_pt_map_kernel(pt: &mut PageTable, current: &PageTable) { - let ekernel = current[KERNEL_L2].clone(); //Kernel - let ephysical = current[PHYSICAL_MEMORY_L2].clone(); //0xffffffff_00000000 --> 0x00000000 - pt[KERNEL_L2].set(Frame::of_addr(ekernel.addr()), ekernel.flags() | EF::GLOBAL); - pt[PHYSICAL_MEMORY_L2].set( - Frame::of_addr(ephysical.addr()), - ephysical.flags() | EF::GLOBAL, - ); - debug!( - "KERNEL_L2:{:x?}, PHYSICAL_MEMORY_L2:{:x?}", - ekernel.addr(), - ephysical.addr() - ); -} - -// First core stores its SATP here. -static mut SATP: usize = 0; - #[cfg(target_arch = "riscv64")] pub unsafe fn clear_bss() { let start = sbss as usize; diff --git a/zircon-loader/Cargo.toml b/zircon-loader/Cargo.toml index a4c809ec9..f0e83c6ab 100644 --- a/zircon-loader/Cargo.toml +++ b/zircon-loader/Cargo.toml @@ -15,10 +15,9 @@ zircon-syscall = { path = "../zircon-syscall" } kernel-hal = { path = "../kernel-hal" } env_logger = { version = "0.8", optional = true } structopt = { version = "0.3", default-features = false, optional = true } -kernel-hal-unix = { path = "../kernel-hal-unix", optional = true } async-std = { version = "1.9", features = ["attributes"], optional = true } [features] -default = ["std"] -std = ["env_logger", "structopt", "async-std", "kernel-hal-unix", - "zircon-object/aspace-separate", "zircon-syscall/std"] +default = ["std", "libos"] +libos = ["kernel-hal/libos"] +std = ["env_logger", "structopt", "async-std", "zircon-object/aspace-separate", "zircon-syscall/std"] diff --git a/zircon-loader/src/kcounter.rs b/zircon-loader/src/kcounter.rs index 4b76f0798..54adc6862 100644 --- a/zircon-loader/src/kcounter.rs +++ b/zircon-loader/src/kcounter.rs @@ -34,9 +34,9 @@ pub fn create_kcounter_vmo() -> (Arc, Arc) { fn kcounters_arena_start(); fn kcounters_arena_end(); } - use kernel_hal::PageTableTrait; - let mut pgtable = kernel_hal::PageTable::current(); - let paddr = pgtable.query(kcounters_arena_start as usize).unwrap(); + use kernel_hal::vm::{GenericPageTable, PageTable}; + let pgtable = PageTable::from_current(); + let paddr = pgtable.query(kcounters_arena_start as usize).unwrap().0; assert_eq!( kcounters_arena_start as usize / PAGE_SIZE, kcounters_arena_end as usize / PAGE_SIZE, diff --git a/zircon-loader/src/lib.rs b/zircon-loader/src/lib.rs index db5e9e24f..f1adea71a 100644 --- a/zircon-loader/src/lib.rs +++ b/zircon-loader/src/lib.rs @@ -83,7 +83,7 @@ pub fn run_userboot(images: &Images>, cmdline: &str) -> Arc>, cmdline: &str) -> Arc handle_syscall(&thread).await, 0x20..=0x3f => { - kernel_hal::InterruptManager::handle_irq(trap_num as u32); + kernel_hal::interrupt::handle_irq(trap_num as u32); if trap_num == 0x20 { EXCEPTIONS_TIMER.add(1); - kernel_hal::yield_now().await; + kernel_hal::future::yield_now().await; } } 0xe => { EXCEPTIONS_PGFAULT.add(1); - let mut flags = MMUFlags::empty(); - if error_code & 0x01 != 0 { - flags.insert(MMUFlags::READ) - } - if error_code & 0x02 != 0 { - flags.insert(MMUFlags::WRITE) - } - if error_code & 0x04 != 0 { - flags.insert(MMUFlags::USER) - } - if error_code & 0x08 != 0 { - warn!("page table entry has reserved bits set!") - } - if error_code & 0x10 != 0 { - flags.insert(MMUFlags::EXECUTE) - } - let fault_vaddr = kernel_hal::fetch_fault_vaddr(); + let (vaddr, flags) = kernel_hal::context::fetch_page_fault_info(error_code); info!( "page fault from user mode {:#x} {:#x?} {:?}", - fault_vaddr, error_code, flags + vaddr, error_code, flags ); let vmar = thread.proc().vmar(); - if let Err(err) = vmar.handle_page_fault(fault_vaddr, flags) { + if let Err(err) = vmar.handle_page_fault(vaddr, flags) { error!("handle_page_fault error: {:?}", err); thread.handle_exception(ExceptionType::FatalPageFault).await; } diff --git a/zircon-loader/src/main.rs b/zircon-loader/src/main.rs index 48925e7c6..f84277b6d 100644 --- a/zircon-loader/src/main.rs +++ b/zircon-loader/src/main.rs @@ -23,7 +23,7 @@ struct Opt { #[async_std::main] async fn main() { - kernel_hal_unix::init(); + kernel_hal::init(); init_logger(); let opt = Opt::from_args(); @@ -53,7 +53,7 @@ fn init_logger() { use log::Level; use std::io::Write; - let (tid, pid) = kernel_hal::Thread::get_tid(); + let (tid, pid) = kernel_hal::thread::get_tid(); let mut style = buf.style(); match record.level() { Level::Trace => style.set_color(Color::Black).set_intense(true), @@ -62,7 +62,7 @@ fn init_logger() { Level::Warn => style.set_color(Color::Yellow), Level::Error => style.set_color(Color::Red).set_bold(true), }; - let now = kernel_hal_unix::timer_now(); + let now = kernel_hal::timer::timer_now(); let level = style.value(record.level()); let args = record.args(); writeln!(buf, "[{:?} {:>5} {}:{}] {}", now, level, pid, tid, args) @@ -76,7 +76,7 @@ mod tests { #[async_std::test] async fn userboot() { - kernel_hal_unix::init(); + kernel_hal::init(); let opt = Opt { #[cfg(target_arch = "x86_64")] diff --git a/zircon-object/Cargo.toml b/zircon-object/Cargo.toml index ff972e24d..7cc4ef87e 100644 --- a/zircon-object/Cargo.toml +++ b/zircon-object/Cargo.toml @@ -29,5 +29,4 @@ cfg-if = "1.0" #rvm = { git = "https://github.com/rcore-os/RVM", rev = "382fc60", optional = true } [dev-dependencies] -kernel-hal-unix = { path = "../kernel-hal-unix" } async-std = { version = "1.9", features = ["attributes", "unstable"] } diff --git a/zircon-object/src/debuglog.rs b/zircon-object/src/debuglog.rs index 144c7ed5b..a38facc47 100644 --- a/zircon-object/src/debuglog.rs +++ b/zircon-object/src/debuglog.rs @@ -3,7 +3,6 @@ use { super::*, crate::object::*, alloc::{sync::Arc, vec::Vec}, - kernel_hal::timer_now, lazy_static::lazy_static, spin::Mutex, }; @@ -111,7 +110,7 @@ impl DlogBuffer { datalen: data.len() as u16, severity, flags: flags as u8, - timestamp: timer_now().as_nanos() as u64, + timestamp: kernel_hal::timer::timer_now().as_nanos() as u64, pid, tid, }; diff --git a/zircon-object/src/dev/interrupt/event_interrupt.rs b/zircon-object/src/dev/interrupt/event_interrupt.rs index 5d79d11e3..098ab01a1 100644 --- a/zircon-object/src/dev/interrupt/event_interrupt.rs +++ b/zircon-object/src/dev/interrupt/event_interrupt.rs @@ -1,4 +1,4 @@ -use kernel_hal::InterruptManager; +use kernel_hal::interrupt; use {super::*, spin::Mutex}; pub struct EventInterrupt { @@ -25,14 +25,14 @@ impl InterruptTrait for EventInterrupt { fn mask(&self) { let inner = self.inner.lock(); if inner.register { - InterruptManager::disable_irq(self.vector as u32); + interrupt::disable_irq(self.vector); } } fn unmask(&self) { let inner = self.inner.lock(); if inner.register { - InterruptManager::enable_irq(self.vector as u32); + interrupt::enable_irq(self.vector); } } @@ -41,7 +41,7 @@ impl InterruptTrait for EventInterrupt { if inner.register { return Err(ZxError::ALREADY_BOUND); } - if InterruptManager::register_irq_handler(self.vector, handle).is_some() { + if interrupt::register_irq_handler(self.vector, handle).is_ok() { inner.register = true; Ok(()) } else { @@ -54,11 +54,11 @@ impl InterruptTrait for EventInterrupt { if !inner.register { return Ok(()); } - if InterruptManager::unregister_irq_handler(self.vector) { + if interrupt::unregister_irq_handler(self.vector).is_ok() { inner.register = false; Ok(()) } else { - Err(ZxError::ALREADY_BOUND) + Err(ZxError::NOT_FOUND) } // maybe a better error code? } } diff --git a/zircon-object/src/dev/interrupt/mod.rs b/zircon-object/src/dev/interrupt/mod.rs index 066a03f99..c54577131 100644 --- a/zircon-object/src/dev/interrupt/mod.rs +++ b/zircon-object/src/dev/interrupt/mod.rs @@ -293,7 +293,7 @@ impl Interrupt { } if inner.timestamp == 0 { // Not sure ZX_CLOCK_MONOTONIC or ZX_CLOCK_UTC - inner.timestamp = kernel_hal::timer_now().as_nanos() as i64; + inner.timestamp = kernel_hal::timer::timer_now().as_nanos() as i64; } match &inner.port { Some(port) => { diff --git a/zircon-object/src/dev/pci/caps.rs b/zircon-object/src/dev/pci/caps.rs index 9cacdebeb..623684606 100644 --- a/zircon-object/src/dev/pci/caps.rs +++ b/zircon-object/src/dev/pci/caps.rs @@ -3,7 +3,7 @@ use crate::{ZxError, ZxResult}; use alloc::boxed::Box; use core::convert::TryFrom; -use kernel_hal::InterruptManager; +use kernel_hal::interrupt; use spin::*; /// Enumeration for PCI capabilities. @@ -46,23 +46,27 @@ impl PciMsiBlock { if irq_num == 0 || irq_num > 32 { return Err(ZxError::INVALID_ARGS); } - let (start, size) = - InterruptManager::msi_allocate_block(irq_num).ok_or(ZxError::NO_RESOURCES)?; + let range = interrupt::msi_allocate_block(irq_num).map_err(|_| ZxError::NO_RESOURCES)?; Ok(PciMsiBlock { target_addr: (0xFEE0_0000 | 0x08) & !0x4, - target_data: start as u32, - base_irq: start as u32, - num_irq: size as u32, + target_data: range.start, + base_irq: range.start, + num_irq: range.len() as u32, allocated: true, }) } pub fn free(&self) { - InterruptManager::msi_free_block(self.base_irq, self.num_irq) + interrupt::msi_free_block(self.base_irq..self.base_irq + self.num_irq).ok(); } pub fn register_handler(&self, msi_id: u32, handle: Box) { assert!(self.allocated); assert!(msi_id < self.num_irq); - InterruptManager::msi_register_handler(self.base_irq, self.num_irq, msi_id, handle); + interrupt::msi_register_handler( + self.base_irq..self.base_irq + self.num_irq, + msi_id, + handle, + ) + .ok(); } } diff --git a/zircon-object/src/dev/pci/nodes.rs b/zircon-object/src/dev/pci/nodes.rs index e8da4d531..d6d626607 100644 --- a/zircon-object/src/dev/pci/nodes.rs +++ b/zircon-object/src/dev/pci/nodes.rs @@ -13,7 +13,7 @@ use crate::{vm::PAGE_SIZE, ZxError, ZxResult}; use alloc::sync::{Arc, Weak}; use alloc::{boxed::Box, vec::Vec}; -use kernel_hal::InterruptManager; +use kernel_hal::interrupt; use numeric_enum_macro::numeric_enum; use region_alloc::RegionAllocator; use spin::{Mutex, MutexGuard}; @@ -192,26 +192,22 @@ impl SharedLegacyIrqHandler { /// Create a new SharedLegacyIrqHandler. pub fn create(irq_id: u32) -> Option> { info!("SharedLegacyIrqHandler created for {:#x?}", irq_id); - InterruptManager::disable_irq(irq_id); + interrupt::disable_irq(irq_id); let handler = Arc::new(SharedLegacyIrqHandler { irq_id, device_handler: Mutex::new(Vec::new()), }); let handler_copy = handler.clone(); - if InterruptManager::register_irq_handler(irq_id, Box::new(move || handler_copy.handle())) - .is_some() - { - Some(handler) - } else { - None - } + interrupt::register_irq_handler(irq_id, Box::new(move || handler_copy.handle())) + .map(|_| handler) + .ok() } /// Handle the IRQ. pub fn handle(&self) { let device_handler = self.device_handler.lock(); if device_handler.is_empty() { - InterruptManager::disable_irq(self.irq_id); + interrupt::disable_irq(self.irq_id); return; } for dev in device_handler.iter() { @@ -260,7 +256,7 @@ impl SharedLegacyIrqHandler { let is_first = device_handler.is_empty(); device_handler.push(device); if is_first { - InterruptManager::enable_irq(self.irq_id); + interrupt::enable_irq(self.irq_id); } } pub fn remove_device(&self, device: Arc) { @@ -272,7 +268,7 @@ impl SharedLegacyIrqHandler { let mut device_handler = self.device_handler.lock(); device_handler.retain(|h| Arc::ptr_eq(h, &device)); if device_handler.is_empty() { - InterruptManager::disable_irq(self.irq_id); + interrupt::disable_irq(self.irq_id); } } } diff --git a/zircon-object/src/dev/pci/pci_init_args.rs b/zircon-object/src/dev/pci/pci_init_args.rs index f80791cf9..d01b203b7 100644 --- a/zircon-object/src/dev/pci/pci_init_args.rs +++ b/zircon-object/src/dev/pci/pci_init_args.rs @@ -45,22 +45,23 @@ pub const PCI_INIT_ARG_MAX_SIZE: usize = core::mem::size_of::(); -use kernel_hal::InterruptManager; +use kernel_hal::interrupt; impl PciInitArgsHeader { pub fn configure_interrupt(&mut self) -> ZxResult { for i in 0..self.num_irqs as usize { let irq = &mut self.irqs[i]; let global_irq = irq.global_irq; - if !InterruptManager::is_valid_irq(global_irq) { + if !interrupt::is_valid_irq(global_irq) { irq.global_irq = PCI_NO_IRQ_MAPPING; self.dev_pin_to_global_irq.remove_irq(global_irq); - } else if !InterruptManager::configure_irq( - global_irq, - irq.level_triggered, /* Trigger mode */ - irq.active_high, /* Polarity */ - ) { - return Err(ZxError::INVALID_ARGS); + } else { + interrupt::configure_irq( + global_irq, + irq.level_triggered, /* Trigger mode */ + irq.active_high, /* Polarity */ + ) + .map_err(|_| ZxError::INVALID_ARGS)?; } } Ok(()) diff --git a/zircon-object/src/dev/pci/pio.rs b/zircon-object/src/dev/pci/pio.rs index 75c4b5aff..36bde8019 100644 --- a/zircon-object/src/dev/pci/pio.rs +++ b/zircon-object/src/dev/pci/pio.rs @@ -12,7 +12,7 @@ pub fn pci_bdf_raw_addr(bus: u8, dev: u8, func: u8, offset: u8) -> u32 { cfg_if::cfg_if! { if #[cfg(all(target_arch = "x86_64", target_os = "none"))] { - use kernel_hal::{inpd, outpd}; + use kernel_hal::x86_64::{pio_read, pio_write}; use spin::Mutex; static PIO_LOCK: Mutex<()> = Mutex::new(()); @@ -26,8 +26,8 @@ if #[cfg(all(target_arch = "x86_64", target_os = "none"))] { if shift + width > 32 { return Err(ZxError::INVALID_ARGS); } - outpd(PCI_CONFIG_ADDR, (addr & !0x3) | PCI_CONFIG_ENABLE); - let tmp_val = u32::from_le(inpd(PCI_CONFIG_DATA)); + pio_write(PCI_CONFIG_ADDR, (addr & !0x3) | PCI_CONFIG_ENABLE); + let tmp_val = u32::from_le(pio_read(PCI_CONFIG_DATA)); Ok((tmp_val >> shift) & (((1u64 << width) - 1) as u32)) } pub fn pio_config_write_addr(addr: u32, val: u32, width: usize) -> ZxResult { @@ -36,15 +36,15 @@ if #[cfg(all(target_arch = "x86_64", target_os = "none"))] { if shift + width > 32 { return Err(ZxError::INVALID_ARGS); } - outpd(PCI_CONFIG_ADDR, (addr & !0x3) | PCI_CONFIG_ENABLE); + pio_write(PCI_CONFIG_ADDR, (addr & !0x3) | PCI_CONFIG_ENABLE); let width_mask = ((1u64 << width) - 1) as u32; let val = val & width_mask; let tmp_val = if width < 32 { - (u32::from_le(inpd(PCI_CONFIG_DATA)) & !(width_mask << shift)) | (val << shift) + (u32::from_le(pio_read(PCI_CONFIG_DATA)) & !(width_mask << shift)) | (val << shift) } else { val }; - outpd(PCI_CONFIG_DATA, u32::to_le(tmp_val)); + pio_write(PCI_CONFIG_DATA, u32::to_le(tmp_val)); Ok(()) } } else { diff --git a/zircon-object/src/hypervisor/mod.rs b/zircon-object/src/hypervisor/mod.rs index 2ae4e28b7..cdc6267e3 100644 --- a/zircon-object/src/hypervisor/mod.rs +++ b/zircon-object/src/hypervisor/mod.rs @@ -4,7 +4,7 @@ mod guest; mod vcpu; use super::ZxError; -use kernel_hal::{HalError, MMUFlags, PageTableTrait, Result}; +use kernel_hal::{GenericPageTable, HalError, MMUFlags, Result}; use rvm::{ ArchRvmPageTable, GuestPhysAddr, HostPhysAddr, IntoRvmPageTableFlags, RvmError, RvmPageTable, }; @@ -56,7 +56,7 @@ impl VmmPageTable { } } -impl PageTableTrait for VmmPageTable { +impl GenericPageTable for VmmPageTable { fn map(&mut self, gpaddr: GuestPhysAddr, hpaddr: HostPhysAddr, flags: MMUFlags) -> Result<()> { self.0 .map(gpaddr, hpaddr, VmmPageTableFlags(flags)) diff --git a/zircon-object/src/signal/timer.rs b/zircon-object/src/signal/timer.rs index fcdfef121..a852831e7 100644 --- a/zircon-object/src/signal/timer.rs +++ b/zircon-object/src/signal/timer.rs @@ -73,7 +73,7 @@ impl Timer { inner.deadline = Some(deadline); self.base.signal_clear(Signal::SIGNALED); let me = Arc::downgrade(self); - kernel_hal::timer_set( + kernel_hal::timer::timer_set( deadline, Box::new(move |now| me.upgrade().map(|timer| timer.touch(now)).unwrap_or(())), ); @@ -100,7 +100,7 @@ impl Timer { #[cfg(test)] mod tests { use super::*; - use kernel_hal::timer_now; + use kernel_hal::timer::timer_now; #[test] fn one_shot() { diff --git a/zircon-object/src/task/exception.rs b/zircon-object/src/task/exception.rs index 6f964ef38..5099ca690 100644 --- a/zircon-object/src/task/exception.rs +++ b/zircon-object/src/task/exception.rs @@ -1,6 +1,6 @@ use { super::*, crate::ipc::*, crate::object::*, alloc::sync::Arc, alloc::vec, alloc::vec::Vec, - core::mem::size_of, futures::channel::oneshot, kernel_hal::UserContext, spin::Mutex, + core::mem::size_of, futures::channel::oneshot, kernel_hal::context::UserContext, spin::Mutex, }; /// Kernel-owned exception channel endpoint. @@ -157,7 +157,7 @@ impl ExceptionContext { ExceptionContext { vector: cx.trap_num as u64, err_code: cx.error_code as u64, - cr2: kernel_hal::fetch_fault_vaddr() as u64, + cr2: kernel_hal::context::fetch_page_fault_info(cx.error_code).0 as u64, } } #[cfg(target_arch = "aarch64")] diff --git a/zircon-object/src/task/process.rs b/zircon-object/src/task/process.rs index 520305f9c..fd7ec0ebb 100644 --- a/zircon-object/src/task/process.rs +++ b/zircon-object/src/task/process.rs @@ -143,7 +143,7 @@ impl Process { /// # use std::sync::Arc; /// # use zircon_object::task::*; /// # use zircon_object::object::*; - /// # kernel_hal_unix::init(); + /// # kernel_hal::init(); /// # async_std::task::block_on(async { /// let job = Job::root(); /// let proc = Process::create(&job, "proc").unwrap(); diff --git a/zircon-object/src/task/suspend_token.rs b/zircon-object/src/task/suspend_token.rs index f3d2674fc..9d3247a99 100644 --- a/zircon-object/src/task/suspend_token.rs +++ b/zircon-object/src/task/suspend_token.rs @@ -13,7 +13,7 @@ use { /// # use std::sync::Arc; /// # use zircon_object::task::*; /// # use zircon_object::object::{KernelObject, Signal}; -/// # kernel_hal_unix::init(); +/// # kernel_hal::init(); /// let job = Job::root(); /// let proc = Process::create(&job, "proc").unwrap(); /// let thread = Thread::create(&proc, "thread").unwrap(); diff --git a/zircon-object/src/task/thread.rs b/zircon-object/src/task/thread.rs index a217c7e3f..1d6ecf902 100644 --- a/zircon-object/src/task/thread.rs +++ b/zircon-object/src/task/thread.rs @@ -14,7 +14,8 @@ use { time::Duration, }, futures::{channel::oneshot::*, future::FutureExt, pin_mut, select_biased}, - kernel_hal::{sleep_until, GeneralRegs, UserContext}, + kernel_hal::context::{GeneralRegs, UserContext}, + // kernel_hal::future::sleep_until, spin::Mutex, }; @@ -193,7 +194,7 @@ impl Thread { /// ``` /// # use std::sync::Arc; /// # use zircon_object::task::*; - /// # kernel_hal_unix::init(); + /// # kernel_hal::init(); /// let job = Job::root(); /// let proc = Process::create(&job, "proc").unwrap(); /// // create a thread with extension info @@ -272,7 +273,7 @@ impl Thread { inner.change_state(ThreadState::Running, &self.base); } let vmtoken = self.proc().vmar().table_phys(); - kernel_hal::Thread::spawn(thread_fn(CurrentThread(self.clone())), vmtoken); + kernel_hal::thread::spawn(thread_fn(CurrentThread(self.clone())), vmtoken); Ok(()) } @@ -289,7 +290,7 @@ impl Thread { inner.change_state(ThreadState::Running, &self.base); } let vmtoken = self.proc().vmar().table_phys(); - kernel_hal::Thread::spawn(thread_fn(CurrentThread(self.clone())), vmtoken); + kernel_hal::thread::spawn(thread_fn(CurrentThread(self.clone())), vmtoken); Ok(()) } @@ -313,7 +314,7 @@ impl Thread { inner.change_state(ThreadState::Running, &self.base); } let vmtoken = self.proc().vmar().table_phys(); - kernel_hal::Thread::spawn(thread_fn(CurrentThread(self.clone())), vmtoken); + kernel_hal::thread::spawn(thread_fn(CurrentThread(self.clone())), vmtoken); Ok(()) } @@ -602,14 +603,14 @@ impl CurrentThread { select_biased! { ret = future.fuse() => ret.into_result(), _ = killed.fuse() => Err(ZxError::STOP), - _ = sleep_until(deadline).fuse() => Err(ZxError::TIMED_OUT), + _ = kernel_hal::future::sleep_until(deadline).fuse() => Err(ZxError::TIMED_OUT), _ = cancel_token.fuse() => Err(ZxError::CANCELED), } } else { select_biased! { ret = future.fuse() => ret.into_result(), _ = killed.fuse() => Err(ZxError::STOP), - _ = sleep_until(deadline).fuse() => Err(ZxError::TIMED_OUT), + _ = kernel_hal::future::sleep_until(deadline).fuse() => Err(ZxError::TIMED_OUT), } }; let mut inner = self.inner.lock(); @@ -765,7 +766,7 @@ pub struct ThreadInfo { mod tests { use super::job::Job; use super::*; - use kernel_hal::timer_now; + use kernel_hal::timer::timer_now; #[test] fn create() { @@ -781,7 +782,7 @@ mod tests { #[async_std::test] async fn start() { - kernel_hal_unix::init(); + kernel_hal::init(); let root_job = Job::root(); let proc = Process::create(&root_job, "proc").expect("failed to create process"); let thread = Thread::create(&proc, "thread").expect("failed to create thread"); diff --git a/zircon-object/src/task/thread/thread_state.rs b/zircon-object/src/task/thread/thread_state.rs index 514c01854..f8af5a315 100644 --- a/zircon-object/src/task/thread/thread_state.rs +++ b/zircon-object/src/task/thread/thread_state.rs @@ -1,5 +1,5 @@ use crate::{ZxError, ZxResult}; -use kernel_hal::UserContext; +use kernel_hal::context::UserContext; use numeric_enum_macro::numeric_enum; numeric_enum! { diff --git a/zircon-object/src/util/block_range.rs b/zircon-object/src/util/block_range.rs index 9c52ea86b..5f7c73e63 100644 --- a/zircon-object/src/util/block_range.rs +++ b/zircon-object/src/util/block_range.rs @@ -1,6 +1,7 @@ #![allow(dead_code)] /// Given a range and iterate sub-range for each block +#[derive(Debug)] pub struct BlockIter { pub begin: usize, pub end: usize, diff --git a/zircon-object/src/vm/vmar.rs b/zircon-object/src/vm/vmar.rs index 433fc34cb..1b0b8ca95 100644 --- a/zircon-object/src/vm/vmar.rs +++ b/zircon-object/src/vm/vmar.rs @@ -1,6 +1,12 @@ use { - super::*, crate::object::*, alloc::sync::Arc, alloc::vec, alloc::vec::Vec, bitflags::bitflags, - kernel_hal::PageTableTrait, spin::Mutex, + super::*, + crate::object::*, + alloc::{sync::Arc, vec, vec::Vec}, + bitflags::bitflags, + kernel_hal::vm::{ + GenericPageTable, IgnoreNotMappedErr, Page, PageSize, PageTable, PagingError, + }, + spin::Mutex, }; bitflags! { @@ -44,7 +50,7 @@ pub struct VmAddressRegion { addr: VirtAddr, size: usize, parent: Option>, - page_table: Arc>, + page_table: Arc>, /// If inner is None, this region is destroyed, all operations are invalid. inner: Mutex>, } @@ -78,7 +84,7 @@ impl VmAddressRegion { addr, size, parent: None, - page_table: Arc::new(Mutex::new(kernel_hal::PageTable::new())), //hal PageTable + page_table: Arc::new(Mutex::new(PageTable::from_current().clone_kernel())), //hal PageTable inner: Mutex::new(Some(VmarInner::default())), }) } @@ -94,7 +100,7 @@ impl VmAddressRegion { addr: kernel_vmar_base, size: kernel_vmar_size, parent: None, - page_table: Arc::new(Mutex::new(kernel_hal::PageTable::new())), + page_table: Arc::new(Mutex::new(PageTable::from_current().clone_kernel())), inner: Mutex::new(Some(VmarInner::default())), }) } @@ -496,12 +502,6 @@ impl VmAddressRegion { self.flags } - #[cfg(target_arch = "riscv64")] - /// Activate this page table - pub fn activate(&self) { - self.page_table.lock().activate(); - } - /// Dump all mappings recursively. pub fn dump(&self) { let mut guard = self.inner.lock(); @@ -637,7 +637,7 @@ impl VmarInner { fn fork_from( &mut self, src: &Arc, - page_table: &Arc>, + page_table: &Arc>, ) -> ZxResult { let src_guard = src.inner.lock(); let src_inner = src_guard.as_ref().unwrap(); @@ -667,7 +667,7 @@ pub struct VmMapping { /// The permission limitation of the vmar permissions: MMUFlags, vmo: Arc, - page_table: Arc>, + page_table: Arc>, inner: Mutex, } @@ -712,7 +712,7 @@ impl VmMapping { vmo_offset: usize, permissions: MMUFlags, flags: MMUFlags, - page_table: Arc>, + page_table: Arc>, ) -> Arc { let mapping = Arc::new(VmMapping { inner: Mutex::new(VmMappingInner { @@ -741,9 +741,13 @@ impl VmMapping { let vmo_offset = inner.vmo_offset / PAGE_SIZE; for i in 0..page_num { let paddr = commit(vmo_offset + i, inner.flags[i])?; - //通过PageTableTrait的hal_pt_map进行页表映射 + //通过GenericPageTable的hal_pt_map进行页表映射 page_table - .map(inner.addr + i * PAGE_SIZE, paddr, inner.flags[i]) + .map( + Page::new_aligned(inner.addr + i * PAGE_SIZE, PageSize::Size4K), + paddr, + inner.flags[i], + ) .expect("failed to map"); } Ok(()) @@ -752,11 +756,10 @@ impl VmMapping { fn unmap(&self) { let inner = self.inner.lock(); - let pages = inner.size / PAGE_SIZE; // TODO inner.vmo_offset unused? self.page_table .lock() - .unmap_cont(inner.addr, pages) + .unmap_cont(inner.addr, inner.size) .expect("failed to unmap") } @@ -789,7 +792,7 @@ impl VmMapping { if inner.addr >= begin && inner.end_addr() <= end { // subset: [xxxxxxxxxx] page_table - .unmap_cont(inner.addr, pages(inner.size)) + .unmap_cont(inner.addr, inner.size) .expect("failed to unmap"); inner.size = 0; inner.flags.clear(); @@ -798,7 +801,7 @@ impl VmMapping { // prefix: [xxxx------] let cut_len = end - inner.addr; page_table - .unmap_cont(inner.addr, pages(cut_len)) + .unmap_cont(inner.addr, cut_len) .expect("failed to unmap"); inner.addr = end; inner.size -= cut_len; @@ -810,7 +813,7 @@ impl VmMapping { let cut_len = inner.end_addr() - begin; let new_len = begin - inner.addr; page_table - .unmap_cont(begin, pages(cut_len)) + .unmap_cont(begin, cut_len) .expect("failed to unmap"); inner.size = new_len; inner.flags.truncate(new_len); @@ -821,7 +824,7 @@ impl VmMapping { let new_len1 = begin - inner.addr; let new_len2 = inner.end_addr() - end; page_table - .unmap_cont(begin, pages(cut_len)) + .unmap_cont(begin, cut_len) .expect("failed to unmap"); let new_flags_range = (pages(inner.size) - pages(new_len2))..pages(inner.size); let new_mapping = Arc::new(VmMapping { @@ -864,7 +867,8 @@ impl VmMapping { new_flags.insert(flags & MMUFlags::RXW); inner.flags[i] = new_flags; pg_table - .protect(inner.addr + i * PAGE_SIZE, new_flags) + .update(inner.addr + i * PAGE_SIZE, None, Some(new_flags)) + .ignore() .unwrap(); } } @@ -907,11 +911,14 @@ impl VmMapping { let mut new_flag = inner.flags[i]; new_flag.remove(MMUFlags::WRITE); pg_table - .protect(inner.addr + i * PAGE_SIZE, new_flag) - .unwrap() + .update(inner.addr + i * PAGE_SIZE, None, Some(new_flag)) + .ignore() + .unwrap(); + } + RangeChangeOp::Unmap => { + pg_table.unmap(inner.addr + i * PAGE_SIZE).ignore().unwrap(); } - RangeChangeOp::Unmap => pg_table.unmap(inner.addr + i * PAGE_SIZE).unwrap(), - } + }; } } } @@ -920,8 +927,11 @@ impl VmMapping { /// Handle page fault happened on this VmMapping. pub(crate) fn handle_page_fault(&self, vaddr: VirtAddr, access_flags: MMUFlags) -> ZxResult { let vaddr = round_down_pages(vaddr); - let page_idx = (vaddr - self.addr()) / PAGE_SIZE; - let mut flags = self.inner.lock().flags[page_idx]; + let (vmo_offset, mut flags) = { + let inner = self.inner.lock(); + let offset = vaddr - inner.addr; + (offset + inner.vmo_offset, inner.flags[offset / PAGE_SIZE]) + }; if !flags.contains(access_flags) { return Err(ZxError::ACCESS_DENIED); } @@ -930,17 +940,18 @@ impl VmMapping { warn!("handle_page_fault remove MMUFlags::WRITE !"); flags.remove(MMUFlags::WRITE) } - let paddr = self.vmo.commit_page(page_idx, access_flags)?; + let paddr = self.vmo.commit_page(vmo_offset / PAGE_SIZE, access_flags)?; let mut pg_table = self.page_table.lock(); - pg_table.unmap(vaddr).unwrap(); - pg_table - .map(vaddr, paddr, flags) - .map_err(|_| ZxError::ACCESS_DENIED)?; + let mut res = pg_table.map(Page::new_aligned(vaddr, PageSize::Size4K), paddr, flags); + if let Err(PagingError::AlreadyMapped) = res { + res = pg_table.update(vaddr, Some(paddr), Some(flags)).map(|_| ()); + } + res.map_err(|_| ZxError::ACCESS_DENIED)?; Ok(()) } /// Clone VMO and map it to a new page table. (For Linux) - fn clone_map(&self, page_table: Arc>) -> ZxResult> { + fn clone_map(&self, page_table: Arc>) -> ZxResult> { //这里调用hal protect后,protect()好像会破坏页表 let new_vmo = self.vmo.create_child(false, 0, self.vmo.len())?; let mapping = Arc::new(VmMapping { diff --git a/zircon-object/src/vm/vmo/paged.rs b/zircon-object/src/vm/vmo/paged.rs index 25798b4b5..416889a8a 100644 --- a/zircon-object/src/vm/vmo/paged.rs +++ b/zircon-object/src/vm/vmo/paged.rs @@ -8,7 +8,7 @@ use { core::ops::Range, core::sync::atomic::*, hashbrown::HashMap, - kernel_hal::{frame_flush, PhysFrame, PAGE_SIZE}, + kernel_hal::{mem::PhysFrame, PAGE_SIZE}, spin::{Mutex, MutexGuard}, }; @@ -180,7 +180,7 @@ impl VMObjectPaged { /// Create a new VMO backing on contiguous pages. pub fn new_contiguous(pages: usize, align_log2: usize) -> ZxResult> { let vmo = Self::new(pages); - let mut frames = PhysFrame::alloc_contiguous(pages, align_log2 - PAGE_SIZE_LOG2); + let mut frames = PhysFrame::new_contiguous(pages, align_log2 - PAGE_SIZE_LOG2); if frames.is_empty() { return Err(ZxError::NO_MEMORY); } @@ -188,7 +188,7 @@ impl VMObjectPaged { let (_guard, mut inner) = vmo.get_inner_mut(); inner.contiguous = true; for (i, f) in frames.drain(0..).enumerate() { - kernel_hal::pmem_zero(f.addr(), PAGE_SIZE); + kernel_hal::mem::pmem_zero(f.paddr(), PAGE_SIZE); let mut state = PageState::new(f); state.pin_count += 1; inner.frames.insert(i, state); @@ -225,7 +225,7 @@ impl VMObjectTrait for VMObjectPaged { return Err(ZxError::BAD_STATE); } inner.for_each_page(offset, buf.len(), MMUFlags::READ, |paddr, buf_range| { - kernel_hal::pmem_read(paddr, &mut buf[buf_range]); + kernel_hal::mem::pmem_read(paddr, &mut buf[buf_range]); }) } @@ -235,7 +235,7 @@ impl VMObjectTrait for VMObjectPaged { return Err(ZxError::BAD_STATE); } inner.for_each_page(offset, buf.len(), MMUFlags::WRITE, |paddr, buf_range| { - kernel_hal::pmem_write(paddr, &buf[buf_range]); + kernel_hal::mem::pmem_write(paddr, &buf[buf_range]); }) } @@ -259,7 +259,7 @@ impl VMObjectTrait for VMObjectPaged { } else if inner.committed_pages_in_range(block.block, block.block + 1) != 0 { // check whether this page is initialized, otherwise nothing should be done let paddr = inner.commit_page(block.block, MMUFlags::WRITE)?; - kernel_hal::pmem_zero(paddr + block.begin, block.len()); + kernel_hal::mem::pmem_zero(paddr + block.begin, block.len()); } } inner.release_unwanted_pages_in_parent(unwanted); @@ -371,7 +371,7 @@ impl VMObjectTrait for VMObjectPaged { } if inner.cache_policy == CachePolicy::Cached && policy != CachePolicy::Cached { for (_, value) in inner.frames.iter() { - frame_flush(value.frame.addr()); + kernel_hal::mem::frame_flush(value.frame.paddr()); } } inner.cache_policy = policy; @@ -523,12 +523,11 @@ impl VMObjectPagedInner { if out_of_range || no_parent { if !flags.contains(MMUFlags::WRITE) { // read-only, just return zero frame - return Ok(CommitResult::Ref(PhysFrame::zero_frame_addr())); + return Ok(CommitResult::Ref(kernel_hal::mem::ZERO_FRAME.paddr())); } // lazy allocate zero frame // 这里会调用HAL层的hal_frame_alloc, 请注意实现该函数时参数要一样 - let target_frame = PhysFrame::alloc().ok_or(ZxError::NO_MEMORY)?; - kernel_hal::pmem_zero(target_frame.addr(), PAGE_SIZE); + let target_frame = PhysFrame::new_zero().ok_or(ZxError::NO_MEMORY)?; if out_of_range { // can never be a hidden vmo assert!(!self.type_.is_hidden()); @@ -606,13 +605,13 @@ impl VMObjectPagedInner { return Ok(CommitResult::CopyOnWrite(target_frame, need_unmap)); } else if flags.contains(MMUFlags::WRITE) && child_tag.is_split() { // copy-on-write - let target_frame = PhysFrame::alloc().ok_or(ZxError::NO_MEMORY)?; - kernel_hal::frame_copy(frame.frame.addr(), target_frame.addr()); + let target_frame = PhysFrame::new().ok_or(ZxError::NO_MEMORY)?; + kernel_hal::mem::pmem_copy(target_frame.paddr(), frame.frame.paddr(), PAGE_SIZE); frame.tag = child_tag; return Ok(CommitResult::CopyOnWrite(target_frame, true)); } // otherwise already committed - Ok(CommitResult::Ref(frame.frame.addr())) + Ok(CommitResult::Ref(frame.frame.paddr())) } fn decommit(&mut self, page_idx: usize) { @@ -1005,7 +1004,7 @@ impl VMObjectPagedInner { } let mut base = 0; for (key, ps) in self.frames.iter() { - let new_base = ps.frame.addr() - key * PAGE_SIZE; + let new_base = ps.frame.paddr() - key * PAGE_SIZE; if base == 0 || new_base == base { base = new_base; } else { diff --git a/zircon-object/src/vm/vmo/physical.rs b/zircon-object/src/vm/vmo/physical.rs index 89888df87..ba05c4d50 100644 --- a/zircon-object/src/vm/vmo/physical.rs +++ b/zircon-object/src/vm/vmo/physical.rs @@ -39,21 +39,21 @@ impl VMObjectTrait for VMObjectPhysical { fn read(&self, offset: usize, buf: &mut [u8]) -> ZxResult { let _ = self.data_lock.lock(); assert!(offset + buf.len() <= self.len()); - kernel_hal::pmem_read(self.paddr + offset, buf); + kernel_hal::mem::pmem_read(self.paddr + offset, buf); Ok(()) } fn write(&self, offset: usize, buf: &[u8]) -> ZxResult { let _ = self.data_lock.lock(); assert!(offset + buf.len() <= self.len()); - kernel_hal::pmem_write(self.paddr + offset, buf); + kernel_hal::mem::pmem_write(self.paddr + offset, buf); Ok(()) } fn zero(&self, offset: usize, len: usize) -> ZxResult { let _ = self.data_lock.lock(); assert!(offset + len <= self.len()); - kernel_hal::pmem_zero(self.paddr + offset, len); + kernel_hal::mem::pmem_zero(self.paddr + offset, len); Ok(()) } diff --git a/zircon-syscall/src/cprng.rs b/zircon-syscall/src/cprng.rs index ffaaf98e2..1e936dbda 100644 --- a/zircon-syscall/src/cprng.rs +++ b/zircon-syscall/src/cprng.rs @@ -1,16 +1,16 @@ use super::*; impl Syscall<'_> { - /// Draw random bytes from the kernel CPRNG. + /// Draw random bytes from the kernel CPRNG. /// - /// This data should be suitable for cryptographic applications. + /// This data should be suitable for cryptographic applications. /// /// Clients that require a large volume of randomness should consider using these bytes to seed a user-space random number generator for better performance. pub fn sys_cprng_draw_once(&self, mut buf: UserOutPtr, len: usize) -> ZxResult { info!("cprng_draw_once: buf=({:?}; {:?})", buf, len); let mut res = vec![0u8; len]; // Fill random bytes to the buffer - kernel_hal::fill_random(&mut res); + kernel_hal::rand::fill_random(&mut res); buf.write_array(&res)?; Ok(()) } diff --git a/zircon-syscall/src/ddk.rs b/zircon-syscall/src/ddk.rs index 3064a1b81..d52007a5e 100644 --- a/zircon-syscall/src/ddk.rs +++ b/zircon-syscall/src/ddk.rs @@ -38,11 +38,11 @@ impl Syscall<'_> { out.write(handle)?; Ok(()) } - /// Creates a new bus transaction initiator. + /// Creates a new bus transaction initiator. /// - /// `iommu: HandleValue`, a handle to an IOMMU. - /// `options: u32`, must be 0 (reserved for future definition of creation flags). - /// `bti_id: u64`, a hardware transaction identifier for a device downstream of that IOMMU. + /// `iommu: HandleValue`, a handle to an IOMMU. + /// `options: u32`, must be 0 (reserved for future definition of creation flags). + /// `bti_id: u64`, a hardware transaction identifier for a device downstream of that IOMMU. pub fn sys_bti_create( &self, iommu: HandleValue, @@ -69,7 +69,7 @@ impl Syscall<'_> { } #[allow(clippy::too_many_arguments)] - /// Pin pages and grant devices access to them. + /// Pin pages and grant devices access to them. pub fn sys_bti_pin( &self, bti: HandleValue, @@ -113,7 +113,7 @@ impl Syscall<'_> { Ok(()) } - /// Unpins pages that were previously pinned by `zx_bti_pin()`. + /// Unpins pages that were previously pinned by `zx_bti_pin()`. pub fn sys_pmt_unpin(&self, pmt: HandleValue) -> ZxResult { info!("pmt.unpin: pmt={:#x}", pmt); let proc = self.thread.proc(); @@ -131,7 +131,7 @@ impl Syscall<'_> { Ok(()) } - /// + /// #[allow(unused_variables, unused_mut)] pub fn sys_pc_firmware_tables( &self, @@ -145,7 +145,7 @@ impl Syscall<'_> { .validate(ResourceKind::ROOT)?; cfg_if::cfg_if! { if #[cfg(all(target_arch = "x86_64", target_os = "none"))] { - let (acpi_rsdp, smbios) = kernel_hal::pc_firmware_tables(); + let (acpi_rsdp, smbios) = kernel_hal::x86_64::pc_firmware_tables(); acpi_rsdp_ptr.write(acpi_rsdp)?; smbios_ptr.write(smbios)?; Ok(()) @@ -155,7 +155,7 @@ impl Syscall<'_> { } } - /// Creates an interrupt object which represents a physical or virtual interrupt. + /// Creates an interrupt object which represents a physical or virtual interrupt. pub fn sys_interrupt_create( &self, resource: HandleValue, @@ -184,7 +184,7 @@ impl Syscall<'_> { Ok(()) } - /// Binds or unbinds an interrupt object to a port. + /// Binds or unbinds an interrupt object to a port. /// /// The key used when binding the interrupt will be present in the key field of the `zx_port_packet_t`. pub fn sys_interrupt_bind( @@ -213,7 +213,7 @@ impl Syscall<'_> { } } - /// Triggers a virtual interrupt object. + /// Triggers a virtual interrupt object. pub fn sys_interrupt_trigger( &self, interrupt: HandleValue, @@ -231,7 +231,7 @@ impl Syscall<'_> { interrupt.trigger(timestamp) } - /// Acknowledge an interrupt and re-arm it. + /// Acknowledge an interrupt and re-arm it. /// /// This system call acknowledges an interrupt object, causing it to be eligible to trigger again (and delivering a packet to the port it is bound to). pub fn sys_interrupt_ack(&self, interrupt: HandleValue) -> ZxResult { @@ -243,14 +243,14 @@ impl Syscall<'_> { interrupt.ack() } - /// Destroys an interrupt object. + /// Destroys an interrupt object. pub fn sys_interrupt_destroy(&self, interrupt: HandleValue) -> ZxResult { info!("interupt.destory: interrupt={:?}", interrupt); let interrupt = self.thread.proc().get_object::(interrupt)?; interrupt.destroy() } - /// A blocking syscall which causes the caller to wait until an interrupt is triggered. + /// A blocking syscall which causes the caller to wait until an interrupt is triggered. pub async fn sys_interrupt_wait( &self, interrupt: HandleValue, diff --git a/zircon-syscall/src/debug.rs b/zircon-syscall/src/debug.rs index 682c3f030..941d81c0a 100644 --- a/zircon-syscall/src/debug.rs +++ b/zircon-syscall/src/debug.rs @@ -2,15 +2,15 @@ use super::*; use zircon_object::dev::*; impl Syscall<'_> { - /// Write debug info to the serial port. + /// Write debug info to the serial port. pub fn sys_debug_write(&self, buf: UserInPtr, len: usize) -> ZxResult { info!("debug.write: buf=({:?}; {:#x})", buf, len); let data = buf.read_array(len)?; - kernel_hal::serial_write(core::str::from_utf8(&data).unwrap()); + kernel_hal::serial::serial_write(core::str::from_utf8(&data).unwrap()); Ok(()) } - /// Read debug info from the serial port. + /// Read debug info from the serial port. pub async fn sys_debug_read( &self, handle: HandleValue, @@ -31,7 +31,7 @@ impl Syscall<'_> { // let len = kernel_hal::serial_read(&mut vec); // buf.write_array(&vec[..len])?; // actual.write(len as u32)?; - let c = kernel_hal::serial_getchar().await; + let c = kernel_hal::future::serial_getchar().await; buf.write_array(&[c])?; actual.write(1)?; Ok(()) diff --git a/zircon-syscall/src/debuglog.rs b/zircon-syscall/src/debuglog.rs index 7675ac69a..2baa18332 100644 --- a/zircon-syscall/src/debuglog.rs +++ b/zircon-syscall/src/debuglog.rs @@ -4,7 +4,7 @@ use { }; impl Syscall<'_> { - /// Create a kernel managed debuglog reader or writer. + /// Create a kernel managed debuglog reader or writer. pub fn sys_debuglog_create( &self, rsrc: HandleValue, @@ -32,7 +32,7 @@ impl Syscall<'_> { Ok(()) } - /// Write log entry to debuglog. + /// Write log entry to debuglog. pub fn sys_debuglog_write( &self, handle_value: HandleValue, @@ -54,15 +54,15 @@ impl Syscall<'_> { let dlog = proc.get_object_with_rights::(handle_value, Rights::WRITE)?; dlog.write(Severity::Info, options, self.thread.id(), proc.id(), &data); // print to kernel console - kernel_hal::serial_write(&data); + kernel_hal::serial::serial_write(&data); if data.as_bytes().last() != Some(&b'\n') { - kernel_hal::serial_write("\n"); + kernel_hal::serial::serial_write("\n"); } Ok(()) } #[allow(unsafe_code)] - /// Read log entries from debuglog. + /// Read log entries from debuglog. pub fn sys_debuglog_read( &self, handle_value: HandleValue, diff --git a/zircon-syscall/src/time.rs b/zircon-syscall/src/time.rs index f0bcbaff1..5ae43ef0f 100644 --- a/zircon-syscall/src/time.rs +++ b/zircon-syscall/src/time.rs @@ -5,7 +5,7 @@ use { sync::atomic::{AtomicU64, Ordering}, time::Duration, }, - kernel_hal::{sleep_until, timer_now, yield_now}, + kernel_hal::timer::timer_now, zircon_object::{dev::*, task::*}, }; @@ -16,7 +16,7 @@ const ZX_CLOCK_UTC: u32 = 1; const ZX_CLOCK_THREAD: u32 = 2; impl Syscall<'_> { - /// Create a new clock object. + /// Create a new clock object. pub fn sys_clock_create( &self, _options: u64, @@ -27,10 +27,10 @@ impl Syscall<'_> { Ok(()) } - /// Acquire the current time. - /// - /// + Returns the current time of clock_id via `time`. - /// + Returns whether `clock_id` was valid. + /// Acquire the current time. + /// + /// + Returns the current time of clock_id via `time`. + /// + Returns whether `clock_id` was valid. pub fn sys_clock_get(&self, clock_id: u32, mut time: UserOutPtr) -> ZxResult { info!("clock.get: id={}", clock_id); match clock_id { @@ -50,7 +50,7 @@ impl Syscall<'_> { } } - /// Perform a basic read of the clock. + /// Perform a basic read of the clock. pub fn sys_clock_read(&self, handle: HandleValue, mut now: UserOutPtr) -> ZxResult { info!("clock.read: handle={:#x?}", handle); warn!("ignore clock handle"); @@ -89,16 +89,16 @@ impl Syscall<'_> { } /// Sleep for some number of nanoseconds. - /// + /// /// A `deadline` value less than or equal to 0 immediately yields the thread. pub async fn sys_nanosleep(&self, deadline: Deadline) -> ZxResult { info!("nanosleep: deadline={:?}", deadline); if deadline.0 <= 0 { - yield_now().await; + kernel_hal::future::yield_now().await; } else { self.thread .blocking_run( - sleep_until(deadline.into()), + kernel_hal::future::sleep_until(deadline.into()), ThreadState::BlockedSleeping, Deadline::forever().into(), None,