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:
|
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
4
kernel/Cargo.lock
generated
@ -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",
|
||||||
|
@ -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"
|
||||||
|
@ -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
|
||||||
|
@ -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");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -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
|
||||||
|
|
||||||
|
@ -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";
|
||||||
|
@ -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
|
||||||
|
}
|
||||||
|
@ -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
|
||||||
|
}
|
||||||
|
@ -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;
|
||||||
|
@ -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>;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -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);
|
||||||
}
|
}
|
||||||
|
@ -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
|
.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
|
||||||
|
@ -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 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";
|
||||||
|
@ -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::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();
|
||||||
|
}
|
@ -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() {
|
||||||
|
@ -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
|
||||||
|
}
|
||||||
|
@ -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"));
|
|
||||||
|
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 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)
|
||||||
|
}
|
||||||
|
@ -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;
|
||||||
|
|
||||||
|
@ -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
|
||||||
|
}
|
||||||
|
@ -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
|
||||||
|
}
|
||||||
|
@ -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 {
|
||||||
|
@ -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;
|
||||||
|
@ -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
|
||||||
|
}
|
||||||
|
@ -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
|
||||||
|
}
|
||||||
|
@ -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;
|
||||||
|
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;
|
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 {
|
||||||
|
@ -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");
|
||||||
|
@ -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 {
|
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());
|
||||||
|
@ -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)?;
|
||||||
|
@ -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;
|
||||||
|
@ -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)]
|
||||||
|
@ -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 {
|
||||||
|
@ -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();
|
||||||
|
@ -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;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -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;
|
||||||
}
|
}
|
||||||
|
@ -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,
|
||||||
};
|
};
|
||||||
|
@ -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
|
||||||
}
|
}
|
||||||
|
@ -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,
|
||||||
},
|
},
|
||||||
|
@ -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() {
|
||||||
|
@ -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
2
user
@ -1 +1 @@
|
|||||||
Subproject commit 291df7f66ed42f642cd691554fa0c88e59cdb894
|
Subproject commit 63342746297b9694676c82a716601d736ebab1a1
|
Loading…
Reference in New Issue
Block a user