diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index eecc059a..ac42316d 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -22,7 +22,7 @@ jobs: matrix: os: [ubuntu-latest, macos-latest] # we will bring back mipsel later - arch: [x86_64, riscv32, riscv64, aarch64] + arch: [x86_64, riscv32, riscv64, aarch64, mipsel] steps: - uses: actions/checkout@v2 - name: Checkout submodules diff --git a/kernel/Cargo.lock b/kernel/Cargo.lock index 5e315aa1..ee529942 100644 --- a/kernel/Cargo.lock +++ b/kernel/Cargo.lock @@ -166,7 +166,7 @@ dependencies = [ [[package]] name = "device_tree" version = "1.0.3" -source = "git+https://github.com/rcore-os/device_tree-rs?rev=2fa8411c#2fa8411c421c6b4761992fd3d1a9b2427bf0cfc4" +source = "git+https://github.com/rcore-os/device_tree-rs?rev=eee2c23#eee2c23d50a2cdacb7777429d71e00691b361978" [[package]] name = "either" @@ -709,7 +709,7 @@ checksum = "3a385d94f3f62e60445a0adb9ff8d9621faa272234530d4c0f848ec98f88e316" [[package]] name = "trapframe" version = "0.4.3" -source = "git+https://github.com/rcore-os/trapframe-rs?rev=b7fb4ff#b7fb4ffb3d8d36355842867837e13384c68212a2" +source = "git+https://github.com/rcore-os/trapframe-rs?rev=bdfe5aa#bdfe5aaebcdd64636c8831c2b8c17e4fede40c0b" dependencies = [ "raw-cpuid", "x86_64", diff --git a/kernel/Cargo.toml b/kernel/Cargo.toml index 237a8e93..642e456d 100644 --- a/kernel/Cargo.toml +++ b/kernel/Cargo.toml @@ -27,8 +27,7 @@ nographic = [] consolegraphic = [] board_raspi3 = ["bcm2837"] # for qemu machine -board_malta = ["link_user"] -board_mipssim = ["link_user"] +board_malta = [] # for x86 PC board_pc = ["link_user"] # Hard link user program @@ -49,7 +48,7 @@ bitvec = { version = "0.17", default-features = false, features = ["alloc"] } bit_field = "0.10" buddy_system_allocator = "0.4.0" compression = { version = "0.1.4", default-features = false, features = ["gzip"] } -device_tree = { git = "https://github.com/rcore-os/device_tree-rs", rev = "2fa8411c" } +device_tree = { git = "https://github.com/rcore-os/device_tree-rs", rev = "eee2c23" } executor = { git = "https://github.com/rcore-os/executor.git", rev = "a2d02ee9" } isomorphic_drivers = { git = "https://github.com/rcore-os/isomorphic_drivers", rev = "fcf694d2", features = ["log"] } lazy_static = { version = "1.4", features = ["spin_no_std"] } @@ -70,7 +69,7 @@ rcore-fs-devfs = { git = "https://github.com/rcore-os/rcore-fs", rev = "517af47" rlibc = "1.0" smoltcp = { git = "https://github.com/rcore-os/smoltcp", rev = "5bd87c7c", default-features = false, features = ["alloc", "log", "ethernet", "proto-ipv4", "proto-igmp", "socket-icmp", "socket-udp", "socket-tcp", "socket-raw"] } spin = "0.5" -trapframe = { git = "https://github.com/rcore-os/trapframe-rs", rev = "b7fb4ff" } +trapframe = { git = "https://github.com/rcore-os/trapframe-rs", rev = "bdfe5aa" } virtio-drivers = { git = "https://github.com/rcore-os/virtio-drivers", rev = "dfa70e14" } volatile = "0.2" woke = "0.0.2" diff --git a/kernel/Makefile b/kernel/Makefile index 61ca313f..ecb17c73 100644 --- a/kernel/Makefile +++ b/kernel/Makefile @@ -65,11 +65,6 @@ ifeq ($(ARCH), mipsel) DTB := src/arch/$(ARCH)/board/$(BOARD)/device.dtb endif -# mipssim does not support SMP -ifeq ($(BOARD), mipssim) -SMP := 1 -endif - ### qemu options ### qemu_opts := \ -smp cores=$(SMP) @@ -157,15 +152,10 @@ else ifeq ($(ARCH), mipsel) ifeq ($(BOARD), malta) qemu_opts += \ -machine $(BOARD) -device VGA \ + -hda $(USER_QCOW2) \ -serial null -serial null -serial mon:stdio \ -kernel $(kernel_img) endif -ifeq ($(BOARD), mipssim) -qemu_opts += \ - -machine $(BOARD) \ - -serial mon:stdio \ - -kernel $(kernel_img) -endif endif ifdef D @@ -302,7 +292,7 @@ ifeq ($(ARCH), $(filter $(ARCH), riscv32 riscv64)) $(sysroot)/lib/rustlib/src/rust/src/libcore/sync/atomic.rs \ src/arch/riscv/atomic.patch else ifeq ($(ARCH), mipsel) - @for file in context entry trap ; do \ + @for file in entry ; do \ $(hostcc) -Dboard_$(BOARD) -E src/arch/$(ARCH)/boot/$${file}.S -o src/arch/$(ARCH)/boot/$${file}.gen.s ; \ done $(hostcc) -Dboard_$(BOARD) -E src/arch/$(ARCH)/boot/linker.ld.S -o src/arch/$(ARCH)/boot/linker.ld diff --git a/kernel/build.rs b/kernel/build.rs index 28d09054..6ad6ceb6 100644 --- a/kernel/build.rs +++ b/kernel/build.rs @@ -17,5 +17,11 @@ fn main() { } else if target.contains("riscv64") { println!("cargo:rustc-cfg=riscv"); println!("cargo:rustc-cfg=riscv64"); + } else if target.contains("mipsel") { + println!("cargo:rustc-cfg=mipsel"); + } else if target.contains("aarch64") { + println!("cargo:rustc-cfg=aarch64"); + } else if target.contains("x86_64") { + println!("cargo:rustc-cfg=x86_64"); } } diff --git a/kernel/spec.md b/kernel/spec.md index 1fea02db..2ed2bea9 100644 --- a/kernel/spec.md +++ b/kernel/spec.md @@ -30,14 +30,13 @@ - fn ack(trap: usize):确认中断处理 - fn timer():处理时钟中断 - fn wait_for_interrupt():打开并等待中断 +- fn handle_user_page_fault(thread: &Arc\, addr: usize):处理用户态的缺页异常 ### interrupt/consts - fn is_page_fault(trap: usize):是否缺页 -- IrqMin:中断的最小 trap -- IrqMax:中断的最大 trap -- Syscall:系统调用的 trap -- Timer:时钟中断的 trap +- fn is_syscall(trap: usize):是否系统调用 +- fn is_intr(trap: usize):是否中断 ### interrupt/handler diff --git a/kernel/src/arch/aarch64/consts.rs b/kernel/src/arch/aarch64/consts.rs index 1eda730e..b7a65cb2 100644 --- a/kernel/src/arch/aarch64/consts.rs +++ b/kernel/src/arch/aarch64/consts.rs @@ -7,5 +7,4 @@ pub const USER_STACK_OFFSET: usize = 0x0000_8000_0000_0000 - USER_STACK_SIZE; pub const USER_STACK_SIZE: usize = 1 * 1024 * 1024; pub const KSEG2_START: usize = 0xffff_fe80_0000_0000; -#[cfg(target_arch = "aarch64")] pub const ARCH: &'static str = "aarch64"; diff --git a/kernel/src/arch/aarch64/interrupt/consts.rs b/kernel/src/arch/aarch64/interrupt/consts.rs index 02b5448d..b0362c37 100644 --- a/kernel/src/arch/aarch64/interrupt/consts.rs +++ b/kernel/src/arch/aarch64/interrupt/consts.rs @@ -28,3 +28,19 @@ pub const Timer: usize = 0x10002; // from el0, sync pub const Syscall: usize = 0x00002; + +pub fn is_syscall(trap: usize) -> bool { + trap == Syscall +} + +pub fn is_intr(trap: usize) -> bool { + IrqMin <= trap && trap <= IrqMax +} + +pub fn is_timer_intr(trap: usize) -> bool { + trap == Timer +} + +pub fn is_reserved_inst(trap: usize) -> bool { + false +} diff --git a/kernel/src/arch/aarch64/interrupt/mod.rs b/kernel/src/arch/aarch64/interrupt/mod.rs index 14a7a3af..9eb6e307 100644 --- a/kernel/src/arch/aarch64/interrupt/mod.rs +++ b/kernel/src/arch/aarch64/interrupt/mod.rs @@ -2,7 +2,9 @@ pub use self::handler::*; use crate::arch::board::timer::is_pending; +use crate::process::thread::Thread; use aarch64::regs::*; +use alloc::sync::Arc; use trapframe::UserContext; pub mod consts; @@ -68,3 +70,11 @@ pub fn wait_for_interrupt() { aarch64::asm::wfe(); DAIF.set(daif); } + +pub fn handle_user_page_fault(thread: &Arc, addr: usize) -> bool { + thread.vm.lock().handle_page_fault(addr) +} + +pub fn handle_reserved_inst(tf: &mut UserContext) -> bool { + false +} diff --git a/kernel/src/arch/mipsel/board/malta/consts.rs b/kernel/src/arch/mipsel/board/malta/consts.rs index 5df1b157..0bdc95ec 100644 --- a/kernel/src/arch/mipsel/board/malta/consts.rs +++ b/kernel/src/arch/mipsel/board/malta/consts.rs @@ -1,3 +1,3 @@ /// board specific constants -pub const MEMORY_END: usize = 0x8400_0000; +pub const MEMORY_END: usize = 0x8800_0000; pub const KERNEL_HEAP_SIZE: usize = 0x0200_0000; diff --git a/kernel/src/arch/mipsel/board/malta/device.dts b/kernel/src/arch/mipsel/board/malta/device.dts index bee60a41..3e18aea1 100644 --- a/kernel/src/arch/mipsel/board/malta/device.dts +++ b/kernel/src/arch/mipsel/board/malta/device.dts @@ -25,19 +25,11 @@ reg = <0x00000000 0x10000000>; }; - uart0: serial@b80003f8 { - compatible = "ns16550a"; - reg = <0xb80003f8 0x8>; - clock-frequency = <1843200>; - }; - uart2: serial@bf000900 { compatible = "ns16550a"; reg = <0xbf000900 0x40>; reg-shift = <3>; clock-frequency = <1843200>; - /* The CBUS UART is attached to the MIPS CPU INT2 pin, ie interrupt 4 */ - interrupt-parent = <&cpu_intc>; interrupts = <4>; }; diff --git a/kernel/src/arch/mipsel/board/malta/mod.rs b/kernel/src/arch/mipsel/board/malta/mod.rs index bb929912..a160814c 100644 --- a/kernel/src/arch/mipsel/board/malta/mod.rs +++ b/kernel/src/arch/mipsel/board/malta/mod.rs @@ -1,10 +1,10 @@ +use crate::drivers::block::ide; use crate::drivers::bus::pci; use crate::drivers::gpu::fb::{self, FramebufferInfo}; +use crate::drivers::*; use mips::registers::cp0; pub mod consts; -#[path = "../../../../drivers/serial/ti_16c550c.rs"] -pub mod serial; #[path = "../../../../drivers/gpu/qemu_stdvga.rs"] pub mod vga; @@ -12,19 +12,18 @@ pub mod vga; pub static DTB: &'static [u8] = include_bytes!("device.dtb"); /// Initialize serial port first -pub fn init_serial_early() { - // initialize serial driver - serial::init(0xbf000900); +pub fn early_init() { // Enable serial interrupt let mut status = cp0::status::read(); status.enable_hard_int2(); cp0::status::write(status); - println!("Hello QEMU Malta!"); + info!("Hello QEMU Malta!"); } /// Initialize other board drivers -pub fn init_driver() { +pub fn init(dtb: usize) { // TODO: add possibly more drivers + serial::uart16550::driver_init(); vga::init(0xbbe00000, 0xb2050000, 800, 600); pci::init(); @@ -42,4 +41,6 @@ pub fn init_driver() { screen_size: 800 * 600, }; fb::init(fb_info); + ide::init(); + device_tree::init(dtb); } diff --git a/kernel/src/arch/mipsel/board/mipssim/consts.rs b/kernel/src/arch/mipsel/board/mipssim/consts.rs deleted file mode 100644 index 73ff9665..00000000 --- a/kernel/src/arch/mipsel/board/mipssim/consts.rs +++ /dev/null @@ -1,3 +0,0 @@ -/// board specific constants -pub const MEMORY_END: usize = 0x8800_0000; -pub const KERNEL_HEAP_SIZE: usize = 0x00a0_0000; diff --git a/kernel/src/arch/mipsel/board/mipssim/device.dts b/kernel/src/arch/mipsel/board/mipssim/device.dts deleted file mode 100644 index 2e99f7bb..00000000 --- a/kernel/src/arch/mipsel/board/mipssim/device.dts +++ /dev/null @@ -1,36 +0,0 @@ -/dts-v1/; - - -/ { - model = "qemu mipssim"; - compatible = "qemu,mipssim"; - #address-cells = <1>; - #size-cells = <1>; - - chosen { - stdio = &uart0; - }; - - aliases { }; - - cpu_intc: interrupt-controller { - compatible = "mti,cpu-interrupt-controller"; - interrupt-controller; - #interrupt-cells = <1>; - }; - - main_memory: memory@0 { - device_type = "memory"; - reg = <0x00000000 0x10000000>; - }; - - uart0: serial@bfd003f8 { - compatible = "ns16550a"; - reg = <0xbfd003f8 0x8>; - clock-frequency = <1843200>; - /* attached to the MIPS CPU INT2 pin, ie interrupt 4 */ - interrupt-parent = <&cpu_intc>; - interrupts = <4>; - }; - -}; diff --git a/kernel/src/arch/mipsel/board/mipssim/mod.rs b/kernel/src/arch/mipsel/board/mipssim/mod.rs deleted file mode 100644 index f5cefeda..00000000 --- a/kernel/src/arch/mipsel/board/mipssim/mod.rs +++ /dev/null @@ -1,18 +0,0 @@ -pub mod consts; -#[path = "../../../../drivers/serial/uart16550.rs"] -pub mod serial; - -/// Device tree bytes -pub static DTB: &'static [u8] = include_bytes!("device.dtb"); - -/// Initialize serial port first -pub fn init_serial_early() { - serial::init(0xbfd003f8); - println!("Hello QEMU MIPSSIM!"); -} - -/// Initialize other board drivers -pub fn init_driver() { - // TODO: add possibly more drivers - // timer::init(); -} diff --git a/kernel/src/arch/mipsel/boot/context.S b/kernel/src/arch/mipsel/boot/context.S deleted file mode 100644 index 5854e851..00000000 --- a/kernel/src/arch/mipsel/boot/context.S +++ /dev/null @@ -1,67 +0,0 @@ -#include "regdef.h" - -.set noat -.set noreorder - -.section .text.context -.globl switch_context -.extern _root_page_table_ptr -.extern _cur_kstack_ptr -.extern _cur_tls - -switch_context: - // save from's registers - addi sp, sp, (-4*16) - sw sp, 0(a0) - sw ra, 0(sp) - sw s0, 4*4(sp) - sw s1, 5*4(sp) - sw s2, 6*4(sp) - sw s3, 7*4(sp) - sw s4, 8*4(sp) - sw s5, 9*4(sp) - sw s6, 10*4(sp) - sw s7, 11*4(sp) - sw s8, 12*4(sp) - sw gp, 13*4(sp) - // sw ra, 12*4(sp) - // sw sp, 13*4(sp) - - // save page table address - la s0, _root_page_table_ptr - lw s1, 0(s0) - sw s1, 4(sp) - - // save TLS - la s2, _cur_tls - lw s1, 0(s2) - sw s1, 2*4(sp) - - // restore to's registers - lw sp, 0(a1) - - // restore page table address - lw s1, 4(sp) - sw s1, 0(s0) - - // restore TLS - lw s1, 2*4(sp) - sw s1, 0(s2) - mtc0 s1, $4, 2 // cp0.user_local - - lw ra, 0(sp) - lw s0, 4*4(sp) - lw s1, 5*4(sp) - lw s2, 6*4(sp) - lw s3, 7*4(sp) - lw s4, 8*4(sp) - lw s5, 9*4(sp) - lw s6, 10*4(sp) - lw s7, 11*4(sp) - lw s8, 12*4(sp) - lw gp, 13*4(sp) - addi sp, sp, (4*16) - - sw zero, 0(a1) - jr ra - nop diff --git a/kernel/src/arch/mipsel/boot/entry.S b/kernel/src/arch/mipsel/boot/entry.S index e72c353b..0297aa11 100644 --- a/kernel/src/arch/mipsel/boot/entry.S +++ b/kernel/src/arch/mipsel/boot/entry.S @@ -38,3 +38,14 @@ bootstack: .space 4096 * 16 * 8 .global bootstacktop bootstacktop: + + .align 12 #PGSHIFT + .global _root_page_table_buffer +_root_page_table_buffer: + .space 1024 * 64 # 64KB + .global _root_page_table_ptr +_root_page_table_ptr: + .space 4 # 4bytes + .global _cur_tls +_cur_tls: + .space 4 # 4bytes diff --git a/kernel/src/arch/mipsel/boot/trap.S b/kernel/src/arch/mipsel/boot/trap.S deleted file mode 100644 index 49b16e95..00000000 --- a/kernel/src/arch/mipsel/boot/trap.S +++ /dev/null @@ -1,199 +0,0 @@ -#include "regdef.h" - - .set noat - .set noreorder - .section .text.ebase - .globl trap_entry - -.org 0x0 -trap_entry: -# +0x000: TLB-miss vector - b general_trap_vec - -# +0x180: general vector -.org 0x180 -general_trap_vec: - move k1, sp # save stack pointer to k1 - mfc0 k0, $12 # read cp0.status - andi k0, k0, 0x10 # extract cp0.status.ksu - beq k0, zero, trap_from_kernel - nop # delayslot - -trap_from_user: - # load kstack, we can use k0 to store something -# la k0, kernel_stack -# la sp, kernel_stack_top - la k0, _cur_kstack_ptr - lw sp, 0(k0) - -trap_from_kernel: - /* - * k0 is damaged - * k1 = old stack pointer - * sp = kernel stack */ - -#define TRAPFRAME_SIZE 176 - - # align stack pointer - andi k0, sp, 0xf - beqz k0, sp_aligned - nop - - la k0, 0xfffffff0 - and k0, sp, k0 - sw sp, -TRAPFRAME_SIZE(k0) - move sp, k0 - -sp_aligned: - # allocate 38 / 70 words for trapframe + 6 extra words - - addiu sp, sp, -TRAPFRAME_SIZE - - # save general registers - sw ra, 160(sp) - sw fp, 156(sp) - sw k1, 152(sp) # k1 = old sp - sw gp, 148(sp) - sw k1, 144(sp) # real k1 is damaged - sw k0, 140(sp) # real k0 is damaged - sw t9, 136(sp) - sw t8, 132(sp) - sw s7, 128(sp) - sw s6, 124(sp) - sw s5, 120(sp) - sw s4, 116(sp) - sw s3, 112(sp) - sw s2, 108(sp) - sw s1, 104(sp) - sw s0, 100(sp) - sw t7, 96(sp) - sw t6, 92(sp) - sw t5, 88(sp) - sw t4, 84(sp) - sw t3, 80(sp) - sw t2, 76(sp) - sw t1, 72(sp) - sw t0, 68(sp) - sw a3, 64(sp) - sw a2, 60(sp) - sw a1, 56(sp) - sw a0, 52(sp) - sw v1, 48(sp) - sw v0, 44(sp) - sw AT, 40(sp) - nop - - # save hi/lo - mflo t1 - sw t1, 36(sp) - mfhi t0 - sw t0, 32(sp) - - # save special registers - mfc0 t0, $8 # cp0.vaddr - sw t0, 28(sp) - - mfc0 t1, $14 # cp0.epc - sw t1, 24(sp) - - mfc0 t0, $13 # cp0.cause - sw t0, 20(sp) - - mfc0 t1, $12 # cp0.status - sw t1, 16(sp) - - # support nested interrupt - la t0, ~0x1b # reset status.ksu, status.exl, status.ie - and t1, t1, t0 - mtc0 t1, $12 # cp0.status - - # prepare to call rust_trap - ori a0, sp, 0 /* set argument (trapframe) */ - jal rust_trap - nop - - .globl trap_return -trap_return: - # restore special registers - lw t1, 16(sp) - ori t1, t1, 0x2 # status.exl - nop - mtc0 t1, $12 # cp0.status - - lw k0, 24(sp) - mtc0 k0, $14 # cp0.epc - - lw t0, 32(sp) - mthi t0 - lw t1, 36(sp) - mtlo t1 - - # restore general registers - lw AT, 40(sp) - lw v0, 44(sp) - lw v1, 48(sp) - lw a0, 52(sp) - lw a1, 56(sp) - lw a2, 60(sp) - lw a3, 64(sp) - lw t0, 68(sp) - lw t1, 72(sp) - lw t2, 76(sp) - lw t3, 80(sp) - lw t4, 84(sp) - lw t5, 88(sp) - lw t6, 92(sp) - lw t7, 96(sp) - lw s0, 100(sp) - lw s1, 104(sp) - lw s2, 108(sp) - lw s3, 112(sp) - lw s4, 116(sp) - lw s5, 120(sp) - lw s6, 124(sp) - lw s7, 128(sp) - lw t8, 132(sp) - lw t9, 136(sp) - - # lw k0, 140(sp) - # lw k1, 144(sp) - lw gp, 148(sp) - lw fp, 156(sp) - lw ra, 160(sp) - - # save kernel stack - lw k0, 0(sp) - addiu k1, sp, TRAPFRAME_SIZE - movn k1, k0, k0 - - la k0, _cur_kstack_ptr - sw k1, 0(k0) - nop - - // restore stack - lw sp, 152(sp) - - eret - nop - - .section .bss.stack - .align 12 #PGSHIFT - .global kernel_stack -kernel_stack: - .space 1024 * 16 # 16KB for kernel stack - .global kernel_stack_top -kernel_stack_top: - - .align 12 #PGSHIFT - .global _root_page_table_buffer -_root_page_table_buffer: - .space 1024 * 64 # 64KB - .global _root_page_table_ptr -_root_page_table_ptr: - .space 4 # 4bytes - .global _cur_kstack_ptr -_cur_kstack_ptr: - .space 4 # 4bytes - .global _cur_tls -_cur_tls: - .space 4 # 4bytes diff --git a/kernel/src/arch/mipsel/consts.rs b/kernel/src/arch/mipsel/consts.rs index cc44ed4c..6b248409 100644 --- a/kernel/src/arch/mipsel/consts.rs +++ b/kernel/src/arch/mipsel/consts.rs @@ -14,3 +14,5 @@ pub const USER_STACK_SIZE: usize = 0x10000; pub const MAX_DTB_SIZE: usize = 0x2000; pub const KSEG2_START: usize = 0xfe80_0000; + +pub const ARCH: &'static str = "mipsel"; diff --git a/kernel/src/arch/mipsel/context.rs b/kernel/src/arch/mipsel/context.rs deleted file mode 100644 index 92ae8b6a..00000000 --- a/kernel/src/arch/mipsel/context.rs +++ /dev/null @@ -1,340 +0,0 @@ -use mips::registers::cp0; -use mips::tlb::TLBEntry; - -/// Saved registers on a trap. -#[derive(Clone)] -#[repr(C)] -pub struct TrapFrame { - /// Non-zero if the kernel stack is not 16-byte-aligned - pub unaligned_kstack: usize, - /// unused 12 bytes - pub unused: [usize; 3], - /// CP0 status register - pub status: cp0::status::Status, - /// CP0 cause register - pub cause: cp0::cause::Cause, - /// CP0 EPC register - pub epc: usize, - /// CP0 vaddr register - pub vaddr: usize, - /// HI/LO registers - pub hi: usize, - pub lo: usize, - /// General registers - pub at: usize, - pub v0: usize, - pub v1: usize, - pub a0: usize, - pub a1: usize, - pub a2: usize, - pub a3: usize, - pub t0: usize, - pub t1: usize, - pub t2: usize, - pub t3: usize, - pub t4: usize, - pub t5: usize, - pub t6: usize, - pub t7: usize, - pub s0: usize, - pub s1: usize, - pub s2: usize, - pub s3: usize, - pub s4: usize, - pub s5: usize, - pub s6: usize, - pub s7: usize, - pub t8: usize, - pub t9: usize, - pub k0: usize, - pub k1: usize, - pub gp: usize, - pub sp: usize, - pub fp: usize, - pub ra: usize, - /// Floating-point registers (contains garbage if no FP support present) - pub f0: usize, - pub f1: usize, - pub f2: usize, - pub f3: usize, - pub f4: usize, - pub f5: usize, - pub f6: usize, - pub f7: usize, - pub f8: usize, - pub f9: usize, - pub f10: usize, - pub f11: usize, - pub f12: usize, - pub f13: usize, - pub f14: usize, - pub f15: usize, - pub f16: usize, - pub f17: usize, - pub f18: usize, - pub f19: usize, - pub f20: usize, - pub f21: usize, - pub f22: usize, - pub f23: usize, - pub f24: usize, - pub f25: usize, - pub f26: usize, - pub f27: usize, - pub f28: usize, - pub f29: usize, - pub f30: usize, - pub f31: usize, - /// Reserved - pub reserved: usize, - pub __padding: [usize; 2], -} - -impl TrapFrame { - /// Constructs TrapFrame for a new kernel thread. - /// - /// The new thread starts at function `entry` with an usize argument `arg`. - /// The stack pointer will be set to `sp`. - fn new_kernel_thread(entry: extern "C" fn(usize) -> !, arg: usize, sp: usize) -> Self { - use core::mem::zeroed; - let mut tf: Self = unsafe { zeroed() }; - tf.a0 = arg; - tf.sp = sp; - tf.epc = entry as usize; - tf.status = cp0::status::read(); - tf.status.set_kernel_mode(); - tf.status.set_ie(); - tf.status.set_exl(); - tf - } - - /// Constructs TrapFrame for a new user thread. - /// - /// The new thread starts at `entry_addr`. - /// The stack pointer will be set to `sp`. - pub fn new_user_thread(entry_addr: usize, sp: usize) -> Self { - use core::mem::zeroed; - let mut tf: Self = unsafe { zeroed() }; - tf.sp = sp; - tf.epc = entry_addr; - tf.status = cp0::status::read(); - tf.status.set_user_mode(); - tf.status.set_ie(); - tf.status.set_exl(); - tf - } -} - -use core::fmt::{Debug, Error, Formatter}; -impl Debug for TrapFrame { - fn fmt(&self, f: &mut Formatter) -> Result<(), Error> { - f.debug_struct("TrapFrame") - .field("status", &self.status.bits) - .field("epc", &self.epc) - .field("cause", &self.cause.bits) - .field("vaddr", &self.vaddr) - .field("at", &self.at) - .field("v0", &self.v0) - .field("v1", &self.v1) - .field("a0", &self.a0) - .field("a1", &self.a1) - .field("a2", &self.a2) - .field("a3", &self.a3) - .field("t0", &self.t0) - .field("t1", &self.t1) - .field("t2", &self.t2) - .field("t3", &self.t3) - .field("t4", &self.t4) - .field("t5", &self.t5) - .field("t6", &self.t6) - .field("t7", &self.t7) - .field("s0", &self.s0) - .field("s1", &self.s1) - .field("s2", &self.s2) - .field("s3", &self.s3) - .field("s4", &self.s4) - .field("s5", &self.s5) - .field("s6", &self.s6) - .field("s7", &self.s7) - .field("t8", &self.t8) - .field("t9", &self.t9) - .field("k0", &self.k0) - .field("k1", &self.k1) - .field("gp", &self.gp) - .field("sp", &self.sp) - .field("fp", &self.fp) - .field("ra", &self.ra) - .finish() - } -} - -/// Kernel stack contents for a new thread -#[derive(Debug)] -#[repr(C)] -pub struct InitStack { - context: ContextData, - tf: TrapFrame, -} - -impl InitStack { - /// Push the InitStack on the stack and transfer to a Context. - unsafe fn push_at(self, stack_top: usize) -> Context { - let ptr = (stack_top as *mut Self).sub(1); //real kernel stack top - *ptr = self; - Context { sp: ptr as usize } - } -} - -extern "C" { - fn trap_return(); - fn _cur_tls(); -} - -/// Saved registers for kernel context switches. -#[derive(Debug, Default)] -#[repr(C)] -struct ContextData { - /// Return address - ra: usize, - /// Page table token - satp: usize, - /// s[0] = TLS - /// s[1] = reserved - /// s[2..11] = Callee-saved registers - s: [usize; 12], - __padding: [usize; 2], -} - -impl ContextData { - fn new(satp: usize, tls: usize) -> Self { - let mut context = ContextData { - ra: trap_return as usize, - satp: satp, - ..ContextData::default() - }; - context.s[0] = tls; - context - } -} - -/// Context of a kernel thread. -#[derive(Debug)] -#[repr(C)] -pub struct Context { - /// The stack pointer of the suspended thread. - /// A `ContextData` is stored here. - sp: usize, -} - -impl Context { - /// Switch to another kernel thread. - /// - /// Push all callee-saved registers at the current kernel stack. - /// Store current sp, switch to target. - /// Pop all callee-saved registers, then return to the target. - #[inline(always)] - pub unsafe fn switch(&mut self, target: &mut Self) { - extern "C" { - fn switch_context(src: *mut Context, dst: *mut Context); - } - - TLBEntry::clear_all(); - switch_context(self as *mut Context, target as *mut Context); - } - - /// Constructs a null Context for the current running thread. - pub unsafe fn null() -> Self { - Context { sp: 0 } - } - - /// Constructs Context for a new kernel thread. - /// - /// The new thread starts at function `entry` with an usize argument `arg`. - /// The stack pointer will be set to `kstack_top`. - /// The SATP register will be set to `satp`. - pub unsafe fn new_kernel_thread( - entry: extern "C" fn(usize) -> !, - arg: usize, - kstack_top: usize, - satp: usize, - ) -> Self { - info!( - "New kernel thread @ {:x}, stack = {:x}", - entry as usize, kstack_top - ); - - InitStack { - context: ContextData::new(satp, 0), - tf: TrapFrame::new_kernel_thread(entry, arg, kstack_top), - } - .push_at(kstack_top) - } - - /// Constructs Context for a new user thread. - /// - /// The new thread starts at `entry_addr`. - /// The stack pointer of user and kernel mode will be set to `ustack_top`, `kstack_top`. - /// The SATP register will be set to `satp`. - pub unsafe fn new_user_thread( - entry_addr: usize, - ustack_top: usize, - kstack_top: usize, - satp: usize, - ) -> Self { - info!( - "New user thread @ {:x}, stack = {:x}", - entry_addr, kstack_top - ); - - InitStack { - context: ContextData::new(satp, 0), - tf: TrapFrame::new_user_thread(entry_addr, ustack_top), - } - .push_at(kstack_top) - } - - /// Fork a user process and get the new Context. - /// - /// The stack pointer in kernel mode will be set to `kstack_top`. - /// The SATP register will be set to `satp`. - /// All the other registers are same as the original. - pub unsafe fn new_fork(tf: &TrapFrame, kstack_top: usize, satp: usize) -> Self { - let tls = *(_cur_tls as *const usize); - InitStack { - context: ContextData::new(satp, tls), - tf: { - let mut tf = tf.clone(); - // fork function's ret value, the new process is 0 - tf.v0 = 0; - tf - }, - } - .push_at(kstack_top) - } - - /// Fork a user thread and get the new Context. - /// - /// The stack pointer in kernel mode will be set to `kstack_top`. - /// The SATP register will be set to `satp`. - /// The new user stack will be set to `ustack_top`. - /// The new thread pointer will be set to `tls`. - /// All the other registers are same as the original. - pub unsafe fn new_clone( - tf: &TrapFrame, - ustack_top: usize, - kstack_top: usize, - satp: usize, - tls: usize, - ) -> Self { - InitStack { - context: ContextData::new(satp, tls), - tf: { - let mut tf = tf.clone(); - tf.sp = ustack_top; // sp - tf.v0 = 0; // return value - tf - }, - } - .push_at(kstack_top) - } -} diff --git a/kernel/src/arch/mipsel/driver/mod.rs b/kernel/src/arch/mipsel/driver/mod.rs deleted file mode 100644 index b4cbd5de..00000000 --- a/kernel/src/arch/mipsel/driver/mod.rs +++ /dev/null @@ -1,11 +0,0 @@ -//! mipsel drivers - -use super::board; - -pub use self::board::serial; - -/// Initialize common drivers -pub fn init() { - board::init_driver(); - crate::drivers::console::init(); -} diff --git a/kernel/src/arch/mipsel/fp.rs b/kernel/src/arch/mipsel/fp.rs new file mode 100644 index 00000000..36c91cbe --- /dev/null +++ b/kernel/src/arch/mipsel/fp.rs @@ -0,0 +1,14 @@ +//! SPDX-License-Identifier: (Apache-2.0 OR MIT) + +#[derive(Debug, Copy, Clone, Default)] +pub struct FpState {} + +impl FpState { + pub fn new() -> Self { + Self { ..Self::default() } + } + + pub fn save(&mut self) {} + + pub fn restore(&self) {} +} diff --git a/kernel/src/arch/mipsel/interrupt/consts.rs b/kernel/src/arch/mipsel/interrupt/consts.rs new file mode 100644 index 00000000..cb6d551a --- /dev/null +++ b/kernel/src/arch/mipsel/interrupt/consts.rs @@ -0,0 +1,46 @@ +use mips::registers::cp0; + +pub fn is_page_fault(trap: usize) -> bool { + use cp0::cause::Exception as E; + let cause = cp0::cause::Cause { bits: trap as u32 }; + match cause.cause() { + E::TLBModification | E::TLBLoadMiss | E::TLBStoreMiss => true, + _ => false, + } +} + +pub fn is_syscall(trap: usize) -> bool { + use cp0::cause::Exception as E; + let cause = cp0::cause::Cause { bits: trap as u32 }; + match cause.cause() { + E::Syscall => true, + _ => false, + } +} + +pub fn is_intr(trap: usize) -> bool { + use cp0::cause::Exception as E; + let cause = cp0::cause::Cause { bits: trap as u32 }; + match cause.cause() { + E::Interrupt => true, + _ => false, + } +} + +pub fn is_timer_intr(trap: usize) -> bool { + use cp0::cause::Exception as E; + let cause = cp0::cause::Cause { bits: trap as u32 }; + match cause.cause() { + E::Interrupt => trap & (1 << 30) != 0, + _ => false, + } +} + +pub fn is_reserved_inst(trap: usize) -> bool { + use cp0::cause::Exception as E; + let cause = cp0::cause::Cause { bits: trap as u32 }; + match cause.cause() { + E::ReservedInstruction => true, + _ => false, + } +} diff --git a/kernel/src/arch/mipsel/interrupt.rs b/kernel/src/arch/mipsel/interrupt/mod.rs similarity index 54% rename from kernel/src/arch/mipsel/interrupt.rs rename to kernel/src/arch/mipsel/interrupt/mod.rs index d2ef184d..6b845f49 100644 --- a/kernel/src/arch/mipsel/interrupt.rs +++ b/kernel/src/arch/mipsel/interrupt/mod.rs @@ -1,23 +1,21 @@ -pub use self::context::*; use crate::arch::paging::get_root_page_table_ptr; use crate::drivers::IRQ_MANAGER; +use crate::process::thread::Thread; +use alloc::sync::Arc; use log::*; use mips::addr::*; use mips::interrupts; use mips::paging::PageTable as MIPSPageTable; use mips::registers::cp0; +use trapframe::{TrapFrame, UserContext}; -#[path = "context.rs"] -mod context; +pub mod consts; /// Initialize interrupt pub fn init() { - extern "C" { - fn trap_entry(); + unsafe { + trapframe::init(); } - // Set the exception vector address - cp0::ebase::write_u32(trap_entry as u32); - println!("Set ebase = {:x}", trap_entry as u32); let mut status = cp0::status::read(); // Enable IPI @@ -61,145 +59,121 @@ pub extern "C" fn stack_pointer_not_aligned(sp: usize) { /// /// This function is called from `trap.asm`. #[no_mangle] -pub extern "C" fn rust_trap(tf: &mut TrapFrame) { +pub extern "C" fn trap_handler(tf: &mut TrapFrame) { use cp0::cause::Exception as E; - trace!("Exception @ CPU{}: {:?} ", 0, tf.cause.cause()); - match tf.cause.cause() { + let cause = cp0::cause::Cause { + bits: tf.cause as u32, + }; + trace!("Exception @ CPU{}: {:?} ", 0, cause.cause()); + match cause.cause() { E::Interrupt => interrupt_dispatcher(tf), E::Syscall => syscall(tf), E::TLBModification => page_fault(tf), E::TLBLoadMiss => page_fault(tf), E::TLBStoreMiss => page_fault(tf), - E::ReservedInstruction => { - if !reserved_inst(tf) { - error!("Unhandled Exception @ CPU{}: {:?} ", 0, tf.cause.cause()); - crate::trap::error(tf) - } else { - tf.epc = tf.epc + 4; - } - } - E::CoprocessorUnusable => { - tf.epc = tf.epc + 4; - } _ => { - error!("Unhandled Exception @ CPU{}: {:?} ", 0, tf.cause.cause()); - crate::trap::error(tf) + error!("Unhandled Exception @ CPU{}: {:?} ", 0, cause.cause()); } } trace!("Interrupt end"); } fn interrupt_dispatcher(tf: &mut TrapFrame) { - let pint = tf.cause.pending_interrupt(); + let cause = cp0::cause::Cause { + bits: tf.cause as u32, + }; + let pint = cause.pending_interrupt(); trace!(" Interrupt {:08b} ", pint); if (pint & 0b100_000_00) != 0 { timer(); } else if (pint & 0b011_111_00) != 0 { - external(); + for i in 0..6 { + if (pint & (1 << i)) != 0 { + IRQ_MANAGER.read().try_handle_interrupt(Some(i)); + } + } } else { ipi(); } } -fn external() { - // true means handled, false otherwise - let handlers = [try_process_serial, try_process_drivers]; - for handler in handlers.iter() { - if handler() == true { - break; - } - } -} - -fn try_process_serial() -> bool { - match super::io::getchar_option() { - Some(ch) => { - trace!("Get char {} from serial", ch); - crate::trap::serial(ch); - true - } - None => false, - } -} - -fn try_process_drivers() -> bool { - IRQ_MANAGER.read().try_handle_interrupt(None) -} - fn ipi() { debug!("IPI"); cp0::cause::reset_soft_int0(); cp0::cause::reset_soft_int1(); } -fn timer() { +pub fn timer() { super::timer::set_next(); crate::trap::timer(); } fn syscall(tf: &mut TrapFrame) { tf.epc += 4; // Must before syscall, because of fork. - let arguments = [tf.a0, tf.a1, tf.a2, tf.a3, tf.t0, tf.t1]; - trace!( - "MIPS syscall {} invoked with {:x?}, epc = {:x?}", - tf.v0, - arguments, - tf.epc - ); + /* + let arguments = [tf.a0, tf.a1, tf.a2, tf.a3, tf.t0, tf.t1]; + trace!( + "MIPS syscall {} invoked with {:x?}, epc = {:x?}", + tf.v0, + arguments, + tf.epc + ); + */ - let ret = crate::syscall::syscall(tf.v0, arguments, tf) as isize; + //let ret = crate::syscall::syscall(tf.v0, arguments, tf) as isize; + let ret = 0 as isize; // comply with mips n32 abi, always return a positive value // https://git.musl-libc.org/cgit/musl/tree/arch/mipsn32/syscall_arch.h if ret < 0 { - tf.v0 = (-ret) as usize; - tf.a3 = 1; + tf.general.v0 = (-ret) as usize; + tf.general.a3 = 1; } else { - tf.v0 = ret as usize; - tf.a3 = 0; + tf.general.v0 = ret as usize; + tf.general.a3 = 0; } } -fn set_trapframe_register(rt: usize, val: usize, tf: &mut TrapFrame) { +fn set_trapframe_register(rt: usize, val: usize, tf: &mut UserContext) { match rt { - 1 => tf.at = val, - 2 => tf.v0 = val, - 3 => tf.v1 = val, - 4 => tf.a0 = val, - 5 => tf.a1 = val, - 6 => tf.a2 = val, - 7 => tf.a3 = val, - 8 => tf.t0 = val, - 9 => tf.t1 = val, - 10 => tf.t2 = val, - 11 => tf.t3 = val, - 12 => tf.t4 = val, - 13 => tf.t5 = val, - 14 => tf.t6 = val, - 15 => tf.t7 = val, - 16 => tf.s0 = val, - 17 => tf.s1 = val, - 18 => tf.s2 = val, - 19 => tf.s3 = val, - 20 => tf.s4 = val, - 21 => tf.s5 = val, - 22 => tf.s6 = val, - 23 => tf.s7 = val, - 24 => tf.t8 = val, - 25 => tf.t9 = val, - 26 => tf.k0 = val, - 27 => tf.k1 = val, - 28 => tf.gp = val, - 29 => tf.sp = val, - 30 => tf.fp = val, - 31 => tf.ra = val, + 1 => tf.general.at = val, + 2 => tf.general.v0 = val, + 3 => tf.general.v1 = val, + 4 => tf.general.a0 = val, + 5 => tf.general.a1 = val, + 6 => tf.general.a2 = val, + 7 => tf.general.a3 = val, + 8 => tf.general.t0 = val, + 9 => tf.general.t1 = val, + 10 => tf.general.t2 = val, + 11 => tf.general.t3 = val, + 12 => tf.general.t4 = val, + 13 => tf.general.t5 = val, + 14 => tf.general.t6 = val, + 15 => tf.general.t7 = val, + 16 => tf.general.s0 = val, + 17 => tf.general.s1 = val, + 18 => tf.general.s2 = val, + 19 => tf.general.s3 = val, + 20 => tf.general.s4 = val, + 21 => tf.general.s5 = val, + 22 => tf.general.s6 = val, + 23 => tf.general.s7 = val, + 24 => tf.general.t8 = val, + 25 => tf.general.t9 = val, + 26 => tf.general.k0 = val, + 27 => tf.general.k1 = val, + 28 => tf.general.gp = val, + 29 => tf.general.sp = val, + 30 => tf.general.fp = val, + 31 => tf.general.ra = val, _ => { error!("Unknown register {:?} ", rt); - crate::trap::error(tf) + //crate::trap::error(tf) } } } -fn reserved_inst(tf: &mut TrapFrame) -> bool { +pub fn handle_reserved_inst(tf: &mut UserContext) -> bool { let inst = unsafe { *(tf.epc as *const usize) }; let opcode = inst >> 26; @@ -210,20 +184,18 @@ fn reserved_inst(tf: &mut TrapFrame) -> bool { if inst == 0x42000020 { // ignore WAIT + tf.epc = tf.epc + 4; return true; } if opcode == 0b011111 && format == 0b111011 { - // RDHWR + // RDHWR UserLocal if rd == 29 && sel == 0 { - extern "C" { - fn _cur_tls(); - } - - let tls = unsafe { *(_cur_tls as *const usize) }; + let tls = tf.tls; set_trapframe_register(rt, tls, tf); - debug!("Read TLS by rdhdr {:x} to register {:?}", tls, rt); + trace!("Read TLS by rdhwr {:x} to register {:?}", tls, rt); + tf.epc = tf.epc + 4; return true; } else { return false; @@ -233,10 +205,43 @@ fn reserved_inst(tf: &mut TrapFrame) -> bool { false } +pub fn handle_user_page_fault(thread: &Arc, addr: usize) -> bool { + let virt_addr = VirtAddr::new(addr); + let root_table = unsafe { &mut *(get_root_page_table_ptr() as *mut MIPSPageTable) }; + let tlb_result = root_table.lookup(addr); + match tlb_result { + Ok(tlb_entry) => { + trace!( + "PhysAddr = {:x}/{:x}", + tlb_entry.entry_lo0.get_pfn() << 12, + tlb_entry.entry_lo1.get_pfn() << 12 + ); + + let tlb_valid = if virt_addr.page_number() & 1 == 0 { + tlb_entry.entry_lo0.valid() + } else { + tlb_entry.entry_lo1.valid() + }; + + if !tlb_valid { + if !thread.vm.lock().handle_page_fault(addr) { + return false; + } + } + + tlb_entry.write_random(); + true + } + Err(()) => { + return thread.vm.lock().handle_page_fault(addr); + } + } +} + fn page_fault(tf: &mut TrapFrame) { // TODO: set access/dirty bit let addr = tf.vaddr; - trace!("\nEXCEPTION: Page Fault @ {:#x}", addr); + // info!("\nEXCEPTION: Page Fault @ {:#x}", addr); let virt_addr = VirtAddr::new(addr); let root_table = unsafe { &mut *(get_root_page_table_ptr() as *mut MIPSPageTable) }; @@ -266,7 +271,7 @@ fn page_fault(tf: &mut TrapFrame) { tf.epc = crate::memory::read_user_fixup as usize; return; } - crate::trap::error(tf); + //crate::trap::error(tf); } } @@ -283,8 +288,25 @@ fn page_fault(tf: &mut TrapFrame) { tf.epc = crate::memory::read_user_fixup as usize; return; } - crate::trap::error(tf); + //crate::trap::error(tf); } } } } + +pub fn enable_irq(irq: usize) { + // TODO +} + +pub fn get_trap_num(cx: &UserContext) -> usize { + cx.cause +} + +pub fn ack(_irq: usize) { + // TODO +} + +pub fn wait_for_interrupt() { + cp0::status::enable_interrupt(); + cp0::status::disable_interrupt(); +} diff --git a/kernel/src/arch/mipsel/io.rs b/kernel/src/arch/mipsel/io.rs index 30777d26..93cbc741 100644 --- a/kernel/src/arch/mipsel/io.rs +++ b/kernel/src/arch/mipsel/io.rs @@ -1,22 +1,14 @@ //! Input/output for mipsel. -use super::driver::serial::*; -use crate::drivers::console::CONSOLE; +use crate::drivers::{console::CONSOLE, SERIAL_DRIVERS}; use core::fmt::{Arguments, Write}; -pub fn getchar() -> u8 { - unsafe { SERIAL_PORT.force_unlock() } - SERIAL_PORT.lock().getchar() -} - -pub fn getchar_option() -> Option { - unsafe { SERIAL_PORT.force_unlock() } - SERIAL_PORT.lock().getchar_option() -} - pub fn putfmt(fmt: Arguments) { - unsafe { SERIAL_PORT.force_unlock() } - SERIAL_PORT.lock().write_fmt(fmt).unwrap(); + // output to serial + let mut drivers = SERIAL_DRIVERS.write(); + if let Some(serial) = drivers.first_mut() { + serial.write(format!("{}", fmt).as_bytes()); + } unsafe { CONSOLE.force_unlock() } if let Some(console) = CONSOLE.lock().as_mut() { diff --git a/kernel/src/arch/mipsel/memory.rs b/kernel/src/arch/mipsel/memory.rs index bd066441..db419410 100644 --- a/kernel/src/arch/mipsel/memory.rs +++ b/kernel/src/arch/mipsel/memory.rs @@ -1,6 +1,7 @@ use crate::arch::paging::*; use crate::consts::{KERNEL_OFFSET, MEMORY_END, MEMORY_OFFSET}; use crate::memory::{init_heap, FRAME_ALLOCATOR}; +use mips::registers::cp0; use rcore_memory::PAGE_SIZE; /// Initialize the memory management module @@ -9,13 +10,12 @@ pub fn init() { init_frame_allocator(); init_heap(); + // for debugging set_root_page_table_ptr(0xFFFF_FFFF); extern "C" { fn _root_page_table_buffer(); fn _root_page_table_ptr(); } - - println!("_root_page_table_ptr {:x}", _root_page_table_ptr as usize); } pub fn init_other() { @@ -37,6 +37,7 @@ fn init_frame_allocator() { /// Transform memory area `[start, end)` to integer range for `FrameAllocator` fn to_range(start: usize, end: usize) -> Range { + info!("frame allocator: start {:#x} end {:#x}", start, end); let page_start = (start - MEMORY_OFFSET) / PAGE_SIZE; let page_end = (end - MEMORY_OFFSET - 1) / PAGE_SIZE + 1; assert!(page_start < page_end, "illegal range for frame allocator"); @@ -69,3 +70,13 @@ extern "C" { fn bootstack(); fn bootstacktop(); } + +pub fn set_page_table(vmtoken: usize) { + if get_root_page_table_ptr() != vmtoken { + set_root_page_table_ptr(vmtoken); + } +} + +pub fn get_page_fault_addr() -> usize { + cp0::bad_vaddr::read_u32() as usize +} diff --git a/kernel/src/arch/mipsel/mod.rs b/kernel/src/arch/mipsel/mod.rs index d0f581bd..b388627e 100644 --- a/kernel/src/arch/mipsel/mod.rs +++ b/kernel/src/arch/mipsel/mod.rs @@ -1,11 +1,12 @@ pub mod consts; pub mod cpu; -pub mod driver; +pub mod fp; pub mod interrupt; pub mod io; pub mod memory; pub mod paging; pub mod rand; +pub mod signal; pub mod syscall; pub mod timer; @@ -15,10 +16,6 @@ use mips::registers::cp0; #[path = "board/malta/mod.rs"] pub mod board; -#[cfg(feature = "board_mipssim")] -#[path = "board/mipssim/mod.rs"] -pub mod board; - #[no_mangle] pub extern "C" fn rust_main() -> ! { // unsafe { cpu::set_cpu_id(hartid); } @@ -30,7 +27,6 @@ pub extern "C" fn rust_main() -> ! { if cpu_id != BOOT_CPU_ID { // TODO: run others_main on other CPU // while unsafe { !cpu::has_started(hartid) } { } - // println!("Hello RISCV! in hart {}, dtb @ {:#x}", hartid, dtb); // others_main(); loop {} } @@ -39,17 +35,17 @@ pub extern "C" fn rust_main() -> ! { memory::clear_bss(); } - board::init_serial_early(); + board::early_init(); crate::logging::init(); interrupt::init(); memory::init(); timer::init(); - driver::init(); + board::init(dtb_start); - println!("Hello MIPS 32 from CPU {}, dtb @ {:#x}", cpu_id, dtb_start); + info!("Hello MIPS 32 from CPU {}, dtb @ {:#x}", cpu_id, dtb_start); - crate::drivers::init(dtb_start); + //crate::drivers::init(dtb_start); crate::process::init(); // TODO: start other CPU @@ -68,6 +64,4 @@ fn others_main() -> ! { const BOOT_CPU_ID: u32 = 0; -global_asm!(include_str!("boot/context.gen.s")); global_asm!(include_str!("boot/entry.gen.s")); -global_asm!(include_str!("boot/trap.gen.s")); diff --git a/kernel/src/arch/mipsel/signal.rs b/kernel/src/arch/mipsel/signal.rs new file mode 100644 index 00000000..f8adb16c --- /dev/null +++ b/kernel/src/arch/mipsel/signal.rs @@ -0,0 +1,36 @@ +use crate::signal::Siginfo; +use crate::signal::SignalUserContext; +use trapframe::UserContext; + +// mcontext +#[repr(C)] +#[derive(Clone, Debug)] +pub struct MachineContext {} + +impl MachineContext { + pub fn from_tf(tf: &UserContext) -> Self { + Self {} + } + + pub fn fill_tf(&self, tf: &mut UserContext) {} +} + +// TODO +pub const RET_CODE: [u8; 7] = [0; 7]; + +pub fn set_signal_handler( + tf: &mut UserContext, + sp: usize, + handler: usize, + signo: usize, + siginfo: *const Siginfo, + ucontext: *const SignalUserContext, +) { + //tf.sp = sp; + //tf.elr = handler; + + // pass handler argument + //tf.general.x0 = signo as usize; + //tf.general.x1 = siginfo as usize; + //tf.general.x2 = ucontext as usize; +} diff --git a/kernel/src/arch/mipsel/timer.rs b/kernel/src/arch/mipsel/timer.rs index 39ff232c..54073bf6 100644 --- a/kernel/src/arch/mipsel/timer.rs +++ b/kernel/src/arch/mipsel/timer.rs @@ -1,3 +1,4 @@ +use core::time::Duration; use log::*; use mips::registers::cp0; @@ -17,3 +18,8 @@ pub fn set_next() { cp0::count::write_u32(0); cp0::compare::write_u32(timebase); } + +pub fn timer_now() -> Duration { + // TODO + Duration::from_nanos(0) +} diff --git a/kernel/src/arch/riscv/consts.rs b/kernel/src/arch/riscv/consts.rs index 23d1e663..dcdd4f61 100644 --- a/kernel/src/arch/riscv/consts.rs +++ b/kernel/src/arch/riscv/consts.rs @@ -15,7 +15,7 @@ pub const MEMORY_OFFSET: usize = 0x8000_0000; // TODO: get memory end from device tree pub const MEMORY_END: usize = 0x8800_0000; -// FIXME: rv64 `sh` and `ls` will crash if stack top > 0x80000000 ??? +// TODO: rv64 `sh` and `ls` will crash if stack top > 0x80000000 ??? pub const USER_STACK_OFFSET: usize = 0x40000000 - USER_STACK_SIZE; pub const USER_STACK_SIZE: usize = 0x10000; diff --git a/kernel/src/arch/riscv/interrupt/consts.rs b/kernel/src/arch/riscv/interrupt/consts.rs index db21b022..01e20bc9 100644 --- a/kernel/src/arch/riscv/interrupt/consts.rs +++ b/kernel/src/arch/riscv/interrupt/consts.rs @@ -13,3 +13,19 @@ pub const SupervisorExternal: usize = usize::MAX / 2 + 1 + 8; pub fn is_page_fault(trap: usize) -> bool { trap == InstructionPageFault || trap == LoadPageFault || trap == StorePageFault } + +pub fn is_syscall(trap: usize) -> bool { + trap == Syscall +} + +pub fn is_intr(trap: usize) -> bool { + IrqMin <= trap && trap <= IrqMax +} + +pub fn is_timer_intr(trap: usize) -> bool { + trap == Timer +} + +pub fn is_reserved_inst(trap: usize) -> bool { + false +} diff --git a/kernel/src/arch/riscv/interrupt/mod.rs b/kernel/src/arch/riscv/interrupt/mod.rs index 871f8307..ea4f1d44 100644 --- a/kernel/src/arch/riscv/interrupt/mod.rs +++ b/kernel/src/arch/riscv/interrupt/mod.rs @@ -1,5 +1,7 @@ use crate::arch::interrupt::consts::SupervisorExternal; use crate::drivers::IRQ_MANAGER; +use crate::process::thread::Thread; +use alloc::sync::Arc; use log::*; use riscv::register::*; use riscv::register::{scause::Scause, sscratch, stvec}; @@ -113,3 +115,11 @@ pub fn wait_for_interrupt() { } } } + +pub fn handle_user_page_fault(thread: &Arc, addr: usize) -> bool { + thread.vm.lock().handle_page_fault(addr) +} + +pub fn handle_reserved_inst(tf: &mut UserContext) -> bool { + false +} diff --git a/kernel/src/arch/riscv/mod.rs b/kernel/src/arch/riscv/mod.rs index bb8e5226..f5b14fd7 100644 --- a/kernel/src/arch/riscv/mod.rs +++ b/kernel/src/arch/riscv/mod.rs @@ -42,7 +42,7 @@ pub extern "C" fn rust_main(hartid: usize, device_tree_paddr: usize) -> ! { memory::clear_bss(); } - println!( + info!( "Hello RISCV! in hart {}, device tree @ {:#x}", hartid, device_tree_vaddr ); @@ -53,7 +53,7 @@ pub extern "C" fn rust_main(hartid: usize, device_tree_paddr: usize) -> ! { } memory::init(device_tree_vaddr); timer::init(); - // FIXME: init driver on u540 + // TODO: init driver on u540 #[cfg(not(any(feature = "board_u540")))] board::init(device_tree_vaddr); unsafe { diff --git a/kernel/src/arch/riscv/syscall.rs b/kernel/src/arch/riscv/syscall.rs index b1db1163..74d09714 100644 --- a/kernel/src/arch/riscv/syscall.rs +++ b/kernel/src/arch/riscv/syscall.rs @@ -39,7 +39,7 @@ pub const SYS_MKDIRAT: usize = 34; pub const SYS_UNLINKAT: usize = 35; pub const SYS_SYMLINKAT: usize = 36; pub const SYS_LINKAT: usize = 37; -pub const SYS_RENAMEAT: usize = 38; // FIXME +pub const SYS_RENAMEAT: usize = 38; pub const SYS_UMOUNT2: usize = 39; pub const SYS_MOUNT: usize = 40; pub const SYS_PIVOT_ROOT: usize = 41; diff --git a/kernel/src/arch/x86_64/interrupt/consts.rs b/kernel/src/arch/x86_64/interrupt/consts.rs index affc9cd8..58126f9e 100644 --- a/kernel/src/arch/x86_64/interrupt/consts.rs +++ b/kernel/src/arch/x86_64/interrupt/consts.rs @@ -49,3 +49,19 @@ pub const IPIFuncCall: usize = 0xfc; pub fn is_page_fault(trap: usize) -> bool { trap == PageFault } + +pub fn is_syscall(trap: usize) -> bool { + trap == Syscall +} + +pub fn is_intr(trap: usize) -> bool { + IrqMin <= trap && trap <= IrqMax +} + +pub fn is_timer_intr(trap: usize) -> bool { + trap == Timer +} + +pub fn is_reserved_inst(trap: usize) -> bool { + false +} diff --git a/kernel/src/arch/x86_64/interrupt/mod.rs b/kernel/src/arch/x86_64/interrupt/mod.rs index 76d3106d..aec2c1cc 100644 --- a/kernel/src/arch/x86_64/interrupt/mod.rs +++ b/kernel/src/arch/x86_64/interrupt/mod.rs @@ -3,6 +3,8 @@ mod handler; pub use self::handler::*; use crate::memory::phys_to_virt; +use crate::process::thread::Thread; +use alloc::sync::Arc; use apic::*; use trapframe::{TrapFrame, UserContext}; @@ -60,3 +62,11 @@ pub fn wait_for_interrupt() { x86_64::instructions::interrupts::enable_interrupts_and_hlt(); x86_64::instructions::interrupts::disable(); } + +pub fn handle_user_page_fault(thread: &Arc, addr: usize) -> bool { + thread.vm.lock().handle_page_fault(addr) +} + +pub fn handle_reserved_inst(tf: &mut UserContext) -> bool { + false +} diff --git a/kernel/src/arch/x86_64/paging.rs b/kernel/src/arch/x86_64/paging.rs index 61a8a394..b762ce78 100644 --- a/kernel/src/arch/x86_64/paging.rs +++ b/kernel/src/arch/x86_64/paging.rs @@ -284,7 +284,7 @@ impl FrameDeallocator for FrameAllocatorForX86 { /// Flush TLB for `vaddr` on all CPU fn flush_tlb_all(_vaddr: usize) { - // FIXME: too slow, disable now. + // TODO: too slow, disable now. return; // if !super::AP_CAN_INIT.load(Ordering::Relaxed) { // return; diff --git a/kernel/src/drivers/block/ide.rs b/kernel/src/drivers/block/ide.rs new file mode 100644 index 00000000..c26c4e93 --- /dev/null +++ b/kernel/src/drivers/block/ide.rs @@ -0,0 +1,252 @@ +//! ATA IO code, handling device multiplexing and IO operations +//! +//! Borrow from Rucore project. Thanks GWord! +//! Port from ucore C code. +//! Currently used in MIPS + +use crate::drivers::{block::BlockDriver, DeviceType, Driver}; +use crate::drivers::{BLK_DRIVERS, DRIVERS}; +use crate::sync::SpinNoIrqLock as Mutex; +use alloc::string::String; +use alloc::sync::Arc; +use core::slice; + +pub const BLOCK_SIZE: usize = 512; + +pub struct IDE { + num: u8, + /// I/O Base + base: u16, + /// Control Base + ctrl: u16, +} + +pub struct IDEDriver(Mutex); + +impl Driver for IDEDriver { + fn try_handle_interrupt(&self, _irq: Option) -> bool { + false + } + + fn device_type(&self) -> DeviceType { + DeviceType::Block + } + + fn get_id(&self) -> String { + format!("ide") + } + + fn as_block(&self) -> Option<&dyn BlockDriver> { + Some(self) + } +} + +impl BlockDriver for IDEDriver { + fn read_block(&self, block_id: usize, buf: &mut [u8]) -> bool { + let mut driver = self.0.lock(); + let buf = unsafe { slice::from_raw_parts_mut(buf.as_ptr() as *mut u32, BLOCK_SIZE / 4) }; + driver.read(block_id as u64, 1, buf).is_ok() + } + + fn write_block(&self, block_id: usize, buf: &[u8]) -> bool { + if buf.len() < BLOCK_SIZE { + return false; + } + let mut driver = self.0.lock(); + let buf = unsafe { slice::from_raw_parts(buf.as_ptr() as *mut u32, BLOCK_SIZE / 4) }; + driver.write(block_id as u64, 1, buf).is_ok() + } +} + +impl IDE { + pub fn new(num: u8) -> Self { + let ide = match num { + 0 => IDE { + num: 0, + base: 0x1f0, + ctrl: 0x3f4, + }, + 1 => IDE { + num: 1, + base: 0x1f0, + ctrl: 0x3f4, + }, + 2 => IDE { + num: 2, + base: 0x170, + ctrl: 0x374, + }, + 3 => IDE { + num: 3, + base: 0x170, + ctrl: 0x374, + }, + _ => panic!("ide number should be 0,1,2,3"), + }; + ide.init(); + ide + } + + /// Read ATA DMA. Block size = 512 bytes. + pub fn read(&self, sector: u64, count: usize, data: &mut [u32]) -> Result<(), ()> { + assert_eq!(data.len(), count * SECTOR_SIZE); + self.wait(); + unsafe { + self.select(sector, count as u8); + port::outb(self.base + ISA_COMMAND, IDE_CMD_READ); + for i in 0..count { + let ptr = &mut data[(i as usize) * SECTOR_SIZE]; + if self.wait_error() { + return Err(()); + } + insl(self.base, ptr, SECTOR_SIZE); + } + } + Ok(()) + } + /// Write ATA DMA. Block size = 512 bytes. + pub fn write(&self, sector: u64, count: usize, data: &[u32]) -> Result<(), ()> { + assert_eq!(data.len(), count * SECTOR_SIZE); + self.wait(); + unsafe { + self.select(sector, count as u8); + port::outb(self.base + ISA_COMMAND, IDE_CMD_WRITE); + for i in 0..count { + let ptr = &data[(i as usize) * SECTOR_SIZE]; + if self.wait_error() { + return Err(()); + } + outsl(self.base, ptr, SECTOR_SIZE); + } + } + Ok(()) + } + + fn wait(&self) { + while unsafe { port::inb(self.base + ISA_STATUS) } & IDE_BUSY != 0 {} + } + + fn wait_error(&self) -> bool { + self.wait(); + let status = unsafe { port::inb(self.base + ISA_STATUS) }; + status & (IDE_DF | IDE_ERR) != 0 + } + + fn init(&self) { + self.wait(); + unsafe { + // step1: select drive + port::outb(self.base + ISA_SDH, (0xE0 | ((self.num & 1) << 4)) as u8); + self.wait(); + + // step2: send ATA identify command + port::outb(self.base + ISA_COMMAND, IDE_CMD_IDENTIFY); + self.wait(); + + // step3: polling + if port::inb(self.base + ISA_STATUS) == 0 || self.wait_error() { + return; + } + + // ??? + let mut data = [0; SECTOR_SIZE]; + insl(self.base + ISA_DATA, data.as_mut_ptr(), SECTOR_SIZE); + } + } + + fn select(&self, sector: u64, count: u8) { + assert_ne!(count, 0); + self.wait(); + unsafe { + // generate interrupt + port::outb(self.ctrl + ISA_CTRL, 0); + port::outb(self.base + ISA_SECCNT, count); + port::outb(self.base + ISA_SECTOR, (sector & 0xFF) as u8); + port::outb(self.base + ISA_CYL_LO, ((sector >> 8) & 0xFF) as u8); + port::outb(self.base + ISA_CYL_HI, ((sector >> 16) & 0xFF) as u8); + port::outb( + self.base + ISA_SDH, + 0xE0 | ((self.num & 1) << 4) | (((sector >> 24) & 0xF) as u8), + ); + } + } +} + +const SECTOR_SIZE: usize = 128; +const MAX_DMA_SECTORS: usize = 0x1F_F000 / SECTOR_SIZE; // Limited by sector count (and PRDT entries) + // 512 PDRT entries, assume maximum fragmentation = 512 * 4K max = 2^21 = 2MB per transfer + +const ISA_DATA: u16 = 0x00; +const ISA_ERROR: u16 = 0x01; +const ISA_PRECOMP: u16 = 0x01; +const ISA_CTRL: u16 = 0x02; +const ISA_SECCNT: u16 = 0x02; +const ISA_SECTOR: u16 = 0x03; +const ISA_CYL_LO: u16 = 0x04; +const ISA_CYL_HI: u16 = 0x05; +const ISA_SDH: u16 = 0x06; +const ISA_COMMAND: u16 = 0x07; +const ISA_STATUS: u16 = 0x07; + +const IDE_BUSY: u8 = 0x80; +const IDE_DRDY: u8 = 0x40; +const IDE_DF: u8 = 0x20; +const IDE_DRQ: u8 = 0x08; +const IDE_ERR: u8 = 0x01; + +const IDE_CMD_READ: u8 = 0x20; +const IDE_CMD_WRITE: u8 = 0x30; +const IDE_CMD_IDENTIFY: u8 = 0xEC; + +const MAX_NSECS: usize = 128; + +#[cfg(target_arch = "x86_64")] +unsafe fn insl(addr: u16, data: *mut u32, len: usize) { + llvm_asm!("rep insl" :: "{dx}"(addr), "{rdi}"(data), "{cx}"(SECTOR_SIZE) : "rdi" : "volatile"); +} + +#[cfg(not(target_arch = "x86_64"))] +unsafe fn insl(addr: u16, data: *mut u32, len: usize) { + for i in 0..len { + *data.add(i) = port::inl(addr); + } +} + +#[cfg(target_arch = "x86_64")] +unsafe fn outsl(addr: u16, data: *const u32, len: usize) { + llvm_asm!("rep insl" :: "{dx}"(addr), "{rdi}"(data), "{cx}"(SECTOR_SIZE) : "rdi" : "volatile"); +} + +#[cfg(not(target_arch = "x86_64"))] +unsafe fn outsl(addr: u16, data: *const u32, len: usize) { + for i in 0..len { + port::outl(addr, *data.add(i)); + } +} + +// MIPS +mod port { + const PCI_BASE: usize = 0xb8000000; + pub unsafe fn inb(port: u16) -> u8 { + crate::util::read(port as usize + PCI_BASE) + } + + pub unsafe fn outb(port: u16, value: u8) { + crate::util::write(port as usize + PCI_BASE, value) + } + + pub unsafe fn inl(port: u16) -> u32 { + crate::util::read(port as usize + PCI_BASE) + } + + pub unsafe fn outl(port: u16, value: u32) { + crate::util::write(port as usize + PCI_BASE, value) + } +} + +pub fn init() { + let ide = IDE::new(0); + let driver = Arc::new(IDEDriver(Mutex::new(ide))); + DRIVERS.write().push(driver.clone()); + BLK_DRIVERS.write().push(driver.clone()); +} diff --git a/kernel/src/drivers/block/mod.rs b/kernel/src/drivers/block/mod.rs index 62cf2ff6..bfebf65b 100644 --- a/kernel/src/drivers/block/mod.rs +++ b/kernel/src/drivers/block/mod.rs @@ -1,6 +1,7 @@ use super::Driver; pub mod ahci; +pub mod ide; pub mod virtio_blk; pub trait BlockDriver: Driver { diff --git a/kernel/src/drivers/console/mod.rs b/kernel/src/drivers/console/mod.rs index a4040960..d797a72c 100644 --- a/kernel/src/drivers/console/mod.rs +++ b/kernel/src/drivers/console/mod.rs @@ -13,7 +13,7 @@ pub static CONSOLE: Mutex> = Mutex::new(None); pub fn init() { if cfg!(feature = "consolegraphic") { if let Some(fb) = FRAME_BUFFER.write().take() { - // FIXME: now take FrameBuffer out of global variable, then move into Console + // TODO: now take FrameBuffer out of global variable, then move into Console let console = Console::on_frame_buffer(fb.fb_info.xres, fb.fb_info.yres, fb); *CONSOLE.lock() = Some(console); info!("console: init end"); diff --git a/kernel/src/drivers/serial/ti_16c550c.rs b/kernel/src/drivers/serial/ti_16c550c.rs deleted file mode 100644 index a1d6ec50..00000000 --- a/kernel/src/drivers/serial/ti_16c550c.rs +++ /dev/null @@ -1,102 +0,0 @@ -//! TI 16c550c serial adapter driver for malta board - -#![allow(dead_code)] - -use crate::sync::SpinLock as Mutex; -use crate::util::{read, write}; -use core::fmt::{Arguments, Result, Write}; - -pub struct SerialPort { - base: usize, -} - -impl SerialPort { - fn new() -> SerialPort { - SerialPort { base: 0 } - } - - pub fn init(&mut self, base: usize) { - self.base = base; - // Turn off the FIFO - // write(self.base + COM_FCR, 0 as u8); - // Set speed; requires DLAB latch - // write(self.base + COM_LCR, COM_LCR_DLAB); - // write(self.base + COM_DLL, (115200 / 9600) as u8); - // write(self.base + COM_DLM, 0 as u8); - - // 8 data bits, 1 stop bit, parity off; turn off DLAB latch - // write(self.base + COM_LCR, COM_LCR_WLEN8 & !COM_LCR_DLAB); - - // No modem controls - // write(self.base + COM_MCR, 0 as u8); - // Enable rcv interrupts - write(self.base + COM_INT_EN, 0x1); - } - - /// non-blocking version of putchar() - pub fn putchar(&mut self, c: u8) { - write(self.base + COM_TX, c); - } - - /// blocking version of getchar() - pub fn getchar(&mut self) -> char { - loop { - if (read::(self.base + COM_LSR) & 0x01) == 0 { - break; - } - } - let c = read::(self.base + COM_RX); - match c { - 255 => '\0', // null - c => c as char, - } - } - - /// non-blocking version of getchar() - pub fn getchar_option(&mut self) -> Option { - match read::(self.base + COM_LSR) & 0x01 { - 0 => None, - _ => Some(read::(self.base + COM_RX) as u8 as char), - } - } - - pub fn putfmt(&mut self, fmt: Arguments) { - self.write_fmt(fmt).unwrap(); - } -} - -impl Write for SerialPort { - fn write_str(&mut self, s: &str) -> Result { - for c in s.bytes() { - match c { - 127 => { - self.putchar(8); - self.putchar(b' '); - self.putchar(8); - } - b'\n' => { - self.putchar(b'\r'); - self.putchar(b'\n'); - } - c => { - self.putchar(c); - } - } - } - Ok(()) - } -} - -const COM_RX: usize = 0x00; // In: Receive buffer (DLAB=0) -const COM_TX: usize = 0x00; // Out: Transmit buffer (DLAB=0) -const COM_INT_EN: usize = 0x08; // In: Interrupt enable -const COM_INT_ID: usize = 0x10; // Out: Interrupt identification -const COM_LSR: usize = 0x28; // In: Line status register - -lazy_static! { - pub static ref SERIAL_PORT: Mutex = Mutex::new(SerialPort::new()); -} - -pub fn init(base: usize) { - SERIAL_PORT.lock().init(base); -} diff --git a/kernel/src/drivers/serial/uart16550.rs b/kernel/src/drivers/serial/uart16550.rs index 6ec3f048..fb66fb76 100644 --- a/kernel/src/drivers/serial/uart16550.rs +++ b/kernel/src/drivers/serial/uart16550.rs @@ -16,6 +16,7 @@ use device_tree::Node; pub struct SerialPort { base: usize, + multiplier: usize, } impl Driver for SerialPort { @@ -38,8 +39,11 @@ impl Driver for SerialPort { } impl SerialPort { - fn new(base: usize) -> SerialPort { - let mut res = SerialPort { base: 0 }; + fn new(base: usize, shift: usize) -> SerialPort { + let mut res = SerialPort { + base: 0, + multiplier: 1 << shift, + }; res.init(base); res } @@ -47,39 +51,42 @@ impl SerialPort { pub fn init(&mut self, base: usize) { self.base = base; // Turn off the FIFO - write(self.base + COM_FCR, 0 as u8); + write(self.base + COM_FCR * self.multiplier, 0 as u8); // Set speed; requires DLAB latch - write(self.base + COM_LCR, COM_LCR_DLAB); - write(self.base + COM_DLL, (115200 / 9600) as u8); - write(self.base + COM_DLM, 0 as u8); + write(self.base + COM_LCR * self.multiplier, COM_LCR_DLAB); + //write(self.base + COM_DLL * self.multiplier, (115200 / 9600) as u8); + //write(self.base + COM_DLM * self.multiplier, 0 as u8); // 8 data bits, 1 stop bit, parity off; turn off DLAB latch - write(self.base + COM_LCR, COM_LCR_WLEN8 & !COM_LCR_DLAB); + write( + self.base + COM_LCR * self.multiplier, + COM_LCR_WLEN8 & !COM_LCR_DLAB, + ); // No modem controls - write(self.base + COM_MCR, 0 as u8); + write(self.base + COM_MCR * self.multiplier, 0 as u8); // Enable rcv interrupts - write(self.base + COM_IER, COM_IER_RDI); + write(self.base + COM_IER * self.multiplier, COM_IER_RDI); } /// non-blocking version of putchar() pub fn putchar(&self, c: u8) { for _ in 0..100 { - if (read::(self.base + COM_LSR) & COM_LSR_TXRDY) == 0 { + if (read::(self.base + COM_LSR * self.multiplier) & COM_LSR_TXRDY) == 0 { break; } } - write(self.base + COM_TX, c); + write(self.base + COM_TX * self.multiplier, c); } /// blocking version of getchar() pub fn getchar(&mut self) -> u8 { loop { - if (read::(self.base + COM_LSR) & COM_LSR_DATA) == 0 { + if (read::(self.base + COM_LSR * self.multiplier) & COM_LSR_DATA) == 0 { break; } } - let c = read::(self.base + COM_RX); + let c = read::(self.base + COM_RX * self.multiplier); match c { 255 => b'\0', // null c => c, @@ -88,9 +95,9 @@ impl SerialPort { /// non-blocking version of getchar() pub fn getchar_option(&self) -> Option { - match read::(self.base + COM_LSR) & COM_LSR_DATA { + match read::(self.base + COM_LSR * self.multiplier) & COM_LSR_DATA { 0 => None, - _ => Some(read::(self.base + COM_RX) as u8), + _ => Some(read::(self.base + COM_RX * self.multiplier) as u8), } } } @@ -128,10 +135,11 @@ const COM_LSR_TXRDY: u8 = 0x20; // Transmit buffer avail const COM_LSR_TSRE: u8 = 0x40; // Transmitter off pub fn init_dt(dt: &Node) { - let addr = dt.prop_u64("reg").unwrap() as usize; + let addr = dt.prop_usize("reg").unwrap(); + let shift = dt.prop_u32("reg-shift").unwrap_or(0) as usize; let base = phys_to_virt(addr); info!("Init uart16550 at {:#x}", base); - let com = Arc::new(SerialPort::new(base)); + let com = Arc::new(SerialPort::new(base, shift)); let mut found = false; let irq_opt = dt.prop_u32("interrupts").ok().map(|irq| irq as usize); DRIVERS.write().push(com.clone()); diff --git a/kernel/src/fs/file.rs b/kernel/src/fs/file.rs index 135a7f0d..f286fd00 100644 --- a/kernel/src/fs/file.rs +++ b/kernel/src/fs/file.rs @@ -113,7 +113,7 @@ impl FileHandle { pub async fn read_at(&self, offset: usize, buf: &mut [u8]) -> Result { // let options = &self.description.read().options; if !self.description.read().options.read { - return Err(FsError::InvalidParam); // FIXME: => EBADF + return Err(FsError::InvalidParam); // TODO: => EBADF } if !self.description.read().options.nonblock { // block @@ -150,7 +150,7 @@ impl FileHandle { pub fn write_at(&self, offset: usize, buf: &[u8]) -> Result { if !self.description.read().options.write { - return Err(FsError::InvalidParam); // FIXME: => EBADF + return Err(FsError::InvalidParam); // TODO: => EBADF } let len = self.inode.write_at(offset, buf)?; TimeSpec::update(&self.inode); @@ -169,7 +169,7 @@ impl FileHandle { pub fn set_len(&mut self, len: u64) -> Result<()> { if !self.description.read().options.write { - return Err(FsError::InvalidParam); // FIXME: => EBADF + return Err(FsError::InvalidParam); // TODO: => EBADF } self.inode.resize(len as usize)?; Ok(()) @@ -194,7 +194,7 @@ impl FileHandle { pub fn read_entry(&mut self) -> Result { let mut description = self.description.write(); if !description.options.read { - return Err(FsError::InvalidParam); // FIXME: => EBADF + return Err(FsError::InvalidParam); // TODO: => EBADF } let mut offset = &mut description.offset; let name = self.inode.get_entry(*offset as usize)?; @@ -205,7 +205,7 @@ impl FileHandle { pub fn read_entry_with_metadata(&mut self) -> Result<(Metadata, String)> { let mut description = self.description.write(); if !description.options.read { - return Err(FsError::InvalidParam); // FIXME: => EBADF + return Err(FsError::InvalidParam); // TODO: => EBADF } let mut offset = &mut description.offset; let ret = self.inode.get_entry_with_metadata(*offset as usize)?; diff --git a/kernel/src/fs/ioctl.rs b/kernel/src/fs/ioctl.rs index b377a14c..8a797b93 100644 --- a/kernel/src/fs/ioctl.rs +++ b/kernel/src/fs/ioctl.rs @@ -13,7 +13,7 @@ pub const TCGETS: usize = 0x540D; #[cfg(not(target_arch = "mips"))] pub const TCSETS: usize = 0x5402; #[cfg(target_arch = "mips")] -pub const TCGETS: usize = 0x540E; +pub const TCSETS: usize = 0x540E; #[cfg(not(target_arch = "mips"))] pub const TIOCGPGRP: usize = 0x540F; diff --git a/kernel/src/lib.rs b/kernel/src/lib.rs index fe8f52a9..18e32782 100644 --- a/kernel/src/lib.rs +++ b/kernel/src/lib.rs @@ -8,6 +8,7 @@ #![feature(negative_impls)] #![feature(alloc_prelude)] #![feature(const_fn)] +#![feature(const_if_match)] #![feature(const_in_array_repeat_expressions)] #![deny(unused_must_use)] #![deny(stable_features)] diff --git a/kernel/src/memory.rs b/kernel/src/memory.rs index 10306d0a..e551d410 100644 --- a/kernel/src/memory.rs +++ b/kernel/src/memory.rs @@ -32,10 +32,22 @@ pub static FRAME_ALLOCATOR: SpinNoIrqLock = SpinNoIrqLock::new(Frame /// Convert physical address to virtual address #[inline] +#[cfg(not(mipsel))] pub const fn phys_to_virt(paddr: usize) -> usize { PHYSICAL_MEMORY_OFFSET + paddr } +/// MIPS is special +#[inline] +#[cfg(mipsel)] +pub const fn phys_to_virt(paddr: usize) -> usize { + if paddr <= PHYSICAL_MEMORY_OFFSET { + PHYSICAL_MEMORY_OFFSET + paddr + } else { + paddr + } +} + /// Convert virtual address to physical address #[inline] pub const fn virt_to_phys(vaddr: usize) -> usize { diff --git a/kernel/src/net/structs.rs b/kernel/src/net/structs.rs index 2141293e..b201d383 100644 --- a/kernel/src/net/structs.rs +++ b/kernel/src/net/structs.rs @@ -527,7 +527,7 @@ impl Socket for UdpSocketState { match request { // SIOCGARP 0x8954 => { - // FIXME: check addr + // TODO: check addr let req = unsafe { &mut *(arg1 as *mut ArpReq) }; if let AddressFamily::Internet = AddressFamily::from(req.arp_pa.family) { let name = req.arp_dev.as_ptr(); diff --git a/kernel/src/process/thread.rs b/kernel/src/process/thread.rs index cb970339..3891aae2 100644 --- a/kernel/src/process/thread.rs +++ b/kernel/src/process/thread.rs @@ -2,8 +2,10 @@ use super::{ abi::{self, ProcInitInfo}, add_to_process_table, Pid, Process, PROCESSORS, }; -use crate::arch::interrupt::consts::{is_page_fault, IrqMax, IrqMin, Syscall, Timer}; -use crate::arch::interrupt::get_trap_num; +use crate::arch::interrupt::consts::{ + is_intr, is_page_fault, is_reserved_inst, is_syscall, is_timer_intr, +}; +use crate::arch::interrupt::{get_trap_num, handle_reserved_inst, handle_user_page_fault}; use crate::arch::{ cpu, fp::FpState, @@ -307,6 +309,15 @@ impl Thread { // F | A | D | EL0 context.spsr = 0b1101_00_0000; } + #[cfg(target_arch = "mips")] + { + // UM | CP1 | IE + context.status = 1 << 4 | 1 << 29 | 1; + // IM1..IM0 + context.status |= 1 << 8 | 1 << 9; + // IPL(IM5..IM2) + context.status |= 1 << 15 | 1 << 14 | 1 << 13 | 1 << 12; + } let thread = Thread { tid: 0, // allocated below @@ -499,27 +510,37 @@ pub fn spawn(thread: Arc) { trace!("back from user: {:#x?} trap_num {:#x}", cx, trap_num); let mut exit = false; + let mut do_yield = false; match trap_num { // must be first _ if is_page_fault(trap_num) => { // page fault let addr = get_page_fault_addr(); - debug!("page fault from user @ {:#x}", addr); + info!("page fault from user @ {:#x}", addr); - if !thread.vm.lock().handle_page_fault(addr as usize) { + if !handle_user_page_fault(&thread, addr) { // TODO: SIGSEGV panic!("page fault handle failed"); } } - Syscall => exit = handle_syscall(&thread, cx).await, - IrqMin..=IrqMax => { + _ if is_syscall(trap_num) => exit = handle_syscall(&thread, cx).await, + _ if is_intr(trap_num) => { crate::arch::interrupt::ack(trap_num); trace!("handle irq {:#x}", trap_num); - if trap_num == Timer { + if is_timer_intr(trap_num) { + do_yield = true; crate::arch::interrupt::timer(); } IRQ_MANAGER.read().try_handle_interrupt(Some(trap_num)); } + _ if is_reserved_inst(trap_num) => { + if !handle_reserved_inst(cx) { + panic!( + "unhandled reserved intr in thread {} trap {:#x} {:x?}", + thread.tid, trap_num, cx + ); + } + } _ => { panic!( "unhandled trap in thread {} trap {:#x} {:x?}", @@ -537,7 +558,7 @@ pub fn spawn(thread: Arc) { if exit { info!("thread {} stopped", thread.tid); break; - } else { + } else if do_yield { yield_now().await; } } diff --git a/kernel/src/signal/mod.rs b/kernel/src/signal/mod.rs index 2f392b2e..b43c18d5 100644 --- a/kernel/src/signal/mod.rs +++ b/kernel/src/signal/mod.rs @@ -172,7 +172,7 @@ pub fn handle_signal(thread: &Arc, tf: &mut UserContext) -> bool { match signal { SIGALRM | SIGHUP | SIGINT => { info!("default action: Term"); - // FIXME: exit code ref please? + // TODO: exit code ref please? process.exit(info.signo as usize + 128); return true; } diff --git a/kernel/src/syscall/fs.rs b/kernel/src/syscall/fs.rs index 306d1013..32e101f1 100644 --- a/kernel/src/syscall/fs.rs +++ b/kernel/src/syscall/fs.rs @@ -1194,7 +1194,7 @@ impl Syscall<'_> { if times[0].nsec == UTIME_NOW { times[0] = TimeSpec::get_epoch(); } - metadata.atime = Timespec { + metadata.atime = rcore_fs::vfs::Timespec { sec: times[0].sec as i64, nsec: times[0].nsec as i32, }; @@ -1203,7 +1203,7 @@ impl Syscall<'_> { if times[1].nsec == UTIME_NOW { times[1] = TimeSpec::get_epoch(); } - metadata.mtime = Timespec { + metadata.mtime = rcore_fs::vfs::Timespec { sec: times[1].sec as i64, nsec: times[1].nsec as i32, }; diff --git a/kernel/src/syscall/mem.rs b/kernel/src/syscall/mem.rs index 9ec75b44..db12e90a 100644 --- a/kernel/src/syscall/mem.rs +++ b/kernel/src/syscall/mem.rs @@ -81,7 +81,7 @@ impl Syscall<'_> { ); let _attr = prot.to_attr(); - // FIXME: properly set the attribute of the area + // TODO: properly set the attribute of the area // now some mut ptr check is fault let vm = self.vm(); let memory_area = vm @@ -147,7 +147,7 @@ impl MmapProt { if self.contains(MmapProt::EXEC) { attr = attr.execute(); } - // FIXME: see sys_mprotect + // TODO: see sys_mprotect // if !self.contains(MmapProt::WRITE) { attr = attr.readonly(); } attr } diff --git a/kernel/src/syscall/mod.rs b/kernel/src/syscall/mod.rs index e9b4e979..36f8660f 100644 --- a/kernel/src/syscall/mod.rs +++ b/kernel/src/syscall/mod.rs @@ -56,11 +56,17 @@ pub async fn handle_syscall(thread: &Arc, context: &mut UserContext) -> let regs = &context.general; let num = context.get_syscall_num(); let args = context.get_syscall_args(); + // add before fork #[cfg(riscv)] { context.sepc = context.sepc + 4; } + #[cfg(mipsel)] + { + context.epc = context.epc + 4; + } + let mut syscall = Syscall { thread, context, @@ -355,9 +361,12 @@ impl Syscall<'_> { } #[cfg(not(target_arch = "mips"))] SYS_SEMCTL => self.sys_semctl(args[0], args[1], args[2], args[3]), + + // msg + #[cfg(not(target_arch = "mips"))] SYS_MSGGET => self.unimplemented("msgget", Ok(0)), - #[cfg(target_arch = "mips")] - SYS_SHMGET => self.unimplemented("shmget", Ok(0)), + #[cfg(not(target_arch = "mips"))] + SYS_MSGCTL => self.unimplemented("msgctl", Ok(0)), // shm #[cfg(not(target_arch = "mips"))] @@ -426,14 +435,13 @@ impl Syscall<'_> { SYS_GET_PADDR => { self.sys_get_paddr(args[0] as *const u64, args[1] as *mut u64, args[2]) } - SYS_MSGCTL => self.unimplemented("msgctl", Ok(0)), _ => { let ret = match () { #[cfg(target_arch = "x86_64")] () => self.x86_64_syscall(id, args).await, #[cfg(target_arch = "mips")] - () => self.mips_syscall(id, args), + () => self.mips_syscall(id, args).await, #[cfg(all(not(target_arch = "x86_64"), not(target_arch = "mips")))] () => None, }; @@ -474,10 +482,13 @@ impl Syscall<'_> { } #[cfg(target_arch = "mips")] - fn mips_syscall(&mut self, id: usize, args: [usize; 6]) -> Option { + async fn mips_syscall(&mut self, id: usize, args: [usize; 6]) -> Option { let ret = match id { SYS_OPEN => self.sys_open(args[0] as *const u8, args[1], args[2]), - SYS_POLL => self.sys_poll(args[0] as *mut PollFd, args[1], args[2]), + SYS_POLL => { + self.sys_poll(UserInOutPtr::from(args[0]), args[1], args[2]) + .await + } SYS_DUP2 => self.sys_dup2(args[0], args[1]), SYS_FORK => self.sys_fork(), SYS_MMAP2 => self.sys_mmap(args[0], args[1], args[2], args[3], args[4], args[5] * 4096), @@ -489,10 +500,10 @@ impl Syscall<'_> { match self.sys_pipe(fd_ptr) { Ok(_code) => { unsafe { - self.tf.v0 = *fd_ptr as usize; - self.tf.v1 = *(fd_ptr.add(1)) as usize; + self.context.general.v0 = *fd_ptr as usize; + self.context.general.v1 = *(fd_ptr.add(1)) as usize; } - Ok(self.tf.v0) + Ok(self.context.general.v0) } Err(err) => Err(err), } @@ -500,19 +511,15 @@ impl Syscall<'_> { SYS_FCNTL64 => self.unimplemented("fcntl64", Ok(0)), SYS_SET_THREAD_AREA => { info!("set_thread_area: tls: 0x{:x}", args[0]); - extern "C" { - fn _cur_tls(); - } - - unsafe { - llvm_asm!("mtc0 $0, $$4, 2": :"r"(args[0])); - *(_cur_tls as *mut usize) = args[0]; - } + self.context.tls = args[0]; Ok(0) } SYS_IPC => match args[0] { - 1 => self.sys_semop(args[1], UserInPtr::from(args[2]), args[3]), - 2 => self.sys_semget(args[1], args[2] as isize, args[3]), + 1 => { + self.sys_semop(args[1], UserInPtr::from(args[2]), args[3]) + .await + } + 2 => self.sys_semget(args[1], args[2], args[3]), 3 => self.sys_semctl(args[1], args[2], args[3], args[4]), _ => return None, }, diff --git a/kernel/src/syscall/proc.rs b/kernel/src/syscall/proc.rs index b5474a82..ddb7feed 100644 --- a/kernel/src/syscall/proc.rs +++ b/kernel/src/syscall/proc.rs @@ -350,7 +350,7 @@ impl Syscall<'_> { // perform futex wake 1 // ref: http://man7.org/linux/man-pages/man2/set_tid_address.2.html - // FIXME: do it in all possible ways a thread can exit + // TODO: do it in all possible ways a thread can exit // it has memory access so we can't move it to Thread::drop? let clear_child_tid = self.thread.inner.lock().clear_child_tid as *mut u32; if !clear_child_tid.is_null() { diff --git a/kernel/src/syscall/user.rs b/kernel/src/syscall/user.rs index 1d954dba..08193587 100644 --- a/kernel/src/syscall/user.rs +++ b/kernel/src/syscall/user.rs @@ -38,7 +38,7 @@ impl Debug for UserPtr { } } -// FIXME: this is a workaround for `clear_child_tid`. +// TODO: this is a workaround for `clear_child_tid`. unsafe impl Send for UserPtr {} unsafe impl Sync for UserPtr {} diff --git a/user b/user index 291df7f6..63342746 160000 --- a/user +++ b/user @@ -1 +1 @@ -Subproject commit 291df7f66ed42f642cd691554fa0c88e59cdb894 +Subproject commit 63342746297b9694676c82a716601d736ebab1a1