Merge ch9

This commit is contained in:
yufeng 2023-02-06 19:51:24 +08:00
commit fc173e5344
57 changed files with 1909 additions and 678 deletions

View File

@ -85,9 +85,9 @@ fn easy_fs_pack() -> std::io::Result<()> {
inode.write_at(0, all_data.as_slice());
}
// list apps
for app in root_inode.ls() {
println!("{}", app);
}
// for app in root_inode.ls() {
// println!("{}", app);
// }
Ok(())
}

View File

@ -17,7 +17,6 @@ volatile = "0.3"
virtio-drivers = { git = "https://github.com/rcore-os/virtio-drivers", rev = "4ee80e5" }
lose-net-stack = { git = "https://github.com/yfblock/lose-net-stack", rev = "3f467dd" }
easy-fs = { path = "../easy-fs" }
virtio-input-decoder = "0.1.4"
embedded-graphics = "0.7.1"
tinybmp = "0.3.1"

View File

@ -12,7 +12,7 @@ pub type CharDeviceImpl = crate::drivers::chardev::NS16550a<VIRT_UART>;
pub const VIRT_PLIC: usize = 0xC00_0000;
pub const VIRT_UART: usize = 0x1000_0000;
#[allow(unused)]
pub const VIRTGPU_XRES: u32 = 1280;
#[allow(unused)]
pub const VIRTGPU_YRES: u32 = 800;

View File

@ -131,7 +131,7 @@ pub struct NS16550a<const BASE_ADDR: usize> {
impl<const BASE_ADDR: usize> NS16550a<BASE_ADDR> {
pub fn new() -> Self {
let mut inner = NS16550aInner {
let inner = NS16550aInner {
ns16550a: NS16550aRaw::new(BASE_ADDR),
read_buffer: VecDeque::new(),
};
@ -141,14 +141,20 @@ impl<const BASE_ADDR: usize> NS16550a<BASE_ADDR> {
condvar: Condvar::new(),
}
}
pub fn read_buffer_is_empty(&self) -> bool {
self.inner
.exclusive_session(|inner| inner.read_buffer.is_empty())
}
}
impl<const BASE_ADDR: usize> CharDevice for NS16550a<BASE_ADDR> {
fn init(&self){
fn init(&self) {
let mut inner = self.inner.exclusive_access();
inner.ns16550a.init();
drop(inner);
}
}
fn read(&self) -> u8 {
loop {
let mut inner = self.inner.exclusive_access();

View File

@ -1,20 +1,28 @@
use crate::drivers::bus::virtio::VirtioHal;
use crate::{
gui::{move_rect, reset},
sync::UPIntrFreeCell,
};
use crate::sync::{Condvar, UPIntrFreeCell};
use crate::task::schedule;
use alloc::collections::VecDeque;
use alloc::sync::Arc;
use core::any::Any;
use virtio_drivers::{VirtIOHeader, VirtIOInput};
use virtio_input_decoder::{Decoder, Key, KeyType};
const VIRTIO5: usize = 0x10005000;
const VIRTIO6: usize = 0x10006000;
struct VirtIOInputWrapper(UPIntrFreeCell<VirtIOInput<'static, VirtioHal>>);
struct VirtIOInputInner {
virtio_input: VirtIOInput<'static, VirtioHal>,
events: VecDeque<u64>,
}
struct VirtIOInputWrapper {
inner: UPIntrFreeCell<VirtIOInputInner>,
condvar: Condvar,
}
pub trait InputDevice: Send + Sync + Any {
fn read_event(&self) -> u64;
fn handle_irq(&self);
fn is_empty(&self) -> bool;
}
lazy_static::lazy_static!(
@ -24,52 +32,52 @@ lazy_static::lazy_static!(
impl VirtIOInputWrapper {
pub fn new(addr: usize) -> Self {
Self(unsafe {
UPIntrFreeCell::new(
VirtIOInput::<VirtioHal>::new(&mut *(addr as *mut VirtIOHeader)).unwrap(),
)
})
let inner = VirtIOInputInner {
virtio_input: unsafe {
VirtIOInput::<VirtioHal>::new(&mut *(addr as *mut VirtIOHeader)).unwrap()
},
events: VecDeque::new(),
};
Self {
inner: unsafe { UPIntrFreeCell::new(inner) },
condvar: Condvar::new(),
}
}
}
impl InputDevice for VirtIOInputWrapper {
fn handle_irq(&self) {
let mut input = self.0.exclusive_access();
input.ack_interrupt();
while let Some(event) = input.pop_pending_event() {
let dtype = match Decoder::decode(
event.event_type as usize,
event.code as usize,
event.value as usize,
) {
Ok(dtype) => dtype,
Err(_) => break,
};
match dtype {
virtio_input_decoder::DecodeType::Key(key, r#type) => {
if r#type == KeyType::Press {
match key {
Key::C | Key::MouseLeft => {
reset();
}
Key::W => {
move_rect(0, -10);
}
Key::S => {
move_rect(0, 10);
}
Key::A => {
move_rect(-10, 0);
}
Key::D => {
move_rect(10, 0);
}
_ => {}
}
}
}
_ => {}
fn is_empty(&self) -> bool {
self.inner.exclusive_access().events.is_empty()
}
fn read_event(&self) -> u64 {
loop {
let mut inner = self.inner.exclusive_access();
if let Some(event) = inner.events.pop_front() {
return event;
} else {
let task_cx_ptr = self.condvar.wait_no_sched();
drop(inner);
schedule(task_cx_ptr);
}
}
}
fn handle_irq(&self) {
let mut count = 0;
let mut result = 0;
self.inner.exclusive_session(|inner| {
inner.virtio_input.ack_interrupt();
while let Some(event) = inner.virtio_input.pop_pending_event() {
count += 1;
result = (event.event_type as u64) << 48
| (event.code as u64) << 32
| (event.value) as u64;
inner.events.push_back(result);
}
});
if count > 0 {
self.condvar.signal();
};
}
}

View File

@ -170,4 +170,4 @@ impl File for Pipe {
}
}
}
}
}

View File

@ -1,63 +0,0 @@
use alloc::sync::Arc;
use embedded_graphics::{
draw_target::DrawTarget,
pixelcolor::Rgb888,
prelude::{OriginDimensions, Point, RgbColor, Size},
};
use crate::board::VIRTGPU_XRES;
use crate::drivers::{GpuDevice, GPU_DEVICE};
#[derive(Clone)]
pub struct Graphics {
pub size: Size,
pub point: Point,
pub drv: Arc<dyn GpuDevice>,
}
impl Graphics {
pub fn new(size: Size, point: Point) -> Self {
Self {
size,
point,
drv: GPU_DEVICE.clone(),
}
}
pub fn reset(&self) {
let fb = self.drv.get_framebuffer();
fb.fill(0u8);
}
}
impl OriginDimensions for Graphics {
fn size(&self) -> Size {
self.size
}
}
impl DrawTarget for Graphics {
type Color = Rgb888;
type Error = core::convert::Infallible;
fn draw_iter<I>(&mut self, pixels: I) -> Result<(), Self::Error>
where
I: IntoIterator<Item = embedded_graphics::Pixel<Self::Color>>,
{
let fb = self.drv.get_framebuffer();
pixels.into_iter().for_each(|px| {
let idx = ((self.point.y + px.0.y) * VIRTGPU_XRES as i32 + self.point.x + px.0.x)
as usize
* 4;
if idx + 2 >= fb.len() {
return;
}
fb[idx] = px.1.b();
fb[idx + 1] = px.1.g();
fb[idx + 2] = px.1.r();
});
self.drv.flush();
Ok(())
}
}

View File

@ -1,5 +0,0 @@
mod graphic;
mod paint;
use graphic::Graphics;
pub use paint::{init_paint, move_rect, reset};

View File

@ -1,62 +0,0 @@
use super::Graphics;
use crate::sync::UPIntrFreeCell;
use embedded_graphics::pixelcolor::Rgb888;
use embedded_graphics::prelude::{Drawable, Point, RgbColor, Size};
use embedded_graphics::primitives::Primitive;
use embedded_graphics::primitives::{PrimitiveStyle, Rectangle};
use lazy_static::*;
const INIT_X: i32 = 640;
const INIT_Y: i32 = 400;
const RECT_SIZE: u32 = 40;
pub struct DrawingBoard {
graphics: Graphics,
latest_pos: Point,
}
impl DrawingBoard {
pub fn new() -> Self {
Self {
graphics: Graphics::new(Size::new(1280, 800), Point::new(0, 0)),
latest_pos: Point::new(INIT_X, INIT_Y),
}
}
fn paint(&mut self) {
Rectangle::with_center(self.latest_pos, Size::new(RECT_SIZE, RECT_SIZE))
.into_styled(PrimitiveStyle::with_stroke(Rgb888::WHITE, 1))
.draw(&mut self.graphics)
.ok();
}
pub fn move_rect(&mut self, dx: i32, dy: i32) {
self.latest_pos.x += dx;
self.latest_pos.y += dy;
self.paint();
}
pub fn reset(&mut self) {
self.latest_pos = Point::new(INIT_X, INIT_Y);
self.graphics.reset();
}
}
lazy_static! {
pub static ref DRAWING_BOARD: UPIntrFreeCell<DrawingBoard> = unsafe { UPIntrFreeCell::new(DrawingBoard::new()) };
}
pub fn init_paint() {
DRAWING_BOARD.exclusive_session(|ripple| {
ripple.paint();
});
}
pub fn move_rect(dx: i32, dy: i32) {
DRAWING_BOARD.exclusive_session(|ripple| {
ripple.move_rect(dx, dy);
});
}
pub fn reset() {
DRAWING_BOARD.exclusive_session(|ripple| {
ripple.reset();
});
}

View File

@ -5,8 +5,8 @@
#![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};
extern crate alloc;
#[macro_use]
@ -20,7 +20,6 @@ mod console;
mod config;
mod drivers;
mod fs;
mod gui;
mod lang_items;
mod mm;
mod sbi;
@ -256,8 +255,6 @@ pub fn rust_main() -> ! {
//clear_bss();
mm::init();
UART.init();
println!("KERN: begin");
//loop{};
println!("KERN: init gpu");
let _gpu = GPU_DEVICE.clone();
println!("KERN: init keyboard");
@ -270,7 +267,6 @@ pub fn rust_main() -> ! {
//timer::set_next_trigger();
board::device_init();
fs::list_apps();
//gui::init_paint();
task::add_initproc();
*DEV_NON_BLOCKING_ACCESS.exclusive_access() = true;
task::run_tasks();

View File

@ -71,7 +71,10 @@ impl MemorySet {
self.areas.remove(idx);
}
}
fn push(&mut self, mut map_area: MapArea, data: Option<&[u8]>) {
/// Add a new MapArea into this MemorySet.
/// Assuming that there are no conflicts in the virtual address
/// space.
pub fn push(&mut self, mut map_area: MapArea, data: Option<&[u8]>) {
map_area.map(&mut self.page_table);
if let Some(data) = data {
map_area.copy_data(&mut self.page_table, data);
@ -286,6 +289,11 @@ impl MapArea {
ppn = frame.ppn;
self.data_frames.insert(vpn, frame);
}
MapType::Linear(pn_offset) => {
// check for sv39
assert!(vpn.0 < (1usize << 27));
ppn = PhysPageNum((vpn.0 as isize + pn_offset) as usize);
}
}
let pte_flags = PTEFlags::from_bits(self.map_perm.bits).unwrap();
page_table.map(vpn, ppn, pte_flags);
@ -334,6 +342,8 @@ impl MapArea {
pub enum MapType {
Identical,
Framed,
/// offset of page num
Linear(isize),
}
bitflags! {

View File

@ -4,11 +4,11 @@ mod heap_allocator;
mod memory_set;
mod page_table;
use address::VPNRange;
pub use address::VPNRange;
pub use address::{PhysAddr, PhysPageNum, StepByOne, VirtAddr, VirtPageNum};
pub use frame_allocator::{frame_alloc, frame_alloc_more, frame_dealloc, FrameTracker};
pub use memory_set::remap_test;
pub use memory_set::{kernel_token, MapPermission, MemorySet, KERNEL_SPACE};
pub use memory_set::{kernel_token, MapArea, MapPermission, MapType, MemorySet, KERNEL_SPACE};
use page_table::PTEFlags;
pub use page_table::{
translated_byte_buffer, translated_ref, translated_refmut, translated_str, PageTable,

View File

@ -1,6 +1,6 @@
use crate::sync::{Mutex, UPIntrFreeCell};
use crate::task::{
add_task, block_current_and_run_next, block_current_task, current_task, TaskContext,
wakeup_task, block_current_and_run_next, block_current_task, current_task, TaskContext,
TaskControlBlock,
};
use alloc::{collections::VecDeque, sync::Arc};
@ -27,7 +27,7 @@ impl Condvar {
pub fn signal(&self) {
let mut inner = self.inner.exclusive_access();
if let Some(task) = inner.wait_queue.pop_front() {
add_task(task);
wakeup_task(task);
}
}

View File

@ -1,6 +1,6 @@
use super::UPIntrFreeCell;
use crate::task::TaskControlBlock;
use crate::task::{add_task, current_task};
use crate::task::{wakeup_task, current_task};
use crate::task::{block_current_and_run_next, suspend_current_and_run_next};
use alloc::{collections::VecDeque, sync::Arc};
@ -80,7 +80,7 @@ impl Mutex for MutexBlocking {
let mut mutex_inner = self.inner.exclusive_access();
assert!(mutex_inner.locked);
if let Some(waking_task) = mutex_inner.wait_queue.pop_front() {
add_task(waking_task);
wakeup_task(waking_task);
} else {
mutex_inner.locked = false;
}

View File

@ -1,5 +1,5 @@
use crate::sync::UPIntrFreeCell;
use crate::task::{add_task, block_current_and_run_next, current_task, TaskControlBlock};
use crate::task::{wakeup_task, block_current_and_run_next, current_task, TaskControlBlock};
use alloc::{collections::VecDeque, sync::Arc};
pub struct Semaphore {
@ -28,7 +28,7 @@ impl Semaphore {
inner.count += 1;
if inner.count <= 0 {
if let Some(task) = inner.wait_queue.pop_front() {
add_task(task);
wakeup_task(task);
}
}
}

34
os/src/syscall/gui.rs Normal file
View File

@ -0,0 +1,34 @@
use crate::drivers::GPU_DEVICE;
use crate::mm::{MapArea, MapPermission, MapType, PhysAddr, VirtAddr};
use crate::task::current_process;
const FB_VADDR: usize = 0x10000000;
pub fn sys_framebuffer() -> isize {
let fb = GPU_DEVICE.get_framebuffer();
let len = fb.len();
// println!("[kernel] FrameBuffer: addr 0x{:X}, len {}", fb.as_ptr() as usize , len);
let fb_start_pa = PhysAddr::from(fb.as_ptr() as usize);
assert!(fb_start_pa.aligned());
let fb_start_ppn = fb_start_pa.floor();
let fb_start_vpn = VirtAddr::from(FB_VADDR).floor();
let pn_offset = fb_start_ppn.0 as isize - fb_start_vpn.0 as isize;
let current_process = current_process();
let mut inner = current_process.inner_exclusive_access();
inner.memory_set.push(
MapArea::new(
(FB_VADDR as usize).into(),
(FB_VADDR + len as usize).into(),
MapType::Linear(pn_offset),
MapPermission::R | MapPermission::W | MapPermission::U,
),
None,
);
FB_VADDR as isize
}
pub fn sys_framebuffer_flush() -> isize {
GPU_DEVICE.flush();
0
}

28
os/src/syscall/input.rs Normal file
View File

@ -0,0 +1,28 @@
//use crate::drivers::{KEYBOARD_DEVICE,MOUSE_DEVICE,INPUT_CONDVAR,read_input_event};
use crate::drivers::{KEYBOARD_DEVICE, MOUSE_DEVICE};
pub fn sys_event_get() -> isize {
let kb = KEYBOARD_DEVICE.clone();
let mouse = MOUSE_DEVICE.clone();
//let input=INPUT_CONDVAR.clone();
//read_input_event() as isize
if !kb.is_empty() {
kb.read_event() as isize
} else if !mouse.is_empty() {
mouse.read_event() as isize
} else {
0
}
}
use crate::drivers::chardev::UART;
/// check UART's read-buffer is empty or not
pub fn sys_key_pressed() -> isize {
let res = !UART.read_buffer_is_empty();
if res {
1
} else {
0
}
}

View File

@ -26,14 +26,22 @@ const SYSCALL_SEMAPHORE_DOWN: usize = 1022;
const SYSCALL_CONDVAR_CREATE: usize = 1030;
const SYSCALL_CONDVAR_SIGNAL: usize = 1031;
const SYSCALL_CONDVAR_WAIT: usize = 1032;
const SYSCALL_FRAMEBUFFER: usize = 2000;
const SYSCALL_FRAMEBUFFER_FLUSH: usize = 2001;
const SYSCALL_EVENT_GET: usize = 3000;
const SYSCALL_KEY_PRESSED: usize = 3001;
mod fs;
mod gui;
mod input;
mod process;
mod sync;
mod thread;
mod net;
use fs::*;
use gui::*;
use input::*;
use process::*;
use sync::*;
use thread::*;
@ -66,9 +74,13 @@ pub fn syscall(syscall_id: usize, args: [usize; 3]) -> isize {
SYSCALL_SEMAPHORE_CREATE => sys_semaphore_create(args[0]),
SYSCALL_SEMAPHORE_UP => sys_semaphore_up(args[0]),
SYSCALL_SEMAPHORE_DOWN => sys_semaphore_down(args[0]),
SYSCALL_CONDVAR_CREATE => sys_condvar_create(args[0]),
SYSCALL_CONDVAR_CREATE => sys_condvar_create(),
SYSCALL_CONDVAR_SIGNAL => sys_condvar_signal(args[0]),
SYSCALL_CONDVAR_WAIT => sys_condvar_wait(args[0], args[1]),
SYSCALL_FRAMEBUFFER => sys_framebuffer(),
SYSCALL_FRAMEBUFFER_FLUSH => sys_framebuffer_flush(),
SYSCALL_EVENT_GET => sys_event_get(),
SYSCALL_KEY_PRESSED => sys_key_pressed(),
_ => panic!("Unsupported syscall_id: {}", syscall_id),
}
}

View File

@ -93,7 +93,7 @@ pub fn sys_semaphore_down(sem_id: usize) -> isize {
0
}
pub fn sys_condvar_create(_arg: usize) -> isize {
pub fn sys_condvar_create() -> isize {
let process = current_process();
let mut process_inner = process.inner_exclusive_access();
let id = if let Some(id) = process_inner

View File

@ -1,4 +1,4 @@
use super::{ProcessControlBlock, TaskControlBlock};
use super::{ProcessControlBlock, TaskControlBlock, TaskStatus};
use crate::sync::UPIntrFreeCell;
use alloc::collections::{BTreeMap, VecDeque};
use alloc::sync::Arc;
@ -34,6 +34,13 @@ pub fn add_task(task: Arc<TaskControlBlock>) {
TASK_MANAGER.exclusive_access().add(task);
}
pub fn wakeup_task(task: Arc<TaskControlBlock>) {
let mut task_inner = task.inner_exclusive_access();
task_inner.task_status = TaskStatus::Ready;
drop(task_inner);
add_task(task);
}
pub fn fetch_task() -> Option<Arc<TaskControlBlock>> {
TASK_MANAGER.exclusive_access().fetch()
}

View File

@ -18,7 +18,7 @@ use switch::__switch;
pub use context::TaskContext;
pub use id::{kstack_alloc, pid_alloc, KernelStack, PidHandle, IDLE_PID};
pub use manager::{add_task, pid2process, remove_from_pid2process};
pub use manager::{add_task, wakeup_task, pid2process, remove_from_pid2process};
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,
@ -48,7 +48,7 @@ pub fn suspend_current_and_run_next() {
pub fn block_current_task() -> *mut TaskContext {
let task = take_current_task().unwrap();
let mut task_inner = task.inner_exclusive_access();
task_inner.task_status = TaskStatus::Blocking;
task_inner.task_status = TaskStatus::Blocked;
&mut task_inner.task_cx as *mut TaskContext
}

View File

@ -76,5 +76,5 @@ impl TaskControlBlock {
pub enum TaskStatus {
Ready,
Running,
Blocking,
Blocked,
}

View File

@ -3,7 +3,7 @@ use core::cmp::Ordering;
use crate::config::CLOCK_FREQ;
use crate::sbi::set_timer;
use crate::sync::UPIntrFreeCell;
use crate::task::{add_task, TaskControlBlock};
use crate::task::{wakeup_task, TaskControlBlock};
use alloc::collections::BinaryHeap;
use alloc::sync::Arc;
use lazy_static::*;
@ -64,7 +64,7 @@ pub fn check_timer() {
TIMERS.exclusive_session(|timers| {
while let Some(timer) = timers.peek() {
if timer.expire_ms <= current_ms {
add_task(Arc::clone(&timer.task));
wakeup_task(Arc::clone(&timer.task));
timers.pop();
} else {
break;

View File

@ -10,10 +10,10 @@ edition = "2018"
buddy_system_allocator = "0.6"
bitflags = "1.2.1"
riscv = { git = "https://github.com/rcore-os/riscv", features = ["inline-asm"] }
lazy_static = { version = "1.4.0", features = ["spin_no_std"] }
embedded-graphics = "0.7.1"
oorandom ="11"
virtio-input-decoder = "0.1.4"
[profile.release]
debug = true
# [features]
# board_qemu = []
# board_k210 = []
debug = true

View File

@ -19,7 +19,7 @@ ifeq ($(TEST), 1)
endif
binary: elf
$(foreach elf, $(ELFS), $(OBJCOPY) $(elf) --strip-all -O binary $(patsubst $(TARGET_DIR)/%, $(TARGET_DIR)/%.bin, $(elf));)
@$(foreach elf, $(ELFS), $(OBJCOPY) $(elf) --strip-all -O binary $(patsubst $(TARGET_DIR)/%, $(TARGET_DIR)/%.bin, $(elf));)
build: binary

55
user/src/bin/adder.rs Normal file
View File

@ -0,0 +1,55 @@
#![no_std]
#![no_main]
#[macro_use]
extern crate user_lib;
extern crate alloc;
use alloc::vec::Vec;
use user_lib::{exit, get_time, thread_create, waittid};
static mut A: usize = 0;
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 f() -> ! {
let mut t = 2usize;
for _ in 0..PER_THREAD {
critical_section(&mut t);
}
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
}

View File

@ -0,0 +1,72 @@
#![no_std]
#![no_main]
#[macro_use]
extern crate user_lib;
extern crate alloc;
use alloc::vec::Vec;
use core::sync::atomic::{AtomicBool, Ordering};
use user_lib::{exit, get_time, thread_create, waittid, yield_};
static mut A: usize = 0;
static OCCUPIED: AtomicBool = AtomicBool::new(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);
}
fn lock() {
while OCCUPIED
.compare_exchange(false, true, Ordering::Relaxed, Ordering::Relaxed)
.is_err()
{
yield_();
}
}
fn unlock() {
OCCUPIED.store(false, Ordering::Relaxed);
}
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
}

View File

@ -0,0 +1,59 @@
#![no_std]
#![no_main]
#[macro_use]
extern crate user_lib;
extern crate alloc;
use alloc::vec::Vec;
use user_lib::{exit, get_time, thread_create, waittid};
use user_lib::{mutex_blocking_create, mutex_lock, mutex_unlock};
static mut A: usize = 0;
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 f() -> ! {
let mut t = 2usize;
for _ in 0..PER_THREAD {
mutex_lock(0);
critical_section(&mut t);
mutex_unlock(0);
}
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();
assert_eq!(mutex_blocking_create(), 0);
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
}

View File

@ -0,0 +1,60 @@
#![no_std]
#![no_main]
#[macro_use]
extern crate user_lib;
extern crate alloc;
use alloc::vec::Vec;
use user_lib::{exit, get_time, thread_create, waittid};
use user_lib::{mutex_create, mutex_lock, mutex_unlock};
static mut A: usize = 0;
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 f() -> ! {
let mut t = 2usize;
for _ in 0..PER_THREAD {
mutex_lock(0);
critical_section(&mut t);
mutex_unlock(0);
}
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();
assert_eq!(mutex_create(), 0);
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
}

View File

@ -0,0 +1,90 @@
//! 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
}

View File

@ -0,0 +1,89 @@
//! 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
}

View File

@ -0,0 +1,68 @@
#![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};
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 vload!(&OCCUPIED) {}
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
}

View File

@ -0,0 +1,70 @@
#![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
}

View File

@ -0,0 +1,72 @@
#![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
}

View File

@ -0,0 +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
}

View File

@ -1,59 +1,59 @@
#![no_std]
#![no_main]
#[macro_use]
extern crate user_lib;
extern crate alloc;
use alloc::vec;
use user_lib::exit;
use user_lib::{
condvar_create, condvar_signal, condvar_wait, mutex_blocking_create, mutex_lock, mutex_unlock,
};
use user_lib::{sleep, thread_create, waittid};
static mut A: usize = 0;
const CONDVAR_ID: usize = 0;
const MUTEX_ID: usize = 0;
unsafe fn first() -> ! {
sleep(10);
println!("First work, Change A --> 1 and wakeup Second");
mutex_lock(MUTEX_ID);
A = 1;
condvar_signal(CONDVAR_ID);
mutex_unlock(MUTEX_ID);
exit(0)
}
unsafe fn second() -> ! {
println!("Second want to continue,but need to wait A=1");
mutex_lock(MUTEX_ID);
while A == 0 {
println!("Second: A is {}", A);
condvar_wait(CONDVAR_ID, MUTEX_ID);
}
mutex_unlock(MUTEX_ID);
println!("A is {}, Second can work now", A);
exit(0)
}
#[no_mangle]
pub fn main() -> i32 {
// create condvar & mutex
assert_eq!(condvar_create() as usize, CONDVAR_ID);
assert_eq!(mutex_blocking_create() as usize, MUTEX_ID);
// create threads
let threads = vec![
thread_create(first as usize, 0),
thread_create(second as usize, 0),
];
// wait for all threads to complete
for thread in threads.iter() {
waittid(*thread as usize);
}
println!("test_condvar passed!");
0
}
#![no_std]
#![no_main]
#[macro_use]
extern crate user_lib;
extern crate alloc;
use alloc::vec;
use user_lib::exit;
use user_lib::{
condvar_create, condvar_signal, condvar_wait, mutex_blocking_create, mutex_lock, mutex_unlock,
};
use user_lib::{sleep, thread_create, waittid};
static mut A: usize = 0;
const CONDVAR_ID: usize = 0;
const MUTEX_ID: usize = 0;
unsafe fn first() -> ! {
sleep(10);
println!("First work, Change A --> 1 and wakeup Second");
mutex_lock(MUTEX_ID);
A = 1;
condvar_signal(CONDVAR_ID);
mutex_unlock(MUTEX_ID);
exit(0)
}
unsafe fn second() -> ! {
println!("Second want to continue,but need to wait A=1");
mutex_lock(MUTEX_ID);
while A == 0 {
println!("Second: A is {}", A);
condvar_wait(CONDVAR_ID, MUTEX_ID);
}
println!("A is {}, Second can work now", A);
mutex_unlock(MUTEX_ID);
exit(0)
}
#[no_mangle]
pub fn main() -> i32 {
// create condvar & mutex
assert_eq!(condvar_create() as usize, CONDVAR_ID);
assert_eq!(mutex_blocking_create() as usize, MUTEX_ID);
// create threads
let threads = vec![
thread_create(first as usize, 0),
thread_create(second as usize, 0),
];
// wait for all threads to complete
for thread in threads.iter() {
waittid(*thread as usize);
}
println!("test_condvar passed!");
0
}

View File

@ -0,0 +1,64 @@
#![no_std]
#![no_main]
#[macro_use]
extern crate user_lib;
extern crate alloc;
use alloc::vec;
use user_lib::exit;
use user_lib::{
semaphore_create, semaphore_down, semaphore_up, mutex_blocking_create, mutex_lock, mutex_unlock,
};
use user_lib::{sleep, thread_create, waittid};
static mut A: usize = 0;
const SEM_ID: usize = 0;
const MUTEX_ID: usize = 0;
unsafe fn first() -> ! {
sleep(10);
println!("First work, Change A --> 1 and wakeup Second");
mutex_lock(MUTEX_ID);
A = 1;
semaphore_up(SEM_ID);
mutex_unlock(MUTEX_ID);
exit(0)
}
unsafe fn second() -> ! {
println!("Second want to continue,but need to wait A=1");
loop {
mutex_lock(MUTEX_ID);
if A == 0 {
println!("Second: A is {}", A);
mutex_unlock(MUTEX_ID);
semaphore_down(SEM_ID);
} else {
mutex_unlock(MUTEX_ID);
break;
}
}
println!("A is {}, Second can work now", A);
exit(0)
}
#[no_mangle]
pub fn main() -> i32 {
// create semaphore & mutex
assert_eq!(semaphore_create(0) as usize, SEM_ID);
assert_eq!(mutex_blocking_create() as usize, MUTEX_ID);
// create threads
let threads = vec![
thread_create(first as usize, 0),
thread_create(second as usize, 0),
];
// wait for all threads to complete
for thread in threads.iter() {
waittid(*thread as usize);
}
println!("test_condvar passed!");
0
}

67
user/src/bin/gui_rect.rs Normal file
View File

@ -0,0 +1,67 @@
#![no_std]
#![no_main]
extern crate alloc;
extern crate user_lib;
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};
const INIT_X: i32 = 80;
const INIT_Y: i32 = 400;
const RECT_SIZE: u32 = 150;
pub struct DrawingBoard {
disp: Display,
latest_pos: Point,
}
impl DrawingBoard {
pub fn new() -> Self {
Self {
disp: Display::new(Size::new(VIRTGPU_XRES, VIRTGPU_YRES)),
latest_pos: Point::new(INIT_X, INIT_Y),
}
}
fn paint(&mut self) {
Rectangle::with_center(self.latest_pos, Size::new(RECT_SIZE, RECT_SIZE))
.into_styled(PrimitiveStyle::with_stroke(Rgb888::RED, 10))
.draw(&mut self.disp)
.ok();
Circle::new(self.latest_pos + Point::new(-70, -300), 150)
.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();
}
fn unpaint(&mut self) {
Rectangle::with_center(self.latest_pos, Size::new(RECT_SIZE, RECT_SIZE))
.into_styled(PrimitiveStyle::with_stroke(Rgb888::BLACK, 10))
.draw(&mut self.disp)
.ok();
}
pub fn move_rect(&mut self, dx: i32, dy: i32) {
self.unpaint();
self.latest_pos.x += dx;
self.latest_pos.y += dy;
self.paint();
}
}
#[no_mangle]
pub fn main() -> i32 {
let mut board = DrawingBoard::new();
let _ = board.disp.clear(Rgb888::BLACK).unwrap();
for i in 0..5 {
board.latest_pos.x += (RECT_SIZE as i32 + 20);
//board.latest_pos.y += i;
board.paint();
}
0
}

View File

@ -0,0 +1,23 @@
#![no_std]
#![no_main]
extern crate user_lib;
use user_lib::{VIRTGPU_XRES, VIRTGPU_YRES, Display};
use embedded_graphics::prelude::Size;
#[no_mangle]
pub fn main() -> i32 {
let mut disp = Display::new(Size::new(VIRTGPU_XRES, VIRTGPU_YRES));
disp.paint_on_framebuffer(|fb| {
for y in 0..VIRTGPU_YRES as usize {
for x in 0..VIRTGPU_XRES as usize {
let idx = (y * VIRTGPU_XRES as usize + x) * 4;
fb[idx] = x as u8;
fb[idx + 1] = y as u8;
fb[idx + 2] = (x + y) as u8;
}
}
});
0
}

351
user/src/bin/gui_snake.rs Normal file
View File

@ -0,0 +1,351 @@
#![no_std]
#![no_main]
extern crate user_lib;
extern crate alloc;
use user_lib::console::getchar;
use user_lib::{Display, key_pressed, sleep, VIRTGPU_XRES, VIRTGPU_YRES};
use embedded_graphics::pixelcolor::*;
use embedded_graphics::prelude::{Drawable, Point, RgbColor, Size};
use embedded_graphics::primitives::Primitive;
use embedded_graphics::primitives::{PrimitiveStyle, Rectangle};
use embedded_graphics::Pixel;
use embedded_graphics::{draw_target::DrawTarget, prelude::OriginDimensions};
use oorandom; //random generator
struct Snake<T: PixelColor, const MAX_SIZE: usize> {
parts: [Pixel<T>; MAX_SIZE],
len: usize,
direction: Direction,
size_x: u32,
size_y: u32,
}
struct SnakeIntoIterator<'a, T: PixelColor, const MAX_SIZE: usize> {
snake: &'a Snake<T, MAX_SIZE>,
index: usize,
}
impl<'a, T: PixelColor, const MAX_SIZE: usize> IntoIterator for &'a Snake<T, MAX_SIZE> {
type Item = Pixel<T>;
type IntoIter = SnakeIntoIterator<'a, T, MAX_SIZE>;
fn into_iter(self) -> Self::IntoIter {
SnakeIntoIterator {
snake: self,
index: 0,
}
}
}
impl<'a, T: PixelColor, const MAX_SIZE: usize> Iterator for SnakeIntoIterator<'a, T, MAX_SIZE> {
type Item = Pixel<T>;
fn next(&mut self) -> Option<Self::Item> {
let cur = self.snake.parts[self.index];
if self.index < self.snake.len {
self.index += 1;
return Some(cur);
}
None
}
}
impl<T: PixelColor, const MAX_SIZE: usize> Snake<T, MAX_SIZE> {
fn new(color: T, size_x: u32, size_y: u32) -> Snake<T, MAX_SIZE> {
Snake {
parts: [Pixel::<T>(Point { x: 0, y: 0 }, color); MAX_SIZE],
len: 1,
direction: Direction::None,
size_x,
size_y,
}
}
fn set_direction(&mut self, direction: Direction) {
self.direction = direction;
}
fn contains(&self, this: Point) -> bool {
for part in self.into_iter() {
if part.0 == this {
return true;
};
}
false
}
fn grow(&mut self) {
if self.len < MAX_SIZE - 1 {
self.len += 1;
}
}
fn make_step(&mut self) {
let mut i = self.len;
while i > 0 {
self.parts[i] = self.parts[i - 1];
i -= 1;
}
match self.direction {
Direction::Left => {
if self.parts[0].0.x == 0 {
self.parts[0].0.x = (self.size_x - 1) as i32;
} else {
self.parts[0].0.x -= 1;
}
}
Direction::Right => {
if self.parts[0].0.x == (self.size_x - 1) as i32 {
self.parts[0].0.x = 0;
} else {
self.parts[0].0.x += 1;
}
}
Direction::Up => {
if self.parts[0].0.y == 0 {
self.parts[0].0.y = (self.size_y - 1) as i32;
} else {
self.parts[0].0.y -= 1;
}
}
Direction::Down => {
if self.parts[0].0.y == (self.size_y - 1) as i32 {
self.parts[0].0.y = 0;
} else {
self.parts[0].0.y += 1;
}
}
Direction::None => {}
}
}
}
struct Food<T: PixelColor> {
size_x: u32,
size_y: u32,
place: Pixel<T>,
rng: oorandom::Rand32,
}
impl<T: PixelColor> Food<T> {
pub fn new(color: T, size_x: u32, size_y: u32) -> Self {
let seed = 4;
let rng = oorandom::Rand32::new(seed);
Food {
size_x,
size_y,
place: Pixel(Point { x: 0, y: 0 }, color),
rng,
}
}
fn replace<'a, const MAX_SIZE: usize>(&mut self, iter_source: &Snake<T, MAX_SIZE>) {
let mut p: Point;
'outer: loop {
let random_number = self.rng.rand_u32();
let blocked_positions = iter_source.into_iter();
p = Point {
x: ((random_number >> 24) as u16 % self.size_x as u16).into(),
y: ((random_number >> 16) as u16 % self.size_y as u16).into(),
};
for blocked_position in blocked_positions {
if p == blocked_position.0 {
continue 'outer;
}
}
break;
}
self.place = Pixel::<T> {
0: p,
1: self.place.1,
}
}
fn get_pixel(&self) -> Pixel<T> {
self.place
}
}
#[derive(PartialEq, Debug, Clone, Copy)]
pub enum Direction {
Left,
Right,
Up,
Down,
None,
}
pub struct SnakeGame<const MAX_SNAKE_SIZE: usize, T: PixelColor> {
snake: Snake<T, MAX_SNAKE_SIZE>,
food: Food<T>,
food_age: u32,
food_lifetime: u32,
size_x: u32,
size_y: u32,
scale_x: u32,
scale_y: u32,
}
impl<const MAX_SIZE: usize, T: PixelColor> SnakeGame<MAX_SIZE, T> {
pub fn new(
size_x: u32,
size_y: u32,
scale_x: u32,
scale_y: u32,
snake_color: T,
food_color: T,
food_lifetime: u32,
) -> Self {
let snake = Snake::<T, MAX_SIZE>::new(snake_color, size_x / scale_x, size_y / scale_y);
let mut food = Food::<T>::new(food_color, size_x / scale_x, size_y / scale_y);
food.replace(&snake);
SnakeGame {
snake,
food,
food_age: 0,
food_lifetime,
size_x,
size_y,
scale_x,
scale_y,
}
}
pub fn set_direction(&mut self, direction: Direction) {
self.snake.set_direction(direction);
}
pub fn draw<D>(&mut self, target: &mut D) -> ()
where
D: DrawTarget<Color = T>,
{
self.snake.make_step();
let hit = self.snake.contains(self.food.get_pixel().0);
if hit {
self.snake.grow();
}
self.food_age += 1;
if self.food_age >= self.food_lifetime || hit {
self.food.replace(&self.snake);
self.food_age = 0;
}
let mut scaled_display = ScaledDisplay::<D> {
real_display: target,
size_x: self.size_x / self.scale_x,
size_y: self.size_y / self.scale_y,
scale_x: self.scale_x,
scale_y: self.scale_y,
};
for part in self.snake.into_iter() {
_ = part.draw(&mut scaled_display);
}
_ = self.food.get_pixel().draw(&mut scaled_display);
}
}
/// A dummy DrawTarget implementation that can magnify each pixel so the user code does not need to adapt for scaling things
struct ScaledDisplay<'a, T: DrawTarget> {
real_display: &'a mut T,
size_x: u32,
size_y: u32,
scale_x: u32,
scale_y: u32,
}
impl<'a, T: DrawTarget> DrawTarget for ScaledDisplay<'a, T> {
type Color = T::Color;
type Error = T::Error;
fn draw_iter<I>(&mut self, pixels: I) -> Result<(), Self::Error>
where
I: IntoIterator<Item = Pixel<Self::Color>>,
{
for pixel in pixels {
let style = PrimitiveStyle::with_fill(pixel.1);
Rectangle::new(
Point::new(
pixel.0.x * self.scale_x as i32,
pixel.0.y * self.scale_y as i32,
),
Size::new(self.scale_x as u32, self.scale_y as u32),
)
.into_styled(style)
.draw(self.real_display)?;
}
Ok(())
}
}
impl<'a, T: DrawTarget> OriginDimensions for ScaledDisplay<'a, T> {
fn size(&self) -> Size {
Size::new(self.size_x as u32, self.size_y as u32)
}
}
#[cfg(test)]
mod tests {
use crate::Snake;
use embedded_graphics::pixelcolor::*;
use embedded_graphics::prelude::*;
#[test]
fn snake_basic() {
let mut snake = Snake::<Rgb888, 20>::new(Rgb888::RED, 8, 8);
snake.set_direction(crate::Direction::Right);
assert_eq!(
Pixel::<Rgb888>(Point { x: 0, y: 0 }, Rgb888::RED),
snake.into_iter().next().unwrap()
);
snake.make_step();
assert_eq!(
Pixel::<Rgb888>(Point { x: 1, y: 0 }, Rgb888::RED),
snake.into_iter().nth(0).unwrap()
);
assert_eq!(
Pixel::<Rgb888>(Point { x: 0, y: 0 }, Rgb888::RED),
snake.into_iter().nth(1).unwrap()
);
snake.set_direction(crate::Direction::Down);
snake.make_step();
assert_eq!(
Pixel::<Rgb888>(Point { x: 1, y: 1 }, Rgb888::RED),
snake.into_iter().nth(0).unwrap()
);
assert_eq!(
Pixel::<Rgb888>(Point { x: 1, y: 0 }, Rgb888::RED),
snake.into_iter().nth(1).unwrap()
);
assert_eq!(
Pixel::<Rgb888>(Point { x: 0, y: 0 }, Rgb888::RED),
snake.into_iter().nth(2).unwrap()
);
assert_eq!(true, snake.contains(Point { x: 0, y: 0 }));
assert_eq!(true, snake.contains(Point { x: 1, y: 0 }));
assert_eq!(true, snake.contains(Point { x: 1, y: 1 }));
}
}
const LF: u8 = 0x0au8;
const CR: u8 = 0x0du8;
#[no_mangle]
pub fn main() -> i32 {
let mut disp = Display::new(Size::new(VIRTGPU_XRES, VIRTGPU_YRES));
let mut game = SnakeGame::<20, Rgb888>::new(1280, 800, 20, 20, Rgb888::RED, Rgb888::YELLOW, 50);
let _ = disp.clear(Rgb888::BLACK).unwrap();
loop {
if key_pressed() {
let c = getchar();
match c {
LF => break,
CR => break,
b'w' => game.set_direction(Direction::Up),
b's' => game.set_direction(Direction::Down),
b'a' => game.set_direction(Direction::Left),
b'd' => game.set_direction(Direction::Right),
_ => (),
}
}
let _ = disp.clear(Rgb888::BLACK).unwrap();
game.draw(&mut disp);
sleep(10);
}
0
}

125
user/src/bin/gui_uart.rs Normal file
View File

@ -0,0 +1,125 @@
#![no_std]
#![no_main]
#[macro_use]
extern crate user_lib;
extern crate alloc;
use user_lib::console::getchar;
use user_lib::{framebuffer, framebuffer_flush};
use embedded_graphics::pixelcolor::Rgb888;
use embedded_graphics::prelude::{Drawable, Point, RgbColor, Size};
use embedded_graphics::primitives::Primitive;
use embedded_graphics::primitives::{PrimitiveStyle, Rectangle};
use embedded_graphics::{draw_target::DrawTarget, prelude::OriginDimensions};
pub const VIRTGPU_XRES: usize = 1280;
pub const VIRTGPU_YRES: usize = 800;
pub const VIRTGPU_LEN: usize = VIRTGPU_XRES * VIRTGPU_YRES * 4;
const INIT_X: i32 = 640;
const INIT_Y: i32 = 400;
const RECT_SIZE: u32 = 40;
pub struct Display {
pub size: Size,
pub point: Point,
//pub fb: Arc<&'static mut [u8]>,
pub fb: &'static mut [u8],
}
impl Display {
pub fn new(size: Size, point: Point) -> Self {
let fb_ptr = framebuffer() as *mut u8;
println!(
"Hello world from user mode program! 0x{:X} , len {}",
fb_ptr as usize, VIRTGPU_LEN
);
let fb =
unsafe { core::slice::from_raw_parts_mut(fb_ptr as *mut u8, VIRTGPU_LEN as usize) };
Self { size, point, fb }
}
}
impl OriginDimensions for Display {
fn size(&self) -> Size {
self.size
}
}
impl DrawTarget for Display {
type Color = Rgb888;
type Error = core::convert::Infallible;
fn draw_iter<I>(&mut self, pixels: I) -> Result<(), Self::Error>
where
I: IntoIterator<Item = embedded_graphics::Pixel<Self::Color>>,
{
pixels.into_iter().for_each(|px| {
let idx = ((self.point.y + px.0.y) * VIRTGPU_XRES as i32 + self.point.x + px.0.x)
as usize
* 4;
if idx + 2 >= self.fb.len() {
return;
}
self.fb[idx] = px.1.b();
self.fb[idx + 1] = px.1.g();
self.fb[idx + 2] = px.1.r();
});
framebuffer_flush();
Ok(())
}
}
pub struct DrawingBoard {
disp: Display,
latest_pos: Point,
}
impl DrawingBoard {
pub fn new() -> Self {
Self {
disp: Display::new(Size::new(1280, 800), Point::new(0, 0)),
latest_pos: Point::new(INIT_X, INIT_Y),
}
}
fn paint(&mut self) {
Rectangle::with_center(self.latest_pos, Size::new(RECT_SIZE, RECT_SIZE))
.into_styled(PrimitiveStyle::with_stroke(Rgb888::WHITE, 1))
.draw(&mut self.disp)
.ok();
}
fn unpaint(&mut self) {
Rectangle::with_center(self.latest_pos, Size::new(RECT_SIZE, RECT_SIZE))
.into_styled(PrimitiveStyle::with_stroke(Rgb888::BLACK, 1))
.draw(&mut self.disp)
.ok();
}
pub fn move_rect(&mut self, dx: i32, dy: i32) {
self.unpaint();
self.latest_pos.x += dx;
self.latest_pos.y += dy;
self.paint();
}
}
const LF: u8 = 0x0au8;
const CR: u8 = 0x0du8;
#[no_mangle]
pub fn main() -> i32 {
// let fb_ptr = framebuffer() as *mut u8;
let mut board = DrawingBoard::new();
let _ = board.disp.clear(Rgb888::BLACK).unwrap();
for i in 0..20 {
let c=getchar();
if c == LF || c == CR {
break;
}
board.latest_pos.x += i;
board.latest_pos.y += i;
board.paint();
}
0
}

View File

@ -0,0 +1,25 @@
#![no_std]
#![no_main]
use user_lib::{event_get, DecodeType, Key, KeyType};
#[macro_use]
extern crate user_lib;
#[no_mangle]
pub fn main() -> i32 {
println!("Input device event test");
loop {
if let Some(event) = event_get() {
if let Some(decoder_type) = event.decode() {
println!("{:?}", decoder_type);
if let DecodeType::Key(key, keytype) = decoder_type {
if key == Key::Enter && keytype == KeyType::Press {
break;
}
}
}
}
}
0
}

View File

@ -14,7 +14,7 @@ use user_lib::{thread_create, waittid};
const SEM_MUTEX: usize = 0;
const SEM_EMPTY: usize = 1;
const SEM_EXISTED: usize = 2;
const SEM_AVAIL: usize = 2;
const BUFFER_SIZE: usize = 8;
static mut BUFFER: [usize; BUFFER_SIZE] = [0; BUFFER_SIZE];
static mut FRONT: usize = 0;
@ -27,20 +27,20 @@ unsafe fn producer(id: *const usize) -> ! {
for _ in 0..NUMBER_PER_PRODUCER {
semaphore_down(SEM_EMPTY);
semaphore_down(SEM_MUTEX);
BUFFER[FRONT] = id;
FRONT = (FRONT + 1) % BUFFER_SIZE;
BUFFER[TAIL] = id;
TAIL = (TAIL + 1) % BUFFER_SIZE;
semaphore_up(SEM_MUTEX);
semaphore_up(SEM_EXISTED);
semaphore_up(SEM_AVAIL);
}
exit(0)
}
unsafe fn consumer() -> ! {
for _ in 0..PRODUCER_COUNT * NUMBER_PER_PRODUCER {
semaphore_down(SEM_EXISTED);
semaphore_down(SEM_AVAIL);
semaphore_down(SEM_MUTEX);
print!("{} ", BUFFER[TAIL]);
TAIL = (TAIL + 1) % BUFFER_SIZE;
print!("{} ", BUFFER[FRONT]);
FRONT = (FRONT + 1) % BUFFER_SIZE;
semaphore_up(SEM_MUTEX);
semaphore_up(SEM_EMPTY);
}
@ -53,7 +53,7 @@ pub fn main() -> i32 {
// create semaphores
assert_eq!(semaphore_create(1) as usize, SEM_MUTEX);
assert_eq!(semaphore_create(BUFFER_SIZE) as usize, SEM_EMPTY);
assert_eq!(semaphore_create(0) as usize, SEM_EXISTED);
assert_eq!(semaphore_create(0) as usize, SEM_AVAIL);
// create threads
let ids: Vec<_> = (0..PRODUCER_COUNT).collect();
let mut threads = Vec::new();

View File

@ -10,7 +10,7 @@ extern crate core;
use alloc::vec::Vec;
use core::sync::atomic::{AtomicUsize, Ordering};
use user_lib::{exit, sleep, thread_create, waittid};
const N: usize = 3;
const N: usize = 1000;
static mut TURN: usize = 0;
static mut FLAG: [bool; 2] = [false; 2];
@ -29,27 +29,30 @@ fn critical_test_exit() {
}
fn peterson_enter_critical(id: usize, peer_id: usize) {
println!("Thread[{}] try enter", id);
// println!("Thread[{}] try enter", id);
vstore!(&FLAG[id], true);
vstore!(&TURN, peer_id);
memory_fence!();
while vload!(&FLAG[peer_id]) && vload!(&TURN) == peer_id {
println!("Thread[{}] enter fail", id);
// println!("Thread[{}] enter fail", id);
sleep(1);
println!("Thread[{}] retry enter", id);
// println!("Thread[{}] retry enter", id);
}
println!("Thread[{}] enter", id);
// println!("Thread[{}] enter", id);
}
fn peterson_exit_critical(id: usize) {
vstore!(&FLAG[id], false);
println!("Thread[{}] exit", id);
// println!("Thread[{}] exit", id);
}
pub fn thread_fn(id: usize) -> ! {
println!("Thread[{}] init.", id);
// println!("Thread[{}] init.", id);
let peer_id: usize = id ^ 1;
for _ in 0..N {
for iter in 0..N {
if iter % 10 == 0 {
println!("[{}] it={}", id, iter);
}
peterson_enter_critical(id, peer_id);
critical_test_enter();
for _ in 0..3 {
@ -74,4 +77,4 @@ pub fn main() -> i32 {
}
println!("main thread exited.");
0
}
}

View File

@ -1,42 +0,0 @@
#![no_std]
#![no_main]
#[macro_use]
extern crate user_lib;
extern crate alloc;
use alloc::vec::Vec;
use user_lib::{exit, get_time, thread_create, waittid};
static mut A: usize = 0;
const PER_THREAD: usize = 1000;
const THREAD_COUNT: usize = 16;
unsafe fn f() -> ! {
let mut t = 2usize;
for _ in 0..PER_THREAD {
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);
}
exit(t as i32)
}
#[no_mangle]
pub fn main() -> i32 {
let start = get_time();
let mut v = Vec::new();
for _ in 0..THREAD_COUNT {
v.push(thread_create(f as usize, 0) 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 }, PER_THREAD * THREAD_COUNT);
0
}

View File

@ -1,51 +0,0 @@
#![no_std]
#![no_main]
#[macro_use]
extern crate user_lib;
extern crate alloc;
use alloc::vec::Vec;
use core::sync::atomic::{AtomicBool, Ordering};
use user_lib::{exit, get_time, thread_create, waittid, yield_};
static mut A: usize = 0;
static OCCUPIED: AtomicBool = AtomicBool::new(false);
const PER_THREAD: usize = 1000;
const THREAD_COUNT: usize = 16;
unsafe fn f() -> ! {
let mut t = 2usize;
for _ in 0..PER_THREAD {
while OCCUPIED
.compare_exchange(false, true, Ordering::Relaxed, Ordering::Relaxed)
.is_err()
{
yield_();
}
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);
OCCUPIED.store(false, Ordering::Relaxed);
}
exit(t as i32)
}
#[no_mangle]
pub fn main() -> i32 {
let start = get_time();
let mut v = Vec::new();
for _ in 0..THREAD_COUNT {
v.push(thread_create(f as usize, 0) 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 }, PER_THREAD * THREAD_COUNT);
0
}

View File

@ -1,51 +0,0 @@
#![no_std]
#![no_main]
#[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: usize = 1000;
const THREAD_COUNT: usize = 16;
unsafe fn f() -> ! {
let mut t = 2usize;
for _ in 0..PER_THREAD {
while OCCUPIED {
yield_();
}
OCCUPIED = true;
// enter critical section
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);
// exit critical section
OCCUPIED = false;
}
exit(t as i32)
}
#[no_mangle]
pub fn main() -> i32 {
let start = get_time();
let mut v = Vec::new();
for _ in 0..THREAD_COUNT {
v.push(thread_create(f as usize, 0) 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 }, PER_THREAD * THREAD_COUNT);
0
}

View File

@ -1,46 +0,0 @@
#![no_std]
#![no_main]
#[macro_use]
extern crate user_lib;
extern crate alloc;
use alloc::vec::Vec;
use user_lib::{exit, get_time, thread_create, waittid};
use user_lib::{mutex_blocking_create, mutex_lock, mutex_unlock};
static mut A: usize = 0;
const PER_THREAD: usize = 1000;
const THREAD_COUNT: usize = 16;
unsafe fn f() -> ! {
let mut t = 2usize;
for _ in 0..PER_THREAD {
mutex_lock(0);
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);
mutex_unlock(0);
}
exit(t as i32)
}
#[no_mangle]
pub fn main() -> i32 {
let start = get_time();
assert_eq!(mutex_blocking_create(), 0);
let mut v = Vec::new();
for _ in 0..THREAD_COUNT {
v.push(thread_create(f as usize, 0) 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 }, PER_THREAD * THREAD_COUNT);
0
}

View File

@ -1,46 +0,0 @@
#![no_std]
#![no_main]
#[macro_use]
extern crate user_lib;
extern crate alloc;
use alloc::vec::Vec;
use user_lib::{exit, get_time, thread_create, waittid};
use user_lib::{mutex_create, mutex_lock, mutex_unlock};
static mut A: usize = 0;
const PER_THREAD: usize = 1000;
const THREAD_COUNT: usize = 16;
unsafe fn f() -> ! {
let mut t = 2usize;
for _ in 0..PER_THREAD {
mutex_lock(0);
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);
mutex_unlock(0);
}
exit(t as i32)
}
#[no_mangle]
pub fn main() -> i32 {
let start = get_time();
assert_eq!(mutex_create(), 0);
let mut v = Vec::new();
for _ in 0..THREAD_COUNT {
v.push(thread_create(f as usize, 0) 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 }, PER_THREAD * THREAD_COUNT);
0
}

View File

@ -0,0 +1,16 @@
#![no_std]
#![no_main]
#[macro_use]
extern crate user_lib;
use oorandom;
#[no_mangle]
pub fn main() -> i32 {
println!("random num program!");
let seed = 4;
let mut rng = oorandom::Rand32::new(seed);
println!("OORandom: Random number 32bit: {}", rng.rand_i32());
println!("OORandom: Random number range: {}", rng.rand_range(1..100));
0
}

View File

@ -27,19 +27,22 @@ static SUCC_TESTS: &[(&str, &str, &str, &str, i32)] = &[
("phil_din_mutex\0", "\0", "\0", "\0", 0),
("pipe_large_test\0", "\0", "\0", "\0", 0),
("pipetest\0", "\0", "\0", "\0", 0),
("race_adder_arg\0", "3\0", "\0", "\0", 0),
("race_adder_atomic\0", "\0", "\0", "\0", 0),
("race_adder_mutex_blocking\0", "\0", "\0", "\0", 0),
("race_adder_mutex_spin\0", "\0", "\0", "\0", 0),
("adder_peterson_spin\0", "\0", "\0", "\0", 0),
("adder_peterson_yield\0", "\0", "\0", "\0", 0),
("adder_mutex_blocking\0", "\0", "\0", "\0", 0),
("adder_mutex_spin\0", "\0", "\0", "\0", 0),
("run_pipe_test\0", "\0", "\0", "\0", 0),
("sleep_simple\0", "\0", "\0", "\0", 0),
("sleep\0", "\0", "\0", "\0", 0),
("sleep_simple\0", "\0", "\0", "\0", 0),
("sync_sem\0", "\0", "\0", "\0", 0),
("test_condvar\0", "\0", "\0", "\0", 0),
("condsync_sem\0", "\0", "\0", "\0", 0),
("condsync_condvar\0", "\0", "\0", "\0", 0),
("threads_arg\0", "\0", "\0", "\0", 0),
("threads\0", "\0", "\0", "\0", 0),
("yield\0", "\0", "\0", "\0", 0),
("barrier_fail\0", "\0", "\0", "\0", 0),
("barrier_condvar\0", "\0", "\0", "\0", 0),
];
static FAIL_TESTS: &[(&str, &str, &str, &str, i32)] = &[
@ -49,8 +52,9 @@ static FAIL_TESTS: &[(&str, &str, &str, &str, i32)] = &[
("priv_inst\0", "\0", "\0", "\0", -4),
("store_fault\0", "\0", "\0", "\0", -11),
("until_timeout\0", "\0", "\0", "\0", -6),
("race_adder\0", "\0", "\0", "\0", -6),
("huge_write_mt\0", "\0", "\0", "\0", -6),
("adder\0", "\0", "\0", "\0", -6),
("adder_simple_spin\0", "\0", "\0", "\0", -6),
("adder_simple_yield\0", "\0", "\0", "\0", -6),
];
use user_lib::{exec, fork, waitpid};

30
user/src/file.rs Normal file
View File

@ -0,0 +1,30 @@
use super::*;
bitflags! {
pub struct OpenFlags: u32 {
const RDONLY = 0;
const WRONLY = 1 << 0;
const RDWR = 1 << 1;
const CREATE = 1 << 9;
const TRUNC = 1 << 10;
}
}
pub fn dup(fd: usize) -> isize {
sys_dup(fd)
}
pub fn open(path: &str, flags: OpenFlags) -> isize {
sys_open(path, flags.bits)
}
pub fn close(fd: usize) -> isize {
sys_close(fd)
}
pub fn pipe(pipe_fd: &mut [usize]) -> isize {
sys_pipe(pipe_fd)
}
pub fn read(fd: usize, buf: &mut [u8]) -> isize {
sys_read(fd, buf)
}
pub fn write(fd: usize, buf: &[u8]) -> isize {
sys_write(fd, buf)
}

118
user/src/io.rs Normal file
View File

@ -0,0 +1,118 @@
use super::*;
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};
pub const VIRTGPU_XRES: u32 = 1280;
pub const VIRTGPU_YRES: u32 = 800;
pub const VIRTGPU_LEN: usize = (VIRTGPU_XRES * VIRTGPU_YRES * 4) as usize;
pub fn framebuffer() -> isize {
sys_framebuffer()
}
pub fn framebuffer_flush() -> isize {
sys_framebuffer_flush()
}
pub struct Display {
pub size: Size,
pub fb: &'static mut [u8],
}
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}
}
pub fn framebuffer(&mut self) -> &mut [u8] {
self.fb
}
pub fn paint_on_framebuffer(&mut self, p: impl FnOnce(&mut [u8]) -> ()) {
p(self.framebuffer());
framebuffer_flush();
}
}
impl OriginDimensions for Display {
fn size(&self) -> Size {
self.size
}
}
impl DrawTarget for Display {
type Color = Rgb888;
type Error = core::convert::Infallible;
fn draw_iter<I>(&mut self, pixels: I) -> Result<(), Self::Error>
where
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;
if idx + 2 >= self.fb.len() {
return;
}
self.fb[idx] = px.1.b();
self.fb[idx + 1] = px.1.g();
self.fb[idx + 2] = px.1.r();
});
framebuffer_flush();
Ok(())
}
}
pub fn event_get() -> Option<InputEvent> {
let raw_value = sys_event_get();
if raw_value == 0 {
None
} else {
Some((raw_value as u64).into())
}
}
pub fn key_pressed() -> bool {
if sys_key_pressed() == 1 {
true
} else {
false
}
}
#[repr(C)]
pub struct InputEvent {
pub event_type: u16,
pub code: u16,
pub value: u32,
}
impl From<u64> for InputEvent {
fn from(mut v: u64) -> Self {
let value = v as u32;
v >>= 32;
let code = v as u16;
v >>= 16;
let event_type = v as u16;
Self {
event_type,
code,
value,
}
}
}
impl InputEvent {
pub fn decode(&self) -> Option<DecodeType> {
Decoder::decode(
self.event_type as usize,
self.code as usize,
self.value as usize,
).ok()
}
}

View File

@ -8,6 +8,10 @@
pub mod console;
mod lang_items;
mod syscall;
mod file;
mod task;
mod sync;
mod io;
extern crate alloc;
#[macro_use]
@ -16,6 +20,10 @@ extern crate bitflags;
use alloc::vec::Vec;
use buddy_system_allocator::LockedHeap;
use syscall::*;
pub use file::*;
pub use task::*;
pub use sync::*;
pub use io::*;
const USER_HEAP_SIZE: usize = 32768;
@ -59,149 +67,6 @@ fn main(_argc: usize, _argv: &[&str]) -> i32 {
panic!("Cannot find main!");
}
bitflags! {
pub struct OpenFlags: u32 {
const RDONLY = 0;
const WRONLY = 1 << 0;
const RDWR = 1 << 1;
const CREATE = 1 << 9;
const TRUNC = 1 << 10;
}
}
pub fn dup(fd: usize) -> isize {
sys_dup(fd)
}
pub fn connect(ip: u32, sport: u16, dport: u16) -> isize {
sys_connect(ip, sport, dport)
}
pub fn open(path: &str, flags: OpenFlags) -> isize {
sys_open(path, flags.bits)
}
pub fn close(fd: usize) -> isize {
sys_close(fd)
}
pub fn pipe(pipe_fd: &mut [usize]) -> isize {
sys_pipe(pipe_fd)
}
pub fn read(fd: usize, buf: &mut [u8]) -> isize {
sys_read(fd, buf)
}
pub fn write(fd: usize, buf: &[u8]) -> isize {
sys_write(fd, buf)
}
pub fn exit(exit_code: i32) -> ! {
sys_exit(exit_code);
}
pub fn yield_() -> isize {
sys_yield()
}
pub fn get_time() -> isize {
sys_get_time()
}
pub fn getpid() -> isize {
sys_getpid()
}
pub fn fork() -> isize {
sys_fork()
}
pub fn exec(path: &str, args: &[*const u8]) -> isize {
sys_exec(path, args)
}
pub fn wait(exit_code: &mut i32) -> isize {
loop {
match sys_waitpid(-1, exit_code as *mut _) {
-2 => {
yield_();
}
// -1 or a real pid
exit_pid => return exit_pid,
}
}
}
pub fn waitpid(pid: usize, exit_code: &mut i32) -> isize {
loop {
match sys_waitpid(pid as isize, exit_code as *mut _) {
-2 => {
yield_();
}
// -1 or a real pid
exit_pid => return exit_pid,
}
}
}
pub fn waitpid_nb(pid: usize, exit_code: &mut i32) -> isize {
sys_waitpid(pid as isize, exit_code as *mut _)
}
bitflags! {
pub struct SignalFlags: i32 {
const SIGINT = 1 << 2;
const SIGILL = 1 << 4;
const SIGABRT = 1 << 6;
const SIGFPE = 1 << 8;
const SIGSEGV = 1 << 11;
}
}
pub fn kill(pid: usize, signal: i32) -> isize {
sys_kill(pid, signal)
}
pub fn sleep(sleep_ms: usize) {
sys_sleep(sleep_ms);
}
pub fn thread_create(entry: usize, arg: usize) -> isize {
sys_thread_create(entry, arg)
}
pub fn gettid() -> isize {
sys_gettid()
}
pub fn waittid(tid: usize) -> isize {
loop {
match sys_waittid(tid) {
-2 => {
yield_();
}
exit_code => return exit_code,
}
}
}
pub fn mutex_create() -> isize {
sys_mutex_create(false)
}
pub fn mutex_blocking_create() -> isize {
sys_mutex_create(true)
}
pub fn mutex_lock(mutex_id: usize) {
sys_mutex_lock(mutex_id);
}
pub fn mutex_unlock(mutex_id: usize) {
sys_mutex_unlock(mutex_id);
}
pub fn semaphore_create(res_count: usize) -> isize {
sys_semaphore_create(res_count)
}
pub fn semaphore_up(sem_id: usize) {
sys_semaphore_up(sem_id);
}
pub fn semaphore_down(sem_id: usize) {
sys_semaphore_down(sem_id);
}
pub fn condvar_create() -> isize {
sys_condvar_create(0)
}
pub fn condvar_signal(condvar_id: usize) {
sys_condvar_signal(condvar_id);
}
pub fn condvar_wait(condvar_id: usize, mutex_id: usize) {
sys_condvar_wait(condvar_id, mutex_id);
}
#[macro_export]
macro_rules! vstore {
($var_ref: expr, $value: expr) => {

32
user/src/sync.rs Normal file
View File

@ -0,0 +1,32 @@
use super::*;
pub fn mutex_create() -> isize {
sys_mutex_create(false)
}
pub fn mutex_blocking_create() -> isize {
sys_mutex_create(true)
}
pub fn mutex_lock(mutex_id: usize) {
sys_mutex_lock(mutex_id);
}
pub fn mutex_unlock(mutex_id: usize) {
sys_mutex_unlock(mutex_id);
}
pub fn semaphore_create(res_count: usize) -> isize {
sys_semaphore_create(res_count)
}
pub fn semaphore_up(sem_id: usize) {
sys_semaphore_up(sem_id);
}
pub fn semaphore_down(sem_id: usize) {
sys_semaphore_down(sem_id);
}
pub fn condvar_create() -> isize {
sys_condvar_create()
}
pub fn condvar_signal(condvar_id: usize) {
sys_condvar_signal(condvar_id);
}
pub fn condvar_wait(condvar_id: usize, mutex_id: usize) {
sys_condvar_wait(condvar_id, mutex_id);
}

View File

@ -26,6 +26,10 @@ const SYSCALL_SEMAPHORE_DOWN: usize = 1022;
const SYSCALL_CONDVAR_CREATE: usize = 1030;
const SYSCALL_CONDVAR_SIGNAL: usize = 1031;
const SYSCALL_CONDVAR_WAIT: usize = 1032;
const SYSCALL_FRAMEBUFFER: usize = 2000;
const SYSCALL_FRAMEBUFFER_FLUSH: usize = 2001;
const SYSCALL_EVENT_GET: usize = 3000;
const SYSCALL_KEY_PRESSED: usize = 3001;
fn syscall(id: usize, args: [usize; 3]) -> isize {
let mut ret: isize;
@ -148,8 +152,8 @@ pub fn sys_semaphore_down(sem_id: usize) -> isize {
syscall(SYSCALL_SEMAPHORE_DOWN, [sem_id, 0, 0])
}
pub fn sys_condvar_create(_arg: usize) -> isize {
syscall(SYSCALL_CONDVAR_CREATE, [_arg, 0, 0])
pub fn sys_condvar_create() -> isize {
syscall(SYSCALL_CONDVAR_CREATE, [0, 0, 0])
}
pub fn sys_condvar_signal(condvar_id: usize) -> isize {
@ -159,3 +163,20 @@ pub fn sys_condvar_signal(condvar_id: usize) -> isize {
pub fn sys_condvar_wait(condvar_id: usize, mutex_id: usize) -> isize {
syscall(SYSCALL_CONDVAR_WAIT, [condvar_id, mutex_id, 0])
}
pub fn sys_framebuffer() -> isize {
syscall(SYSCALL_FRAMEBUFFER, [0, 0, 0])
}
pub fn sys_framebuffer_flush() -> isize {
syscall(SYSCALL_FRAMEBUFFER_FLUSH, [0, 0, 0])
}
pub fn sys_event_get() -> isize {
syscall(SYSCALL_EVENT_GET, [0, 0, 0])
}
pub fn sys_key_pressed() -> isize {
syscall(SYSCALL_KEY_PRESSED, [0, 0, 0])
}

85
user/src/task.rs Normal file
View File

@ -0,0 +1,85 @@
use super::*;
pub fn exit(exit_code: i32) -> ! {
sys_exit(exit_code);
}
pub fn yield_() -> isize {
sys_yield()
}
pub fn get_time() -> isize {
sys_get_time()
}
pub fn getpid() -> isize {
sys_getpid()
}
pub fn fork() -> isize {
sys_fork()
}
pub fn exec(path: &str, args: &[*const u8]) -> isize {
sys_exec(path, args)
}
pub fn connect(raddr: u32, lport: u16, rport: u16) -> isize {
sys_connect(raddr, lport, rport)
}
pub fn wait(exit_code: &mut i32) -> isize {
loop {
match sys_waitpid(-1, exit_code as *mut _) {
-2 => {
yield_();
}
// -1 or a real pid
exit_pid => return exit_pid,
}
}
}
pub fn waitpid(pid: usize, exit_code: &mut i32) -> isize {
loop {
match sys_waitpid(pid as isize, exit_code as *mut _) {
-2 => {
yield_();
}
// -1 or a real pid
exit_pid => return exit_pid,
}
}
}
pub fn waitpid_nb(pid: usize, exit_code: &mut i32) -> isize {
sys_waitpid(pid as isize, exit_code as *mut _)
}
bitflags! {
pub struct SignalFlags: i32 {
const SIGINT = 1 << 2;
const SIGILL = 1 << 4;
const SIGABRT = 1 << 6;
const SIGFPE = 1 << 8;
const SIGSEGV = 1 << 11;
}
}
pub fn kill(pid: usize, signal: i32) -> isize {
sys_kill(pid, signal)
}
pub fn sleep(sleep_ms: usize) {
sys_sleep(sleep_ms);
}
pub fn thread_create(entry: usize, arg: usize) -> isize {
sys_thread_create(entry, arg)
}
pub fn gettid() -> isize {
sys_gettid()
}
pub fn waittid(tid: usize) -> isize {
loop {
match sys_waittid(tid) {
-2 => {
yield_();
}
exit_code => return exit_code,
}
}
}