diff --git a/Cargo.toml b/Cargo.toml index 9817d48..097d7d6 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -10,6 +10,7 @@ crate-type = ["staticlib"] [dependencies] bitflags = "*" spin = "*" +syscall = { path = "syscall/" } [dependencies.goblin] git = "https://github.com/m4b/goblin.git" diff --git a/Makefile b/Makefile index 3c9c5e0..6bd76aa 100644 --- a/Makefile +++ b/Makefile @@ -26,7 +26,9 @@ clean: cargo clean --manifest-path libstd/Cargo.toml cargo clean --manifest-path init/Cargo.toml cargo clean --manifest-path ion/Cargo.toml + cargo clean --manifest-path drivers/ps2d/Cargo.toml cargo clean --manifest-path drivers/pcid/Cargo.toml + cargo clean --manifest-path schemes/example/Cargo.toml rm -rf build FORCE: @@ -133,4 +135,12 @@ $(BUILD)/pcid: drivers/pcid/Cargo.toml drivers/pcid/src/** $(BUILD)/libstd.rlib $(CARGO) rustc --manifest-path $< $(CARGOFLAGS) -o $@ strip $@ -$(BUILD)/initfs.rs: $(BUILD)/init $(BUILD)/ion $(BUILD)/pcid +$(BUILD)/ps2d: drivers/ps2d/Cargo.toml drivers/ps2d/src/** $(BUILD)/libstd.rlib + $(CARGO) rustc --manifest-path $< $(CARGOFLAGS) -o $@ + strip $@ + +$(BUILD)/example: schemes/example/Cargo.toml schemes/example/src/** $(BUILD)/libstd.rlib + $(CARGO) rustc --manifest-path $< $(CARGOFLAGS) -o $@ + strip $@ + +$(BUILD)/initfs.rs: $(BUILD)/init $(BUILD)/ion $(BUILD)/pcid $(BUILD)/ps2d $(BUILD)/example diff --git a/arch/x86_64/Cargo.toml b/arch/x86_64/Cargo.toml index 65a644a..567b412 100644 --- a/arch/x86_64/Cargo.toml +++ b/arch/x86_64/Cargo.toml @@ -4,7 +4,8 @@ version = "0.1.0" [dependencies] bitflags = "*" -hole_list_allocator = { path = "../../alloc/hole_list_allocator"} +hole_list_allocator = { path = "../../alloc/hole_list_allocator" } +io = { path = "../../drivers/io" } ransid = { git = "https://github.com/redox-os/ransid.git", branch = "new_api" } spin = "*" diff --git a/arch/x86_64/src/acpi/mod.rs b/arch/x86_64/src/acpi/mod.rs index eccd165..f44bd07 100644 --- a/arch/x86_64/src/acpi/mod.rs +++ b/arch/x86_64/src/acpi/mod.rs @@ -59,11 +59,11 @@ pub fn init_sdt(sdt: &'static Sdt, active_table: &mut ActivePageTable) { if ap_local_apic.flags & 1 == 1 { // Allocate a stack // TODO: Allocate contiguous - let stack_start = allocate_frame().expect("no more frames in acpi stack_start").start_address().get(); + let stack_start = allocate_frame().expect("no more frames in acpi stack_start").start_address().get() + ::KERNEL_OFFSET; for _i in 0..62 { allocate_frame().expect("no more frames in acpi stack"); } - let stack_end = allocate_frame().expect("no more frames in acpi stack_end").start_address().get() + 4096; + let stack_end = allocate_frame().expect("no more frames in acpi stack_end").start_address().get() + 4096 + ::KERNEL_OFFSET; let ap_ready = TRAMPOLINE as *mut u64; let ap_cpu_id = unsafe { ap_ready.offset(1) }; diff --git a/arch/x86_64/src/context.rs b/arch/x86_64/src/context.rs index 004914d..946330a 100644 --- a/arch/x86_64/src/context.rs +++ b/arch/x86_64/src/context.rs @@ -43,6 +43,10 @@ impl Context { } } + pub fn get_page_table(&self) -> usize { + self.cr3 + } + pub fn set_page_table(&mut self, address: usize) { self.cr3 = address; } @@ -52,6 +56,7 @@ impl Context { } /// Switch to the next context by restoring its stack and registers + #[cold] #[inline(never)] #[naked] pub unsafe fn switch_to(&mut self, next: &mut Context) { @@ -94,7 +99,12 @@ impl Context { asm!("mov $0, rbp" : "=r"(self.rbp) : : "memory" : "intel", "volatile"); asm!("mov rbp, $0" : : "r"(next.rbp) : "memory" : "intel", "volatile"); - // Unset global lock, set inside of kernel - CONTEXT_SWITCH_LOCK.store(false, Ordering::SeqCst); + asm!("call context_switch_unlock" : : : "memory" : "intel", "volatile"); } } + +/// Unset global lock, set inside of kernel +#[no_mangle] +extern fn context_switch_unlock(){ + CONTEXT_SWITCH_LOCK.store(false, Ordering::SeqCst); +} diff --git a/arch/x86_64/src/device/mod.rs b/arch/x86_64/src/device/mod.rs index 02fe70d..c803264 100644 --- a/arch/x86_64/src/device/mod.rs +++ b/arch/x86_64/src/device/mod.rs @@ -1,11 +1,9 @@ use paging::ActivePageTable; pub mod display; -pub mod ps2; pub mod serial; pub unsafe fn init(active_table: &mut ActivePageTable){ serial::init(); display::init(active_table); - ps2::init(); } diff --git a/arch/x86_64/src/interrupt/irq.rs b/arch/x86_64/src/interrupt/irq.rs index a36d019..091a2e2 100644 --- a/arch/x86_64/src/interrupt/irq.rs +++ b/arch/x86_64/src/interrupt/irq.rs @@ -1,9 +1,9 @@ use spin::Mutex; use x86::io; -use device::ps2::{PS2_KEYBOARD, PS2_MOUSE}; use device::serial::{COM1, COM2}; +pub static ACKS: Mutex<[usize; 16]> = Mutex::new([0; 16]); pub static COUNTS: Mutex<[usize; 16]> = Mutex::new([0; 16]); #[inline(always)] @@ -17,6 +17,14 @@ unsafe fn slave_ack() { master_ack(); } +pub unsafe fn acknowledge(irq: usize) { + if irq >= 8 { + slave_ack(); + } else { + master_ack(); + } +} + interrupt!(pit, { COUNTS.lock()[0] += 1; master_ack(); @@ -24,10 +32,6 @@ interrupt!(pit, { interrupt!(keyboard, { COUNTS.lock()[1] += 1; - if let Some(ref mut keyboard) = *PS2_KEYBOARD.lock(){ - keyboard.on_irq(); - } - master_ack(); }); interrupt!(cascade, { @@ -84,10 +88,6 @@ interrupt!(pci3, { interrupt!(mouse, { COUNTS.lock()[12] += 1; - if let Some(ref mut mouse) = *PS2_MOUSE.lock() { - mouse.on_irq(); - } - slave_ack(); }); interrupt!(fpu, { diff --git a/arch/x86_64/src/io/mod.rs b/arch/x86_64/src/io/mod.rs deleted file mode 100644 index 86a1c34..0000000 --- a/arch/x86_64/src/io/mod.rs +++ /dev/null @@ -1,9 +0,0 @@ -/// I/O functions - -pub use self::io::*; -pub use self::mmio::*; -pub use self::pio::*; - -mod io; -mod mmio; -mod pio; diff --git a/arch/x86_64/src/lib.rs b/arch/x86_64/src/lib.rs index 870bf73..009f722 100644 --- a/arch/x86_64/src/lib.rs +++ b/arch/x86_64/src/lib.rs @@ -15,6 +15,7 @@ extern crate hole_list_allocator as allocator; #[macro_use] extern crate bitflags; +extern crate io; extern crate ransid; extern crate spin; pub extern crate x86; @@ -58,6 +59,9 @@ pub extern crate x86; /// Size of user stack pub const USER_STACK_SIZE: usize = 1024 * 1024; // 1 MB + /// Offset to user grants + pub const USER_GRANT_OFFSET: usize = USER_STACK_OFFSET + PML4_SIZE; + /// Offset to user temporary image (used when cloning) pub const USER_TMP_OFFSET: usize = USER_STACK_OFFSET + PML4_SIZE; @@ -67,14 +71,16 @@ pub extern crate x86; /// Offset to user temporary stack (used when cloning) pub const USER_TMP_STACK_OFFSET: usize = USER_TMP_HEAP_OFFSET + PML4_SIZE; + /// Offset to user temporary page for grants + pub const USER_TMP_GRANT_OFFSET: usize = USER_TMP_STACK_OFFSET + PML4_SIZE; + /// Print to console #[macro_export] macro_rules! print { ($($arg:tt)*) => ({ use core::fmt::Write; - let mut console = $crate::console::CONSOLE.lock(); - let _ = write!(console, $($arg)*); + let _ = write!($crate::console::CONSOLE.lock(), $($arg)*); }); } @@ -199,9 +205,6 @@ pub mod gdt; /// Interrupt descriptor table pub mod idt; -/// IO Handling -pub mod io; - /// Interrupt instructions pub mod interrupt; diff --git a/arch/x86_64/src/paging/mapper.rs b/arch/x86_64/src/paging/mapper.rs index 5b7665a..819efa9 100644 --- a/arch/x86_64/src/paging/mapper.rs +++ b/arch/x86_64/src/paging/mapper.rs @@ -93,6 +93,13 @@ impl Mapper { .and_then(|p1| p1[page.p1_index()].pointed_frame()) } + pub fn translate_page_flags(&self, page: Page) -> Option { + self.p4().next_table(page.p4_index()) + .and_then(|p3| p3.next_table(page.p3_index())) + .and_then(|p2| p2.next_table(page.p2_index())) + .and_then(|p1| Some(p1[page.p1_index()].flags())) + } + /// Translate a virtual address to a physical one pub fn translate(&self, virtual_address: VirtualAddress) -> Option { let offset = virtual_address.get() % PAGE_SIZE; diff --git a/arch/x86_64/src/paging/mod.rs b/arch/x86_64/src/paging/mod.rs index 4c3da06..5ebfe11 100644 --- a/arch/x86_64/src/paging/mod.rs +++ b/arch/x86_64/src/paging/mod.rs @@ -133,23 +133,23 @@ pub unsafe fn init(cpu_id: usize, stack_start: usize, stack_end: usize) -> (Acti } } - let mut remap = |start: usize, end: usize, flags: EntryFlags, offset: usize| { + let mut remap = |start: usize, end: usize, flags: EntryFlags| { if end > start { let start_frame = Frame::containing_address(PhysicalAddress::new(start)); let end_frame = Frame::containing_address(PhysicalAddress::new(end - 1)); for frame in Frame::range_inclusive(start_frame, end_frame) { - let page = Page::containing_address(VirtualAddress::new(frame.start_address().get() + offset)); + let page = Page::containing_address(VirtualAddress::new(frame.start_address().get() + ::KERNEL_OFFSET)); mapper.map_to(page, frame, flags); } } }; // Remap stack writable, no execute - remap(stack_start, stack_end, PRESENT | NO_EXECUTE | WRITABLE, 0); + remap(stack_start - ::KERNEL_OFFSET, stack_end - ::KERNEL_OFFSET, PRESENT | NO_EXECUTE | WRITABLE); // Remap a section with `flags` let mut remap_section = |start: &u8, end: &u8, flags: EntryFlags| { - remap(start as *const _ as usize - ::KERNEL_OFFSET, end as *const _ as usize - ::KERNEL_OFFSET, flags, ::KERNEL_OFFSET); + remap(start as *const _ as usize - ::KERNEL_OFFSET, end as *const _ as usize - ::KERNEL_OFFSET, flags); }; // Remap text read-only remap_section(& __text_start, & __text_end, PRESENT); @@ -211,19 +211,19 @@ pub unsafe fn init_ap(cpu_id: usize, stack_start: usize, stack_end: usize, kerne } } - let mut remap = |start: usize, end: usize, flags: EntryFlags, offset: usize| { + let mut remap = |start: usize, end: usize, flags: EntryFlags| { if end > start { let start_frame = Frame::containing_address(PhysicalAddress::new(start)); let end_frame = Frame::containing_address(PhysicalAddress::new(end - 1)); for frame in Frame::range_inclusive(start_frame, end_frame) { - let page = Page::containing_address(VirtualAddress::new(frame.start_address().get() + offset)); + let page = Page::containing_address(VirtualAddress::new(frame.start_address().get() + ::KERNEL_OFFSET)); mapper.map_to(page, frame, flags); } } }; // Remap stack writable, no execute - remap(stack_start, stack_end, PRESENT | NO_EXECUTE | WRITABLE, 0); + remap(stack_start - ::KERNEL_OFFSET, stack_end - ::KERNEL_OFFSET, PRESENT | NO_EXECUTE | WRITABLE); }); active_table.switch(new_table); @@ -328,6 +328,10 @@ impl InactivePageTable { InactivePageTable { p4_frame: frame } } + pub unsafe fn from_address(cr3: usize) -> InactivePageTable { + InactivePageTable { p4_frame: Frame::containing_address(PhysicalAddress::new(cr3)) } + } + pub unsafe fn address(&self) -> usize { self.p4_frame.start_address().get() } diff --git a/arch/x86_64/src/start.rs b/arch/x86_64/src/start.rs index c941a88..10f53c5 100644 --- a/arch/x86_64/src/start.rs +++ b/arch/x86_64/src/start.rs @@ -12,8 +12,8 @@ use externs::memset; use gdt; use idt; use interrupt; -use memory::{self, Frame}; -use paging::{self, entry, Page, PhysicalAddress, VirtualAddress}; +use memory; +use paging::{self, entry, Page, VirtualAddress}; /// Test of zero values in BSS. static BSS_TEST_ZERO: usize = 0; @@ -68,8 +68,8 @@ pub unsafe extern fn kstart() -> ! { memory::init(0, &__end as *const u8 as usize - ::KERNEL_OFFSET); // TODO: allocate a stack - let stack_start = 0x00080000; - let stack_end = 0x0009F000; + let stack_start = 0x00080000 + ::KERNEL_OFFSET; + let stack_end = 0x0009F000 + ::KERNEL_OFFSET; // Initialize paging let (mut active_table, tcb_offset) = paging::init(0, stack_start, stack_end); @@ -148,7 +148,7 @@ pub unsafe extern fn kstart_ap(cpu_id: usize, page_table: usize, stack_start: us let kernel_table = KERNEL_TABLE.load(Ordering::SeqCst); // Initialize paging - let (mut active_table, tcb_offset) = paging::init_ap(cpu_id, stack_start, stack_end, kernel_table); + let (active_table, tcb_offset) = paging::init_ap(cpu_id, stack_start, stack_end, kernel_table); // Set up GDT for AP gdt::init(tcb_offset, stack_end); diff --git a/bootloader/x86_64/startup-x86_64.asm b/bootloader/x86_64/startup-x86_64.asm index 9cb683b..48d7980 100644 --- a/bootloader/x86_64/startup-x86_64.asm +++ b/bootloader/x86_64/startup-x86_64.asm @@ -122,10 +122,11 @@ long_mode: mov gs, rax mov ss, rax - mov rsp, 0x0009F000 + mov rsp, 0xFFFFFF000009F000 ;rust init mov rax, [kernel_base + 0x18] + xchg bx, bx jmp rax long_mode_ap: diff --git a/drivers/io/Cargo.toml b/drivers/io/Cargo.toml new file mode 100644 index 0000000..b0ee40b --- /dev/null +++ b/drivers/io/Cargo.toml @@ -0,0 +1,3 @@ +[package] +name = "io" +version = "0.1.0" diff --git a/arch/x86_64/src/io/io.rs b/drivers/io/src/io.rs similarity index 100% rename from arch/x86_64/src/io/io.rs rename to drivers/io/src/io.rs diff --git a/drivers/io/src/lib.rs b/drivers/io/src/lib.rs new file mode 100644 index 0000000..22f8eb7 --- /dev/null +++ b/drivers/io/src/lib.rs @@ -0,0 +1,14 @@ +//! I/O functions + +#![feature(asm)] +#![feature(const_fn)] +#![feature(core_intrinsics)] +#![no_std] + +pub use self::io::*; +pub use self::mmio::*; +pub use self::pio::*; + +mod io; +mod mmio; +mod pio; diff --git a/arch/x86_64/src/io/mmio.rs b/drivers/io/src/mmio.rs similarity index 100% rename from arch/x86_64/src/io/mmio.rs rename to drivers/io/src/mmio.rs diff --git a/arch/x86_64/src/io/pio.rs b/drivers/io/src/pio.rs similarity index 53% rename from arch/x86_64/src/io/pio.rs rename to drivers/io/src/pio.rs index 562c1c1..91ae310 100644 --- a/arch/x86_64/src/io/pio.rs +++ b/drivers/io/src/pio.rs @@ -1,5 +1,4 @@ use core::marker::PhantomData; -use x86::io; use super::io::Io; @@ -27,13 +26,19 @@ impl Io for Pio { /// Read #[inline(always)] fn read(&self) -> u8 { - unsafe { io::inb(self.port) } + let value: u8; + unsafe { + asm!("in $0, $1" : "={al}"(value) : "{dx}"(self.port) : "memory" : "intel", "volatile"); + } + value } /// Write #[inline(always)] fn write(&mut self, value: u8) { - unsafe { io::outb(self.port, value) } + unsafe { + asm!("out $1, $0" : : "{al}"(value), "{dx}"(self.port) : "memory" : "intel", "volatile"); + } } } @@ -44,13 +49,19 @@ impl Io for Pio { /// Read #[inline(always)] fn read(&self) -> u16 { - unsafe { io::inw(self.port) } + let value: u16; + unsafe { + asm!("in $0, $1" : "={ax}"(value) : "{dx}"(self.port) : "memory" : "intel", "volatile"); + } + value } /// Write #[inline(always)] fn write(&mut self, value: u16) { - unsafe { io::outw(self.port, value) } + unsafe { + asm!("out $1, $0" : : "{ax}"(value), "{dx}"(self.port) : "memory" : "intel", "volatile"); + } } } @@ -61,12 +72,18 @@ impl Io for Pio { /// Read #[inline(always)] fn read(&self) -> u32 { - unsafe { io::inl(self.port) } + let value: u32; + unsafe { + asm!("in $0, $1" : "={eax}"(value) : "{dx}"(self.port) : "memory" : "intel", "volatile"); + } + value } /// Write #[inline(always)] fn write(&mut self, value: u32) { - unsafe { io::outl(self.port, value) } + unsafe { + asm!("out $1, $0" : : "{eax}"(value), "{dx}"(self.port) : "memory" : "intel", "volatile"); + } } } diff --git a/drivers/ps2d/Cargo.toml b/drivers/ps2d/Cargo.toml new file mode 100644 index 0000000..665e3c1 --- /dev/null +++ b/drivers/ps2d/Cargo.toml @@ -0,0 +1,9 @@ +[package] +name = "ps2d" +version = "0.1.0" + +[dependencies] +bitflags = "*" +io = { path = "../io/" } +spin = "*" +syscall = { path = "../../syscall/" } diff --git a/arch/x86_64/src/device/ps2.rs b/drivers/ps2d/src/controller.rs similarity index 59% rename from arch/x86_64/src/device/ps2.rs rename to drivers/ps2d/src/controller.rs index 8980086..e68d4f1 100644 --- a/arch/x86_64/src/device/ps2.rs +++ b/drivers/ps2d/src/controller.rs @@ -1,17 +1,5 @@ -use core::cmp; -use spin::Mutex; - use io::{Io, Pio, ReadOnly, WriteOnly}; -pub static PS2_KEYBOARD: Mutex> = Mutex::new(None); -pub static PS2_MOUSE: Mutex> = Mutex::new(None); - -pub unsafe fn init() { - let (keyboard, mouse) = Ps2::new().init(); - *PS2_KEYBOARD.lock() = keyboard; - *PS2_MOUSE.lock() = mouse; -} - bitflags! { flags StatusFlags: u8 { const OUTPUT_FULL = 1, @@ -85,114 +73,6 @@ enum MouseCommandData { SetSampleRate = 0xF3, } -bitflags! { - flags MousePacketFlags: u8 { - const LEFT_BUTTON = 1, - const RIGHT_BUTTON = 1 << 1, - const MIDDLE_BUTTON = 1 << 2, - const ALWAYS_ON = 1 << 3, - const X_SIGN = 1 << 4, - const Y_SIGN = 1 << 5, - const X_OVERFLOW = 1 << 6, - const Y_OVERFLOW = 1 << 7 - } -} - -pub struct Ps2Keyboard { - data: ReadOnly>, - key: [u8; 3], - key_i: usize, -} - -impl Ps2Keyboard { - fn new() -> Self { - Ps2Keyboard { - data: ReadOnly::new(Pio::new(0x60)), - key: [0; 3], - key_i: 0 - } - } - - pub fn on_irq(&mut self) { - let scancode = self.data.read(); - self.key[self.key_i] = scancode; - self.key_i += 1; - if self.key_i >= self.key.len() || scancode < 0xE0 { - println!("KEY: {:X} {:X} {:X}", self.key[0], self.key[1], self.key[2]); - - self.key = [0; 3]; - self.key_i = 0; - } - } -} - -pub struct Ps2Mouse { - data: ReadOnly>, - mouse: [u8; 4], - mouse_i: usize, - mouse_extra: bool, - mouse_x: usize, - mouse_y: usize -} - -impl Ps2Mouse { - fn new(mouse_extra: bool) -> Self { - Ps2Mouse { - data: ReadOnly::new(Pio::new(0x60)), - mouse: [0; 4], - mouse_i: 0, - mouse_extra: mouse_extra, - mouse_x: 0, - mouse_y: 0 - } - } - - pub fn on_irq(&mut self) { - self.mouse[self.mouse_i] = self.data.read(); - self.mouse_i += 1; - - let flags = MousePacketFlags::from_bits_truncate(self.mouse[0]); - if ! flags.contains(ALWAYS_ON) { - println!("MOUSE MISALIGN {:X}", self.mouse[0]); - - self.mouse = [0; 4]; - self.mouse_i = 0; - } else if self.mouse_i >= self.mouse.len() || (!self.mouse_extra && self.mouse_i >= 3) { - if ! flags.contains(X_OVERFLOW) && ! flags.contains(Y_OVERFLOW) { - let mut dx = self.mouse[1] as isize; - if flags.contains(X_SIGN) { - dx -= 0x100; - } - - let mut dy = self.mouse[2] as isize; - if flags.contains(Y_SIGN) { - dy -= 0x100; - } - - let _extra = if self.mouse_extra { - self.mouse[3] - } else { - 0 - }; - - //print!("MOUSE {:?}, {}, {}, {}\n", flags, dx, dy, extra); - - if let Some(ref mut display) = *super::display::DISPLAY.lock() { - self.mouse_x = cmp::max(0, cmp::min(display.width as isize - 1, self.mouse_x as isize + dx)) as usize; - self.mouse_y = cmp::max(0, cmp::min(display.height as isize - 1, self.mouse_y as isize - dy)) as usize; - let offset = self.mouse_y * display.width + self.mouse_x; - display.onscreen[offset as usize] = 0xFF0000; - } - } else { - println!("MOUSE OVERFLOW {:X} {:X} {:X} {:X}", self.mouse[0], self.mouse[1], self.mouse[2], self.mouse[3]); - } - - self.mouse = [0; 4]; - self.mouse_i = 0; - } - } -} - pub struct Ps2 { data: Pio, status: ReadOnly>, @@ -200,7 +80,7 @@ pub struct Ps2 { } impl Ps2 { - const fn new() -> Self { + pub fn new() -> Self { Ps2 { data: Pio::new(0x60), status: ReadOnly::new(Pio::new(0x64)), @@ -278,7 +158,7 @@ impl Ps2 { self.read() } - fn init(&mut self) -> (Option, Option) { + pub fn init(&mut self) -> bool { // Disable devices self.command(Command::DisableFirst); self.command(Command::DisableSecond); @@ -328,18 +208,6 @@ impl Ps2 { let mouse_id = self.read(); let mouse_extra = mouse_id == 3; - // Enable extra buttons, TODO - /* - if self.mouse_extra { - print!("SAMPLE 200 {:X}\n", self.mouse_command_data(MouseCommandData::SetSampleRate, 200)); - print!("SAMPLE 200 {:X}\n", self.mouse_command_data(MouseCommandData::SetSampleRate, 200)); - print!("SAMPLE 80 {:X}\n", self.mouse_command_data(MouseCommandData::SetSampleRate, 80)); - print!("GET ID {:X}\n", self.mouse_command(MouseCommand::GetDeviceId)); - let mouse_id = self.read(); - print!("MOUSE ID: {:X} == 0x04\n", mouse_id); - } - */ - // Set sample rate to maximum assert_eq!(self.mouse_command_data(MouseCommandData::SetSampleRate, 200), 0xFA); @@ -352,6 +220,7 @@ impl Ps2 { let mut config = self.config(); config.remove(FIRST_DISABLED); config.remove(SECOND_DISABLED); + config.insert(FIRST_TRANSLATE); config.insert(FIRST_INTERRUPT); config.insert(SECOND_INTERRUPT); self.set_config(config); @@ -359,6 +228,6 @@ impl Ps2 { self.flush_read(); - (Some(Ps2Keyboard::new()), Some(Ps2Mouse::new(mouse_extra))) + mouse_extra } } diff --git a/drivers/ps2d/src/keyboard.rs b/drivers/ps2d/src/keyboard.rs new file mode 100644 index 0000000..b0090a3 --- /dev/null +++ b/drivers/ps2d/src/keyboard.rs @@ -0,0 +1,34 @@ +use std::fs::File; +use std::io::{Read, Write}; +use std::mem; +use std::thread; + +use keymap; + +pub fn keyboard() { + let mut file = File::open("irq:1").expect("ps2d: failed to open irq:1"); + + loop { + let mut irqs = [0; 8]; + if file.read(&mut irqs).expect("ps2d: failed to read irq:1") >= mem::size_of::() { + let data: u8; + unsafe { + asm!("in al, dx" : "={al}"(data) : "{dx}"(0x60) : : "intel", "volatile"); + } + + let (scancode, pressed) = if data >= 0x80 { + (data - 0x80, false) + } else { + (data, true) + }; + + if pressed { + print!("{}", keymap::get_char(scancode)); + } + + file.write(&irqs).expect("ps2d: failed to write irq:1"); + } else { + thread::yield_now(); + } + } +} diff --git a/drivers/ps2d/src/keymap.rs b/drivers/ps2d/src/keymap.rs new file mode 100644 index 0000000..699e3ad --- /dev/null +++ b/drivers/ps2d/src/keymap.rs @@ -0,0 +1,68 @@ +static ENGLISH: [[char; 3]; 58] = [ + ['\0', '\0', '\0'], + ['\x1B', '\x1B', '\x1B'], + ['1', '!', '1'], + ['2', '@', '2'], + ['3', '#', '3'], + ['4', '$', '4'], + ['5', '%', '5'], + ['6', '^', '6'], + ['7', '&', '7'], + ['8', '*', '8'], + ['9', '(', '9'], + ['0', ')', '0'], + ['-', '_', '-'], + ['=', '+', '='], + ['\0', '\0', '\0'], + ['\t', '\t', '\t'], + ['q', 'Q', 'q'], + ['w', 'W', 'w'], + ['e', 'E', 'e'], + ['r', 'R', 'r'], + ['t', 'T', 't'], + ['y', 'Y', 'y'], + ['u', 'U', 'u'], + ['i', 'I', 'i'], + ['o', 'O', 'o'], + ['p', 'P', 'p'], + ['[', '{', '['], + [']', '}', ']'], + ['\n', '\n', '\n'], + ['\0', '\0', '\0'], + ['a', 'A', 'a'], + ['s', 'S', 's'], + ['d', 'D', 'd'], + ['f', 'F', 'f'], + ['g', 'G', 'g'], + ['h', 'H', 'h'], + ['j', 'J', 'j'], + ['k', 'K', 'k'], + ['l', 'L', 'l'], + [';', ':', ';'], + ['\'', '"', '\''], + ['`', '~', '`'], + ['\0', '\0', '\0'], + ['\\', '|', '\\'], + ['z', 'Z', 'z'], + ['x', 'X', 'x'], + ['c', 'C', 'c'], + ['v', 'V', 'v'], + ['b', 'B', 'b'], + ['n', 'N', 'n'], + ['m', 'M', 'm'], + [',', '<', ','], + ['.', '>', '.'], + ['/', '?', '/'], + ['\0', '\0', '\0'], + ['\0', '\0', '\0'], + ['\0', '\0', '\0'], + [' ', ' ', ' '] +]; + +pub fn get_char(scancode: u8) -> char { + if let Some(c) = ENGLISH.get(scancode as usize) { + c[0] + } else { + '\0' + } +} diff --git a/drivers/ps2d/src/main.rs b/drivers/ps2d/src/main.rs new file mode 100644 index 0000000..4a3888e --- /dev/null +++ b/drivers/ps2d/src/main.rs @@ -0,0 +1,42 @@ +#![feature(asm)] + +#[macro_use] +extern crate bitflags; +extern crate io; +extern crate syscall; + +use std::thread; + +use syscall::iopl; + +mod controller; +mod keyboard; +mod keymap; +mod mouse; + +fn main() { + unsafe { + iopl(3).expect("ps2d: failed to get I/O permission"); + asm!("cli" :::: "intel", "volatile"); + } + + let extra_packet = controller::Ps2::new().init(); + + thread::spawn(|| { + unsafe { + iopl(3).expect("ps2d: failed to get I/O permission"); + asm!("cli" :::: "intel", "volatile"); + } + + keyboard::keyboard(); + }); + + thread::spawn(move || { + unsafe { + iopl(3).expect("ps2d: failed to get I/O permission"); + asm!("cli" :::: "intel", "volatile"); + } + + mouse::mouse(extra_packet); + }); +} diff --git a/drivers/ps2d/src/mouse.rs b/drivers/ps2d/src/mouse.rs new file mode 100644 index 0000000..f273de9 --- /dev/null +++ b/drivers/ps2d/src/mouse.rs @@ -0,0 +1,73 @@ +use std::fs::File; +use std::io::{Read, Write}; +use std::mem; +use std::thread; + +bitflags! { + flags MousePacketFlags: u8 { + const LEFT_BUTTON = 1, + const RIGHT_BUTTON = 1 << 1, + const MIDDLE_BUTTON = 1 << 2, + const ALWAYS_ON = 1 << 3, + const X_SIGN = 1 << 4, + const Y_SIGN = 1 << 5, + const X_OVERFLOW = 1 << 6, + const Y_OVERFLOW = 1 << 7 + } +} + +pub fn mouse(extra_packet: bool) { + let mut file = File::open("irq:12").expect("ps2d: failed to open irq:12"); + + let mut packets = [0; 4]; + let mut packet_i = 0; + loop { + let mut irqs = [0; 8]; + if file.read(&mut irqs).expect("ps2d: failed to read irq:12") >= mem::size_of::() { + let data: u8; + unsafe { + asm!("in al, dx" : "={al}"(data) : "{dx}"(0x60) : : "intel", "volatile"); + } + + packets[packet_i] = data; + packet_i += 1; + + let flags = MousePacketFlags::from_bits_truncate(packets[0]); + if ! flags.contains(ALWAYS_ON) { + println!("MOUSE MISALIGN {:X}", packets[0]); + + packets = [0; 4]; + packet_i = 0; + } else if packet_i >= packets.len() || (!extra_packet && packet_i >= 3) { + if ! flags.contains(X_OVERFLOW) && ! flags.contains(Y_OVERFLOW) { + let mut dx = packets[1] as isize; + if flags.contains(X_SIGN) { + dx -= 0x100; + } + + let mut dy = packets[2] as isize; + if flags.contains(Y_SIGN) { + dy -= 0x100; + } + + let extra = if extra_packet { + packets[3] + } else { + 0 + }; + + print!("ps2d: IRQ {:?}, {}, {}, {}\n", flags, dx, dy, extra); + } else { + println!("ps2d: overflow {:X} {:X} {:X} {:X}", packets[0], packets[1], packets[2], packets[3]); + } + + packets = [0; 4]; + packet_i = 0; + } + + file.write(&irqs).expect("ps2d: failed to write irq:12"); + } else { + thread::yield_now(); + } + } +} diff --git a/kernel/context/context.rs b/kernel/context/context.rs index 4b4cc3a..73f31f4 100644 --- a/kernel/context/context.rs +++ b/kernel/context/context.rs @@ -5,7 +5,7 @@ use spin::Mutex; use arch; use super::file::File; -use super::memory::{Memory, SharedMemory}; +use super::memory::{Grant, Memory, SharedMemory}; #[derive(Copy, Clone, Debug, Eq, PartialEq)] pub enum Status { @@ -33,6 +33,8 @@ pub struct Context { pub heap: Option, /// User stack pub stack: Option, + /// User grants + pub grants: Arc>>, /// The current working directory pub cwd: Arc>>, /// The open files in the scheme @@ -51,6 +53,7 @@ impl Context { image: Vec::new(), heap: None, stack: None, + grants: Arc::new(Mutex::new(Vec::new())), cwd: Arc::new(Mutex::new(Vec::new())), files: Arc::new(Mutex::new(Vec::new())) } diff --git a/kernel/context/list.rs b/kernel/context/list.rs index 7e60e76..2ad5efb 100644 --- a/kernel/context/list.rs +++ b/kernel/context/list.rs @@ -1,15 +1,16 @@ +use alloc::arc::Arc; use collections::BTreeMap; use core::mem; use core::sync::atomic::Ordering; use spin::RwLock; use arch; -use syscall::{Result, Error}; +use syscall::error::{Result, Error, EAGAIN}; use super::context::Context; /// Context list type pub struct ContextList { - map: BTreeMap>, + map: BTreeMap>>, next_id: usize } @@ -23,21 +24,21 @@ impl ContextList { } /// Get the nth context. - pub fn get(&self, id: usize) -> Option<&RwLock> { + pub fn get(&self, id: usize) -> Option<&Arc>> { self.map.get(&id) } /// Get the current context. - pub fn current(&self) -> Option<&RwLock> { + pub fn current(&self) -> Option<&Arc>> { self.map.get(&super::CONTEXT_ID.load(Ordering::SeqCst)) } - pub fn iter(&self) -> ::collections::btree_map::Iter> { + pub fn iter(&self) -> ::collections::btree_map::Iter>> { self.map.iter() } /// Create a new context. - pub fn new_context(&mut self) -> Result<&RwLock> { + pub fn new_context(&mut self) -> Result<&Arc>> { if self.next_id >= super::CONTEXT_MAX_CONTEXTS { self.next_id = 1; } @@ -47,19 +48,19 @@ impl ContextList { } if self.next_id >= super::CONTEXT_MAX_CONTEXTS { - return Err(Error::TryAgain); + return Err(Error::new(EAGAIN)); } let id = self.next_id; self.next_id += 1; - assert!(self.map.insert(id, RwLock::new(Context::new(id))).is_none()); + assert!(self.map.insert(id, Arc::new(RwLock::new(Context::new(id)))).is_none()); Ok(self.map.get(&id).expect("Failed to insert new context. ID is out of bounds.")) } /// Spawn a context from a function. - pub fn spawn(&mut self, func: extern fn()) -> Result<&RwLock> { + pub fn spawn(&mut self, func: extern fn()) -> Result<&Arc>> { let context_lock = self.new_context()?; { let mut context = context_lock.write(); @@ -77,7 +78,7 @@ impl ContextList { Ok(context_lock) } - pub fn remove(&mut self, id: usize) -> Option> { + pub fn remove(&mut self, id: usize) -> Option>> { self.map.remove(&id) } } diff --git a/kernel/context/memory.rs b/kernel/context/memory.rs index 34e69a3..3121794 100644 --- a/kernel/context/memory.rs +++ b/kernel/context/memory.rs @@ -1,4 +1,5 @@ use alloc::arc::{Arc, Weak}; +use collections::VecDeque; use spin::Mutex; use arch::externs::memset; @@ -7,13 +8,67 @@ use arch::paging::entry::{self, EntryFlags}; use arch::paging::temporary_page::TemporaryPage; #[derive(Debug)] -pub struct Memory { +pub struct Grant { start: VirtualAddress, size: usize, flags: EntryFlags } -#[derive(Debug)] +impl Grant { + pub fn new(from: VirtualAddress, to: VirtualAddress, size: usize, flags: EntryFlags, new_table: &mut InactivePageTable, temporary_page: &mut TemporaryPage) -> Grant { + let mut active_table = unsafe { ActivePageTable::new() }; + + let mut frames = VecDeque::new(); + + let start_page = Page::containing_address(from); + let end_page = Page::containing_address(VirtualAddress::new(from.get() + size - 1)); + for page in Page::range_inclusive(start_page, end_page) { + let frame = active_table.translate_page(page).expect("grant references unmapped memory"); + frames.push_back(frame); + } + + active_table.with(new_table, temporary_page, |mapper| { + let start_page = Page::containing_address(to); + let end_page = Page::containing_address(VirtualAddress::new(to.get() + size - 1)); + for page in Page::range_inclusive(start_page, end_page) { + let frame = frames.pop_front().expect("grant did not find enough frames"); + mapper.map_to(page, frame, flags); + } + }); + + Grant { + start: to, + size: size, + flags: flags + } + } + + pub fn destroy(self, new_table: &mut InactivePageTable, temporary_page: &mut TemporaryPage) { + let mut active_table = unsafe { ActivePageTable::new() }; + + active_table.with(new_table, temporary_page, |mapper| { + let start_page = Page::containing_address(self.start); + let end_page = Page::containing_address(VirtualAddress::new(self.start.get() + self.size - 1)); + for page in Page::range_inclusive(start_page, end_page) { + mapper.unmap_return(page); + } + }); + } + + pub fn start_address(&self) -> VirtualAddress { + self.start + } + + pub fn size(&self) -> usize { + self.size + } + + pub fn flags(&self) -> EntryFlags { + self.flags + } +} + +#[derive(Clone, Debug)] pub enum SharedMemory { Owned(Arc>), Borrowed(Weak>) @@ -42,6 +97,13 @@ impl SharedMemory { } } +#[derive(Debug)] +pub struct Memory { + start: VirtualAddress, + size: usize, + flags: EntryFlags +} + impl Memory { pub fn new(start: VirtualAddress, size: usize, flags: EntryFlags, flush: bool, clear: bool) -> Self { let mut memory = Memory { diff --git a/kernel/context/switch.rs b/kernel/context/switch.rs index 49902d2..2e16727 100644 --- a/kernel/context/switch.rs +++ b/kernel/context/switch.rs @@ -54,6 +54,8 @@ pub unsafe fn switch() { return; } + //println!("Switch {} to {}", (&*from_ptr).id, (&*to_ptr).id); + (&mut *from_ptr).running = false; (&mut *to_ptr).running = true; if let Some(ref stack) = (*to_ptr).kstack { diff --git a/kernel/scheme/debug.rs b/kernel/scheme/debug.rs index 0dc6726..70459e7 100644 --- a/kernel/scheme/debug.rs +++ b/kernel/scheme/debug.rs @@ -3,8 +3,8 @@ use core::str; use spin::{Mutex, Once}; use context; -use syscall::Result; -use super::Scheme; +use syscall::error::*; +use syscall::scheme::Scheme; /// Input static INPUT: Once>> = Once::new(); @@ -23,18 +23,18 @@ pub extern fn debug_input(b: u8) { pub struct DebugScheme; impl Scheme for DebugScheme { - fn open(&mut self, _path: &[u8], _flags: usize) -> Result { + fn open(&self, _path: &[u8], _flags: usize) -> Result { Ok(0) } - fn dup(&mut self, _file: usize) -> Result { + fn dup(&self, _file: usize) -> Result { Ok(0) } /// Read the file `number` into the `buffer` /// /// Returns the number of bytes read - fn read(&mut self, _file: usize, buf: &mut [u8]) -> Result { + fn read(&self, _file: usize, buf: &mut [u8]) -> Result { loop { let mut i = 0; { @@ -56,18 +56,18 @@ impl Scheme for DebugScheme { /// Write the `buffer` to the `file` /// /// Returns the number of bytes written - fn write(&mut self, _file: usize, buffer: &[u8]) -> Result { + fn write(&self, _file: usize, buffer: &[u8]) -> Result { //TODO: Write bytes, do not convert to str print!("{}", unsafe { str::from_utf8_unchecked(buffer) }); Ok(buffer.len()) } - fn fsync(&mut self, file: usize) -> Result<()> { - Ok(()) + fn fsync(&self, _file: usize) -> Result { + Ok(0) } /// Close the file `number` - fn close(&mut self, _file: usize) -> Result<()> { - Ok(()) + fn close(&self, _file: usize) -> Result { + Ok(0) } } diff --git a/kernel/scheme/env.rs b/kernel/scheme/env.rs index a04142f..3f3f1f5 100644 --- a/kernel/scheme/env.rs +++ b/kernel/scheme/env.rs @@ -1,7 +1,11 @@ use collections::BTreeMap; +use core::cmp; +use core::sync::atomic::{AtomicUsize, Ordering}; +use spin::RwLock; -use syscall::{Error, Result}; -use super::Scheme; +use syscall::error::*; +use syscall::flag::{SEEK_SET, SEEK_CUR, SEEK_END}; +use syscall::scheme::Scheme; struct Handle { data: &'static [u8], @@ -9,9 +13,9 @@ struct Handle { } pub struct EnvScheme { - next_id: usize, + next_id: AtomicUsize, files: BTreeMap<&'static [u8], &'static [u8]>, - handles: BTreeMap + handles: RwLock> } impl EnvScheme { @@ -24,20 +28,19 @@ impl EnvScheme { files.insert(b"LINES", b"30"); EnvScheme { - next_id: 0, + next_id: AtomicUsize::new(0), files: files, - handles: BTreeMap::new() + handles: RwLock::new(BTreeMap::new()) } } } impl Scheme for EnvScheme { - fn open(&mut self, path: &[u8], _flags: usize) -> Result { - let data = self.files.get(path).ok_or(Error::NoEntry)?; + fn open(&self, path: &[u8], _flags: usize) -> Result { + let data = self.files.get(path).ok_or(Error::new(ENOENT))?; - let id = self.next_id; - self.next_id += 1; - self.handles.insert(id, Handle { + let id = self.next_id.fetch_add(1, Ordering::SeqCst); + self.handles.write().insert(id, Handle { data: data, seek: 0 }); @@ -45,15 +48,15 @@ impl Scheme for EnvScheme { Ok(id) } - fn dup(&mut self, file: usize) -> Result { + fn dup(&self, file: usize) -> Result { let (data, seek) = { - let handle = self.handles.get(&file).ok_or(Error::BadFile)?; + let handles = self.handles.read(); + let handle = handles.get(&file).ok_or(Error::new(EBADF))?; (handle.data, handle.seek) }; - let id = self.next_id; - self.next_id += 1; - self.handles.insert(id, Handle { + let id = self.next_id.fetch_add(1, Ordering::SeqCst); + self.handles.write().insert(id, Handle { data: data, seek: seek }); @@ -61,8 +64,9 @@ impl Scheme for EnvScheme { Ok(id) } - fn read(&mut self, file: usize, buffer: &mut [u8]) -> Result { - let mut handle = self.handles.get_mut(&file).ok_or(Error::BadFile)?; + fn read(&self, file: usize, buffer: &mut [u8]) -> Result { + let mut handles = self.handles.write(); + let mut handle = handles.get_mut(&file).ok_or(Error::new(EBADF))?; let mut i = 0; while i < buffer.len() && handle.seek < handle.data.len() { @@ -74,15 +78,25 @@ impl Scheme for EnvScheme { Ok(i) } - fn write(&mut self, _file: usize, _buffer: &[u8]) -> Result { - Err(Error::NotPermitted) + fn seek(&self, id: usize, pos: usize, whence: usize) -> Result { + let mut handles = self.handles.write(); + let mut handle = handles.get_mut(&id).ok_or(Error::new(EBADF))?; + + handle.seek = match whence { + SEEK_SET => cmp::min(handle.data.len(), pos), + SEEK_CUR => cmp::max(0, cmp::min(handle.data.len() as isize, handle.seek as isize + pos as isize)) as usize, + SEEK_END => cmp::max(0, cmp::min(handle.data.len() as isize, handle.data.len() as isize + pos as isize)) as usize, + _ => return Err(Error::new(EINVAL)) + }; + + Ok(handle.seek) } - fn fsync(&mut self, file: usize) -> Result<()> { - Ok(()) + fn fsync(&self, _file: usize) -> Result { + Ok(0) } - fn close(&mut self, file: usize) -> Result<()> { - self.handles.remove(&file).ok_or(Error::BadFile).and(Ok(())) + fn close(&self, file: usize) -> Result { + self.handles.write().remove(&file).ok_or(Error::new(EBADF)).and(Ok(0)) } } diff --git a/kernel/scheme/initfs.rs b/kernel/scheme/initfs.rs index 0b15bd2..84df203 100644 --- a/kernel/scheme/initfs.rs +++ b/kernel/scheme/initfs.rs @@ -1,7 +1,11 @@ use collections::BTreeMap; +use core::cmp; +use core::sync::atomic::{AtomicUsize, Ordering}; +use spin::RwLock; -use syscall::{Error, Result}; -use super::Scheme; +use syscall::error::*; +use syscall::flag::{SEEK_SET, SEEK_CUR, SEEK_END}; +use syscall::scheme::Scheme; struct Handle { data: &'static [u8], @@ -9,9 +13,9 @@ struct Handle { } pub struct InitFsScheme { - next_id: usize, + next_id: AtomicUsize, files: BTreeMap<&'static [u8], &'static [u8]>, - handles: BTreeMap + handles: RwLock> } impl InitFsScheme { @@ -21,23 +25,24 @@ impl InitFsScheme { files.insert(b"bin/init", include_bytes!("../../build/userspace/init")); files.insert(b"bin/ion", include_bytes!("../../build/userspace/ion")); files.insert(b"bin/pcid", include_bytes!("../../build/userspace/pcid")); - files.insert(b"etc/init.rc", b"echo testing\ninitfs:bin/pcid\ninitfs:bin/ion"); + files.insert(b"bin/ps2d", include_bytes!("../../build/userspace/ps2d")); + files.insert(b"bin/example", include_bytes!("../../build/userspace/example")); + files.insert(b"etc/init.rc", b"initfs:bin/pcid\ninitfs:bin/ps2d\ninitfs:bin/example\ninitfs:bin/ion"); InitFsScheme { - next_id: 0, + next_id: AtomicUsize::new(0), files: files, - handles: BTreeMap::new() + handles: RwLock::new(BTreeMap::new()) } } } impl Scheme for InitFsScheme { - fn open(&mut self, path: &[u8], _flags: usize) -> Result { - let data = self.files.get(path).ok_or(Error::NoEntry)?; + fn open(&self, path: &[u8], _flags: usize) -> Result { + let data = self.files.get(path).ok_or(Error::new(ENOENT))?; - let id = self.next_id; - self.next_id += 1; - self.handles.insert(id, Handle { + let id = self.next_id.fetch_add(1, Ordering::SeqCst); + self.handles.write().insert(id, Handle { data: data, seek: 0 }); @@ -45,28 +50,29 @@ impl Scheme for InitFsScheme { Ok(id) } - fn dup(&mut self, file: usize) -> Result { + fn dup(&self, id: usize) -> Result { let (data, seek) = { - let handle = self.handles.get(&file).ok_or(Error::BadFile)?; + let handles = self.handles.read(); + let handle = handles.get(&id).ok_or(Error::new(EBADF))?; (handle.data, handle.seek) }; - let id = self.next_id; - self.next_id += 1; - self.handles.insert(id, Handle { + let new_id = self.next_id.fetch_add(1, Ordering::SeqCst); + self.handles.write().insert(new_id, Handle { data: data, seek: seek }); - Ok(id) + Ok(new_id) } - fn read(&mut self, file: usize, buffer: &mut [u8]) -> Result { - let mut handle = self.handles.get_mut(&file).ok_or(Error::BadFile)?; + fn read(&self, id: usize, buf: &mut [u8]) -> Result { + let mut handles = self.handles.write(); + let mut handle = handles.get_mut(&id).ok_or(Error::new(EBADF))?; let mut i = 0; - while i < buffer.len() && handle.seek < handle.data.len() { - buffer[i] = handle.data[handle.seek]; + while i < buf.len() && handle.seek < handle.data.len() { + buf[i] = handle.data[handle.seek]; i += 1; handle.seek += 1; } @@ -74,15 +80,25 @@ impl Scheme for InitFsScheme { Ok(i) } - fn write(&mut self, _file: usize, _buffer: &[u8]) -> Result { - Err(Error::NotPermitted) + fn seek(&self, id: usize, pos: usize, whence: usize) -> Result { + let mut handles = self.handles.write(); + let mut handle = handles.get_mut(&id).ok_or(Error::new(EBADF))?; + + handle.seek = match whence { + SEEK_SET => cmp::min(handle.data.len(), pos), + SEEK_CUR => cmp::max(0, cmp::min(handle.data.len() as isize, handle.seek as isize + pos as isize)) as usize, + SEEK_END => cmp::max(0, cmp::min(handle.data.len() as isize, handle.data.len() as isize + pos as isize)) as usize, + _ => return Err(Error::new(EINVAL)) + }; + + Ok(handle.seek) } - fn fsync(&mut self, file: usize) -> Result<()> { - Ok(()) + fn fsync(&self, _id: usize) -> Result { + Ok(0) } - fn close(&mut self, file: usize) -> Result<()> { - self.handles.remove(&file).ok_or(Error::BadFile).and(Ok(())) + fn close(&self, id: usize) -> Result { + self.handles.write().remove(&id).ok_or(Error::new(EBADF)).and(Ok(0)) } } diff --git a/kernel/scheme/irq.rs b/kernel/scheme/irq.rs index 9d7d42d..7ec202a 100644 --- a/kernel/scheme/irq.rs +++ b/kernel/scheme/irq.rs @@ -1,57 +1,68 @@ use core::{mem, str}; -use arch::interrupt::irq::COUNTS; -use context; -use syscall::{Error, Result}; -use super::Scheme; +use arch::interrupt::irq::{ACKS, COUNTS, acknowledge}; +use syscall::error::*; +use syscall::scheme::Scheme; pub struct IrqScheme; impl Scheme for IrqScheme { - fn open(&mut self, path: &[u8], _flags: usize) -> Result { - let path_str = str::from_utf8(path).or(Err(Error::NoEntry))?; - let id = path_str.parse::().or(Err(Error::NoEntry))?; + fn open(&self, path: &[u8], _flags: usize) -> Result { + let path_str = str::from_utf8(path).or(Err(Error::new(ENOENT)))?; + + let id = path_str.parse::().or(Err(Error::new(ENOENT)))?; + if id < COUNTS.lock().len() { Ok(id) } else { - Err(Error::NoEntry) + Err(Error::new(ENOENT)) } } - fn dup(&mut self, file: usize) -> Result { + fn dup(&self, file: usize) -> Result { Ok(file) } - fn read(&mut self, file: usize, buffer: &mut [u8]) -> Result { + fn read(&self, file: usize, buffer: &mut [u8]) -> Result { // Ensures that the length of the buffer is larger than the size of a usize if buffer.len() >= mem::size_of::() { + let ack = ACKS.lock()[file]; let current = COUNTS.lock()[file]; - loop { - let next = COUNTS.lock()[file]; - if next != current { - // Safe if the length of the buffer is larger than the size of a usize - assert!(buffer.len() >= mem::size_of::()); - unsafe { *(buffer.as_mut_ptr() as *mut usize) = next }; - return Ok(mem::size_of::()); - } else { - // Safe if all locks have been dropped - unsafe { context::switch(); } - } + if ack != current { + // Safe if the length of the buffer is larger than the size of a usize + assert!(buffer.len() >= mem::size_of::()); + unsafe { *(buffer.as_mut_ptr() as *mut usize) = current; } + Ok(mem::size_of::()) + } else { + Ok(0) } } else { - Err(Error::InvalidValue) + Err(Error::new(EINVAL)) } } - fn write(&mut self, _file: usize, _buffer: &[u8]) -> Result { - Err(Error::NotPermitted) + fn write(&self, file: usize, buffer: &[u8]) -> Result { + if buffer.len() >= mem::size_of::() { + assert!(buffer.len() >= mem::size_of::()); + let ack = unsafe { *(buffer.as_ptr() as *const usize) }; + let current = COUNTS.lock()[file]; + if ack == current { + ACKS.lock()[file] = ack; + unsafe { acknowledge(file); } + Ok(mem::size_of::()) + } else { + Ok(0) + } + } else { + Err(Error::new(EINVAL)) + } } - fn fsync(&mut self, file: usize) -> Result<()> { - Ok(()) + fn fsync(&self, _file: usize) -> Result { + Ok(0) } - fn close(&mut self, file: usize) -> Result<()> { - Ok(()) + fn close(&self, _file: usize) -> Result { + Ok(0) } } diff --git a/kernel/scheme/mod.rs b/kernel/scheme/mod.rs index 6ca5c13..4d0580a 100644 --- a/kernel/scheme/mod.rs +++ b/kernel/scheme/mod.rs @@ -11,14 +11,16 @@ use alloc::boxed::Box; use collections::BTreeMap; -use spin::{Once, Mutex, RwLock, RwLockReadGuard, RwLockWriteGuard}; +use spin::{Once, RwLock, RwLockReadGuard, RwLockWriteGuard}; -use syscall::{Error, Result}; +use syscall::error::*; +use syscall::scheme::Scheme; use self::debug::DebugScheme; use self::env::EnvScheme; use self::initfs::InitFsScheme; use self::irq::IrqScheme; +use self::root::RootScheme; /// Debug scheme pub mod debug; @@ -32,12 +34,18 @@ pub mod initfs; /// IRQ handling pub mod irq; +/// Root scheme +pub mod root; + +/// Userspace schemes +pub mod user; + /// Limit on number of schemes pub const SCHEME_MAX_SCHEMES: usize = 65536; /// Scheme list type pub struct SchemeList { - map: BTreeMap>>>, + map: BTreeMap>>, names: BTreeMap, usize>, next_id: usize } @@ -53,11 +61,11 @@ impl SchemeList { } /// Get the nth scheme. - pub fn get(&self, id: usize) -> Option<&Arc>>> { + pub fn get(&self, id: usize) -> Option<&Arc>> { self.map.get(&id) } - pub fn get_name(&self, name: &[u8]) -> Option<(usize, &Arc>>)> { + pub fn get_name(&self, name: &[u8]) -> Option<(usize, &Arc>)> { if let Some(&id) = self.names.get(name) { self.get(id).map(|scheme| (id, scheme)) } else { @@ -66,9 +74,9 @@ impl SchemeList { } /// Create a new scheme. - pub fn insert(&mut self, name: Box<[u8]>, scheme: Arc>>) -> Result<&Arc>>> { + pub fn insert(&mut self, name: Box<[u8]>, scheme: Arc>) -> Result<&Arc>> { if self.names.contains_key(&name) { - return Err(Error::FileExists); + return Err(Error::new(EEXIST)); } if self.next_id >= SCHEME_MAX_SCHEMES { @@ -80,7 +88,7 @@ impl SchemeList { } if self.next_id >= SCHEME_MAX_SCHEMES { - return Err(Error::TryAgain); + return Err(Error::new(EAGAIN)); } let id = self.next_id; @@ -99,10 +107,11 @@ static SCHEMES: Once> = Once::new(); /// Initialize schemes, called if needed fn init_schemes() -> RwLock { let mut list: SchemeList = SchemeList::new(); - list.insert(Box::new(*b"debug"), Arc::new(Mutex::new(Box::new(DebugScheme)))).expect("failed to insert debug: scheme"); - list.insert(Box::new(*b"env"), Arc::new(Mutex::new(Box::new(EnvScheme::new())))).expect("failed to insert env: scheme"); - list.insert(Box::new(*b"initfs"), Arc::new(Mutex::new(Box::new(InitFsScheme::new())))).expect("failed to insert initfs: scheme"); - list.insert(Box::new(*b"irq"), Arc::new(Mutex::new(Box::new(IrqScheme)))).expect("failed to insert irq: scheme"); + list.insert(Box::new(*b""), Arc::new(Box::new(RootScheme::new()))).expect("failed to insert root scheme"); + list.insert(Box::new(*b"debug"), Arc::new(Box::new(DebugScheme))).expect("failed to insert debug scheme"); + list.insert(Box::new(*b"env"), Arc::new(Box::new(EnvScheme::new()))).expect("failed to insert env scheme"); + list.insert(Box::new(*b"initfs"), Arc::new(Box::new(InitFsScheme::new()))).expect("failed to insert initfs scheme"); + list.insert(Box::new(*b"irq"), Arc::new(Box::new(IrqScheme))).expect("failed to insert irq scheme"); RwLock::new(list) } @@ -115,32 +124,3 @@ pub fn schemes() -> RwLockReadGuard<'static, SchemeList> { pub fn schemes_mut() -> RwLockWriteGuard<'static, SchemeList> { SCHEMES.call_once(init_schemes).write() } - -/// A scheme trait, implemented by a scheme handler -pub trait Scheme { - /// Open the file at `path` with `flags`. - /// - /// Returns a file descriptor or an error - fn open(&mut self, path: &[u8], flags: usize) -> Result; - - /// Duplicate an open file descriptor - /// - /// Returns a file descriptor or an error - fn dup(&mut self, file: usize) -> Result; - - /// Read from some file descriptor into the `buffer` - /// - /// Returns the number of bytes read - fn read(&mut self, file: usize, buffer: &mut [u8]) -> Result; - - /// Write the `buffer` to the file descriptor - /// - /// Returns the number of bytes written - fn write(&mut self, file: usize, buffer: &[u8]) -> Result; - - /// Sync the file descriptor - fn fsync(&mut self, file: usize) -> Result<()>; - - /// Close the file descriptor - fn close(&mut self, file: usize) -> Result<()>; -} diff --git a/kernel/scheme/root.rs b/kernel/scheme/root.rs new file mode 100644 index 0000000..a2e0060 --- /dev/null +++ b/kernel/scheme/root.rs @@ -0,0 +1,91 @@ +use alloc::arc::Arc; +use alloc::boxed::Box; +use collections::BTreeMap; +use core::sync::atomic::{AtomicUsize, Ordering}; +use spin::RwLock; + +use context; +use syscall::error::*; +use syscall::scheme::Scheme; +use scheme; +use scheme::user::{UserInner, UserScheme}; + +pub struct RootScheme { + next_id: AtomicUsize, + handles: RwLock>> +} + +impl RootScheme { + pub fn new() -> RootScheme { + RootScheme { + next_id: AtomicUsize::new(0), + handles: RwLock::new(BTreeMap::new()) + } + } +} + +impl Scheme for RootScheme { + fn open(&self, path: &[u8], _flags: usize) -> Result { + let context = { + let contexts = context::contexts(); + let context = contexts.current().ok_or(Error::new(ESRCH))?; + Arc::downgrade(&context) + }; + + let inner = { + let mut schemes = scheme::schemes_mut(); + if schemes.get_name(path).is_some() { + return Err(Error::new(EEXIST)); + } + let inner = Arc::new(UserInner::new(context)); + schemes.insert(path.to_vec().into_boxed_slice(), Arc::new(Box::new(UserScheme::new(Arc::downgrade(&inner))))).expect("failed to insert user scheme"); + inner + }; + + let id = self.next_id.fetch_add(1, Ordering::SeqCst); + self.handles.write().insert(id, inner); + + Ok(id) + } + + fn dup(&self, file: usize) -> Result { + let mut handles = self.handles.write(); + let inner = { + let inner = handles.get(&file).ok_or(Error::new(EBADF))?; + inner.clone() + }; + + let id = self.next_id.fetch_add(1, Ordering::SeqCst); + handles.insert(id, inner); + + Ok(id) + } + + fn read(&self, file: usize, buf: &mut [u8]) -> Result { + let inner = { + let handles = self.handles.read(); + let inner = handles.get(&file).ok_or(Error::new(EBADF))?; + inner.clone() + }; + + inner.read(buf) + } + + fn write(&self, file: usize, buf: &[u8]) -> Result { + let inner = { + let handles = self.handles.read(); + let inner = handles.get(&file).ok_or(Error::new(EBADF))?; + inner.clone() + }; + + inner.write(buf) + } + + fn fsync(&self, _file: usize) -> Result { + Ok(0) + } + + fn close(&self, file: usize) -> Result { + self.handles.write().remove(&file).ok_or(Error::new(EBADF)).and(Ok(0)) + } +} diff --git a/kernel/scheme/user.rs b/kernel/scheme/user.rs new file mode 100644 index 0000000..f2c797e --- /dev/null +++ b/kernel/scheme/user.rs @@ -0,0 +1,258 @@ +use alloc::arc::Weak; +use collections::{BTreeMap, VecDeque}; +use core::sync::atomic::{AtomicUsize, Ordering}; +use core::{mem, usize}; +use spin::{Mutex, RwLock}; + +use arch; +use arch::paging::{InactivePageTable, Page, VirtualAddress, entry}; +use arch::paging::temporary_page::TemporaryPage; +use context::{self, Context}; +use context::memory::Grant; +use syscall::data::{Packet, Stat}; +use syscall::error::*; +use syscall::number::*; +use syscall::scheme::Scheme; + +pub struct UserInner { + next_id: AtomicUsize, + context: Weak>, + todo: Mutex>, + done: Mutex> +} + +impl UserInner { + pub fn new(context: Weak>) -> UserInner { + UserInner { + next_id: AtomicUsize::new(0), + context: context, + todo: Mutex::new(VecDeque::new()), + done: Mutex::new(BTreeMap::new()) + } + } + + pub fn call(&self, a: usize, b: usize, c: usize, d: usize) -> Result { + let id = self.next_id.fetch_add(1, Ordering::SeqCst); + + let packet = Packet { + id: id, + a: a, + b: b, + c: c, + d: d + }; + + self.todo.lock().push_back(packet); + + loop { + { + let mut done = self.done.lock(); + if let Some(a) = done.remove(&id) { + return Error::demux(a); + } + } + + unsafe { context::switch(); } + } + } + + pub fn capture(&self, buf: &[u8]) -> Result { + self.capture_inner(buf.as_ptr() as usize, buf.len(), false) + } + + pub fn capture_mut(&self, buf: &mut [u8]) -> Result { + self.capture_inner(buf.as_mut_ptr() as usize, buf.len(), true) + } + + fn capture_inner(&self, address: usize, size: usize, writable: bool) -> Result { + if size == 0 { + Ok(0) + } else { + let context_lock = self.context.upgrade().ok_or(Error::new(ESRCH))?; + let context = context_lock.read(); + + let mut grants = context.grants.lock(); + + let mut new_table = unsafe { InactivePageTable::from_address(context.arch.get_page_table()) }; + let mut temporary_page = TemporaryPage::new(Page::containing_address(VirtualAddress::new(arch::USER_TMP_GRANT_OFFSET))); + + let from_address = (address/4096) * 4096; + let offset = address - from_address; + let full_size = ((offset + size + 4095)/4096) * 4096; + let mut to_address = arch::USER_GRANT_OFFSET; + + let mut flags = entry::PRESENT | entry::NO_EXECUTE; + if writable { + flags |= entry::WRITABLE; + } + + for i in 0 .. grants.len() { + let start = grants[i].start_address().get(); + if to_address + full_size < start { + grants.insert(i, Grant::new( + VirtualAddress::new(from_address), + VirtualAddress::new(to_address), + full_size, + flags, + &mut new_table, + &mut temporary_page + )); + + return Ok(to_address + offset); + } else { + let pages = (grants[i].size() + 4095) / 4096; + let end = start + pages * 4096; + to_address = end; + } + } + + grants.push(Grant::new( + VirtualAddress::new(from_address), + VirtualAddress::new(to_address), + full_size, + flags, + &mut new_table, + &mut temporary_page + )); + + Ok(to_address + offset) + } + } + + pub fn release(&self, address: usize) -> Result<()> { + if address == 0 { + Ok(()) + } else { + let context_lock = self.context.upgrade().ok_or(Error::new(ESRCH))?; + let context = context_lock.read(); + + let mut grants = context.grants.lock(); + + let mut new_table = unsafe { InactivePageTable::from_address(context.arch.get_page_table()) }; + let mut temporary_page = TemporaryPage::new(Page::containing_address(VirtualAddress::new(arch::USER_TMP_GRANT_OFFSET))); + + for i in 0 .. grants.len() { + let start = grants[i].start_address().get(); + let end = start + grants[i].size(); + if address >= start && address < end { + grants.remove(i).destroy(&mut new_table, &mut temporary_page); + + return Ok(()); + } + } + + Err(Error::new(EFAULT)) + } + } + + pub fn read(&self, buf: &mut [u8]) -> Result { + let packet_size = mem::size_of::(); + let len = buf.len()/packet_size; + if len > 0 { + loop { + let mut i = 0; + { + let mut todo = self.todo.lock(); + while ! todo.is_empty() && i < len { + let packet = todo.pop_front().unwrap(); + unsafe { *(buf.as_mut_ptr() as *mut Packet).offset(i as isize) = packet; } + i += 1; + } + } + + if i > 0 { + return Ok(i * packet_size); + } else { + unsafe { context::switch(); } + } + } + } else { + Ok(0) + } + } + + pub fn write(&self, buf: &[u8]) -> Result { + let packet_size = mem::size_of::(); + let len = buf.len()/packet_size; + let mut i = 0; + while i < len { + let packet = unsafe { *(buf.as_ptr() as *const Packet).offset(i as isize) }; + self.done.lock().insert(packet.id, packet.a); + i += 1; + } + + Ok(i * packet_size) + } +} + +/// UserInner has to be wrapped +pub struct UserScheme { + inner: Weak +} + +impl UserScheme { + pub fn new(inner: Weak) -> UserScheme { + UserScheme { + inner: inner + } + } +} + +impl Scheme for UserScheme { + fn open(&self, path: &[u8], flags: usize) -> Result { + let inner = self.inner.upgrade().ok_or(Error::new(ENODEV))?; + let address = inner.capture(path)?; + let result = inner.call(SYS_OPEN, address, path.len(), flags); + let _ = inner.release(address); + result + } + + fn dup(&self, file: usize) -> Result { + let inner = self.inner.upgrade().ok_or(Error::new(ENODEV))?; + inner.call(SYS_DUP, file, 0, 0) + } + + fn read(&self, file: usize, buf: &mut [u8]) -> Result { + let inner = self.inner.upgrade().ok_or(Error::new(ENODEV))?; + let address = inner.capture_mut(buf)?; + let result = inner.call(SYS_READ, file, address, buf.len()); + let _ = inner.release(address); + result + } + + fn write(&self, file: usize, buf: &[u8]) -> Result { + let inner = self.inner.upgrade().ok_or(Error::new(ENODEV))?; + let address = inner.capture(buf)?; + let result = inner.call(SYS_WRITE, file, address, buf.len()); + let _ = inner.release(address); + result + } + + fn seek(&self, file: usize, position: usize, whence: usize) -> Result { + let inner = self.inner.upgrade().ok_or(Error::new(ENODEV))?; + inner.call(SYS_FSYNC, file, position, whence) + } + + fn fstat(&self, file: usize, stat: &mut Stat) -> Result { + let inner = self.inner.upgrade().ok_or(Error::new(ENODEV))?; + let address = inner.capture_mut(stat)?; + let result = inner.call(SYS_FSTAT, file, address, 0); + let _ = inner.release(address); + result + } + + fn fsync(&self, file: usize) -> Result { + let inner = self.inner.upgrade().ok_or(Error::new(ENODEV))?; + inner.call(SYS_FSYNC, file, 0, 0) + } + + fn ftruncate(&self, file: usize, len: usize) -> Result { + let inner = self.inner.upgrade().ok_or(Error::new(ENODEV))?; + inner.call(SYS_FTRUNCATE, file, len, 0) + } + + fn close(&self, file: usize) -> Result { + let inner = self.inner.upgrade().ok_or(Error::new(ENODEV))?; + inner.call(SYS_CLOSE, file, 0, 0) + } +} diff --git a/kernel/syscall/call.rs b/kernel/syscall/call.rs deleted file mode 100644 index 3bcefd4..0000000 --- a/kernel/syscall/call.rs +++ /dev/null @@ -1,67 +0,0 @@ -use super::{Error, Result}; - -/// System call list -/// See http://syscalls.kernelgrok.com/ for numbers -#[derive(Copy, Clone, Debug, Eq, PartialEq)] -#[repr(C)] -pub enum Call { - /// Exit syscall - Exit = 1, - /// Read syscall - Read = 3, - /// Write syscall - Write = 4, - /// Open syscall - Open = 5, - /// Close syscall - Close = 6, - /// Wait for a process - WaitPid = 7, - /// Execute syscall - Exec = 11, - /// Change working directory - ChDir = 12, - /// Get process ID - GetPid = 20, - /// Duplicate file descriptor - Dup = 41, - /// Set process break - Brk = 45, - /// Set process I/O privilege level - Iopl = 110, - /// Sync file descriptor - FSync = 118, - /// Clone process - Clone = 120, - /// Yield to scheduler - SchedYield = 158, - /// Get process working directory - GetCwd = 183 -} - -/// Convert numbers to calls -/// See http://syscalls.kernelgrok.com/ -impl Call { - //TODO: Return Option - pub fn from(number: usize) -> Result { - match number { - 1 => Ok(Call::Exit), - 3 => Ok(Call::Read), - 4 => Ok(Call::Write), - 5 => Ok(Call::Open), - 6 => Ok(Call::Close), - 7 => Ok(Call::WaitPid), - 11 => Ok(Call::Exec), - 12 => Ok(Call::ChDir), - 20 => Ok(Call::GetPid), - 41 => Ok(Call::Dup), - 45 => Ok(Call::Brk), - 110 => Ok(Call::Iopl), - 118 => Ok(Call::FSync), - 120 => Ok(Call::Clone), - 158 => Ok(Call::SchedYield), - 183 => Ok(Call::GetCwd), - _ => Err(Error::NoCall) - } - } -} diff --git a/kernel/syscall/error.rs b/kernel/syscall/error.rs deleted file mode 100644 index ad37b33..0000000 --- a/kernel/syscall/error.rs +++ /dev/null @@ -1,28 +0,0 @@ -/// The error number for an invalid value -/// See http://www-numi.fnal.gov/offline_software/srt_public_context/WebDocs/Errors/unix_system_errors.html for numbers -#[derive(Copy, Clone, Debug, Eq, PartialEq)] -#[repr(C)] -pub enum Error { - /// Operation not permitted - NotPermitted = 1, - /// No such file or directory - NoEntry = 2, - /// No such process - NoProcess = 3, - /// Invalid executable format - NoExec = 8, - /// Bad file number - BadFile = 9, - /// Try again - TryAgain = 11, - /// File exists - FileExists = 17, - /// Invalid argument - InvalidValue = 22, - /// Too many open files - TooManyFiles = 24, - /// Syscall not implemented - NoCall = 38 -} - -pub type Result = ::core::result::Result; diff --git a/kernel/syscall/fs.rs b/kernel/syscall/fs.rs index d68727d..029222b 100644 --- a/kernel/syscall/fs.rs +++ b/kernel/syscall/fs.rs @@ -2,21 +2,23 @@ use context; use scheme; +use syscall::data::Stat; +use syscall::error::*; -use super::{Error, Result}; - +/// Change the current working directory pub fn chdir(path: &[u8]) -> Result { let contexts = context::contexts(); - let context_lock = contexts.current().ok_or(Error::NoProcess)?; + let context_lock = contexts.current().ok_or(Error::new(ESRCH))?; let context = context_lock.read(); let canonical = context.canonicalize(path); *context.cwd.lock() = canonical; Ok(0) } +/// Get the current working directory pub fn getcwd(buf: &mut [u8]) -> Result { let contexts = context::contexts(); - let context_lock = contexts.current().ok_or(Error::NoProcess)?; + let context_lock = contexts.current().ok_or(Error::new(ESRCH))?; let context = context_lock.read(); let cwd = context.cwd.lock(); let mut i = 0; @@ -27,43 +29,11 @@ pub fn getcwd(buf: &mut [u8]) -> Result { Ok(i) } -/// Read syscall -pub fn read(fd: usize, buf: &mut [u8]) -> Result { - let file = { - let contexts = context::contexts(); - let context_lock = contexts.current().ok_or(Error::NoProcess)?; - let context = context_lock.read(); - let file = context.get_file(fd).ok_or(Error::BadFile)?; - file - }; - - let schemes = scheme::schemes(); - let scheme_mutex = schemes.get(file.scheme).ok_or(Error::BadFile)?; - let result = scheme_mutex.lock().read(file.number, buf); - result -} - -/// Write syscall -pub fn write(fd: usize, buf: &[u8]) -> Result { - let file = { - let contexts = context::contexts(); - let context_lock = contexts.current().ok_or(Error::NoProcess)?; - let context = context_lock.read(); - let file = context.get_file(fd).ok_or(Error::BadFile)?; - file - }; - - let schemes = scheme::schemes(); - let scheme_mutex = schemes.get(file.scheme).ok_or(Error::BadFile)?; - let result = scheme_mutex.lock().write(file.number, buf); - result -} - /// Open syscall pub fn open(path: &[u8], flags: usize) -> Result { let path_canon = { let contexts = context::contexts(); - let context_lock = contexts.current().ok_or(Error::NoProcess)?; + let context_lock = contexts.current().ok_or(Error::new(ESRCH))?; let context = context_lock.read(); context.canonicalize(path) }; @@ -73,65 +43,147 @@ pub fn open(path: &[u8], flags: usize) -> Result { let reference_opt = parts.next(); let (scheme_id, file_id) = { - let namespace = namespace_opt.ok_or(Error::NoEntry)?; - let schemes = scheme::schemes(); - let (scheme_id, scheme_mutex) = schemes.get_name(namespace).ok_or(Error::NoEntry)?; - let file_id = scheme_mutex.lock().open(reference_opt.unwrap_or(b""), flags)?; + let namespace = namespace_opt.ok_or(Error::new(ENOENT))?; + let (scheme_id, scheme) = { + let schemes = scheme::schemes(); + let (scheme_id, scheme) = schemes.get_name(namespace).ok_or(Error::new(ENOENT))?; + (scheme_id, scheme.clone()) + }; + let file_id = scheme.open(reference_opt.unwrap_or(b""), flags)?; (scheme_id, file_id) }; let contexts = context::contexts(); - let context_lock = contexts.current().ok_or(Error::NoProcess)?; + let context_lock = contexts.current().ok_or(Error::new(ESRCH))?; let context = context_lock.read(); context.add_file(::context::file::File { scheme: scheme_id, number: file_id - }).ok_or(Error::TooManyFiles) + }).ok_or(Error::new(EMFILE)) } /// Close syscall pub fn close(fd: usize) -> Result { let file = { let contexts = context::contexts(); - let context_lock = contexts.current().ok_or(Error::NoProcess)?; + let context_lock = contexts.current().ok_or(Error::new(ESRCH))?; let context = context_lock.read(); - let file = context.remove_file(fd).ok_or(Error::BadFile)?; + let file = context.remove_file(fd).ok_or(Error::new(EBADF))?; file }; - let schemes = scheme::schemes(); - let scheme_mutex = schemes.get(file.scheme).ok_or(Error::BadFile)?; - let result = scheme_mutex.lock().close(file.number).and(Ok(0)); - result + let scheme = { + let schemes = scheme::schemes(); + let scheme = schemes.get(file.scheme).ok_or(Error::new(EBADF))?; + scheme.clone() + }; + scheme.close(file.number) } /// Duplicate file descriptor pub fn dup(fd: usize) -> Result { let file = { let contexts = context::contexts(); - let context_lock = contexts.current().ok_or(Error::NoProcess)?; + let context_lock = contexts.current().ok_or(Error::new(ESRCH))?; let context = context_lock.read(); - let file = context.get_file(fd).ok_or(Error::BadFile)?; + let file = context.get_file(fd).ok_or(Error::new(EBADF))?; file }; - let schemes = scheme::schemes(); - let scheme_mutex = schemes.get(file.scheme).ok_or(Error::BadFile)?; - let result = scheme_mutex.lock().dup(file.number); - result + let scheme = { + let schemes = scheme::schemes(); + let scheme = schemes.get(file.scheme).ok_or(Error::new(EBADF))?; + scheme.clone() + }; + scheme.dup(file.number) } +/// Get information about the file +pub fn fstat(fd: usize, stat: &mut Stat) -> Result { + let file = { + let contexts = context::contexts(); + let context_lock = contexts.current().ok_or(Error::new(ESRCH))?; + let context = context_lock.read(); + let file = context.get_file(fd).ok_or(Error::new(EBADF))?; + file + }; + + let scheme = { + let schemes = scheme::schemes(); + let scheme = schemes.get(file.scheme).ok_or(Error::new(EBADF))?; + scheme.clone() + }; + scheme.fstat(file.number, stat) +} + +/// Sync the file descriptor pub fn fsync(fd: usize) -> Result { let file = { let contexts = context::contexts(); - let context_lock = contexts.current().ok_or(Error::NoProcess)?; + let context_lock = contexts.current().ok_or(Error::new(ESRCH))?; let context = context_lock.read(); - let file = context.get_file(fd).ok_or(Error::BadFile)?; + let file = context.get_file(fd).ok_or(Error::new(EBADF))?; file }; - let schemes = scheme::schemes(); - let scheme_mutex = schemes.get(file.scheme).ok_or(Error::BadFile)?; - let result = scheme_mutex.lock().fsync(file.number).and(Ok(0)); - result + let scheme = { + let schemes = scheme::schemes(); + let scheme = schemes.get(file.scheme).ok_or(Error::new(EBADF))?; + scheme.clone() + }; + scheme.fsync(file.number) +} + +/// Seek to an offset +pub fn lseek(fd: usize, pos: usize, whence: usize) -> Result { + let file = { + let contexts = context::contexts(); + let context_lock = contexts.current().ok_or(Error::new(ESRCH))?; + let context = context_lock.read(); + let file = context.get_file(fd).ok_or(Error::new(EBADF))?; + file + }; + + let scheme = { + let schemes = scheme::schemes(); + let scheme = schemes.get(file.scheme).ok_or(Error::new(EBADF))?; + scheme.clone() + }; + scheme.seek(file.number, pos, whence) +} + +/// Read syscall +pub fn read(fd: usize, buf: &mut [u8]) -> Result { + let file = { + let contexts = context::contexts(); + let context_lock = contexts.current().ok_or(Error::new(ESRCH))?; + let context = context_lock.read(); + let file = context.get_file(fd).ok_or(Error::new(EBADF))?; + file + }; + + let scheme = { + let schemes = scheme::schemes(); + let scheme = schemes.get(file.scheme).ok_or(Error::new(EBADF))?; + scheme.clone() + }; + scheme.read(file.number, buf) +} + +/// Write syscall +pub fn write(fd: usize, buf: &[u8]) -> Result { + let file = { + let contexts = context::contexts(); + let context_lock = contexts.current().ok_or(Error::new(ESRCH))?; + let context = context_lock.read(); + let file = context.get_file(fd).ok_or(Error::new(EBADF))?; + file + }; + + let scheme = { + let schemes = scheme::schemes(); + let scheme = schemes.get(file.scheme).ok_or(Error::new(EBADF))?; + scheme.clone() + }; + scheme.write(file.number, buf) } diff --git a/kernel/syscall/mod.rs b/kernel/syscall/mod.rs index 396f366..b37a056 100644 --- a/kernel/syscall/mod.rs +++ b/kernel/syscall/mod.rs @@ -1,58 +1,55 @@ ///! Syscall handlers -pub use self::call::*; -pub use self::error::*; +extern crate syscall; + +pub use self::syscall::{data, error, flag, number, scheme}; + pub use self::fs::*; pub use self::process::*; pub use self::validate::*; -/// System call numbers -mod call; - -/// System error codes -mod error; +use self::data::Stat; +use self::error::{Error, Result, ENOSYS}; +use self::number::*; /// Filesystem syscalls -mod fs; +pub mod fs; /// Process syscalls -mod process; +pub mod process; /// Validate input -mod validate; +pub mod validate; #[no_mangle] pub extern fn syscall(a: usize, b: usize, c: usize, d: usize, e: usize, f: usize, stack: usize) -> usize { #[inline(always)] fn inner(a: usize, b: usize, c: usize, d: usize, e: usize, _f: usize, stack: usize) -> Result { - match Call::from(a) { - Ok(call) => match call { - Call::Exit => exit(b), - Call::Read => read(b, validate_slice_mut(c as *mut u8, d)?), - Call::Write => write(b, validate_slice(c as *const u8, d)?), - Call::Open => open(validate_slice(b as *const u8, c)?, d), - Call::Close => close(b), - Call::WaitPid => waitpid(b, c, d), - Call::Exec => exec(validate_slice(b as *const u8, c)?, validate_slice(d as *const [usize; 2], e)?), - Call::ChDir => chdir(validate_slice(b as *const u8, c)?), - Call::GetPid => getpid(), - Call::Dup => dup(b), - Call::Brk => brk(b), - Call::Iopl => iopl(b), - Call::FSync => fsync(b), - Call::Clone => clone(b, stack), - Call::SchedYield => sched_yield(), - Call::GetCwd => getcwd(validate_slice_mut(b as *mut u8, c)?) - }, - Err(err) => { + match a { + SYS_EXIT => exit(b), + SYS_READ => read(b, validate_slice_mut(c as *mut u8, d)?), + SYS_WRITE => write(b, validate_slice(c as *const u8, d)?), + SYS_OPEN => open(validate_slice(b as *const u8, c)?, d), + SYS_CLOSE => close(b), + SYS_WAITPID => waitpid(b, c, d), + SYS_EXECVE => exec(validate_slice(b as *const u8, c)?, validate_slice(d as *const [usize; 2], e)?), + SYS_CHDIR => chdir(validate_slice(b as *const u8, c)?), + SYS_LSEEK => lseek(b, c, d), + SYS_GETPID => getpid(), + SYS_FSTAT => fstat(b, &mut validate_slice_mut(b as *mut Stat, 1)?[0]), + SYS_DUP => dup(b), + SYS_BRK => brk(b), + SYS_IOPL => iopl(b), + SYS_FSYNC => fsync(b), + SYS_CLONE => clone(b, stack), + SYS_YIELD => sched_yield(), + SYS_GETCWD => getcwd(validate_slice_mut(b as *mut u8, c)?), + _ => { println!("Unknown syscall {}", a); - Err(err) + Err(Error::new(ENOSYS)) } } } - match inner(a, b, c, d, e, f, stack) { - Ok(value) => value, - Err(value) => (-(value as isize)) as usize - } + Error::mux(inner(a, b, c, d, e, f, stack)) } diff --git a/kernel/syscall/process.rs b/kernel/syscall/process.rs index 383141c..3d94a11 100644 --- a/kernel/syscall/process.rs +++ b/kernel/syscall/process.rs @@ -15,11 +15,13 @@ use arch::start::usermode; use context; use elf::{self, program_header}; use scheme; -use syscall::{self, Error, Result, validate_slice, validate_slice_mut}; +use syscall; +use syscall::error::*; +use syscall::validate::{validate_slice, validate_slice_mut}; pub fn brk(address: usize) -> Result { let contexts = context::contexts(); - let context_lock = contexts.current().ok_or(Error::NoProcess)?; + let context_lock = contexts.current().ok_or(Error::new(ESRCH))?; let context = context_lock.read(); let current = if let Some(ref heap_shared) = context.heap { @@ -45,8 +47,7 @@ pub fn brk(address: usize) -> Result { Ok(address) } else { - //TODO: Return correct error - Err(Error::NotPermitted) + Err(Error::new(ENOMEM)) } } @@ -75,7 +76,7 @@ pub fn clone(flags: usize, stack_base: usize) -> Result { // Copy from old process { let contexts = context::contexts(); - let context_lock = contexts.current().ok_or(Error::NoProcess)?; + let context_lock = contexts.current().ok_or(Error::new(ESRCH))?; let context = context_lock.read(); ppid = context.id; @@ -96,11 +97,11 @@ pub fn clone(flags: usize, stack_base: usize) -> Result { if flags & CLONE_VM == CLONE_VM { for memory_shared in context.image.iter() { - image.push(memory_shared.borrow()); + image.push(memory_shared.clone()); } if let Some(ref heap_shared) = context.heap { - heap_option = Some(heap_shared.borrow()); + heap_option = Some(heap_shared.clone()); } } else { for memory_shared in context.image.iter() { @@ -174,28 +175,38 @@ pub fn clone(flags: usize, stack_base: usize) -> Result { if flags & CLONE_FILES == CLONE_FILES { files = context.files.clone(); } else { - let mut files_vec = Vec::new(); - for (fd, file_option) in context.files.lock().iter().enumerate() { - if let Some(file) = *file_option { - let result = { + files = Arc::new(Mutex::new(context.files.lock().clone())); + } + } + + // If not cloning files, dup to get a new number from scheme + // This has to be done outside the context lock to prevent deadlocks + if flags & CLONE_FILES == 0 { + for (fd, mut file_option) in files.lock().iter_mut().enumerate() { + let new_file_option = if let Some(file) = *file_option { + let result = { + let scheme = { let schemes = scheme::schemes(); - let scheme_mutex = schemes.get(file.scheme).ok_or(Error::BadFile)?; - let result = scheme_mutex.lock().dup(file.number); - result + let scheme = schemes.get(file.scheme).ok_or(Error::new(EBADF))?; + scheme.clone() }; - match result { - Ok(new_number) => { - files_vec.push(Some(context::file::File { scheme: file.scheme, number: new_number })); - }, - Err(err) => { - println!("clone: failed to dup {}: {:?}", fd, err); - } + let result = scheme.dup(file.number); + result + }; + match result { + Ok(new_number) => { + Some(context::file::File { scheme: file.scheme, number: new_number }) + }, + Err(err) => { + println!("clone: failed to dup {}: {:?}", fd, err); + None } - } else { - files_vec.push(None); } - } - files = Arc::new(Mutex::new(files_vec)); + } else { + None + }; + + *file_option = new_file_option; } } @@ -349,7 +360,7 @@ pub fn exec(path: &[u8], arg_ptrs: &[[usize; 2]]) -> Result { //TODO: Only read elf header, not entire file. Then read required segments let mut data = vec![]; loop { - let mut buf = [0; 4096]; + let mut buf = [0; 16384]; let count = syscall::read(file, &mut buf)?; if count > 0 { data.extend_from_slice(&buf[..count]); @@ -367,7 +378,7 @@ pub fn exec(path: &[u8], arg_ptrs: &[[usize; 2]]) -> Result { drop(arg_ptrs); // Drop so that usage is not allowed after unmapping context let contexts = context::contexts(); - let context_lock = contexts.current().ok_or(Error::NoProcess)?; + let context_lock = contexts.current().ok_or(Error::new(ESRCH))?; let mut context = context_lock.write(); // Unmap previous image and stack @@ -468,7 +479,7 @@ pub fn exec(path: &[u8], arg_ptrs: &[[usize; 2]]) -> Result { }, Err(err) => { println!("failed to execute {}: {}", unsafe { str::from_utf8_unchecked(path) }, err); - return Err(Error::NoExec); + return Err(Error::new(ENOEXEC)); } } } @@ -479,7 +490,7 @@ pub fn exec(path: &[u8], arg_ptrs: &[[usize; 2]]) -> Result { pub fn getpid() -> Result { let contexts = context::contexts(); - let context_lock = contexts.current().ok_or(Error::NoProcess)?; + let context_lock = contexts.current().ok_or(Error::new(ESRCH))?; let context = context_lock.read(); Ok(context.id) } @@ -502,7 +513,7 @@ pub fn waitpid(pid: usize, status_ptr: usize, _options: usize) -> Result { let contexts = context::contexts(); - let context_lock = contexts.get(pid).ok_or(Error::NoProcess)?; + let context_lock = contexts.get(pid).ok_or(Error::new(ESRCH))?; let context = context_lock.read(); if let context::Status::Exited(status) = context.status { if status_ptr != 0 { @@ -515,7 +526,7 @@ pub fn waitpid(pid: usize, status_ptr: usize, _options: usize) -> Result if exited { let mut contexts = context::contexts_mut(); - return contexts.remove(pid).ok_or(Error::NoProcess).and(Ok(pid)); + return contexts.remove(pid).ok_or(Error::new(ESRCH)).and(Ok(pid)); } } diff --git a/kernel/syscall/validate.rs b/kernel/syscall/validate.rs index 61c7384..361f58d 100644 --- a/kernel/syscall/validate.rs +++ b/kernel/syscall/validate.rs @@ -1,15 +1,39 @@ -use core::slice; +use core::{mem, slice}; -use super::Result; +use arch::paging::{ActivePageTable, Page, VirtualAddress, entry}; +use syscall::error::*; + +fn validate(address: usize, size: usize, flags: entry::EntryFlags) -> Result<()> { + let active_table = unsafe { ActivePageTable::new() }; + + let start_page = Page::containing_address(VirtualAddress::new(address)); + let end_page = Page::containing_address(VirtualAddress::new(address + size - 1)); + for page in Page::range_inclusive(start_page, end_page) { + let page_flags = active_table.translate_page_flags(page).ok_or(Error::new(EFAULT))?; + if ! page_flags.contains(flags) { + return Err(Error::new(EFAULT)); + } + } + + Ok(()) +} /// Convert a pointer and length to slice, if valid -/// TODO: Check validity pub fn validate_slice(ptr: *const T, len: usize) -> Result<&'static [T]> { - Ok(unsafe { slice::from_raw_parts(ptr, len) }) + if len == 0 { + Ok(&[]) + } else { + validate(ptr as usize, len * mem::size_of::(), entry::PRESENT /* TODO | entry::USER_ACCESSIBLE */)?; + Ok(unsafe { slice::from_raw_parts(ptr, len) }) + } } /// Convert a pointer and length to slice, if valid -/// TODO: Check validity pub fn validate_slice_mut(ptr: *mut T, len: usize) -> Result<&'static mut [T]> { - Ok(unsafe { slice::from_raw_parts_mut(ptr, len) }) + if len == 0 { + Ok(&mut []) + } else { + validate(ptr as usize, len * mem::size_of::(), entry::PRESENT | entry::WRITABLE /* TODO | entry::USER_ACCESSIBLE */)?; + Ok(unsafe { slice::from_raw_parts_mut(ptr, len) }) + } } diff --git a/kernel/tests/mod.rs b/kernel/tests/mod.rs index 3b92c18..0ad27af 100644 --- a/kernel/tests/mod.rs +++ b/kernel/tests/mod.rs @@ -24,6 +24,6 @@ fn stdio() { /// Test that invalid reads/writes cause errors #[test] fn invalid_path() { - assert_eq!(syscall::read(999, &mut []), Err(Error::BadFile)); - assert_eq!(syscall::write(999, &[]), Err(Error::BadFile)); + assert_eq!(syscall::read(999, &mut []), Err(Error::new(EBADF))); + assert_eq!(syscall::write(999, &[]), Err(Error::new(EBADF))); } diff --git a/libstd b/libstd index 0d434cc..ae80aff 160000 --- a/libstd +++ b/libstd @@ -1 +1 @@ -Subproject commit 0d434cc168b1d88211f1a3b72c8290c911432826 +Subproject commit ae80aff4d39b2d3a83f7d32bc95739e4e1169184 diff --git a/schemes/example/Cargo.toml b/schemes/example/Cargo.toml new file mode 100644 index 0000000..68b930f --- /dev/null +++ b/schemes/example/Cargo.toml @@ -0,0 +1,6 @@ +[package] +name = "example" +version = "0.1.0" + +[dependencies.syscall] +path = "../../syscall/" diff --git a/schemes/example/src/main.rs b/schemes/example/src/main.rs new file mode 100644 index 0000000..84fb345 --- /dev/null +++ b/schemes/example/src/main.rs @@ -0,0 +1,39 @@ +extern crate syscall; + +use std::fs::File; +use std::io::{Read, Write}; +use std::str; +use std::thread; + +use syscall::{Packet, Result, Scheme}; + +struct ExampleScheme; + +impl Scheme for ExampleScheme { + fn open(&self, path: &[u8], _flags: usize) -> Result { + println!("{}", unsafe { str::from_utf8_unchecked(path) }); + Ok(0) + } + + fn dup(&self, file: usize) -> Result { + Ok(file) + } + + fn close(&self, _file: usize) -> Result { + Ok(0) + } +} + +fn main(){ + thread::spawn(move || { + let mut socket = File::create(":example").expect("example: failed to create example scheme"); + let scheme = ExampleScheme; + loop { + let mut packet = Packet::default(); + socket.read(&mut packet).expect("example: failed to read events from example scheme"); + println!("{:?}", packet); + scheme.handle(&mut packet); + socket.write(&packet).expect("example: failed to write responses to example scheme"); + } + }); +} diff --git a/syscall/src/data.rs b/syscall/src/data.rs new file mode 100644 index 0000000..399950b --- /dev/null +++ b/syscall/src/data.rs @@ -0,0 +1,69 @@ +use core::ops::{Deref, DerefMut}; +use core::{mem, slice}; + +#[derive(Copy, Clone, Debug, Default)] +#[repr(packed)] +pub struct Packet { + pub id: usize, + pub a: usize, + pub b: usize, + pub c: usize, + pub d: usize +} + +impl Deref for Packet { + type Target = [u8]; + fn deref(&self) -> &[u8] { + unsafe { + slice::from_raw_parts(self as *const Packet as *const u8, mem::size_of::()) as &[u8] + } + } +} + +impl DerefMut for Packet { + fn deref_mut(&mut self) -> &mut [u8] { + unsafe { + slice::from_raw_parts_mut(self as *mut Packet as *mut u8, mem::size_of::()) as &mut [u8] + } + } +} + +#[derive(Copy, Clone, Debug, Default)] +#[repr(packed)] +pub struct Stat { + pub st_dev: u16, + pub st_ino: u16, + pub st_mode: u16, + pub st_nlink: u16, + pub st_uid: u16, + pub st_gid: u16, + pub st_rdev: u16, + pub st_size: u32, + pub st_atime: u32, + pub st_mtime: u32, + pub st_ctime: u32 +} + +impl Deref for Stat { + type Target = [u8]; + fn deref(&self) -> &[u8] { + unsafe { + slice::from_raw_parts(self as *const Stat as *const u8, mem::size_of::()) as &[u8] + } + } +} + +impl DerefMut for Stat { + fn deref_mut(&mut self) -> &mut [u8] { + unsafe { + slice::from_raw_parts_mut(self as *mut Stat as *mut u8, mem::size_of::()) as &mut [u8] + } + } +} + +#[derive(Copy, Clone, Debug, Default)] +#[repr(packed)] +pub struct TimeSpec { + pub tv_sec: i64, + pub tv_nsec: i32, +} diff --git a/syscall/src/error.rs b/syscall/src/error.rs index 9af8f4a..5481f9f 100644 --- a/syscall/src/error.rs +++ b/syscall/src/error.rs @@ -1,5 +1,6 @@ use core::{fmt, result}; +#[derive(Eq, PartialEq)] pub struct Error { pub errno: isize, } diff --git a/syscall/src/flag.rs b/syscall/src/flag.rs new file mode 100644 index 0000000..fa00558 --- /dev/null +++ b/syscall/src/flag.rs @@ -0,0 +1,40 @@ +pub const CLONE_VM: usize = 0x100; +pub const CLONE_FS: usize = 0x200; +pub const CLONE_FILES: usize = 0x400; +pub const CLONE_VFORK: usize = 0x4000; +/// Mark this clone as supervised. +/// +/// This means that the process can run in supervised mode, even not being connected to +/// a supervisor yet. In other words, the parent can later on supervise the process and handle +/// the potential blocking syscall. +/// +/// This is an important security measure, since otherwise the process would be able to fork it +/// self right after starting, making supervising it impossible. +pub const CLONE_SUPERVISE: usize = 0x400000; +pub const CLOCK_REALTIME: usize = 1; +pub const CLOCK_MONOTONIC: usize = 4; + +pub const MODE_DIR: u16 = 0x4000; +pub const MODE_FILE: u16 = 0x8000; +pub const MODE_ALL: u16 = MODE_DIR | MODE_FILE; + +pub const FUTEX_WAIT: usize = 0; +pub const FUTEX_WAKE: usize = 1; +pub const FUTEX_REQUEUE: usize = 2; + +pub const SEEK_SET: usize = 0; +pub const SEEK_CUR: usize = 1; +pub const SEEK_END: usize = 2; + +pub const O_RDONLY: usize = 0; +pub const O_WRONLY: usize = 1; +pub const O_RDWR: usize = 2; +pub const O_NONBLOCK: usize = 4; +pub const O_APPEND: usize = 8; +pub const O_SHLOCK: usize = 0x10; +pub const O_EXLOCK: usize = 0x20; +pub const O_ASYNC: usize = 0x40; +pub const O_FSYNC: usize = 0x80; +pub const O_CREAT: usize = 0x200; +pub const O_TRUNC: usize = 0x400; +pub const O_EXCL: usize = 0x800; diff --git a/syscall/src/lib.rs b/syscall/src/lib.rs index 800a1db..099f61f 100644 --- a/syscall/src/lib.rs +++ b/syscall/src/lib.rs @@ -2,105 +2,29 @@ #![no_std] pub use self::arch::*; +pub use self::data::*; pub use self::error::*; +pub use self::flag::*; +pub use self::number::*; +pub use self::scheme::*; #[cfg(target_arch = "x86")] #[path="x86.rs"] -pub mod arch; +mod arch; #[cfg(target_arch = "x86_64")] #[path="x86_64.rs"] -pub mod arch; +mod arch; + +pub mod data; pub mod error; -pub const SYS_BRK: usize = 45; -pub const SYS_CHDIR: usize = 12; -pub const SYS_CLONE: usize = 120; - pub const CLONE_VM: usize = 0x100; - pub const CLONE_FS: usize = 0x200; - pub const CLONE_FILES: usize = 0x400; - pub const CLONE_VFORK: usize = 0x4000; - /// Mark this clone as supervised. - /// - /// This means that the process can run in supervised mode, even not being connected to - /// a supervisor yet. In other words, the parent can later on supervise the process and handle - /// the potential blocking syscall. - /// - /// This is an important security measure, since otherwise the process would be able to fork it - /// self right after starting, making supervising it impossible. - pub const CLONE_SUPERVISE: usize = 0x400000; -pub const SYS_CLOSE: usize = 6; -pub const SYS_CLOCK_GETTIME: usize = 265; - pub const CLOCK_REALTIME: usize = 1; - pub const CLOCK_MONOTONIC: usize = 4; -pub const SYS_DUP: usize = 41; -pub const SYS_EXECVE: usize = 11; -pub const SYS_EXIT: usize = 1; -pub const SYS_FPATH: usize = 928; -pub const SYS_FSTAT: usize = 28; - pub const MODE_DIR: u16 = 0x4000; - pub const MODE_FILE: u16 = 0x8000; - pub const MODE_ALL: u16 = MODE_DIR | MODE_FILE; -pub const SYS_FSYNC: usize = 118; -pub const SYS_FTRUNCATE: usize = 93; -pub const SYS_FUTEX: usize = 240; - pub const FUTEX_WAIT: usize = 0; - pub const FUTEX_WAKE: usize = 1; - pub const FUTEX_REQUEUE: usize = 2; -pub const SYS_GETCWD: usize = 183; -pub const SYS_GETPID: usize = 20; -pub const SYS_IOPL: usize = 110; -pub const SYS_LINK: usize = 9; -pub const SYS_LSEEK: usize = 19; - pub const SEEK_SET: usize = 0; - pub const SEEK_CUR: usize = 1; - pub const SEEK_END: usize = 2; -pub const SYS_MKDIR: usize = 39; -pub const SYS_NANOSLEEP: usize = 162; -pub const SYS_OPEN: usize = 5; - pub const O_RDONLY: usize = 0; - pub const O_WRONLY: usize = 1; - pub const O_RDWR: usize = 2; - pub const O_NONBLOCK: usize = 4; - pub const O_APPEND: usize = 8; - pub const O_SHLOCK: usize = 0x10; - pub const O_EXLOCK: usize = 0x20; - pub const O_ASYNC: usize = 0x40; - pub const O_FSYNC: usize = 0x80; - pub const O_CREAT: usize = 0x200; - pub const O_TRUNC: usize = 0x400; - pub const O_EXCL: usize = 0x800; -pub const SYS_PIPE2: usize = 331; -pub const SYS_READ: usize = 3; -pub const SYS_RMDIR: usize = 84; -pub const SYS_UNLINK: usize = 10; -pub const SYS_WAITPID: usize = 7; -pub const SYS_WRITE: usize = 4; -pub const SYS_YIELD: usize = 158; +pub mod flag; -#[derive(Copy, Clone, Debug, Default)] -#[repr(packed)] -pub struct Stat { - pub st_dev: u16, - pub st_ino: u16, - pub st_mode: u16, - pub st_nlink: u16, - pub st_uid: u16, - pub st_gid: u16, - pub st_rdev: u16, - pub st_size: u32, - pub st_atime: u32, - pub st_mtime: u32, - pub st_ctime: u32 -} +pub mod number; -#[derive(Copy, Clone, Debug, Default)] -#[repr(packed)] -pub struct TimeSpec { - pub tv_sec: i64, - pub tv_nsec: i32, -} +pub mod scheme; pub unsafe fn brk(addr: usize) -> Result { syscall1(SYS_BRK, addr) diff --git a/syscall/src/number.rs b/syscall/src/number.rs new file mode 100644 index 0000000..e65c37f --- /dev/null +++ b/syscall/src/number.rs @@ -0,0 +1,28 @@ +pub const SYS_BRK: usize = 45; +pub const SYS_CHDIR: usize = 12; +pub const SYS_CLONE: usize = 120; +pub const SYS_CLOSE: usize = 6; +pub const SYS_CLOCK_GETTIME: usize = 265; +pub const SYS_DUP: usize = 41; +pub const SYS_EXECVE: usize = 11; +pub const SYS_EXIT: usize = 1; +pub const SYS_FPATH: usize = 928; +pub const SYS_FSTAT: usize = 28; +pub const SYS_FSYNC: usize = 118; +pub const SYS_FTRUNCATE: usize = 93; +pub const SYS_FUTEX: usize = 240; +pub const SYS_GETCWD: usize = 183; +pub const SYS_GETPID: usize = 20; +pub const SYS_IOPL: usize = 110; +pub const SYS_LINK: usize = 9; +pub const SYS_LSEEK: usize = 19; +pub const SYS_MKDIR: usize = 39; +pub const SYS_NANOSLEEP: usize = 162; +pub const SYS_OPEN: usize = 5; +pub const SYS_PIPE2: usize = 331; +pub const SYS_READ: usize = 3; +pub const SYS_RMDIR: usize = 84; +pub const SYS_UNLINK: usize = 10; +pub const SYS_WAITPID: usize = 7; +pub const SYS_WRITE: usize = 4; +pub const SYS_YIELD: usize = 158; diff --git a/syscall/src/scheme.rs b/syscall/src/scheme.rs new file mode 100644 index 0000000..6a857d1 --- /dev/null +++ b/syscall/src/scheme.rs @@ -0,0 +1,94 @@ +use core::slice; + +use super::*; + +pub trait Scheme { + fn handle(&self, packet: &mut Packet) { + packet.a = Error::mux(match packet.a { + SYS_OPEN => self.open(unsafe { slice::from_raw_parts(packet.b as *const u8, packet.c) }, packet.d), + SYS_MKDIR => self.mkdir(unsafe { slice::from_raw_parts(packet.b as *const u8, packet.c) }, packet.d), + SYS_RMDIR => self.rmdir(unsafe { slice::from_raw_parts(packet.b as *const u8, packet.c) }), + SYS_UNLINK => self.unlink(unsafe { slice::from_raw_parts(packet.b as *const u8, packet.c) }), + + SYS_DUP => self.dup(packet.b), + SYS_READ => self.read(packet.b, unsafe { slice::from_raw_parts_mut(packet.c as *mut u8, packet.d) }), + SYS_WRITE => self.write(packet.b, unsafe { slice::from_raw_parts(packet.c as *const u8, packet.d) }), + SYS_LSEEK => self.seek(packet.b, packet.c, packet.d), + SYS_FPATH => self.fpath(packet.b, unsafe { slice::from_raw_parts_mut(packet.c as *mut u8, packet.d) }), + SYS_FSTAT => self.fstat(packet.b, unsafe { &mut *(packet.c as *mut Stat) }), + SYS_FSYNC => self.fsync(packet.b), + SYS_FTRUNCATE => self.ftruncate(packet.b, packet.c), + SYS_CLOSE => self.close(packet.b), + + _ => Err(Error::new(ENOSYS)) + }); + } + + /* Scheme operations */ + + #[allow(unused_variables)] + fn open(&self, path: &[u8], flags: usize) -> Result { + Err(Error::new(ENOENT)) + } + + #[allow(unused_variables)] + fn mkdir(&self, path: &[u8], mode: usize) -> Result { + Err(Error::new(ENOENT)) + } + + #[allow(unused_variables)] + fn rmdir(&self, path: &[u8]) -> Result { + Err(Error::new(ENOENT)) + } + + #[allow(unused_variables)] + fn unlink(&self, path: &[u8]) -> Result { + Err(Error::new(ENOENT)) + } + + /* Resource operations */ + #[allow(unused_variables)] + fn dup(&self, old_id: usize) -> Result { + Err(Error::new(EBADF)) + } + + #[allow(unused_variables)] + fn read(&self, id: usize, buf: &mut [u8]) -> Result { + Err(Error::new(EBADF)) + } + + #[allow(unused_variables)] + fn write(&self, id: usize, buf: &[u8]) -> Result { + Err(Error::new(EBADF)) + } + + #[allow(unused_variables)] + fn seek(&self, id: usize, pos: usize, whence: usize) -> Result { + Err(Error::new(EBADF)) + } + + #[allow(unused_variables)] + fn fpath(&self, id: usize, buf: &mut [u8]) -> Result { + Err(Error::new(EBADF)) + } + + #[allow(unused_variables)] + fn fstat(&self, id: usize, stat: &mut Stat) -> Result { + Err(Error::new(EBADF)) + } + + #[allow(unused_variables)] + fn fsync(&self, id: usize) -> Result { + Err(Error::new(EBADF)) + } + + #[allow(unused_variables)] + fn ftruncate(&self, id: usize, len: usize) -> Result { + Err(Error::new(EBADF)) + } + + #[allow(unused_variables)] + fn close(&self, id: usize) -> Result { + Err(Error::new(EBADF)) + } +}