cargo fmt && use rustsbi as the bootl
This commit is contained in:
parent
099b9b2ddd
commit
45ab29ae1b
43 changed files with 545 additions and 1489 deletions
|
@ -10,7 +10,6 @@ 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"
|
||||||
|
|
14
os/Makefile
14
os/Makefile
|
@ -24,7 +24,7 @@ ifeq ($(MODE), release)
|
||||||
endif
|
endif
|
||||||
|
|
||||||
# KERNEL ENTRY
|
# KERNEL ENTRY
|
||||||
KERNEL_ENTRY_PA := 0x80000000
|
KERNEL_ENTRY_PA := 0x80200000
|
||||||
|
|
||||||
# Binutils
|
# Binutils
|
||||||
OBJDUMP := rust-objdump --arch-name=riscv64
|
OBJDUMP := rust-objdump --arch-name=riscv64
|
||||||
|
@ -109,18 +109,6 @@ 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,9 +2,9 @@ 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), // core local interrupter (CLINT)
|
(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
|
||||||
];
|
];
|
||||||
|
|
||||||
pub type BlockDeviceImpl = crate::drivers::block::VirtIOBlock;
|
pub type BlockDeviceImpl = crate::drivers::block::VirtIOBlock;
|
||||||
|
@ -52,54 +52,3 @@ 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 {}
|
|
||||||
core::arch::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)
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
|
@ -1,10 +1,10 @@
|
||||||
use super::BlockDevice;
|
use super::BlockDevice;
|
||||||
|
use crate::drivers::bus::virtio::VirtioHal;
|
||||||
use crate::sync::{Condvar, UPIntrFreeCell};
|
use crate::sync::{Condvar, UPIntrFreeCell};
|
||||||
use crate::task::schedule;
|
use crate::task::schedule;
|
||||||
use crate::DEV_NON_BLOCKING_ACCESS;
|
use crate::DEV_NON_BLOCKING_ACCESS;
|
||||||
use alloc::collections::BTreeMap;
|
use alloc::collections::BTreeMap;
|
||||||
use virtio_drivers::{BlkResp, RespStatus, VirtIOBlk, VirtIOHeader};
|
use virtio_drivers::{BlkResp, RespStatus, VirtIOBlk, VirtIOHeader};
|
||||||
use crate::drivers::bus::virtio::VirtioHal;
|
|
||||||
|
|
||||||
#[allow(unused)]
|
#[allow(unused)]
|
||||||
const VIRTIO0: usize = 0x10008000;
|
const VIRTIO0: usize = 0x10008000;
|
||||||
|
|
|
@ -1,10 +1,10 @@
|
||||||
|
use crate::drivers::bus::virtio::VirtioHal;
|
||||||
use crate::sync::UPIntrFreeCell;
|
use crate::sync::UPIntrFreeCell;
|
||||||
use alloc::{sync::Arc, vec::Vec};
|
use alloc::{sync::Arc, vec::Vec};
|
||||||
use core::any::Any;
|
use core::any::Any;
|
||||||
use embedded_graphics::pixelcolor::Rgb888;
|
use embedded_graphics::pixelcolor::Rgb888;
|
||||||
use tinybmp::Bmp;
|
use tinybmp::Bmp;
|
||||||
use virtio_drivers::{VirtIOGpu, VirtIOHeader};
|
use virtio_drivers::{VirtIOGpu, VirtIOHeader};
|
||||||
use crate::drivers::bus::virtio::VirtioHal;
|
|
||||||
const VIRTIO7: usize = 0x10007000;
|
const VIRTIO7: usize = 0x10007000;
|
||||||
pub trait GpuDevice: Send + Sync + Any {
|
pub trait GpuDevice: Send + Sync + Any {
|
||||||
fn update_cursor(&self);
|
fn update_cursor(&self);
|
||||||
|
|
|
@ -2,7 +2,7 @@
|
||||||
.globl _start
|
.globl _start
|
||||||
_start:
|
_start:
|
||||||
la sp, boot_stack_top
|
la sp, boot_stack_top
|
||||||
call rust_start
|
call rust_main
|
||||||
|
|
||||||
.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 = 0x80000000;
|
BASE_ADDRESS = 0x80200000;
|
||||||
|
|
||||||
SECTIONS
|
SECTIONS
|
||||||
{
|
{
|
||||||
|
|
210
os/src/main.rs
210
os/src/main.rs
|
@ -2,8 +2,6 @@
|
||||||
#![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};
|
||||||
|
@ -14,7 +12,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;
|
||||||
|
@ -30,15 +28,8 @@ mod task;
|
||||||
mod timer;
|
mod timer;
|
||||||
mod trap;
|
mod trap;
|
||||||
|
|
||||||
use riscv::register::*;
|
use crate::drivers::chardev::CharDevice;
|
||||||
// mod riscvreg;
|
use crate::drivers::chardev::UART;
|
||||||
// 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"));
|
||||||
|
|
||||||
|
@ -61,198 +52,9 @@ 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");
|
||||||
|
@ -263,8 +65,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();
|
||||||
|
|
|
@ -75,7 +75,7 @@ impl FrameAllocator for StackFrameAllocator {
|
||||||
None
|
None
|
||||||
} else {
|
} else {
|
||||||
self.current += pages;
|
self.current += pages;
|
||||||
let arr:Vec<usize> = (1..pages + 1).collect();
|
let arr: Vec<usize> = (1..pages + 1).collect();
|
||||||
let v = arr.iter().map(|x| (self.current - x).into()).collect();
|
let v = arr.iter().map(|x| (self.current - x).into()).collect();
|
||||||
Some(v)
|
Some(v)
|
||||||
}
|
}
|
||||||
|
@ -144,7 +144,6 @@ pub fn frame_allocator_test() {
|
||||||
println!("frame_allocator_test passed!");
|
println!("frame_allocator_test passed!");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
#[allow(unused)]
|
#[allow(unused)]
|
||||||
pub fn frame_allocator_alloc_more_test() {
|
pub fn frame_allocator_alloc_more_test() {
|
||||||
let mut v: Vec<FrameTracker> = Vec::new();
|
let mut v: Vec<FrameTracker> = Vec::new();
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
|
pub mod port_table;
|
||||||
pub mod socket;
|
pub mod socket;
|
||||||
pub mod tcp;
|
pub mod tcp;
|
||||||
pub mod udp;
|
pub mod udp;
|
||||||
pub mod port_table;
|
|
||||||
|
|
||||||
pub use lose_net_stack::IPv4;
|
pub use lose_net_stack::IPv4;
|
||||||
|
|
||||||
|
@ -95,7 +95,7 @@ pub fn net_interrupt_handler() {
|
||||||
if let Some(socket_index) = get_socket(target, lport, rport) {
|
if let Some(socket_index) = get_socket(target, lport, rport) {
|
||||||
push_data(socket_index, tcp_packet.data.to_vec());
|
push_data(socket_index, tcp_packet.data.to_vec());
|
||||||
set_s_a_by_index(socket_index, tcp_packet.seq, tcp_packet.ack);
|
set_s_a_by_index(socket_index, tcp_packet.seq, tcp_packet.ack);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
_ => {}
|
_ => {}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
use alloc::{vec::Vec, sync::Arc};
|
use alloc::{sync::Arc, vec::Vec};
|
||||||
use lazy_static::lazy_static;
|
use lazy_static::lazy_static;
|
||||||
use lose_net_stack::packets::tcp::TCPPacket;
|
use lose_net_stack::packets::tcp::TCPPacket;
|
||||||
|
|
||||||
|
@ -11,7 +11,7 @@ use super::tcp::TCP;
|
||||||
pub struct Port {
|
pub struct Port {
|
||||||
pub port: u16,
|
pub port: u16,
|
||||||
pub receivable: bool,
|
pub receivable: bool,
|
||||||
pub schedule: Option<Arc<TaskControlBlock>>
|
pub schedule: Option<Arc<TaskControlBlock>>,
|
||||||
}
|
}
|
||||||
|
|
||||||
lazy_static! {
|
lazy_static! {
|
||||||
|
@ -32,7 +32,7 @@ pub fn listen(port: u16) -> Option<usize> {
|
||||||
let listen_port = Port {
|
let listen_port = Port {
|
||||||
port,
|
port,
|
||||||
receivable: false,
|
receivable: false,
|
||||||
schedule: None
|
schedule: None,
|
||||||
};
|
};
|
||||||
|
|
||||||
if index == usize::MAX {
|
if index == usize::MAX {
|
||||||
|
@ -66,10 +66,13 @@ pub fn port_acceptable(listen_index: usize) -> bool {
|
||||||
// check whether it can accept request
|
// check whether it can accept request
|
||||||
pub fn check_accept(port: u16, tcp_packet: &TCPPacket) -> Option<()> {
|
pub fn check_accept(port: u16, tcp_packet: &TCPPacket) -> Option<()> {
|
||||||
LISTEN_TABLE.exclusive_session(|listen_table| {
|
LISTEN_TABLE.exclusive_session(|listen_table| {
|
||||||
let mut listen_ports: Vec<&mut Option<Port>> = listen_table.iter_mut().filter(|x| match x {
|
let mut listen_ports: Vec<&mut Option<Port>> = listen_table
|
||||||
Some(t) => t.port == port && t.receivable == true,
|
.iter_mut()
|
||||||
None => false,
|
.filter(|x| match x {
|
||||||
}).collect();
|
Some(t) => t.port == port && t.receivable == true,
|
||||||
|
None => false,
|
||||||
|
})
|
||||||
|
.collect();
|
||||||
if listen_ports.len() == 0 {
|
if listen_ports.len() == 0 {
|
||||||
None
|
None
|
||||||
} else {
|
} else {
|
||||||
|
@ -90,7 +93,13 @@ pub fn accept_connection(_port: u16, tcp_packet: &TCPPacket, task: Arc<TaskContr
|
||||||
let mut inner = process.inner_exclusive_access();
|
let mut inner = process.inner_exclusive_access();
|
||||||
let fd = inner.alloc_fd();
|
let fd = inner.alloc_fd();
|
||||||
|
|
||||||
let tcp_socket = TCP::new(tcp_packet.source_ip, tcp_packet.dest_port, tcp_packet.source_port, tcp_packet.seq, tcp_packet.ack);
|
let tcp_socket = TCP::new(
|
||||||
|
tcp_packet.source_ip,
|
||||||
|
tcp_packet.dest_port,
|
||||||
|
tcp_packet.source_port,
|
||||||
|
tcp_packet.seq,
|
||||||
|
tcp_packet.ack,
|
||||||
|
);
|
||||||
|
|
||||||
inner.fd_table[fd] = Some(Arc::new(tcp_socket));
|
inner.fd_table[fd] = Some(Arc::new(tcp_socket));
|
||||||
|
|
||||||
|
@ -130,4 +139,3 @@ impl File for PortFd {
|
||||||
0
|
0
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -12,7 +12,7 @@ pub struct Socket {
|
||||||
pub rport: u16, // rempote port
|
pub rport: u16, // rempote port
|
||||||
pub buffers: VecDeque<Vec<u8>>, // datas
|
pub buffers: VecDeque<Vec<u8>>, // datas
|
||||||
pub seq: u32,
|
pub seq: u32,
|
||||||
pub ack: u32
|
pub ack: u32,
|
||||||
}
|
}
|
||||||
|
|
||||||
lazy_static! {
|
lazy_static! {
|
||||||
|
@ -26,11 +26,9 @@ pub fn get_s_a_by_index(index: usize) -> Option<(u32, u32)> {
|
||||||
|
|
||||||
assert!(index < socket_table.len());
|
assert!(index < socket_table.len());
|
||||||
|
|
||||||
socket_table.get(index).map_or(None, |x| {
|
socket_table.get(index).map_or(None, |x| match x {
|
||||||
match x {
|
Some(x) => Some((x.seq, x.ack)),
|
||||||
Some(x) => Some((x.seq, x.ack)),
|
None => None,
|
||||||
None => None,
|
|
||||||
}
|
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -40,9 +38,7 @@ pub fn set_s_a_by_index(index: usize, seq: u32, ack: u32) {
|
||||||
assert!(socket_table.len() > index);
|
assert!(socket_table.len() > index);
|
||||||
assert!(socket_table[index].is_some());
|
assert!(socket_table[index].is_some());
|
||||||
|
|
||||||
let sock = socket_table[index]
|
let sock = socket_table[index].as_mut().unwrap();
|
||||||
.as_mut()
|
|
||||||
.unwrap();
|
|
||||||
|
|
||||||
sock.ack = ack;
|
sock.ack = ack;
|
||||||
sock.seq = seq;
|
sock.seq = seq;
|
||||||
|
@ -84,7 +80,7 @@ pub fn add_socket(raddr: IPv4, lport: u16, rport: u16) -> Option<usize> {
|
||||||
rport,
|
rport,
|
||||||
buffers: VecDeque::new(),
|
buffers: VecDeque::new(),
|
||||||
seq: 0,
|
seq: 0,
|
||||||
ack: 0
|
ack: 0,
|
||||||
};
|
};
|
||||||
|
|
||||||
if index == usize::MAX {
|
if index == usize::MAX {
|
||||||
|
|
|
@ -1,8 +1,8 @@
|
||||||
use alloc::vec;
|
use alloc::vec;
|
||||||
use lose_net_stack::MacAddress;
|
|
||||||
use lose_net_stack::IPv4;
|
|
||||||
use lose_net_stack::TcpFlags;
|
|
||||||
use lose_net_stack::packets::tcp::TCPPacket;
|
use lose_net_stack::packets::tcp::TCPPacket;
|
||||||
|
use lose_net_stack::IPv4;
|
||||||
|
use lose_net_stack::MacAddress;
|
||||||
|
use lose_net_stack::TcpFlags;
|
||||||
|
|
||||||
use crate::{drivers::NET_DEVICE, fs::File};
|
use crate::{drivers::NET_DEVICE, fs::File};
|
||||||
|
|
||||||
|
|
|
@ -1,614 +0,0 @@
|
||||||
// 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
|
|
||||||
}
|
|
|
@ -1,86 +0,0 @@
|
||||||
//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,6 +1,6 @@
|
||||||
use crate::sync::{Mutex, UPIntrFreeCell};
|
use crate::sync::{Mutex, UPIntrFreeCell};
|
||||||
use crate::task::{
|
use crate::task::{
|
||||||
wakeup_task, block_current_and_run_next, block_current_task, current_task, TaskContext,
|
block_current_and_run_next, block_current_task, current_task, wakeup_task, TaskContext,
|
||||||
TaskControlBlock,
|
TaskControlBlock,
|
||||||
};
|
};
|
||||||
use alloc::{collections::VecDeque, sync::Arc};
|
use alloc::{collections::VecDeque, sync::Arc};
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
use super::UPIntrFreeCell;
|
use super::UPIntrFreeCell;
|
||||||
use crate::task::TaskControlBlock;
|
use crate::task::TaskControlBlock;
|
||||||
use crate::task::{wakeup_task, current_task};
|
|
||||||
use crate::task::{block_current_and_run_next, suspend_current_and_run_next};
|
use crate::task::{block_current_and_run_next, suspend_current_and_run_next};
|
||||||
|
use crate::task::{current_task, wakeup_task};
|
||||||
use alloc::{collections::VecDeque, sync::Arc};
|
use alloc::{collections::VecDeque, sync::Arc};
|
||||||
|
|
||||||
pub trait Mutex: Sync + Send {
|
pub trait Mutex: Sync + Send {
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
use crate::sync::UPIntrFreeCell;
|
use crate::sync::UPIntrFreeCell;
|
||||||
use crate::task::{wakeup_task, block_current_and_run_next, current_task, TaskControlBlock};
|
use crate::task::{block_current_and_run_next, current_task, wakeup_task, TaskControlBlock};
|
||||||
use alloc::{collections::VecDeque, sync::Arc};
|
use alloc::{collections::VecDeque, sync::Arc};
|
||||||
|
|
||||||
pub struct Semaphore {
|
pub struct Semaphore {
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
use crate::net::port_table::{listen, PortFd, accept, port_acceptable};
|
use crate::net::port_table::{accept, listen, port_acceptable, PortFd};
|
||||||
use crate::net::udp::UDP;
|
use crate::net::udp::UDP;
|
||||||
use crate::net::{IPv4, net_interrupt_handler};
|
use crate::net::{net_interrupt_handler, IPv4};
|
||||||
use crate::task::{current_process, current_task, current_trap_cx};
|
use crate::task::{current_process, current_task, current_trap_cx};
|
||||||
use alloc::sync::Arc;
|
use alloc::sync::Arc;
|
||||||
|
|
||||||
|
@ -34,11 +34,11 @@ pub fn sys_listen(port: u16) -> isize {
|
||||||
// accept a tcp connection
|
// accept a tcp connection
|
||||||
pub fn sys_accept(port_index: usize) -> isize {
|
pub fn sys_accept(port_index: usize) -> isize {
|
||||||
println!("accepting port {}", port_index);
|
println!("accepting port {}", port_index);
|
||||||
|
|
||||||
let task = current_task().unwrap();
|
let task = current_task().unwrap();
|
||||||
accept(port_index, task);
|
accept(port_index, task);
|
||||||
// block_current_and_run_next();
|
// block_current_and_run_next();
|
||||||
|
|
||||||
// NOTICE: There does not have interrupt handler, just call it munually.
|
// NOTICE: There does not have interrupt handler, just call it munually.
|
||||||
loop {
|
loop {
|
||||||
net_interrupt_handler();
|
net_interrupt_handler();
|
||||||
|
|
|
@ -19,7 +19,7 @@ use switch::__switch;
|
||||||
|
|
||||||
pub use context::TaskContext;
|
pub use context::TaskContext;
|
||||||
pub use id::{kstack_alloc, pid_alloc, KernelStack, PidHandle, IDLE_PID};
|
pub use id::{kstack_alloc, pid_alloc, KernelStack, PidHandle, IDLE_PID};
|
||||||
pub use manager::{add_task, wakeup_task, pid2process, remove_from_pid2process};
|
pub use manager::{add_task, pid2process, remove_from_pid2process, wakeup_task};
|
||||||
pub use processor::{
|
pub use processor::{
|
||||||
current_kstack_top, current_process, current_task, current_trap_cx, current_trap_cx_user_va,
|
current_kstack_top, current_process, current_task, current_trap_cx, current_trap_cx_user_va,
|
||||||
current_user_token, run_tasks, schedule, take_current_task,
|
current_user_token, run_tasks, schedule, take_current_task,
|
||||||
|
|
|
@ -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,sip
|
sie, sip, sscratch, sstatus, stval, stvec,
|
||||||
};
|
};
|
||||||
|
|
||||||
global_asm!(include_str!("trap.S"));
|
global_asm!(include_str!("trap.S"));
|
||||||
|
@ -95,20 +95,10 @@ 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();
|
||||||
// do not schedule now
|
suspend_current_and_run_next();
|
||||||
}
|
}
|
||||||
Trap::Interrupt(Interrupt::SupervisorExternal) => {
|
Trap::Interrupt(Interrupt::SupervisorExternal) => {
|
||||||
crate::board::irq_handler();
|
crate::board::irq_handler();
|
||||||
|
@ -161,18 +151,8 @@ 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
|
||||||
}
|
}
|
||||||
|
|
|
@ -40,7 +40,9 @@ pub fn main(argc: usize, argv: &[&str]) -> i32 {
|
||||||
per_thread = argv[2].parse().unwrap();
|
per_thread = argv[2].parse().unwrap();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
unsafe { PER_THREAD = per_thread; }
|
unsafe {
|
||||||
|
PER_THREAD = per_thread;
|
||||||
|
}
|
||||||
let start = get_time();
|
let start = get_time();
|
||||||
let mut v = Vec::new();
|
let mut v = Vec::new();
|
||||||
for _ in 0..thread_count {
|
for _ in 0..thread_count {
|
||||||
|
|
|
@ -26,8 +26,8 @@ unsafe fn critical_section(t: &mut usize) {
|
||||||
|
|
||||||
fn lock() {
|
fn lock() {
|
||||||
while OCCUPIED
|
while OCCUPIED
|
||||||
.compare_exchange(false, true, Ordering::Relaxed, Ordering::Relaxed)
|
.compare_exchange(false, true, Ordering::Relaxed, Ordering::Relaxed)
|
||||||
.is_err()
|
.is_err()
|
||||||
{
|
{
|
||||||
yield_();
|
yield_();
|
||||||
}
|
}
|
||||||
|
@ -57,7 +57,9 @@ pub fn main(argc: usize, argv: &[&str]) -> i32 {
|
||||||
per_thread = argv[2].parse().unwrap();
|
per_thread = argv[2].parse().unwrap();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
unsafe { PER_THREAD = per_thread; }
|
unsafe {
|
||||||
|
PER_THREAD = per_thread;
|
||||||
|
}
|
||||||
let start = get_time();
|
let start = get_time();
|
||||||
let mut v = Vec::new();
|
let mut v = Vec::new();
|
||||||
for _ in 0..thread_count {
|
for _ in 0..thread_count {
|
||||||
|
|
|
@ -42,7 +42,9 @@ pub fn main(argc: usize, argv: &[&str]) -> i32 {
|
||||||
per_thread = argv[2].parse().unwrap();
|
per_thread = argv[2].parse().unwrap();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
unsafe { PER_THREAD = per_thread; }
|
unsafe {
|
||||||
|
PER_THREAD = per_thread;
|
||||||
|
}
|
||||||
|
|
||||||
let start = get_time();
|
let start = get_time();
|
||||||
assert_eq!(mutex_blocking_create(), 0);
|
assert_eq!(mutex_blocking_create(), 0);
|
||||||
|
|
|
@ -43,7 +43,9 @@ pub fn main(argc: usize, argv: &[&str]) -> i32 {
|
||||||
per_thread = argv[2].parse().unwrap();
|
per_thread = argv[2].parse().unwrap();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
unsafe { PER_THREAD = per_thread; }
|
unsafe {
|
||||||
|
PER_THREAD = per_thread;
|
||||||
|
}
|
||||||
|
|
||||||
let start = get_time();
|
let start = get_time();
|
||||||
assert_eq!(mutex_create(), 0);
|
assert_eq!(mutex_create(), 0);
|
||||||
|
|
|
@ -1,90 +1,95 @@
|
||||||
//! It only works on a single CPU!
|
//! It only works on a single CPU!
|
||||||
|
|
||||||
#![no_std]
|
#![no_std]
|
||||||
#![no_main]
|
#![no_main]
|
||||||
#![feature(core_intrinsics)]
|
#![feature(core_intrinsics)]
|
||||||
|
|
||||||
#[macro_use]
|
#[macro_use]
|
||||||
extern crate user_lib;
|
extern crate user_lib;
|
||||||
extern crate alloc;
|
extern crate alloc;
|
||||||
|
|
||||||
use alloc::vec::Vec;
|
use alloc::vec::Vec;
|
||||||
use user_lib::{exit, get_time, thread_create, waittid};
|
use core::sync::atomic::{compiler_fence, Ordering};
|
||||||
use core::sync::atomic::{compiler_fence, Ordering};
|
use user_lib::{exit, get_time, thread_create, waittid};
|
||||||
|
|
||||||
static mut A: usize = 0;
|
static mut A: usize = 0;
|
||||||
static mut FLAG: [bool; 2] = [false; 2];
|
static mut FLAG: [bool; 2] = [false; 2];
|
||||||
static mut TURN: usize = 0;
|
static mut TURN: usize = 0;
|
||||||
const PER_THREAD_DEFAULT: usize = 2000;
|
const PER_THREAD_DEFAULT: usize = 2000;
|
||||||
const THREAD_COUNT_DEFAULT: usize = 2;
|
const THREAD_COUNT_DEFAULT: usize = 2;
|
||||||
static mut PER_THREAD: usize = 0;
|
static mut PER_THREAD: usize = 0;
|
||||||
|
|
||||||
unsafe fn critical_section(t: &mut usize) {
|
unsafe fn critical_section(t: &mut usize) {
|
||||||
let a = &mut A as *mut usize;
|
let a = &mut A as *mut usize;
|
||||||
let cur = a.read_volatile();
|
let cur = a.read_volatile();
|
||||||
for _ in 0..500 {
|
for _ in 0..500 {
|
||||||
*t = (*t) * (*t) % 10007;
|
*t = (*t) * (*t) % 10007;
|
||||||
}
|
}
|
||||||
a.write_volatile(cur + 1);
|
a.write_volatile(cur + 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
unsafe fn lock(id: usize) {
|
unsafe fn lock(id: usize) {
|
||||||
FLAG[id] = true;
|
FLAG[id] = true;
|
||||||
let j = 1 - id;
|
let j = 1 - id;
|
||||||
TURN = j;
|
TURN = j;
|
||||||
// Tell the compiler not to reorder memory operations
|
// Tell the compiler not to reorder memory operations
|
||||||
// across this fence.
|
// across this fence.
|
||||||
compiler_fence(Ordering::SeqCst);
|
compiler_fence(Ordering::SeqCst);
|
||||||
// Why do we need to use volatile_read here?
|
// Why do we need to use volatile_read here?
|
||||||
// Otherwise the compiler will assume that they will never
|
// Otherwise the compiler will assume that they will never
|
||||||
// be changed on this thread. Thus, they will be accessed
|
// be changed on this thread. Thus, they will be accessed
|
||||||
// only once!
|
// only once!
|
||||||
while vload!(&FLAG[j]) && vload!(&TURN) == j {}
|
while vload!(&FLAG[j]) && vload!(&TURN) == j {}
|
||||||
}
|
}
|
||||||
|
|
||||||
unsafe fn unlock(id: usize) {
|
unsafe fn unlock(id: usize) {
|
||||||
FLAG[id] = false;
|
FLAG[id] = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
unsafe fn f(id: usize) -> ! {
|
unsafe fn f(id: usize) -> ! {
|
||||||
let mut t = 2usize;
|
let mut t = 2usize;
|
||||||
for _iter in 0..PER_THREAD {
|
for _iter in 0..PER_THREAD {
|
||||||
lock(id);
|
lock(id);
|
||||||
critical_section(&mut t);
|
critical_section(&mut t);
|
||||||
unlock(id);
|
unlock(id);
|
||||||
}
|
}
|
||||||
exit(t as i32)
|
exit(t as i32)
|
||||||
}
|
}
|
||||||
|
|
||||||
#[no_mangle]
|
#[no_mangle]
|
||||||
pub fn main(argc: usize, argv: &[&str]) -> i32 {
|
pub fn main(argc: usize, argv: &[&str]) -> i32 {
|
||||||
let mut thread_count = THREAD_COUNT_DEFAULT;
|
let mut thread_count = THREAD_COUNT_DEFAULT;
|
||||||
let mut per_thread = PER_THREAD_DEFAULT;
|
let mut per_thread = PER_THREAD_DEFAULT;
|
||||||
if argc >= 2 {
|
if argc >= 2 {
|
||||||
thread_count = argv[1].parse().unwrap();
|
thread_count = argv[1].parse().unwrap();
|
||||||
if argc >= 3 {
|
if argc >= 3 {
|
||||||
per_thread = argv[2].parse().unwrap();
|
per_thread = argv[2].parse().unwrap();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
unsafe { PER_THREAD = per_thread; }
|
unsafe {
|
||||||
|
PER_THREAD = per_thread;
|
||||||
// uncomment this if you want to check the assembly
|
}
|
||||||
// println!(
|
|
||||||
// "addr: lock={:#x}, unlock={:#x}",
|
// uncomment this if you want to check the assembly
|
||||||
// lock as usize,
|
// println!(
|
||||||
// unlock as usize
|
// "addr: lock={:#x}, unlock={:#x}",
|
||||||
// );
|
// lock as usize,
|
||||||
let start = get_time();
|
// unlock as usize
|
||||||
let mut v = Vec::new();
|
// );
|
||||||
assert_eq!(thread_count, 2, "Peterson works when there are only 2 threads.");
|
let start = get_time();
|
||||||
for id in 0..thread_count {
|
let mut v = Vec::new();
|
||||||
v.push(thread_create(f as usize, id) as usize);
|
assert_eq!(
|
||||||
}
|
thread_count, 2,
|
||||||
let mut time_cost = Vec::new();
|
"Peterson works when there are only 2 threads."
|
||||||
for tid in v.iter() {
|
);
|
||||||
time_cost.push(waittid(*tid));
|
for id in 0..thread_count {
|
||||||
}
|
v.push(thread_create(f as usize, id) as usize);
|
||||||
println!("time cost is {}ms", get_time() - start);
|
}
|
||||||
assert_eq!(unsafe { A }, unsafe { PER_THREAD } * thread_count);
|
let mut time_cost = Vec::new();
|
||||||
0
|
for tid in v.iter() {
|
||||||
}
|
time_cost.push(waittid(*tid));
|
||||||
|
}
|
||||||
|
println!("time cost is {}ms", get_time() - start);
|
||||||
|
assert_eq!(unsafe { A }, unsafe { PER_THREAD } * thread_count);
|
||||||
|
0
|
||||||
|
}
|
||||||
|
|
|
@ -1,89 +1,94 @@
|
||||||
//! It only works on a single CPU!
|
//! It only works on a single CPU!
|
||||||
|
|
||||||
#![no_std]
|
#![no_std]
|
||||||
#![no_main]
|
#![no_main]
|
||||||
#![feature(core_intrinsics)]
|
#![feature(core_intrinsics)]
|
||||||
|
|
||||||
#[macro_use]
|
#[macro_use]
|
||||||
extern crate user_lib;
|
extern crate user_lib;
|
||||||
extern crate alloc;
|
extern crate alloc;
|
||||||
|
|
||||||
use alloc::vec::Vec;
|
use alloc::vec::Vec;
|
||||||
use user_lib::{exit, get_time, thread_create, waittid, yield_};
|
use core::sync::atomic::{compiler_fence, Ordering};
|
||||||
use core::sync::atomic::{compiler_fence, Ordering};
|
use user_lib::{exit, get_time, thread_create, waittid, yield_};
|
||||||
|
|
||||||
static mut A: usize = 0;
|
static mut A: usize = 0;
|
||||||
static mut FLAG: [bool; 2] = [false; 2];
|
static mut FLAG: [bool; 2] = [false; 2];
|
||||||
static mut TURN: usize = 0;
|
static mut TURN: usize = 0;
|
||||||
const PER_THREAD_DEFAULT: usize = 2000;
|
const PER_THREAD_DEFAULT: usize = 2000;
|
||||||
const THREAD_COUNT_DEFAULT: usize = 2;
|
const THREAD_COUNT_DEFAULT: usize = 2;
|
||||||
static mut PER_THREAD: usize = 0;
|
static mut PER_THREAD: usize = 0;
|
||||||
|
|
||||||
unsafe fn critical_section(t: &mut usize) {
|
unsafe fn critical_section(t: &mut usize) {
|
||||||
let a = &mut A as *mut usize;
|
let a = &mut A as *mut usize;
|
||||||
let cur = a.read_volatile();
|
let cur = a.read_volatile();
|
||||||
for _ in 0..500 {
|
for _ in 0..500 {
|
||||||
*t = (*t) * (*t) % 10007;
|
*t = (*t) * (*t) % 10007;
|
||||||
}
|
}
|
||||||
a.write_volatile(cur + 1);
|
a.write_volatile(cur + 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
unsafe fn lock(id: usize) {
|
unsafe fn lock(id: usize) {
|
||||||
FLAG[id] = true;
|
FLAG[id] = true;
|
||||||
let j = 1 - id;
|
let j = 1 - id;
|
||||||
TURN = j;
|
TURN = j;
|
||||||
// Tell the compiler not to reorder memory operations
|
// Tell the compiler not to reorder memory operations
|
||||||
// across this fence.
|
// across this fence.
|
||||||
compiler_fence(Ordering::SeqCst);
|
compiler_fence(Ordering::SeqCst);
|
||||||
while FLAG[j] && TURN == j {
|
while FLAG[j] && TURN == j {
|
||||||
yield_();
|
yield_();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
unsafe fn unlock(id: usize) {
|
unsafe fn unlock(id: usize) {
|
||||||
FLAG[id] = false;
|
FLAG[id] = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
unsafe fn f(id: usize) -> ! {
|
unsafe fn f(id: usize) -> ! {
|
||||||
let mut t = 2usize;
|
let mut t = 2usize;
|
||||||
for _iter in 0..PER_THREAD {
|
for _iter in 0..PER_THREAD {
|
||||||
lock(id);
|
lock(id);
|
||||||
critical_section(&mut t);
|
critical_section(&mut t);
|
||||||
unlock(id);
|
unlock(id);
|
||||||
}
|
}
|
||||||
exit(t as i32)
|
exit(t as i32)
|
||||||
}
|
}
|
||||||
|
|
||||||
#[no_mangle]
|
#[no_mangle]
|
||||||
pub fn main(argc: usize, argv: &[&str]) -> i32 {
|
pub fn main(argc: usize, argv: &[&str]) -> i32 {
|
||||||
let mut thread_count = THREAD_COUNT_DEFAULT;
|
let mut thread_count = THREAD_COUNT_DEFAULT;
|
||||||
let mut per_thread = PER_THREAD_DEFAULT;
|
let mut per_thread = PER_THREAD_DEFAULT;
|
||||||
if argc >= 2 {
|
if argc >= 2 {
|
||||||
thread_count = argv[1].parse().unwrap();
|
thread_count = argv[1].parse().unwrap();
|
||||||
if argc >= 3 {
|
if argc >= 3 {
|
||||||
per_thread = argv[2].parse().unwrap();
|
per_thread = argv[2].parse().unwrap();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
unsafe { PER_THREAD = per_thread; }
|
unsafe {
|
||||||
|
PER_THREAD = per_thread;
|
||||||
// uncomment this if you want to check the assembly
|
}
|
||||||
// println!(
|
|
||||||
// "addr: lock={:#x}, unlock={:#x}",
|
// uncomment this if you want to check the assembly
|
||||||
// lock as usize,
|
// println!(
|
||||||
// unlock as usize
|
// "addr: lock={:#x}, unlock={:#x}",
|
||||||
// );
|
// lock as usize,
|
||||||
|
// unlock as usize
|
||||||
let start = get_time();
|
// );
|
||||||
let mut v = Vec::new();
|
|
||||||
assert_eq!(thread_count, 2, "Peterson works when there are only 2 threads.");
|
let start = get_time();
|
||||||
for id in 0..thread_count {
|
let mut v = Vec::new();
|
||||||
v.push(thread_create(f as usize, id) as usize);
|
assert_eq!(
|
||||||
}
|
thread_count, 2,
|
||||||
let mut time_cost = Vec::new();
|
"Peterson works when there are only 2 threads."
|
||||||
for tid in v.iter() {
|
);
|
||||||
time_cost.push(waittid(*tid));
|
for id in 0..thread_count {
|
||||||
}
|
v.push(thread_create(f as usize, id) as usize);
|
||||||
println!("time cost is {}ms", get_time() - start);
|
}
|
||||||
assert_eq!(unsafe { A }, unsafe { PER_THREAD } * thread_count);
|
let mut time_cost = Vec::new();
|
||||||
0
|
for tid in v.iter() {
|
||||||
}
|
time_cost.push(waittid(*tid));
|
||||||
|
}
|
||||||
|
println!("time cost is {}ms", get_time() - start);
|
||||||
|
assert_eq!(unsafe { A }, unsafe { PER_THREAD } * thread_count);
|
||||||
|
0
|
||||||
|
}
|
||||||
|
|
|
@ -53,7 +53,9 @@ pub fn main(argc: usize, argv: &[&str]) -> i32 {
|
||||||
per_thread = argv[2].parse().unwrap();
|
per_thread = argv[2].parse().unwrap();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
unsafe { PER_THREAD = per_thread; }
|
unsafe {
|
||||||
|
PER_THREAD = per_thread;
|
||||||
|
}
|
||||||
let start = get_time();
|
let start = get_time();
|
||||||
let mut v = Vec::new();
|
let mut v = Vec::new();
|
||||||
for _ in 0..thread_count {
|
for _ in 0..thread_count {
|
||||||
|
|
|
@ -1,70 +1,72 @@
|
||||||
#![no_std]
|
#![no_std]
|
||||||
#![no_main]
|
#![no_main]
|
||||||
#![feature(core_intrinsics)]
|
#![feature(core_intrinsics)]
|
||||||
|
|
||||||
#[macro_use]
|
#[macro_use]
|
||||||
extern crate user_lib;
|
extern crate user_lib;
|
||||||
extern crate alloc;
|
extern crate alloc;
|
||||||
|
|
||||||
use alloc::vec::Vec;
|
use alloc::vec::Vec;
|
||||||
use user_lib::{exit, get_time, thread_create, waittid, yield_};
|
use user_lib::{exit, get_time, thread_create, waittid, yield_};
|
||||||
|
|
||||||
static mut A: usize = 0;
|
static mut A: usize = 0;
|
||||||
static mut OCCUPIED: bool = false;
|
static mut OCCUPIED: bool = false;
|
||||||
const PER_THREAD_DEFAULT: usize = 10000;
|
const PER_THREAD_DEFAULT: usize = 10000;
|
||||||
const THREAD_COUNT_DEFAULT: usize = 16;
|
const THREAD_COUNT_DEFAULT: usize = 16;
|
||||||
static mut PER_THREAD: usize = 0;
|
static mut PER_THREAD: usize = 0;
|
||||||
|
|
||||||
unsafe fn critical_section(t: &mut usize) {
|
unsafe fn critical_section(t: &mut usize) {
|
||||||
let a = &mut A as *mut usize;
|
let a = &mut A as *mut usize;
|
||||||
let cur = a.read_volatile();
|
let cur = a.read_volatile();
|
||||||
for _ in 0..500 {
|
for _ in 0..500 {
|
||||||
*t = (*t) * (*t) % 10007;
|
*t = (*t) * (*t) % 10007;
|
||||||
}
|
}
|
||||||
a.write_volatile(cur + 1);
|
a.write_volatile(cur + 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
unsafe fn lock() {
|
unsafe fn lock() {
|
||||||
while OCCUPIED {
|
while OCCUPIED {
|
||||||
yield_();
|
yield_();
|
||||||
}
|
}
|
||||||
OCCUPIED = true;
|
OCCUPIED = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
unsafe fn unlock() {
|
unsafe fn unlock() {
|
||||||
OCCUPIED = false;
|
OCCUPIED = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
unsafe fn f() -> ! {
|
unsafe fn f() -> ! {
|
||||||
let mut t = 2usize;
|
let mut t = 2usize;
|
||||||
for _ in 0..PER_THREAD {
|
for _ in 0..PER_THREAD {
|
||||||
lock();
|
lock();
|
||||||
critical_section(&mut t);
|
critical_section(&mut t);
|
||||||
unlock();
|
unlock();
|
||||||
}
|
}
|
||||||
exit(t as i32)
|
exit(t as i32)
|
||||||
}
|
}
|
||||||
|
|
||||||
#[no_mangle]
|
#[no_mangle]
|
||||||
pub fn main(argc: usize, argv: &[&str]) -> i32 {
|
pub fn main(argc: usize, argv: &[&str]) -> i32 {
|
||||||
let mut thread_count = THREAD_COUNT_DEFAULT;
|
let mut thread_count = THREAD_COUNT_DEFAULT;
|
||||||
let mut per_thread = PER_THREAD_DEFAULT;
|
let mut per_thread = PER_THREAD_DEFAULT;
|
||||||
if argc >= 2 {
|
if argc >= 2 {
|
||||||
thread_count = argv[1].parse().unwrap();
|
thread_count = argv[1].parse().unwrap();
|
||||||
if argc >= 3 {
|
if argc >= 3 {
|
||||||
per_thread = argv[2].parse().unwrap();
|
per_thread = argv[2].parse().unwrap();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
unsafe { PER_THREAD = per_thread; }
|
unsafe {
|
||||||
let start = get_time();
|
PER_THREAD = per_thread;
|
||||||
let mut v = Vec::new();
|
}
|
||||||
for _ in 0..thread_count {
|
let start = get_time();
|
||||||
v.push(thread_create(f as usize, 0) as usize);
|
let mut v = Vec::new();
|
||||||
}
|
for _ in 0..thread_count {
|
||||||
for tid in v.into_iter() {
|
v.push(thread_create(f as usize, 0) as usize);
|
||||||
waittid(tid);
|
}
|
||||||
}
|
for tid in v.into_iter() {
|
||||||
println!("time cost is {}ms", get_time() - start);
|
waittid(tid);
|
||||||
assert_eq!(unsafe { A }, unsafe { PER_THREAD } * thread_count);
|
}
|
||||||
0
|
println!("time cost is {}ms", get_time() - start);
|
||||||
}
|
assert_eq!(unsafe { A }, unsafe { PER_THREAD } * thread_count);
|
||||||
|
0
|
||||||
|
}
|
||||||
|
|
|
@ -1,72 +1,83 @@
|
||||||
#![no_std]
|
#![no_std]
|
||||||
#![no_main]
|
#![no_main]
|
||||||
|
|
||||||
#[macro_use]
|
#[macro_use]
|
||||||
extern crate user_lib;
|
extern crate user_lib;
|
||||||
extern crate alloc;
|
extern crate alloc;
|
||||||
|
|
||||||
use user_lib::{thread_create, exit, waittid, mutex_create, mutex_lock, mutex_unlock, condvar_create, condvar_signal, condvar_wait};
|
use alloc::vec::Vec;
|
||||||
use alloc::vec::Vec;
|
use core::cell::UnsafeCell;
|
||||||
use core::cell::UnsafeCell;
|
use lazy_static::*;
|
||||||
use lazy_static::*;
|
use user_lib::{
|
||||||
|
condvar_create, condvar_signal, condvar_wait, exit, mutex_create, mutex_lock, mutex_unlock,
|
||||||
const THREAD_NUM: usize = 3;
|
thread_create, waittid,
|
||||||
|
};
|
||||||
struct Barrier {
|
|
||||||
mutex_id: usize,
|
const THREAD_NUM: usize = 3;
|
||||||
condvar_id: usize,
|
|
||||||
count: UnsafeCell<usize>,
|
struct Barrier {
|
||||||
}
|
mutex_id: usize,
|
||||||
|
condvar_id: usize,
|
||||||
impl Barrier {
|
count: UnsafeCell<usize>,
|
||||||
pub fn new() -> Self {
|
}
|
||||||
Self {
|
|
||||||
mutex_id: mutex_create() as usize,
|
impl Barrier {
|
||||||
condvar_id: condvar_create() as usize,
|
pub fn new() -> Self {
|
||||||
count: UnsafeCell::new(0),
|
Self {
|
||||||
}
|
mutex_id: mutex_create() as usize,
|
||||||
}
|
condvar_id: condvar_create() as usize,
|
||||||
pub fn block(&self) {
|
count: UnsafeCell::new(0),
|
||||||
mutex_lock(self.mutex_id);
|
}
|
||||||
let count = self.count.get();
|
}
|
||||||
// SAFETY: Here, the accesses of the count is in the
|
pub fn block(&self) {
|
||||||
// critical section protected by the mutex.
|
mutex_lock(self.mutex_id);
|
||||||
unsafe { *count = *count + 1; }
|
let count = self.count.get();
|
||||||
if unsafe { *count } == THREAD_NUM {
|
// SAFETY: Here, the accesses of the count is in the
|
||||||
condvar_signal(self.condvar_id);
|
// critical section protected by the mutex.
|
||||||
} else {
|
unsafe {
|
||||||
condvar_wait(self.condvar_id, self.mutex_id);
|
*count = *count + 1;
|
||||||
condvar_signal(self.condvar_id);
|
}
|
||||||
}
|
if unsafe { *count } == THREAD_NUM {
|
||||||
mutex_unlock(self.mutex_id);
|
condvar_signal(self.condvar_id);
|
||||||
}
|
} else {
|
||||||
}
|
condvar_wait(self.condvar_id, self.mutex_id);
|
||||||
|
condvar_signal(self.condvar_id);
|
||||||
unsafe impl Sync for Barrier {}
|
}
|
||||||
|
mutex_unlock(self.mutex_id);
|
||||||
lazy_static! {
|
}
|
||||||
static ref BARRIER_AB: Barrier = Barrier::new();
|
}
|
||||||
static ref BARRIER_BC: Barrier = Barrier::new();
|
|
||||||
}
|
unsafe impl Sync for Barrier {}
|
||||||
|
|
||||||
fn thread_fn() {
|
lazy_static! {
|
||||||
for _ in 0..300 { print!("a"); }
|
static ref BARRIER_AB: Barrier = Barrier::new();
|
||||||
BARRIER_AB.block();
|
static ref BARRIER_BC: Barrier = Barrier::new();
|
||||||
for _ in 0..300 { print!("b"); }
|
}
|
||||||
BARRIER_BC.block();
|
|
||||||
for _ in 0..300 { print!("c"); }
|
fn thread_fn() {
|
||||||
exit(0)
|
for _ in 0..300 {
|
||||||
}
|
print!("a");
|
||||||
|
}
|
||||||
#[no_mangle]
|
BARRIER_AB.block();
|
||||||
pub fn main() -> i32 {
|
for _ in 0..300 {
|
||||||
let mut v: Vec<isize> = Vec::new();
|
print!("b");
|
||||||
for _ in 0..THREAD_NUM {
|
}
|
||||||
v.push(thread_create(thread_fn as usize, 0));
|
BARRIER_BC.block();
|
||||||
}
|
for _ in 0..300 {
|
||||||
for tid in v.into_iter() {
|
print!("c");
|
||||||
waittid(tid as usize);
|
}
|
||||||
}
|
exit(0)
|
||||||
println!("\nOK!");
|
}
|
||||||
0
|
|
||||||
}
|
#[no_mangle]
|
||||||
|
pub fn main() -> i32 {
|
||||||
|
let mut v: Vec<isize> = Vec::new();
|
||||||
|
for _ in 0..THREAD_NUM {
|
||||||
|
v.push(thread_create(thread_fn as usize, 0));
|
||||||
|
}
|
||||||
|
for tid in v.into_iter() {
|
||||||
|
waittid(tid as usize);
|
||||||
|
}
|
||||||
|
println!("\nOK!");
|
||||||
|
0
|
||||||
|
}
|
||||||
|
|
|
@ -1,33 +1,33 @@
|
||||||
#![no_std]
|
#![no_std]
|
||||||
#![no_main]
|
#![no_main]
|
||||||
|
|
||||||
#[macro_use]
|
#[macro_use]
|
||||||
extern crate user_lib;
|
extern crate user_lib;
|
||||||
extern crate alloc;
|
extern crate alloc;
|
||||||
|
|
||||||
use user_lib::{thread_create, exit, waittid};
|
use alloc::vec::Vec;
|
||||||
use alloc::vec::Vec;
|
use user_lib::{exit, thread_create, waittid};
|
||||||
|
|
||||||
const THREAD_NUM: usize = 3;
|
const THREAD_NUM: usize = 3;
|
||||||
|
|
||||||
fn thread_fn() {
|
fn thread_fn() {
|
||||||
for ch in 'a'..='c' {
|
for ch in 'a'..='c' {
|
||||||
for _ in 0..300 {
|
for _ in 0..300 {
|
||||||
print!("{}", ch);
|
print!("{}", ch);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
exit(0)
|
exit(0)
|
||||||
}
|
}
|
||||||
|
|
||||||
#[no_mangle]
|
#[no_mangle]
|
||||||
pub fn main() -> i32 {
|
pub fn main() -> i32 {
|
||||||
let mut v: Vec<isize> = Vec::new();
|
let mut v: Vec<isize> = Vec::new();
|
||||||
for _ in 0..THREAD_NUM {
|
for _ in 0..THREAD_NUM {
|
||||||
v.push(thread_create(thread_fn as usize, 0));
|
v.push(thread_create(thread_fn as usize, 0));
|
||||||
}
|
}
|
||||||
for tid in v.into_iter() {
|
for tid in v.into_iter() {
|
||||||
waittid(tid as usize);
|
waittid(tid as usize);
|
||||||
}
|
}
|
||||||
println!("\nOK!");
|
println!("\nOK!");
|
||||||
0
|
0
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,64 +1,64 @@
|
||||||
#![no_std]
|
#![no_std]
|
||||||
#![no_main]
|
#![no_main]
|
||||||
|
|
||||||
#[macro_use]
|
#[macro_use]
|
||||||
extern crate user_lib;
|
extern crate user_lib;
|
||||||
|
|
||||||
extern crate alloc;
|
extern crate alloc;
|
||||||
|
|
||||||
use alloc::vec;
|
use alloc::vec;
|
||||||
use user_lib::exit;
|
use user_lib::exit;
|
||||||
use user_lib::{
|
use user_lib::{
|
||||||
semaphore_create, semaphore_down, semaphore_up, mutex_blocking_create, mutex_lock, mutex_unlock,
|
mutex_blocking_create, mutex_lock, mutex_unlock, semaphore_create, semaphore_down, semaphore_up,
|
||||||
};
|
};
|
||||||
use user_lib::{sleep, thread_create, waittid};
|
use user_lib::{sleep, thread_create, waittid};
|
||||||
|
|
||||||
static mut A: usize = 0;
|
static mut A: usize = 0;
|
||||||
|
|
||||||
const SEM_ID: usize = 0;
|
const SEM_ID: usize = 0;
|
||||||
const MUTEX_ID: usize = 0;
|
const MUTEX_ID: usize = 0;
|
||||||
|
|
||||||
unsafe fn first() -> ! {
|
unsafe fn first() -> ! {
|
||||||
sleep(10);
|
sleep(10);
|
||||||
println!("First work, Change A --> 1 and wakeup Second");
|
println!("First work, Change A --> 1 and wakeup Second");
|
||||||
mutex_lock(MUTEX_ID);
|
mutex_lock(MUTEX_ID);
|
||||||
A = 1;
|
A = 1;
|
||||||
semaphore_up(SEM_ID);
|
semaphore_up(SEM_ID);
|
||||||
mutex_unlock(MUTEX_ID);
|
mutex_unlock(MUTEX_ID);
|
||||||
exit(0)
|
exit(0)
|
||||||
}
|
}
|
||||||
|
|
||||||
unsafe fn second() -> ! {
|
unsafe fn second() -> ! {
|
||||||
println!("Second want to continue,but need to wait A=1");
|
println!("Second want to continue,but need to wait A=1");
|
||||||
loop {
|
loop {
|
||||||
mutex_lock(MUTEX_ID);
|
mutex_lock(MUTEX_ID);
|
||||||
if A == 0 {
|
if A == 0 {
|
||||||
println!("Second: A is {}", A);
|
println!("Second: A is {}", A);
|
||||||
mutex_unlock(MUTEX_ID);
|
mutex_unlock(MUTEX_ID);
|
||||||
semaphore_down(SEM_ID);
|
semaphore_down(SEM_ID);
|
||||||
} else {
|
} else {
|
||||||
mutex_unlock(MUTEX_ID);
|
mutex_unlock(MUTEX_ID);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
println!("A is {}, Second can work now", A);
|
println!("A is {}, Second can work now", A);
|
||||||
exit(0)
|
exit(0)
|
||||||
}
|
}
|
||||||
|
|
||||||
#[no_mangle]
|
#[no_mangle]
|
||||||
pub fn main() -> i32 {
|
pub fn main() -> i32 {
|
||||||
// create semaphore & mutex
|
// create semaphore & mutex
|
||||||
assert_eq!(semaphore_create(0) as usize, SEM_ID);
|
assert_eq!(semaphore_create(0) as usize, SEM_ID);
|
||||||
assert_eq!(mutex_blocking_create() as usize, MUTEX_ID);
|
assert_eq!(mutex_blocking_create() as usize, MUTEX_ID);
|
||||||
// create threads
|
// create threads
|
||||||
let threads = vec![
|
let threads = vec![
|
||||||
thread_create(first as usize, 0),
|
thread_create(first as usize, 0),
|
||||||
thread_create(second as usize, 0),
|
thread_create(second as usize, 0),
|
||||||
];
|
];
|
||||||
// wait for all threads to complete
|
// wait for all threads to complete
|
||||||
for thread in threads.iter() {
|
for thread in threads.iter() {
|
||||||
waittid(*thread as usize);
|
waittid(*thread as usize);
|
||||||
}
|
}
|
||||||
println!("test_condvar passed!");
|
println!("test_condvar passed!");
|
||||||
0
|
0
|
||||||
}
|
}
|
||||||
|
|
|
@ -8,7 +8,7 @@ use user_lib::{Display, VIRTGPU_XRES, VIRTGPU_YRES};
|
||||||
|
|
||||||
use embedded_graphics::pixelcolor::Rgb888;
|
use embedded_graphics::pixelcolor::Rgb888;
|
||||||
use embedded_graphics::prelude::{DrawTarget, Drawable, Point, RgbColor, Size};
|
use embedded_graphics::prelude::{DrawTarget, Drawable, Point, RgbColor, Size};
|
||||||
use embedded_graphics::primitives::{Circle, Primitive, PrimitiveStyle, Rectangle,Triangle};
|
use embedded_graphics::primitives::{Circle, Primitive, PrimitiveStyle, Rectangle, Triangle};
|
||||||
|
|
||||||
const INIT_X: i32 = 80;
|
const INIT_X: i32 = 80;
|
||||||
const INIT_Y: i32 = 400;
|
const INIT_Y: i32 = 400;
|
||||||
|
@ -35,10 +35,14 @@ impl DrawingBoard {
|
||||||
.into_styled(PrimitiveStyle::with_fill(Rgb888::BLUE))
|
.into_styled(PrimitiveStyle::with_fill(Rgb888::BLUE))
|
||||||
.draw(&mut self.disp)
|
.draw(&mut self.disp)
|
||||||
.ok();
|
.ok();
|
||||||
Triangle::new(self.latest_pos + Point::new(0, 150), self.latest_pos + Point::new(80, 200), self.latest_pos + Point::new(-120, 300))
|
Triangle::new(
|
||||||
.into_styled(PrimitiveStyle::with_stroke(Rgb888::GREEN, 10))
|
self.latest_pos + Point::new(0, 150),
|
||||||
.draw(&mut self.disp)
|
self.latest_pos + Point::new(80, 200),
|
||||||
.ok();
|
self.latest_pos + Point::new(-120, 300),
|
||||||
|
)
|
||||||
|
.into_styled(PrimitiveStyle::with_stroke(Rgb888::GREEN, 10))
|
||||||
|
.draw(&mut self.disp)
|
||||||
|
.ok();
|
||||||
}
|
}
|
||||||
fn unpaint(&mut self) {
|
fn unpaint(&mut self) {
|
||||||
Rectangle::with_center(self.latest_pos, Size::new(RECT_SIZE, RECT_SIZE))
|
Rectangle::with_center(self.latest_pos, Size::new(RECT_SIZE, RECT_SIZE))
|
||||||
|
|
|
@ -3,8 +3,8 @@
|
||||||
|
|
||||||
extern crate user_lib;
|
extern crate user_lib;
|
||||||
|
|
||||||
use user_lib::{VIRTGPU_XRES, VIRTGPU_YRES, Display};
|
|
||||||
use embedded_graphics::prelude::Size;
|
use embedded_graphics::prelude::Size;
|
||||||
|
use user_lib::{Display, VIRTGPU_XRES, VIRTGPU_YRES};
|
||||||
|
|
||||||
#[no_mangle]
|
#[no_mangle]
|
||||||
pub fn main() -> i32 {
|
pub fn main() -> i32 {
|
||||||
|
|
|
@ -1,11 +1,11 @@
|
||||||
#![no_std]
|
#![no_std]
|
||||||
#![no_main]
|
#![no_main]
|
||||||
|
|
||||||
extern crate user_lib;
|
|
||||||
extern crate alloc;
|
extern crate alloc;
|
||||||
|
extern crate user_lib;
|
||||||
|
|
||||||
use user_lib::console::getchar;
|
use user_lib::console::getchar;
|
||||||
use user_lib::{Display, key_pressed, sleep, VIRTGPU_XRES, VIRTGPU_YRES};
|
use user_lib::{key_pressed, sleep, Display, VIRTGPU_XRES, VIRTGPU_YRES};
|
||||||
|
|
||||||
use embedded_graphics::pixelcolor::*;
|
use embedded_graphics::pixelcolor::*;
|
||||||
use embedded_graphics::prelude::{Drawable, Point, RgbColor, Size};
|
use embedded_graphics::prelude::{Drawable, Point, RgbColor, Size};
|
||||||
|
|
|
@ -113,7 +113,7 @@ pub fn main() -> i32 {
|
||||||
let mut board = DrawingBoard::new();
|
let mut board = DrawingBoard::new();
|
||||||
let _ = board.disp.clear(Rgb888::BLACK).unwrap();
|
let _ = board.disp.clear(Rgb888::BLACK).unwrap();
|
||||||
for i in 0..20 {
|
for i in 0..20 {
|
||||||
let c=getchar();
|
let c = getchar();
|
||||||
if c == LF || c == CR {
|
if c == LF || c == CR {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
|
@ -22,4 +22,4 @@ pub fn main() -> i32 {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
0
|
0
|
||||||
}
|
}
|
||||||
|
|
|
@ -77,4 +77,4 @@ pub fn main() -> i32 {
|
||||||
}
|
}
|
||||||
println!("main thread exited.");
|
println!("main thread exited.");
|
||||||
0
|
0
|
||||||
}
|
}
|
||||||
|
|
|
@ -13,4 +13,4 @@ pub fn main() -> i32 {
|
||||||
println!("OORandom: Random number 32bit: {}", rng.rand_i32());
|
println!("OORandom: Random number 32bit: {}", rng.rand_i32());
|
||||||
println!("OORandom: Random number range: {}", rng.rand_range(1..100));
|
println!("OORandom: Random number range: {}", rng.rand_range(1..100));
|
||||||
0
|
0
|
||||||
}
|
}
|
||||||
|
|
|
@ -69,7 +69,7 @@ impl Task {
|
||||||
// we can allocate memory for it later, but it keeps complexity down and lets us focus on more interesting parts
|
// we can allocate memory for it later, but it keeps complexity down and lets us focus on more interesting parts
|
||||||
// to do it here. The important part is that once allocated it MUST NOT move in memory.
|
// to do it here. The important part is that once allocated it MUST NOT move in memory.
|
||||||
Task {
|
Task {
|
||||||
id:id,
|
id: id,
|
||||||
stack: vec![0_u8; DEFAULT_STACK_SIZE],
|
stack: vec![0_u8; DEFAULT_STACK_SIZE],
|
||||||
ctx: TaskContext::default(),
|
ctx: TaskContext::default(),
|
||||||
state: State::Available,
|
state: State::Available,
|
||||||
|
|
|
@ -10,7 +10,7 @@ extern crate alloc;
|
||||||
|
|
||||||
// use http://localhost:6201/ to access the http server
|
// use http://localhost:6201/ to access the http server
|
||||||
|
|
||||||
use user_lib::{read, write, listen, accept};
|
use user_lib::{accept, listen, read, write};
|
||||||
|
|
||||||
// get url from the tcp request list.
|
// get url from the tcp request list.
|
||||||
fn get_url_from_tcp_request(req: &[u8]) -> String {
|
fn get_url_from_tcp_request(req: &[u8]) -> String {
|
||||||
|
@ -35,8 +35,8 @@ fn handle_tcp_client(client_fd: usize) -> bool {
|
||||||
println!("receive {} bytes", len);
|
println!("receive {} bytes", len);
|
||||||
hexdump(&buf[..len as usize]);
|
hexdump(&buf[..len as usize]);
|
||||||
|
|
||||||
// verify whether it is a valid HTTP request simply, [0x47,0x45,0x54, 0x20] is GET
|
// verify whether it is a valid HTTP request simply, [0x47,0x45,0x54, 0x20] is GET
|
||||||
if len < 4 || buf[..4] != [0x47,0x45,0x54, 0x20] {
|
if len < 4 || buf[..4] != [0x47, 0x45, 0x54, 0x20] {
|
||||||
println!("it's not a valid http request");
|
println!("it's not a valid http request");
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
@ -136,12 +136,12 @@ pub fn main() -> i32 {
|
||||||
loop {
|
loop {
|
||||||
let client = accept(tcp_fd as usize);
|
let client = accept(tcp_fd as usize);
|
||||||
println!("client connected: {}", client);
|
println!("client connected: {}", client);
|
||||||
|
|
||||||
if client < 1 {
|
if client < 1 {
|
||||||
println!("Failed to accept a client on port 80");
|
println!("Failed to accept a client on port 80");
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
if handle_tcp_client(client as usize) {
|
if handle_tcp_client(client as usize) {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
use super::*;
|
use super::*;
|
||||||
|
use embedded_graphics::pixelcolor::Rgb888;
|
||||||
use embedded_graphics::prelude::{RgbColor, Size};
|
use embedded_graphics::prelude::{RgbColor, Size};
|
||||||
use embedded_graphics::{draw_target::DrawTarget, prelude::OriginDimensions};
|
use embedded_graphics::{draw_target::DrawTarget, prelude::OriginDimensions};
|
||||||
use embedded_graphics::pixelcolor::Rgb888;
|
|
||||||
use virtio_input_decoder::Decoder;
|
use virtio_input_decoder::Decoder;
|
||||||
pub use virtio_input_decoder::{DecodeType, Key, KeyType, Mouse};
|
pub use virtio_input_decoder::{DecodeType, Key, KeyType, Mouse};
|
||||||
|
|
||||||
|
@ -24,9 +24,8 @@ pub struct Display {
|
||||||
impl Display {
|
impl Display {
|
||||||
pub fn new(size: Size) -> Self {
|
pub fn new(size: Size) -> Self {
|
||||||
let fb_ptr = framebuffer() as *mut u8;
|
let fb_ptr = framebuffer() as *mut u8;
|
||||||
let fb =
|
let fb = unsafe { core::slice::from_raw_parts_mut(fb_ptr, VIRTGPU_LEN as usize) };
|
||||||
unsafe { core::slice::from_raw_parts_mut(fb_ptr, VIRTGPU_LEN as usize) };
|
Self { size, fb }
|
||||||
Self { size, fb}
|
|
||||||
}
|
}
|
||||||
pub fn framebuffer(&mut self) -> &mut [u8] {
|
pub fn framebuffer(&mut self) -> &mut [u8] {
|
||||||
self.fb
|
self.fb
|
||||||
|
@ -53,9 +52,7 @@ impl DrawTarget for Display {
|
||||||
I: IntoIterator<Item = embedded_graphics::Pixel<Self::Color>>,
|
I: IntoIterator<Item = embedded_graphics::Pixel<Self::Color>>,
|
||||||
{
|
{
|
||||||
pixels.into_iter().for_each(|px| {
|
pixels.into_iter().for_each(|px| {
|
||||||
let idx = (px.0.y * VIRTGPU_XRES as i32 + px.0.x)
|
let idx = (px.0.y * VIRTGPU_XRES as i32 + px.0.x) as usize * 4;
|
||||||
as usize
|
|
||||||
* 4;
|
|
||||||
if idx + 2 >= self.fb.len() {
|
if idx + 2 >= self.fb.len() {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
@ -113,6 +110,7 @@ impl InputEvent {
|
||||||
self.event_type as usize,
|
self.event_type as usize,
|
||||||
self.code as usize,
|
self.code as usize,
|
||||||
self.value as usize,
|
self.value as usize,
|
||||||
).ok()
|
)
|
||||||
|
.ok()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -80,4 +80,4 @@ pub fn waittid(tid: usize) -> isize {
|
||||||
exit_code => return exit_code,
|
exit_code => return exit_code,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue