Expand description
§BSB - A7: Application for StuBS
It is time to reap the rewards of your hard work during this semester. In this assignment, you implement an application of your choice. If possible, use several threads and synchronize them via semaphores.
PS: Now you can use every rust crate you want to use (https://lib.rs/no-std).
§Learning Objectives
- Using threads and semaphores
- Applying more comprehensive libraries
- Having fun
§Dynamic Memory Allocator
Until now, we have not used dynamic memory allocation et all. This might have been hard at some points, so now you are allowed to integrate an allocator into your RStuBS.
- Simple Bumping Pointer Allocator: https://lib.rs/crates/static-alloc
- Or just design your own
- With this, you can use all of Rust’s dynamic data structures (
alloc
)
§Minix File System
A filesystem would be great for an OS to load images or sounds. The C++ version implements Minix, but for Rust, we do not have this yet. Still, you can implement your own filesystem or just embed files directly:
- See
include_bytes!
§Graphics Mode
Yes ASCII art is great but have you tried turning RTX on?
RStuBS now has support for pixel graphics.
To use it, you have to enable the graphics
feature and use grub (cargo run-iso -F graphics
), as QEMU on its own does not correctly configure the screen.
You can control the resolution with SCREEN_WIDTH
and SCREEN_HEIGHT
.
- RStuBS parses Multiboot Framebuffer or VESA BIOS Extensions
- Supports 32-bit RGB888, 24bit RGB888, and 16-bit RGB565
The graphics::app contains an example of how to draw things (this function can be used as thread action).
let mut g = GUARD.enter();
g.scheduler.add(Thread::new(graphics::app));
The example uses the embedded-graphics crate, which has a good documentation. For images, we use tinytga.
For maximum VM performance, we would recommend:
cargo run-iso -r -F graphics -- --enable-kvm
§Floating Point Unit
On x86, floating-point operations require a bit of compiler and OS support. This is primarily caused by the CPU using extra registers for floating-point operations. These registers have to be saved and restored for context switches.
We focus on the x87 Floating Point Unit, as it has a small register file (108 bytes). This FPU is not entirely accurate and some operations (srqt, sin, cos) are approximated.
First, we have to tell the compiler to use the x87 FPU (in build/i686-rstubs-kernel.json
):
- "features": "-mmx,-sse,+soft-float",
+ "features": "-mmx,-sse",
Then, our thread registers have to be extended to include the FPU state:
#[repr(C)]
pub struct Registers {
pub ebx: u32,
pub esi: u32,
pub edi: u32,
pub ebp: u32,
pub esp: u32,
pub fpu: [u8; 108], // <- x87 FPU
}
Also, the context::launch()
and context::switch()
functions have to load and store this state using the finit
, frstor
, and fsave
instructions:
// In context launch
finit
// in context switch
// EAX and ECX contain pointers to the Register structs
// Store FPU context
fsave [eax+20]
// Load FPU context
frstor [ecx+20]
Now, you can use floating point operations in your threads. Unfortunately, some functions are still missing (sin/cos/sqrt…), even though the x87 FPU supports them. The Rust core library sadly does not implement them for this x87 FPU, only for newer FPUs (like SSE). But we can implement them ourselves:
pub fn sqrt(mut a: f32) -> f32 {
unsafe { asm!("fld dword ptr [{0}]", "fsqrt", "fst dword ptr [{0}]", in(reg) &mut a) };
a
}
pub fn sin(mut a: f32) -> f32 {
unsafe { asm!("fld dword ptr [{0}]", "fsin", "fst dword ptr [{0}]", in(reg) &mut a) };
a
}
pub fn cos(mut a: f32) -> f32 {
unsafe { asm!("fld dword ptr [{0}]", "fcos", "fst dword ptr [{0}]", in(reg) &mut a) };
a
}