mirror of
https://github.com/rcore-os/rCore.git
synced 2024-11-22 08:06:17 +04:00
commit
d3ab8c58ad
2
.github/workflows/main.yml
vendored
2
.github/workflows/main.yml
vendored
@ -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
|
||||
|
4
kernel/Cargo.lock
generated
4
kernel/Cargo.lock
generated
@ -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",
|
||||
|
@ -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"
|
||||
|
@ -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
|
||||
|
@ -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");
|
||||
}
|
||||
}
|
||||
|
@ -30,14 +30,13 @@
|
||||
- fn ack(trap: usize):确认中断处理
|
||||
- fn timer():处理时钟中断
|
||||
- fn wait_for_interrupt():打开并等待中断
|
||||
- fn handle_user_page_fault(thread: &Arc\<Thread\>, 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
|
||||
|
||||
|
@ -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";
|
||||
|
@ -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
|
||||
}
|
||||
|
@ -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<Thread>, addr: usize) -> bool {
|
||||
thread.vm.lock().handle_page_fault(addr)
|
||||
}
|
||||
|
||||
pub fn handle_reserved_inst(tf: &mut UserContext) -> bool {
|
||||
false
|
||||
}
|
||||
|
@ -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;
|
||||
|
@ -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>;
|
||||
};
|
||||
|
||||
|
@ -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);
|
||||
}
|
||||
|
@ -1,3 +0,0 @@
|
||||
/// board specific constants
|
||||
pub const MEMORY_END: usize = 0x8800_0000;
|
||||
pub const KERNEL_HEAP_SIZE: usize = 0x00a0_0000;
|
@ -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>;
|
||||
};
|
||||
|
||||
};
|
@ -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();
|
||||
}
|
@ -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
|
@ -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
|
||||
|
@ -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
|
@ -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";
|
||||
|
@ -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)
|
||||
}
|
||||
}
|
@ -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();
|
||||
}
|
14
kernel/src/arch/mipsel/fp.rs
Normal file
14
kernel/src/arch/mipsel/fp.rs
Normal 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) {}
|
||||
}
|
46
kernel/src/arch/mipsel/interrupt/consts.rs
Normal file
46
kernel/src/arch/mipsel/interrupt/consts.rs
Normal 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,
|
||||
}
|
||||
}
|
@ -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<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) {
|
||||
// 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();
|
||||
}
|
@ -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<u8> {
|
||||
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() {
|
||||
|
@ -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<usize> {
|
||||
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
|
||||
}
|
||||
|
@ -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"));
|
||||
|
36
kernel/src/arch/mipsel/signal.rs
Normal file
36
kernel/src/arch/mipsel/signal.rs
Normal 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;
|
||||
}
|
@ -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)
|
||||
}
|
||||
|
@ -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;
|
||||
|
||||
|
@ -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
|
||||
}
|
||||
|
@ -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<Thread>, addr: usize) -> bool {
|
||||
thread.vm.lock().handle_page_fault(addr)
|
||||
}
|
||||
|
||||
pub fn handle_reserved_inst(tf: &mut UserContext) -> bool {
|
||||
false
|
||||
}
|
||||
|
@ -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 {
|
||||
|
@ -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;
|
||||
|
@ -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
|
||||
}
|
||||
|
@ -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<Thread>, addr: usize) -> bool {
|
||||
thread.vm.lock().handle_page_fault(addr)
|
||||
}
|
||||
|
||||
pub fn handle_reserved_inst(tf: &mut UserContext) -> bool {
|
||||
false
|
||||
}
|
||||
|
@ -284,7 +284,7 @@ impl FrameDeallocator<Size4KiB> 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;
|
||||
|
252
kernel/src/drivers/block/ide.rs
Normal file
252
kernel/src/drivers/block/ide.rs
Normal 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());
|
||||
}
|
@ -1,6 +1,7 @@
|
||||
use super::Driver;
|
||||
|
||||
pub mod ahci;
|
||||
pub mod ide;
|
||||
pub mod virtio_blk;
|
||||
|
||||
pub trait BlockDriver: Driver {
|
||||
|
@ -13,7 +13,7 @@ pub static CONSOLE: Mutex<Option<RCoreConsole>> = 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");
|
||||
|
@ -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);
|
||||
}
|
@ -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::<u8>(self.base + COM_LSR) & COM_LSR_TXRDY) == 0 {
|
||||
if (read::<u8>(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::<u8>(self.base + COM_LSR) & COM_LSR_DATA) == 0 {
|
||||
if (read::<u8>(self.base + COM_LSR * self.multiplier) & COM_LSR_DATA) == 0 {
|
||||
break;
|
||||
}
|
||||
}
|
||||
let c = read::<u8>(self.base + COM_RX);
|
||||
let c = read::<u8>(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<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,
|
||||
_ => 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
|
||||
|
||||
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());
|
||||
|
@ -113,7 +113,7 @@ impl FileHandle {
|
||||
pub async fn read_at(&self, offset: usize, buf: &mut [u8]) -> Result<usize> {
|
||||
// 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<usize> {
|
||||
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<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 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)?;
|
||||
|
@ -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;
|
||||
|
@ -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)]
|
||||
|
@ -32,10 +32,22 @@ pub static FRAME_ALLOCATOR: SpinNoIrqLock<FrameAlloc> = 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 {
|
||||
|
@ -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();
|
||||
|
@ -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<Thread>) {
|
||||
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<Thread>) {
|
||||
if exit {
|
||||
info!("thread {} stopped", thread.tid);
|
||||
break;
|
||||
} else {
|
||||
} else if do_yield {
|
||||
yield_now().await;
|
||||
}
|
||||
}
|
||||
|
@ -172,7 +172,7 @@ pub fn handle_signal(thread: &Arc<Thread>, 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;
|
||||
}
|
||||
|
@ -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,
|
||||
};
|
||||
|
@ -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
|
||||
}
|
||||
|
@ -56,11 +56,17 @@ pub async fn handle_syscall(thread: &Arc<Thread>, 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<SysResult> {
|
||||
async fn mips_syscall(&mut self, id: usize, args: [usize; 6]) -> Option<SysResult> {
|
||||
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,
|
||||
},
|
||||
|
@ -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() {
|
||||
|
@ -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> Sync for UserPtr<T, P> {}
|
||||
|
||||
|
2
user
2
user
@ -1 +1 @@
|
||||
Subproject commit 291df7f66ed42f642cd691554fa0c88e59cdb894
|
||||
Subproject commit 63342746297b9694676c82a716601d736ebab1a1
|
Loading…
Reference in New Issue
Block a user