From 3337b81d8916c8926b939c5c8d9091f6267d5313 Mon Sep 17 00:00:00 2001 From: Yu Chen Date: Thu, 23 Jun 2022 22:41:51 +0800 Subject: [PATCH 01/14] update README --- README.md | 40 +++++++++++++++++----------------------- 1 file changed, 17 insertions(+), 23 deletions(-) diff --git a/README.md b/README.md index c65d14c..767cb14 100644 --- a/README.md +++ b/README.md @@ -1,5 +1,5 @@ # rCore-Tutorial-v3 -rCore-Tutorial version 3.5. See the [Documentation in Chinese](https://rcore-os.github.io/rCore-Tutorial-Book-v3/). +rCore-Tutorial version 3.6. See the [Documentation in Chinese](https://rcore-os.github.io/rCore-Tutorial-Book-v3/). rCore-Tutorial API Docs. See the [API Docs of Ten OSes ](#OS-API-DOCS) @@ -8,7 +8,7 @@ If you don't know Rust Language and try to learn it, please visit [Rust Learnin Official QQ group number: 735045051 ## news -- 25/01/2022: Version 3.6.0 is on the way! Now we directly update the code on chX branches, please periodically check if there are any updates. +- 23/06/2022: Version 3.6.0 is on the way! Now we directly update the code on chX branches, please periodically check if there are any updates. ## Overview @@ -44,7 +44,7 @@ $ rustup component add rust-src ### Install Qemu -Here we manually compile and install Qemu 5.0.0. For example, on Ubuntu 18.04: +Here we manually compile and install Qemu 7.0.0. For example, on Ubuntu 18.04: ```sh # install dependency packages @@ -52,10 +52,10 @@ $ sudo apt install autoconf automake autotools-dev curl libmpc-dev libmpfr-dev l gawk build-essential bison flex texinfo gperf libtool patchutils bc \ zlib1g-dev libexpat-dev pkg-config libglib2.0-dev libpixman-1-dev git tmux python3 python3-pip # download Qemu source code -$ wget https://download.qemu.org/qemu-5.0.0.tar.xz -# extract to qemu-5.0.0/ -$ tar xvJf qemu-5.0.0.tar.xz -$ cd qemu-5.0.0 +$ wget https://download.qemu.org/qemu-7.0.0.tar.xz +# extract to qemu-7.0.0/ +$ tar xvJf qemu-7.0.0.tar.xz +$ cd qemu-7.0.0 # build $ ./configure --target-list=riscv64-softmmu,riscv64-linux-user $ make -j$(nproc) @@ -64,9 +64,9 @@ $ make -j$(nproc) Then, add following contents to `~/.bashrc`(please adjust these paths according to your environment): ``` -export PATH=$PATH:/home/shinbokuow/Downloads/built/qemu-5.0.0 -export PATH=$PATH:/home/shinbokuow/Downloads/built/qemu-5.0.0/riscv64-softmmu -export PATH=$PATH:/home/shinbokuow/Downloads/built/qemu-5.0.0/riscv64-linux-user +export PATH=$PATH:/home/shinbokuow/Downloads/built/qemu-7.0.0 +export PATH=$PATH:/home/shinbokuow/Downloads/built/qemu-7.0.0/riscv64-softmmu +export PATH=$PATH:/home/shinbokuow/Downloads/built/qemu-7.0.0/riscv64-linux-user ``` Finally, update the current shell: @@ -79,7 +79,7 @@ Now we can check the version of Qemu: ```sh $ qemu-system-riscv64 --version -QEMU emulator version 5.0.0 +QEMU emulator version 7.0.0 Copyright (c) 2003-2020 Fabrice Bellard and the QEMU Project developers ``` @@ -251,13 +251,9 @@ The API Docs for Ten OS ## Working in progress -Our first release 3.5.0 (chapter 1-7) has been published. +Our first release 3.6.0 (chapter 1-9) has been published, and we are still working on it. -There will be 9 chapters in our next release 3.6.0, where 2 new chapters will be added: -* chapter 8: synchronization on a uniprocessor -* chapter 9: I/O devices - -Current version is 3.6.0-alpha.1 and we are still working on it. +* chapter 9: need more descripts about different I/O devices Here are the updates since 3.5.0: @@ -279,18 +275,16 @@ Here are the updates since 3.5.0: * [x] switch the code of chapter 6 and chapter 7 * [x] support signal mechanism in chapter 7/8(only works for apps with a single thread) * [x] Add boards/ directory and support rustdoc, for example you can use `cargo doc --no-deps --open` to view the documentation of a crate - +* [x] code of chapter 9: device drivers based on interrupts, including UART, block, keyboard, mouse, gpu devices +* [x] add CI autotest and doc in github ### Todo(High priority) -* [ ] review documentation, current progress: 5/9 -* [ ] support user-level sync primitives in chapter 8 -* [ ] code of chapter 9: device drivers based on interrupts, including UART and block devices +* [ ] review documentation, current progress: 8/9 * [ ] use old fs image optionally, do not always rebuild the image -* [ ] add new system calls: getdents64/fstat * [ ] shell functionality improvement(to be continued...) * [ ] give every non-zero process exit code an unique and clear error type * [ ] effective error handling of mm module - +* [ ] add more os functions for understanding os conecpts and principles ### Todo(Low priority) * [ ] rewrite practice doc and remove some inproper questions From 58bf26222f0946495827a86ef6b04f40e2fdb114 Mon Sep 17 00:00:00 2001 From: Yu Chen Date: Mon, 2 Jan 2023 11:28:06 +0800 Subject: [PATCH 02/14] run in qemu -bios none ENV --- os/Makefile | 18 +- os/src/boards/qemu.rs | 53 +++- os/src/entry.asm | 2 +- os/src/linker-qemu.ld | 2 +- os/src/main.rs | 92 ++++++- os/src/riscvregs.rs | 614 ++++++++++++++++++++++++++++++++++++++++++ os/src/start.rs | 86 ++++++ 7 files changed, 858 insertions(+), 9 deletions(-) create mode 100644 os/src/riscvregs.rs create mode 100644 os/src/start.rs diff --git a/os/Makefile b/os/Makefile index e02bc81..a8f180f 100644 --- a/os/Makefile +++ b/os/Makefile @@ -24,7 +24,7 @@ ifeq ($(MODE), release) endif # KERNEL ENTRY -KERNEL_ENTRY_PA := 0x80200000 +KERNEL_ENTRY_PA := 0x80000000 # Binutils OBJDUMP := rust-objdump --arch-name=riscv64 @@ -71,7 +71,21 @@ disasm-vim: kernel @nvim $(DISASM_TMP) @rm $(DISASM_TMP) -run: run-inner +run: run-inner-none + +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 \ + -serial stdio run-inner: build @qemu-system-riscv64 \ diff --git a/os/src/boards/qemu.rs b/os/src/boards/qemu.rs index ffabff6..d68ee2f 100644 --- a/os/src/boards/qemu.rs +++ b/os/src/boards/qemu.rs @@ -2,7 +2,7 @@ pub const CLOCK_FREQ: usize = 12500000; pub const MMIO: &[(usize, usize)] = &[ (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 (0x10000000, 0x9000), // VIRT_UART0 with GPU in virt machine ]; @@ -53,6 +53,57 @@ pub fn irq_handler() { 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. + +#[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 use core::arch::asm; diff --git a/os/src/entry.asm b/os/src/entry.asm index c32d68f..1d1a175 100644 --- a/os/src/entry.asm +++ b/os/src/entry.asm @@ -2,7 +2,7 @@ .globl _start _start: la sp, boot_stack_top - call rust_main + call rust_start .section .bss.stack .globl boot_stack_lower_bound diff --git a/os/src/linker-qemu.ld b/os/src/linker-qemu.ld index 5baafbd..92dd51c 100644 --- a/os/src/linker-qemu.ld +++ b/os/src/linker-qemu.ld @@ -1,6 +1,6 @@ OUTPUT_ARCH(riscv) ENTRY(_start) -BASE_ADDRESS = 0x80200000; +BASE_ADDRESS = 0x80000000; SECTIONS { diff --git a/os/src/main.rs b/os/src/main.rs index 299e4cf..7859560 100644 --- a/os/src/main.rs +++ b/os/src/main.rs @@ -2,6 +2,8 @@ #![no_main] #![feature(panic_info_message)] #![feature(alloc_error_handler)] +#![feature(naked_functions)] +#![feature(fn_align)] use crate::drivers::{GPU_DEVICE, KEYBOARD_DEVICE, MOUSE_DEVICE}; @@ -27,7 +29,10 @@ mod syscall; mod task; mod timer; mod trap; - +//mod start; +mod riscvregs; +use riscvregs::registers::*; +use riscvregs::registers::pmpcfg0::*; //use syscall::create_desktop; //for test core::arch::global_asm!(include_str!("entry.asm")); @@ -51,6 +56,85 @@ lazy_static! { 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]); + +#[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(); + 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(); +} + +// 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 = board::clint_mtimecmp(id) 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[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(board::timervec as usize, mtvec::TrapMode::Direct); + + // enable machine-mode interrupts. + mstatus::set_mie(); + + // enable machime-mode timer interrupts. + mie::set_mtimer(); +} + + #[no_mangle] pub fn rust_main() -> ! { clear_bss(); @@ -63,11 +147,11 @@ pub fn rust_main() -> ! { let _mouse = MOUSE_DEVICE.clone(); println!("KERN: init trap"); trap::init(); - trap::enable_timer_interrupt(); - timer::set_next_trigger(); + //trap::enable_timer_interrupt(); + //timer::set_next_trigger(); board::device_init(); fs::list_apps(); - gui::init_paint(); + //gui::init_paint(); task::add_initproc(); *DEV_NON_BLOCKING_ACCESS.exclusive_access() = true; task::run_tasks(); diff --git a/os/src/riscvregs.rs b/os/src/riscvregs.rs new file mode 100644 index 0000000..1871242 --- /dev/null +++ b/os/src/riscvregs.rs @@ -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::() * 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::() * 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 +} diff --git a/os/src/start.rs b/os/src/start.rs new file mode 100644 index 0000000..3a6d391 --- /dev/null +++ b/os/src/start.rs @@ -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(); +} \ No newline at end of file From 2e57ec432a1cedbcec9cbc1c67f0de3b58667fd5 Mon Sep 17 00:00:00 2001 From: Yu Chen Date: Mon, 2 Jan 2023 20:06:03 +0800 Subject: [PATCH 03/14] temp stage --- os/Cargo.toml | 1 + os/Makefile | 12 +++ os/src/boards/qemu.rs | 7 +- os/src/main.rs | 186 ++++++++++++++++++++++++++++++++++-------- os/src/trap/mod.rs | 24 +++++- 5 files changed, 190 insertions(+), 40 deletions(-) diff --git a/os/Cargo.toml b/os/Cargo.toml index f4b2d80..3cae609 100644 --- a/os/Cargo.toml +++ b/os/Cargo.toml @@ -10,6 +10,7 @@ edition = "2021" riscv = { git = "https://github.com/rcore-os/riscv", features = ["inline-asm"] } lazy_static = { version = "1.4.0", features = ["spin_no_std"] } buddy_system_allocator = "0.6" +bit_field = "0.10.0" bitflags = "1.2.1" xmas-elf = "0.7.0" volatile = "0.3" diff --git a/os/Makefile b/os/Makefile index a8f180f..4331ae5 100644 --- a/os/Makefile +++ b/os/Makefile @@ -105,6 +105,18 @@ fdt: @qemu-system-riscv64 -M 128m -machine virt,dumpdtb=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 @tmux new-session -d \ "qemu-system-riscv64 -machine virt -nographic -bios $(BOOTLOADER) -device loader,file=$(KERNEL_BIN),addr=$(KERNEL_ENTRY_PA) -s -S" && \ diff --git a/os/src/boards/qemu.rs b/os/src/boards/qemu.rs index d68ee2f..6217925 100644 --- a/os/src/boards/qemu.rs +++ b/os/src/boards/qemu.rs @@ -56,10 +56,11 @@ pub fn irq_handler() { // 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 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. diff --git a/os/src/main.rs b/os/src/main.rs index 7859560..c720b59 100644 --- a/os/src/main.rs +++ b/os/src/main.rs @@ -14,7 +14,7 @@ extern crate bitflags; #[path = "boards/qemu.rs"] mod board; - +use board::*; #[macro_use] mod console; mod config; @@ -29,10 +29,15 @@ mod syscall; mod task; mod timer; mod trap; -//mod start; -mod riscvregs; -use riscvregs::registers::*; -use riscvregs::registers::pmpcfg0::*; + +use riscv::register::*; +// 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")); @@ -63,6 +68,41 @@ 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 @@ -75,23 +115,21 @@ pub unsafe fn rust_start() -> ! { 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(); + 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::set_pmp(0, Range::TOR, Permission::RWX, false); // 0 < addr < pmpaddr0 + //pmpaddr0::write(0x3fffffffffffff); + //pmpcfg0::set_pmp(0, Range::TOR, Permission::RWX, false); // 0 < addr < pmpaddr0 // ask for clock interrupts. - timerinit(); + 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); + // 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"); @@ -102,49 +140,127 @@ pub unsafe fn rust_start() -> ! { core::hint::unreachable_unchecked(); } -// a scratch area per CPU for machine-mode timer interrupts. -static mut TIMER_SCRATCH: [[u64; 5]; 1] = [[0; 5]; 1]; +use core::convert::Into; +use core::ptr; -unsafe fn timerinit() { +// 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::::into(CLINT_MTIME) as *const u64) +} + +unsafe fn write_mtimecmp(value: u64) { + let offset = Into::::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::::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() { // each CPU has a separate source of timer interrupts - let id = mhartid::read(); + //let id = mhartid::read(); // ask the CLINT for a timer interrupts let interval = 1000000u64; // cycles; about 1/10th second in qemu. - let mtimecmp = board::clint_mtimecmp(id) as *mut u64; - let mtime = board::CLINT_MTIME as *const u64; - mtimecmp.write_volatile(mtime.read_volatile() + interval); + 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[id]; - scratch[3] = mtimecmp as u64; + 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(board::timervec as usize, mtvec::TrapMode::Direct); + mtvec_write(timervec as usize); + //mtvec::write(board::timervec as usize, mtvec::TrapMode::Direct); // enable machine-mode interrupts. - mstatus::set_mie(); + mstatus_enable_interrupt(); + //mstatus::set_mie(); - // enable machime-mode timer interrupts. - mie::set_mtimer(); + // enable machine-mode timer interrupts. + mie_write(mie_read() | MIE::MTIE as usize); + //mie::set_mtimer(); } #[no_mangle] pub fn rust_main() -> ! { - clear_bss(); + + //clear_bss(); + + //println!("KERN: begin"); + mm::init(); - println!("KERN: init gpu"); - let _gpu = GPU_DEVICE.clone(); - println!("KERN: init keyboard"); - let _keyboard = KEYBOARD_DEVICE.clone(); - println!("KERN: init mouse"); - let _mouse = MOUSE_DEVICE.clone(); + loop{}; + //println!("KERN: init gpu"); + //let _gpu = GPU_DEVICE.clone(); + // println!("KERN: init keyboard"); + // let _keyboard = KEYBOARD_DEVICE.clone(); + //println!("KERN: init mouse"); + //let _mouse = MOUSE_DEVICE.clone(); println!("KERN: init trap"); trap::init(); //trap::enable_timer_interrupt(); diff --git a/os/src/trap/mod.rs b/os/src/trap/mod.rs index cb4a7ad..05a9126 100644 --- a/os/src/trap/mod.rs +++ b/os/src/trap/mod.rs @@ -11,7 +11,7 @@ use core::arch::{asm, global_asm}; use riscv::register::{ mtvec::TrapMode, scause::{self, Exception, Interrupt, Trap}, - sie, sscratch, sstatus, stval, stvec, + sie, sscratch, sstatus, stval, stvec,sip }; global_asm!(include_str!("trap.S")); @@ -100,6 +100,16 @@ pub fn trap_handler() -> ! { 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(); + // do not schedule now + } Trap::Interrupt(Interrupt::SupervisorExternal) => { crate::board::irq_handler(); } @@ -152,7 +162,17 @@ pub fn trap_from_kernel(_trap_cx: &TrapContext) { crate::board::irq_handler(); } 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(); // do not schedule now } From b1c5751546684e19c2b63a8a130978a5725abd4e Mon Sep 17 00:00:00 2001 From: Yu Chen Date: Tue, 3 Jan 2023 08:45:00 +0800 Subject: [PATCH 04/14] temp stage2:add pmpaddr0/pmpcfg0 setup --- os/src/main.rs | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/os/src/main.rs b/os/src/main.rs index c720b59..56fba0c 100644 --- a/os/src/main.rs +++ b/os/src/main.rs @@ -121,7 +121,8 @@ pub unsafe fn rust_start() -> ! { // configure Physical Memory Protection to give supervisor mode // access to all of physical memory. - //pmpaddr0::write(0x3fffffffffffff); + pmpaddr0::write(0x3fffffffffffff); + pmpcfg0::write(0xf); //pmpcfg0::set_pmp(0, Range::TOR, Permission::RWX, false); // 0 < addr < pmpaddr0 // ask for clock interrupts. @@ -249,12 +250,12 @@ unsafe fn timer_init() { #[no_mangle] pub fn rust_main() -> ! { - //clear_bss(); + clear_bss(); - //println!("KERN: begin"); + println!("KERN: begin"); mm::init(); - loop{}; + //loop{}; //println!("KERN: init gpu"); //let _gpu = GPU_DEVICE.clone(); // println!("KERN: init keyboard"); From e71bbcbc8d2f51b89a0efe985be07e8966ffb211 Mon Sep 17 00:00:00 2001 From: Yu Chen Date: Tue, 3 Jan 2023 09:50:56 +0800 Subject: [PATCH 05/14] in gdb mode, OK. For the safety of TIMER_SCRATCH, put clear_bss Fn in rust_start. and explicitly UART.init in rust_main. --- os/src/drivers/chardev/mod.rs | 1 + os/src/drivers/chardev/ns16550a.rs | 7 ++++++- os/src/main.rs | 17 +++++++++-------- 3 files changed, 16 insertions(+), 9 deletions(-) diff --git a/os/src/drivers/chardev/mod.rs b/os/src/drivers/chardev/mod.rs index de1446d..64c168f 100644 --- a/os/src/drivers/chardev/mod.rs +++ b/os/src/drivers/chardev/mod.rs @@ -6,6 +6,7 @@ use lazy_static::*; pub use ns16550a::NS16550a; pub trait CharDevice { + fn init(&self); fn read(&self) -> u8; fn write(&self, ch: u8); fn handle_irq(&self); diff --git a/os/src/drivers/chardev/ns16550a.rs b/os/src/drivers/chardev/ns16550a.rs index da29063..de53b3e 100644 --- a/os/src/drivers/chardev/ns16550a.rs +++ b/os/src/drivers/chardev/ns16550a.rs @@ -135,7 +135,7 @@ impl NS16550a { ns16550a: NS16550aRaw::new(BASE_ADDR), read_buffer: VecDeque::new(), }; - inner.ns16550a.init(); + //inner.ns16550a.init(); Self { inner: unsafe { UPIntrFreeCell::new(inner) }, condvar: Condvar::new(), @@ -144,6 +144,11 @@ impl NS16550a { } impl CharDevice for NS16550a { + fn init(&self){ + let mut inner = self.inner.exclusive_access(); + inner.ns16550a.init(); + drop(inner); + } fn read(&self) -> u8 { loop { let mut inner = self.inner.exclusive_access(); diff --git a/os/src/main.rs b/os/src/main.rs index 56fba0c..4440253 100644 --- a/os/src/main.rs +++ b/os/src/main.rs @@ -214,6 +214,7 @@ pub unsafe fn mie_write(x:usize){ } unsafe fn timer_init() { + clear_bss(); // each CPU has a separate source of timer interrupts //let id = mhartid::read(); @@ -246,19 +247,19 @@ unsafe fn timer_init() { //mie::set_mtimer(); } - +use crate::drivers::chardev::CharDevice; +use crate::drivers::chardev::UART; #[no_mangle] pub fn rust_main() -> ! { - clear_bss(); - - println!("KERN: begin"); - + //clear_bss(); mm::init(); + UART.init(); + println!("KERN: begin"); //loop{}; - //println!("KERN: init gpu"); - //let _gpu = GPU_DEVICE.clone(); - // println!("KERN: init keyboard"); + println!("KERN: init gpu"); + let _gpu = GPU_DEVICE.clone(); + println!("KERN: init keyboard"); // let _keyboard = KEYBOARD_DEVICE.clone(); //println!("KERN: init mouse"); //let _mouse = MOUSE_DEVICE.clone(); From 4aaa7f9206cbbb766dc8967e720daf75083aba33 Mon Sep 17 00:00:00 2001 From: Yu Chen Date: Tue, 3 Jan 2023 10:05:40 +0800 Subject: [PATCH 06/14] update code, now '-bios none' can get the same result as ch9 --- os/Makefile | 2 +- os/src/main.rs | 6 +++--- os/src/trap/mod.rs | 24 ++++++++++++------------ 3 files changed, 16 insertions(+), 16 deletions(-) diff --git a/os/Makefile b/os/Makefile index 4331ae5..6b7e9cf 100644 --- a/os/Makefile +++ b/os/Makefile @@ -71,7 +71,7 @@ disasm-vim: kernel @nvim $(DISASM_TMP) @rm $(DISASM_TMP) -run: run-inner-none +run: run-inner run-inner-none: build @qemu-system-riscv64 \ diff --git a/os/src/main.rs b/os/src/main.rs index 4440253..b9b5f15 100644 --- a/os/src/main.rs +++ b/os/src/main.rs @@ -260,9 +260,9 @@ pub fn rust_main() -> ! { println!("KERN: init gpu"); let _gpu = GPU_DEVICE.clone(); println!("KERN: init keyboard"); - // let _keyboard = KEYBOARD_DEVICE.clone(); - //println!("KERN: init mouse"); - //let _mouse = MOUSE_DEVICE.clone(); + let _keyboard = KEYBOARD_DEVICE.clone(); + println!("KERN: init mouse"); + let _mouse = MOUSE_DEVICE.clone(); println!("KERN: init trap"); trap::init(); //trap::enable_timer_interrupt(); diff --git a/os/src/trap/mod.rs b/os/src/trap/mod.rs index 05a9126..6040c7f 100644 --- a/os/src/trap/mod.rs +++ b/os/src/trap/mod.rs @@ -95,18 +95,18 @@ pub fn trap_handler() -> ! { Trap::Exception(Exception::IllegalInstruction) => { current_add_signal(SignalFlags::SIGILL); } - Trap::Interrupt(Interrupt::SupervisorTimer) => { - set_next_trigger(); - check_timer(); - suspend_current_and_run_next(); - } + // Trap::Interrupt(Interrupt::SupervisorTimer) => { + // 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"); + //println!("TRAP: ssoft in Kern"); check_timer(); // do not schedule now } @@ -161,18 +161,18 @@ pub fn trap_from_kernel(_trap_cx: &TrapContext) { Trap::Interrupt(Interrupt::SupervisorExternal) => { crate::board::irq_handler(); } - Trap::Interrupt(Interrupt::SupervisorTimer) => { - //set_next_trigger(); - check_timer(); - // do not schedule now - } + // Trap::Interrupt(Interrupt::SupervisorTimer) => { + // //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"); + //println!("TRAP: ssoft in Kern"); check_timer(); // do not schedule now } From ffe22a57fb6ea701d8106a32a72ed498ec35b534 Mon Sep 17 00:00:00 2001 From: Yifan Wu Date: Fri, 27 Jan 2023 16:57:40 +0800 Subject: [PATCH 07/14] update mpsc_sem --- user/src/bin/mpsc_sem.rs | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/user/src/bin/mpsc_sem.rs b/user/src/bin/mpsc_sem.rs index 7b92b9b..7b72bbb 100644 --- a/user/src/bin/mpsc_sem.rs +++ b/user/src/bin/mpsc_sem.rs @@ -14,7 +14,7 @@ use user_lib::{thread_create, waittid}; const SEM_MUTEX: usize = 0; const SEM_EMPTY: usize = 1; -const SEM_EXISTED: usize = 2; +const SEM_AVAIL: usize = 2; const BUFFER_SIZE: usize = 8; static mut BUFFER: [usize; BUFFER_SIZE] = [0; BUFFER_SIZE]; static mut FRONT: usize = 0; @@ -27,20 +27,20 @@ unsafe fn producer(id: *const usize) -> ! { for _ in 0..NUMBER_PER_PRODUCER { semaphore_down(SEM_EMPTY); semaphore_down(SEM_MUTEX); - BUFFER[FRONT] = id; - FRONT = (FRONT + 1) % BUFFER_SIZE; + BUFFER[TAIL] = id; + TAIL = (TAIL + 1) % BUFFER_SIZE; semaphore_up(SEM_MUTEX); - semaphore_up(SEM_EXISTED); + semaphore_up(SEM_AVAIL); } exit(0) } unsafe fn consumer() -> ! { for _ in 0..PRODUCER_COUNT * NUMBER_PER_PRODUCER { - semaphore_down(SEM_EXISTED); + semaphore_down(SEM_AVAIL); semaphore_down(SEM_MUTEX); - print!("{} ", BUFFER[TAIL]); - TAIL = (TAIL + 1) % BUFFER_SIZE; + print!("{} ", BUFFER[FRONT]); + FRONT = (FRONT + 1) % BUFFER_SIZE; semaphore_up(SEM_MUTEX); semaphore_up(SEM_EMPTY); } @@ -53,7 +53,7 @@ pub fn main() -> i32 { // create semaphores assert_eq!(semaphore_create(1) as usize, SEM_MUTEX); assert_eq!(semaphore_create(BUFFER_SIZE) as usize, SEM_EMPTY); - assert_eq!(semaphore_create(0) as usize, SEM_EXISTED); + assert_eq!(semaphore_create(0) as usize, SEM_AVAIL); // create threads let ids: Vec<_> = (0..PRODUCER_COUNT).collect(); let mut threads = Vec::new(); From 9d9d3f496b87cd3eaa0f489bc8004e547632c1db Mon Sep 17 00:00:00 2001 From: Yifan Wu Date: Wed, 1 Feb 2023 20:46:07 +0800 Subject: [PATCH 08/14] update condvar-related testcases. --- os/src/syscall/mod.rs | 2 +- os/src/syscall/sync.rs | 2 +- user/src/bin/barrier_condvar.rs | 2 +- .../{test_condvar.rs => condsync_condvar.rs} | 118 +++++++++--------- user/src/bin/condsync_sem.rs | 64 ++++++++++ user/src/sync.rs | 2 +- user/src/syscall.rs | 4 +- 7 files changed, 129 insertions(+), 65 deletions(-) rename user/src/bin/{test_condvar.rs => condsync_condvar.rs} (95%) create mode 100644 user/src/bin/condsync_sem.rs diff --git a/os/src/syscall/mod.rs b/os/src/syscall/mod.rs index d28073f..4052cf5 100644 --- a/os/src/syscall/mod.rs +++ b/os/src/syscall/mod.rs @@ -70,7 +70,7 @@ pub fn syscall(syscall_id: usize, args: [usize; 3]) -> isize { SYSCALL_SEMAPHORE_CREATE => sys_semaphore_create(args[0]), SYSCALL_SEMAPHORE_UP => sys_semaphore_up(args[0]), SYSCALL_SEMAPHORE_DOWN => sys_semaphore_down(args[0]), - SYSCALL_CONDVAR_CREATE => sys_condvar_create(args[0]), + SYSCALL_CONDVAR_CREATE => sys_condvar_create(), SYSCALL_CONDVAR_SIGNAL => sys_condvar_signal(args[0]), SYSCALL_CONDVAR_WAIT => sys_condvar_wait(args[0], args[1]), SYSCALL_FRAMEBUFFER => sys_framebuffer(), diff --git a/os/src/syscall/sync.rs b/os/src/syscall/sync.rs index e08f329..1180669 100644 --- a/os/src/syscall/sync.rs +++ b/os/src/syscall/sync.rs @@ -93,7 +93,7 @@ pub fn sys_semaphore_down(sem_id: usize) -> isize { 0 } -pub fn sys_condvar_create(_arg: usize) -> isize { +pub fn sys_condvar_create() -> isize { let process = current_process(); let mut process_inner = process.inner_exclusive_access(); let id = if let Some(id) = process_inner diff --git a/user/src/bin/barrier_condvar.rs b/user/src/bin/barrier_condvar.rs index db0a80b..ca0953b 100644 --- a/user/src/bin/barrier_condvar.rs +++ b/user/src/bin/barrier_condvar.rs @@ -28,7 +28,7 @@ impl Barrier { } pub fn block(&self) { mutex_lock(self.mutex_id); - let mut count = self.count.get(); + let count = self.count.get(); // SAFETY: Here, the accesses of the count is in the // critical section protected by the mutex. unsafe { *count = *count + 1; } diff --git a/user/src/bin/test_condvar.rs b/user/src/bin/condsync_condvar.rs similarity index 95% rename from user/src/bin/test_condvar.rs rename to user/src/bin/condsync_condvar.rs index 2db9d8a..78605ad 100644 --- a/user/src/bin/test_condvar.rs +++ b/user/src/bin/condsync_condvar.rs @@ -1,59 +1,59 @@ -#![no_std] -#![no_main] - -#[macro_use] -extern crate user_lib; - -extern crate alloc; - -use alloc::vec; -use user_lib::exit; -use user_lib::{ - condvar_create, condvar_signal, condvar_wait, mutex_blocking_create, mutex_lock, mutex_unlock, -}; -use user_lib::{sleep, thread_create, waittid}; - -static mut A: usize = 0; - -const CONDVAR_ID: usize = 0; -const MUTEX_ID: usize = 0; - -unsafe fn first() -> ! { - sleep(10); - println!("First work, Change A --> 1 and wakeup Second"); - mutex_lock(MUTEX_ID); - A = 1; - condvar_signal(CONDVAR_ID); - mutex_unlock(MUTEX_ID); - exit(0) -} - -unsafe fn second() -> ! { - println!("Second want to continue,but need to wait A=1"); - mutex_lock(MUTEX_ID); - while A == 0 { - println!("Second: A is {}", A); - condvar_wait(CONDVAR_ID, MUTEX_ID); - } - mutex_unlock(MUTEX_ID); - println!("A is {}, Second can work now", A); - exit(0) -} - -#[no_mangle] -pub fn main() -> i32 { - // create condvar & mutex - assert_eq!(condvar_create() as usize, CONDVAR_ID); - assert_eq!(mutex_blocking_create() as usize, MUTEX_ID); - // create threads - let threads = vec![ - thread_create(first as usize, 0), - thread_create(second as usize, 0), - ]; - // wait for all threads to complete - for thread in threads.iter() { - waittid(*thread as usize); - } - println!("test_condvar passed!"); - 0 -} +#![no_std] +#![no_main] + +#[macro_use] +extern crate user_lib; + +extern crate alloc; + +use alloc::vec; +use user_lib::exit; +use user_lib::{ + condvar_create, condvar_signal, condvar_wait, mutex_blocking_create, mutex_lock, mutex_unlock, +}; +use user_lib::{sleep, thread_create, waittid}; + +static mut A: usize = 0; + +const CONDVAR_ID: usize = 0; +const MUTEX_ID: usize = 0; + +unsafe fn first() -> ! { + sleep(10); + println!("First work, Change A --> 1 and wakeup Second"); + mutex_lock(MUTEX_ID); + A = 1; + condvar_signal(CONDVAR_ID); + mutex_unlock(MUTEX_ID); + exit(0) +} + +unsafe fn second() -> ! { + println!("Second want to continue,but need to wait A=1"); + mutex_lock(MUTEX_ID); + while A == 0 { + println!("Second: A is {}", A); + condvar_wait(CONDVAR_ID, MUTEX_ID); + } + println!("A is {}, Second can work now", A); + mutex_unlock(MUTEX_ID); + exit(0) +} + +#[no_mangle] +pub fn main() -> i32 { + // create condvar & mutex + assert_eq!(condvar_create() as usize, CONDVAR_ID); + assert_eq!(mutex_blocking_create() as usize, MUTEX_ID); + // create threads + let threads = vec![ + thread_create(first as usize, 0), + thread_create(second as usize, 0), + ]; + // wait for all threads to complete + for thread in threads.iter() { + waittid(*thread as usize); + } + println!("test_condvar passed!"); + 0 +} diff --git a/user/src/bin/condsync_sem.rs b/user/src/bin/condsync_sem.rs new file mode 100644 index 0000000..d7b875a --- /dev/null +++ b/user/src/bin/condsync_sem.rs @@ -0,0 +1,64 @@ +#![no_std] +#![no_main] + +#[macro_use] +extern crate user_lib; + +extern crate alloc; + +use alloc::vec; +use user_lib::exit; +use user_lib::{ + semaphore_create, semaphore_down, semaphore_up, mutex_blocking_create, mutex_lock, mutex_unlock, +}; +use user_lib::{sleep, thread_create, waittid}; + +static mut A: usize = 0; + +const SEM_ID: usize = 0; +const MUTEX_ID: usize = 0; + +unsafe fn first() -> ! { + sleep(10); + println!("First work, Change A --> 1 and wakeup Second"); + mutex_lock(MUTEX_ID); + A = 1; + semaphore_up(SEM_ID); + mutex_unlock(MUTEX_ID); + exit(0) +} + +unsafe fn second() -> ! { + println!("Second want to continue,but need to wait A=1"); + loop { + mutex_lock(MUTEX_ID); + if A == 0 { + println!("Second: A is {}", A); + mutex_unlock(MUTEX_ID); + semaphore_down(SEM_ID); + } else { + mutex_unlock(MUTEX_ID); + break; + } + } + println!("A is {}, Second can work now", A); + exit(0) +} + +#[no_mangle] +pub fn main() -> i32 { + // create semaphore & mutex + assert_eq!(semaphore_create(0) as usize, SEM_ID); + assert_eq!(mutex_blocking_create() as usize, MUTEX_ID); + // create threads + let threads = vec![ + thread_create(first as usize, 0), + thread_create(second as usize, 0), + ]; + // wait for all threads to complete + for thread in threads.iter() { + waittid(*thread as usize); + } + println!("test_condvar passed!"); + 0 +} diff --git a/user/src/sync.rs b/user/src/sync.rs index fbed4e3..c41e4d6 100644 --- a/user/src/sync.rs +++ b/user/src/sync.rs @@ -22,7 +22,7 @@ pub fn semaphore_down(sem_id: usize) { sys_semaphore_down(sem_id); } pub fn condvar_create() -> isize { - sys_condvar_create(0) + sys_condvar_create() } pub fn condvar_signal(condvar_id: usize) { sys_condvar_signal(condvar_id); diff --git a/user/src/syscall.rs b/user/src/syscall.rs index 530ea20..87885f5 100644 --- a/user/src/syscall.rs +++ b/user/src/syscall.rs @@ -147,8 +147,8 @@ pub fn sys_semaphore_down(sem_id: usize) -> isize { syscall(SYSCALL_SEMAPHORE_DOWN, [sem_id, 0, 0]) } -pub fn sys_condvar_create(_arg: usize) -> isize { - syscall(SYSCALL_CONDVAR_CREATE, [_arg, 0, 0]) +pub fn sys_condvar_create() -> isize { + syscall(SYSCALL_CONDVAR_CREATE, [0, 0, 0]) } pub fn sys_condvar_signal(condvar_id: usize) -> isize { From 8cfd457341fa697f5292abfdf58f16c502d19532 Mon Sep 17 00:00:00 2001 From: Yifan Wu Date: Wed, 1 Feb 2023 21:00:34 +0800 Subject: [PATCH 09/14] update usertests --- user/src/bin/usertests.rs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/user/src/bin/usertests.rs b/user/src/bin/usertests.rs index 9ee0340..b522af2 100644 --- a/user/src/bin/usertests.rs +++ b/user/src/bin/usertests.rs @@ -36,7 +36,8 @@ static SUCC_TESTS: &[(&str, &str, &str, &str, i32)] = &[ ("sleep\0", "\0", "\0", "\0", 0), ("sleep_simple\0", "\0", "\0", "\0", 0), ("sync_sem\0", "\0", "\0", "\0", 0), - ("test_condvar\0", "\0", "\0", "\0", 0), + ("condsync_sem\0", "\0", "\0", "\0", 0), + ("condsync_condvar\0", "\0", "\0", "\0", 0), ("threads_arg\0", "\0", "\0", "\0", 0), ("threads\0", "\0", "\0", "\0", 0), ("yield\0", "\0", "\0", "\0", 0), From 191eb13c21ceb00a020678a020fcbcf1de7a7ae5 Mon Sep 17 00:00:00 2001 From: Yifan Wu Date: Wed, 1 Feb 2023 21:17:43 +0800 Subject: [PATCH 10/14] Remove unnecessary output. --- easy-fs-fuse/src/main.rs | 6 +++--- user/Makefile | 2 +- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/easy-fs-fuse/src/main.rs b/easy-fs-fuse/src/main.rs index 17b2465..bb9ff76 100644 --- a/easy-fs-fuse/src/main.rs +++ b/easy-fs-fuse/src/main.rs @@ -85,9 +85,9 @@ fn easy_fs_pack() -> std::io::Result<()> { inode.write_at(0, all_data.as_slice()); } // list apps - for app in root_inode.ls() { - println!("{}", app); - } + // for app in root_inode.ls() { + // println!("{}", app); + // } Ok(()) } diff --git a/user/Makefile b/user/Makefile index c09b5e9..5170327 100644 --- a/user/Makefile +++ b/user/Makefile @@ -19,7 +19,7 @@ ifeq ($(TEST), 1) endif binary: elf - $(foreach elf, $(ELFS), $(OBJCOPY) $(elf) --strip-all -O binary $(patsubst $(TARGET_DIR)/%, $(TARGET_DIR)/%.bin, $(elf));) + @$(foreach elf, $(ELFS), $(OBJCOPY) $(elf) --strip-all -O binary $(patsubst $(TARGET_DIR)/%, $(TARGET_DIR)/%.bin, $(elf));) build: binary From e80b7057a46a7c810003b7979b0cd89426a00d3e Mon Sep 17 00:00:00 2001 From: yufeng <321353225@qq.com> Date: Mon, 6 Feb 2023 19:12:45 +0800 Subject: [PATCH 11/14] add alloc_more --- os/src/mm/frame_allocator.rs | 36 ++++++++++++++++++++++++++++++++++++ 1 file changed, 36 insertions(+) diff --git a/os/src/mm/frame_allocator.rs b/os/src/mm/frame_allocator.rs index 1ecfe99..3635e18 100644 --- a/os/src/mm/frame_allocator.rs +++ b/os/src/mm/frame_allocator.rs @@ -35,6 +35,7 @@ impl Drop for FrameTracker { trait FrameAllocator { fn new() -> Self; fn alloc(&mut self) -> Option; + fn alloc_more(&mut self, pages: usize) -> Option>; fn dealloc(&mut self, ppn: PhysPageNum); } @@ -69,6 +70,16 @@ impl FrameAllocator for StackFrameAllocator { Some((self.current - 1).into()) } } + fn alloc_more(&mut self, pages: usize) -> Option> { + if self.current + pages >= self.end { + None + } else { + self.current += pages; + let arr:Vec = (1..pages + 1).collect(); + let v = arr.iter().map(|x| (self.current - x).into()).collect(); + Some(v) + } + } fn dealloc(&mut self, ppn: PhysPageNum) { let ppn = ppn.0; // validity check @@ -104,6 +115,13 @@ pub fn frame_alloc() -> Option { .map(FrameTracker::new) } +pub fn frame_alloc_more(num: usize) -> Option> { + FRAME_ALLOCATOR + .exclusive_access() + .alloc_more(num) + .map(|x| x.iter().map(|&t| FrameTracker::new(t)).collect()) +} + pub fn frame_dealloc(ppn: PhysPageNum) { FRAME_ALLOCATOR.exclusive_access().dealloc(ppn); } @@ -125,3 +143,21 @@ pub fn frame_allocator_test() { drop(v); println!("frame_allocator_test passed!"); } + + +#[allow(unused)] +pub fn frame_allocator_alloc_more_test() { + let mut v: Vec = 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!"); +} From 680f7fed2698cd8b0c3ca8793639a788eb664712 Mon Sep 17 00:00:00 2001 From: yufeng <321353225@qq.com> Date: Mon, 6 Feb 2023 19:15:46 +0800 Subject: [PATCH 12/14] use frame_alloc_more in VirtioHal --- os/src/drivers/bus/virtio.rs | 14 ++++---------- os/src/mm/mod.rs | 2 +- 2 files changed, 5 insertions(+), 11 deletions(-) diff --git a/os/src/drivers/bus/virtio.rs b/os/src/drivers/bus/virtio.rs index 6871eb8..d9a6121 100644 --- a/os/src/drivers/bus/virtio.rs +++ b/os/src/drivers/bus/virtio.rs @@ -1,6 +1,6 @@ use crate::mm::{ frame_alloc, frame_dealloc, kernel_token, FrameTracker, PageTable, PhysAddr, PhysPageNum, - StepByOne, VirtAddr, + StepByOne, VirtAddr, frame_alloc_more, }; use crate::sync::UPIntrFreeCell; use alloc::vec::Vec; @@ -16,15 +16,9 @@ pub struct VirtioHal; impl Hal for VirtioHal { fn dma_alloc(pages: usize) -> usize { - let mut ppn_base = PhysPageNum(0); - for i in 0..pages { - let frame = frame_alloc().unwrap(); - if i == 0 { - ppn_base = frame.ppn; - } - assert_eq!(frame.ppn.0, ppn_base.0 + i); - QUEUE_FRAMES.exclusive_access().push(frame); - } + let trakcers = frame_alloc_more(pages); + let ppn_base = trakcers.as_ref().unwrap().last().unwrap().ppn; + QUEUE_FRAMES.exclusive_access().append(&mut trakcers.unwrap()); let pa: PhysAddr = ppn_base.into(); pa.0 } diff --git a/os/src/mm/mod.rs b/os/src/mm/mod.rs index 34220c4..05e52ea 100644 --- a/os/src/mm/mod.rs +++ b/os/src/mm/mod.rs @@ -6,7 +6,7 @@ mod page_table; use address::VPNRange; 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::{kernel_token, MapPermission, MemorySet, KERNEL_SPACE}; use page_table::PTEFlags; From 9355acf9039021dfc98f6cd2f94b778322934cf1 Mon Sep 17 00:00:00 2001 From: yufeng <321353225@qq.com> Date: Mon, 6 Feb 2023 19:21:43 +0800 Subject: [PATCH 13/14] add net support --- os/Cargo.toml | 1 + os/Makefile | 4 ++ os/src/drivers/mod.rs | 2 + os/src/drivers/net/mod.rs | 41 +++++++++++++++++ os/src/main.rs | 1 + os/src/net/mod.rs | 92 ++++++++++++++++++++++++++++++++++++++ os/src/net/socket.rs | 93 ++++++++++++++++++++++++++++++++++++++ os/src/net/udp.rs | 94 +++++++++++++++++++++++++++++++++++++++ os/src/syscall/mod.rs | 4 ++ os/src/syscall/net.rs | 14 ++++++ user/src/lib.rs | 3 ++ user/src/syscall.rs | 5 +++ 12 files changed, 354 insertions(+) create mode 100644 os/src/drivers/net/mod.rs create mode 100644 os/src/net/mod.rs create mode 100644 os/src/net/socket.rs create mode 100644 os/src/net/udp.rs create mode 100644 os/src/syscall/net.rs diff --git a/os/Cargo.toml b/os/Cargo.toml index 3cae609..4f7f709 100644 --- a/os/Cargo.toml +++ b/os/Cargo.toml @@ -15,6 +15,7 @@ bitflags = "1.2.1" xmas-elf = "0.7.0" volatile = "0.3" 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" } virtio-input-decoder = "0.1.4" embedded-graphics = "0.7.1" diff --git a/os/Makefile b/os/Makefile index 6b7e9cf..ac0fd27 100644 --- a/os/Makefile +++ b/os/Makefile @@ -85,6 +85,8 @@ run-inner-none: build # -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 @@ -99,6 +101,8 @@ run-inner: build -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 fdt: diff --git a/os/src/drivers/mod.rs b/os/src/drivers/mod.rs index 57a15f0..e4f4172 100644 --- a/os/src/drivers/mod.rs +++ b/os/src/drivers/mod.rs @@ -3,6 +3,7 @@ pub mod bus; pub mod chardev; pub mod gpu; pub mod input; +pub mod net; pub mod plic; pub use block::BLOCK_DEVICE; @@ -10,3 +11,4 @@ pub use bus::*; pub use chardev::UART; pub use gpu::*; pub use input::*; +pub use net::*; \ No newline at end of file diff --git a/os/src/drivers/net/mod.rs b/os/src/drivers/net/mod.rs new file mode 100644 index 0000000..e1f76b0 --- /dev/null +++ b/os/src/drivers/net/mod.rs @@ -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 = 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>); + +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::::new(&mut *(VIRTIO8 as *mut VirtIOHeader)) + .expect("can't create net device by virtio"); + VirtIONetWrapper(UPIntrFreeCell::new(virtio)) + } + } +} \ No newline at end of file diff --git a/os/src/main.rs b/os/src/main.rs index b9b5f15..500e913 100644 --- a/os/src/main.rs +++ b/os/src/main.rs @@ -29,6 +29,7 @@ mod syscall; mod task; mod timer; mod trap; +mod net; use riscv::register::*; // mod riscvreg; diff --git a/os/src/net/mod.rs b/os/src/net/mod.rs new file mode 100644 index 0000000..57673d3 --- /dev/null +++ b/os/src/net/mod.rs @@ -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); + +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 = 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); +} \ No newline at end of file diff --git a/os/src/net/socket.rs b/os/src/net/socket.rs new file mode 100644 index 0000000..4e92a00 --- /dev/null +++ b/os/src/net/socket.rs @@ -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> // datas +} + +lazy_static! { + static ref SOCKET_TABLE:UPIntrFreeCell>> = unsafe { + UPIntrFreeCell::new(Vec::new()) + }; +} + +pub fn get_socket(raddr: IPv4, lport: u16, rport: u16) -> Option { + 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 { + 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) { + 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> { + 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() +} \ No newline at end of file diff --git a/os/src/net/udp.rs b/os/src/net/udp.rs new file mode 100644 index 0000000..afa26d0 --- /dev/null +++ b/os/src/net/udp.rs @@ -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) + } +} \ No newline at end of file diff --git a/os/src/syscall/mod.rs b/os/src/syscall/mod.rs index fa4a4cf..1766f3e 100644 --- a/os/src/syscall/mod.rs +++ b/os/src/syscall/mod.rs @@ -1,4 +1,5 @@ const SYSCALL_DUP: usize = 24; +const SYSCALL_CONNECT: usize = 29; const SYSCALL_OPEN: usize = 56; const SYSCALL_CLOSE: usize = 57; const SYSCALL_PIPE: usize = 59; @@ -30,15 +31,18 @@ mod fs; mod process; mod sync; mod thread; +mod net; use fs::*; use process::*; use sync::*; use thread::*; +use net::*; pub fn syscall(syscall_id: usize, args: [usize; 3]) -> isize { match syscall_id { 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_CLOSE => sys_close(args[0]), SYSCALL_PIPE => sys_pipe(args[0] as *mut usize), diff --git a/os/src/syscall/net.rs b/os/src/syscall/net.rs new file mode 100644 index 0000000..4ed4466 --- /dev/null +++ b/os/src/syscall/net.rs @@ -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 +} \ No newline at end of file diff --git a/user/src/lib.rs b/user/src/lib.rs index 729eaef..6f30d75 100644 --- a/user/src/lib.rs +++ b/user/src/lib.rs @@ -72,6 +72,9 @@ bitflags! { pub fn dup(fd: usize) -> isize { sys_dup(fd) } +pub fn connect(ip: u32, sport: u16, dport: u16) -> isize { + sys_connect(ip, sport, dport) +} pub fn open(path: &str, flags: OpenFlags) -> isize { sys_open(path, flags.bits) } diff --git a/user/src/syscall.rs b/user/src/syscall.rs index b4bb67a..1e5e405 100644 --- a/user/src/syscall.rs +++ b/user/src/syscall.rs @@ -1,4 +1,5 @@ const SYSCALL_DUP: usize = 24; +const SYSCALL_CONNECT: usize = 29; const SYSCALL_OPEN: usize = 56; const SYSCALL_CLOSE: usize = 57; const SYSCALL_PIPE: usize = 59; @@ -44,6 +45,10 @@ pub fn sys_dup(fd: usize) -> isize { 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 { syscall(SYSCALL_OPEN, [path.as_ptr() as usize, flags as usize, 0]) } From d31be8cba0165a6715c32fd1e58cde2e6ec1ec2c Mon Sep 17 00:00:00 2001 From: yufeng <321353225@qq.com> Date: Mon, 6 Feb 2023 19:22:44 +0800 Subject: [PATCH 14/14] Add a udp program and a ping test script --- ping.py | 18 ++++++++++++++++++ user/src/bin/udp.rs | 45 +++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 63 insertions(+) create mode 100644 ping.py create mode 100644 user/src/bin/udp.rs diff --git a/ping.py b/ping.py new file mode 100644 index 0000000..c68fc71 --- /dev/null +++ b/ping.py @@ -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) diff --git a/user/src/bin/udp.rs b/user/src/bin/udp.rs new file mode 100644 index 0000000..dda6005 --- /dev/null +++ b/user/src/bin/udp.rs @@ -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 +} \ No newline at end of file