mirror of
https://github.com/rcore-os/rCore-Tutorial-v3.git
synced 2024-11-22 01:16:26 +04:00
cargo fmt && use rustsbi as the bootl
This commit is contained in:
parent
4284b9d119
commit
ce32c3b1f3
@ -10,7 +10,6 @@ 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"
|
||||
|
14
os/Makefile
14
os/Makefile
@ -24,7 +24,7 @@ ifeq ($(MODE), release)
|
||||
endif
|
||||
|
||||
# KERNEL ENTRY
|
||||
KERNEL_ENTRY_PA := 0x80000000
|
||||
KERNEL_ENTRY_PA := 0x80200000
|
||||
|
||||
# Binutils
|
||||
OBJDUMP := rust-objdump --arch-name=riscv64
|
||||
@ -109,18 +109,6 @@ 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" && \
|
||||
|
@ -2,9 +2,9 @@ pub const CLOCK_FREQ: usize = 12500000;
|
||||
|
||||
pub const MMIO: &[(usize, usize)] = &[
|
||||
(0x0010_0000, 0x00_2000), // VIRT_TEST/RTC in virt machine
|
||||
(0x2000000, 0x10000), // core local interrupter (CLINT)
|
||||
(0xc000000, 0x210000), // VIRT_PLIC in virt machine
|
||||
(0x10000000, 0x9000), // VIRT_UART0 with GPU in virt machine
|
||||
(0x2000000, 0x10000), // core local interrupter (CLINT)
|
||||
(0xc000000, 0x210000), // VIRT_PLIC in virt machine
|
||||
(0x10000000, 0x9000), // VIRT_UART0 with GPU in virt machine
|
||||
];
|
||||
|
||||
pub type BlockDeviceImpl = crate::drivers::block::VirtIOBlock;
|
||||
@ -52,54 +52,3 @@ 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.
|
||||
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 crate::drivers::bus::virtio::VirtioHal;
|
||||
use crate::sync::{Condvar, UPIntrFreeCell};
|
||||
use crate::task::schedule;
|
||||
use crate::DEV_NON_BLOCKING_ACCESS;
|
||||
use alloc::collections::BTreeMap;
|
||||
use virtio_drivers::{BlkResp, RespStatus, VirtIOBlk, VirtIOHeader};
|
||||
use crate::drivers::bus::virtio::VirtioHal;
|
||||
|
||||
#[allow(unused)]
|
||||
const VIRTIO0: usize = 0x10008000;
|
||||
|
@ -1,10 +1,10 @@
|
||||
use crate::drivers::bus::virtio::VirtioHal;
|
||||
use crate::sync::UPIntrFreeCell;
|
||||
use alloc::{sync::Arc, vec::Vec};
|
||||
use core::any::Any;
|
||||
use embedded_graphics::pixelcolor::Rgb888;
|
||||
use tinybmp::Bmp;
|
||||
use virtio_drivers::{VirtIOGpu, VirtIOHeader};
|
||||
use crate::drivers::bus::virtio::VirtioHal;
|
||||
const VIRTIO7: usize = 0x10007000;
|
||||
pub trait GpuDevice: Send + Sync + Any {
|
||||
fn update_cursor(&self);
|
||||
|
@ -2,7 +2,7 @@
|
||||
.globl _start
|
||||
_start:
|
||||
la sp, boot_stack_top
|
||||
call rust_start
|
||||
call rust_main
|
||||
|
||||
.section .bss.stack
|
||||
.globl boot_stack_lower_bound
|
||||
|
@ -1,6 +1,6 @@
|
||||
OUTPUT_ARCH(riscv)
|
||||
ENTRY(_start)
|
||||
BASE_ADDRESS = 0x80000000;
|
||||
BASE_ADDRESS = 0x80200000;
|
||||
|
||||
SECTIONS
|
||||
{
|
||||
|
210
os/src/main.rs
210
os/src/main.rs
@ -2,8 +2,6 @@
|
||||
#![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, INPUT_CONDVAR};
|
||||
use crate::drivers::{GPU_DEVICE, KEYBOARD_DEVICE, MOUSE_DEVICE};
|
||||
@ -14,7 +12,7 @@ extern crate bitflags;
|
||||
|
||||
#[path = "boards/qemu.rs"]
|
||||
mod board;
|
||||
use board::*;
|
||||
|
||||
#[macro_use]
|
||||
mod console;
|
||||
mod config;
|
||||
@ -30,15 +28,8 @@ mod task;
|
||||
mod timer;
|
||||
mod trap;
|
||||
|
||||
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
|
||||
use crate::drivers::chardev::CharDevice;
|
||||
use crate::drivers::chardev::UART;
|
||||
|
||||
core::arch::global_asm!(include_str!("entry.asm"));
|
||||
|
||||
@ -61,198 +52,9 @@ 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]);
|
||||
|
||||
#[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]
|
||||
pub fn rust_main() -> ! {
|
||||
|
||||
//clear_bss();
|
||||
clear_bss();
|
||||
mm::init();
|
||||
UART.init();
|
||||
println!("KERN: init gpu");
|
||||
@ -263,8 +65,8 @@ 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();
|
||||
task::add_initproc();
|
||||
|
@ -75,7 +75,7 @@ impl FrameAllocator for StackFrameAllocator {
|
||||
None
|
||||
} else {
|
||||
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();
|
||||
Some(v)
|
||||
}
|
||||
@ -144,7 +144,6 @@ pub fn frame_allocator_test() {
|
||||
println!("frame_allocator_test passed!");
|
||||
}
|
||||
|
||||
|
||||
#[allow(unused)]
|
||||
pub fn frame_allocator_alloc_more_test() {
|
||||
let mut v: Vec<FrameTracker> = Vec::new();
|
||||
|
@ -1,7 +1,7 @@
|
||||
pub mod port_table;
|
||||
pub mod socket;
|
||||
pub mod tcp;
|
||||
pub mod udp;
|
||||
pub mod port_table;
|
||||
|
||||
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) {
|
||||
push_data(socket_index, tcp_packet.data.to_vec());
|
||||
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 lose_net_stack::packets::tcp::TCPPacket;
|
||||
|
||||
@ -11,7 +11,7 @@ use super::tcp::TCP;
|
||||
pub struct Port {
|
||||
pub port: u16,
|
||||
pub receivable: bool,
|
||||
pub schedule: Option<Arc<TaskControlBlock>>
|
||||
pub schedule: Option<Arc<TaskControlBlock>>,
|
||||
}
|
||||
|
||||
lazy_static! {
|
||||
@ -32,7 +32,7 @@ pub fn listen(port: u16) -> Option<usize> {
|
||||
let listen_port = Port {
|
||||
port,
|
||||
receivable: false,
|
||||
schedule: None
|
||||
schedule: None,
|
||||
};
|
||||
|
||||
if index == usize::MAX {
|
||||
@ -66,10 +66,13 @@ pub fn port_acceptable(listen_index: usize) -> bool {
|
||||
// check whether it can accept request
|
||||
pub fn check_accept(port: u16, tcp_packet: &TCPPacket) -> Option<()> {
|
||||
LISTEN_TABLE.exclusive_session(|listen_table| {
|
||||
let mut listen_ports: Vec<&mut Option<Port>> = listen_table.iter_mut().filter(|x| match x {
|
||||
Some(t) => t.port == port && t.receivable == true,
|
||||
None => false,
|
||||
}).collect();
|
||||
let mut listen_ports: Vec<&mut Option<Port>> = listen_table
|
||||
.iter_mut()
|
||||
.filter(|x| match x {
|
||||
Some(t) => t.port == port && t.receivable == true,
|
||||
None => false,
|
||||
})
|
||||
.collect();
|
||||
if listen_ports.len() == 0 {
|
||||
None
|
||||
} 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 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));
|
||||
|
||||
@ -130,4 +139,3 @@ impl File for PortFd {
|
||||
0
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -12,7 +12,7 @@ pub struct Socket {
|
||||
pub rport: u16, // rempote port
|
||||
pub buffers: VecDeque<Vec<u8>>, // datas
|
||||
pub seq: u32,
|
||||
pub ack: u32
|
||||
pub ack: u32,
|
||||
}
|
||||
|
||||
lazy_static! {
|
||||
@ -26,11 +26,9 @@ pub fn get_s_a_by_index(index: usize) -> Option<(u32, u32)> {
|
||||
|
||||
assert!(index < socket_table.len());
|
||||
|
||||
socket_table.get(index).map_or(None, |x| {
|
||||
match x {
|
||||
Some(x) => Some((x.seq, x.ack)),
|
||||
None => None,
|
||||
}
|
||||
socket_table.get(index).map_or(None, |x| match x {
|
||||
Some(x) => Some((x.seq, x.ack)),
|
||||
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[index].is_some());
|
||||
|
||||
let sock = socket_table[index]
|
||||
.as_mut()
|
||||
.unwrap();
|
||||
let sock = socket_table[index].as_mut().unwrap();
|
||||
|
||||
sock.ack = ack;
|
||||
sock.seq = seq;
|
||||
@ -84,7 +80,7 @@ pub fn add_socket(raddr: IPv4, lport: u16, rport: u16) -> Option<usize> {
|
||||
rport,
|
||||
buffers: VecDeque::new(),
|
||||
seq: 0,
|
||||
ack: 0
|
||||
ack: 0,
|
||||
};
|
||||
|
||||
if index == usize::MAX {
|
||||
|
@ -1,8 +1,8 @@
|
||||
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::IPv4;
|
||||
use lose_net_stack::MacAddress;
|
||||
use lose_net_stack::TcpFlags;
|
||||
|
||||
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::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,
|
||||
};
|
||||
use alloc::{collections::VecDeque, sync::Arc};
|
||||
|
@ -1,7 +1,7 @@
|
||||
use super::UPIntrFreeCell;
|
||||
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::{current_task, wakeup_task};
|
||||
use alloc::{collections::VecDeque, sync::Arc};
|
||||
|
||||
pub trait Mutex: Sync + Send {
|
||||
|
@ -1,5 +1,5 @@
|
||||
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};
|
||||
|
||||
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::{IPv4, net_interrupt_handler};
|
||||
use crate::net::{net_interrupt_handler, IPv4};
|
||||
use crate::task::{current_process, current_task, current_trap_cx};
|
||||
use alloc::sync::Arc;
|
||||
|
||||
@ -34,11 +34,11 @@ pub fn sys_listen(port: u16) -> isize {
|
||||
// accept a tcp connection
|
||||
pub fn sys_accept(port_index: usize) -> isize {
|
||||
println!("accepting port {}", port_index);
|
||||
|
||||
|
||||
let task = current_task().unwrap();
|
||||
accept(port_index, task);
|
||||
// block_current_and_run_next();
|
||||
|
||||
|
||||
// NOTICE: There does not have interrupt handler, just call it munually.
|
||||
loop {
|
||||
net_interrupt_handler();
|
||||
|
@ -19,7 +19,7 @@ use switch::__switch;
|
||||
|
||||
pub use context::TaskContext;
|
||||
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::{
|
||||
current_kstack_top, current_process, current_task, current_trap_cx, current_trap_cx_user_va,
|
||||
current_user_token, run_tasks, schedule, take_current_task,
|
||||
|
@ -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,sip
|
||||
sie, sip, sscratch, sstatus, stval, stvec,
|
||||
};
|
||||
|
||||
global_asm!(include_str!("trap.S"));
|
||||
@ -95,20 +95,10 @@ 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::SupervisorSoft) => {
|
||||
//set_next_trigger();
|
||||
const SSIP: usize = 1 << 1;
|
||||
unsafe {
|
||||
asm!("csrc sip, {}", in(reg) SSIP);
|
||||
}
|
||||
//println!("TRAP: ssoft in Kern");
|
||||
Trap::Interrupt(Interrupt::SupervisorTimer) => {
|
||||
set_next_trigger();
|
||||
check_timer();
|
||||
// do not schedule now
|
||||
suspend_current_and_run_next();
|
||||
}
|
||||
Trap::Interrupt(Interrupt::SupervisorExternal) => {
|
||||
crate::board::irq_handler();
|
||||
@ -161,18 +151,8 @@ 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::SupervisorSoft) => {
|
||||
//set_next_trigger();
|
||||
const SSIP: usize = 1 << 1;
|
||||
unsafe {
|
||||
asm!("csrc sip, {}", in(reg) SSIP);
|
||||
}
|
||||
//println!("TRAP: ssoft in Kern");
|
||||
Trap::Interrupt(Interrupt::SupervisorTimer) => {
|
||||
set_next_trigger();
|
||||
check_timer();
|
||||
// do not schedule now
|
||||
}
|
||||
|
@ -40,7 +40,9 @@ pub fn main(argc: usize, argv: &[&str]) -> i32 {
|
||||
per_thread = argv[2].parse().unwrap();
|
||||
}
|
||||
}
|
||||
unsafe { PER_THREAD = per_thread; }
|
||||
unsafe {
|
||||
PER_THREAD = per_thread;
|
||||
}
|
||||
let start = get_time();
|
||||
let mut v = Vec::new();
|
||||
for _ in 0..thread_count {
|
||||
|
@ -26,8 +26,8 @@ unsafe fn critical_section(t: &mut usize) {
|
||||
|
||||
fn lock() {
|
||||
while OCCUPIED
|
||||
.compare_exchange(false, true, Ordering::Relaxed, Ordering::Relaxed)
|
||||
.is_err()
|
||||
.compare_exchange(false, true, Ordering::Relaxed, Ordering::Relaxed)
|
||||
.is_err()
|
||||
{
|
||||
yield_();
|
||||
}
|
||||
@ -57,7 +57,9 @@ pub fn main(argc: usize, argv: &[&str]) -> i32 {
|
||||
per_thread = argv[2].parse().unwrap();
|
||||
}
|
||||
}
|
||||
unsafe { PER_THREAD = per_thread; }
|
||||
unsafe {
|
||||
PER_THREAD = per_thread;
|
||||
}
|
||||
let start = get_time();
|
||||
let mut v = Vec::new();
|
||||
for _ in 0..thread_count {
|
||||
|
@ -42,7 +42,9 @@ pub fn main(argc: usize, argv: &[&str]) -> i32 {
|
||||
per_thread = argv[2].parse().unwrap();
|
||||
}
|
||||
}
|
||||
unsafe { PER_THREAD = per_thread; }
|
||||
unsafe {
|
||||
PER_THREAD = per_thread;
|
||||
}
|
||||
|
||||
let start = get_time();
|
||||
assert_eq!(mutex_blocking_create(), 0);
|
||||
|
@ -43,7 +43,9 @@ pub fn main(argc: usize, argv: &[&str]) -> i32 {
|
||||
per_thread = argv[2].parse().unwrap();
|
||||
}
|
||||
}
|
||||
unsafe { PER_THREAD = per_thread; }
|
||||
unsafe {
|
||||
PER_THREAD = per_thread;
|
||||
}
|
||||
|
||||
let start = get_time();
|
||||
assert_eq!(mutex_create(), 0);
|
||||
|
@ -1,90 +1,95 @@
|
||||
//! It only works on a single CPU!
|
||||
|
||||
#![no_std]
|
||||
#![no_main]
|
||||
#![feature(core_intrinsics)]
|
||||
|
||||
#[macro_use]
|
||||
extern crate user_lib;
|
||||
extern crate alloc;
|
||||
|
||||
use alloc::vec::Vec;
|
||||
use user_lib::{exit, get_time, thread_create, waittid};
|
||||
use core::sync::atomic::{compiler_fence, Ordering};
|
||||
|
||||
static mut A: usize = 0;
|
||||
static mut FLAG: [bool; 2] = [false; 2];
|
||||
static mut TURN: usize = 0;
|
||||
const PER_THREAD_DEFAULT: usize = 2000;
|
||||
const THREAD_COUNT_DEFAULT: usize = 2;
|
||||
static mut PER_THREAD: usize = 0;
|
||||
|
||||
unsafe fn critical_section(t: &mut usize) {
|
||||
let a = &mut A as *mut usize;
|
||||
let cur = a.read_volatile();
|
||||
for _ in 0..500 {
|
||||
*t = (*t) * (*t) % 10007;
|
||||
}
|
||||
a.write_volatile(cur + 1);
|
||||
}
|
||||
|
||||
unsafe fn lock(id: usize) {
|
||||
FLAG[id] = true;
|
||||
let j = 1 - id;
|
||||
TURN = j;
|
||||
// Tell the compiler not to reorder memory operations
|
||||
// across this fence.
|
||||
compiler_fence(Ordering::SeqCst);
|
||||
// Why do we need to use volatile_read here?
|
||||
// Otherwise the compiler will assume that they will never
|
||||
// be changed on this thread. Thus, they will be accessed
|
||||
// only once!
|
||||
while vload!(&FLAG[j]) && vload!(&TURN) == j {}
|
||||
}
|
||||
|
||||
unsafe fn unlock(id: usize) {
|
||||
FLAG[id] = false;
|
||||
}
|
||||
|
||||
unsafe fn f(id: usize) -> ! {
|
||||
let mut t = 2usize;
|
||||
for _iter in 0..PER_THREAD {
|
||||
lock(id);
|
||||
critical_section(&mut t);
|
||||
unlock(id);
|
||||
}
|
||||
exit(t as i32)
|
||||
}
|
||||
|
||||
#[no_mangle]
|
||||
pub fn main(argc: usize, argv: &[&str]) -> i32 {
|
||||
let mut thread_count = THREAD_COUNT_DEFAULT;
|
||||
let mut per_thread = PER_THREAD_DEFAULT;
|
||||
if argc >= 2 {
|
||||
thread_count = argv[1].parse().unwrap();
|
||||
if argc >= 3 {
|
||||
per_thread = argv[2].parse().unwrap();
|
||||
}
|
||||
}
|
||||
unsafe { PER_THREAD = per_thread; }
|
||||
|
||||
// uncomment this if you want to check the assembly
|
||||
// println!(
|
||||
// "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.");
|
||||
for id in 0..thread_count {
|
||||
v.push(thread_create(f as usize, id) as usize);
|
||||
}
|
||||
let mut time_cost = Vec::new();
|
||||
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
|
||||
}
|
||||
//! It only works on a single CPU!
|
||||
|
||||
#![no_std]
|
||||
#![no_main]
|
||||
#![feature(core_intrinsics)]
|
||||
|
||||
#[macro_use]
|
||||
extern crate user_lib;
|
||||
extern crate alloc;
|
||||
|
||||
use alloc::vec::Vec;
|
||||
use core::sync::atomic::{compiler_fence, Ordering};
|
||||
use user_lib::{exit, get_time, thread_create, waittid};
|
||||
|
||||
static mut A: usize = 0;
|
||||
static mut FLAG: [bool; 2] = [false; 2];
|
||||
static mut TURN: usize = 0;
|
||||
const PER_THREAD_DEFAULT: usize = 2000;
|
||||
const THREAD_COUNT_DEFAULT: usize = 2;
|
||||
static mut PER_THREAD: usize = 0;
|
||||
|
||||
unsafe fn critical_section(t: &mut usize) {
|
||||
let a = &mut A as *mut usize;
|
||||
let cur = a.read_volatile();
|
||||
for _ in 0..500 {
|
||||
*t = (*t) * (*t) % 10007;
|
||||
}
|
||||
a.write_volatile(cur + 1);
|
||||
}
|
||||
|
||||
unsafe fn lock(id: usize) {
|
||||
FLAG[id] = true;
|
||||
let j = 1 - id;
|
||||
TURN = j;
|
||||
// Tell the compiler not to reorder memory operations
|
||||
// across this fence.
|
||||
compiler_fence(Ordering::SeqCst);
|
||||
// Why do we need to use volatile_read here?
|
||||
// Otherwise the compiler will assume that they will never
|
||||
// be changed on this thread. Thus, they will be accessed
|
||||
// only once!
|
||||
while vload!(&FLAG[j]) && vload!(&TURN) == j {}
|
||||
}
|
||||
|
||||
unsafe fn unlock(id: usize) {
|
||||
FLAG[id] = false;
|
||||
}
|
||||
|
||||
unsafe fn f(id: usize) -> ! {
|
||||
let mut t = 2usize;
|
||||
for _iter in 0..PER_THREAD {
|
||||
lock(id);
|
||||
critical_section(&mut t);
|
||||
unlock(id);
|
||||
}
|
||||
exit(t as i32)
|
||||
}
|
||||
|
||||
#[no_mangle]
|
||||
pub fn main(argc: usize, argv: &[&str]) -> i32 {
|
||||
let mut thread_count = THREAD_COUNT_DEFAULT;
|
||||
let mut per_thread = PER_THREAD_DEFAULT;
|
||||
if argc >= 2 {
|
||||
thread_count = argv[1].parse().unwrap();
|
||||
if argc >= 3 {
|
||||
per_thread = argv[2].parse().unwrap();
|
||||
}
|
||||
}
|
||||
unsafe {
|
||||
PER_THREAD = per_thread;
|
||||
}
|
||||
|
||||
// uncomment this if you want to check the assembly
|
||||
// println!(
|
||||
// "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."
|
||||
);
|
||||
for id in 0..thread_count {
|
||||
v.push(thread_create(f as usize, id) as usize);
|
||||
}
|
||||
let mut time_cost = Vec::new();
|
||||
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!
|
||||
|
||||
#![no_std]
|
||||
#![no_main]
|
||||
#![feature(core_intrinsics)]
|
||||
|
||||
#[macro_use]
|
||||
extern crate user_lib;
|
||||
extern crate alloc;
|
||||
|
||||
use alloc::vec::Vec;
|
||||
use user_lib::{exit, get_time, thread_create, waittid, yield_};
|
||||
use core::sync::atomic::{compiler_fence, Ordering};
|
||||
|
||||
static mut A: usize = 0;
|
||||
static mut FLAG: [bool; 2] = [false; 2];
|
||||
static mut TURN: usize = 0;
|
||||
const PER_THREAD_DEFAULT: usize = 2000;
|
||||
const THREAD_COUNT_DEFAULT: usize = 2;
|
||||
static mut PER_THREAD: usize = 0;
|
||||
|
||||
unsafe fn critical_section(t: &mut usize) {
|
||||
let a = &mut A as *mut usize;
|
||||
let cur = a.read_volatile();
|
||||
for _ in 0..500 {
|
||||
*t = (*t) * (*t) % 10007;
|
||||
}
|
||||
a.write_volatile(cur + 1);
|
||||
}
|
||||
|
||||
unsafe fn lock(id: usize) {
|
||||
FLAG[id] = true;
|
||||
let j = 1 - id;
|
||||
TURN = j;
|
||||
// Tell the compiler not to reorder memory operations
|
||||
// across this fence.
|
||||
compiler_fence(Ordering::SeqCst);
|
||||
while FLAG[j] && TURN == j {
|
||||
yield_();
|
||||
}
|
||||
}
|
||||
|
||||
unsafe fn unlock(id: usize) {
|
||||
FLAG[id] = false;
|
||||
}
|
||||
|
||||
unsafe fn f(id: usize) -> ! {
|
||||
let mut t = 2usize;
|
||||
for _iter in 0..PER_THREAD {
|
||||
lock(id);
|
||||
critical_section(&mut t);
|
||||
unlock(id);
|
||||
}
|
||||
exit(t as i32)
|
||||
}
|
||||
|
||||
#[no_mangle]
|
||||
pub fn main(argc: usize, argv: &[&str]) -> i32 {
|
||||
let mut thread_count = THREAD_COUNT_DEFAULT;
|
||||
let mut per_thread = PER_THREAD_DEFAULT;
|
||||
if argc >= 2 {
|
||||
thread_count = argv[1].parse().unwrap();
|
||||
if argc >= 3 {
|
||||
per_thread = argv[2].parse().unwrap();
|
||||
}
|
||||
}
|
||||
unsafe { PER_THREAD = per_thread; }
|
||||
|
||||
// uncomment this if you want to check the assembly
|
||||
// println!(
|
||||
// "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.");
|
||||
for id in 0..thread_count {
|
||||
v.push(thread_create(f as usize, id) as usize);
|
||||
}
|
||||
let mut time_cost = Vec::new();
|
||||
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
|
||||
}
|
||||
//! It only works on a single CPU!
|
||||
|
||||
#![no_std]
|
||||
#![no_main]
|
||||
#![feature(core_intrinsics)]
|
||||
|
||||
#[macro_use]
|
||||
extern crate user_lib;
|
||||
extern crate alloc;
|
||||
|
||||
use alloc::vec::Vec;
|
||||
use core::sync::atomic::{compiler_fence, Ordering};
|
||||
use user_lib::{exit, get_time, thread_create, waittid, yield_};
|
||||
|
||||
static mut A: usize = 0;
|
||||
static mut FLAG: [bool; 2] = [false; 2];
|
||||
static mut TURN: usize = 0;
|
||||
const PER_THREAD_DEFAULT: usize = 2000;
|
||||
const THREAD_COUNT_DEFAULT: usize = 2;
|
||||
static mut PER_THREAD: usize = 0;
|
||||
|
||||
unsafe fn critical_section(t: &mut usize) {
|
||||
let a = &mut A as *mut usize;
|
||||
let cur = a.read_volatile();
|
||||
for _ in 0..500 {
|
||||
*t = (*t) * (*t) % 10007;
|
||||
}
|
||||
a.write_volatile(cur + 1);
|
||||
}
|
||||
|
||||
unsafe fn lock(id: usize) {
|
||||
FLAG[id] = true;
|
||||
let j = 1 - id;
|
||||
TURN = j;
|
||||
// Tell the compiler not to reorder memory operations
|
||||
// across this fence.
|
||||
compiler_fence(Ordering::SeqCst);
|
||||
while FLAG[j] && TURN == j {
|
||||
yield_();
|
||||
}
|
||||
}
|
||||
|
||||
unsafe fn unlock(id: usize) {
|
||||
FLAG[id] = false;
|
||||
}
|
||||
|
||||
unsafe fn f(id: usize) -> ! {
|
||||
let mut t = 2usize;
|
||||
for _iter in 0..PER_THREAD {
|
||||
lock(id);
|
||||
critical_section(&mut t);
|
||||
unlock(id);
|
||||
}
|
||||
exit(t as i32)
|
||||
}
|
||||
|
||||
#[no_mangle]
|
||||
pub fn main(argc: usize, argv: &[&str]) -> i32 {
|
||||
let mut thread_count = THREAD_COUNT_DEFAULT;
|
||||
let mut per_thread = PER_THREAD_DEFAULT;
|
||||
if argc >= 2 {
|
||||
thread_count = argv[1].parse().unwrap();
|
||||
if argc >= 3 {
|
||||
per_thread = argv[2].parse().unwrap();
|
||||
}
|
||||
}
|
||||
unsafe {
|
||||
PER_THREAD = per_thread;
|
||||
}
|
||||
|
||||
// uncomment this if you want to check the assembly
|
||||
// println!(
|
||||
// "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."
|
||||
);
|
||||
for id in 0..thread_count {
|
||||
v.push(thread_create(f as usize, id) as usize);
|
||||
}
|
||||
let mut time_cost = Vec::new();
|
||||
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();
|
||||
}
|
||||
}
|
||||
unsafe { PER_THREAD = per_thread; }
|
||||
unsafe {
|
||||
PER_THREAD = per_thread;
|
||||
}
|
||||
let start = get_time();
|
||||
let mut v = Vec::new();
|
||||
for _ in 0..thread_count {
|
||||
|
@ -1,70 +1,72 @@
|
||||
#![no_std]
|
||||
#![no_main]
|
||||
#![feature(core_intrinsics)]
|
||||
|
||||
#[macro_use]
|
||||
extern crate user_lib;
|
||||
extern crate alloc;
|
||||
|
||||
use alloc::vec::Vec;
|
||||
use user_lib::{exit, get_time, thread_create, waittid, yield_};
|
||||
|
||||
static mut A: usize = 0;
|
||||
static mut OCCUPIED: bool = false;
|
||||
const PER_THREAD_DEFAULT: usize = 10000;
|
||||
const THREAD_COUNT_DEFAULT: usize = 16;
|
||||
static mut PER_THREAD: usize = 0;
|
||||
|
||||
unsafe fn critical_section(t: &mut usize) {
|
||||
let a = &mut A as *mut usize;
|
||||
let cur = a.read_volatile();
|
||||
for _ in 0..500 {
|
||||
*t = (*t) * (*t) % 10007;
|
||||
}
|
||||
a.write_volatile(cur + 1);
|
||||
}
|
||||
|
||||
unsafe fn lock() {
|
||||
while OCCUPIED {
|
||||
yield_();
|
||||
}
|
||||
OCCUPIED = true;
|
||||
}
|
||||
|
||||
unsafe fn unlock() {
|
||||
OCCUPIED = false;
|
||||
}
|
||||
|
||||
unsafe fn f() -> ! {
|
||||
let mut t = 2usize;
|
||||
for _ in 0..PER_THREAD {
|
||||
lock();
|
||||
critical_section(&mut t);
|
||||
unlock();
|
||||
}
|
||||
exit(t as i32)
|
||||
}
|
||||
|
||||
#[no_mangle]
|
||||
pub fn main(argc: usize, argv: &[&str]) -> i32 {
|
||||
let mut thread_count = THREAD_COUNT_DEFAULT;
|
||||
let mut per_thread = PER_THREAD_DEFAULT;
|
||||
if argc >= 2 {
|
||||
thread_count = argv[1].parse().unwrap();
|
||||
if argc >= 3 {
|
||||
per_thread = argv[2].parse().unwrap();
|
||||
}
|
||||
}
|
||||
unsafe { PER_THREAD = per_thread; }
|
||||
let start = get_time();
|
||||
let mut v = Vec::new();
|
||||
for _ in 0..thread_count {
|
||||
v.push(thread_create(f as usize, 0) as usize);
|
||||
}
|
||||
for tid in v.into_iter() {
|
||||
waittid(tid);
|
||||
}
|
||||
println!("time cost is {}ms", get_time() - start);
|
||||
assert_eq!(unsafe { A }, unsafe { PER_THREAD } * thread_count);
|
||||
0
|
||||
}
|
||||
#![no_std]
|
||||
#![no_main]
|
||||
#![feature(core_intrinsics)]
|
||||
|
||||
#[macro_use]
|
||||
extern crate user_lib;
|
||||
extern crate alloc;
|
||||
|
||||
use alloc::vec::Vec;
|
||||
use user_lib::{exit, get_time, thread_create, waittid, yield_};
|
||||
|
||||
static mut A: usize = 0;
|
||||
static mut OCCUPIED: bool = false;
|
||||
const PER_THREAD_DEFAULT: usize = 10000;
|
||||
const THREAD_COUNT_DEFAULT: usize = 16;
|
||||
static mut PER_THREAD: usize = 0;
|
||||
|
||||
unsafe fn critical_section(t: &mut usize) {
|
||||
let a = &mut A as *mut usize;
|
||||
let cur = a.read_volatile();
|
||||
for _ in 0..500 {
|
||||
*t = (*t) * (*t) % 10007;
|
||||
}
|
||||
a.write_volatile(cur + 1);
|
||||
}
|
||||
|
||||
unsafe fn lock() {
|
||||
while OCCUPIED {
|
||||
yield_();
|
||||
}
|
||||
OCCUPIED = true;
|
||||
}
|
||||
|
||||
unsafe fn unlock() {
|
||||
OCCUPIED = false;
|
||||
}
|
||||
|
||||
unsafe fn f() -> ! {
|
||||
let mut t = 2usize;
|
||||
for _ in 0..PER_THREAD {
|
||||
lock();
|
||||
critical_section(&mut t);
|
||||
unlock();
|
||||
}
|
||||
exit(t as i32)
|
||||
}
|
||||
|
||||
#[no_mangle]
|
||||
pub fn main(argc: usize, argv: &[&str]) -> i32 {
|
||||
let mut thread_count = THREAD_COUNT_DEFAULT;
|
||||
let mut per_thread = PER_THREAD_DEFAULT;
|
||||
if argc >= 2 {
|
||||
thread_count = argv[1].parse().unwrap();
|
||||
if argc >= 3 {
|
||||
per_thread = argv[2].parse().unwrap();
|
||||
}
|
||||
}
|
||||
unsafe {
|
||||
PER_THREAD = per_thread;
|
||||
}
|
||||
let start = get_time();
|
||||
let mut v = Vec::new();
|
||||
for _ in 0..thread_count {
|
||||
v.push(thread_create(f as usize, 0) as usize);
|
||||
}
|
||||
for tid in v.into_iter() {
|
||||
waittid(tid);
|
||||
}
|
||||
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_main]
|
||||
|
||||
#[macro_use]
|
||||
extern crate user_lib;
|
||||
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 core::cell::UnsafeCell;
|
||||
use lazy_static::*;
|
||||
|
||||
const THREAD_NUM: usize = 3;
|
||||
|
||||
struct Barrier {
|
||||
mutex_id: usize,
|
||||
condvar_id: usize,
|
||||
count: UnsafeCell<usize>,
|
||||
}
|
||||
|
||||
impl Barrier {
|
||||
pub fn new() -> Self {
|
||||
Self {
|
||||
mutex_id: mutex_create() as usize,
|
||||
condvar_id: condvar_create() as usize,
|
||||
count: UnsafeCell::new(0),
|
||||
}
|
||||
}
|
||||
pub fn block(&self) {
|
||||
mutex_lock(self.mutex_id);
|
||||
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; }
|
||||
if unsafe { *count } == THREAD_NUM {
|
||||
condvar_signal(self.condvar_id);
|
||||
} else {
|
||||
condvar_wait(self.condvar_id, self.mutex_id);
|
||||
condvar_signal(self.condvar_id);
|
||||
}
|
||||
mutex_unlock(self.mutex_id);
|
||||
}
|
||||
}
|
||||
|
||||
unsafe impl Sync for Barrier {}
|
||||
|
||||
lazy_static! {
|
||||
static ref BARRIER_AB: Barrier = Barrier::new();
|
||||
static ref BARRIER_BC: Barrier = Barrier::new();
|
||||
}
|
||||
|
||||
fn thread_fn() {
|
||||
for _ in 0..300 { print!("a"); }
|
||||
BARRIER_AB.block();
|
||||
for _ in 0..300 { print!("b"); }
|
||||
BARRIER_BC.block();
|
||||
for _ in 0..300 { print!("c"); }
|
||||
exit(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
|
||||
}
|
||||
#![no_std]
|
||||
#![no_main]
|
||||
|
||||
#[macro_use]
|
||||
extern crate user_lib;
|
||||
extern crate alloc;
|
||||
|
||||
use alloc::vec::Vec;
|
||||
use core::cell::UnsafeCell;
|
||||
use lazy_static::*;
|
||||
use user_lib::{
|
||||
condvar_create, condvar_signal, condvar_wait, exit, mutex_create, mutex_lock, mutex_unlock,
|
||||
thread_create, waittid,
|
||||
};
|
||||
|
||||
const THREAD_NUM: usize = 3;
|
||||
|
||||
struct Barrier {
|
||||
mutex_id: usize,
|
||||
condvar_id: usize,
|
||||
count: UnsafeCell<usize>,
|
||||
}
|
||||
|
||||
impl Barrier {
|
||||
pub fn new() -> Self {
|
||||
Self {
|
||||
mutex_id: mutex_create() as usize,
|
||||
condvar_id: condvar_create() as usize,
|
||||
count: UnsafeCell::new(0),
|
||||
}
|
||||
}
|
||||
pub fn block(&self) {
|
||||
mutex_lock(self.mutex_id);
|
||||
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;
|
||||
}
|
||||
if unsafe { *count } == THREAD_NUM {
|
||||
condvar_signal(self.condvar_id);
|
||||
} else {
|
||||
condvar_wait(self.condvar_id, self.mutex_id);
|
||||
condvar_signal(self.condvar_id);
|
||||
}
|
||||
mutex_unlock(self.mutex_id);
|
||||
}
|
||||
}
|
||||
|
||||
unsafe impl Sync for Barrier {}
|
||||
|
||||
lazy_static! {
|
||||
static ref BARRIER_AB: Barrier = Barrier::new();
|
||||
static ref BARRIER_BC: Barrier = Barrier::new();
|
||||
}
|
||||
|
||||
fn thread_fn() {
|
||||
for _ in 0..300 {
|
||||
print!("a");
|
||||
}
|
||||
BARRIER_AB.block();
|
||||
for _ in 0..300 {
|
||||
print!("b");
|
||||
}
|
||||
BARRIER_BC.block();
|
||||
for _ in 0..300 {
|
||||
print!("c");
|
||||
}
|
||||
exit(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_main]
|
||||
|
||||
#[macro_use]
|
||||
extern crate user_lib;
|
||||
extern crate alloc;
|
||||
|
||||
use user_lib::{thread_create, exit, waittid};
|
||||
use alloc::vec::Vec;
|
||||
|
||||
const THREAD_NUM: usize = 3;
|
||||
|
||||
fn thread_fn() {
|
||||
for ch in 'a'..='c' {
|
||||
for _ in 0..300 {
|
||||
print!("{}", ch);
|
||||
}
|
||||
}
|
||||
exit(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
|
||||
}
|
||||
#![no_std]
|
||||
#![no_main]
|
||||
|
||||
#[macro_use]
|
||||
extern crate user_lib;
|
||||
extern crate alloc;
|
||||
|
||||
use alloc::vec::Vec;
|
||||
use user_lib::{exit, thread_create, waittid};
|
||||
|
||||
const THREAD_NUM: usize = 3;
|
||||
|
||||
fn thread_fn() {
|
||||
for ch in 'a'..='c' {
|
||||
for _ in 0..300 {
|
||||
print!("{}", ch);
|
||||
}
|
||||
}
|
||||
exit(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,64 +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
|
||||
}
|
||||
#![no_std]
|
||||
#![no_main]
|
||||
|
||||
#[macro_use]
|
||||
extern crate user_lib;
|
||||
|
||||
extern crate alloc;
|
||||
|
||||
use alloc::vec;
|
||||
use user_lib::exit;
|
||||
use user_lib::{
|
||||
mutex_blocking_create, mutex_lock, mutex_unlock, semaphore_create, semaphore_down, semaphore_up,
|
||||
};
|
||||
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
|
||||
}
|
||||
|
@ -8,7 +8,7 @@ use user_lib::{Display, VIRTGPU_XRES, VIRTGPU_YRES};
|
||||
|
||||
use embedded_graphics::pixelcolor::Rgb888;
|
||||
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_Y: i32 = 400;
|
||||
@ -35,10 +35,14 @@ impl DrawingBoard {
|
||||
.into_styled(PrimitiveStyle::with_fill(Rgb888::BLUE))
|
||||
.draw(&mut self.disp)
|
||||
.ok();
|
||||
Triangle::new(self.latest_pos + Point::new(0, 150), self.latest_pos + Point::new(80, 200), self.latest_pos + Point::new(-120, 300))
|
||||
.into_styled(PrimitiveStyle::with_stroke(Rgb888::GREEN, 10))
|
||||
.draw(&mut self.disp)
|
||||
.ok();
|
||||
Triangle::new(
|
||||
self.latest_pos + Point::new(0, 150),
|
||||
self.latest_pos + Point::new(80, 200),
|
||||
self.latest_pos + Point::new(-120, 300),
|
||||
)
|
||||
.into_styled(PrimitiveStyle::with_stroke(Rgb888::GREEN, 10))
|
||||
.draw(&mut self.disp)
|
||||
.ok();
|
||||
}
|
||||
fn unpaint(&mut self) {
|
||||
Rectangle::with_center(self.latest_pos, Size::new(RECT_SIZE, RECT_SIZE))
|
||||
|
@ -3,8 +3,8 @@
|
||||
|
||||
extern crate user_lib;
|
||||
|
||||
use user_lib::{VIRTGPU_XRES, VIRTGPU_YRES, Display};
|
||||
use embedded_graphics::prelude::Size;
|
||||
use user_lib::{Display, VIRTGPU_XRES, VIRTGPU_YRES};
|
||||
|
||||
#[no_mangle]
|
||||
pub fn main() -> i32 {
|
||||
|
@ -1,11 +1,11 @@
|
||||
#![no_std]
|
||||
#![no_main]
|
||||
|
||||
extern crate user_lib;
|
||||
extern crate alloc;
|
||||
extern crate user_lib;
|
||||
|
||||
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::prelude::{Drawable, Point, RgbColor, Size};
|
||||
|
@ -113,7 +113,7 @@ pub fn main() -> i32 {
|
||||
let mut board = DrawingBoard::new();
|
||||
let _ = board.disp.clear(Rgb888::BLACK).unwrap();
|
||||
for i in 0..20 {
|
||||
let c=getchar();
|
||||
let c = getchar();
|
||||
if c == LF || c == CR {
|
||||
break;
|
||||
}
|
||||
|
@ -22,4 +22,4 @@ pub fn main() -> i32 {
|
||||
}
|
||||
}
|
||||
0
|
||||
}
|
||||
}
|
||||
|
@ -77,4 +77,4 @@ pub fn main() -> i32 {
|
||||
}
|
||||
println!("main thread exited.");
|
||||
0
|
||||
}
|
||||
}
|
||||
|
@ -13,4 +13,4 @@ pub fn main() -> i32 {
|
||||
println!("OORandom: Random number 32bit: {}", rng.rand_i32());
|
||||
println!("OORandom: Random number range: {}", rng.rand_range(1..100));
|
||||
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
|
||||
// to do it here. The important part is that once allocated it MUST NOT move in memory.
|
||||
Task {
|
||||
id:id,
|
||||
id: id,
|
||||
stack: vec![0_u8; DEFAULT_STACK_SIZE],
|
||||
ctx: TaskContext::default(),
|
||||
state: State::Available,
|
||||
|
@ -10,7 +10,7 @@ extern crate alloc;
|
||||
|
||||
// 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.
|
||||
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);
|
||||
hexdump(&buf[..len as usize]);
|
||||
|
||||
// verify whether it is a valid HTTP request simply, [0x47,0x45,0x54, 0x20] is GET
|
||||
if len < 4 || buf[..4] != [0x47,0x45,0x54, 0x20] {
|
||||
// verify whether it is a valid HTTP request simply, [0x47,0x45,0x54, 0x20] is GET
|
||||
if len < 4 || buf[..4] != [0x47, 0x45, 0x54, 0x20] {
|
||||
println!("it's not a valid http request");
|
||||
return false;
|
||||
}
|
||||
@ -136,12 +136,12 @@ pub fn main() -> i32 {
|
||||
loop {
|
||||
let client = accept(tcp_fd as usize);
|
||||
println!("client connected: {}", client);
|
||||
|
||||
|
||||
if client < 1 {
|
||||
println!("Failed to accept a client on port 80");
|
||||
return -1;
|
||||
}
|
||||
|
||||
|
||||
if handle_tcp_client(client as usize) {
|
||||
break;
|
||||
}
|
||||
|
@ -1,7 +1,7 @@
|
||||
use super::*;
|
||||
use embedded_graphics::pixelcolor::Rgb888;
|
||||
use embedded_graphics::prelude::{RgbColor, Size};
|
||||
use embedded_graphics::{draw_target::DrawTarget, prelude::OriginDimensions};
|
||||
use embedded_graphics::pixelcolor::Rgb888;
|
||||
use virtio_input_decoder::Decoder;
|
||||
pub use virtio_input_decoder::{DecodeType, Key, KeyType, Mouse};
|
||||
|
||||
@ -24,9 +24,8 @@ pub struct Display {
|
||||
impl Display {
|
||||
pub fn new(size: Size) -> Self {
|
||||
let fb_ptr = framebuffer() as *mut u8;
|
||||
let fb =
|
||||
unsafe { core::slice::from_raw_parts_mut(fb_ptr, VIRTGPU_LEN as usize) };
|
||||
Self { size, fb}
|
||||
let fb = unsafe { core::slice::from_raw_parts_mut(fb_ptr, VIRTGPU_LEN as usize) };
|
||||
Self { size, fb }
|
||||
}
|
||||
pub fn framebuffer(&mut self) -> &mut [u8] {
|
||||
self.fb
|
||||
@ -53,9 +52,7 @@ impl DrawTarget for Display {
|
||||
I: IntoIterator<Item = embedded_graphics::Pixel<Self::Color>>,
|
||||
{
|
||||
pixels.into_iter().for_each(|px| {
|
||||
let idx = (px.0.y * VIRTGPU_XRES as i32 + px.0.x)
|
||||
as usize
|
||||
* 4;
|
||||
let idx = (px.0.y * VIRTGPU_XRES as i32 + px.0.x) as usize * 4;
|
||||
if idx + 2 >= self.fb.len() {
|
||||
return;
|
||||
}
|
||||
@ -113,6 +110,7 @@ impl InputEvent {
|
||||
self.event_type as usize,
|
||||
self.code as usize,
|
||||
self.value as usize,
|
||||
).ok()
|
||||
)
|
||||
.ok()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -80,4 +80,4 @@ pub fn waittid(tid: usize) -> isize {
|
||||
exit_code => return exit_code,
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user