1
0
mirror of https://github.com/rcore-os/rCore.git synced 2024-11-22 08:06:17 +04:00

Merge pull request #63 from rcore-os/fix-mipsel

Fix mipsel
This commit is contained in:
Chen 2020-07-09 13:14:55 +08:00 committed by GitHub
commit d3ab8c58ad
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
55 changed files with 741 additions and 1017 deletions

View File

@ -22,7 +22,7 @@ jobs:
matrix: matrix:
os: [ubuntu-latest, macos-latest] os: [ubuntu-latest, macos-latest]
# we will bring back mipsel later # we will bring back mipsel later
arch: [x86_64, riscv32, riscv64, aarch64] arch: [x86_64, riscv32, riscv64, aarch64, mipsel]
steps: steps:
- uses: actions/checkout@v2 - uses: actions/checkout@v2
- name: Checkout submodules - name: Checkout submodules

4
kernel/Cargo.lock generated
View File

@ -166,7 +166,7 @@ dependencies = [
[[package]] [[package]]
name = "device_tree" name = "device_tree"
version = "1.0.3" 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]] [[package]]
name = "either" name = "either"
@ -709,7 +709,7 @@ checksum = "3a385d94f3f62e60445a0adb9ff8d9621faa272234530d4c0f848ec98f88e316"
[[package]] [[package]]
name = "trapframe" name = "trapframe"
version = "0.4.3" 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 = [ dependencies = [
"raw-cpuid", "raw-cpuid",
"x86_64", "x86_64",

View File

@ -27,8 +27,7 @@ nographic = []
consolegraphic = [] consolegraphic = []
board_raspi3 = ["bcm2837"] board_raspi3 = ["bcm2837"]
# for qemu machine # for qemu machine
board_malta = ["link_user"] board_malta = []
board_mipssim = ["link_user"]
# for x86 PC # for x86 PC
board_pc = ["link_user"] board_pc = ["link_user"]
# Hard link user program # Hard link user program
@ -49,7 +48,7 @@ bitvec = { version = "0.17", default-features = false, features = ["alloc"] }
bit_field = "0.10" bit_field = "0.10"
buddy_system_allocator = "0.4.0" buddy_system_allocator = "0.4.0"
compression = { version = "0.1.4", default-features = false, features = ["gzip"] } 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" } 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"] } isomorphic_drivers = { git = "https://github.com/rcore-os/isomorphic_drivers", rev = "fcf694d2", features = ["log"] }
lazy_static = { version = "1.4", features = ["spin_no_std"] } 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" 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"] } 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" 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" } virtio-drivers = { git = "https://github.com/rcore-os/virtio-drivers", rev = "dfa70e14" }
volatile = "0.2" volatile = "0.2"
woke = "0.0.2" woke = "0.0.2"

View File

@ -65,11 +65,6 @@ ifeq ($(ARCH), mipsel)
DTB := src/arch/$(ARCH)/board/$(BOARD)/device.dtb DTB := src/arch/$(ARCH)/board/$(BOARD)/device.dtb
endif endif
# mipssim does not support SMP
ifeq ($(BOARD), mipssim)
SMP := 1
endif
### qemu options ### ### qemu options ###
qemu_opts := \ qemu_opts := \
-smp cores=$(SMP) -smp cores=$(SMP)
@ -157,15 +152,10 @@ else ifeq ($(ARCH), mipsel)
ifeq ($(BOARD), malta) ifeq ($(BOARD), malta)
qemu_opts += \ qemu_opts += \
-machine $(BOARD) -device VGA \ -machine $(BOARD) -device VGA \
-hda $(USER_QCOW2) \
-serial null -serial null -serial mon:stdio \ -serial null -serial null -serial mon:stdio \
-kernel $(kernel_img) -kernel $(kernel_img)
endif endif
ifeq ($(BOARD), mipssim)
qemu_opts += \
-machine $(BOARD) \
-serial mon:stdio \
-kernel $(kernel_img)
endif
endif endif
ifdef D ifdef D
@ -302,7 +292,7 @@ ifeq ($(ARCH), $(filter $(ARCH), riscv32 riscv64))
$(sysroot)/lib/rustlib/src/rust/src/libcore/sync/atomic.rs \ $(sysroot)/lib/rustlib/src/rust/src/libcore/sync/atomic.rs \
src/arch/riscv/atomic.patch src/arch/riscv/atomic.patch
else ifeq ($(ARCH), mipsel) 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 ; \ $(hostcc) -Dboard_$(BOARD) -E src/arch/$(ARCH)/boot/$${file}.S -o src/arch/$(ARCH)/boot/$${file}.gen.s ; \
done done
$(hostcc) -Dboard_$(BOARD) -E src/arch/$(ARCH)/boot/linker.ld.S -o src/arch/$(ARCH)/boot/linker.ld $(hostcc) -Dboard_$(BOARD) -E src/arch/$(ARCH)/boot/linker.ld.S -o src/arch/$(ARCH)/boot/linker.ld

View File

@ -17,5 +17,11 @@ fn main() {
} else if target.contains("riscv64") { } else if target.contains("riscv64") {
println!("cargo:rustc-cfg=riscv"); println!("cargo:rustc-cfg=riscv");
println!("cargo:rustc-cfg=riscv64"); 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");
} }
} }

View File

@ -30,14 +30,13 @@
- fn ack(trap: usize):确认中断处理 - fn ack(trap: usize):确认中断处理
- fn timer():处理时钟中断 - fn timer():处理时钟中断
- fn wait_for_interrupt():打开并等待中断 - fn wait_for_interrupt():打开并等待中断
- fn handle_user_page_fault(thread: &Arc\<Thread\>, addr: usize):处理用户态的缺页异常
### interrupt/consts ### interrupt/consts
- fn is_page_fault(trap: usize):是否缺页 - fn is_page_fault(trap: usize):是否缺页
- IrqMin中断的最小 trap - fn is_syscall(trap: usize):是否系统调用
- IrqMax中断的最大 trap - fn is_intr(trap: usize):是否中断
- Syscall系统调用的 trap
- Timer时钟中断的 trap
### interrupt/handler ### interrupt/handler

View File

@ -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 USER_STACK_SIZE: usize = 1 * 1024 * 1024;
pub const KSEG2_START: usize = 0xffff_fe80_0000_0000; pub const KSEG2_START: usize = 0xffff_fe80_0000_0000;
#[cfg(target_arch = "aarch64")]
pub const ARCH: &'static str = "aarch64"; pub const ARCH: &'static str = "aarch64";

View File

@ -28,3 +28,19 @@ pub const Timer: usize = 0x10002;
// from el0, sync // from el0, sync
pub const Syscall: usize = 0x00002; 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
}

View File

@ -2,7 +2,9 @@
pub use self::handler::*; pub use self::handler::*;
use crate::arch::board::timer::is_pending; use crate::arch::board::timer::is_pending;
use crate::process::thread::Thread;
use aarch64::regs::*; use aarch64::regs::*;
use alloc::sync::Arc;
use trapframe::UserContext; use trapframe::UserContext;
pub mod consts; pub mod consts;
@ -68,3 +70,11 @@ pub fn wait_for_interrupt() {
aarch64::asm::wfe(); aarch64::asm::wfe();
DAIF.set(daif); DAIF.set(daif);
} }
pub fn handle_user_page_fault(thread: &Arc<Thread>, addr: usize) -> bool {
thread.vm.lock().handle_page_fault(addr)
}
pub fn handle_reserved_inst(tf: &mut UserContext) -> bool {
false
}

View File

@ -1,3 +1,3 @@
/// board specific constants /// 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; pub const KERNEL_HEAP_SIZE: usize = 0x0200_0000;

View File

@ -25,19 +25,11 @@
reg = <0x00000000 0x10000000>; reg = <0x00000000 0x10000000>;
}; };
uart0: serial@b80003f8 {
compatible = "ns16550a";
reg = <0xb80003f8 0x8>;
clock-frequency = <1843200>;
};
uart2: serial@bf000900 { uart2: serial@bf000900 {
compatible = "ns16550a"; compatible = "ns16550a";
reg = <0xbf000900 0x40>; reg = <0xbf000900 0x40>;
reg-shift = <3>; reg-shift = <3>;
clock-frequency = <1843200>; clock-frequency = <1843200>;
/* The CBUS UART is attached to the MIPS CPU INT2 pin, ie interrupt 4 */
interrupt-parent = <&cpu_intc>;
interrupts = <4>; interrupts = <4>;
}; };

View File

@ -1,10 +1,10 @@
use crate::drivers::block::ide;
use crate::drivers::bus::pci; use crate::drivers::bus::pci;
use crate::drivers::gpu::fb::{self, FramebufferInfo}; use crate::drivers::gpu::fb::{self, FramebufferInfo};
use crate::drivers::*;
use mips::registers::cp0; use mips::registers::cp0;
pub mod consts; pub mod consts;
#[path = "../../../../drivers/serial/ti_16c550c.rs"]
pub mod serial;
#[path = "../../../../drivers/gpu/qemu_stdvga.rs"] #[path = "../../../../drivers/gpu/qemu_stdvga.rs"]
pub mod vga; pub mod vga;
@ -12,19 +12,18 @@ pub mod vga;
pub static DTB: &'static [u8] = include_bytes!("device.dtb"); pub static DTB: &'static [u8] = include_bytes!("device.dtb");
/// Initialize serial port first /// Initialize serial port first
pub fn init_serial_early() { pub fn early_init() {
// initialize serial driver
serial::init(0xbf000900);
// Enable serial interrupt // Enable serial interrupt
let mut status = cp0::status::read(); let mut status = cp0::status::read();
status.enable_hard_int2(); status.enable_hard_int2();
cp0::status::write(status); cp0::status::write(status);
println!("Hello QEMU Malta!"); info!("Hello QEMU Malta!");
} }
/// Initialize other board drivers /// Initialize other board drivers
pub fn init_driver() { pub fn init(dtb: usize) {
// TODO: add possibly more drivers // TODO: add possibly more drivers
serial::uart16550::driver_init();
vga::init(0xbbe00000, 0xb2050000, 800, 600); vga::init(0xbbe00000, 0xb2050000, 800, 600);
pci::init(); pci::init();
@ -42,4 +41,6 @@ pub fn init_driver() {
screen_size: 800 * 600, screen_size: 800 * 600,
}; };
fb::init(fb_info); fb::init(fb_info);
ide::init();
device_tree::init(dtb);
} }

View File

@ -1,3 +0,0 @@
/// board specific constants
pub const MEMORY_END: usize = 0x8800_0000;
pub const KERNEL_HEAP_SIZE: usize = 0x00a0_0000;

View File

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

View File

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

View File

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

View File

@ -38,3 +38,14 @@ bootstack:
.space 4096 * 16 * 8 .space 4096 * 16 * 8
.global bootstacktop .global bootstacktop
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

View File

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

View File

@ -14,3 +14,5 @@ pub const USER_STACK_SIZE: usize = 0x10000;
pub const MAX_DTB_SIZE: usize = 0x2000; pub const MAX_DTB_SIZE: usize = 0x2000;
pub const KSEG2_START: usize = 0xfe80_0000; pub const KSEG2_START: usize = 0xfe80_0000;
pub const ARCH: &'static str = "mipsel";

View File

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

View File

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

View File

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

View File

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

View File

@ -1,23 +1,21 @@
pub use self::context::*;
use crate::arch::paging::get_root_page_table_ptr; use crate::arch::paging::get_root_page_table_ptr;
use crate::drivers::IRQ_MANAGER; use crate::drivers::IRQ_MANAGER;
use crate::process::thread::Thread;
use alloc::sync::Arc;
use log::*; use log::*;
use mips::addr::*; use mips::addr::*;
use mips::interrupts; use mips::interrupts;
use mips::paging::PageTable as MIPSPageTable; use mips::paging::PageTable as MIPSPageTable;
use mips::registers::cp0; use mips::registers::cp0;
use trapframe::{TrapFrame, UserContext};
#[path = "context.rs"] pub mod consts;
mod context;
/// Initialize interrupt /// Initialize interrupt
pub fn init() { pub fn init() {
extern "C" { unsafe {
fn trap_entry(); 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(); let mut status = cp0::status::read();
// Enable IPI // Enable IPI
@ -61,145 +59,121 @@ pub extern "C" fn stack_pointer_not_aligned(sp: usize) {
/// ///
/// This function is called from `trap.asm`. /// This function is called from `trap.asm`.
#[no_mangle] #[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; use cp0::cause::Exception as E;
trace!("Exception @ CPU{}: {:?} ", 0, tf.cause.cause()); let cause = cp0::cause::Cause {
match tf.cause.cause() { bits: tf.cause as u32,
};
trace!("Exception @ CPU{}: {:?} ", 0, cause.cause());
match cause.cause() {
E::Interrupt => interrupt_dispatcher(tf), E::Interrupt => interrupt_dispatcher(tf),
E::Syscall => syscall(tf), E::Syscall => syscall(tf),
E::TLBModification => page_fault(tf), E::TLBModification => page_fault(tf),
E::TLBLoadMiss => page_fault(tf), E::TLBLoadMiss => page_fault(tf),
E::TLBStoreMiss => 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()); error!("Unhandled Exception @ CPU{}: {:?} ", 0, cause.cause());
crate::trap::error(tf)
} }
} }
trace!("Interrupt end"); trace!("Interrupt end");
} }
fn interrupt_dispatcher(tf: &mut TrapFrame) { 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); trace!(" Interrupt {:08b} ", pint);
if (pint & 0b100_000_00) != 0 { if (pint & 0b100_000_00) != 0 {
timer(); timer();
} else if (pint & 0b011_111_00) != 0 { } 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 { } else {
ipi(); 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() { fn ipi() {
debug!("IPI"); debug!("IPI");
cp0::cause::reset_soft_int0(); cp0::cause::reset_soft_int0();
cp0::cause::reset_soft_int1(); cp0::cause::reset_soft_int1();
} }
fn timer() { pub fn timer() {
super::timer::set_next(); super::timer::set_next();
crate::trap::timer(); crate::trap::timer();
} }
fn syscall(tf: &mut TrapFrame) { fn syscall(tf: &mut TrapFrame) {
tf.epc += 4; // Must before syscall, because of fork. tf.epc += 4; // Must before syscall, because of fork.
let arguments = [tf.a0, tf.a1, tf.a2, tf.a3, tf.t0, tf.t1]; /*
trace!( let arguments = [tf.a0, tf.a1, tf.a2, tf.a3, tf.t0, tf.t1];
"MIPS syscall {} invoked with {:x?}, epc = {:x?}", trace!(
tf.v0, "MIPS syscall {} invoked with {:x?}, epc = {:x?}",
arguments, tf.v0,
tf.epc 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 // comply with mips n32 abi, always return a positive value
// https://git.musl-libc.org/cgit/musl/tree/arch/mipsn32/syscall_arch.h // https://git.musl-libc.org/cgit/musl/tree/arch/mipsn32/syscall_arch.h
if ret < 0 { if ret < 0 {
tf.v0 = (-ret) as usize; tf.general.v0 = (-ret) as usize;
tf.a3 = 1; tf.general.a3 = 1;
} else { } else {
tf.v0 = ret as usize; tf.general.v0 = ret as usize;
tf.a3 = 0; 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 { match rt {
1 => tf.at = val, 1 => tf.general.at = val,
2 => tf.v0 = val, 2 => tf.general.v0 = val,
3 => tf.v1 = val, 3 => tf.general.v1 = val,
4 => tf.a0 = val, 4 => tf.general.a0 = val,
5 => tf.a1 = val, 5 => tf.general.a1 = val,
6 => tf.a2 = val, 6 => tf.general.a2 = val,
7 => tf.a3 = val, 7 => tf.general.a3 = val,
8 => tf.t0 = val, 8 => tf.general.t0 = val,
9 => tf.t1 = val, 9 => tf.general.t1 = val,
10 => tf.t2 = val, 10 => tf.general.t2 = val,
11 => tf.t3 = val, 11 => tf.general.t3 = val,
12 => tf.t4 = val, 12 => tf.general.t4 = val,
13 => tf.t5 = val, 13 => tf.general.t5 = val,
14 => tf.t6 = val, 14 => tf.general.t6 = val,
15 => tf.t7 = val, 15 => tf.general.t7 = val,
16 => tf.s0 = val, 16 => tf.general.s0 = val,
17 => tf.s1 = val, 17 => tf.general.s1 = val,
18 => tf.s2 = val, 18 => tf.general.s2 = val,
19 => tf.s3 = val, 19 => tf.general.s3 = val,
20 => tf.s4 = val, 20 => tf.general.s4 = val,
21 => tf.s5 = val, 21 => tf.general.s5 = val,
22 => tf.s6 = val, 22 => tf.general.s6 = val,
23 => tf.s7 = val, 23 => tf.general.s7 = val,
24 => tf.t8 = val, 24 => tf.general.t8 = val,
25 => tf.t9 = val, 25 => tf.general.t9 = val,
26 => tf.k0 = val, 26 => tf.general.k0 = val,
27 => tf.k1 = val, 27 => tf.general.k1 = val,
28 => tf.gp = val, 28 => tf.general.gp = val,
29 => tf.sp = val, 29 => tf.general.sp = val,
30 => tf.fp = val, 30 => tf.general.fp = val,
31 => tf.ra = val, 31 => tf.general.ra = val,
_ => { _ => {
error!("Unknown register {:?} ", rt); 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 inst = unsafe { *(tf.epc as *const usize) };
let opcode = inst >> 26; let opcode = inst >> 26;
@ -210,20 +184,18 @@ fn reserved_inst(tf: &mut TrapFrame) -> bool {
if inst == 0x42000020 { if inst == 0x42000020 {
// ignore WAIT // ignore WAIT
tf.epc = tf.epc + 4;
return true; return true;
} }
if opcode == 0b011111 && format == 0b111011 { if opcode == 0b011111 && format == 0b111011 {
// RDHWR // RDHWR UserLocal
if rd == 29 && sel == 0 { if rd == 29 && sel == 0 {
extern "C" { let tls = tf.tls;
fn _cur_tls();
}
let tls = unsafe { *(_cur_tls as *const usize) };
set_trapframe_register(rt, tls, tf); 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; return true;
} else { } else {
return false; return false;
@ -233,10 +205,43 @@ fn reserved_inst(tf: &mut TrapFrame) -> bool {
false false
} }
pub fn handle_user_page_fault(thread: &Arc<Thread>, 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) { fn page_fault(tf: &mut TrapFrame) {
// TODO: set access/dirty bit // TODO: set access/dirty bit
let addr = tf.vaddr; let addr = tf.vaddr;
trace!("\nEXCEPTION: Page Fault @ {:#x}", addr); // info!("\nEXCEPTION: Page Fault @ {:#x}", addr);
let virt_addr = VirtAddr::new(addr); let virt_addr = VirtAddr::new(addr);
let root_table = unsafe { &mut *(get_root_page_table_ptr() as *mut MIPSPageTable) }; 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; tf.epc = crate::memory::read_user_fixup as usize;
return; 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; tf.epc = crate::memory::read_user_fixup as usize;
return; 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();
}

View File

@ -1,22 +1,14 @@
//! Input/output for mipsel. //! Input/output for mipsel.
use super::driver::serial::*; use crate::drivers::{console::CONSOLE, SERIAL_DRIVERS};
use crate::drivers::console::CONSOLE;
use core::fmt::{Arguments, Write}; use core::fmt::{Arguments, Write};
pub fn getchar() -> u8 {
unsafe { SERIAL_PORT.force_unlock() }
SERIAL_PORT.lock().getchar()
}
pub fn getchar_option() -> Option<u8> {
unsafe { SERIAL_PORT.force_unlock() }
SERIAL_PORT.lock().getchar_option()
}
pub fn putfmt(fmt: Arguments) { pub fn putfmt(fmt: Arguments) {
unsafe { SERIAL_PORT.force_unlock() } // output to serial
SERIAL_PORT.lock().write_fmt(fmt).unwrap(); let mut drivers = SERIAL_DRIVERS.write();
if let Some(serial) = drivers.first_mut() {
serial.write(format!("{}", fmt).as_bytes());
}
unsafe { CONSOLE.force_unlock() } unsafe { CONSOLE.force_unlock() }
if let Some(console) = CONSOLE.lock().as_mut() { if let Some(console) = CONSOLE.lock().as_mut() {

View File

@ -1,6 +1,7 @@
use crate::arch::paging::*; use crate::arch::paging::*;
use crate::consts::{KERNEL_OFFSET, MEMORY_END, MEMORY_OFFSET}; use crate::consts::{KERNEL_OFFSET, MEMORY_END, MEMORY_OFFSET};
use crate::memory::{init_heap, FRAME_ALLOCATOR}; use crate::memory::{init_heap, FRAME_ALLOCATOR};
use mips::registers::cp0;
use rcore_memory::PAGE_SIZE; use rcore_memory::PAGE_SIZE;
/// Initialize the memory management module /// Initialize the memory management module
@ -9,13 +10,12 @@ pub fn init() {
init_frame_allocator(); init_frame_allocator();
init_heap(); init_heap();
// for debugging
set_root_page_table_ptr(0xFFFF_FFFF); set_root_page_table_ptr(0xFFFF_FFFF);
extern "C" { extern "C" {
fn _root_page_table_buffer(); fn _root_page_table_buffer();
fn _root_page_table_ptr(); fn _root_page_table_ptr();
} }
println!("_root_page_table_ptr {:x}", _root_page_table_ptr as usize);
} }
pub fn init_other() { pub fn init_other() {
@ -37,6 +37,7 @@ fn init_frame_allocator() {
/// Transform memory area `[start, end)` to integer range for `FrameAllocator` /// Transform memory area `[start, end)` to integer range for `FrameAllocator`
fn to_range(start: usize, end: usize) -> Range<usize> { fn to_range(start: usize, end: usize) -> Range<usize> {
info!("frame allocator: start {:#x} end {:#x}", start, end);
let page_start = (start - MEMORY_OFFSET) / PAGE_SIZE; let page_start = (start - MEMORY_OFFSET) / PAGE_SIZE;
let page_end = (end - MEMORY_OFFSET - 1) / PAGE_SIZE + 1; let page_end = (end - MEMORY_OFFSET - 1) / PAGE_SIZE + 1;
assert!(page_start < page_end, "illegal range for frame allocator"); assert!(page_start < page_end, "illegal range for frame allocator");
@ -69,3 +70,13 @@ extern "C" {
fn bootstack(); fn bootstack();
fn bootstacktop(); 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
}

View File

@ -1,11 +1,12 @@
pub mod consts; pub mod consts;
pub mod cpu; pub mod cpu;
pub mod driver; pub mod fp;
pub mod interrupt; pub mod interrupt;
pub mod io; pub mod io;
pub mod memory; pub mod memory;
pub mod paging; pub mod paging;
pub mod rand; pub mod rand;
pub mod signal;
pub mod syscall; pub mod syscall;
pub mod timer; pub mod timer;
@ -15,10 +16,6 @@ use mips::registers::cp0;
#[path = "board/malta/mod.rs"] #[path = "board/malta/mod.rs"]
pub mod board; pub mod board;
#[cfg(feature = "board_mipssim")]
#[path = "board/mipssim/mod.rs"]
pub mod board;
#[no_mangle] #[no_mangle]
pub extern "C" fn rust_main() -> ! { pub extern "C" fn rust_main() -> ! {
// unsafe { cpu::set_cpu_id(hartid); } // unsafe { cpu::set_cpu_id(hartid); }
@ -30,7 +27,6 @@ pub extern "C" fn rust_main() -> ! {
if cpu_id != BOOT_CPU_ID { if cpu_id != BOOT_CPU_ID {
// TODO: run others_main on other CPU // TODO: run others_main on other CPU
// while unsafe { !cpu::has_started(hartid) } { } // while unsafe { !cpu::has_started(hartid) } { }
// println!("Hello RISCV! in hart {}, dtb @ {:#x}", hartid, dtb);
// others_main(); // others_main();
loop {} loop {}
} }
@ -39,17 +35,17 @@ pub extern "C" fn rust_main() -> ! {
memory::clear_bss(); memory::clear_bss();
} }
board::init_serial_early(); board::early_init();
crate::logging::init(); crate::logging::init();
interrupt::init(); interrupt::init();
memory::init(); memory::init();
timer::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(); crate::process::init();
// TODO: start other CPU // TODO: start other CPU
@ -68,6 +64,4 @@ fn others_main() -> ! {
const BOOT_CPU_ID: u32 = 0; 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/entry.gen.s"));
global_asm!(include_str!("boot/trap.gen.s"));

View File

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

View File

@ -1,3 +1,4 @@
use core::time::Duration;
use log::*; use log::*;
use mips::registers::cp0; use mips::registers::cp0;
@ -17,3 +18,8 @@ pub fn set_next() {
cp0::count::write_u32(0); cp0::count::write_u32(0);
cp0::compare::write_u32(timebase); cp0::compare::write_u32(timebase);
} }
pub fn timer_now() -> Duration {
// TODO
Duration::from_nanos(0)
}

View File

@ -15,7 +15,7 @@ pub const MEMORY_OFFSET: usize = 0x8000_0000;
// TODO: get memory end from device tree // TODO: get memory end from device tree
pub const MEMORY_END: usize = 0x8800_0000; 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_OFFSET: usize = 0x40000000 - USER_STACK_SIZE;
pub const USER_STACK_SIZE: usize = 0x10000; pub const USER_STACK_SIZE: usize = 0x10000;

View File

@ -13,3 +13,19 @@ pub const SupervisorExternal: usize = usize::MAX / 2 + 1 + 8;
pub fn is_page_fault(trap: usize) -> bool { pub fn is_page_fault(trap: usize) -> bool {
trap == InstructionPageFault || trap == LoadPageFault || trap == StorePageFault 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
}

View File

@ -1,5 +1,7 @@
use crate::arch::interrupt::consts::SupervisorExternal; use crate::arch::interrupt::consts::SupervisorExternal;
use crate::drivers::IRQ_MANAGER; use crate::drivers::IRQ_MANAGER;
use crate::process::thread::Thread;
use alloc::sync::Arc;
use log::*; use log::*;
use riscv::register::*; use riscv::register::*;
use riscv::register::{scause::Scause, sscratch, stvec}; use riscv::register::{scause::Scause, sscratch, stvec};
@ -113,3 +115,11 @@ pub fn wait_for_interrupt() {
} }
} }
} }
pub fn handle_user_page_fault(thread: &Arc<Thread>, addr: usize) -> bool {
thread.vm.lock().handle_page_fault(addr)
}
pub fn handle_reserved_inst(tf: &mut UserContext) -> bool {
false
}

View File

@ -42,7 +42,7 @@ pub extern "C" fn rust_main(hartid: usize, device_tree_paddr: usize) -> ! {
memory::clear_bss(); memory::clear_bss();
} }
println!( info!(
"Hello RISCV! in hart {}, device tree @ {:#x}", "Hello RISCV! in hart {}, device tree @ {:#x}",
hartid, device_tree_vaddr 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); memory::init(device_tree_vaddr);
timer::init(); timer::init();
// FIXME: init driver on u540 // TODO: init driver on u540
#[cfg(not(any(feature = "board_u540")))] #[cfg(not(any(feature = "board_u540")))]
board::init(device_tree_vaddr); board::init(device_tree_vaddr);
unsafe { unsafe {

View File

@ -39,7 +39,7 @@ pub const SYS_MKDIRAT: usize = 34;
pub const SYS_UNLINKAT: usize = 35; pub const SYS_UNLINKAT: usize = 35;
pub const SYS_SYMLINKAT: usize = 36; pub const SYS_SYMLINKAT: usize = 36;
pub const SYS_LINKAT: usize = 37; 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_UMOUNT2: usize = 39;
pub const SYS_MOUNT: usize = 40; pub const SYS_MOUNT: usize = 40;
pub const SYS_PIVOT_ROOT: usize = 41; pub const SYS_PIVOT_ROOT: usize = 41;

View File

@ -49,3 +49,19 @@ pub const IPIFuncCall: usize = 0xfc;
pub fn is_page_fault(trap: usize) -> bool { pub fn is_page_fault(trap: usize) -> bool {
trap == PageFault 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
}

View File

@ -3,6 +3,8 @@ mod handler;
pub use self::handler::*; pub use self::handler::*;
use crate::memory::phys_to_virt; use crate::memory::phys_to_virt;
use crate::process::thread::Thread;
use alloc::sync::Arc;
use apic::*; use apic::*;
use trapframe::{TrapFrame, UserContext}; 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::enable_interrupts_and_hlt();
x86_64::instructions::interrupts::disable(); x86_64::instructions::interrupts::disable();
} }
pub fn handle_user_page_fault(thread: &Arc<Thread>, addr: usize) -> bool {
thread.vm.lock().handle_page_fault(addr)
}
pub fn handle_reserved_inst(tf: &mut UserContext) -> bool {
false
}

View File

@ -284,7 +284,7 @@ impl FrameDeallocator<Size4KiB> for FrameAllocatorForX86 {
/// Flush TLB for `vaddr` on all CPU /// Flush TLB for `vaddr` on all CPU
fn flush_tlb_all(_vaddr: usize) { fn flush_tlb_all(_vaddr: usize) {
// FIXME: too slow, disable now. // TODO: too slow, disable now.
return; return;
// if !super::AP_CAN_INIT.load(Ordering::Relaxed) { // if !super::AP_CAN_INIT.load(Ordering::Relaxed) {
// return; // return;

View File

@ -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<IDE>);
impl Driver for IDEDriver {
fn try_handle_interrupt(&self, _irq: Option<usize>) -> 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());
}

View File

@ -1,6 +1,7 @@
use super::Driver; use super::Driver;
pub mod ahci; pub mod ahci;
pub mod ide;
pub mod virtio_blk; pub mod virtio_blk;
pub trait BlockDriver: Driver { pub trait BlockDriver: Driver {

View File

@ -13,7 +13,7 @@ pub static CONSOLE: Mutex<Option<RCoreConsole>> = Mutex::new(None);
pub fn init() { pub fn init() {
if cfg!(feature = "consolegraphic") { if cfg!(feature = "consolegraphic") {
if let Some(fb) = FRAME_BUFFER.write().take() { 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); let console = Console::on_frame_buffer(fb.fb_info.xres, fb.fb_info.yres, fb);
*CONSOLE.lock() = Some(console); *CONSOLE.lock() = Some(console);
info!("console: init end"); info!("console: init end");

View File

@ -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::<u8>(self.base + COM_LSR) & 0x01) == 0 {
break;
}
}
let c = read::<u8>(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<char> {
match read::<u8>(self.base + COM_LSR) & 0x01 {
0 => None,
_ => Some(read::<u8>(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<SerialPort> = Mutex::new(SerialPort::new());
}
pub fn init(base: usize) {
SERIAL_PORT.lock().init(base);
}

View File

@ -16,6 +16,7 @@ use device_tree::Node;
pub struct SerialPort { pub struct SerialPort {
base: usize, base: usize,
multiplier: usize,
} }
impl Driver for SerialPort { impl Driver for SerialPort {
@ -38,8 +39,11 @@ impl Driver for SerialPort {
} }
impl SerialPort { impl SerialPort {
fn new(base: usize) -> SerialPort { fn new(base: usize, shift: usize) -> SerialPort {
let mut res = SerialPort { base: 0 }; let mut res = SerialPort {
base: 0,
multiplier: 1 << shift,
};
res.init(base); res.init(base);
res res
} }
@ -47,39 +51,42 @@ impl SerialPort {
pub fn init(&mut self, base: usize) { pub fn init(&mut self, base: usize) {
self.base = base; self.base = base;
// Turn off the FIFO // 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 // Set speed; requires DLAB latch
write(self.base + COM_LCR, COM_LCR_DLAB); write(self.base + COM_LCR * self.multiplier, COM_LCR_DLAB);
write(self.base + COM_DLL, (115200 / 9600) as u8); //write(self.base + COM_DLL * self.multiplier, (115200 / 9600) as u8);
write(self.base + COM_DLM, 0 as u8); //write(self.base + COM_DLM * self.multiplier, 0 as u8);
// 8 data bits, 1 stop bit, parity off; turn off DLAB latch // 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 // No modem controls
write(self.base + COM_MCR, 0 as u8); write(self.base + COM_MCR * self.multiplier, 0 as u8);
// Enable rcv interrupts // 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() /// non-blocking version of putchar()
pub fn putchar(&self, c: u8) { pub fn putchar(&self, c: u8) {
for _ in 0..100 { for _ in 0..100 {
if (read::<u8>(self.base + COM_LSR) & COM_LSR_TXRDY) == 0 { if (read::<u8>(self.base + COM_LSR * self.multiplier) & COM_LSR_TXRDY) == 0 {
break; break;
} }
} }
write(self.base + COM_TX, c); write(self.base + COM_TX * self.multiplier, c);
} }
/// blocking version of getchar() /// blocking version of getchar()
pub fn getchar(&mut self) -> u8 { pub fn getchar(&mut self) -> u8 {
loop { loop {
if (read::<u8>(self.base + COM_LSR) & COM_LSR_DATA) == 0 { if (read::<u8>(self.base + COM_LSR * self.multiplier) & COM_LSR_DATA) == 0 {
break; break;
} }
} }
let c = read::<u8>(self.base + COM_RX); let c = read::<u8>(self.base + COM_RX * self.multiplier);
match c { match c {
255 => b'\0', // null 255 => b'\0', // null
c => c, c => c,
@ -88,9 +95,9 @@ impl SerialPort {
/// non-blocking version of getchar() /// non-blocking version of getchar()
pub fn getchar_option(&self) -> Option<u8> { pub fn getchar_option(&self) -> Option<u8> {
match read::<u8>(self.base + COM_LSR) & COM_LSR_DATA { match read::<u8>(self.base + COM_LSR * self.multiplier) & COM_LSR_DATA {
0 => None, 0 => None,
_ => Some(read::<u8>(self.base + COM_RX) as u8), _ => Some(read::<u8>(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 const COM_LSR_TSRE: u8 = 0x40; // Transmitter off
pub fn init_dt(dt: &Node) { 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); let base = phys_to_virt(addr);
info!("Init uart16550 at {:#x}", base); 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 mut found = false;
let irq_opt = dt.prop_u32("interrupts").ok().map(|irq| irq as usize); let irq_opt = dt.prop_u32("interrupts").ok().map(|irq| irq as usize);
DRIVERS.write().push(com.clone()); DRIVERS.write().push(com.clone());

View File

@ -113,7 +113,7 @@ impl FileHandle {
pub async fn read_at(&self, offset: usize, buf: &mut [u8]) -> Result<usize> { pub async fn read_at(&self, offset: usize, buf: &mut [u8]) -> Result<usize> {
// let options = &self.description.read().options; // let options = &self.description.read().options;
if !self.description.read().options.read { if !self.description.read().options.read {
return Err(FsError::InvalidParam); // FIXME: => EBADF return Err(FsError::InvalidParam); // TODO: => EBADF
} }
if !self.description.read().options.nonblock { if !self.description.read().options.nonblock {
// block // block
@ -150,7 +150,7 @@ impl FileHandle {
pub fn write_at(&self, offset: usize, buf: &[u8]) -> Result<usize> { pub fn write_at(&self, offset: usize, buf: &[u8]) -> Result<usize> {
if !self.description.read().options.write { 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)?; let len = self.inode.write_at(offset, buf)?;
TimeSpec::update(&self.inode); TimeSpec::update(&self.inode);
@ -169,7 +169,7 @@ impl FileHandle {
pub fn set_len(&mut self, len: u64) -> Result<()> { pub fn set_len(&mut self, len: u64) -> Result<()> {
if !self.description.read().options.write { if !self.description.read().options.write {
return Err(FsError::InvalidParam); // FIXME: => EBADF return Err(FsError::InvalidParam); // TODO: => EBADF
} }
self.inode.resize(len as usize)?; self.inode.resize(len as usize)?;
Ok(()) Ok(())
@ -194,7 +194,7 @@ impl FileHandle {
pub fn read_entry(&mut self) -> Result<String> { pub fn read_entry(&mut self) -> Result<String> {
let mut description = self.description.write(); let mut description = self.description.write();
if !description.options.read { if !description.options.read {
return Err(FsError::InvalidParam); // FIXME: => EBADF return Err(FsError::InvalidParam); // TODO: => EBADF
} }
let mut offset = &mut description.offset; let mut offset = &mut description.offset;
let name = self.inode.get_entry(*offset as usize)?; 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)> { pub fn read_entry_with_metadata(&mut self) -> Result<(Metadata, String)> {
let mut description = self.description.write(); let mut description = self.description.write();
if !description.options.read { if !description.options.read {
return Err(FsError::InvalidParam); // FIXME: => EBADF return Err(FsError::InvalidParam); // TODO: => EBADF
} }
let mut offset = &mut description.offset; let mut offset = &mut description.offset;
let ret = self.inode.get_entry_with_metadata(*offset as usize)?; let ret = self.inode.get_entry_with_metadata(*offset as usize)?;

View File

@ -13,7 +13,7 @@ pub const TCGETS: usize = 0x540D;
#[cfg(not(target_arch = "mips"))] #[cfg(not(target_arch = "mips"))]
pub const TCSETS: usize = 0x5402; pub const TCSETS: usize = 0x5402;
#[cfg(target_arch = "mips")] #[cfg(target_arch = "mips")]
pub const TCGETS: usize = 0x540E; pub const TCSETS: usize = 0x540E;
#[cfg(not(target_arch = "mips"))] #[cfg(not(target_arch = "mips"))]
pub const TIOCGPGRP: usize = 0x540F; pub const TIOCGPGRP: usize = 0x540F;

View File

@ -8,6 +8,7 @@
#![feature(negative_impls)] #![feature(negative_impls)]
#![feature(alloc_prelude)] #![feature(alloc_prelude)]
#![feature(const_fn)] #![feature(const_fn)]
#![feature(const_if_match)]
#![feature(const_in_array_repeat_expressions)] #![feature(const_in_array_repeat_expressions)]
#![deny(unused_must_use)] #![deny(unused_must_use)]
#![deny(stable_features)] #![deny(stable_features)]

View File

@ -32,10 +32,22 @@ pub static FRAME_ALLOCATOR: SpinNoIrqLock<FrameAlloc> = SpinNoIrqLock::new(Frame
/// Convert physical address to virtual address /// Convert physical address to virtual address
#[inline] #[inline]
#[cfg(not(mipsel))]
pub const fn phys_to_virt(paddr: usize) -> usize { pub const fn phys_to_virt(paddr: usize) -> usize {
PHYSICAL_MEMORY_OFFSET + paddr 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 /// Convert virtual address to physical address
#[inline] #[inline]
pub const fn virt_to_phys(vaddr: usize) -> usize { pub const fn virt_to_phys(vaddr: usize) -> usize {

View File

@ -527,7 +527,7 @@ impl Socket for UdpSocketState {
match request { match request {
// SIOCGARP // SIOCGARP
0x8954 => { 0x8954 => {
// FIXME: check addr // TODO: check addr
let req = unsafe { &mut *(arg1 as *mut ArpReq) }; let req = unsafe { &mut *(arg1 as *mut ArpReq) };
if let AddressFamily::Internet = AddressFamily::from(req.arp_pa.family) { if let AddressFamily::Internet = AddressFamily::from(req.arp_pa.family) {
let name = req.arp_dev.as_ptr(); let name = req.arp_dev.as_ptr();

View File

@ -2,8 +2,10 @@ use super::{
abi::{self, ProcInitInfo}, abi::{self, ProcInitInfo},
add_to_process_table, Pid, Process, PROCESSORS, add_to_process_table, Pid, Process, PROCESSORS,
}; };
use crate::arch::interrupt::consts::{is_page_fault, IrqMax, IrqMin, Syscall, Timer}; use crate::arch::interrupt::consts::{
use crate::arch::interrupt::get_trap_num; 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::{ use crate::arch::{
cpu, cpu,
fp::FpState, fp::FpState,
@ -307,6 +309,15 @@ impl Thread {
// F | A | D | EL0 // F | A | D | EL0
context.spsr = 0b1101_00_0000; 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 { let thread = Thread {
tid: 0, // allocated below tid: 0, // allocated below
@ -499,27 +510,37 @@ pub fn spawn(thread: Arc<Thread>) {
trace!("back from user: {:#x?} trap_num {:#x}", cx, trap_num); trace!("back from user: {:#x?} trap_num {:#x}", cx, trap_num);
let mut exit = false; let mut exit = false;
let mut do_yield = false;
match trap_num { match trap_num {
// must be first // must be first
_ if is_page_fault(trap_num) => { _ if is_page_fault(trap_num) => {
// page fault // page fault
let addr = get_page_fault_addr(); 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 // TODO: SIGSEGV
panic!("page fault handle failed"); panic!("page fault handle failed");
} }
} }
Syscall => exit = handle_syscall(&thread, cx).await, _ if is_syscall(trap_num) => exit = handle_syscall(&thread, cx).await,
IrqMin..=IrqMax => { _ if is_intr(trap_num) => {
crate::arch::interrupt::ack(trap_num); crate::arch::interrupt::ack(trap_num);
trace!("handle irq {:#x}", 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(); crate::arch::interrupt::timer();
} }
IRQ_MANAGER.read().try_handle_interrupt(Some(trap_num)); 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!( panic!(
"unhandled trap in thread {} trap {:#x} {:x?}", "unhandled trap in thread {} trap {:#x} {:x?}",
@ -537,7 +558,7 @@ pub fn spawn(thread: Arc<Thread>) {
if exit { if exit {
info!("thread {} stopped", thread.tid); info!("thread {} stopped", thread.tid);
break; break;
} else { } else if do_yield {
yield_now().await; yield_now().await;
} }
} }

View File

@ -172,7 +172,7 @@ pub fn handle_signal(thread: &Arc<Thread>, tf: &mut UserContext) -> bool {
match signal { match signal {
SIGALRM | SIGHUP | SIGINT => { SIGALRM | SIGHUP | SIGINT => {
info!("default action: Term"); info!("default action: Term");
// FIXME: exit code ref please? // TODO: exit code ref please?
process.exit(info.signo as usize + 128); process.exit(info.signo as usize + 128);
return true; return true;
} }

View File

@ -1194,7 +1194,7 @@ impl Syscall<'_> {
if times[0].nsec == UTIME_NOW { if times[0].nsec == UTIME_NOW {
times[0] = TimeSpec::get_epoch(); times[0] = TimeSpec::get_epoch();
} }
metadata.atime = Timespec { metadata.atime = rcore_fs::vfs::Timespec {
sec: times[0].sec as i64, sec: times[0].sec as i64,
nsec: times[0].nsec as i32, nsec: times[0].nsec as i32,
}; };
@ -1203,7 +1203,7 @@ impl Syscall<'_> {
if times[1].nsec == UTIME_NOW { if times[1].nsec == UTIME_NOW {
times[1] = TimeSpec::get_epoch(); times[1] = TimeSpec::get_epoch();
} }
metadata.mtime = Timespec { metadata.mtime = rcore_fs::vfs::Timespec {
sec: times[1].sec as i64, sec: times[1].sec as i64,
nsec: times[1].nsec as i32, nsec: times[1].nsec as i32,
}; };

View File

@ -81,7 +81,7 @@ impl Syscall<'_> {
); );
let _attr = prot.to_attr(); 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 // now some mut ptr check is fault
let vm = self.vm(); let vm = self.vm();
let memory_area = vm let memory_area = vm
@ -147,7 +147,7 @@ impl MmapProt {
if self.contains(MmapProt::EXEC) { if self.contains(MmapProt::EXEC) {
attr = attr.execute(); attr = attr.execute();
} }
// FIXME: see sys_mprotect // TODO: see sys_mprotect
// if !self.contains(MmapProt::WRITE) { attr = attr.readonly(); } // if !self.contains(MmapProt::WRITE) { attr = attr.readonly(); }
attr attr
} }

View File

@ -56,11 +56,17 @@ pub async fn handle_syscall(thread: &Arc<Thread>, context: &mut UserContext) ->
let regs = &context.general; let regs = &context.general;
let num = context.get_syscall_num(); let num = context.get_syscall_num();
let args = context.get_syscall_args(); let args = context.get_syscall_args();
// add before fork // add before fork
#[cfg(riscv)] #[cfg(riscv)]
{ {
context.sepc = context.sepc + 4; context.sepc = context.sepc + 4;
} }
#[cfg(mipsel)]
{
context.epc = context.epc + 4;
}
let mut syscall = Syscall { let mut syscall = Syscall {
thread, thread,
context, context,
@ -355,9 +361,12 @@ impl Syscall<'_> {
} }
#[cfg(not(target_arch = "mips"))] #[cfg(not(target_arch = "mips"))]
SYS_SEMCTL => self.sys_semctl(args[0], args[1], args[2], args[3]), 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)), SYS_MSGGET => self.unimplemented("msgget", Ok(0)),
#[cfg(target_arch = "mips")] #[cfg(not(target_arch = "mips"))]
SYS_SHMGET => self.unimplemented("shmget", Ok(0)), SYS_MSGCTL => self.unimplemented("msgctl", Ok(0)),
// shm // shm
#[cfg(not(target_arch = "mips"))] #[cfg(not(target_arch = "mips"))]
@ -426,14 +435,13 @@ impl Syscall<'_> {
SYS_GET_PADDR => { SYS_GET_PADDR => {
self.sys_get_paddr(args[0] as *const u64, args[1] as *mut u64, args[2]) 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 () { let ret = match () {
#[cfg(target_arch = "x86_64")] #[cfg(target_arch = "x86_64")]
() => self.x86_64_syscall(id, args).await, () => self.x86_64_syscall(id, args).await,
#[cfg(target_arch = "mips")] #[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")))] #[cfg(all(not(target_arch = "x86_64"), not(target_arch = "mips")))]
() => None, () => None,
}; };
@ -474,10 +482,13 @@ impl Syscall<'_> {
} }
#[cfg(target_arch = "mips")] #[cfg(target_arch = "mips")]
fn mips_syscall(&mut self, id: usize, args: [usize; 6]) -> Option<SysResult> { async fn mips_syscall(&mut self, id: usize, args: [usize; 6]) -> Option<SysResult> {
let ret = match id { let ret = match id {
SYS_OPEN => self.sys_open(args[0] as *const u8, args[1], args[2]), 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_DUP2 => self.sys_dup2(args[0], args[1]),
SYS_FORK => self.sys_fork(), SYS_FORK => self.sys_fork(),
SYS_MMAP2 => self.sys_mmap(args[0], args[1], args[2], args[3], args[4], args[5] * 4096), 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) { match self.sys_pipe(fd_ptr) {
Ok(_code) => { Ok(_code) => {
unsafe { unsafe {
self.tf.v0 = *fd_ptr as usize; self.context.general.v0 = *fd_ptr as usize;
self.tf.v1 = *(fd_ptr.add(1)) 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), Err(err) => Err(err),
} }
@ -500,19 +511,15 @@ impl Syscall<'_> {
SYS_FCNTL64 => self.unimplemented("fcntl64", Ok(0)), SYS_FCNTL64 => self.unimplemented("fcntl64", Ok(0)),
SYS_SET_THREAD_AREA => { SYS_SET_THREAD_AREA => {
info!("set_thread_area: tls: 0x{:x}", args[0]); info!("set_thread_area: tls: 0x{:x}", args[0]);
extern "C" { self.context.tls = args[0];
fn _cur_tls();
}
unsafe {
llvm_asm!("mtc0 $0, $$4, 2": :"r"(args[0]));
*(_cur_tls as *mut usize) = args[0];
}
Ok(0) Ok(0)
} }
SYS_IPC => match args[0] { SYS_IPC => match args[0] {
1 => self.sys_semop(args[1], UserInPtr::from(args[2]), args[3]), 1 => {
2 => self.sys_semget(args[1], args[2] as isize, args[3]), 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]), 3 => self.sys_semctl(args[1], args[2], args[3], args[4]),
_ => return None, _ => return None,
}, },

View File

@ -350,7 +350,7 @@ impl Syscall<'_> {
// perform futex wake 1 // perform futex wake 1
// ref: http://man7.org/linux/man-pages/man2/set_tid_address.2.html // 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? // 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; let clear_child_tid = self.thread.inner.lock().clear_child_tid as *mut u32;
if !clear_child_tid.is_null() { if !clear_child_tid.is_null() {

View File

@ -38,7 +38,7 @@ impl<T, P: Policy> Debug for UserPtr<T, P> {
} }
} }
// FIXME: this is a workaround for `clear_child_tid`. // TODO: this is a workaround for `clear_child_tid`.
unsafe impl<T, P: Policy> Send for UserPtr<T, P> {} unsafe impl<T, P: Policy> Send for UserPtr<T, P> {}
unsafe impl<T, P: Policy> Sync for UserPtr<T, P> {} unsafe impl<T, P: Policy> Sync for UserPtr<T, P> {}

2
user

@ -1 +1 @@
Subproject commit 291df7f66ed42f642cd691554fa0c88e59cdb894 Subproject commit 63342746297b9694676c82a716601d736ebab1a1