mirror of
https://github.com/rcore-os/rCore-Tutorial-v3.git
synced 2024-11-22 01:16:26 +04:00
Merge branch 'ch9-net-dev' of github.com:yfblock/rCore-Tutorial-v3 into main
This commit is contained in:
commit
4a62741c46
@ -10,10 +10,12 @@ edition = "2021"
|
|||||||
riscv = { git = "https://github.com/rcore-os/riscv", features = ["inline-asm"] }
|
riscv = { git = "https://github.com/rcore-os/riscv", features = ["inline-asm"] }
|
||||||
lazy_static = { version = "1.4.0", features = ["spin_no_std"] }
|
lazy_static = { version = "1.4.0", features = ["spin_no_std"] }
|
||||||
buddy_system_allocator = "0.6"
|
buddy_system_allocator = "0.6"
|
||||||
|
bit_field = "0.10.0"
|
||||||
bitflags = "1.2.1"
|
bitflags = "1.2.1"
|
||||||
xmas-elf = "0.7.0"
|
xmas-elf = "0.7.0"
|
||||||
volatile = "0.3"
|
volatile = "0.3"
|
||||||
virtio-drivers = { git = "https://github.com/rcore-os/virtio-drivers", rev = "4ee80e5" }
|
virtio-drivers = { git = "https://github.com/rcore-os/virtio-drivers", rev = "4ee80e5" }
|
||||||
|
lose-net-stack = { git = "https://github.com/yfblock/lose-net-stack", rev = "3f467dd" }
|
||||||
easy-fs = { path = "../easy-fs" }
|
easy-fs = { path = "../easy-fs" }
|
||||||
embedded-graphics = "0.7.1"
|
embedded-graphics = "0.7.1"
|
||||||
tinybmp = "0.3.1"
|
tinybmp = "0.3.1"
|
||||||
|
32
os/Makefile
32
os/Makefile
@ -24,7 +24,7 @@ ifeq ($(MODE), release)
|
|||||||
endif
|
endif
|
||||||
|
|
||||||
# KERNEL ENTRY
|
# KERNEL ENTRY
|
||||||
KERNEL_ENTRY_PA := 0x80200000
|
KERNEL_ENTRY_PA := 0x80000000
|
||||||
|
|
||||||
# Binutils
|
# Binutils
|
||||||
OBJDUMP := rust-objdump --arch-name=riscv64
|
OBJDUMP := rust-objdump --arch-name=riscv64
|
||||||
@ -73,6 +73,22 @@ disasm-vim: kernel
|
|||||||
|
|
||||||
run: run-inner
|
run: run-inner
|
||||||
|
|
||||||
|
run-inner-none: build
|
||||||
|
@qemu-system-riscv64 \
|
||||||
|
-M 128m \
|
||||||
|
-machine virt \
|
||||||
|
-bios none \
|
||||||
|
$(GUI_OPTION) \
|
||||||
|
-kernel $(KERNEL_ELF) \
|
||||||
|
-drive file=$(FS_IMG),if=none,format=raw,id=x0 \
|
||||||
|
-device virtio-blk-device,drive=x0 \
|
||||||
|
# -device virtio-gpu-device \
|
||||||
|
-device virtio-keyboard-device \
|
||||||
|
-device virtio-mouse-device \
|
||||||
|
-device virtio-net-device,netdev=net0 \
|
||||||
|
-netdev user,id=net0,hostfwd=udp::6200-:2000 \
|
||||||
|
-serial stdio
|
||||||
|
|
||||||
run-inner: build
|
run-inner: build
|
||||||
@qemu-system-riscv64 \
|
@qemu-system-riscv64 \
|
||||||
-M 128m \
|
-M 128m \
|
||||||
@ -85,12 +101,26 @@ run-inner: build
|
|||||||
-device virtio-gpu-device \
|
-device virtio-gpu-device \
|
||||||
-device virtio-keyboard-device \
|
-device virtio-keyboard-device \
|
||||||
-device virtio-mouse-device \
|
-device virtio-mouse-device \
|
||||||
|
-device virtio-net-device,netdev=net0 \
|
||||||
|
-netdev user,id=net0,hostfwd=udp::6200-:2000 \
|
||||||
-serial stdio
|
-serial stdio
|
||||||
|
|
||||||
fdt:
|
fdt:
|
||||||
@qemu-system-riscv64 -M 128m -machine virt,dumpdtb=virt.out
|
@qemu-system-riscv64 -M 128m -machine virt,dumpdtb=virt.out
|
||||||
fdtdump virt.out
|
fdtdump virt.out
|
||||||
|
|
||||||
|
debug-none: build
|
||||||
|
@tmux new-session -d \
|
||||||
|
"qemu-system-riscv64 -machine virt -nographic -bios none -kernel $(KERNEL_ELF) \
|
||||||
|
-drive file=$(FS_IMG),if=none,format=raw,id=x0 \
|
||||||
|
-device virtio-blk-device,drive=x0 \
|
||||||
|
-device virtio-keyboard-device \
|
||||||
|
-device virtio-mouse-device \
|
||||||
|
-serial stdio \
|
||||||
|
-s -S" && \
|
||||||
|
tmux split-window -h "riscv64-unknown-elf-gdb -ex 'file $(KERNEL_ELF)' -ex 'set arch riscv:rv64' -ex 'target remote localhost:1234'" && \
|
||||||
|
tmux -2 attach-session -d
|
||||||
|
|
||||||
debug: build
|
debug: build
|
||||||
@tmux new-session -d \
|
@tmux new-session -d \
|
||||||
"qemu-system-riscv64 -machine virt -nographic -bios $(BOOTLOADER) -device loader,file=$(KERNEL_BIN),addr=$(KERNEL_ENTRY_PA) -s -S" && \
|
"qemu-system-riscv64 -machine virt -nographic -bios $(BOOTLOADER) -device loader,file=$(KERNEL_BIN),addr=$(KERNEL_ENTRY_PA) -s -S" && \
|
||||||
|
@ -2,7 +2,7 @@ pub const CLOCK_FREQ: usize = 12500000;
|
|||||||
|
|
||||||
pub const MMIO: &[(usize, usize)] = &[
|
pub const MMIO: &[(usize, usize)] = &[
|
||||||
(0x0010_0000, 0x00_2000), // VIRT_TEST/RTC in virt machine
|
(0x0010_0000, 0x00_2000), // VIRT_TEST/RTC in virt machine
|
||||||
(0x2000000, 0x10000),
|
(0x2000000, 0x10000), // core local interrupter (CLINT)
|
||||||
(0xc000000, 0x210000), // VIRT_PLIC in virt machine
|
(0xc000000, 0x210000), // VIRT_PLIC in virt machine
|
||||||
(0x10000000, 0x9000), // VIRT_UART0 with GPU in virt machine
|
(0x10000000, 0x9000), // VIRT_UART0 with GPU in virt machine
|
||||||
];
|
];
|
||||||
@ -53,6 +53,58 @@ pub fn irq_handler() {
|
|||||||
plic.complete(0, IntrTargetPriority::Supervisor, intr_src_id);
|
plic.complete(0, IntrTargetPriority::Supervisor, intr_src_id);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// core local interrupter (CLINT), which contains the timer
|
||||||
|
pub const CLINT: usize = 0x2000000;
|
||||||
|
// pub const fn clint_mtimecmp(hartid: usize) -> usize {
|
||||||
|
// CLINT + 0x4000 + 8 * hartid
|
||||||
|
// }
|
||||||
|
pub const CLINT_MTIME: usize = CLINT + 0xBFF8; // Cycles since boot.
|
||||||
|
pub const CLINT_MTIMECMP: usize = CLINT + 0x4000;
|
||||||
|
|
||||||
|
#[naked]
|
||||||
|
#[repr(align(16))] // if miss this alignment, a load access fault will occur.
|
||||||
|
#[no_mangle]
|
||||||
|
pub unsafe extern "C" fn timervec() -> ! {
|
||||||
|
// start.rs has set up the memory that mscratch points to:
|
||||||
|
// scratch[0,8,16] : register save area.
|
||||||
|
// scratch[24] : address of CLINT's MTIMECMP register.
|
||||||
|
// scratch[32] : desired interval between interrupts.
|
||||||
|
|
||||||
|
// Now, mscrach has a pointer to an additional scratch space.
|
||||||
|
// to aboid overwriting the contents of the integer registers,
|
||||||
|
// the prologue of an interrupts handler usually begins by swapping
|
||||||
|
// an integer register(say a0) with mscratch CSR.
|
||||||
|
// The interrupt handler stores the integer registers
|
||||||
|
// used for processing in this scratch space.
|
||||||
|
// a0 saved in mscrach, a1 ~ a3 saved in scratch space.
|
||||||
|
//loop {}
|
||||||
|
asm!(
|
||||||
|
"csrrw a0, mscratch, a0",
|
||||||
|
"sd a1, 0(a0)",
|
||||||
|
"sd a2, 8(a0)",
|
||||||
|
"sd a3, 16(a0)",
|
||||||
|
// schedule the next timer interrupt
|
||||||
|
// by adding interval to mtimecmp.
|
||||||
|
"ld a1, 24(a0)", // CLINT_MTIMECMP(hartid) contents
|
||||||
|
"ld a2, 32(a0)", // interval
|
||||||
|
"ld a3, 0(a1)",
|
||||||
|
"add a3, a3, a2",
|
||||||
|
"sd a3, 0(a1)",
|
||||||
|
// raise a supervisor software interrupt.
|
||||||
|
"li a1, 2",
|
||||||
|
"csrw sip, a1",
|
||||||
|
// restore and return
|
||||||
|
"ld a3, 16(a0)",
|
||||||
|
"ld a2, 8(a0)",
|
||||||
|
"ld a1, 0(a0)",
|
||||||
|
"csrrw a0, mscratch, a0",
|
||||||
|
"mret",
|
||||||
|
options(noreturn)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
//ref:: https://github.com/andre-richter/qemu-exit
|
//ref:: https://github.com/andre-richter/qemu-exit
|
||||||
use core::arch::asm;
|
use core::arch::asm;
|
||||||
|
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
use crate::mm::{
|
use crate::mm::{
|
||||||
frame_alloc, frame_dealloc, kernel_token, FrameTracker, PageTable, PhysAddr, PhysPageNum,
|
frame_alloc, frame_dealloc, kernel_token, FrameTracker, PageTable, PhysAddr, PhysPageNum,
|
||||||
StepByOne, VirtAddr,
|
StepByOne, VirtAddr, frame_alloc_more,
|
||||||
};
|
};
|
||||||
use crate::sync::UPIntrFreeCell;
|
use crate::sync::UPIntrFreeCell;
|
||||||
use alloc::vec::Vec;
|
use alloc::vec::Vec;
|
||||||
@ -16,15 +16,9 @@ pub struct VirtioHal;
|
|||||||
|
|
||||||
impl Hal for VirtioHal {
|
impl Hal for VirtioHal {
|
||||||
fn dma_alloc(pages: usize) -> usize {
|
fn dma_alloc(pages: usize) -> usize {
|
||||||
let mut ppn_base = PhysPageNum(0);
|
let trakcers = frame_alloc_more(pages);
|
||||||
for i in 0..pages {
|
let ppn_base = trakcers.as_ref().unwrap().last().unwrap().ppn;
|
||||||
let frame = frame_alloc().unwrap();
|
QUEUE_FRAMES.exclusive_access().append(&mut trakcers.unwrap());
|
||||||
if i == 0 {
|
|
||||||
ppn_base = frame.ppn;
|
|
||||||
}
|
|
||||||
assert_eq!(frame.ppn.0, ppn_base.0 + i);
|
|
||||||
QUEUE_FRAMES.exclusive_access().push(frame);
|
|
||||||
}
|
|
||||||
let pa: PhysAddr = ppn_base.into();
|
let pa: PhysAddr = ppn_base.into();
|
||||||
pa.0
|
pa.0
|
||||||
}
|
}
|
||||||
|
@ -3,6 +3,7 @@ pub mod bus;
|
|||||||
pub mod chardev;
|
pub mod chardev;
|
||||||
pub mod gpu;
|
pub mod gpu;
|
||||||
pub mod input;
|
pub mod input;
|
||||||
|
pub mod net;
|
||||||
pub mod plic;
|
pub mod plic;
|
||||||
|
|
||||||
pub use block::BLOCK_DEVICE;
|
pub use block::BLOCK_DEVICE;
|
||||||
@ -10,3 +11,4 @@ pub use bus::*;
|
|||||||
pub use chardev::UART;
|
pub use chardev::UART;
|
||||||
pub use gpu::*;
|
pub use gpu::*;
|
||||||
pub use input::*;
|
pub use input::*;
|
||||||
|
pub use net::*;
|
41
os/src/drivers/net/mod.rs
Normal file
41
os/src/drivers/net/mod.rs
Normal file
@ -0,0 +1,41 @@
|
|||||||
|
use core::any::Any;
|
||||||
|
|
||||||
|
use alloc::sync::Arc;
|
||||||
|
use lazy_static::*;
|
||||||
|
use virtio_drivers::{VirtIONet, VirtIOHeader};
|
||||||
|
use crate::drivers::virtio::VirtioHal;
|
||||||
|
use crate::sync::UPIntrFreeCell;
|
||||||
|
|
||||||
|
const VIRTIO8: usize = 0x10004000;
|
||||||
|
|
||||||
|
lazy_static! {
|
||||||
|
pub static ref NET_DEVICE: Arc<dyn NetDevice> = Arc::new(VirtIONetWrapper::new());
|
||||||
|
}
|
||||||
|
|
||||||
|
pub trait NetDevice: Send + Sync + Any {
|
||||||
|
fn transmit(&self, data: &[u8]);
|
||||||
|
fn receive(&self, data: &mut [u8]) -> usize;
|
||||||
|
}
|
||||||
|
|
||||||
|
pub struct VirtIONetWrapper(UPIntrFreeCell<VirtIONet<'static, VirtioHal>>);
|
||||||
|
|
||||||
|
impl NetDevice for VirtIONetWrapper {
|
||||||
|
fn transmit(&self, data: &[u8]) {
|
||||||
|
self.0.exclusive_access().send(data).expect("can't send data")
|
||||||
|
}
|
||||||
|
|
||||||
|
fn receive(&self, data: &mut [u8]) -> usize {
|
||||||
|
self.0.exclusive_access().recv(data).expect("can't receive data")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl VirtIONetWrapper {
|
||||||
|
pub fn new() -> Self {
|
||||||
|
unsafe {
|
||||||
|
let virtio =
|
||||||
|
VirtIONet::<VirtioHal>::new(&mut *(VIRTIO8 as *mut VirtIOHeader))
|
||||||
|
.expect("can't create net device by virtio");
|
||||||
|
VirtIONetWrapper(UPIntrFreeCell::new(virtio))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -2,7 +2,7 @@
|
|||||||
.globl _start
|
.globl _start
|
||||||
_start:
|
_start:
|
||||||
la sp, boot_stack_top
|
la sp, boot_stack_top
|
||||||
call rust_main
|
call rust_start
|
||||||
|
|
||||||
.section .bss.stack
|
.section .bss.stack
|
||||||
.globl boot_stack_lower_bound
|
.globl boot_stack_lower_bound
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
OUTPUT_ARCH(riscv)
|
OUTPUT_ARCH(riscv)
|
||||||
ENTRY(_start)
|
ENTRY(_start)
|
||||||
BASE_ADDRESS = 0x80200000;
|
BASE_ADDRESS = 0x80000000;
|
||||||
|
|
||||||
SECTIONS
|
SECTIONS
|
||||||
{
|
{
|
||||||
|
211
os/src/main.rs
211
os/src/main.rs
@ -2,6 +2,8 @@
|
|||||||
#![no_main]
|
#![no_main]
|
||||||
#![feature(panic_info_message)]
|
#![feature(panic_info_message)]
|
||||||
#![feature(alloc_error_handler)]
|
#![feature(alloc_error_handler)]
|
||||||
|
#![feature(naked_functions)]
|
||||||
|
#![feature(fn_align)]
|
||||||
|
|
||||||
//use crate::drivers::{GPU_DEVICE, KEYBOARD_DEVICE, MOUSE_DEVICE, INPUT_CONDVAR};
|
//use crate::drivers::{GPU_DEVICE, KEYBOARD_DEVICE, MOUSE_DEVICE, INPUT_CONDVAR};
|
||||||
use crate::drivers::{GPU_DEVICE, KEYBOARD_DEVICE, MOUSE_DEVICE};
|
use crate::drivers::{GPU_DEVICE, KEYBOARD_DEVICE, MOUSE_DEVICE};
|
||||||
@ -12,7 +14,7 @@ extern crate bitflags;
|
|||||||
|
|
||||||
#[path = "boards/qemu.rs"]
|
#[path = "boards/qemu.rs"]
|
||||||
mod board;
|
mod board;
|
||||||
|
use board::*;
|
||||||
#[macro_use]
|
#[macro_use]
|
||||||
mod console;
|
mod console;
|
||||||
mod config;
|
mod config;
|
||||||
@ -26,9 +28,17 @@ mod syscall;
|
|||||||
mod task;
|
mod task;
|
||||||
mod timer;
|
mod timer;
|
||||||
mod trap;
|
mod trap;
|
||||||
|
mod net;
|
||||||
|
|
||||||
use crate::drivers::chardev::CharDevice;
|
use riscv::register::*;
|
||||||
use crate::drivers::chardev::UART;
|
// mod riscvreg;
|
||||||
|
// use riscvreg::{
|
||||||
|
// mstatus, mepc, satp, medeleg, mideleg, sie, mhartid, tp, clint,
|
||||||
|
// mscratch, mtvec, mie, sstatus
|
||||||
|
// };
|
||||||
|
// use riscvregs::registers::*;
|
||||||
|
// use riscvregs::registers::pmpcfg0::*;
|
||||||
|
//use syscall::create_desktop; //for test
|
||||||
|
|
||||||
core::arch::global_asm!(include_str!("entry.asm"));
|
core::arch::global_asm!(include_str!("entry.asm"));
|
||||||
|
|
||||||
@ -51,9 +61,198 @@ lazy_static! {
|
|||||||
unsafe { UPIntrFreeCell::new(false) };
|
unsafe { UPIntrFreeCell::new(false) };
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
#[repr(C, align(16))]
|
||||||
|
struct Stack([u8; 4096 * 4 * 1]);
|
||||||
|
|
||||||
|
#[no_mangle]
|
||||||
|
static mut STACK0: Stack = Stack([0; 4096 * 4 * 1]);
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
pub unsafe fn medeleg_write(medeleg: usize){
|
||||||
|
core::arch::asm!("csrw medeleg, {}",in(reg)medeleg);
|
||||||
|
}
|
||||||
|
|
||||||
|
pub unsafe fn mideleg_write(mideleg: usize) {
|
||||||
|
core::arch::asm!("csrw mideleg, {}", in(reg)mideleg);
|
||||||
|
}
|
||||||
|
|
||||||
|
pub enum SIE {
|
||||||
|
SEIE = 1 << 9, // external
|
||||||
|
STIE = 1 << 5, // timer
|
||||||
|
SSIE = 1 << 1, // software
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
pub unsafe fn sie_read() -> usize {
|
||||||
|
let ret:usize;
|
||||||
|
core::arch::asm!("csrr {}, sie", out(reg)ret);
|
||||||
|
ret
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
pub unsafe fn sie_write(x:usize) {
|
||||||
|
core::arch::asm!("csrw sie, {}", in(reg)x);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// enable all software interrupts
|
||||||
|
/// still need to set SIE bit in sstatus
|
||||||
|
pub unsafe fn intr_on() {
|
||||||
|
let mut sie = sie_read();
|
||||||
|
sie |= SIE::SSIE as usize | SIE::STIE as usize | SIE::SEIE as usize;
|
||||||
|
sie_write(sie);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[no_mangle]
|
||||||
|
pub unsafe fn rust_start() -> ! {
|
||||||
|
// set MPP mode to Supervisor, for mret
|
||||||
|
mstatus::set_mpp(mstatus::MPP::Supervisor);
|
||||||
|
|
||||||
|
// set MEPC to main, for mret
|
||||||
|
mepc::write(rust_main as usize);
|
||||||
|
|
||||||
|
// disable paging for now.
|
||||||
|
satp::write(0);
|
||||||
|
|
||||||
|
// delegate all interrupts and exceptions to supervisor mode.
|
||||||
|
medeleg_write(0xffff);
|
||||||
|
mideleg_write(0xffff);
|
||||||
|
intr_on();
|
||||||
|
|
||||||
|
// configure Physical Memory Protection to give supervisor mode
|
||||||
|
// access to all of physical memory.
|
||||||
|
pmpaddr0::write(0x3fffffffffffff);
|
||||||
|
pmpcfg0::write(0xf);
|
||||||
|
//pmpcfg0::set_pmp(0, Range::TOR, Permission::RWX, false); // 0 < addr < pmpaddr0
|
||||||
|
|
||||||
|
// ask for clock interrupts.
|
||||||
|
timer_init();
|
||||||
|
|
||||||
|
// keep each CPU's hartid in its tp register, for cpuid().
|
||||||
|
// let id = mhartid::read();
|
||||||
|
// core::arch::asm!("mv tp, {0}", in(reg) id);
|
||||||
|
|
||||||
|
// switch to supervisor mode and jump to main().
|
||||||
|
core::arch::asm!("mret");
|
||||||
|
|
||||||
|
extern "C" {
|
||||||
|
fn rust_main() -> !;
|
||||||
|
}
|
||||||
|
core::hint::unreachable_unchecked();
|
||||||
|
}
|
||||||
|
|
||||||
|
use core::convert::Into;
|
||||||
|
use core::ptr;
|
||||||
|
|
||||||
|
// a scratch area per CPU for machine-mode timer interrupts.
|
||||||
|
static mut TIMER_SCRATCH: [u64; 5] = [0; 5];
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
unsafe fn read_mtime() -> u64 {
|
||||||
|
ptr::read_volatile(Into::<usize>::into(CLINT_MTIME) as *const u64)
|
||||||
|
}
|
||||||
|
|
||||||
|
unsafe fn write_mtimecmp(value: u64) {
|
||||||
|
let offset = Into::<usize>::into(CLINT_MTIMECMP);
|
||||||
|
ptr::write_volatile(offset as *mut u64, value);
|
||||||
|
}
|
||||||
|
|
||||||
|
pub unsafe fn add_mtimecmp(interval:u64){
|
||||||
|
let value = read_mtime();
|
||||||
|
write_mtimecmp(value+interval);
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn count_mtiecmp() -> usize{
|
||||||
|
let ret:usize;
|
||||||
|
ret = Into::<usize>::into(CLINT) + 0x4000;
|
||||||
|
ret
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
pub unsafe fn mtvec_write(x:usize){
|
||||||
|
core::arch::asm!("csrw mtvec, {}",in(reg)x);
|
||||||
|
}
|
||||||
|
|
||||||
|
use bit_field::BitField;
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
unsafe fn mstatus_read() -> usize {
|
||||||
|
let ret:usize;
|
||||||
|
core::arch::asm!("csrr {}, mstatus",out(reg)ret);
|
||||||
|
ret
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
unsafe fn mstatus_write(x: usize) {
|
||||||
|
core::arch::asm!("csrw mstatus, {}",in(reg)x);
|
||||||
|
}
|
||||||
|
|
||||||
|
// enable machine-mode interrupts.
|
||||||
|
pub unsafe fn mstatus_enable_interrupt(){
|
||||||
|
let mut mstatus = mstatus_read();
|
||||||
|
mstatus.set_bit(3, true);
|
||||||
|
mstatus_write(mstatus);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
pub enum MIE {
|
||||||
|
MEIE = 1 << 11, // external
|
||||||
|
MTIE = 1 << 7, // timer
|
||||||
|
MSIE = 1 << 3 // software
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
pub unsafe fn mie_read() -> usize {
|
||||||
|
let ret:usize;
|
||||||
|
core::arch::asm!("csrr {}, mie", out(reg)ret);
|
||||||
|
ret
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
pub unsafe fn mie_write(x:usize){
|
||||||
|
core::arch::asm!("csrw mie, {}",in(reg)x);
|
||||||
|
}
|
||||||
|
|
||||||
|
unsafe fn timer_init() {
|
||||||
|
clear_bss();
|
||||||
|
// each CPU has a separate source of timer interrupts
|
||||||
|
//let id = mhartid::read();
|
||||||
|
|
||||||
|
// ask the CLINT for a timer interrupts
|
||||||
|
let interval = 1000000u64; // cycles; about 1/10th second in qemu.
|
||||||
|
add_mtimecmp(interval);
|
||||||
|
// let mtimecmp = board::clint_mtimecmp(0) as *mut u64;
|
||||||
|
// let mtime = board::CLINT_MTIME as *const u64;
|
||||||
|
// mtimecmp.write_volatile(mtime.read_volatile() + interval);
|
||||||
|
|
||||||
|
// prepare information in scratch[] for timervec.
|
||||||
|
// scratch[0..2] : space for timervec to save registers.
|
||||||
|
// scratch[3] : address of CLINT MTIMECMP register.
|
||||||
|
// scratch[4] : desired interval (in cycles) between timer interrupts.
|
||||||
|
let scratch = &mut TIMER_SCRATCH;
|
||||||
|
scratch[3] = count_mtiecmp() as u64;
|
||||||
|
scratch[4] = interval;
|
||||||
|
mscratch::write(scratch.as_mut_ptr() as usize);
|
||||||
|
|
||||||
|
// set the machine-mode trap handler
|
||||||
|
mtvec_write(timervec as usize);
|
||||||
|
//mtvec::write(board::timervec as usize, mtvec::TrapMode::Direct);
|
||||||
|
|
||||||
|
// enable machine-mode interrupts.
|
||||||
|
mstatus_enable_interrupt();
|
||||||
|
//mstatus::set_mie();
|
||||||
|
|
||||||
|
// enable machine-mode timer interrupts.
|
||||||
|
mie_write(mie_read() | MIE::MTIE as usize);
|
||||||
|
//mie::set_mtimer();
|
||||||
|
}
|
||||||
|
|
||||||
|
use crate::drivers::chardev::CharDevice;
|
||||||
|
use crate::drivers::chardev::UART;
|
||||||
#[no_mangle]
|
#[no_mangle]
|
||||||
pub fn rust_main() -> ! {
|
pub fn rust_main() -> ! {
|
||||||
clear_bss();
|
|
||||||
|
//clear_bss();
|
||||||
mm::init();
|
mm::init();
|
||||||
UART.init();
|
UART.init();
|
||||||
println!("KERN: init gpu");
|
println!("KERN: init gpu");
|
||||||
@ -64,8 +263,8 @@ pub fn rust_main() -> ! {
|
|||||||
let _mouse = MOUSE_DEVICE.clone();
|
let _mouse = MOUSE_DEVICE.clone();
|
||||||
println!("KERN: init trap");
|
println!("KERN: init trap");
|
||||||
trap::init();
|
trap::init();
|
||||||
trap::enable_timer_interrupt();
|
//trap::enable_timer_interrupt();
|
||||||
timer::set_next_trigger();
|
//timer::set_next_trigger();
|
||||||
board::device_init();
|
board::device_init();
|
||||||
fs::list_apps();
|
fs::list_apps();
|
||||||
task::add_initproc();
|
task::add_initproc();
|
||||||
|
@ -35,6 +35,7 @@ impl Drop for FrameTracker {
|
|||||||
trait FrameAllocator {
|
trait FrameAllocator {
|
||||||
fn new() -> Self;
|
fn new() -> Self;
|
||||||
fn alloc(&mut self) -> Option<PhysPageNum>;
|
fn alloc(&mut self) -> Option<PhysPageNum>;
|
||||||
|
fn alloc_more(&mut self, pages: usize) -> Option<Vec<PhysPageNum>>;
|
||||||
fn dealloc(&mut self, ppn: PhysPageNum);
|
fn dealloc(&mut self, ppn: PhysPageNum);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -69,6 +70,16 @@ impl FrameAllocator for StackFrameAllocator {
|
|||||||
Some((self.current - 1).into())
|
Some((self.current - 1).into())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
fn alloc_more(&mut self, pages: usize) -> Option<Vec<PhysPageNum>> {
|
||||||
|
if self.current + pages >= self.end {
|
||||||
|
None
|
||||||
|
} else {
|
||||||
|
self.current += pages;
|
||||||
|
let arr:Vec<usize> = (1..pages + 1).collect();
|
||||||
|
let v = arr.iter().map(|x| (self.current - x).into()).collect();
|
||||||
|
Some(v)
|
||||||
|
}
|
||||||
|
}
|
||||||
fn dealloc(&mut self, ppn: PhysPageNum) {
|
fn dealloc(&mut self, ppn: PhysPageNum) {
|
||||||
let ppn = ppn.0;
|
let ppn = ppn.0;
|
||||||
// validity check
|
// validity check
|
||||||
@ -104,6 +115,13 @@ pub fn frame_alloc() -> Option<FrameTracker> {
|
|||||||
.map(FrameTracker::new)
|
.map(FrameTracker::new)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn frame_alloc_more(num: usize) -> Option<Vec<FrameTracker>> {
|
||||||
|
FRAME_ALLOCATOR
|
||||||
|
.exclusive_access()
|
||||||
|
.alloc_more(num)
|
||||||
|
.map(|x| x.iter().map(|&t| FrameTracker::new(t)).collect())
|
||||||
|
}
|
||||||
|
|
||||||
pub fn frame_dealloc(ppn: PhysPageNum) {
|
pub fn frame_dealloc(ppn: PhysPageNum) {
|
||||||
FRAME_ALLOCATOR.exclusive_access().dealloc(ppn);
|
FRAME_ALLOCATOR.exclusive_access().dealloc(ppn);
|
||||||
}
|
}
|
||||||
@ -125,3 +143,21 @@ pub fn frame_allocator_test() {
|
|||||||
drop(v);
|
drop(v);
|
||||||
println!("frame_allocator_test passed!");
|
println!("frame_allocator_test passed!");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
#[allow(unused)]
|
||||||
|
pub fn frame_allocator_alloc_more_test() {
|
||||||
|
let mut v: Vec<FrameTracker> = Vec::new();
|
||||||
|
let frames = frame_alloc_more(5).unwrap();
|
||||||
|
for frame in &frames {
|
||||||
|
println!("{:?}", frame);
|
||||||
|
}
|
||||||
|
v.extend(frames);
|
||||||
|
v.clear();
|
||||||
|
let frames = frame_alloc_more(5).unwrap();
|
||||||
|
for frame in &frames {
|
||||||
|
println!("{:?}", frame);
|
||||||
|
}
|
||||||
|
drop(v);
|
||||||
|
println!("frame_allocator_test passed!");
|
||||||
|
}
|
||||||
|
@ -6,7 +6,7 @@ mod page_table;
|
|||||||
|
|
||||||
pub use address::VPNRange;
|
pub use address::VPNRange;
|
||||||
pub use address::{PhysAddr, PhysPageNum, StepByOne, VirtAddr, VirtPageNum};
|
pub use address::{PhysAddr, PhysPageNum, StepByOne, VirtAddr, VirtPageNum};
|
||||||
pub use frame_allocator::{frame_alloc, frame_dealloc, FrameTracker};
|
pub use frame_allocator::{frame_alloc, frame_alloc_more, frame_dealloc, FrameTracker};
|
||||||
pub use memory_set::remap_test;
|
pub use memory_set::remap_test;
|
||||||
pub use memory_set::{kernel_token, MapArea, MapPermission, MapType, MemorySet, KERNEL_SPACE};
|
pub use memory_set::{kernel_token, MapArea, MapPermission, MapType, MemorySet, KERNEL_SPACE};
|
||||||
use page_table::PTEFlags;
|
use page_table::PTEFlags;
|
||||||
|
92
os/src/net/mod.rs
Normal file
92
os/src/net/mod.rs
Normal file
@ -0,0 +1,92 @@
|
|||||||
|
pub mod udp;
|
||||||
|
pub mod socket;
|
||||||
|
|
||||||
|
pub use lose_net_stack::IPv4;
|
||||||
|
|
||||||
|
use alloc::{vec, sync::Arc};
|
||||||
|
use lose_net_stack::{LoseStack, MacAddress, results::Packet};
|
||||||
|
|
||||||
|
use crate::{drivers::NET_DEVICE, sync::UPIntrFreeCell, net::socket::{get_socket, push_data}};
|
||||||
|
|
||||||
|
pub struct NetStack(UPIntrFreeCell<LoseStack>);
|
||||||
|
|
||||||
|
impl NetStack {
|
||||||
|
pub fn new() -> Self {
|
||||||
|
unsafe {
|
||||||
|
NetStack(UPIntrFreeCell::new(LoseStack::new(
|
||||||
|
IPv4::new(10, 0, 2, 15),
|
||||||
|
MacAddress::new([0x52, 0x54, 0x00, 0x12, 0x34, 0x56])
|
||||||
|
)))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
lazy_static::lazy_static! {
|
||||||
|
static ref LOSE_NET_STACK: Arc<NetStack> = Arc::new(NetStack::new());
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
pub fn net_interrupt_handler() {
|
||||||
|
let mut recv_buf = vec![0u8; 1024];
|
||||||
|
|
||||||
|
let len = NET_DEVICE.receive(&mut recv_buf);
|
||||||
|
|
||||||
|
let packet = LOSE_NET_STACK.0.exclusive_access().analysis(&recv_buf[..len]);
|
||||||
|
|
||||||
|
// println!("[kernel] receive a packet");
|
||||||
|
// hexdump(&recv_buf[..len]);
|
||||||
|
|
||||||
|
match packet {
|
||||||
|
Packet::ARP(arp_packet) => {
|
||||||
|
let lose_stack = LOSE_NET_STACK.0.exclusive_access();
|
||||||
|
let reply_packet = arp_packet.reply_packet(lose_stack.ip, lose_stack.mac).expect("can't build reply");
|
||||||
|
let reply_data = reply_packet.build_data();
|
||||||
|
NET_DEVICE.transmit(&reply_data)
|
||||||
|
},
|
||||||
|
|
||||||
|
Packet::UDP(udp_packet) => {
|
||||||
|
let target = udp_packet.source_ip;
|
||||||
|
let lport = udp_packet.dest_port;
|
||||||
|
let rport = udp_packet.source_port;
|
||||||
|
|
||||||
|
if let Some(socket_index) = get_socket(target, lport, rport) {
|
||||||
|
push_data(socket_index, udp_packet.data.to_vec());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
_ => {}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[allow(unused)]
|
||||||
|
pub fn hexdump(data: &[u8]) {
|
||||||
|
const PRELAND_WIDTH: usize = 70;
|
||||||
|
println!("[kernel] {:-^1$}", " hexdump ", PRELAND_WIDTH);
|
||||||
|
for offset in (0..data.len()).step_by(16) {
|
||||||
|
print!("[kernel] ");
|
||||||
|
for i in 0..16 {
|
||||||
|
if offset + i < data.len() {
|
||||||
|
print!("{:02x} ", data[offset + i]);
|
||||||
|
} else {
|
||||||
|
print!("{:02} ", "");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
print!("{:>6}", ' ');
|
||||||
|
|
||||||
|
for i in 0..16 {
|
||||||
|
if offset + i < data.len() {
|
||||||
|
let c = data[offset + i];
|
||||||
|
if c >= 0x20 && c <= 0x7e {
|
||||||
|
print!("{}", c as char);
|
||||||
|
} else {
|
||||||
|
print!(".");
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
print!("{:02} ", "");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
println!("");
|
||||||
|
}
|
||||||
|
println!("[kernel] {:-^1$}", " hexdump end ", PRELAND_WIDTH);
|
||||||
|
}
|
93
os/src/net/socket.rs
Normal file
93
os/src/net/socket.rs
Normal file
@ -0,0 +1,93 @@
|
|||||||
|
use alloc::collections::VecDeque;
|
||||||
|
use alloc::vec::Vec;
|
||||||
|
use lazy_static::lazy_static;
|
||||||
|
use lose_net_stack::IPv4;
|
||||||
|
|
||||||
|
use crate::sync::UPIntrFreeCell;
|
||||||
|
|
||||||
|
|
||||||
|
// TODO: specify the protocol, TCP or UDP
|
||||||
|
pub struct Socket {
|
||||||
|
pub raddr: IPv4, // remote address
|
||||||
|
pub lport: u16, // local port
|
||||||
|
pub rport: u16, // rempote port
|
||||||
|
pub buffers: VecDeque<Vec<u8>> // datas
|
||||||
|
}
|
||||||
|
|
||||||
|
lazy_static! {
|
||||||
|
static ref SOCKET_TABLE:UPIntrFreeCell<Vec<Option<Socket>>> = unsafe {
|
||||||
|
UPIntrFreeCell::new(Vec::new())
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn get_socket(raddr: IPv4, lport: u16, rport: u16) -> Option<usize> {
|
||||||
|
let socket_table = SOCKET_TABLE.exclusive_access();
|
||||||
|
for i in 0..socket_table.len() {
|
||||||
|
let sock = &socket_table[i];
|
||||||
|
if sock.is_none() {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
let sock = sock.as_ref().unwrap();
|
||||||
|
if sock.raddr == raddr && sock.lport == lport && sock.rport == rport {
|
||||||
|
return Some(i)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
None
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn add_socket(raddr: IPv4, lport: u16, rport: u16) -> Option<usize> {
|
||||||
|
if get_socket(raddr, lport, rport).is_some() {
|
||||||
|
return None;
|
||||||
|
}
|
||||||
|
|
||||||
|
let mut socket_table = SOCKET_TABLE.exclusive_access();
|
||||||
|
let mut index = usize::MAX;
|
||||||
|
for i in 0..socket_table.len() {
|
||||||
|
if socket_table[i].is_none() {
|
||||||
|
index = i;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
let socket = Socket {
|
||||||
|
raddr,
|
||||||
|
lport,
|
||||||
|
rport,
|
||||||
|
buffers: VecDeque::new()
|
||||||
|
};
|
||||||
|
|
||||||
|
if index == usize::MAX {
|
||||||
|
socket_table.push(Some(socket));
|
||||||
|
Some(socket_table.len() - 1)
|
||||||
|
} else {
|
||||||
|
socket_table[index] = Some(socket);
|
||||||
|
Some(index)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn remove_socket(index: usize) {
|
||||||
|
let mut socket_table = SOCKET_TABLE.exclusive_access();
|
||||||
|
|
||||||
|
assert!(socket_table.len() > index);
|
||||||
|
|
||||||
|
socket_table[index] = None;
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn push_data(index: usize, data: Vec<u8>) {
|
||||||
|
let mut socket_table = SOCKET_TABLE.exclusive_access();
|
||||||
|
|
||||||
|
assert!(socket_table.len() > index);
|
||||||
|
assert!(socket_table[index].is_some());
|
||||||
|
|
||||||
|
socket_table[index].as_mut().unwrap().buffers.push_back(data);
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn pop_data(index: usize) -> Option<Vec<u8>> {
|
||||||
|
let mut socket_table = SOCKET_TABLE.exclusive_access();
|
||||||
|
|
||||||
|
assert!(socket_table.len() > index);
|
||||||
|
assert!(socket_table[index].is_some());
|
||||||
|
|
||||||
|
socket_table[index].as_mut().unwrap().buffers.pop_front()
|
||||||
|
}
|
94
os/src/net/udp.rs
Normal file
94
os/src/net/udp.rs
Normal file
@ -0,0 +1,94 @@
|
|||||||
|
use alloc::vec;
|
||||||
|
use lose_net_stack::MacAddress;
|
||||||
|
use lose_net_stack::packets::udp::UDPPacket;
|
||||||
|
use lose_net_stack::IPv4;
|
||||||
|
use crate::fs::File;
|
||||||
|
use super::net_interrupt_handler;
|
||||||
|
use super::socket::{add_socket, remove_socket, pop_data};
|
||||||
|
use super::LOSE_NET_STACK;
|
||||||
|
use super::NET_DEVICE;
|
||||||
|
|
||||||
|
pub struct UDP{
|
||||||
|
pub target: IPv4,
|
||||||
|
pub sport: u16,
|
||||||
|
pub dport: u16,
|
||||||
|
pub socket_index: usize
|
||||||
|
}
|
||||||
|
|
||||||
|
impl UDP {
|
||||||
|
pub fn new(target: IPv4, sport: u16, dport: u16) -> Self {
|
||||||
|
let index = add_socket(target, sport, dport).expect("can't add socket");
|
||||||
|
|
||||||
|
Self {
|
||||||
|
target,
|
||||||
|
sport,
|
||||||
|
dport,
|
||||||
|
socket_index: index
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl File for UDP {
|
||||||
|
fn readable(&self) -> bool {
|
||||||
|
true
|
||||||
|
}
|
||||||
|
|
||||||
|
fn writable(&self) -> bool {
|
||||||
|
true
|
||||||
|
}
|
||||||
|
|
||||||
|
fn read(&self, mut buf: crate::mm::UserBuffer) -> usize {
|
||||||
|
loop {
|
||||||
|
if let Some(data) = pop_data(self.socket_index) {
|
||||||
|
let data_len = data.len();
|
||||||
|
let mut left = 0;
|
||||||
|
for i in 0..buf.buffers.len() {
|
||||||
|
let buffer_i_len = buf.buffers[i].len().min(data_len - left);
|
||||||
|
|
||||||
|
buf.buffers[i][..buffer_i_len].copy_from_slice(&data[left..(left + buffer_i_len)]);
|
||||||
|
|
||||||
|
left += buffer_i_len;
|
||||||
|
if left == data_len {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return left;
|
||||||
|
} else {
|
||||||
|
net_interrupt_handler();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn write(&self, buf: crate::mm::UserBuffer) -> usize {
|
||||||
|
let lose_net_stack = LOSE_NET_STACK.0.exclusive_access();
|
||||||
|
|
||||||
|
let mut data = vec![0u8; buf.len()];
|
||||||
|
|
||||||
|
let mut left = 0;
|
||||||
|
for i in 0..buf.buffers.len() {
|
||||||
|
data[left..(left + buf.buffers[i].len())].copy_from_slice(buf.buffers[i]);
|
||||||
|
left += buf.buffers[i].len();
|
||||||
|
}
|
||||||
|
|
||||||
|
let len = data.len();
|
||||||
|
|
||||||
|
let udp_packet = UDPPacket::new(
|
||||||
|
lose_net_stack.ip,
|
||||||
|
lose_net_stack.mac,
|
||||||
|
self.sport,
|
||||||
|
self.target,
|
||||||
|
MacAddress::new([0xff, 0xff, 0xff, 0xff, 0xff, 0xff]),
|
||||||
|
self.dport,
|
||||||
|
len,
|
||||||
|
data.as_ref()
|
||||||
|
);
|
||||||
|
NET_DEVICE.transmit(&udp_packet.build_data());
|
||||||
|
len
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Drop for UDP {
|
||||||
|
fn drop(&mut self) {
|
||||||
|
remove_socket(self.socket_index)
|
||||||
|
}
|
||||||
|
}
|
614
os/src/riscvregs.rs
Normal file
614
os/src/riscvregs.rs
Normal file
@ -0,0 +1,614 @@
|
|||||||
|
// RISC-V registers
|
||||||
|
pub mod registers {
|
||||||
|
// hart (core) id registers
|
||||||
|
pub mod mhartid {
|
||||||
|
use core::arch::asm;
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
pub fn read() -> usize {
|
||||||
|
let id: usize;
|
||||||
|
unsafe {
|
||||||
|
asm!("csrr {}, mhartid", out(reg) id);
|
||||||
|
}
|
||||||
|
id
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Machine Status Register, mstatus
|
||||||
|
pub mod mstatus {
|
||||||
|
use core::arch::asm;
|
||||||
|
|
||||||
|
// Machine Status Register bit
|
||||||
|
const MPP_MASK: usize = 3 << 11;
|
||||||
|
const MIE: usize = 1 << 3;
|
||||||
|
|
||||||
|
// Machine Previous Privilege mode
|
||||||
|
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
|
||||||
|
pub enum MPP {
|
||||||
|
Machine = 3,
|
||||||
|
Supervisor = 1,
|
||||||
|
User = 0,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
unsafe fn _read() -> usize {
|
||||||
|
let bits: usize;
|
||||||
|
asm!("csrr {}, mstatus", out(reg) bits);
|
||||||
|
bits
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
unsafe fn _write(bits: usize) {
|
||||||
|
asm!("csrw mstatus, {}", in(reg) bits);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Machine Previous Privilege Mode
|
||||||
|
#[inline]
|
||||||
|
pub fn set_mpp(mpp: MPP) {
|
||||||
|
unsafe {
|
||||||
|
let mut value = _read();
|
||||||
|
value &= !MPP_MASK;
|
||||||
|
value |= (mpp as usize) << 11;
|
||||||
|
_write(value);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
pub fn set_mie() {
|
||||||
|
unsafe {
|
||||||
|
asm!("csrs mstatus, {}", in(reg) MIE);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// machine exception program counter, holds the
|
||||||
|
// instruction address to which a return from
|
||||||
|
// exception will go.
|
||||||
|
pub mod mepc {
|
||||||
|
use core::arch::asm;
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
pub fn write(x: usize) {
|
||||||
|
unsafe {
|
||||||
|
asm!("csrw mepc, {}", in(reg) x);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Supervisor Status Register, sstatus
|
||||||
|
pub mod sstatus {
|
||||||
|
use core::arch::asm;
|
||||||
|
|
||||||
|
// Supervisor Status Register bit
|
||||||
|
const SPP: usize = 1 << 8; // Previous mode, 1=Supervisor, 0=user
|
||||||
|
const SPIE: usize = 1 << 5; // Supervisor Previous Interrupt Enable
|
||||||
|
const SIE: usize = 1 << 1; // Supervisor Interrupt Enable
|
||||||
|
|
||||||
|
#[derive(Clone, Copy, Debug)]
|
||||||
|
pub struct Sstatus {
|
||||||
|
bits: usize,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Sstatus {
|
||||||
|
// Supervisor Interrupt Enable
|
||||||
|
#[inline]
|
||||||
|
pub(in crate::riscvregs) fn sie(&self) -> bool {
|
||||||
|
self.bits & SIE != 0
|
||||||
|
}
|
||||||
|
|
||||||
|
// Supervisor Previous Privilege mode
|
||||||
|
#[inline]
|
||||||
|
pub fn spp(&self) -> SPP {
|
||||||
|
match self.bits & SPP {
|
||||||
|
0 => SPP::User,
|
||||||
|
_ => SPP::Supervisor,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// restore status bits
|
||||||
|
#[inline]
|
||||||
|
pub fn restore(&self) {
|
||||||
|
unsafe {
|
||||||
|
_write(self.bits);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Supervisor Previous Privilege Mode
|
||||||
|
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
|
||||||
|
pub enum SPP {
|
||||||
|
Supervisor = 1,
|
||||||
|
User = 0,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
pub fn read() -> Sstatus {
|
||||||
|
let bits: usize;
|
||||||
|
unsafe { asm!("csrr {}, sstatus", out(reg) bits) }
|
||||||
|
Sstatus { bits }
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
unsafe fn _write(bits: usize) {
|
||||||
|
asm!("csrw sstatus, {}", in(reg) bits);
|
||||||
|
}
|
||||||
|
|
||||||
|
// bit set
|
||||||
|
#[inline]
|
||||||
|
unsafe fn _set(bits: usize) {
|
||||||
|
asm!("csrs sstatus, {}", in(reg) bits);
|
||||||
|
}
|
||||||
|
|
||||||
|
// bit clear
|
||||||
|
#[inline]
|
||||||
|
unsafe fn _clear(bits: usize) {
|
||||||
|
asm!("csrc sstatus, {}", in(reg) bits);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
pub(in crate::riscvregs) unsafe fn set_sie() {
|
||||||
|
_set(SIE)
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
pub(in crate::riscvregs) unsafe fn clear_sie() {
|
||||||
|
_clear(SIE)
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
pub unsafe fn set_spie() {
|
||||||
|
_set(SPIE);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
pub unsafe fn set_spp(spp: SPP) {
|
||||||
|
match spp {
|
||||||
|
SPP::Supervisor => _set(SPP),
|
||||||
|
SPP::User => _clear(SPP),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Supervisor Interrupt Pending
|
||||||
|
pub mod sip {
|
||||||
|
use core::arch::asm;
|
||||||
|
|
||||||
|
const SSIP: usize = 1 << 1;
|
||||||
|
|
||||||
|
// Supervisor Software Interrupt Pending
|
||||||
|
#[inline]
|
||||||
|
pub unsafe fn clear_ssoft() {
|
||||||
|
asm!("csrc sip, {}", in(reg) SSIP);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Supervisor Interrupt Enable
|
||||||
|
pub mod sie {
|
||||||
|
use core::arch::asm;
|
||||||
|
|
||||||
|
const SEIE: usize = 1 << 9; // external
|
||||||
|
const STIE: usize = 1 << 5; // timer
|
||||||
|
const SSIE: usize = 1 << 1; // software
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
unsafe fn _set(bits: usize) {
|
||||||
|
asm!("csrs sie, {}", in(reg) bits);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
pub unsafe fn set_sext() {
|
||||||
|
_set(SEIE);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
pub unsafe fn set_stimer() {
|
||||||
|
_set(STIE);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
pub unsafe fn set_ssoft() {
|
||||||
|
_set(SSIE);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Machine-mode Interrupt Enable
|
||||||
|
pub mod mie {
|
||||||
|
use core::arch::asm;
|
||||||
|
|
||||||
|
const MTIE: usize = 1 << 7;
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
pub unsafe fn set_mtimer() {
|
||||||
|
asm!("csrs mie, {}", in(reg) MTIE);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// supervisor exceptions program counter, holds the
|
||||||
|
// instruction address to which a return from
|
||||||
|
// exception will go.
|
||||||
|
pub mod sepc {
|
||||||
|
use core::arch::asm;
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
pub fn read() -> usize {
|
||||||
|
let bits: usize;
|
||||||
|
unsafe {
|
||||||
|
asm!("csrr {}, sepc", out(reg) bits);
|
||||||
|
}
|
||||||
|
bits
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
pub fn write(bits: usize) {
|
||||||
|
unsafe {
|
||||||
|
asm!("csrw sepc, {}", in(reg) bits);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Machine Exception Delegation
|
||||||
|
pub mod medeleg {
|
||||||
|
use core::arch::asm;
|
||||||
|
|
||||||
|
pub unsafe fn set_all() {
|
||||||
|
asm!("csrw medeleg, {}", in(reg) 0xffff);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Machine Interrupt Delegation
|
||||||
|
pub mod mideleg {
|
||||||
|
use core::arch::asm;
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
pub unsafe fn set_all() {
|
||||||
|
asm!("csrw mideleg, {}", in(reg) 0xffff);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Supervisor Trap-Vector Base Address
|
||||||
|
// low two bits are mode.
|
||||||
|
pub mod stvec {
|
||||||
|
pub use super::mtvec::TrapMode;
|
||||||
|
use core::arch::asm;
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
pub unsafe fn write(addr: usize, mode: TrapMode) {
|
||||||
|
asm!("csrw stvec, {}", in(reg) addr + mode as usize);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Machine-mode interrupt vector
|
||||||
|
pub mod mtvec {
|
||||||
|
use core::arch::asm;
|
||||||
|
|
||||||
|
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
|
||||||
|
pub enum TrapMode {
|
||||||
|
Direct = 0,
|
||||||
|
Vectored = 1,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
pub unsafe fn write(addr: usize, mode: TrapMode) {
|
||||||
|
asm!("csrw mtvec, {}", in(reg) addr + mode as usize);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Physical Memory Protection Configuration
|
||||||
|
pub mod pmpcfg0 {
|
||||||
|
use core::arch::asm;
|
||||||
|
|
||||||
|
// Permission enum contains all possible permission modes for pmp registers
|
||||||
|
#[derive(Clone, Copy, Debug)]
|
||||||
|
pub enum Permission {
|
||||||
|
NONE = 0b000,
|
||||||
|
R = 0b001,
|
||||||
|
W = 0b010,
|
||||||
|
RW = 0b011,
|
||||||
|
X = 0b100,
|
||||||
|
RX = 0b101,
|
||||||
|
WX = 0b110,
|
||||||
|
RWX = 0b111,
|
||||||
|
}
|
||||||
|
|
||||||
|
// Range enum contains all possible addressing modes for pmp registers
|
||||||
|
pub enum Range {
|
||||||
|
OFF = 0b00,
|
||||||
|
TOR = 0b01,
|
||||||
|
NA4 = 0b10,
|
||||||
|
NAPOT = 0b11,
|
||||||
|
}
|
||||||
|
|
||||||
|
// Set the pmp configuration corresponging to the index
|
||||||
|
#[inline]
|
||||||
|
pub unsafe fn set_pmp(index: usize, range: Range, permission: Permission, locked: bool) {
|
||||||
|
assert!(index < 8);
|
||||||
|
let mut value = _read();
|
||||||
|
let byte = (locked as usize) << 7 | (range as usize) << 3 | (permission as usize);
|
||||||
|
value |= byte << (8 * index);
|
||||||
|
_write(value);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
unsafe fn _read() -> usize {
|
||||||
|
let bits: usize;
|
||||||
|
asm!("csrr {}, pmpcfg0", out(reg) bits);
|
||||||
|
bits
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
unsafe fn _write(bits: usize) {
|
||||||
|
asm!("csrw pmpcfg0, {}", in(reg) bits);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Physical memory protection address register
|
||||||
|
pub mod pmpaddr0 {
|
||||||
|
use core::arch::asm;
|
||||||
|
|
||||||
|
pub fn write(bits: usize) {
|
||||||
|
unsafe {
|
||||||
|
asm!("csrw pmpaddr0, {}", in(reg) bits);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Supervisor address translation and protection;
|
||||||
|
// holds the address of the page table.
|
||||||
|
pub mod satp {
|
||||||
|
use core::arch::asm;
|
||||||
|
|
||||||
|
// stap register
|
||||||
|
#[derive(Clone, Copy, Debug)]
|
||||||
|
pub struct Satp {
|
||||||
|
bits: usize,
|
||||||
|
}
|
||||||
|
|
||||||
|
// 64-bit satp mode
|
||||||
|
pub enum Mode {
|
||||||
|
// No translation or protection
|
||||||
|
Bare = 0,
|
||||||
|
// Page-based 39-bit virtual addressing
|
||||||
|
Sv39 = 8,
|
||||||
|
// Page-based 48-bit virtual addressing
|
||||||
|
Sv48 = 9,
|
||||||
|
// Page-based 57-bit virtual addressing
|
||||||
|
Sv57 = 10,
|
||||||
|
// Page-based 64-bit virtual addressing
|
||||||
|
Sv64 = 11,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Satp {
|
||||||
|
// Return the contents of the register as raw bits
|
||||||
|
#[inline]
|
||||||
|
pub fn bits(&self) -> usize {
|
||||||
|
self.bits
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
pub unsafe fn read() -> Satp {
|
||||||
|
let bits: usize;
|
||||||
|
asm!("csrr {}, satp", out(reg) bits);
|
||||||
|
Satp { bits }
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
pub unsafe fn write(bits: usize) {
|
||||||
|
asm!("csrw satp, {}", in(reg) bits);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
pub fn make(mode: Mode, asid: usize, ppn: usize) -> usize {
|
||||||
|
let mut bits: usize = 0;
|
||||||
|
bits |= (mode as usize) << 60;
|
||||||
|
bits |= asid << 44;
|
||||||
|
bits |= ppn >> 12;
|
||||||
|
bits
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// mscratch register
|
||||||
|
pub mod mscratch {
|
||||||
|
use core::arch::asm;
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
pub fn write(bits: usize) {
|
||||||
|
unsafe {
|
||||||
|
asm!("csrw mscratch, {}", in(reg) bits);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Supervisor Trap Cause
|
||||||
|
pub mod scause {
|
||||||
|
use core::{arch::asm, mem::size_of};
|
||||||
|
|
||||||
|
// scause register
|
||||||
|
#[derive(Clone, Copy)]
|
||||||
|
pub struct Scause {
|
||||||
|
bits: usize,
|
||||||
|
}
|
||||||
|
|
||||||
|
// Trap Cause
|
||||||
|
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
|
||||||
|
pub enum Trap {
|
||||||
|
Interrupt(Interrupt),
|
||||||
|
Exception(Exception),
|
||||||
|
}
|
||||||
|
|
||||||
|
// Interrupt
|
||||||
|
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
|
||||||
|
pub enum Interrupt {
|
||||||
|
UserSoft,
|
||||||
|
SupervisorSoft,
|
||||||
|
UserTimer,
|
||||||
|
SupervisorTimer,
|
||||||
|
UserExternal,
|
||||||
|
SupervisorExternal,
|
||||||
|
Unknown,
|
||||||
|
}
|
||||||
|
|
||||||
|
// Exception
|
||||||
|
#[derive(Copy, Clone, Debug, Eq, PartialEq)]
|
||||||
|
pub enum Exception {
|
||||||
|
InstructionMisaligned,
|
||||||
|
InstructionFault,
|
||||||
|
IllegalInstruction,
|
||||||
|
Breakpoint,
|
||||||
|
LoadFault,
|
||||||
|
StoreMisaligned,
|
||||||
|
StoreFault,
|
||||||
|
UserEnvCall,
|
||||||
|
InstructionPageFault,
|
||||||
|
LoadPageFault,
|
||||||
|
StorePageFault,
|
||||||
|
Unknown,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Interrupt {
|
||||||
|
#[inline]
|
||||||
|
pub fn from(nr: usize) -> Self {
|
||||||
|
match nr {
|
||||||
|
0 => Interrupt::UserSoft,
|
||||||
|
1 => Interrupt::SupervisorSoft,
|
||||||
|
4 => Interrupt::UserTimer,
|
||||||
|
5 => Interrupt::SupervisorTimer,
|
||||||
|
8 => Interrupt::UserExternal,
|
||||||
|
9 => Interrupt::SupervisorExternal,
|
||||||
|
_ => Interrupt::Unknown,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Exception {
|
||||||
|
#[inline]
|
||||||
|
pub fn from(nr: usize) -> Self {
|
||||||
|
match nr {
|
||||||
|
0 => Exception::InstructionMisaligned,
|
||||||
|
1 => Exception::InstructionFault,
|
||||||
|
2 => Exception::IllegalInstruction,
|
||||||
|
3 => Exception::Breakpoint,
|
||||||
|
5 => Exception::LoadFault,
|
||||||
|
6 => Exception::StoreMisaligned,
|
||||||
|
7 => Exception::StoreFault,
|
||||||
|
8 => Exception::UserEnvCall,
|
||||||
|
12 => Exception::InstructionPageFault,
|
||||||
|
13 => Exception::LoadPageFault,
|
||||||
|
15 => Exception::StorePageFault,
|
||||||
|
_ => Exception::Unknown,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Scause {
|
||||||
|
// Returns the contents of the register as raw bits
|
||||||
|
#[inline]
|
||||||
|
pub fn bits(&self) -> usize {
|
||||||
|
self.bits
|
||||||
|
}
|
||||||
|
|
||||||
|
// Returns the code field
|
||||||
|
#[inline]
|
||||||
|
pub fn code(&self) -> usize {
|
||||||
|
let bit = 1 << (size_of::<usize>() * 8 - 1);
|
||||||
|
self.bits & !bit
|
||||||
|
}
|
||||||
|
|
||||||
|
// Trap cause
|
||||||
|
#[inline]
|
||||||
|
pub fn cause(&self) -> Trap {
|
||||||
|
if self.is_interrupt() {
|
||||||
|
Trap::Interrupt(Interrupt::from(self.code()))
|
||||||
|
} else {
|
||||||
|
Trap::Exception(Exception::from(self.code()))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Is trap cause an interrupt.
|
||||||
|
#[inline]
|
||||||
|
pub fn is_interrupt(&self) -> bool {
|
||||||
|
self.bits & (1 << (size_of::<usize>() * 8 - 1)) != 0
|
||||||
|
}
|
||||||
|
|
||||||
|
// Is trap cause an exception.
|
||||||
|
#[inline]
|
||||||
|
pub fn is_exception(&self) -> bool {
|
||||||
|
!self.is_interrupt()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
pub fn read() -> Scause {
|
||||||
|
let bits: usize;
|
||||||
|
unsafe {
|
||||||
|
asm!("csrr {}, scause", out(reg) bits);
|
||||||
|
}
|
||||||
|
Scause { bits }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Supervisor Trap Value
|
||||||
|
pub mod stval {
|
||||||
|
use core::arch::asm;
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
pub fn read() -> usize {
|
||||||
|
let bits: usize;
|
||||||
|
unsafe { asm!("csrr {}, stval", out(reg) bits) }
|
||||||
|
bits
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
use core::arch::asm;
|
||||||
|
|
||||||
|
use registers::*;
|
||||||
|
|
||||||
|
// enable device interrupts
|
||||||
|
#[inline]
|
||||||
|
pub fn intr_on() {
|
||||||
|
unsafe {
|
||||||
|
sstatus::set_sie();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// disable device interrupts
|
||||||
|
#[inline]
|
||||||
|
pub fn intr_off() {
|
||||||
|
unsafe {
|
||||||
|
sstatus::clear_sie();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// are device interrupts enabled?
|
||||||
|
#[inline]
|
||||||
|
pub fn intr_get() -> bool {
|
||||||
|
sstatus::read().sie()
|
||||||
|
}
|
||||||
|
|
||||||
|
// flush the TLB.
|
||||||
|
#[inline]
|
||||||
|
pub unsafe fn sfence_vma() {
|
||||||
|
// the zero, zero means flush all TLB entries
|
||||||
|
asm!("sfence.vma zero, zero");
|
||||||
|
}
|
||||||
|
|
||||||
|
pub const PGSIZE: usize = 4096; // bytes per page
|
||||||
|
pub const PGSHIFT: usize = 12; // bits of offset within a page
|
||||||
|
|
||||||
|
pub const fn pgroundup(sz: usize) -> usize {
|
||||||
|
(sz + PGSIZE - 1) & !(PGSIZE - 1)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub const fn pgrounddown(sz: usize) -> usize {
|
||||||
|
sz & !(PGSIZE - 1)
|
||||||
|
}
|
||||||
|
|
||||||
|
// PTE flags
|
||||||
|
pub mod pteflags {
|
||||||
|
pub const PTE_V: usize = 1 << 0; // valid
|
||||||
|
pub const PTE_R: usize = 1 << 1;
|
||||||
|
pub const PTE_W: usize = 1 << 2;
|
||||||
|
pub const PTE_X: usize = 1 << 3;
|
||||||
|
pub const PTE_U: usize = 1 << 4; // user can access
|
||||||
|
}
|
86
os/src/start.rs
Normal file
86
os/src/start.rs
Normal file
@ -0,0 +1,86 @@
|
|||||||
|
//use crate::kernelvec::*;
|
||||||
|
//use crate::memlayout::*;
|
||||||
|
//use crate::param::NCPU;
|
||||||
|
//use super::main::*;
|
||||||
|
//use crate::riscv::registers::{pmpcfg0::*, *};
|
||||||
|
use core::arch::asm;
|
||||||
|
use core::hint::unreachable_unchecked;
|
||||||
|
|
||||||
|
mod riscv;
|
||||||
|
|
||||||
|
#[repr(C, align(16))]
|
||||||
|
struct Stack([u8; 4096 * 4 * NCPU]);
|
||||||
|
|
||||||
|
#[no_mangle]
|
||||||
|
static mut STACK0: Stack = Stack([0; 4096 * 4 * NCPU]);
|
||||||
|
|
||||||
|
#[no_mangle]
|
||||||
|
pub unsafe fn rust_start() -> ! {
|
||||||
|
// set MPP mode to Supervisor, for mret
|
||||||
|
mstatus::set_mpp(mstatus::MPP::Supervisor);
|
||||||
|
|
||||||
|
// set MEPC to main, for mret
|
||||||
|
mepc::write(rust_main as usize);
|
||||||
|
|
||||||
|
// disable paging for now.
|
||||||
|
satp::write(0);
|
||||||
|
|
||||||
|
// delegate all interrupts and exceptions to supervisor mode.
|
||||||
|
medeleg::set_all();
|
||||||
|
mideleg::set_all();
|
||||||
|
sie::set_sext();
|
||||||
|
sie::set_ssoft();
|
||||||
|
sie::set_stimer();
|
||||||
|
|
||||||
|
// configure Physical Memory Protection to give supervisor mode
|
||||||
|
// access to all of physical memory.
|
||||||
|
pmpaddr0::write(0x3fffffffffffff);
|
||||||
|
pmpcfg0::set_pmp(0, Range::TOR, Permission::RWX, false); // 0 < addr < pmpaddr0
|
||||||
|
|
||||||
|
// ask for clock interrupts.
|
||||||
|
timerinit();
|
||||||
|
|
||||||
|
// keep each CPU's hartid in its tp register, for cpuid().
|
||||||
|
let id = mhartid::read();
|
||||||
|
asm!("mv tp, {0}", in(reg) id);
|
||||||
|
|
||||||
|
// switch to supervisor mode and jump to main().
|
||||||
|
asm!("mret");
|
||||||
|
|
||||||
|
extern "C" {
|
||||||
|
fn rust_main() -> !;
|
||||||
|
}
|
||||||
|
unreachable_unchecked();
|
||||||
|
}
|
||||||
|
|
||||||
|
// a scratch area per CPU for machine-mode timer interrupts.
|
||||||
|
static mut TIMER_SCRATCH: [[u64; 5]; 1] = [[0; 5]; 1];
|
||||||
|
|
||||||
|
unsafe fn timerinit() {
|
||||||
|
// each CPU has a separate source of timer interrupts
|
||||||
|
let id = mhartid::read();
|
||||||
|
|
||||||
|
// ask the CLINT for a timer interrupts
|
||||||
|
let interval = 1000000u64; // cycles; about 1/10th second in qemu.
|
||||||
|
let mtimecmp = clint_mtimecmp(id) as *mut u64;
|
||||||
|
let mtime = CLINT_MTIME as *const u64;
|
||||||
|
mtimecmp.write_volatile(mtime.read_volatile() + interval);
|
||||||
|
|
||||||
|
// prepare information in scratch[] for timervec.
|
||||||
|
// scratch[0..2] : space for timervec to save registers.
|
||||||
|
// scratch[3] : address of CLINT MTIMECMP register.
|
||||||
|
// scratch[4] : desired interval (in cycles) between timer interrupts.
|
||||||
|
let scratch = &mut TIMER_SCRATCH[id];
|
||||||
|
scratch[3] = mtimecmp as u64;
|
||||||
|
scratch[4] = interval;
|
||||||
|
mscratch::write(scratch.as_mut_ptr() as usize);
|
||||||
|
|
||||||
|
// set the machine-mode trap handler
|
||||||
|
mtvec::write(timervec as usize, mtvec::TrapMode::Direct);
|
||||||
|
|
||||||
|
// enable machine-mode interrupts.
|
||||||
|
mstatus::set_mie();
|
||||||
|
|
||||||
|
// enable machime-mode timer interrupts.
|
||||||
|
mie::set_mtimer();
|
||||||
|
}
|
@ -1,4 +1,5 @@
|
|||||||
const SYSCALL_DUP: usize = 24;
|
const SYSCALL_DUP: usize = 24;
|
||||||
|
const SYSCALL_CONNECT: usize = 29;
|
||||||
const SYSCALL_OPEN: usize = 56;
|
const SYSCALL_OPEN: usize = 56;
|
||||||
const SYSCALL_CLOSE: usize = 57;
|
const SYSCALL_CLOSE: usize = 57;
|
||||||
const SYSCALL_PIPE: usize = 59;
|
const SYSCALL_PIPE: usize = 59;
|
||||||
@ -36,6 +37,7 @@ mod input;
|
|||||||
mod process;
|
mod process;
|
||||||
mod sync;
|
mod sync;
|
||||||
mod thread;
|
mod thread;
|
||||||
|
mod net;
|
||||||
|
|
||||||
use fs::*;
|
use fs::*;
|
||||||
use gui::*;
|
use gui::*;
|
||||||
@ -43,10 +45,12 @@ use input::*;
|
|||||||
use process::*;
|
use process::*;
|
||||||
use sync::*;
|
use sync::*;
|
||||||
use thread::*;
|
use thread::*;
|
||||||
|
use net::*;
|
||||||
|
|
||||||
pub fn syscall(syscall_id: usize, args: [usize; 3]) -> isize {
|
pub fn syscall(syscall_id: usize, args: [usize; 3]) -> isize {
|
||||||
match syscall_id {
|
match syscall_id {
|
||||||
SYSCALL_DUP => sys_dup(args[0]),
|
SYSCALL_DUP => sys_dup(args[0]),
|
||||||
|
SYSCALL_CONNECT => sys_connect(args[0] as _, args[1] as _, args[2] as _),
|
||||||
SYSCALL_OPEN => sys_open(args[0] as *const u8, args[1] as u32),
|
SYSCALL_OPEN => sys_open(args[0] as *const u8, args[1] as u32),
|
||||||
SYSCALL_CLOSE => sys_close(args[0]),
|
SYSCALL_CLOSE => sys_close(args[0]),
|
||||||
SYSCALL_PIPE => sys_pipe(args[0] as *mut usize),
|
SYSCALL_PIPE => sys_pipe(args[0] as *mut usize),
|
||||||
|
14
os/src/syscall/net.rs
Normal file
14
os/src/syscall/net.rs
Normal file
@ -0,0 +1,14 @@
|
|||||||
|
use alloc::sync::Arc;
|
||||||
|
use crate::net::IPv4;
|
||||||
|
use crate::net::udp::UDP;
|
||||||
|
use crate::task::current_process;
|
||||||
|
|
||||||
|
// just support udp
|
||||||
|
pub fn sys_connect(raddr: u32, lport: u16, rport: u16) -> isize {
|
||||||
|
let process = current_process();
|
||||||
|
let mut inner = process.inner_exclusive_access();
|
||||||
|
let fd = inner.alloc_fd();
|
||||||
|
let udp_node = UDP::new(IPv4::from_u32(raddr), lport, rport);
|
||||||
|
inner.fd_table[fd] = Some(Arc::new(udp_node));
|
||||||
|
fd as isize
|
||||||
|
}
|
@ -11,7 +11,7 @@ use core::arch::{asm, global_asm};
|
|||||||
use riscv::register::{
|
use riscv::register::{
|
||||||
mtvec::TrapMode,
|
mtvec::TrapMode,
|
||||||
scause::{self, Exception, Interrupt, Trap},
|
scause::{self, Exception, Interrupt, Trap},
|
||||||
sie, sscratch, sstatus, stval, stvec,
|
sie, sscratch, sstatus, stval, stvec,sip
|
||||||
};
|
};
|
||||||
|
|
||||||
global_asm!(include_str!("trap.S"));
|
global_asm!(include_str!("trap.S"));
|
||||||
@ -95,10 +95,20 @@ pub fn trap_handler() -> ! {
|
|||||||
Trap::Exception(Exception::IllegalInstruction) => {
|
Trap::Exception(Exception::IllegalInstruction) => {
|
||||||
current_add_signal(SignalFlags::SIGILL);
|
current_add_signal(SignalFlags::SIGILL);
|
||||||
}
|
}
|
||||||
Trap::Interrupt(Interrupt::SupervisorTimer) => {
|
// Trap::Interrupt(Interrupt::SupervisorTimer) => {
|
||||||
set_next_trigger();
|
// set_next_trigger();
|
||||||
|
// check_timer();
|
||||||
|
// suspend_current_and_run_next();
|
||||||
|
// }
|
||||||
|
Trap::Interrupt(Interrupt::SupervisorSoft) => {
|
||||||
|
//set_next_trigger();
|
||||||
|
const SSIP: usize = 1 << 1;
|
||||||
|
unsafe {
|
||||||
|
asm!("csrc sip, {}", in(reg) SSIP);
|
||||||
|
}
|
||||||
|
//println!("TRAP: ssoft in Kern");
|
||||||
check_timer();
|
check_timer();
|
||||||
suspend_current_and_run_next();
|
// do not schedule now
|
||||||
}
|
}
|
||||||
Trap::Interrupt(Interrupt::SupervisorExternal) => {
|
Trap::Interrupt(Interrupt::SupervisorExternal) => {
|
||||||
crate::board::irq_handler();
|
crate::board::irq_handler();
|
||||||
@ -151,8 +161,18 @@ pub fn trap_from_kernel(_trap_cx: &TrapContext) {
|
|||||||
Trap::Interrupt(Interrupt::SupervisorExternal) => {
|
Trap::Interrupt(Interrupt::SupervisorExternal) => {
|
||||||
crate::board::irq_handler();
|
crate::board::irq_handler();
|
||||||
}
|
}
|
||||||
Trap::Interrupt(Interrupt::SupervisorTimer) => {
|
// Trap::Interrupt(Interrupt::SupervisorTimer) => {
|
||||||
set_next_trigger();
|
// //set_next_trigger();
|
||||||
|
// check_timer();
|
||||||
|
// // do not schedule now
|
||||||
|
// }
|
||||||
|
Trap::Interrupt(Interrupt::SupervisorSoft) => {
|
||||||
|
//set_next_trigger();
|
||||||
|
const SSIP: usize = 1 << 1;
|
||||||
|
unsafe {
|
||||||
|
asm!("csrc sip, {}", in(reg) SSIP);
|
||||||
|
}
|
||||||
|
//println!("TRAP: ssoft in Kern");
|
||||||
check_timer();
|
check_timer();
|
||||||
// do not schedule now
|
// do not schedule now
|
||||||
}
|
}
|
||||||
|
18
ping.py
Normal file
18
ping.py
Normal file
@ -0,0 +1,18 @@
|
|||||||
|
import socket
|
||||||
|
import sys
|
||||||
|
import time
|
||||||
|
|
||||||
|
sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
|
||||||
|
addr = ('localhost', 26099)
|
||||||
|
sock.bind(addr)
|
||||||
|
|
||||||
|
|
||||||
|
print("pinging...", file=sys.stderr)
|
||||||
|
while True:
|
||||||
|
buf, raddr = sock.recvfrom(4096)
|
||||||
|
print("receive: " + buf.decode("utf-8"))
|
||||||
|
buf = "this is a ping to port 6200!".encode('utf-8')
|
||||||
|
sock.sendto(buf, ("127.0.0.1", 6200))
|
||||||
|
buf = "this is a ping to reply!".encode('utf-8')
|
||||||
|
sock.sendto(buf, raddr)
|
||||||
|
time.sleep(1)
|
45
user/src/bin/udp.rs
Normal file
45
user/src/bin/udp.rs
Normal file
@ -0,0 +1,45 @@
|
|||||||
|
#![no_std]
|
||||||
|
#![no_main]
|
||||||
|
|
||||||
|
use alloc::string::String;
|
||||||
|
use user_lib::{connect, write, read};
|
||||||
|
|
||||||
|
#[macro_use]
|
||||||
|
extern crate user_lib;
|
||||||
|
#[macro_use]
|
||||||
|
extern crate alloc;
|
||||||
|
|
||||||
|
#[no_mangle]
|
||||||
|
pub fn main() -> i32 {
|
||||||
|
println!("udp test open!");
|
||||||
|
|
||||||
|
let udp_fd = connect(10 << 24 | 0 << 16 | 2 << 8 | 2, 2001, 26099);
|
||||||
|
|
||||||
|
if udp_fd < 0 {
|
||||||
|
println!("failed to create udp connection.");
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
let buf = "Hello rCoreOS user program!";
|
||||||
|
|
||||||
|
println!("send <{}>", buf);
|
||||||
|
|
||||||
|
write(udp_fd as usize, buf.as_bytes());
|
||||||
|
|
||||||
|
println!("udp send done, waiting for reply.");
|
||||||
|
|
||||||
|
let mut buf = vec![0u8; 1024];
|
||||||
|
|
||||||
|
let len = read(udp_fd as usize, &mut buf);
|
||||||
|
|
||||||
|
if len < 0 {
|
||||||
|
println!("can't receive udp packet");
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
let recv_str = String::from_utf8_lossy(&buf[..len as usize]);
|
||||||
|
|
||||||
|
println!("receive reply <{}>", recv_str);
|
||||||
|
|
||||||
|
0
|
||||||
|
}
|
@ -1,4 +1,5 @@
|
|||||||
const SYSCALL_DUP: usize = 24;
|
const SYSCALL_DUP: usize = 24;
|
||||||
|
const SYSCALL_CONNECT: usize = 29;
|
||||||
const SYSCALL_OPEN: usize = 56;
|
const SYSCALL_OPEN: usize = 56;
|
||||||
const SYSCALL_CLOSE: usize = 57;
|
const SYSCALL_CLOSE: usize = 57;
|
||||||
const SYSCALL_PIPE: usize = 59;
|
const SYSCALL_PIPE: usize = 59;
|
||||||
@ -48,6 +49,10 @@ pub fn sys_dup(fd: usize) -> isize {
|
|||||||
syscall(SYSCALL_DUP, [fd, 0, 0])
|
syscall(SYSCALL_DUP, [fd, 0, 0])
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn sys_connect(dest: u32, sport: u16, dport: u16) -> isize {
|
||||||
|
syscall(SYSCALL_CONNECT, [dest as usize, sport as usize, dport as usize])
|
||||||
|
}
|
||||||
|
|
||||||
pub fn sys_open(path: &str, flags: u32) -> isize {
|
pub fn sys_open(path: &str, flags: u32) -> isize {
|
||||||
syscall(SYSCALL_OPEN, [path.as_ptr() as usize, flags as usize, 0])
|
syscall(SYSCALL_OPEN, [path.as_ptr() as usize, flags as usize, 0])
|
||||||
}
|
}
|
||||||
|
@ -18,6 +18,9 @@ pub fn fork() -> isize {
|
|||||||
pub fn exec(path: &str, args: &[*const u8]) -> isize {
|
pub fn exec(path: &str, args: &[*const u8]) -> isize {
|
||||||
sys_exec(path, args)
|
sys_exec(path, args)
|
||||||
}
|
}
|
||||||
|
pub fn connect(raddr: u32, lport: u16, rport: u16) -> isize {
|
||||||
|
sys_connect(raddr, lport, rport)
|
||||||
|
}
|
||||||
pub fn wait(exit_code: &mut i32) -> isize {
|
pub fn wait(exit_code: &mut i32) -> isize {
|
||||||
loop {
|
loop {
|
||||||
match sys_waitpid(-1, exit_code as *mut _) {
|
match sys_waitpid(-1, exit_code as *mut _) {
|
||||||
|
Loading…
Reference in New Issue
Block a user