From 36fde7c7c52bef2c680719778e56761d517e9b3b Mon Sep 17 00:00:00 2001 From: Jeremy Soller Date: Sun, 18 Sep 2016 20:17:08 -0600 Subject: [PATCH 01/17] Allow userspace to handle IRQs (WIP). Create basic keyboard handler --- Makefile | 7 +++- arch/x86_64/src/interrupt/irq.rs | 12 ++++--- drivers/ps2d/Cargo.toml | 6 ++++ drivers/ps2d/src/main.rs | 59 ++++++++++++++++++++++++++++++++ kernel/context/memory.rs | 2 +- kernel/scheme/initfs.rs | 3 +- kernel/scheme/irq.rs | 46 +++++++++++++++++-------- kernel/syscall/process.rs | 4 +-- 8 files changed, 115 insertions(+), 24 deletions(-) create mode 100644 drivers/ps2d/Cargo.toml create mode 100644 drivers/ps2d/src/main.rs diff --git a/Makefile b/Makefile index 3c9c5e0..ac98e50 100644 --- a/Makefile +++ b/Makefile @@ -26,6 +26,7 @@ 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/atkbd/Cargo.toml cargo clean --manifest-path drivers/pcid/Cargo.toml rm -rf build @@ -133,4 +134,8 @@ $(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)/initfs.rs: $(BUILD)/init $(BUILD)/ion $(BUILD)/pcid $(BUILD)/ps2d diff --git a/arch/x86_64/src/interrupt/irq.rs b/arch/x86_64/src/interrupt/irq.rs index a36d019..ec65a20 100644 --- a/arch/x86_64/src/interrupt/irq.rs +++ b/arch/x86_64/src/interrupt/irq.rs @@ -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, { diff --git a/drivers/ps2d/Cargo.toml b/drivers/ps2d/Cargo.toml new file mode 100644 index 0000000..f49dee1 --- /dev/null +++ b/drivers/ps2d/Cargo.toml @@ -0,0 +1,6 @@ +[package] +name = "ps2d" +version = "0.1.0" + +[dependencies.syscall] +path = "../../syscall/" diff --git a/drivers/ps2d/src/main.rs b/drivers/ps2d/src/main.rs new file mode 100644 index 0000000..9f45412 --- /dev/null +++ b/drivers/ps2d/src/main.rs @@ -0,0 +1,59 @@ +#![feature(asm)] + +extern crate syscall; + +use std::fs::File; +use std::io::{Read, Write}; +use std::thread; + +use syscall::iopl; + +fn main() { + if true { + unsafe { + iopl(3).expect("pskbd: failed to get I/O permission"); + asm!("cli" :::: "intel", "volatile"); + } + + let mut file = File::open("irq:1").expect("pskbd: failed to open irq:1"); + + println!("pskbd: Reading keyboard IRQs"); + + loop { + let mut irqs = [0; 8]; + file.read(&mut irqs).expect("pskbd: failed to read irq:1"); + + let data: u8; + unsafe { + asm!("in al, dx" : "={al}"(data) : "{dx}"(0x60) : : "intel", "volatile"); + } + + println!("pskbd: IRQ {}: {:X}", unsafe { *(irqs.as_ptr() as *const usize) }, data); + + file.write(&irqs).expect("pskbd: failed to write irq:1"); + } + } else { + unsafe { + iopl(3).expect("psmsd: failed to get I/O permission"); + asm!("cli" :::: "intel", "volatile"); + } + + let mut file = File::open("irq:12").expect("psmsd: failed to open irq:12"); + + println!("psmsd: Reading mouse IRQs"); + + loop { + let mut count = [0; 8]; + file.read(&mut count).expect("psmsd: failed to read irq:12"); + + let data: u8; + unsafe { + asm!("in al, dx" : "={al}"(data) : "{dx}"(0x60) : : "intel", "volatile"); + } + + println!("psmsd: IRQ: {:X}", data); + + file.write(&count).expect("psmsd: failed to write irq:12"); + } + } +} diff --git a/kernel/context/memory.rs b/kernel/context/memory.rs index 34e69a3..8f1fecb 100644 --- a/kernel/context/memory.rs +++ b/kernel/context/memory.rs @@ -13,7 +13,7 @@ pub struct Memory { flags: EntryFlags } -#[derive(Debug)] +#[derive(Clone, Debug)] pub enum SharedMemory { Owned(Arc>), Borrowed(Weak>) diff --git a/kernel/scheme/initfs.rs b/kernel/scheme/initfs.rs index 0b15bd2..aa5e7ff 100644 --- a/kernel/scheme/initfs.rs +++ b/kernel/scheme/initfs.rs @@ -21,7 +21,8 @@ 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"etc/init.rc", b"echo testing\n#initfs:bin/pcid\ninitfs:bin/ps2d\n#initfs:bin/ion"); InitFsScheme { next_id: 0, diff --git a/kernel/scheme/irq.rs b/kernel/scheme/irq.rs index 9d7d42d..8eee59d 100644 --- a/kernel/scheme/irq.rs +++ b/kernel/scheme/irq.rs @@ -1,6 +1,6 @@ use core::{mem, str}; -use arch::interrupt::irq::COUNTS; +use arch::interrupt::irq::{COUNTS, acknowledge}; use context; use syscall::{Error, Result}; use super::Scheme; @@ -10,7 +10,9 @@ 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))?; + if id < COUNTS.lock().len() { Ok(id) } else { @@ -19,35 +21,49 @@ impl Scheme for IrqScheme { } fn dup(&mut self, file: usize) -> Result { - Ok(file) + Err(Error::NotPermitted) } fn read(&mut 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 current = COUNTS.lock()[file]; + let prev = { 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(); } + { + let current = COUNTS.lock()[file]; + if prev != 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; } + return Ok(mem::size_of::()); + } } + + // Safe if all locks have been dropped + unsafe { context::switch(); } } } else { Err(Error::InvalidValue) } } - fn write(&mut self, _file: usize, _buffer: &[u8]) -> Result { - Err(Error::NotPermitted) + fn write(&mut self, file: usize, buffer: &[u8]) -> Result { + if buffer.len() >= mem::size_of::() { + assert!(buffer.len() >= mem::size_of::()); + let prev = unsafe { *(buffer.as_ptr() as *const usize) }; + let current = COUNTS.lock()[file]; + if prev == current { + unsafe { acknowledge(file); } + return Ok(mem::size_of::()); + } else { + return Ok(0); + } + } else { + Err(Error::InvalidValue) + } } - fn fsync(&mut self, file: usize) -> Result<()> { + fn fsync(&mut self, _file: usize) -> Result<()> { Ok(()) } diff --git a/kernel/syscall/process.rs b/kernel/syscall/process.rs index 383141c..f05271a 100644 --- a/kernel/syscall/process.rs +++ b/kernel/syscall/process.rs @@ -96,11 +96,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() { From 1331f4103f4c59856061bf4e4833ba1f48d9a6e0 Mon Sep 17 00:00:00 2001 From: Jeremy Soller Date: Sun, 18 Sep 2016 21:05:59 -0600 Subject: [PATCH 02/17] Unlock context switch lock without potentially screwing up switch_to function --- arch/x86_64/src/context.rs | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/arch/x86_64/src/context.rs b/arch/x86_64/src/context.rs index 004914d..09cca9c 100644 --- a/arch/x86_64/src/context.rs +++ b/arch/x86_64/src/context.rs @@ -52,6 +52,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 +95,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); +} From 70a2faa0c7a7a524f61a66f7d89dca53f59c8525 Mon Sep 17 00:00:00 2001 From: Jeremy Soller Date: Mon, 19 Sep 2016 08:46:11 -0600 Subject: [PATCH 03/17] Correctly position stack in higher half --- arch/x86_64/src/acpi/mod.rs | 4 ++-- arch/x86_64/src/paging/mod.rs | 14 +++++++------- arch/x86_64/src/start.rs | 6 +++--- bootloader/x86_64/startup-x86_64.asm | 3 ++- 4 files changed, 14 insertions(+), 13 deletions(-) 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/paging/mod.rs b/arch/x86_64/src/paging/mod.rs index 4c3da06..249b467 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); diff --git a/arch/x86_64/src/start.rs b/arch/x86_64/src/start.rs index c941a88..8774064 100644 --- a/arch/x86_64/src/start.rs +++ b/arch/x86_64/src/start.rs @@ -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: From 727647dbf1b53318212c4336e42591b37859dcc7 Mon Sep 17 00:00:00 2001 From: Jeremy Soller Date: Mon, 19 Sep 2016 09:43:30 -0600 Subject: [PATCH 04/17] Seperate PS/2 keyboard and mouse driver --- arch/x86_64/src/interrupt/irq.rs | 5 +--- arch/x86_64/src/lib.rs | 3 +- drivers/ps2d/src/main.rs | 51 +++++++++++++++++++------------- kernel/context/switch.rs | 2 ++ kernel/scheme/initfs.rs | 2 +- kernel/scheme/irq.rs | 30 ++++++++----------- 6 files changed, 49 insertions(+), 44 deletions(-) diff --git a/arch/x86_64/src/interrupt/irq.rs b/arch/x86_64/src/interrupt/irq.rs index ec65a20..fdc38f6 100644 --- a/arch/x86_64/src/interrupt/irq.rs +++ b/arch/x86_64/src/interrupt/irq.rs @@ -4,6 +4,7 @@ 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)] @@ -88,10 +89,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/lib.rs b/arch/x86_64/src/lib.rs index 870bf73..21d4ceb 100644 --- a/arch/x86_64/src/lib.rs +++ b/arch/x86_64/src/lib.rs @@ -73,8 +73,7 @@ pub extern crate x86; 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)*); }); } diff --git a/drivers/ps2d/src/main.rs b/drivers/ps2d/src/main.rs index 9f45412..95345ae 100644 --- a/drivers/ps2d/src/main.rs +++ b/drivers/ps2d/src/main.rs @@ -4,12 +4,15 @@ extern crate syscall; use std::fs::File; use std::io::{Read, Write}; +use std::mem; use std::thread; use syscall::iopl; fn main() { - if true { + println!("PS/2 driver launching"); + + thread::spawn(|| { unsafe { iopl(3).expect("pskbd: failed to get I/O permission"); asm!("cli" :::: "intel", "volatile"); @@ -21,18 +24,22 @@ fn main() { loop { let mut irqs = [0; 8]; - file.read(&mut irqs).expect("pskbd: failed to read irq:1"); + if file.read(&mut irqs).expect("pskbd: failed to read irq:1") >= mem::size_of::() { + let data: u8; + unsafe { + asm!("in al, dx" : "={al}"(data) : "{dx}"(0x60) : : "intel", "volatile"); + } - let data: u8; - unsafe { - asm!("in al, dx" : "={al}"(data) : "{dx}"(0x60) : : "intel", "volatile"); + println!("pskbd: IRQ {}: {:X}", unsafe { *(irqs.as_ptr() as *const usize) }, data); + + file.write(&irqs).expect("pskbd: failed to write irq:1"); + } else { + thread::yield_now(); } - - println!("pskbd: IRQ {}: {:X}", unsafe { *(irqs.as_ptr() as *const usize) }, data); - - file.write(&irqs).expect("pskbd: failed to write irq:1"); } - } else { + }); + + thread::spawn(|| { unsafe { iopl(3).expect("psmsd: failed to get I/O permission"); asm!("cli" :::: "intel", "volatile"); @@ -43,17 +50,21 @@ fn main() { println!("psmsd: Reading mouse IRQs"); loop { - let mut count = [0; 8]; - file.read(&mut count).expect("psmsd: failed to read irq:12"); + let mut irqs = [0; 8]; + if file.read(&mut irqs).expect("psmsd: failed to read irq:12") >= mem::size_of::() { + let data: u8; + unsafe { + asm!("in al, dx" : "={al}"(data) : "{dx}"(0x60) : : "intel", "volatile"); + } - let data: u8; - unsafe { - asm!("in al, dx" : "={al}"(data) : "{dx}"(0x60) : : "intel", "volatile"); + println!("psmsd: IRQ {}: {:X}", unsafe { *(irqs.as_ptr() as *const usize) }, data); + + file.write(&irqs).expect("psmsd: failed to write irq:12"); + } else { + thread::yield_now(); } - - println!("psmsd: IRQ: {:X}", data); - - file.write(&count).expect("psmsd: failed to write irq:12"); } - } + }); + + println!("PS/2 driver running in background"); } 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/initfs.rs b/kernel/scheme/initfs.rs index aa5e7ff..0a33ce7 100644 --- a/kernel/scheme/initfs.rs +++ b/kernel/scheme/initfs.rs @@ -22,7 +22,7 @@ impl InitFsScheme { files.insert(b"bin/ion", include_bytes!("../../build/userspace/ion")); files.insert(b"bin/pcid", include_bytes!("../../build/userspace/pcid")); files.insert(b"bin/ps2d", include_bytes!("../../build/userspace/ps2d")); - files.insert(b"etc/init.rc", b"echo testing\n#initfs:bin/pcid\ninitfs:bin/ps2d\n#initfs:bin/ion"); + files.insert(b"etc/init.rc", b"#initfs:bin/pcid\ninitfs:bin/ps2d\n#initfs:bin/ion"); InitFsScheme { next_id: 0, diff --git a/kernel/scheme/irq.rs b/kernel/scheme/irq.rs index 8eee59d..fb68e11 100644 --- a/kernel/scheme/irq.rs +++ b/kernel/scheme/irq.rs @@ -1,6 +1,6 @@ use core::{mem, str}; -use arch::interrupt::irq::{COUNTS, acknowledge}; +use arch::interrupt::irq::{ACKS, COUNTS, acknowledge}; use context; use syscall::{Error, Result}; use super::Scheme; @@ -27,20 +27,15 @@ impl Scheme for IrqScheme { fn read(&mut 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 prev = { COUNTS.lock()[file] }; - loop { - { - let current = COUNTS.lock()[file]; - if prev != 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; } - return Ok(mem::size_of::()); - } - } - - // Safe if all locks have been dropped - unsafe { context::switch(); } + let ack = ACKS.lock()[file]; + let current = COUNTS.lock()[file]; + 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; } + return Ok(mem::size_of::()); + } else { + return Ok(0); } } else { Err(Error::InvalidValue) @@ -50,9 +45,10 @@ impl Scheme for IrqScheme { fn write(&mut self, file: usize, buffer: &[u8]) -> Result { if buffer.len() >= mem::size_of::() { assert!(buffer.len() >= mem::size_of::()); - let prev = unsafe { *(buffer.as_ptr() as *const usize) }; + let ack = unsafe { *(buffer.as_ptr() as *const usize) }; let current = COUNTS.lock()[file]; - if prev == current { + if ack == current { + ACKS.lock()[file] = ack; unsafe { acknowledge(file); } return Ok(mem::size_of::()); } else { From c957c2a1050ac43305025f7f9a679e5ad96d2775 Mon Sep 17 00:00:00 2001 From: Jeremy Soller Date: Mon, 19 Sep 2016 10:24:19 -0600 Subject: [PATCH 05/17] PS/2 driver convert to char --- arch/x86_64/src/device/ps2.rs | 41 ++------------ arch/x86_64/src/interrupt/irq.rs | 1 - drivers/ps2d/src/keymap.rs | 68 ++++++++++++++++++++++++ drivers/ps2d/src/main.rs | 91 +++++++++++++++++--------------- kernel/scheme/irq.rs | 1 - 5 files changed, 120 insertions(+), 82 deletions(-) create mode 100644 drivers/ps2d/src/keymap.rs diff --git a/arch/x86_64/src/device/ps2.rs b/arch/x86_64/src/device/ps2.rs index 8980086..8b29f03 100644 --- a/arch/x86_64/src/device/ps2.rs +++ b/arch/x86_64/src/device/ps2.rs @@ -1,15 +1,9 @@ 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; + Ps2::new().init(); } bitflags! { @@ -98,34 +92,6 @@ bitflags! { } } -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], @@ -278,7 +244,7 @@ impl Ps2 { self.read() } - fn init(&mut self) -> (Option, Option) { + fn init(&mut self) { // Disable devices self.command(Command::DisableFirst); self.command(Command::DisableSecond); @@ -352,13 +318,12 @@ 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); } self.flush_read(); - - (Some(Ps2Keyboard::new()), Some(Ps2Mouse::new(mouse_extra))) } } diff --git a/arch/x86_64/src/interrupt/irq.rs b/arch/x86_64/src/interrupt/irq.rs index fdc38f6..091a2e2 100644 --- a/arch/x86_64/src/interrupt/irq.rs +++ b/arch/x86_64/src/interrupt/irq.rs @@ -1,7 +1,6 @@ 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]); 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 index 95345ae..f5818a6 100644 --- a/drivers/ps2d/src/main.rs +++ b/drivers/ps2d/src/main.rs @@ -9,34 +9,61 @@ use std::thread; use syscall::iopl; -fn main() { - println!("PS/2 driver launching"); +mod keymap; +fn keyboard() { + let mut file = File::open("irq:1").expect("pskbd: failed to open irq:1"); + + loop { + let mut irqs = [0; 8]; + if file.read(&mut irqs).expect("pskbd: 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) + }; + println!("pskbd: IRQ {}: {:X}: {:X}: {}: {}", unsafe { *(irqs.as_ptr() as *const usize) }, data, scancode, keymap::get_char(scancode), pressed); + + file.write(&irqs).expect("pskbd: failed to write irq:1"); + } else { + thread::yield_now(); + } + } +} + +fn mouse() { + let mut file = File::open("irq:12").expect("psmsd: failed to open irq:12"); + + loop { + let mut irqs = [0; 8]; + if file.read(&mut irqs).expect("psmsd: failed to read irq:12") >= mem::size_of::() { + let data: u8; + unsafe { + asm!("in al, dx" : "={al}"(data) : "{dx}"(0x60) : : "intel", "volatile"); + } + + println!("psmsd: IRQ {}: {:X}", unsafe { *(irqs.as_ptr() as *const usize) }, data); + + file.write(&irqs).expect("psmsd: failed to write irq:12"); + } else { + thread::yield_now(); + } + } +} + +fn main() { thread::spawn(|| { unsafe { iopl(3).expect("pskbd: failed to get I/O permission"); asm!("cli" :::: "intel", "volatile"); } - let mut file = File::open("irq:1").expect("pskbd: failed to open irq:1"); - - println!("pskbd: Reading keyboard IRQs"); - - loop { - let mut irqs = [0; 8]; - if file.read(&mut irqs).expect("pskbd: failed to read irq:1") >= mem::size_of::() { - let data: u8; - unsafe { - asm!("in al, dx" : "={al}"(data) : "{dx}"(0x60) : : "intel", "volatile"); - } - - println!("pskbd: IRQ {}: {:X}", unsafe { *(irqs.as_ptr() as *const usize) }, data); - - file.write(&irqs).expect("pskbd: failed to write irq:1"); - } else { - thread::yield_now(); - } - } + keyboard(); }); thread::spawn(|| { @@ -45,26 +72,6 @@ fn main() { asm!("cli" :::: "intel", "volatile"); } - let mut file = File::open("irq:12").expect("psmsd: failed to open irq:12"); - - println!("psmsd: Reading mouse IRQs"); - - loop { - let mut irqs = [0; 8]; - if file.read(&mut irqs).expect("psmsd: failed to read irq:12") >= mem::size_of::() { - let data: u8; - unsafe { - asm!("in al, dx" : "={al}"(data) : "{dx}"(0x60) : : "intel", "volatile"); - } - - println!("psmsd: IRQ {}: {:X}", unsafe { *(irqs.as_ptr() as *const usize) }, data); - - file.write(&irqs).expect("psmsd: failed to write irq:12"); - } else { - thread::yield_now(); - } - } + mouse(); }); - - println!("PS/2 driver running in background"); } diff --git a/kernel/scheme/irq.rs b/kernel/scheme/irq.rs index fb68e11..1720d93 100644 --- a/kernel/scheme/irq.rs +++ b/kernel/scheme/irq.rs @@ -1,7 +1,6 @@ use core::{mem, str}; use arch::interrupt::irq::{ACKS, COUNTS, acknowledge}; -use context; use syscall::{Error, Result}; use super::Scheme; From 0b3be623fc9e9e9e319da38f694d64f146f005ab Mon Sep 17 00:00:00 2001 From: Jeremy Soller Date: Mon, 19 Sep 2016 17:19:49 -0600 Subject: [PATCH 06/17] Move PS/2 driver to userspace --- arch/x86_64/Cargo.toml | 3 +- arch/x86_64/src/device/mod.rs | 2 - arch/x86_64/src/io/mod.rs | 9 -- arch/x86_64/src/lib.rs | 4 +- drivers/io/Cargo.toml | 3 + {arch/x86_64/src/io => drivers/io/src}/io.rs | 0 drivers/io/src/lib.rs | 14 +++ .../x86_64/src/io => drivers/io/src}/mmio.rs | 0 {arch/x86_64/src/io => drivers/io/src}/pio.rs | 31 ++++-- drivers/ps2d/Cargo.toml | 7 +- .../ps2.rs => drivers/ps2d/src/controller.rs | 100 +----------------- drivers/ps2d/src/keyboard.rs | 34 ++++++ drivers/ps2d/src/main.rs | 71 ++++--------- drivers/ps2d/src/mouse.rs | 73 +++++++++++++ 14 files changed, 178 insertions(+), 173 deletions(-) delete mode 100644 arch/x86_64/src/io/mod.rs create mode 100644 drivers/io/Cargo.toml rename {arch/x86_64/src/io => drivers/io/src}/io.rs (100%) create mode 100644 drivers/io/src/lib.rs rename {arch/x86_64/src/io => drivers/io/src}/mmio.rs (100%) rename {arch/x86_64/src/io => drivers/io/src}/pio.rs (53%) rename arch/x86_64/src/device/ps2.rs => drivers/ps2d/src/controller.rs (66%) create mode 100644 drivers/ps2d/src/keyboard.rs create mode 100644 drivers/ps2d/src/mouse.rs 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/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/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 21d4ceb..c7e5f87 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; @@ -198,9 +199,6 @@ pub mod gdt; /// Interrupt descriptor table pub mod idt; -/// IO Handling -pub mod io; - /// Interrupt instructions pub mod interrupt; 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 index f49dee1..665e3c1 100644 --- a/drivers/ps2d/Cargo.toml +++ b/drivers/ps2d/Cargo.toml @@ -2,5 +2,8 @@ name = "ps2d" version = "0.1.0" -[dependencies.syscall] -path = "../../syscall/" +[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 66% rename from arch/x86_64/src/device/ps2.rs rename to drivers/ps2d/src/controller.rs index 8b29f03..8355dba 100644 --- a/arch/x86_64/src/device/ps2.rs +++ b/drivers/ps2d/src/controller.rs @@ -1,5 +1,3 @@ -use core::cmp; - use io::{Io, Pio, ReadOnly, WriteOnly}; pub unsafe fn init() { @@ -79,86 +77,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 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>, @@ -166,7 +84,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)), @@ -244,7 +162,7 @@ impl Ps2 { self.read() } - fn init(&mut self) { + pub fn init(&mut self) -> bool { // Disable devices self.command(Command::DisableFirst); self.command(Command::DisableSecond); @@ -294,18 +212,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); @@ -325,5 +231,7 @@ impl Ps2 { } self.flush_read(); + + mouse_extra } } diff --git a/drivers/ps2d/src/keyboard.rs b/drivers/ps2d/src/keyboard.rs new file mode 100644 index 0000000..109819a --- /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/main.rs b/drivers/ps2d/src/main.rs index f5818a6..4a3888e 100644 --- a/drivers/ps2d/src/main.rs +++ b/drivers/ps2d/src/main.rs @@ -1,77 +1,42 @@ #![feature(asm)] +#[macro_use] +extern crate bitflags; +extern crate io; extern crate syscall; -use std::fs::File; -use std::io::{Read, Write}; -use std::mem; use std::thread; use syscall::iopl; +mod controller; +mod keyboard; mod keymap; - -fn keyboard() { - let mut file = File::open("irq:1").expect("pskbd: failed to open irq:1"); - - loop { - let mut irqs = [0; 8]; - if file.read(&mut irqs).expect("pskbd: 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) - }; - println!("pskbd: IRQ {}: {:X}: {:X}: {}: {}", unsafe { *(irqs.as_ptr() as *const usize) }, data, scancode, keymap::get_char(scancode), pressed); - - file.write(&irqs).expect("pskbd: failed to write irq:1"); - } else { - thread::yield_now(); - } - } -} - -fn mouse() { - let mut file = File::open("irq:12").expect("psmsd: failed to open irq:12"); - - loop { - let mut irqs = [0; 8]; - if file.read(&mut irqs).expect("psmsd: failed to read irq:12") >= mem::size_of::() { - let data: u8; - unsafe { - asm!("in al, dx" : "={al}"(data) : "{dx}"(0x60) : : "intel", "volatile"); - } - - println!("psmsd: IRQ {}: {:X}", unsafe { *(irqs.as_ptr() as *const usize) }, data); - - file.write(&irqs).expect("psmsd: failed to write irq:12"); - } else { - thread::yield_now(); - } - } -} +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("pskbd: failed to get I/O permission"); + iopl(3).expect("ps2d: failed to get I/O permission"); asm!("cli" :::: "intel", "volatile"); } - keyboard(); + keyboard::keyboard(); }); - thread::spawn(|| { + thread::spawn(move || { unsafe { - iopl(3).expect("psmsd: failed to get I/O permission"); + iopl(3).expect("ps2d: failed to get I/O permission"); asm!("cli" :::: "intel", "volatile"); } - mouse(); + 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(); + } + } +} From 94ad63de1194dd9fe1b2a12e9709f292586aaeb0 Mon Sep 17 00:00:00 2001 From: Jeremy Soller Date: Mon, 19 Sep 2016 17:28:22 -0600 Subject: [PATCH 07/17] Remove warnings --- kernel/scheme/debug.rs | 2 +- kernel/scheme/env.rs | 2 +- kernel/scheme/initfs.rs | 2 +- kernel/scheme/irq.rs | 12 ++++++------ 4 files changed, 9 insertions(+), 9 deletions(-) diff --git a/kernel/scheme/debug.rs b/kernel/scheme/debug.rs index 0dc6726..c3b77d8 100644 --- a/kernel/scheme/debug.rs +++ b/kernel/scheme/debug.rs @@ -62,7 +62,7 @@ impl Scheme for DebugScheme { Ok(buffer.len()) } - fn fsync(&mut self, file: usize) -> Result<()> { + fn fsync(&mut self, _file: usize) -> Result<()> { Ok(()) } diff --git a/kernel/scheme/env.rs b/kernel/scheme/env.rs index a04142f..6e57783 100644 --- a/kernel/scheme/env.rs +++ b/kernel/scheme/env.rs @@ -78,7 +78,7 @@ impl Scheme for EnvScheme { Err(Error::NotPermitted) } - fn fsync(&mut self, file: usize) -> Result<()> { + fn fsync(&mut self, _file: usize) -> Result<()> { Ok(()) } diff --git a/kernel/scheme/initfs.rs b/kernel/scheme/initfs.rs index 0a33ce7..96d7d35 100644 --- a/kernel/scheme/initfs.rs +++ b/kernel/scheme/initfs.rs @@ -79,7 +79,7 @@ impl Scheme for InitFsScheme { Err(Error::NotPermitted) } - fn fsync(&mut self, file: usize) -> Result<()> { + fn fsync(&mut self, _file: usize) -> Result<()> { Ok(()) } diff --git a/kernel/scheme/irq.rs b/kernel/scheme/irq.rs index 1720d93..2e762d4 100644 --- a/kernel/scheme/irq.rs +++ b/kernel/scheme/irq.rs @@ -20,7 +20,7 @@ impl Scheme for IrqScheme { } fn dup(&mut self, file: usize) -> Result { - Err(Error::NotPermitted) + Ok(file) } fn read(&mut self, file: usize, buffer: &mut [u8]) -> Result { @@ -32,9 +32,9 @@ impl Scheme for IrqScheme { // 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; } - return Ok(mem::size_of::()); + Ok(mem::size_of::()) } else { - return Ok(0); + Ok(0) } } else { Err(Error::InvalidValue) @@ -49,9 +49,9 @@ impl Scheme for IrqScheme { if ack == current { ACKS.lock()[file] = ack; unsafe { acknowledge(file); } - return Ok(mem::size_of::()); + Ok(mem::size_of::()) } else { - return Ok(0); + Ok(0) } } else { Err(Error::InvalidValue) @@ -62,7 +62,7 @@ impl Scheme for IrqScheme { Ok(()) } - fn close(&mut self, file: usize) -> Result<()> { + fn close(&mut self, _file: usize) -> Result<()> { Ok(()) } } From abdbadfea3fc72c44f474d0f101ca06c2756c89c Mon Sep 17 00:00:00 2001 From: Jeremy Soller Date: Mon, 19 Sep 2016 18:29:28 -0600 Subject: [PATCH 08/17] Minimize locking in schemes. Reenable pcid and ion launch in init. WIP: Userspace schemes --- kernel/scheme/debug.rs | 12 +-- kernel/scheme/env.rs | 40 +++---- kernel/scheme/initfs.rs | 42 ++++---- kernel/scheme/irq.rs | 12 +-- kernel/scheme/mod.rs | 33 +++--- kernel/scheme/user.rs | 217 ++++++++++++++++++++++++++++++++++++++ kernel/syscall/error.rs | 6 ++ kernel/syscall/fs.rs | 109 +++++++++++-------- kernel/syscall/process.rs | 9 +- 9 files changed, 367 insertions(+), 113 deletions(-) create mode 100644 kernel/scheme/user.rs diff --git a/kernel/scheme/debug.rs b/kernel/scheme/debug.rs index c3b77d8..a282191 100644 --- a/kernel/scheme/debug.rs +++ b/kernel/scheme/debug.rs @@ -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<()> { + fn fsync(&self, _file: usize) -> Result<()> { Ok(()) } /// Close the file `number` - fn close(&mut self, _file: usize) -> Result<()> { + fn close(&self, _file: usize) -> Result<()> { Ok(()) } } diff --git a/kernel/scheme/env.rs b/kernel/scheme/env.rs index 6e57783..98c0948 100644 --- a/kernel/scheme/env.rs +++ b/kernel/scheme/env.rs @@ -1,4 +1,6 @@ use collections::BTreeMap; +use core::sync::atomic::{AtomicUsize, Ordering}; +use spin::RwLock; use syscall::{Error, Result}; use super::Scheme; @@ -9,9 +11,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 +26,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 { + fn open(&self, path: &[u8], _flags: usize) -> Result { let data = self.files.get(path).ok_or(Error::NoEntry)?; - 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 +46,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::BadFile)?; (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 +62,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::BadFile)?; let mut i = 0; while i < buffer.len() && handle.seek < handle.data.len() { @@ -74,15 +76,15 @@ impl Scheme for EnvScheme { Ok(i) } - fn write(&mut self, _file: usize, _buffer: &[u8]) -> Result { + fn write(&self, _file: usize, _buffer: &[u8]) -> Result { Err(Error::NotPermitted) } - fn fsync(&mut self, _file: usize) -> Result<()> { + fn fsync(&self, _file: usize) -> Result<()> { Ok(()) } - 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::BadFile).and(Ok(())) } } diff --git a/kernel/scheme/initfs.rs b/kernel/scheme/initfs.rs index 96d7d35..186d89d 100644 --- a/kernel/scheme/initfs.rs +++ b/kernel/scheme/initfs.rs @@ -1,4 +1,6 @@ use collections::BTreeMap; +use core::sync::atomic::{AtomicUsize, Ordering}; +use spin::RwLock; use syscall::{Error, Result}; use super::Scheme; @@ -9,9 +11,9 @@ struct Handle { } pub struct InitFsScheme { - next_id: usize, + next_id: AtomicUsize, files: BTreeMap<&'static [u8], &'static [u8]>, - handles: BTreeMap + handles: RwLock> } impl InitFsScheme { @@ -22,23 +24,22 @@ impl InitFsScheme { files.insert(b"bin/ion", include_bytes!("../../build/userspace/ion")); files.insert(b"bin/pcid", include_bytes!("../../build/userspace/pcid")); files.insert(b"bin/ps2d", include_bytes!("../../build/userspace/ps2d")); - files.insert(b"etc/init.rc", b"#initfs:bin/pcid\ninitfs:bin/ps2d\n#initfs:bin/ion"); + files.insert(b"etc/init.rc", b"initfs:bin/pcid\ninitfs:bin/ps2d\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 { + fn open(&self, path: &[u8], _flags: usize) -> Result { let data = self.files.get(path).ok_or(Error::NoEntry)?; - 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 }); @@ -46,15 +47,15 @@ impl Scheme for InitFsScheme { 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::BadFile)?; (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 }); @@ -62,8 +63,9 @@ impl Scheme for InitFsScheme { 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::BadFile)?; let mut i = 0; while i < buffer.len() && handle.seek < handle.data.len() { @@ -75,15 +77,15 @@ impl Scheme for InitFsScheme { Ok(i) } - fn write(&mut self, _file: usize, _buffer: &[u8]) -> Result { + fn write(&self, _file: usize, _buffer: &[u8]) -> Result { Err(Error::NotPermitted) } - fn fsync(&mut self, _file: usize) -> Result<()> { + fn fsync(&self, _file: usize) -> Result<()> { Ok(()) } - 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::BadFile).and(Ok(())) } } diff --git a/kernel/scheme/irq.rs b/kernel/scheme/irq.rs index 2e762d4..41928b0 100644 --- a/kernel/scheme/irq.rs +++ b/kernel/scheme/irq.rs @@ -7,7 +7,7 @@ use super::Scheme; pub struct IrqScheme; impl Scheme for IrqScheme { - fn open(&mut self, path: &[u8], _flags: usize) -> Result { + fn open(&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))?; @@ -19,11 +19,11 @@ impl Scheme for IrqScheme { } } - 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]; @@ -41,7 +41,7 @@ impl Scheme for IrqScheme { } } - fn write(&mut self, file: usize, buffer: &[u8]) -> Result { + 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) }; @@ -58,11 +58,11 @@ impl Scheme for IrqScheme { } } - fn fsync(&mut self, _file: usize) -> Result<()> { + fn fsync(&self, _file: usize) -> Result<()> { Ok(()) } - fn close(&mut self, _file: usize) -> Result<()> { + fn close(&self, _file: usize) -> Result<()> { Ok(()) } } diff --git a/kernel/scheme/mod.rs b/kernel/scheme/mod.rs index 6ca5c13..41e7978 100644 --- a/kernel/scheme/mod.rs +++ b/kernel/scheme/mod.rs @@ -11,7 +11,7 @@ use alloc::boxed::Box; use collections::BTreeMap; -use spin::{Once, Mutex, RwLock, RwLockReadGuard, RwLockWriteGuard}; +use spin::{Once, RwLock, RwLockReadGuard, RwLockWriteGuard}; use syscall::{Error, Result}; @@ -32,12 +32,15 @@ pub mod initfs; /// IRQ handling pub mod irq; +/// 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 +56,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,7 +69,7 @@ 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); } @@ -99,10 +102,10 @@ 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"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) } @@ -121,26 +124,26 @@ 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; + fn open(&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; + fn dup(&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; + fn read(&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; + fn write(&self, file: usize, buffer: &[u8]) -> Result; /// Sync the file descriptor - fn fsync(&mut self, file: usize) -> Result<()>; + fn fsync(&self, file: usize) -> Result<()>; /// Close the file descriptor - fn close(&mut self, file: usize) -> Result<()>; + fn close(&self, file: usize) -> Result<()>; } diff --git a/kernel/scheme/user.rs b/kernel/scheme/user.rs new file mode 100644 index 0000000..23b9c71 --- /dev/null +++ b/kernel/scheme/user.rs @@ -0,0 +1,217 @@ +use alloc::arc::{Arc, Weak}; +use alloc::boxed::Box; + +use collections::{BTreeMap, VecDeque}; + +use core::cell::Cell; +use core::mem::size_of; +use core::ops::DerefMut; +use core::{ptr, slice}; + +use syscall::{Call, Error, Result}; + +use super::Scheme; + +/// UserScheme has to be wrapped +pub struct UserScheme { + next_id: Cell, + todo: VecDeque<(usize, (usize, usize, usize, usize))>, + done: BTreeMap, +} + +impl UserScheme { + fn call(&self, a: Call, b: usize, c: usize, d: usize) -> Result { + let id = self.next_id.get(); + + //TODO: What should be done about collisions in self.todo or self.done? + let mut next_id = id + 1; + if next_id <= 0 { + next_id = 1; + } + self.next_id.set(next_id); + + // println!("{} {}: {} {} {:X} {:X} {:X}", UserScheme.name, id, a, ::syscall::name(a), b, c, d); + + Ok(0) + } + + fn capture(&self, mut physical_address: usize, size: usize, writeable: bool) -> Result { + Ok(0) + } + + fn release(&self, virtual_address: usize) { + + } +} + +impl Scheme for UserScheme { + fn open(&mut self, path: &[u8], flags: usize) -> Result { + let virtual_address = try!(self.capture(path.as_ptr() as usize, path.len(), false)); + + let result = self.call(Call::Open, virtual_address, path.len(), flags); + + self.release(virtual_address); + + result + } + + /* + fn mkdir(&mut self, path: &str, flags: usize) -> Result<()> { + let virtual_address = try!(self.capture(path.as_ptr() as usize, path.len(), false)); + + let result = self.call(Call::MkDir, virtual_address, path.len(), flags); + + self.release(virtual_address); + + result.and(Ok(())) + } + + fn rmdir(&mut self, path: &str) -> Result<()> { + let virtual_address = try!(self.capture(path.as_ptr() as usize, path.len(), false)); + + let result = self.call(SYS_RMDIR, virtual_address, path.len(), 0); + + self.release(virtual_address); + + result.and(Ok(())) + } + + fn unlink(&mut self, path: &str) -> Result<()> { + let virtual_address = try!(self.capture(path.as_ptr() as usize, path.len(), false)); + + let result = self.call(SYS_UNLINK, virtual_address, path.len(), 0); + + self.release(virtual_address); + + result.and(Ok(())) + } + */ + + /// Duplicate the resource + fn dup(&mut self, file: usize) -> Result { + self.call(Call::Dup, file, 0, 0) + } + + /* + /// Return the URL of this resource + fn path(&self, file: usize, buf: &mut [u8]) -> Result { + let contexts = unsafe { & *::env().contexts.get() }; + let current = try!(contexts.current()); + if let Ok(physical_address) = current.translate(buf.as_mut_ptr() as usize, buf.len()) { + let offset = physical_address % 4096; + + let virtual_address = try!(self.capture(physical_address - offset, buf.len() + offset, true)); + + let result = self.call(SYS_FPATH, file, virtual_address + offset, buf.len()); + + //println!("Read {:X} mapped from {:X} to {:X} offset {} length {} size {} result {:?}", physical_address, buf.as_ptr() as usize, virtual_address + offset, offset, buf.len(), virtual_size, result); + + self.release(virtual_address); + + result + } else { + println!("{}:{} fault {:X} {}", file!(), line!(), buf.as_ptr() as usize, buf.len()); + Err(Error::Fault) + } + } + */ + + /// Read data to buffer + fn read(&mut self, file: usize, buf: &mut [u8]) -> Result { + /* + let contexts = unsafe { & *::env().contexts.get() }; + let current = try!(contexts.current()); + if let Ok(physical_address) = current.translate(buf.as_mut_ptr() as usize, buf.len()) { + let offset = physical_address % 4096; + + let virtual_address = try!(self.capture(physical_address - offset, buf.len() + offset, true)); + + let result = self.call(Call::Read, file, virtual_address + offset, buf.len()); + + //println!("Read {:X} mapped from {:X} to {:X} offset {} length {} size {} result {:?}", physical_address, buf.as_ptr() as usize, virtual_address + offset, offset, buf.len(), virtual_size, result); + + self.release(virtual_address); + + result + } else */ + { + println!("{}:{} fault {:X} {}", file!(), line!(), buf.as_ptr() as usize, buf.len()); + Err(Error::Fault) + } + } + + /// Write to resource + fn write(&mut self, file: usize, buf: &[u8]) -> Result { + /* + let contexts = unsafe { & *::env().contexts.get() }; + let current = try!(contexts.current()); + if let Ok(physical_address) = current.translate(buf.as_ptr() as usize, buf.len()) { + let offset = physical_address % 4096; + + let virtual_address = try!(self.capture(physical_address - offset, buf.len() + offset, false)); + + let result = self.call(Call::Write, file, virtual_address + offset, buf.len()); + + // println!("Write {:X} mapped from {:X} to {:X} offset {} length {} result {:?}", physical_address, buf.as_ptr() as usize, virtual_address + offset, offset, buf.len(), result); + + self.release(virtual_address); + + result + } else */ + { + println!("{}:{} fault {:X} {}", file!(), line!(), buf.as_ptr() as usize, buf.len()); + Err(Error::Fault) + } + } + + /* + /// Seek + fn seek(&mut self, file: usize, pos: ResourceSeek) -> Result { + let (whence, offset) = match pos { + ResourceSeek::Start(offset) => (SEEK_SET, offset as usize), + ResourceSeek::Current(offset) => (SEEK_CUR, offset as usize), + ResourceSeek::End(offset) => (SEEK_END, offset as usize) + }; + + self.call(SYS_LSEEK, file, offset, whence) + } + + /// Stat the resource + fn stat(&self, file: usize, stat: &mut Stat) -> Result<()> { + let buf = unsafe { slice::from_raw_parts_mut(stat as *mut Stat as *mut u8, size_of::()) }; + + let contexts = unsafe { & *::env().contexts.get() }; + let current = try!(contexts.current()); + if let Ok(physical_address) = current.translate(buf.as_mut_ptr() as usize, buf.len()) { + let offset = physical_address % 4096; + + let virtual_address = try!(self.capture(physical_address - offset, buf.len() + offset, true)); + + let result = self.call(SYS_FSTAT, file, virtual_address + offset, 0); + + self.release(virtual_address); + + result.and(Ok(())) + } else { + println!("{}:{} fault {:X} {}", file!(), line!(), buf.as_ptr() as usize, buf.len()); + Err(Error::Fault) + } + } + */ + + /// Sync the resource + fn fsync(&mut self, file: usize) -> Result<()> { + self.call(Call::FSync, file, 0, 0).and(Ok(())) + } + + /* + /// Truncate the resource + fn truncate(&mut self, file: usize, len: usize) -> Result<()> { + self.call(SYS_FTRUNCATE, file, len, 0).and(Ok(())) + } + */ + + fn close(&mut self, file: usize) -> Result<()> { + self.call(Call::Close, file, 0, 0).and(Ok(())) + } +} diff --git a/kernel/syscall/error.rs b/kernel/syscall/error.rs index ad37b33..e71a8ca 100644 --- a/kernel/syscall/error.rs +++ b/kernel/syscall/error.rs @@ -15,12 +15,18 @@ pub enum Error { BadFile = 9, /// Try again TryAgain = 11, + /// Bad address + Fault = 14, /// File exists FileExists = 17, + /// No such device + NoDevice = 19, /// Invalid argument InvalidValue = 22, /// Too many open files TooManyFiles = 24, + /// Illegal seek + IllegalSeek = 29, /// Syscall not implemented NoCall = 38 } diff --git a/kernel/syscall/fs.rs b/kernel/syscall/fs.rs index d68727d..15a2453 100644 --- a/kernel/syscall/fs.rs +++ b/kernel/syscall/fs.rs @@ -5,6 +5,7 @@ use scheme; 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)?; @@ -14,6 +15,7 @@ pub fn chdir(path: &[u8]) -> Result { 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)?; @@ -27,38 +29,6 @@ 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 = { @@ -74,9 +44,12 @@ pub fn open(path: &[u8], flags: usize) -> Result { 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 (scheme_id, scheme) = { + let schemes = scheme::schemes(); + let (scheme_id, scheme) = schemes.get_name(namespace).ok_or(Error::NoEntry)?; + (scheme_id, scheme.clone()) + }; + let file_id = scheme.open(reference_opt.unwrap_or(b""), flags)?; (scheme_id, file_id) }; @@ -99,9 +72,12 @@ pub fn close(fd: usize) -> Result { 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)); + let scheme = { + let schemes = scheme::schemes(); + let scheme = schemes.get(file.scheme).ok_or(Error::BadFile)?; + scheme.clone() + }; + let result = scheme.close(file.number).and(Ok(0)); result } @@ -115,12 +91,16 @@ pub fn dup(fd: usize) -> Result { file }; - let schemes = scheme::schemes(); - let scheme_mutex = schemes.get(file.scheme).ok_or(Error::BadFile)?; - let result = scheme_mutex.lock().dup(file.number); + let scheme = { + let schemes = scheme::schemes(); + let scheme = schemes.get(file.scheme).ok_or(Error::BadFile)?; + scheme.clone() + }; + let result = scheme.dup(file.number); result } +/// Sync the file descriptor pub fn fsync(fd: usize) -> Result { let file = { let contexts = context::contexts(); @@ -130,8 +110,49 @@ pub fn fsync(fd: usize) -> Result { 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)); + let scheme = { + let schemes = scheme::schemes(); + let scheme = schemes.get(file.scheme).ok_or(Error::BadFile)?; + scheme.clone() + }; + let result = scheme.fsync(file.number).and(Ok(0)); + result +} + +/// 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 scheme = { + let schemes = scheme::schemes(); + let scheme = schemes.get(file.scheme).ok_or(Error::BadFile)?; + scheme.clone() + }; + let result = scheme.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 scheme = { + let schemes = scheme::schemes(); + let scheme = schemes.get(file.scheme).ok_or(Error::BadFile)?; + scheme.clone() + }; + let result = scheme.write(file.number, buf); result } diff --git a/kernel/syscall/process.rs b/kernel/syscall/process.rs index f05271a..081b587 100644 --- a/kernel/syscall/process.rs +++ b/kernel/syscall/process.rs @@ -178,9 +178,12 @@ pub fn clone(flags: usize, stack_base: usize) -> Result { for (fd, file_option) in context.files.lock().iter().enumerate() { if let Some(file) = *file_option { let result = { - let schemes = scheme::schemes(); - let scheme_mutex = schemes.get(file.scheme).ok_or(Error::BadFile)?; - let result = scheme_mutex.lock().dup(file.number); + let scheme = { + let schemes = scheme::schemes(); + let scheme = schemes.get(file.scheme).ok_or(Error::BadFile)?; + scheme.clone() + }; + let result = scheme.dup(file.number); result }; match result { From c512d0437841b39cf616b019fc39eab12e491690 Mon Sep 17 00:00:00 2001 From: Jeremy Soller Date: Mon, 19 Sep 2016 21:24:54 -0600 Subject: [PATCH 09/17] WIP: User scheme --- kernel/scheme/mod.rs | 2 +- kernel/scheme/user.rs | 275 ++++++++++++++-------------------------- kernel/syscall/call.rs | 39 +++--- kernel/syscall/error.rs | 29 +++++ kernel/syscall/mod.rs | 6 +- 5 files changed, 143 insertions(+), 208 deletions(-) diff --git a/kernel/scheme/mod.rs b/kernel/scheme/mod.rs index 41e7978..f4340a0 100644 --- a/kernel/scheme/mod.rs +++ b/kernel/scheme/mod.rs @@ -33,7 +33,7 @@ pub mod initfs; pub mod irq; /// Userspace schemes -//pub mod user; +pub mod user; /// Limit on number of schemes pub const SCHEME_MAX_SCHEMES: usize = 65536; diff --git a/kernel/scheme/user.rs b/kernel/scheme/user.rs index 23b9c71..6ff446a 100644 --- a/kernel/scheme/user.rs +++ b/kernel/scheme/user.rs @@ -1,217 +1,126 @@ -use alloc::arc::{Arc, Weak}; -use alloc::boxed::Box; - use collections::{BTreeMap, VecDeque}; +use core::sync::atomic::{AtomicUsize, Ordering}; +use core::{mem, usize}; +use spin::RwLock; -use core::cell::Cell; -use core::mem::size_of; -use core::ops::DerefMut; -use core::{ptr, slice}; - -use syscall::{Call, Error, Result}; +use context; +use syscall::{convert_to_result, Call, Error, Result}; use super::Scheme; +#[derive(Copy, Clone, Debug)] +#[repr(packed)] +pub struct Packet { + pub id: usize, + pub a: usize, + pub b: usize, + pub c: usize, + pub d: usize +} + /// UserScheme has to be wrapped pub struct UserScheme { - next_id: Cell, - todo: VecDeque<(usize, (usize, usize, usize, usize))>, - done: BTreeMap, + next_id: AtomicUsize, + todo: RwLock>, + done: RwLock> } impl UserScheme { fn call(&self, a: Call, b: usize, c: usize, d: usize) -> Result { - let id = self.next_id.get(); + let id = self.next_id.fetch_add(1, Ordering::SeqCst); - //TODO: What should be done about collisions in self.todo or self.done? - let mut next_id = id + 1; - if next_id <= 0 { - next_id = 1; + self.todo.write().push_back(Packet { + id: id, + a: a as usize, + b: b, + c: c, + d: d + }); + + loop { + if let Some(a) = self.done.write().remove(&id) { + return convert_to_result(a); + } + + unsafe { context::switch(); } } - self.next_id.set(next_id); - - // println!("{} {}: {} {} {:X} {:X} {:X}", UserScheme.name, id, a, ::syscall::name(a), b, c, d); - - Ok(0) - } - - fn capture(&self, mut physical_address: usize, size: usize, writeable: bool) -> Result { - Ok(0) - } - - fn release(&self, virtual_address: usize) { - } } impl Scheme for UserScheme { - fn open(&mut self, path: &[u8], flags: usize) -> Result { - let virtual_address = try!(self.capture(path.as_ptr() as usize, path.len(), false)); - - let result = self.call(Call::Open, virtual_address, path.len(), flags); - - self.release(virtual_address); - - result + fn open(&self, path: &[u8], flags: usize) -> Result { + self.call(Call::Open, path.as_ptr() as usize, path.len(), flags) } - /* - fn mkdir(&mut self, path: &str, flags: usize) -> Result<()> { - let virtual_address = try!(self.capture(path.as_ptr() as usize, path.len(), false)); - - let result = self.call(Call::MkDir, virtual_address, path.len(), flags); - - self.release(virtual_address); - - result.and(Ok(())) - } - - fn rmdir(&mut self, path: &str) -> Result<()> { - let virtual_address = try!(self.capture(path.as_ptr() as usize, path.len(), false)); - - let result = self.call(SYS_RMDIR, virtual_address, path.len(), 0); - - self.release(virtual_address); - - result.and(Ok(())) - } - - fn unlink(&mut self, path: &str) -> Result<()> { - let virtual_address = try!(self.capture(path.as_ptr() as usize, path.len(), false)); - - let result = self.call(SYS_UNLINK, virtual_address, path.len(), 0); - - self.release(virtual_address); - - result.and(Ok(())) - } - */ - - /// Duplicate the resource - fn dup(&mut self, file: usize) -> Result { - self.call(Call::Dup, file, 0, 0) - } - - /* - /// Return the URL of this resource - fn path(&self, file: usize, buf: &mut [u8]) -> Result { - let contexts = unsafe { & *::env().contexts.get() }; - let current = try!(contexts.current()); - if let Ok(physical_address) = current.translate(buf.as_mut_ptr() as usize, buf.len()) { - let offset = physical_address % 4096; - - let virtual_address = try!(self.capture(physical_address - offset, buf.len() + offset, true)); - - let result = self.call(SYS_FPATH, file, virtual_address + offset, buf.len()); - - //println!("Read {:X} mapped from {:X} to {:X} offset {} length {} size {} result {:?}", physical_address, buf.as_ptr() as usize, virtual_address + offset, offset, buf.len(), virtual_size, result); - - self.release(virtual_address); - - result + fn dup(&self, file: usize) -> Result { + if file == usize::MAX { + Ok(file) } else { - println!("{}:{} fault {:X} {}", file!(), line!(), buf.as_ptr() as usize, buf.len()); - Err(Error::Fault) - } - } - */ - - /// Read data to buffer - fn read(&mut self, file: usize, buf: &mut [u8]) -> Result { - /* - let contexts = unsafe { & *::env().contexts.get() }; - let current = try!(contexts.current()); - if let Ok(physical_address) = current.translate(buf.as_mut_ptr() as usize, buf.len()) { - let offset = physical_address % 4096; - - let virtual_address = try!(self.capture(physical_address - offset, buf.len() + offset, true)); - - let result = self.call(Call::Read, file, virtual_address + offset, buf.len()); - - //println!("Read {:X} mapped from {:X} to {:X} offset {} length {} size {} result {:?}", physical_address, buf.as_ptr() as usize, virtual_address + offset, offset, buf.len(), virtual_size, result); - - self.release(virtual_address); - - result - } else */ - { - println!("{}:{} fault {:X} {}", file!(), line!(), buf.as_ptr() as usize, buf.len()); - Err(Error::Fault) + self.call(Call::Dup, file, 0, 0) } } - /// Write to resource - fn write(&mut self, file: usize, buf: &[u8]) -> Result { - /* - let contexts = unsafe { & *::env().contexts.get() }; - let current = try!(contexts.current()); - if let Ok(physical_address) = current.translate(buf.as_ptr() as usize, buf.len()) { - let offset = physical_address % 4096; + fn read(&self, file: usize, buf: &mut [u8]) -> Result { + if file == usize::MAX { + 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.write(); + while ! todo.is_empty() && i < len { + unsafe { *(buf.as_mut_ptr() as *mut Packet).offset(i as isize) = todo.pop_front().unwrap(); } + i += 1; + } + } - let virtual_address = try!(self.capture(physical_address - offset, buf.len() + offset, false)); - - let result = self.call(Call::Write, file, virtual_address + offset, buf.len()); - - // println!("Write {:X} mapped from {:X} to {:X} offset {} length {} result {:?}", physical_address, buf.as_ptr() as usize, virtual_address + offset, offset, buf.len(), result); - - self.release(virtual_address); - - result - } else */ - { - println!("{}:{} fault {:X} {}", file!(), line!(), buf.as_ptr() as usize, buf.len()); - Err(Error::Fault) - } - } - - /* - /// Seek - fn seek(&mut self, file: usize, pos: ResourceSeek) -> Result { - let (whence, offset) = match pos { - ResourceSeek::Start(offset) => (SEEK_SET, offset as usize), - ResourceSeek::Current(offset) => (SEEK_CUR, offset as usize), - ResourceSeek::End(offset) => (SEEK_END, offset as usize) - }; - - self.call(SYS_LSEEK, file, offset, whence) - } - - /// Stat the resource - fn stat(&self, file: usize, stat: &mut Stat) -> Result<()> { - let buf = unsafe { slice::from_raw_parts_mut(stat as *mut Stat as *mut u8, size_of::()) }; - - let contexts = unsafe { & *::env().contexts.get() }; - let current = try!(contexts.current()); - if let Ok(physical_address) = current.translate(buf.as_mut_ptr() as usize, buf.len()) { - let offset = physical_address % 4096; - - let virtual_address = try!(self.capture(physical_address - offset, buf.len() + offset, true)); - - let result = self.call(SYS_FSTAT, file, virtual_address + offset, 0); - - self.release(virtual_address); - - result.and(Ok(())) + if i > 0 { + return Ok(i * packet_size); + } else { + unsafe { context::switch(); } + } + } + } else { + Ok(0) + } } else { - println!("{}:{} fault {:X} {}", file!(), line!(), buf.as_ptr() as usize, buf.len()); - Err(Error::Fault) + self.call(Call::Read, file, buf.as_mut_ptr() as usize, buf.len()) } } - */ - /// Sync the resource - fn fsync(&mut self, file: usize) -> Result<()> { - self.call(Call::FSync, file, 0, 0).and(Ok(())) + fn write(&self, file: usize, buf: &[u8]) -> Result { + if file == usize::MAX { + 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.write().insert(packet.id, packet.a); + + i += 1; + } + + Ok(i * packet_size) + } else { + self.call(Call::Write, file, buf.as_ptr() as usize, buf.len()) + } } - /* - /// Truncate the resource - fn truncate(&mut self, file: usize, len: usize) -> Result<()> { - self.call(SYS_FTRUNCATE, file, len, 0).and(Ok(())) + fn fsync(&self, file: usize) -> Result<()> { + if file == usize::MAX { + Ok(()) + } else { + self.call(Call::FSync, file, 0, 0).and(Ok(())) + } } - */ - fn close(&mut self, file: usize) -> Result<()> { - self.call(Call::Close, file, 0, 0).and(Ok(())) + fn close(&self, file: usize) -> Result<()> { + if file == usize::MAX { + println!("Close user scheme"); + Ok(()) + } else { + self.call(Call::Close, file, 0, 0).and(Ok(())) + } } } diff --git a/kernel/syscall/call.rs b/kernel/syscall/call.rs index 3bcefd4..2aa41ae 100644 --- a/kernel/syscall/call.rs +++ b/kernel/syscall/call.rs @@ -1,5 +1,3 @@ -use super::{Error, Result}; - /// System call list /// See http://syscalls.kernelgrok.com/ for numbers #[derive(Copy, Clone, Debug, Eq, PartialEq)] @@ -42,26 +40,25 @@ pub enum Call { /// Convert numbers to calls /// See http://syscalls.kernelgrok.com/ impl Call { - //TODO: Return Option - pub fn from(number: usize) -> Result { + pub fn from(number: usize) -> Option { 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) + 1 => Some(Call::Exit), + 3 => Some(Call::Read), + 4 => Some(Call::Write), + 5 => Some(Call::Open), + 6 => Some(Call::Close), + 7 => Some(Call::WaitPid), + 11 => Some(Call::Exec), + 12 => Some(Call::ChDir), + 20 => Some(Call::GetPid), + 41 => Some(Call::Dup), + 45 => Some(Call::Brk), + 110 => Some(Call::Iopl), + 118 => Some(Call::FSync), + 120 => Some(Call::Clone), + 158 => Some(Call::SchedYield), + 183 => Some(Call::GetCwd), + _ => None } } } diff --git a/kernel/syscall/error.rs b/kernel/syscall/error.rs index e71a8ca..8fcffea 100644 --- a/kernel/syscall/error.rs +++ b/kernel/syscall/error.rs @@ -31,4 +31,33 @@ pub enum Error { NoCall = 38 } +impl Error { + pub fn from(number: usize) -> Option { + match number { + 1 => Some(Error::NotPermitted), + 2 => Some(Error::NoEntry), + 3 => Some(Error::NoProcess), + 8 => Some(Error::NoExec), + 9 => Some(Error::BadFile), + 11 => Some(Error::TryAgain), + 14 => Some(Error::Fault), + 17 => Some(Error::FileExists), + 19 => Some(Error::NoDevice), + 22 => Some(Error::InvalidValue), + 24 => Some(Error::TooManyFiles), + 29 => Some(Error::IllegalSeek), + 38 => Some(Error::NoCall), + _ => None + } + } +} + pub type Result = ::core::result::Result; + +pub fn convert_to_result(number: usize) -> Result { + if let Some(err) = Error::from((-(number as isize)) as usize) { + Err(err) + } else { + Ok(number) + } +} diff --git a/kernel/syscall/mod.rs b/kernel/syscall/mod.rs index 396f366..b76dfbd 100644 --- a/kernel/syscall/mod.rs +++ b/kernel/syscall/mod.rs @@ -26,7 +26,7 @@ pub extern fn syscall(a: usize, b: usize, c: usize, d: usize, e: usize, f: 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 { + Some(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)?), @@ -44,9 +44,9 @@ pub extern fn syscall(a: usize, b: usize, c: usize, d: usize, e: usize, f: usize Call::SchedYield => sched_yield(), Call::GetCwd => getcwd(validate_slice_mut(b as *mut u8, c)?) }, - Err(err) => { + None => { println!("Unknown syscall {}", a); - Err(err) + Err(Error::NoCall) } } } From 791dbfa7ad80d29cec4fe22b78eae37423a05852 Mon Sep 17 00:00:00 2001 From: Jeremy Soller Date: Tue, 20 Sep 2016 08:47:16 -0600 Subject: [PATCH 10/17] Implement user schemes. Example in pcid. Currently deadlocks in UserInner --- Makefile | 2 +- drivers/pcid/src/main.rs | 16 +++- drivers/ps2d/src/keyboard.rs | 2 +- kernel/scheme/mod.rs | 13 ++- kernel/scheme/root.rs | 84 +++++++++++++++++++ kernel/scheme/user.rs | 153 +++++++++++++++++++---------------- libstd | 2 +- syscall/src/lib.rs | 9 ++- syscall/src/scheme.rs | 29 +++++++ 9 files changed, 231 insertions(+), 79 deletions(-) create mode 100644 kernel/scheme/root.rs create mode 100644 syscall/src/scheme.rs diff --git a/Makefile b/Makefile index ac98e50..fc04650 100644 --- a/Makefile +++ b/Makefile @@ -26,7 +26,7 @@ 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/atkbd/Cargo.toml + cargo clean --manifest-path drivers/ps2d/Cargo.toml cargo clean --manifest-path drivers/pcid/Cargo.toml rm -rf build diff --git a/drivers/pcid/src/main.rs b/drivers/pcid/src/main.rs index 0886bef..52f90b1 100644 --- a/drivers/pcid/src/main.rs +++ b/drivers/pcid/src/main.rs @@ -2,8 +2,10 @@ extern crate syscall; +use std::fs::File; +use std::io::{Read, Write}; use std::thread; -use syscall::iopl; +use syscall::{iopl, Packet}; use pci::{Pci, PciBar, PciClass}; @@ -75,5 +77,17 @@ fn main() { unsafe { iopl(3).unwrap() }; enumerate_pci(); + + let mut scheme = File::create(":pci").expect("pcid: failed to create pci scheme"); + loop { + let mut packet = Packet::default(); + scheme.read(&mut packet).expect("pcid: failed to read events from pci scheme"); + + println!("{:?}", packet); + + packet.a = 0; + + scheme.write(&packet).expect("pcid: failed to write responses to pci scheme"); + } }); } diff --git a/drivers/ps2d/src/keyboard.rs b/drivers/ps2d/src/keyboard.rs index 109819a..b0090a3 100644 --- a/drivers/ps2d/src/keyboard.rs +++ b/drivers/ps2d/src/keyboard.rs @@ -5,7 +5,7 @@ use std::thread; use keymap; -pub fn keyboard() { +pub fn keyboard() { let mut file = File::open("irq:1").expect("ps2d: failed to open irq:1"); loop { diff --git a/kernel/scheme/mod.rs b/kernel/scheme/mod.rs index f4340a0..d53688b 100644 --- a/kernel/scheme/mod.rs +++ b/kernel/scheme/mod.rs @@ -19,6 +19,7 @@ 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,6 +33,9 @@ pub mod initfs; /// IRQ handling pub mod irq; +/// Root scheme +pub mod root; + /// Userspace schemes pub mod user; @@ -102,10 +106,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(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"); + 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) } diff --git a/kernel/scheme/root.rs b/kernel/scheme/root.rs new file mode 100644 index 0000000..14cf55e --- /dev/null +++ b/kernel/scheme/root.rs @@ -0,0 +1,84 @@ +use alloc::arc::Arc; +use alloc::boxed::Box; +use collections::BTreeMap; +use core::sync::atomic::{AtomicUsize, Ordering}; +use core::str; +use spin::RwLock; + +use syscall::{Error, Result}; +use scheme::{self, 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 inner = { + let mut schemes = scheme::schemes_mut(); + if schemes.get_name(path).is_some() { + return Err(Error::FileExists); + } + let inner = Arc::new(UserInner::new()); + 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 inner = { + let handles = self.handles.read(); + let inner = handles.get(&file).ok_or(Error::BadFile)?; + inner.clone() + }; + + let id = self.next_id.fetch_add(1, Ordering::SeqCst); + self.handles.write().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::BadFile)?; + 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::BadFile)?; + inner.clone() + }; + + inner.write(buf) + } + + fn fsync(&self, _file: usize) -> Result<()> { + Ok(()) + } + + fn close(&self, file: usize) -> Result<()> { + self.handles.write().remove(&file).ok_or(Error::BadFile).and(Ok(())) + } +} diff --git a/kernel/scheme/user.rs b/kernel/scheme/user.rs index 6ff446a..691ae02 100644 --- a/kernel/scheme/user.rs +++ b/kernel/scheme/user.rs @@ -1,7 +1,8 @@ +use alloc::arc::Weak; use collections::{BTreeMap, VecDeque}; use core::sync::atomic::{AtomicUsize, Ordering}; use core::{mem, usize}; -use spin::RwLock; +use spin::Mutex; use context; use syscall::{convert_to_result, Call, Error, Result}; @@ -18,109 +19,125 @@ pub struct Packet { pub d: usize } -/// UserScheme has to be wrapped -pub struct UserScheme { +pub struct UserInner { next_id: AtomicUsize, - todo: RwLock>, - done: RwLock> + todo: Mutex>, + done: Mutex> } -impl UserScheme { - fn call(&self, a: Call, b: usize, c: usize, d: usize) -> Result { +impl UserInner { + pub fn new() -> UserInner { + UserInner { + next_id: AtomicUsize::new(0), + todo: Mutex::new(VecDeque::new()), + done: Mutex::new(BTreeMap::new()) + } + } + + pub fn call(&self, a: Call, b: usize, c: usize, d: usize) -> Result { let id = self.next_id.fetch_add(1, Ordering::SeqCst); - self.todo.write().push_back(Packet { + let packet = Packet { id: id, a: a as usize, b: b, c: c, d: d - }); + }; + + self.todo.lock().push_back(packet); loop { - if let Some(a) = self.done.write().remove(&id) { + if let Some(a) = self.done.lock().remove(&id) { return convert_to_result(a); } unsafe { context::switch(); } } } + + 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 { - self.call(Call::Open, path.as_ptr() as usize, path.len(), flags) + let inner = self.inner.upgrade().ok_or(Error::NoDevice)?; + inner.call(Call::Open, path.as_ptr() as usize, path.len(), flags) } fn dup(&self, file: usize) -> Result { - if file == usize::MAX { - Ok(file) - } else { - self.call(Call::Dup, file, 0, 0) - } + let inner = self.inner.upgrade().ok_or(Error::NoDevice)?; + inner.call(Call::Dup, file, 0, 0) } fn read(&self, file: usize, buf: &mut [u8]) -> Result { - if file == usize::MAX { - 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.write(); - while ! todo.is_empty() && i < len { - unsafe { *(buf.as_mut_ptr() as *mut Packet).offset(i as isize) = todo.pop_front().unwrap(); } - i += 1; - } - } - - if i > 0 { - return Ok(i * packet_size); - } else { - unsafe { context::switch(); } - } - } - } else { - Ok(0) - } - } else { - self.call(Call::Read, file, buf.as_mut_ptr() as usize, buf.len()) - } + let inner = self.inner.upgrade().ok_or(Error::NoDevice)?; + inner.call(Call::Read, file, buf.as_mut_ptr() as usize, buf.len()) } fn write(&self, file: usize, buf: &[u8]) -> Result { - if file == usize::MAX { - 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.write().insert(packet.id, packet.a); - - i += 1; - } - - Ok(i * packet_size) - } else { - self.call(Call::Write, file, buf.as_ptr() as usize, buf.len()) - } + let inner = self.inner.upgrade().ok_or(Error::NoDevice)?; + inner.call(Call::Write, file, buf.as_ptr() as usize, buf.len()) } fn fsync(&self, file: usize) -> Result<()> { - if file == usize::MAX { - Ok(()) - } else { - self.call(Call::FSync, file, 0, 0).and(Ok(())) - } + let inner = self.inner.upgrade().ok_or(Error::NoDevice)?; + inner.call(Call::FSync, file, 0, 0).and(Ok(())) } fn close(&self, file: usize) -> Result<()> { - if file == usize::MAX { - println!("Close user scheme"); - Ok(()) - } else { - self.call(Call::Close, file, 0, 0).and(Ok(())) - } + let inner = self.inner.upgrade().ok_or(Error::NoDevice)?; + inner.call(Call::Close, file, 0, 0).and(Ok(())) } } diff --git a/libstd b/libstd index 0d434cc..3d771c7 160000 --- a/libstd +++ b/libstd @@ -1 +1 @@ -Subproject commit 0d434cc168b1d88211f1a3b72c8290c911432826 +Subproject commit 3d771c76c4cbd82ad699c59d3bfb645556d90f39 diff --git a/syscall/src/lib.rs b/syscall/src/lib.rs index 800a1db..51032bb 100644 --- a/syscall/src/lib.rs +++ b/syscall/src/lib.rs @@ -3,16 +3,19 @@ pub use self::arch::*; pub use self::error::*; +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 error; +mod error; + +mod scheme; pub const SYS_BRK: usize = 45; pub const SYS_CHDIR: usize = 12; diff --git a/syscall/src/scheme.rs b/syscall/src/scheme.rs new file mode 100644 index 0000000..756fc26 --- /dev/null +++ b/syscall/src/scheme.rs @@ -0,0 +1,29 @@ +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] + } + } +} From d329f7c7d2540fb5bd73624adee6151092248dc8 Mon Sep 17 00:00:00 2001 From: Jeremy Soller Date: Tue, 20 Sep 2016 09:21:54 -0600 Subject: [PATCH 11/17] Fix deadlock --- kernel/scheme/root.rs | 7 +++--- kernel/scheme/user.rs | 8 ++++--- kernel/syscall/mod.rs | 2 ++ kernel/syscall/process.rs | 49 +++++++++++++++++++++------------------ 4 files changed, 37 insertions(+), 29 deletions(-) diff --git a/kernel/scheme/root.rs b/kernel/scheme/root.rs index 14cf55e..23a9e57 100644 --- a/kernel/scheme/root.rs +++ b/kernel/scheme/root.rs @@ -2,7 +2,6 @@ use alloc::arc::Arc; use alloc::boxed::Box; use collections::BTreeMap; use core::sync::atomic::{AtomicUsize, Ordering}; -use core::str; use spin::RwLock; use syscall::{Error, Result}; @@ -24,7 +23,7 @@ impl RootScheme { } impl Scheme for RootScheme { - fn open(&self, path: &[u8], flags: usize) -> Result { + fn open(&self, path: &[u8], _flags: usize) -> Result { let inner = { let mut schemes = scheme::schemes_mut(); if schemes.get_name(path).is_some() { @@ -42,14 +41,14 @@ impl Scheme for RootScheme { } fn dup(&self, file: usize) -> Result { + let mut handles = self.handles.write(); let inner = { - let handles = self.handles.read(); let inner = handles.get(&file).ok_or(Error::BadFile)?; inner.clone() }; let id = self.next_id.fetch_add(1, Ordering::SeqCst); - self.handles.write().insert(id, inner); + handles.insert(id, inner); Ok(id) } diff --git a/kernel/scheme/user.rs b/kernel/scheme/user.rs index 691ae02..c209ecf 100644 --- a/kernel/scheme/user.rs +++ b/kernel/scheme/user.rs @@ -48,8 +48,11 @@ impl UserInner { self.todo.lock().push_back(packet); loop { - if let Some(a) = self.done.lock().remove(&id) { - return convert_to_result(a); + { + let mut done = self.done.lock(); + if let Some(a) = done.remove(&id) { + return convert_to_result(a); + } } unsafe { context::switch(); } @@ -89,7 +92,6 @@ impl UserInner { 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; } diff --git a/kernel/syscall/mod.rs b/kernel/syscall/mod.rs index b76dfbd..9ec87ed 100644 --- a/kernel/syscall/mod.rs +++ b/kernel/syscall/mod.rs @@ -25,6 +25,8 @@ mod validate; 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 { + //println!("{}: {:?}: {} {} {} {}", ::context::context_id(), Call::from(a), a, b, c, d); + match Call::from(a) { Some(call) => match call { Call::Exit => exit(b), diff --git a/kernel/syscall/process.rs b/kernel/syscall/process.rs index 081b587..44175d7 100644 --- a/kernel/syscall/process.rs +++ b/kernel/syscall/process.rs @@ -174,31 +174,36 @@ 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 = { - let scheme = { - let schemes = scheme::schemes(); - let scheme = schemes.get(file.scheme).ok_or(Error::BadFile)?; - scheme.clone() - }; - let result = scheme.dup(file.number); - result + files = Arc::new(Mutex::new(context.files.lock().clone())); + } + } + + 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 = schemes.get(file.scheme).ok_or(Error::BadFile)?; + 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; } } From 2b915953c9cb83f90b9a692bf68789e3baed18b4 Mon Sep 17 00:00:00 2001 From: Jeremy Soller Date: Tue, 20 Sep 2016 09:51:26 -0600 Subject: [PATCH 12/17] Increase buffer size when reading executable, update libstd --- kernel/scheme/user.rs | 2 +- kernel/syscall/process.rs | 4 +++- libstd | 2 +- 3 files changed, 5 insertions(+), 3 deletions(-) diff --git a/kernel/scheme/user.rs b/kernel/scheme/user.rs index c209ecf..7da21d4 100644 --- a/kernel/scheme/user.rs +++ b/kernel/scheme/user.rs @@ -9,7 +9,7 @@ use syscall::{convert_to_result, Call, Error, Result}; use super::Scheme; -#[derive(Copy, Clone, Debug)] +#[derive(Copy, Clone, Debug, Default)] #[repr(packed)] pub struct Packet { pub id: usize, diff --git a/kernel/syscall/process.rs b/kernel/syscall/process.rs index 44175d7..b6be85f 100644 --- a/kernel/syscall/process.rs +++ b/kernel/syscall/process.rs @@ -178,6 +178,8 @@ pub fn clone(flags: usize, stack_base: usize) -> Result { } } + // 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 { @@ -357,7 +359,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]); diff --git a/libstd b/libstd index 3d771c7..ae80aff 160000 --- a/libstd +++ b/libstd @@ -1 +1 @@ -Subproject commit 3d771c76c4cbd82ad699c59d3bfb645556d90f39 +Subproject commit ae80aff4d39b2d3a83f7d32bc95739e4e1169184 From 941fc0b4945b1dda9e4df657dfcc383e47dba65c Mon Sep 17 00:00:00 2001 From: Jeremy Soller Date: Tue, 20 Sep 2016 14:50:04 -0600 Subject: [PATCH 13/17] Grant to allow passing data to scheme handler --- arch/x86_64/src/context.rs | 4 ++ arch/x86_64/src/lib.rs | 6 ++ arch/x86_64/src/paging/mod.rs | 4 ++ arch/x86_64/src/start.rs | 4 +- drivers/pcid/src/main.rs | 3 + kernel/context/context.rs | 5 +- kernel/context/list.rs | 17 +++--- kernel/context/memory.rs | 64 +++++++++++++++++++- kernel/scheme/root.rs | 9 ++- kernel/scheme/user.rs | 108 ++++++++++++++++++++++++++++++++-- 10 files changed, 205 insertions(+), 19 deletions(-) diff --git a/arch/x86_64/src/context.rs b/arch/x86_64/src/context.rs index 09cca9c..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; } diff --git a/arch/x86_64/src/lib.rs b/arch/x86_64/src/lib.rs index c7e5f87..009f722 100644 --- a/arch/x86_64/src/lib.rs +++ b/arch/x86_64/src/lib.rs @@ -59,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; @@ -68,6 +71,9 @@ 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] diff --git a/arch/x86_64/src/paging/mod.rs b/arch/x86_64/src/paging/mod.rs index 249b467..5ebfe11 100644 --- a/arch/x86_64/src/paging/mod.rs +++ b/arch/x86_64/src/paging/mod.rs @@ -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 8774064..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; diff --git a/drivers/pcid/src/main.rs b/drivers/pcid/src/main.rs index 52f90b1..976d02a 100644 --- a/drivers/pcid/src/main.rs +++ b/drivers/pcid/src/main.rs @@ -84,6 +84,9 @@ fn main() { scheme.read(&mut packet).expect("pcid: failed to read events from pci scheme"); println!("{:?}", packet); + if packet.a == 5 { + println!("{}", unsafe { ::std::str::from_utf8_unchecked(::std::slice::from_raw_parts(packet.b as *const u8, packet.c)) }); + } packet.a = 0; 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..22ebbe9 100644 --- a/kernel/context/list.rs +++ b/kernel/context/list.rs @@ -1,3 +1,4 @@ +use alloc::arc::Arc; use collections::BTreeMap; use core::mem; use core::sync::atomic::Ordering; @@ -9,7 +10,7 @@ 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; } @@ -53,13 +54,13 @@ impl ContextList { 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 8f1fecb..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,12 +8,66 @@ 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 } +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>), @@ -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/scheme/root.rs b/kernel/scheme/root.rs index 23a9e57..2264ade 100644 --- a/kernel/scheme/root.rs +++ b/kernel/scheme/root.rs @@ -4,6 +4,7 @@ use collections::BTreeMap; use core::sync::atomic::{AtomicUsize, Ordering}; use spin::RwLock; +use context; use syscall::{Error, Result}; use scheme::{self, Scheme}; use scheme::user::{UserInner, UserScheme}; @@ -24,12 +25,18 @@ impl RootScheme { 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::NoProcess)?; + Arc::downgrade(&context) + }; + let inner = { let mut schemes = scheme::schemes_mut(); if schemes.get_name(path).is_some() { return Err(Error::FileExists); } - let inner = Arc::new(UserInner::new()); + 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 }; diff --git a/kernel/scheme/user.rs b/kernel/scheme/user.rs index 7da21d4..9825f9d 100644 --- a/kernel/scheme/user.rs +++ b/kernel/scheme/user.rs @@ -2,9 +2,13 @@ use alloc::arc::Weak; use collections::{BTreeMap, VecDeque}; use core::sync::atomic::{AtomicUsize, Ordering}; use core::{mem, usize}; -use spin::Mutex; +use spin::{Mutex, RwLock}; -use context; +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::{convert_to_result, Call, Error, Result}; use super::Scheme; @@ -21,14 +25,16 @@ pub struct Packet { pub struct UserInner { next_id: AtomicUsize, + context: Weak>, todo: Mutex>, done: Mutex> } impl UserInner { - pub fn new() -> 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()) } @@ -59,6 +65,87 @@ impl UserInner { } } + 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 { + let context_lock = self.context.upgrade().ok_or(Error::NoProcess)?; + 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 + )); + + return Ok(to_address + offset); + } + + pub fn release(&self, address: usize) -> Result<()> { + let context_lock = self.context.upgrade().ok_or(Error::NoProcess)?; + 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::Fault) + } + pub fn read(&self, buf: &mut [u8]) -> Result { let packet_size = mem::size_of::(); let len = buf.len()/packet_size; @@ -115,7 +202,10 @@ impl UserScheme { impl Scheme for UserScheme { fn open(&self, path: &[u8], flags: usize) -> Result { let inner = self.inner.upgrade().ok_or(Error::NoDevice)?; - inner.call(Call::Open, path.as_ptr() as usize, path.len(), flags) + let address = inner.capture(path)?; + let result = inner.call(Call::Open, address, path.len(), flags); + let _ = inner.release(address); + result } fn dup(&self, file: usize) -> Result { @@ -125,12 +215,18 @@ impl Scheme for UserScheme { fn read(&self, file: usize, buf: &mut [u8]) -> Result { let inner = self.inner.upgrade().ok_or(Error::NoDevice)?; - inner.call(Call::Read, file, buf.as_mut_ptr() as usize, buf.len()) + let address = inner.capture_mut(buf)?; + let result = inner.call(Call::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::NoDevice)?; - inner.call(Call::Write, file, buf.as_ptr() as usize, buf.len()) + let address = inner.capture(buf)?; + let result = inner.call(Call::Write, file, buf.as_ptr() as usize, buf.len()); + let _ = inner.release(address); + result } fn fsync(&self, file: usize) -> Result<()> { From f60661820d3541a05e04a401f848050e710a1bca Mon Sep 17 00:00:00 2001 From: Jeremy Soller Date: Tue, 20 Sep 2016 16:23:28 -0600 Subject: [PATCH 14/17] Create example userspace scheme. Remove kernel duplication of syscalls, use syscall crate instead --- Cargo.toml | 1 + Makefile | 7 ++- drivers/pcid/src/main.rs | 19 +----- drivers/ps2d/src/controller.rs | 4 -- kernel/context/list.rs | 4 +- kernel/scheme/debug.rs | 12 ++-- kernel/scheme/env.rs | 22 +++---- kernel/scheme/initfs.rs | 25 ++++---- kernel/scheme/irq.rs | 22 +++---- kernel/scheme/mod.rs | 36 ++--------- kernel/scheme/root.rs | 23 +++---- kernel/scheme/user.rs | 46 +++++++------- kernel/syscall/call.rs | 64 ------------------- kernel/syscall/error.rs | 63 ------------------- kernel/syscall/fs.rs | 62 +++++++++--------- kernel/syscall/mod.rs | 67 +++++++++----------- kernel/syscall/process.rs | 23 +++---- kernel/syscall/validate.rs | 2 +- kernel/tests/mod.rs | 4 +- schemes/example/Cargo.toml | 6 ++ schemes/example/src/main.rs | 38 +++++++++++ syscall/src/error.rs | 1 + syscall/src/lib.rs | 111 +++++++++++++-------------------- syscall/src/number.rs | 28 +++++++++ syscall/src/scheme.rs | 98 +++++++++++++++++++++++++++++ 25 files changed, 374 insertions(+), 414 deletions(-) delete mode 100644 kernel/syscall/call.rs delete mode 100644 kernel/syscall/error.rs create mode 100644 schemes/example/Cargo.toml create mode 100644 schemes/example/src/main.rs create mode 100644 syscall/src/number.rs 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 fc04650..6bd76aa 100644 --- a/Makefile +++ b/Makefile @@ -28,6 +28,7 @@ clean: 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: @@ -138,4 +139,8 @@ $(BUILD)/ps2d: drivers/ps2d/Cargo.toml drivers/ps2d/src/** $(BUILD)/libstd.rlib $(CARGO) rustc --manifest-path $< $(CARGOFLAGS) -o $@ strip $@ -$(BUILD)/initfs.rs: $(BUILD)/init $(BUILD)/ion $(BUILD)/pcid $(BUILD)/ps2d +$(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/drivers/pcid/src/main.rs b/drivers/pcid/src/main.rs index 976d02a..0886bef 100644 --- a/drivers/pcid/src/main.rs +++ b/drivers/pcid/src/main.rs @@ -2,10 +2,8 @@ extern crate syscall; -use std::fs::File; -use std::io::{Read, Write}; use std::thread; -use syscall::{iopl, Packet}; +use syscall::iopl; use pci::{Pci, PciBar, PciClass}; @@ -77,20 +75,5 @@ fn main() { unsafe { iopl(3).unwrap() }; enumerate_pci(); - - let mut scheme = File::create(":pci").expect("pcid: failed to create pci scheme"); - loop { - let mut packet = Packet::default(); - scheme.read(&mut packet).expect("pcid: failed to read events from pci scheme"); - - println!("{:?}", packet); - if packet.a == 5 { - println!("{}", unsafe { ::std::str::from_utf8_unchecked(::std::slice::from_raw_parts(packet.b as *const u8, packet.c)) }); - } - - packet.a = 0; - - scheme.write(&packet).expect("pcid: failed to write responses to pci scheme"); - } }); } diff --git a/drivers/ps2d/src/controller.rs b/drivers/ps2d/src/controller.rs index 8355dba..e68d4f1 100644 --- a/drivers/ps2d/src/controller.rs +++ b/drivers/ps2d/src/controller.rs @@ -1,9 +1,5 @@ use io::{Io, Pio, ReadOnly, WriteOnly}; -pub unsafe fn init() { - Ps2::new().init(); -} - bitflags! { flags StatusFlags: u8 { const OUTPUT_FULL = 1, diff --git a/kernel/context/list.rs b/kernel/context/list.rs index 22ebbe9..2ad5efb 100644 --- a/kernel/context/list.rs +++ b/kernel/context/list.rs @@ -5,7 +5,7 @@ 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 @@ -48,7 +48,7 @@ impl ContextList { } if self.next_id >= super::CONTEXT_MAX_CONTEXTS { - return Err(Error::TryAgain); + return Err(Error::new(EAGAIN)); } let id = self.next_id; diff --git a/kernel/scheme/debug.rs b/kernel/scheme/debug.rs index a282191..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(); @@ -62,12 +62,12 @@ impl Scheme for DebugScheme { Ok(buffer.len()) } - fn fsync(&self, _file: usize) -> Result<()> { - Ok(()) + fn fsync(&self, _file: usize) -> Result { + Ok(0) } /// Close the file `number` - fn close(&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 98c0948..8448cfe 100644 --- a/kernel/scheme/env.rs +++ b/kernel/scheme/env.rs @@ -2,8 +2,8 @@ use collections::BTreeMap; use core::sync::atomic::{AtomicUsize, Ordering}; use spin::RwLock; -use syscall::{Error, Result}; -use super::Scheme; +use syscall::error::*; +use syscall::scheme::Scheme; struct Handle { data: &'static [u8], @@ -35,7 +35,7 @@ impl EnvScheme { impl Scheme for EnvScheme { fn open(&self, path: &[u8], _flags: usize) -> Result { - let data = self.files.get(path).ok_or(Error::NoEntry)?; + let data = self.files.get(path).ok_or(Error::new(ENOENT))?; let id = self.next_id.fetch_add(1, Ordering::SeqCst); self.handles.write().insert(id, Handle { @@ -49,7 +49,7 @@ impl Scheme for EnvScheme { fn dup(&self, file: usize) -> Result { let (data, seek) = { let handles = self.handles.read(); - let handle = handles.get(&file).ok_or(Error::BadFile)?; + let handle = handles.get(&file).ok_or(Error::new(EBADF))?; (handle.data, handle.seek) }; @@ -64,7 +64,7 @@ impl Scheme for EnvScheme { 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::BadFile)?; + 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() { @@ -76,15 +76,11 @@ impl Scheme for EnvScheme { Ok(i) } - fn write(&self, _file: usize, _buffer: &[u8]) -> Result { - Err(Error::NotPermitted) + fn fsync(&self, _file: usize) -> Result { + Ok(0) } - fn fsync(&self, _file: usize) -> Result<()> { - Ok(()) - } - - fn close(&self, file: usize) -> Result<()> { - self.handles.write().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 186d89d..1380c6e 100644 --- a/kernel/scheme/initfs.rs +++ b/kernel/scheme/initfs.rs @@ -2,8 +2,8 @@ use collections::BTreeMap; use core::sync::atomic::{AtomicUsize, Ordering}; use spin::RwLock; -use syscall::{Error, Result}; -use super::Scheme; +use syscall::error::*; +use syscall::scheme::Scheme; struct Handle { data: &'static [u8], @@ -24,7 +24,8 @@ impl InitFsScheme { files.insert(b"bin/ion", include_bytes!("../../build/userspace/ion")); files.insert(b"bin/pcid", include_bytes!("../../build/userspace/pcid")); files.insert(b"bin/ps2d", include_bytes!("../../build/userspace/ps2d")); - files.insert(b"etc/init.rc", b"initfs:bin/pcid\ninitfs:bin/ps2d\ninitfs:bin/ion"); + 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: AtomicUsize::new(0), @@ -36,7 +37,7 @@ impl InitFsScheme { impl Scheme for InitFsScheme { fn open(&self, path: &[u8], _flags: usize) -> Result { - let data = self.files.get(path).ok_or(Error::NoEntry)?; + let data = self.files.get(path).ok_or(Error::new(ENOENT))?; let id = self.next_id.fetch_add(1, Ordering::SeqCst); self.handles.write().insert(id, Handle { @@ -50,7 +51,7 @@ impl Scheme for InitFsScheme { fn dup(&self, file: usize) -> Result { let (data, seek) = { let handles = self.handles.read(); - let handle = handles.get(&file).ok_or(Error::BadFile)?; + let handle = handles.get(&file).ok_or(Error::new(EBADF))?; (handle.data, handle.seek) }; @@ -65,7 +66,7 @@ impl Scheme for InitFsScheme { 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::BadFile)?; + 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() { @@ -77,15 +78,11 @@ impl Scheme for InitFsScheme { Ok(i) } - fn write(&self, _file: usize, _buffer: &[u8]) -> Result { - Err(Error::NotPermitted) + fn fsync(&self, _file: usize) -> Result { + Ok(0) } - fn fsync(&self, _file: usize) -> Result<()> { - Ok(()) - } - - fn close(&self, file: usize) -> Result<()> { - self.handles.write().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/irq.rs b/kernel/scheme/irq.rs index 41928b0..7ec202a 100644 --- a/kernel/scheme/irq.rs +++ b/kernel/scheme/irq.rs @@ -1,21 +1,21 @@ use core::{mem, str}; use arch::interrupt::irq::{ACKS, COUNTS, acknowledge}; -use syscall::{Error, Result}; -use super::Scheme; +use syscall::error::*; +use syscall::scheme::Scheme; pub struct IrqScheme; impl Scheme for IrqScheme { fn open(&self, path: &[u8], _flags: usize) -> Result { - let path_str = str::from_utf8(path).or(Err(Error::NoEntry))?; + let path_str = str::from_utf8(path).or(Err(Error::new(ENOENT)))?; - let id = path_str.parse::().or(Err(Error::NoEntry))?; + 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)) } } @@ -37,7 +37,7 @@ impl Scheme for IrqScheme { Ok(0) } } else { - Err(Error::InvalidValue) + Err(Error::new(EINVAL)) } } @@ -54,15 +54,15 @@ impl Scheme for IrqScheme { Ok(0) } } else { - Err(Error::InvalidValue) + Err(Error::new(EINVAL)) } } - fn fsync(&self, _file: usize) -> Result<()> { - Ok(()) + fn fsync(&self, _file: usize) -> Result { + Ok(0) } - fn close(&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 d53688b..4d0580a 100644 --- a/kernel/scheme/mod.rs +++ b/kernel/scheme/mod.rs @@ -13,7 +13,8 @@ use collections::BTreeMap; 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; @@ -75,7 +76,7 @@ impl SchemeList { /// Create a new scheme. 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 { @@ -87,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; @@ -123,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(&self, path: &[u8], flags: usize) -> Result; - - /// Duplicate an open file descriptor - /// - /// Returns a file descriptor or an error - fn dup(&self, file: usize) -> Result; - - /// Read from some file descriptor into the `buffer` - /// - /// Returns the number of bytes read - fn read(&self, file: usize, buffer: &mut [u8]) -> Result; - - /// Write the `buffer` to the file descriptor - /// - /// Returns the number of bytes written - fn write(&self, file: usize, buffer: &[u8]) -> Result; - - /// Sync the file descriptor - fn fsync(&self, file: usize) -> Result<()>; - - /// Close the file descriptor - fn close(&self, file: usize) -> Result<()>; -} diff --git a/kernel/scheme/root.rs b/kernel/scheme/root.rs index 2264ade..a2e0060 100644 --- a/kernel/scheme/root.rs +++ b/kernel/scheme/root.rs @@ -5,8 +5,9 @@ use core::sync::atomic::{AtomicUsize, Ordering}; use spin::RwLock; use context; -use syscall::{Error, Result}; -use scheme::{self, Scheme}; +use syscall::error::*; +use syscall::scheme::Scheme; +use scheme; use scheme::user::{UserInner, UserScheme}; pub struct RootScheme { @@ -27,14 +28,14 @@ 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::NoProcess)?; + 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::FileExists); + 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"); @@ -50,7 +51,7 @@ impl Scheme for RootScheme { fn dup(&self, file: usize) -> Result { let mut handles = self.handles.write(); let inner = { - let inner = handles.get(&file).ok_or(Error::BadFile)?; + let inner = handles.get(&file).ok_or(Error::new(EBADF))?; inner.clone() }; @@ -63,7 +64,7 @@ impl Scheme for RootScheme { fn read(&self, file: usize, buf: &mut [u8]) -> Result { let inner = { let handles = self.handles.read(); - let inner = handles.get(&file).ok_or(Error::BadFile)?; + let inner = handles.get(&file).ok_or(Error::new(EBADF))?; inner.clone() }; @@ -73,18 +74,18 @@ impl Scheme for RootScheme { fn write(&self, file: usize, buf: &[u8]) -> Result { let inner = { let handles = self.handles.read(); - let inner = handles.get(&file).ok_or(Error::BadFile)?; + let inner = handles.get(&file).ok_or(Error::new(EBADF))?; inner.clone() }; inner.write(buf) } - fn fsync(&self, _file: usize) -> Result<()> { - Ok(()) + fn fsync(&self, _file: usize) -> Result { + Ok(0) } - fn close(&self, file: usize) -> Result<()> { - self.handles.write().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/user.rs b/kernel/scheme/user.rs index 9825f9d..9d9ae7e 100644 --- a/kernel/scheme/user.rs +++ b/kernel/scheme/user.rs @@ -9,9 +9,9 @@ use arch::paging::{InactivePageTable, Page, VirtualAddress, entry}; use arch::paging::temporary_page::TemporaryPage; use context::{self, Context}; use context::memory::Grant; -use syscall::{convert_to_result, Call, Error, Result}; - -use super::Scheme; +use syscall::error::*; +use syscall::number::*; +use syscall::scheme::Scheme; #[derive(Copy, Clone, Debug, Default)] #[repr(packed)] @@ -40,12 +40,12 @@ impl UserInner { } } - pub fn call(&self, a: Call, b: usize, c: usize, d: usize) -> Result { + 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 as usize, + a: a, b: b, c: c, d: d @@ -57,7 +57,7 @@ impl UserInner { { let mut done = self.done.lock(); if let Some(a) = done.remove(&id) { - return convert_to_result(a); + return Error::demux(a); } } @@ -74,7 +74,7 @@ impl UserInner { } fn capture_inner(&self, address: usize, size: usize, writable: bool) -> Result { - let context_lock = self.context.upgrade().ok_or(Error::NoProcess)?; + let context_lock = self.context.upgrade().ok_or(Error::new(ESRCH))?; let context = context_lock.read(); let mut grants = context.grants.lock(); @@ -125,7 +125,7 @@ impl UserInner { } pub fn release(&self, address: usize) -> Result<()> { - let context_lock = self.context.upgrade().ok_or(Error::NoProcess)?; + let context_lock = self.context.upgrade().ok_or(Error::new(ESRCH))?; let context = context_lock.read(); let mut grants = context.grants.lock(); @@ -143,7 +143,7 @@ impl UserInner { } } - Err(Error::Fault) + Err(Error::new(EFAULT)) } pub fn read(&self, buf: &mut [u8]) -> Result { @@ -201,41 +201,41 @@ impl UserScheme { impl Scheme for UserScheme { fn open(&self, path: &[u8], flags: usize) -> Result { - let inner = self.inner.upgrade().ok_or(Error::NoDevice)?; + let inner = self.inner.upgrade().ok_or(Error::new(ENODEV))?; let address = inner.capture(path)?; - let result = inner.call(Call::Open, address, path.len(), flags); + 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::NoDevice)?; - inner.call(Call::Dup, file, 0, 0) + 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::NoDevice)?; + let inner = self.inner.upgrade().ok_or(Error::new(ENODEV))?; let address = inner.capture_mut(buf)?; - let result = inner.call(Call::Read, file, address, buf.len()); + 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::NoDevice)?; + let inner = self.inner.upgrade().ok_or(Error::new(ENODEV))?; let address = inner.capture(buf)?; - let result = inner.call(Call::Write, file, buf.as_ptr() as usize, buf.len()); + let result = inner.call(SYS_WRITE, file, buf.as_ptr() as usize, buf.len()); let _ = inner.release(address); result } - fn fsync(&self, file: usize) -> Result<()> { - let inner = self.inner.upgrade().ok_or(Error::NoDevice)?; - inner.call(Call::FSync, file, 0, 0).and(Ok(())) + fn fsync(&self, file: usize) -> Result { + let inner = self.inner.upgrade().ok_or(Error::new(ENODEV))?; + inner.call(SYS_FSYNC, file, 0, 0) } - fn close(&self, file: usize) -> Result<()> { - let inner = self.inner.upgrade().ok_or(Error::NoDevice)?; - inner.call(Call::Close, file, 0, 0).and(Ok(())) + 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 2aa41ae..0000000 --- a/kernel/syscall/call.rs +++ /dev/null @@ -1,64 +0,0 @@ -/// 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 { - pub fn from(number: usize) -> Option { - match number { - 1 => Some(Call::Exit), - 3 => Some(Call::Read), - 4 => Some(Call::Write), - 5 => Some(Call::Open), - 6 => Some(Call::Close), - 7 => Some(Call::WaitPid), - 11 => Some(Call::Exec), - 12 => Some(Call::ChDir), - 20 => Some(Call::GetPid), - 41 => Some(Call::Dup), - 45 => Some(Call::Brk), - 110 => Some(Call::Iopl), - 118 => Some(Call::FSync), - 120 => Some(Call::Clone), - 158 => Some(Call::SchedYield), - 183 => Some(Call::GetCwd), - _ => None - } - } -} diff --git a/kernel/syscall/error.rs b/kernel/syscall/error.rs deleted file mode 100644 index 8fcffea..0000000 --- a/kernel/syscall/error.rs +++ /dev/null @@ -1,63 +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, - /// Bad address - Fault = 14, - /// File exists - FileExists = 17, - /// No such device - NoDevice = 19, - /// Invalid argument - InvalidValue = 22, - /// Too many open files - TooManyFiles = 24, - /// Illegal seek - IllegalSeek = 29, - /// Syscall not implemented - NoCall = 38 -} - -impl Error { - pub fn from(number: usize) -> Option { - match number { - 1 => Some(Error::NotPermitted), - 2 => Some(Error::NoEntry), - 3 => Some(Error::NoProcess), - 8 => Some(Error::NoExec), - 9 => Some(Error::BadFile), - 11 => Some(Error::TryAgain), - 14 => Some(Error::Fault), - 17 => Some(Error::FileExists), - 19 => Some(Error::NoDevice), - 22 => Some(Error::InvalidValue), - 24 => Some(Error::TooManyFiles), - 29 => Some(Error::IllegalSeek), - 38 => Some(Error::NoCall), - _ => None - } - } -} - -pub type Result = ::core::result::Result; - -pub fn convert_to_result(number: usize) -> Result { - if let Some(err) = Error::from((-(number as isize)) as usize) { - Err(err) - } else { - Ok(number) - } -} diff --git a/kernel/syscall/fs.rs b/kernel/syscall/fs.rs index 15a2453..a487019 100644 --- a/kernel/syscall/fs.rs +++ b/kernel/syscall/fs.rs @@ -2,13 +2,12 @@ use context; use scheme; - -use super::{Error, Result}; +use syscall::error::*; /// 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; @@ -18,7 +17,7 @@ pub fn chdir(path: &[u8]) -> Result { /// 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; @@ -33,7 +32,7 @@ pub fn getcwd(buf: &mut [u8]) -> Result { 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) }; @@ -43,10 +42,10 @@ 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 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::NoEntry)?; + 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)?; @@ -54,105 +53,100 @@ pub fn open(path: &[u8], flags: 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(); 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 scheme = { let schemes = scheme::schemes(); - let scheme = schemes.get(file.scheme).ok_or(Error::BadFile)?; + let scheme = schemes.get(file.scheme).ok_or(Error::new(EBADF))?; scheme.clone() }; - let result = scheme.close(file.number).and(Ok(0)); - result + 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 scheme = { let schemes = scheme::schemes(); - let scheme = schemes.get(file.scheme).ok_or(Error::BadFile)?; + let scheme = schemes.get(file.scheme).ok_or(Error::new(EBADF))?; scheme.clone() }; - let result = scheme.dup(file.number); - result + scheme.dup(file.number) } /// 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 scheme = { let schemes = scheme::schemes(); - let scheme = schemes.get(file.scheme).ok_or(Error::BadFile)?; + let scheme = schemes.get(file.scheme).ok_or(Error::new(EBADF))?; scheme.clone() }; - let result = scheme.fsync(file.number).and(Ok(0)); - result + scheme.fsync(file.number) } /// 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_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 scheme = { let schemes = scheme::schemes(); - let scheme = schemes.get(file.scheme).ok_or(Error::BadFile)?; + let scheme = schemes.get(file.scheme).ok_or(Error::new(EBADF))?; scheme.clone() }; - let result = scheme.read(file.number, buf); - result + 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::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 scheme = { let schemes = scheme::schemes(); - let scheme = schemes.get(file.scheme).ok_or(Error::BadFile)?; + let scheme = schemes.get(file.scheme).ok_or(Error::new(EBADF))?; scheme.clone() }; - let result = scheme.write(file.number, buf); - result + scheme.write(file.number, buf) } diff --git a/kernel/syscall/mod.rs b/kernel/syscall/mod.rs index 9ec87ed..70400e7 100644 --- a/kernel/syscall/mod.rs +++ b/kernel/syscall/mod.rs @@ -1,60 +1,51 @@ ///! Syscall handlers -pub use self::call::*; -pub use self::error::*; +extern crate syscall; + +pub use self::syscall::{error, number, scheme}; + +use self::error::{Error, Result, ENOSYS}; +use self::number::*; pub use self::fs::*; pub use self::process::*; pub use self::validate::*; -/// System call numbers -mod call; - -/// System error codes -mod error; - /// 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 { - //println!("{}: {:?}: {} {} {} {}", ::context::context_id(), Call::from(a), a, b, c, d); - - match Call::from(a) { - Some(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)?) - }, - None => { + 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_GETPID => getpid(), + 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(Error::NoCall) + 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 b6be85f..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; @@ -186,7 +187,7 @@ pub fn clone(flags: usize, stack_base: usize) -> Result { let result = { let scheme = { let schemes = scheme::schemes(); - let scheme = schemes.get(file.scheme).ok_or(Error::BadFile)?; + let scheme = schemes.get(file.scheme).ok_or(Error::new(EBADF))?; scheme.clone() }; let result = scheme.dup(file.number); @@ -377,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 @@ -478,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)); } } } @@ -489,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) } @@ -512,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 { @@ -525,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..2ba6ef7 100644 --- a/kernel/syscall/validate.rs +++ b/kernel/syscall/validate.rs @@ -1,6 +1,6 @@ use core::slice; -use super::Result; +use syscall::error::*; /// Convert a pointer and length to slice, if valid /// TODO: Check validity 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/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..9c7d3fe --- /dev/null +++ b/schemes/example/src/main.rs @@ -0,0 +1,38 @@ +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"); + scheme.handle(&mut packet); + socket.write(&packet).expect("example: failed to write responses to example scheme"); + } + }); +} 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/lib.rs b/syscall/src/lib.rs index 51032bb..e55ed44 100644 --- a/syscall/src/lib.rs +++ b/syscall/src/lib.rs @@ -3,6 +3,7 @@ pub use self::arch::*; pub use self::error::*; +pub use self::number::*; pub use self::scheme::*; #[cfg(target_arch = "x86")] @@ -13,74 +14,52 @@ mod arch; #[path="x86_64.rs"] mod arch; -mod error; +pub mod error; -mod scheme; +pub mod number; -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 scheme; + +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; #[derive(Copy, Clone, Debug, Default)] #[repr(packed)] 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 index 756fc26..40405c4 100644 --- a/syscall/src/scheme.rs +++ b/syscall/src/scheme.rs @@ -1,6 +1,8 @@ use core::ops::{Deref, DerefMut}; use core::{mem, slice}; +use super::*; + #[derive(Copy, Clone, Debug, Default)] #[repr(packed)] pub struct Packet { @@ -27,3 +29,99 @@ impl DerefMut for Packet { } } } + +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 stat(&self, path: &[u8], stat: &mut Stat) -> 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)) + } +} From ed3170bdcc12742a62d326ac82b6fc781680273c Mon Sep 17 00:00:00 2001 From: Jeremy Soller Date: Tue, 20 Sep 2016 16:57:45 -0600 Subject: [PATCH 15/17] Implement more system calls --- kernel/scheme/env.rs | 16 ++++++++++ kernel/scheme/initfs.rs | 40 ++++++++++++++++------- kernel/scheme/user.rs | 31 +++++++++++------- kernel/syscall/fs.rs | 37 ++++++++++++++++++++++ kernel/syscall/mod.rs | 10 ++++-- syscall/src/data.rs | 69 ++++++++++++++++++++++++++++++++++++++++ syscall/src/flag.rs | 40 +++++++++++++++++++++++ syscall/src/lib.rs | 70 ++++------------------------------------- syscall/src/scheme.rs | 35 +-------------------- 9 files changed, 224 insertions(+), 124 deletions(-) create mode 100644 syscall/src/data.rs create mode 100644 syscall/src/flag.rs diff --git a/kernel/scheme/env.rs b/kernel/scheme/env.rs index 8448cfe..3f3f1f5 100644 --- a/kernel/scheme/env.rs +++ b/kernel/scheme/env.rs @@ -1,8 +1,10 @@ use collections::BTreeMap; +use core::cmp; use core::sync::atomic::{AtomicUsize, Ordering}; use spin::RwLock; use syscall::error::*; +use syscall::flag::{SEEK_SET, SEEK_CUR, SEEK_END}; use syscall::scheme::Scheme; struct Handle { @@ -76,6 +78,20 @@ impl Scheme for EnvScheme { Ok(i) } + 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(&self, _file: usize) -> Result { Ok(0) } diff --git a/kernel/scheme/initfs.rs b/kernel/scheme/initfs.rs index 1380c6e..84df203 100644 --- a/kernel/scheme/initfs.rs +++ b/kernel/scheme/initfs.rs @@ -1,8 +1,10 @@ use collections::BTreeMap; +use core::cmp; use core::sync::atomic::{AtomicUsize, Ordering}; use spin::RwLock; use syscall::error::*; +use syscall::flag::{SEEK_SET, SEEK_CUR, SEEK_END}; use syscall::scheme::Scheme; struct Handle { @@ -48,29 +50,29 @@ impl Scheme for InitFsScheme { Ok(id) } - fn dup(&self, file: usize) -> Result { + fn dup(&self, id: usize) -> Result { let (data, seek) = { let handles = self.handles.read(); - let handle = handles.get(&file).ok_or(Error::new(EBADF))?; + let handle = handles.get(&id).ok_or(Error::new(EBADF))?; (handle.data, handle.seek) }; - let id = self.next_id.fetch_add(1, Ordering::SeqCst); - self.handles.write().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(&self, file: usize, buffer: &mut [u8]) -> Result { + fn read(&self, id: usize, buf: &mut [u8]) -> Result { let mut handles = self.handles.write(); - let mut handle = handles.get_mut(&file).ok_or(Error::new(EBADF))?; + 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; } @@ -78,11 +80,25 @@ impl Scheme for InitFsScheme { Ok(i) } - fn fsync(&self, _file: usize) -> Result { + 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(&self, _id: usize) -> Result { Ok(0) } - fn close(&self, file: usize) -> Result { - self.handles.write().remove(&file).ok_or(Error::new(EBADF)).and(Ok(0)) + fn close(&self, id: usize) -> Result { + self.handles.write().remove(&id).ok_or(Error::new(EBADF)).and(Ok(0)) } } diff --git a/kernel/scheme/user.rs b/kernel/scheme/user.rs index 9d9ae7e..e5a0167 100644 --- a/kernel/scheme/user.rs +++ b/kernel/scheme/user.rs @@ -9,20 +9,11 @@ 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; -#[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 -} - pub struct UserInner { next_id: AtomicUsize, context: Weak>, @@ -224,7 +215,20 @@ impl Scheme for UserScheme { 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, buf.as_ptr() as usize, buf.len()); + 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 } @@ -234,6 +238,11 @@ impl Scheme for UserScheme { 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/fs.rs b/kernel/syscall/fs.rs index a487019..029222b 100644 --- a/kernel/syscall/fs.rs +++ b/kernel/syscall/fs.rs @@ -2,6 +2,7 @@ use context; use scheme; +use syscall::data::Stat; use syscall::error::*; /// Change the current working directory @@ -97,6 +98,24 @@ pub fn dup(fd: usize) -> Result { 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 = { @@ -115,6 +134,24 @@ pub fn fsync(fd: usize) -> Result { 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 = { diff --git a/kernel/syscall/mod.rs b/kernel/syscall/mod.rs index 70400e7..b37a056 100644 --- a/kernel/syscall/mod.rs +++ b/kernel/syscall/mod.rs @@ -2,14 +2,16 @@ extern crate syscall; -pub use self::syscall::{error, number, scheme}; +pub use self::syscall::{data, error, flag, number, scheme}; -use self::error::{Error, Result, ENOSYS}; -use self::number::*; pub use self::fs::*; pub use self::process::*; pub use self::validate::*; +use self::data::Stat; +use self::error::{Error, Result, ENOSYS}; +use self::number::*; + /// Filesystem syscalls pub mod fs; @@ -32,7 +34,9 @@ pub extern fn syscall(a: usize, b: usize, c: usize, d: usize, e: usize, f: usize 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), 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/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 e55ed44..099f61f 100644 --- a/syscall/src/lib.rs +++ b/syscall/src/lib.rs @@ -2,7 +2,9 @@ #![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::*; @@ -14,76 +16,16 @@ mod arch; #[path="x86_64.rs"] mod arch; +pub mod data; + pub mod error; +pub mod flag; + pub mod number; pub mod scheme; -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; - -#[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 -} - -#[derive(Copy, Clone, Debug, Default)] -#[repr(packed)] -pub struct TimeSpec { - pub tv_sec: i64, - pub tv_nsec: i32, -} - pub unsafe fn brk(addr: usize) -> Result { syscall1(SYS_BRK, addr) } diff --git a/syscall/src/scheme.rs b/syscall/src/scheme.rs index 40405c4..6a857d1 100644 --- a/syscall/src/scheme.rs +++ b/syscall/src/scheme.rs @@ -1,35 +1,7 @@ -use core::ops::{Deref, DerefMut}; -use core::{mem, slice}; +use core::slice; use super::*; -#[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] - } - } -} - pub trait Scheme { fn handle(&self, packet: &mut Packet) { packet.a = Error::mux(match packet.a { @@ -69,11 +41,6 @@ pub trait Scheme { Err(Error::new(ENOENT)) } - #[allow(unused_variables)] - fn stat(&self, path: &[u8], stat: &mut Stat) -> Result { - Err(Error::new(ENOENT)) - } - #[allow(unused_variables)] fn unlink(&self, path: &[u8]) -> Result { Err(Error::new(ENOENT)) From be3bcbb878cf110be531a9fea17811fcb55f0e95 Mon Sep 17 00:00:00 2001 From: Jeremy Soller Date: Tue, 20 Sep 2016 17:36:36 -0600 Subject: [PATCH 16/17] Add function for getting mapped page flags --- arch/x86_64/src/paging/mapper.rs | 7 +++++++ 1 file changed, 7 insertions(+) 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; From 8dfd003c727d34f77f030937594bf67c2850a909 Mon Sep 17 00:00:00 2001 From: Jeremy Soller Date: Tue, 20 Sep 2016 18:03:14 -0600 Subject: [PATCH 17/17] Validate memory pointers --- kernel/scheme/user.rs | 118 +++++++++++++++++++----------------- kernel/syscall/validate.rs | 40 +++++++++--- schemes/example/src/main.rs | 1 + 3 files changed, 96 insertions(+), 63 deletions(-) diff --git a/kernel/scheme/user.rs b/kernel/scheme/user.rs index e5a0167..f2c797e 100644 --- a/kernel/scheme/user.rs +++ b/kernel/scheme/user.rs @@ -65,76 +65,84 @@ impl UserInner { } fn capture_inner(&self, address: usize, size: usize, writable: bool) -> Result { - let context_lock = self.context.upgrade().ok_or(Error::new(ESRCH))?; - let context = context_lock.read(); + 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 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 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 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; + 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) } - - grants.push(Grant::new( - VirtualAddress::new(from_address), - VirtualAddress::new(to_address), - full_size, - flags, - &mut new_table, - &mut temporary_page - )); - - return Ok(to_address + offset); } pub fn release(&self, address: usize) -> Result<()> { - let context_lock = self.context.upgrade().ok_or(Error::new(ESRCH))?; - let context = context_lock.read(); + 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 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 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); + 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(()); + return Ok(()); + } } - } - Err(Error::new(EFAULT)) + Err(Error::new(EFAULT)) + } } pub fn read(&self, buf: &mut [u8]) -> Result { diff --git a/kernel/syscall/validate.rs b/kernel/syscall/validate.rs index 2ba6ef7..361f58d 100644 --- a/kernel/syscall/validate.rs +++ b/kernel/syscall/validate.rs @@ -1,15 +1,39 @@ -use core::slice; +use core::{mem, slice}; +use arch::paging::{ActivePageTable, Page, VirtualAddress, entry}; use syscall::error::*; -/// 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) }) +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_mut(ptr: *mut T, len: usize) -> Result<&'static mut [T]> { - Ok(unsafe { slice::from_raw_parts_mut(ptr, len) }) +pub fn validate_slice(ptr: *const T, len: usize) -> Result<&'static [T]> { + 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 +pub fn validate_slice_mut(ptr: *mut T, len: usize) -> Result<&'static mut [T]> { + 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/schemes/example/src/main.rs b/schemes/example/src/main.rs index 9c7d3fe..84fb345 100644 --- a/schemes/example/src/main.rs +++ b/schemes/example/src/main.rs @@ -31,6 +31,7 @@ fn main(){ 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"); }