Merge pull request #7 from redox-os/user_irq
Userspace Schemes and Drivers
This commit is contained in:
		
						commit
						a4ede1d23d
					
				
					 51 changed files with 1431 additions and 648 deletions
				
			
		|  | @ -10,6 +10,7 @@ crate-type = ["staticlib"] | |||
| [dependencies] | ||||
| bitflags = "*" | ||||
| spin = "*" | ||||
| syscall = { path = "syscall/" } | ||||
| 
 | ||||
| [dependencies.goblin] | ||||
| git = "https://github.com/m4b/goblin.git" | ||||
|  |  | |||
							
								
								
									
										12
									
								
								Makefile
									
										
									
									
									
								
							
							
						
						
									
										12
									
								
								Makefile
									
										
									
									
									
								
							|  | @ -26,7 +26,9 @@ clean: | |||
| 	cargo clean --manifest-path libstd/Cargo.toml | ||||
| 	cargo clean --manifest-path init/Cargo.toml | ||||
| 	cargo clean --manifest-path ion/Cargo.toml | ||||
| 	cargo clean --manifest-path drivers/ps2d/Cargo.toml | ||||
| 	cargo clean --manifest-path drivers/pcid/Cargo.toml | ||||
| 	cargo clean --manifest-path schemes/example/Cargo.toml | ||||
| 	rm -rf build | ||||
| 
 | ||||
| FORCE: | ||||
|  | @ -133,4 +135,12 @@ $(BUILD)/pcid: drivers/pcid/Cargo.toml drivers/pcid/src/** $(BUILD)/libstd.rlib | |||
| 	$(CARGO) rustc --manifest-path $< $(CARGOFLAGS) -o $@ | ||||
| 	strip $@ | ||||
| 
 | ||||
| $(BUILD)/initfs.rs: $(BUILD)/init $(BUILD)/ion $(BUILD)/pcid | ||||
| $(BUILD)/ps2d: drivers/ps2d/Cargo.toml drivers/ps2d/src/** $(BUILD)/libstd.rlib | ||||
| 	$(CARGO) rustc --manifest-path $< $(CARGOFLAGS) -o $@ | ||||
| 	strip $@ | ||||
| 
 | ||||
| $(BUILD)/example: schemes/example/Cargo.toml schemes/example/src/** $(BUILD)/libstd.rlib | ||||
| 	$(CARGO) rustc --manifest-path $< $(CARGOFLAGS) -o $@ | ||||
| 	strip $@ | ||||
| 
 | ||||
| $(BUILD)/initfs.rs: $(BUILD)/init $(BUILD)/ion $(BUILD)/pcid $(BUILD)/ps2d $(BUILD)/example | ||||
|  |  | |||
|  | @ -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 = "*" | ||||
| 
 | ||||
|  |  | |||
|  | @ -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) }; | ||||
|  |  | |||
|  | @ -43,6 +43,10 @@ impl Context { | |||
|         } | ||||
|     } | ||||
| 
 | ||||
|     pub fn get_page_table(&self) -> usize { | ||||
|         self.cr3 | ||||
|     } | ||||
| 
 | ||||
|     pub fn set_page_table(&mut self, address: usize) { | ||||
|         self.cr3 = address; | ||||
|     } | ||||
|  | @ -52,6 +56,7 @@ impl Context { | |||
|     } | ||||
| 
 | ||||
|     /// Switch to the next context by restoring its stack and registers
 | ||||
|     #[cold] | ||||
|     #[inline(never)] | ||||
|     #[naked] | ||||
|     pub unsafe fn switch_to(&mut self, next: &mut Context) { | ||||
|  | @ -94,7 +99,12 @@ impl Context { | |||
|         asm!("mov $0, rbp" : "=r"(self.rbp) : : "memory" : "intel", "volatile"); | ||||
|         asm!("mov rbp, $0" : : "r"(next.rbp) : "memory" : "intel", "volatile"); | ||||
| 
 | ||||
|         // Unset global lock, set inside of kernel
 | ||||
|         CONTEXT_SWITCH_LOCK.store(false, Ordering::SeqCst); | ||||
|         asm!("call context_switch_unlock" : : : "memory" : "intel", "volatile"); | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| /// Unset global lock, set inside of kernel
 | ||||
| #[no_mangle] | ||||
| extern fn context_switch_unlock(){ | ||||
|     CONTEXT_SWITCH_LOCK.store(false, Ordering::SeqCst); | ||||
| } | ||||
|  |  | |||
|  | @ -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(); | ||||
| } | ||||
|  |  | |||
|  | @ -1,9 +1,9 @@ | |||
| use spin::Mutex; | ||||
| use x86::io; | ||||
| 
 | ||||
| use device::ps2::{PS2_KEYBOARD, PS2_MOUSE}; | ||||
| use device::serial::{COM1, COM2}; | ||||
| 
 | ||||
| pub static ACKS: Mutex<[usize; 16]> = Mutex::new([0; 16]); | ||||
| pub static COUNTS: Mutex<[usize; 16]> = Mutex::new([0; 16]); | ||||
| 
 | ||||
| #[inline(always)] | ||||
|  | @ -17,6 +17,14 @@ unsafe fn slave_ack() { | |||
|     master_ack(); | ||||
| } | ||||
| 
 | ||||
| pub unsafe fn acknowledge(irq: usize) { | ||||
|     if irq >= 8 { | ||||
|         slave_ack(); | ||||
|     } else { | ||||
|         master_ack(); | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| interrupt!(pit, { | ||||
|     COUNTS.lock()[0] += 1; | ||||
|     master_ack(); | ||||
|  | @ -24,10 +32,6 @@ interrupt!(pit, { | |||
| 
 | ||||
| interrupt!(keyboard, { | ||||
|     COUNTS.lock()[1] += 1; | ||||
|     if let Some(ref mut keyboard) = *PS2_KEYBOARD.lock(){ | ||||
|         keyboard.on_irq(); | ||||
|     } | ||||
|     master_ack(); | ||||
| }); | ||||
| 
 | ||||
| interrupt!(cascade, { | ||||
|  | @ -84,10 +88,6 @@ interrupt!(pci3, { | |||
| 
 | ||||
| interrupt!(mouse, { | ||||
|     COUNTS.lock()[12] += 1; | ||||
|     if let Some(ref mut mouse) = *PS2_MOUSE.lock() { | ||||
|         mouse.on_irq(); | ||||
|     } | ||||
|     slave_ack(); | ||||
| }); | ||||
| 
 | ||||
| interrupt!(fpu, { | ||||
|  |  | |||
|  | @ -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; | ||||
|  | @ -15,6 +15,7 @@ extern crate hole_list_allocator as allocator; | |||
| 
 | ||||
| #[macro_use] | ||||
| extern crate bitflags; | ||||
| extern crate io; | ||||
| extern crate ransid; | ||||
| extern crate spin; | ||||
| pub extern crate x86; | ||||
|  | @ -58,6 +59,9 @@ pub extern crate x86; | |||
|     /// Size of user stack
 | ||||
|     pub const USER_STACK_SIZE: usize = 1024 * 1024; // 1 MB
 | ||||
| 
 | ||||
|     /// Offset to user grants
 | ||||
|     pub const USER_GRANT_OFFSET: usize = USER_STACK_OFFSET + PML4_SIZE; | ||||
| 
 | ||||
|     /// Offset to user temporary image (used when cloning)
 | ||||
|     pub const USER_TMP_OFFSET: usize = USER_STACK_OFFSET + PML4_SIZE; | ||||
| 
 | ||||
|  | @ -67,14 +71,16 @@ pub extern crate x86; | |||
|     /// Offset to user temporary stack (used when cloning)
 | ||||
|     pub const USER_TMP_STACK_OFFSET: usize = USER_TMP_HEAP_OFFSET + PML4_SIZE; | ||||
| 
 | ||||
|     /// Offset to user temporary page for grants
 | ||||
|     pub const USER_TMP_GRANT_OFFSET: usize = USER_TMP_STACK_OFFSET + PML4_SIZE; | ||||
| 
 | ||||
| 
 | ||||
| /// Print to console
 | ||||
| #[macro_export] | ||||
| macro_rules! print { | ||||
|     ($($arg:tt)*) => ({ | ||||
|         use core::fmt::Write; | ||||
|         let mut console = $crate::console::CONSOLE.lock(); | ||||
|         let _ = write!(console, $($arg)*); | ||||
|         let _ = write!($crate::console::CONSOLE.lock(), $($arg)*); | ||||
|     }); | ||||
| } | ||||
| 
 | ||||
|  | @ -199,9 +205,6 @@ pub mod gdt; | |||
| /// Interrupt descriptor table
 | ||||
| pub mod idt; | ||||
| 
 | ||||
| /// IO Handling
 | ||||
| pub mod io; | ||||
| 
 | ||||
| /// Interrupt instructions
 | ||||
| pub mod interrupt; | ||||
| 
 | ||||
|  |  | |||
|  | @ -93,6 +93,13 @@ impl Mapper { | |||
|             .and_then(|p1| p1[page.p1_index()].pointed_frame()) | ||||
|     } | ||||
| 
 | ||||
|     pub fn translate_page_flags(&self, page: Page) -> Option<EntryFlags> { | ||||
|         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<PhysicalAddress> { | ||||
|         let offset = virtual_address.get() % PAGE_SIZE; | ||||
|  |  | |||
|  | @ -133,23 +133,23 @@ pub unsafe fn init(cpu_id: usize, stack_start: usize, stack_end: usize) -> (Acti | |||
|                 } | ||||
|             } | ||||
| 
 | ||||
|             let mut remap = |start: usize, end: usize, flags: EntryFlags, offset: usize| { | ||||
|             let mut remap = |start: usize, end: usize, flags: EntryFlags| { | ||||
|                 if end > start { | ||||
|                     let start_frame = Frame::containing_address(PhysicalAddress::new(start)); | ||||
|                     let end_frame = Frame::containing_address(PhysicalAddress::new(end - 1)); | ||||
|                     for frame in Frame::range_inclusive(start_frame, end_frame) { | ||||
|                         let page = Page::containing_address(VirtualAddress::new(frame.start_address().get() + offset)); | ||||
|                         let page = Page::containing_address(VirtualAddress::new(frame.start_address().get() + ::KERNEL_OFFSET)); | ||||
|                         mapper.map_to(page, frame, flags); | ||||
|                     } | ||||
|                 } | ||||
|             }; | ||||
| 
 | ||||
|             // Remap stack writable, no execute
 | ||||
|             remap(stack_start, stack_end, PRESENT | NO_EXECUTE | WRITABLE, 0); | ||||
|             remap(stack_start - ::KERNEL_OFFSET, stack_end - ::KERNEL_OFFSET, PRESENT | NO_EXECUTE | WRITABLE); | ||||
| 
 | ||||
|             // Remap a section with `flags`
 | ||||
|             let mut remap_section = |start: &u8, end: &u8, flags: EntryFlags| { | ||||
|                 remap(start as *const _ as usize - ::KERNEL_OFFSET, end as *const _ as usize - ::KERNEL_OFFSET, flags, ::KERNEL_OFFSET); | ||||
|                 remap(start as *const _ as usize - ::KERNEL_OFFSET, end as *const _ as usize - ::KERNEL_OFFSET, flags); | ||||
|             }; | ||||
|             // Remap text read-only
 | ||||
|             remap_section(& __text_start, & __text_end, PRESENT); | ||||
|  | @ -211,19 +211,19 @@ pub unsafe fn init_ap(cpu_id: usize, stack_start: usize, stack_end: usize, kerne | |||
|             } | ||||
|         } | ||||
| 
 | ||||
|         let mut remap = |start: usize, end: usize, flags: EntryFlags, offset: usize| { | ||||
|         let mut remap = |start: usize, end: usize, flags: EntryFlags| { | ||||
|             if end > start { | ||||
|                 let start_frame = Frame::containing_address(PhysicalAddress::new(start)); | ||||
|                 let end_frame = Frame::containing_address(PhysicalAddress::new(end - 1)); | ||||
|                 for frame in Frame::range_inclusive(start_frame, end_frame) { | ||||
|                     let page = Page::containing_address(VirtualAddress::new(frame.start_address().get() + offset)); | ||||
|                     let page = Page::containing_address(VirtualAddress::new(frame.start_address().get() + ::KERNEL_OFFSET)); | ||||
|                     mapper.map_to(page, frame, flags); | ||||
|                 } | ||||
|             } | ||||
|         }; | ||||
| 
 | ||||
|         // Remap stack writable, no execute
 | ||||
|         remap(stack_start, stack_end, PRESENT | NO_EXECUTE | WRITABLE, 0); | ||||
|         remap(stack_start - ::KERNEL_OFFSET, stack_end - ::KERNEL_OFFSET, PRESENT | NO_EXECUTE | WRITABLE); | ||||
|     }); | ||||
| 
 | ||||
|     active_table.switch(new_table); | ||||
|  | @ -328,6 +328,10 @@ impl InactivePageTable { | |||
|         InactivePageTable { p4_frame: frame } | ||||
|     } | ||||
| 
 | ||||
|     pub unsafe fn from_address(cr3: usize) -> InactivePageTable { | ||||
|         InactivePageTable { p4_frame: Frame::containing_address(PhysicalAddress::new(cr3)) } | ||||
|     } | ||||
| 
 | ||||
|     pub unsafe fn address(&self) -> usize { | ||||
|         self.p4_frame.start_address().get() | ||||
|     } | ||||
|  |  | |||
|  | @ -12,8 +12,8 @@ use externs::memset; | |||
| use gdt; | ||||
| use idt; | ||||
| use interrupt; | ||||
| use memory::{self, Frame}; | ||||
| use paging::{self, entry, Page, PhysicalAddress, VirtualAddress}; | ||||
| use memory; | ||||
| use paging::{self, entry, Page, VirtualAddress}; | ||||
| 
 | ||||
| /// Test of zero values in BSS.
 | ||||
| static BSS_TEST_ZERO: usize = 0; | ||||
|  | @ -68,8 +68,8 @@ pub unsafe extern fn kstart() -> ! { | |||
|         memory::init(0, &__end as *const u8 as usize - ::KERNEL_OFFSET); | ||||
| 
 | ||||
|         // TODO: allocate a stack
 | ||||
|         let stack_start = 0x00080000; | ||||
|         let stack_end = 0x0009F000; | ||||
|         let stack_start = 0x00080000 + ::KERNEL_OFFSET; | ||||
|         let stack_end = 0x0009F000 + ::KERNEL_OFFSET; | ||||
| 
 | ||||
|         // Initialize paging
 | ||||
|         let (mut active_table, tcb_offset) = paging::init(0, stack_start, stack_end); | ||||
|  | @ -148,7 +148,7 @@ pub unsafe extern fn kstart_ap(cpu_id: usize, page_table: usize, stack_start: us | |||
|         let kernel_table = KERNEL_TABLE.load(Ordering::SeqCst); | ||||
| 
 | ||||
|         // Initialize paging
 | ||||
|         let (mut active_table, tcb_offset) = paging::init_ap(cpu_id, stack_start, stack_end, kernel_table); | ||||
|         let (active_table, tcb_offset) = paging::init_ap(cpu_id, stack_start, stack_end, kernel_table); | ||||
| 
 | ||||
|         // Set up GDT for AP
 | ||||
|         gdt::init(tcb_offset, stack_end); | ||||
|  |  | |||
|  | @ -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: | ||||
|  |  | |||
							
								
								
									
										3
									
								
								drivers/io/Cargo.toml
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										3
									
								
								drivers/io/Cargo.toml
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,3 @@ | |||
| [package] | ||||
| name = "io" | ||||
| version = "0.1.0" | ||||
							
								
								
									
										14
									
								
								drivers/io/src/lib.rs
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										14
									
								
								drivers/io/src/lib.rs
									
										
									
									
									
										Normal file
									
								
							|  | @ -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; | ||||
|  | @ -1,5 +1,4 @@ | |||
| use core::marker::PhantomData; | ||||
| use x86::io; | ||||
| 
 | ||||
| use super::io::Io; | ||||
| 
 | ||||
|  | @ -27,13 +26,19 @@ impl Io for Pio<u8> { | |||
|     /// 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<u16> { | |||
|     /// 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<u32> { | |||
|     /// 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"); | ||||
|         } | ||||
|     } | ||||
| } | ||||
							
								
								
									
										9
									
								
								drivers/ps2d/Cargo.toml
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										9
									
								
								drivers/ps2d/Cargo.toml
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,9 @@ | |||
| [package] | ||||
| name = "ps2d" | ||||
| version = "0.1.0" | ||||
| 
 | ||||
| [dependencies] | ||||
| bitflags = "*" | ||||
| io = { path = "../io/" } | ||||
| spin = "*" | ||||
| syscall = { path = "../../syscall/" } | ||||
|  | @ -1,17 +1,5 @@ | |||
| use core::cmp; | ||||
| use spin::Mutex; | ||||
| 
 | ||||
| use io::{Io, Pio, ReadOnly, WriteOnly}; | ||||
| 
 | ||||
| pub static PS2_KEYBOARD: Mutex<Option<Ps2Keyboard>> = Mutex::new(None); | ||||
| pub static PS2_MOUSE: Mutex<Option<Ps2Mouse>> = Mutex::new(None); | ||||
| 
 | ||||
| pub unsafe fn init() { | ||||
|     let (keyboard, mouse) = Ps2::new().init(); | ||||
|     *PS2_KEYBOARD.lock() = keyboard; | ||||
|     *PS2_MOUSE.lock() = mouse; | ||||
| } | ||||
| 
 | ||||
| bitflags! { | ||||
|     flags StatusFlags: u8 { | ||||
|         const OUTPUT_FULL = 1, | ||||
|  | @ -85,114 +73,6 @@ enum MouseCommandData { | |||
|     SetSampleRate = 0xF3, | ||||
| } | ||||
| 
 | ||||
| bitflags! { | ||||
|     flags MousePacketFlags: u8 { | ||||
|         const LEFT_BUTTON = 1, | ||||
|         const RIGHT_BUTTON = 1 << 1, | ||||
|         const MIDDLE_BUTTON = 1 << 2, | ||||
|         const ALWAYS_ON = 1 << 3, | ||||
|         const X_SIGN = 1 << 4, | ||||
|         const Y_SIGN = 1 << 5, | ||||
|         const X_OVERFLOW = 1 << 6, | ||||
|         const Y_OVERFLOW = 1 << 7 | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| pub struct Ps2Keyboard { | ||||
|     data: ReadOnly<Pio<u8>>, | ||||
|     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<Pio<u8>>, | ||||
|     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<u8>, | ||||
|     status: ReadOnly<Pio<u8>>, | ||||
|  | @ -200,7 +80,7 @@ pub struct Ps2 { | |||
| } | ||||
| 
 | ||||
| impl Ps2 { | ||||
|     const fn new() -> Self { | ||||
|     pub fn new() -> Self { | ||||
|         Ps2 { | ||||
|             data: Pio::new(0x60), | ||||
|             status: ReadOnly::new(Pio::new(0x64)), | ||||
|  | @ -278,7 +158,7 @@ impl Ps2 { | |||
|         self.read() | ||||
|     } | ||||
| 
 | ||||
|     fn init(&mut self) -> (Option<Ps2Keyboard>, Option<Ps2Mouse>) { | ||||
|     pub fn init(&mut self) -> bool { | ||||
|         // Disable devices
 | ||||
|         self.command(Command::DisableFirst); | ||||
|         self.command(Command::DisableSecond); | ||||
|  | @ -328,18 +208,6 @@ impl Ps2 { | |||
|         let mouse_id = self.read(); | ||||
|         let mouse_extra = mouse_id == 3; | ||||
| 
 | ||||
|         // Enable extra buttons, TODO
 | ||||
|         /* | ||||
|         if self.mouse_extra { | ||||
|             print!("SAMPLE 200 {:X}\n", self.mouse_command_data(MouseCommandData::SetSampleRate, 200)); | ||||
|             print!("SAMPLE 200 {:X}\n", self.mouse_command_data(MouseCommandData::SetSampleRate, 200)); | ||||
|             print!("SAMPLE 80 {:X}\n", self.mouse_command_data(MouseCommandData::SetSampleRate, 80)); | ||||
|             print!("GET ID {:X}\n", self.mouse_command(MouseCommand::GetDeviceId)); | ||||
|             let mouse_id = self.read(); | ||||
|             print!("MOUSE ID: {:X} == 0x04\n", mouse_id); | ||||
|         } | ||||
|         */ | ||||
| 
 | ||||
|         // Set sample rate to maximum
 | ||||
|         assert_eq!(self.mouse_command_data(MouseCommandData::SetSampleRate, 200), 0xFA); | ||||
| 
 | ||||
|  | @ -352,6 +220,7 @@ impl Ps2 { | |||
|             let mut config = self.config(); | ||||
|             config.remove(FIRST_DISABLED); | ||||
|             config.remove(SECOND_DISABLED); | ||||
|             config.insert(FIRST_TRANSLATE); | ||||
|             config.insert(FIRST_INTERRUPT); | ||||
|             config.insert(SECOND_INTERRUPT); | ||||
|             self.set_config(config); | ||||
|  | @ -359,6 +228,6 @@ impl Ps2 { | |||
| 
 | ||||
|         self.flush_read(); | ||||
| 
 | ||||
|         (Some(Ps2Keyboard::new()), Some(Ps2Mouse::new(mouse_extra))) | ||||
|         mouse_extra | ||||
|     } | ||||
| } | ||||
							
								
								
									
										34
									
								
								drivers/ps2d/src/keyboard.rs
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										34
									
								
								drivers/ps2d/src/keyboard.rs
									
										
									
									
									
										Normal file
									
								
							|  | @ -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::<usize>() { | ||||
|             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(); | ||||
|         } | ||||
|     } | ||||
| } | ||||
							
								
								
									
										68
									
								
								drivers/ps2d/src/keymap.rs
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										68
									
								
								drivers/ps2d/src/keymap.rs
									
										
									
									
									
										Normal file
									
								
							|  | @ -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' | ||||
|     } | ||||
| } | ||||
							
								
								
									
										42
									
								
								drivers/ps2d/src/main.rs
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										42
									
								
								drivers/ps2d/src/main.rs
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,42 @@ | |||
| #![feature(asm)] | ||||
| 
 | ||||
| #[macro_use] | ||||
| extern crate bitflags; | ||||
| extern crate io; | ||||
| extern crate syscall; | ||||
| 
 | ||||
| use std::thread; | ||||
| 
 | ||||
| use syscall::iopl; | ||||
| 
 | ||||
| mod controller; | ||||
| mod keyboard; | ||||
| mod keymap; | ||||
| mod mouse; | ||||
| 
 | ||||
| fn main() { | ||||
|     unsafe { | ||||
|         iopl(3).expect("ps2d: failed to get I/O permission"); | ||||
|         asm!("cli" :::: "intel", "volatile"); | ||||
|     } | ||||
| 
 | ||||
|     let extra_packet = controller::Ps2::new().init(); | ||||
| 
 | ||||
|     thread::spawn(|| { | ||||
|         unsafe { | ||||
|             iopl(3).expect("ps2d: failed to get I/O permission"); | ||||
|             asm!("cli" :::: "intel", "volatile"); | ||||
|         } | ||||
| 
 | ||||
|         keyboard::keyboard(); | ||||
|     }); | ||||
| 
 | ||||
|     thread::spawn(move || { | ||||
|         unsafe { | ||||
|             iopl(3).expect("ps2d: failed to get I/O permission"); | ||||
|             asm!("cli" :::: "intel", "volatile"); | ||||
|         } | ||||
| 
 | ||||
|         mouse::mouse(extra_packet); | ||||
|     }); | ||||
| } | ||||
							
								
								
									
										73
									
								
								drivers/ps2d/src/mouse.rs
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										73
									
								
								drivers/ps2d/src/mouse.rs
									
										
									
									
									
										Normal file
									
								
							|  | @ -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::<usize>() { | ||||
|             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(); | ||||
|         } | ||||
|     } | ||||
| } | ||||
|  | @ -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<SharedMemory>, | ||||
|     /// User stack
 | ||||
|     pub stack: Option<Memory>, | ||||
|     /// User grants
 | ||||
|     pub grants: Arc<Mutex<Vec<Grant>>>, | ||||
|     /// The current working directory
 | ||||
|     pub cwd: Arc<Mutex<Vec<u8>>>, | ||||
|     /// 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())) | ||||
|         } | ||||
|  |  | |||
|  | @ -1,15 +1,16 @@ | |||
| use alloc::arc::Arc; | ||||
| use collections::BTreeMap; | ||||
| use core::mem; | ||||
| use core::sync::atomic::Ordering; | ||||
| use spin::RwLock; | ||||
| 
 | ||||
| use arch; | ||||
| use syscall::{Result, Error}; | ||||
| use syscall::error::{Result, Error, EAGAIN}; | ||||
| use super::context::Context; | ||||
| 
 | ||||
| /// Context list type
 | ||||
| pub struct ContextList { | ||||
|     map: BTreeMap<usize, RwLock<Context>>, | ||||
|     map: BTreeMap<usize, Arc<RwLock<Context>>>, | ||||
|     next_id: usize | ||||
| } | ||||
| 
 | ||||
|  | @ -23,21 +24,21 @@ impl ContextList { | |||
|     } | ||||
| 
 | ||||
|     /// Get the nth context.
 | ||||
|     pub fn get(&self, id: usize) -> Option<&RwLock<Context>> { | ||||
|     pub fn get(&self, id: usize) -> Option<&Arc<RwLock<Context>>> { | ||||
|         self.map.get(&id) | ||||
|     } | ||||
| 
 | ||||
|     /// Get the current context.
 | ||||
|     pub fn current(&self) -> Option<&RwLock<Context>> { | ||||
|     pub fn current(&self) -> Option<&Arc<RwLock<Context>>> { | ||||
|         self.map.get(&super::CONTEXT_ID.load(Ordering::SeqCst)) | ||||
|     } | ||||
| 
 | ||||
|     pub fn iter(&self) -> ::collections::btree_map::Iter<usize, RwLock<Context>> { | ||||
|     pub fn iter(&self) -> ::collections::btree_map::Iter<usize, Arc<RwLock<Context>>> { | ||||
|         self.map.iter() | ||||
|     } | ||||
| 
 | ||||
|     /// Create a new context.
 | ||||
|     pub fn new_context(&mut self) -> Result<&RwLock<Context>> { | ||||
|     pub fn new_context(&mut self) -> Result<&Arc<RwLock<Context>>> { | ||||
|         if self.next_id >= super::CONTEXT_MAX_CONTEXTS { | ||||
|             self.next_id = 1; | ||||
|         } | ||||
|  | @ -47,19 +48,19 @@ impl ContextList { | |||
|         } | ||||
| 
 | ||||
|         if self.next_id >= super::CONTEXT_MAX_CONTEXTS { | ||||
|             return Err(Error::TryAgain); | ||||
|             return Err(Error::new(EAGAIN)); | ||||
|         } | ||||
| 
 | ||||
|         let id = self.next_id; | ||||
|         self.next_id += 1; | ||||
| 
 | ||||
|         assert!(self.map.insert(id, RwLock::new(Context::new(id))).is_none()); | ||||
|         assert!(self.map.insert(id, Arc::new(RwLock::new(Context::new(id)))).is_none()); | ||||
| 
 | ||||
|         Ok(self.map.get(&id).expect("Failed to insert new context. ID is out of bounds.")) | ||||
|     } | ||||
| 
 | ||||
|     /// Spawn a context from a function.
 | ||||
|     pub fn spawn(&mut self, func: extern fn()) -> Result<&RwLock<Context>> { | ||||
|     pub fn spawn(&mut self, func: extern fn()) -> Result<&Arc<RwLock<Context>>> { | ||||
|         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<RwLock<Context>> { | ||||
|     pub fn remove(&mut self, id: usize) -> Option<Arc<RwLock<Context>>> { | ||||
|         self.map.remove(&id) | ||||
|     } | ||||
| } | ||||
|  |  | |||
|  | @ -1,4 +1,5 @@ | |||
| use alloc::arc::{Arc, Weak}; | ||||
| use collections::VecDeque; | ||||
| use spin::Mutex; | ||||
| 
 | ||||
| use arch::externs::memset; | ||||
|  | @ -7,13 +8,67 @@ use arch::paging::entry::{self, EntryFlags}; | |||
| use arch::paging::temporary_page::TemporaryPage; | ||||
| 
 | ||||
| #[derive(Debug)] | ||||
| pub struct Memory { | ||||
| pub struct Grant { | ||||
|     start: VirtualAddress, | ||||
|     size: usize, | ||||
|     flags: EntryFlags | ||||
| } | ||||
| 
 | ||||
| #[derive(Debug)] | ||||
| impl Grant { | ||||
|     pub fn new(from: VirtualAddress, to: VirtualAddress, size: usize, flags: EntryFlags, new_table: &mut InactivePageTable, temporary_page: &mut TemporaryPage) -> Grant { | ||||
|         let mut active_table = unsafe { ActivePageTable::new() }; | ||||
| 
 | ||||
|         let mut frames = VecDeque::new(); | ||||
| 
 | ||||
|         let start_page = Page::containing_address(from); | ||||
|         let end_page = Page::containing_address(VirtualAddress::new(from.get() + size - 1)); | ||||
|         for page in Page::range_inclusive(start_page, end_page) { | ||||
|             let frame = active_table.translate_page(page).expect("grant references unmapped memory"); | ||||
|             frames.push_back(frame); | ||||
|         } | ||||
| 
 | ||||
|         active_table.with(new_table, temporary_page, |mapper| { | ||||
|             let start_page = Page::containing_address(to); | ||||
|             let end_page = Page::containing_address(VirtualAddress::new(to.get() + size - 1)); | ||||
|             for page in Page::range_inclusive(start_page, end_page) { | ||||
|                 let frame = frames.pop_front().expect("grant did not find enough frames"); | ||||
|                 mapper.map_to(page, frame, flags); | ||||
|             } | ||||
|         }); | ||||
| 
 | ||||
|         Grant { | ||||
|             start: to, | ||||
|             size: size, | ||||
|             flags: flags | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
|     pub fn destroy(self, new_table: &mut InactivePageTable, temporary_page: &mut TemporaryPage) { | ||||
|         let mut active_table = unsafe { ActivePageTable::new() }; | ||||
| 
 | ||||
|         active_table.with(new_table, temporary_page, |mapper| { | ||||
|             let start_page = Page::containing_address(self.start); | ||||
|             let end_page = Page::containing_address(VirtualAddress::new(self.start.get() + self.size - 1)); | ||||
|             for page in Page::range_inclusive(start_page, end_page) { | ||||
|                 mapper.unmap_return(page); | ||||
|             } | ||||
|         }); | ||||
|     } | ||||
| 
 | ||||
|     pub fn start_address(&self) -> VirtualAddress { | ||||
|         self.start | ||||
|     } | ||||
| 
 | ||||
|     pub fn size(&self) -> usize { | ||||
|         self.size | ||||
|     } | ||||
| 
 | ||||
|     pub fn flags(&self) -> EntryFlags { | ||||
|         self.flags | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| #[derive(Clone, Debug)] | ||||
| pub enum SharedMemory { | ||||
|     Owned(Arc<Mutex<Memory>>), | ||||
|     Borrowed(Weak<Mutex<Memory>>) | ||||
|  | @ -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 { | ||||
|  |  | |||
|  | @ -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 { | ||||
|  |  | |||
|  | @ -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<Mutex<VecDeque<u8>>> = Once::new(); | ||||
|  | @ -23,18 +23,18 @@ pub extern fn debug_input(b: u8) { | |||
| pub struct DebugScheme; | ||||
| 
 | ||||
| impl Scheme for DebugScheme { | ||||
|     fn open(&mut self, _path: &[u8], _flags: usize) -> Result<usize> { | ||||
|     fn open(&self, _path: &[u8], _flags: usize) -> Result<usize> { | ||||
|         Ok(0) | ||||
|     } | ||||
| 
 | ||||
|     fn dup(&mut self, _file: usize) -> Result<usize> { | ||||
|     fn dup(&self, _file: usize) -> Result<usize> { | ||||
|         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<usize> { | ||||
|     fn read(&self, _file: usize, buf: &mut [u8]) -> Result<usize> { | ||||
|         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<usize> { | ||||
|     fn write(&self, _file: usize, buffer: &[u8]) -> Result<usize> { | ||||
|         //TODO: Write bytes, do not convert to str
 | ||||
|         print!("{}", unsafe { str::from_utf8_unchecked(buffer) }); | ||||
|         Ok(buffer.len()) | ||||
|     } | ||||
| 
 | ||||
|     fn fsync(&mut self, file: usize) -> Result<()> { | ||||
|         Ok(()) | ||||
|     fn fsync(&self, _file: usize) -> Result<usize> { | ||||
|         Ok(0) | ||||
|     } | ||||
| 
 | ||||
|     /// Close the file `number`
 | ||||
|     fn close(&mut self, _file: usize) -> Result<()> { | ||||
|         Ok(()) | ||||
|     fn close(&self, _file: usize) -> Result<usize> { | ||||
|         Ok(0) | ||||
|     } | ||||
| } | ||||
|  |  | |||
|  | @ -1,7 +1,11 @@ | |||
| use collections::BTreeMap; | ||||
| use core::cmp; | ||||
| use core::sync::atomic::{AtomicUsize, Ordering}; | ||||
| use spin::RwLock; | ||||
| 
 | ||||
| use syscall::{Error, Result}; | ||||
| use super::Scheme; | ||||
| use syscall::error::*; | ||||
| use syscall::flag::{SEEK_SET, SEEK_CUR, SEEK_END}; | ||||
| use syscall::scheme::Scheme; | ||||
| 
 | ||||
| struct Handle { | ||||
|     data: &'static [u8], | ||||
|  | @ -9,9 +13,9 @@ struct Handle { | |||
| } | ||||
| 
 | ||||
| pub struct EnvScheme { | ||||
|     next_id: usize, | ||||
|     next_id: AtomicUsize, | ||||
|     files: BTreeMap<&'static [u8], &'static [u8]>, | ||||
|     handles: BTreeMap<usize, Handle> | ||||
|     handles: RwLock<BTreeMap<usize, Handle>> | ||||
| } | ||||
| 
 | ||||
| impl EnvScheme { | ||||
|  | @ -24,20 +28,19 @@ impl EnvScheme { | |||
|         files.insert(b"LINES", b"30"); | ||||
| 
 | ||||
|         EnvScheme { | ||||
|             next_id: 0, | ||||
|             next_id: AtomicUsize::new(0), | ||||
|             files: files, | ||||
|             handles: BTreeMap::new() | ||||
|             handles: RwLock::new(BTreeMap::new()) | ||||
|         } | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| impl Scheme for EnvScheme { | ||||
|     fn open(&mut self, path: &[u8], _flags: usize) -> Result<usize> { | ||||
|         let data = self.files.get(path).ok_or(Error::NoEntry)?; | ||||
|     fn open(&self, path: &[u8], _flags: usize) -> Result<usize> { | ||||
|         let data = self.files.get(path).ok_or(Error::new(ENOENT))?; | ||||
| 
 | ||||
|         let id = self.next_id; | ||||
|         self.next_id += 1; | ||||
|         self.handles.insert(id, Handle { | ||||
|         let id = self.next_id.fetch_add(1, Ordering::SeqCst); | ||||
|         self.handles.write().insert(id, Handle { | ||||
|             data: data, | ||||
|             seek: 0 | ||||
|         }); | ||||
|  | @ -45,15 +48,15 @@ impl Scheme for EnvScheme { | |||
|         Ok(id) | ||||
|     } | ||||
| 
 | ||||
|     fn dup(&mut self, file: usize) -> Result<usize> { | ||||
|     fn dup(&self, file: usize) -> Result<usize> { | ||||
|         let (data, seek) = { | ||||
|             let handle = self.handles.get(&file).ok_or(Error::BadFile)?; | ||||
|             let handles = self.handles.read(); | ||||
|             let handle = handles.get(&file).ok_or(Error::new(EBADF))?; | ||||
|             (handle.data, handle.seek) | ||||
|         }; | ||||
| 
 | ||||
|         let id = self.next_id; | ||||
|         self.next_id += 1; | ||||
|         self.handles.insert(id, Handle { | ||||
|         let id = self.next_id.fetch_add(1, Ordering::SeqCst); | ||||
|         self.handles.write().insert(id, Handle { | ||||
|             data: data, | ||||
|             seek: seek | ||||
|         }); | ||||
|  | @ -61,8 +64,9 @@ impl Scheme for EnvScheme { | |||
|         Ok(id) | ||||
|     } | ||||
| 
 | ||||
|     fn read(&mut self, file: usize, buffer: &mut [u8]) -> Result<usize> { | ||||
|         let mut handle = self.handles.get_mut(&file).ok_or(Error::BadFile)?; | ||||
|     fn read(&self, file: usize, buffer: &mut [u8]) -> Result<usize> { | ||||
|         let mut handles = self.handles.write(); | ||||
|         let mut handle = handles.get_mut(&file).ok_or(Error::new(EBADF))?; | ||||
| 
 | ||||
|         let mut i = 0; | ||||
|         while i < buffer.len() && handle.seek < handle.data.len() { | ||||
|  | @ -74,15 +78,25 @@ impl Scheme for EnvScheme { | |||
|         Ok(i) | ||||
|     } | ||||
| 
 | ||||
|     fn write(&mut self, _file: usize, _buffer: &[u8]) -> Result<usize> { | ||||
|         Err(Error::NotPermitted) | ||||
|     fn seek(&self, id: usize, pos: usize, whence: usize) -> Result<usize> { | ||||
|         let mut handles = self.handles.write(); | ||||
|         let mut handle = handles.get_mut(&id).ok_or(Error::new(EBADF))?; | ||||
| 
 | ||||
|         handle.seek = match whence { | ||||
|             SEEK_SET => cmp::min(handle.data.len(), pos), | ||||
|             SEEK_CUR => cmp::max(0, cmp::min(handle.data.len() as isize, handle.seek as isize + pos as isize)) as usize, | ||||
|             SEEK_END => cmp::max(0, cmp::min(handle.data.len() as isize, handle.data.len() as isize + pos as isize)) as usize, | ||||
|             _ => return Err(Error::new(EINVAL)) | ||||
|         }; | ||||
| 
 | ||||
|         Ok(handle.seek) | ||||
|     } | ||||
| 
 | ||||
|     fn fsync(&mut self, file: usize) -> Result<()> { | ||||
|         Ok(()) | ||||
|     fn fsync(&self, _file: usize) -> Result<usize> { | ||||
|         Ok(0) | ||||
|     } | ||||
| 
 | ||||
|     fn close(&mut self, file: usize) -> Result<()> { | ||||
|         self.handles.remove(&file).ok_or(Error::BadFile).and(Ok(())) | ||||
|     fn close(&self, file: usize) -> Result<usize> { | ||||
|         self.handles.write().remove(&file).ok_or(Error::new(EBADF)).and(Ok(0)) | ||||
|     } | ||||
| } | ||||
|  |  | |||
|  | @ -1,7 +1,11 @@ | |||
| use collections::BTreeMap; | ||||
| use core::cmp; | ||||
| use core::sync::atomic::{AtomicUsize, Ordering}; | ||||
| use spin::RwLock; | ||||
| 
 | ||||
| use syscall::{Error, Result}; | ||||
| use super::Scheme; | ||||
| use syscall::error::*; | ||||
| use syscall::flag::{SEEK_SET, SEEK_CUR, SEEK_END}; | ||||
| use syscall::scheme::Scheme; | ||||
| 
 | ||||
| struct Handle { | ||||
|     data: &'static [u8], | ||||
|  | @ -9,9 +13,9 @@ struct Handle { | |||
| } | ||||
| 
 | ||||
| pub struct InitFsScheme { | ||||
|     next_id: usize, | ||||
|     next_id: AtomicUsize, | ||||
|     files: BTreeMap<&'static [u8], &'static [u8]>, | ||||
|     handles: BTreeMap<usize, Handle> | ||||
|     handles: RwLock<BTreeMap<usize, Handle>> | ||||
| } | ||||
| 
 | ||||
| impl InitFsScheme { | ||||
|  | @ -21,23 +25,24 @@ impl InitFsScheme { | |||
|         files.insert(b"bin/init", include_bytes!("../../build/userspace/init")); | ||||
|         files.insert(b"bin/ion", include_bytes!("../../build/userspace/ion")); | ||||
|         files.insert(b"bin/pcid", include_bytes!("../../build/userspace/pcid")); | ||||
|         files.insert(b"etc/init.rc", b"echo testing\ninitfs:bin/pcid\ninitfs:bin/ion"); | ||||
|         files.insert(b"bin/ps2d", include_bytes!("../../build/userspace/ps2d")); | ||||
|         files.insert(b"bin/example", include_bytes!("../../build/userspace/example")); | ||||
|         files.insert(b"etc/init.rc", b"initfs:bin/pcid\ninitfs:bin/ps2d\ninitfs:bin/example\ninitfs:bin/ion"); | ||||
| 
 | ||||
|         InitFsScheme { | ||||
|             next_id: 0, | ||||
|             next_id: AtomicUsize::new(0), | ||||
|             files: files, | ||||
|             handles: BTreeMap::new() | ||||
|             handles: RwLock::new(BTreeMap::new()) | ||||
|         } | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| impl Scheme for InitFsScheme { | ||||
|     fn open(&mut self, path: &[u8], _flags: usize) -> Result<usize> { | ||||
|         let data = self.files.get(path).ok_or(Error::NoEntry)?; | ||||
|     fn open(&self, path: &[u8], _flags: usize) -> Result<usize> { | ||||
|         let data = self.files.get(path).ok_or(Error::new(ENOENT))?; | ||||
| 
 | ||||
|         let id = self.next_id; | ||||
|         self.next_id += 1; | ||||
|         self.handles.insert(id, Handle { | ||||
|         let id = self.next_id.fetch_add(1, Ordering::SeqCst); | ||||
|         self.handles.write().insert(id, Handle { | ||||
|             data: data, | ||||
|             seek: 0 | ||||
|         }); | ||||
|  | @ -45,28 +50,29 @@ impl Scheme for InitFsScheme { | |||
|         Ok(id) | ||||
|     } | ||||
| 
 | ||||
|     fn dup(&mut self, file: usize) -> Result<usize> { | ||||
|     fn dup(&self, id: usize) -> Result<usize> { | ||||
|         let (data, seek) = { | ||||
|             let handle = self.handles.get(&file).ok_or(Error::BadFile)?; | ||||
|             let handles = self.handles.read(); | ||||
|             let handle = handles.get(&id).ok_or(Error::new(EBADF))?; | ||||
|             (handle.data, handle.seek) | ||||
|         }; | ||||
| 
 | ||||
|         let id = self.next_id; | ||||
|         self.next_id += 1; | ||||
|         self.handles.insert(id, Handle { | ||||
|         let new_id = self.next_id.fetch_add(1, Ordering::SeqCst); | ||||
|         self.handles.write().insert(new_id, Handle { | ||||
|             data: data, | ||||
|             seek: seek | ||||
|         }); | ||||
| 
 | ||||
|         Ok(id) | ||||
|         Ok(new_id) | ||||
|     } | ||||
| 
 | ||||
|     fn read(&mut self, file: usize, buffer: &mut [u8]) -> Result<usize> { | ||||
|         let mut handle = self.handles.get_mut(&file).ok_or(Error::BadFile)?; | ||||
|     fn read(&self, id: usize, buf: &mut [u8]) -> Result<usize> { | ||||
|         let mut handles = self.handles.write(); | ||||
|         let mut handle = handles.get_mut(&id).ok_or(Error::new(EBADF))?; | ||||
| 
 | ||||
|         let mut i = 0; | ||||
|         while i < buffer.len() && handle.seek < handle.data.len() { | ||||
|             buffer[i] = handle.data[handle.seek]; | ||||
|         while i < buf.len() && handle.seek < handle.data.len() { | ||||
|             buf[i] = handle.data[handle.seek]; | ||||
|             i += 1; | ||||
|             handle.seek += 1; | ||||
|         } | ||||
|  | @ -74,15 +80,25 @@ impl Scheme for InitFsScheme { | |||
|         Ok(i) | ||||
|     } | ||||
| 
 | ||||
|     fn write(&mut self, _file: usize, _buffer: &[u8]) -> Result<usize> { | ||||
|         Err(Error::NotPermitted) | ||||
|     fn seek(&self, id: usize, pos: usize, whence: usize) -> Result<usize> { | ||||
|         let mut handles = self.handles.write(); | ||||
|         let mut handle = handles.get_mut(&id).ok_or(Error::new(EBADF))?; | ||||
| 
 | ||||
|         handle.seek = match whence { | ||||
|             SEEK_SET => cmp::min(handle.data.len(), pos), | ||||
|             SEEK_CUR => cmp::max(0, cmp::min(handle.data.len() as isize, handle.seek as isize + pos as isize)) as usize, | ||||
|             SEEK_END => cmp::max(0, cmp::min(handle.data.len() as isize, handle.data.len() as isize + pos as isize)) as usize, | ||||
|             _ => return Err(Error::new(EINVAL)) | ||||
|         }; | ||||
| 
 | ||||
|         Ok(handle.seek) | ||||
|     } | ||||
| 
 | ||||
|     fn fsync(&mut self, file: usize) -> Result<()> { | ||||
|         Ok(()) | ||||
|     fn fsync(&self, _id: usize) -> Result<usize> { | ||||
|         Ok(0) | ||||
|     } | ||||
| 
 | ||||
|     fn close(&mut self, file: usize) -> Result<()> { | ||||
|         self.handles.remove(&file).ok_or(Error::BadFile).and(Ok(())) | ||||
|     fn close(&self, id: usize) -> Result<usize> { | ||||
|         self.handles.write().remove(&id).ok_or(Error::new(EBADF)).and(Ok(0)) | ||||
|     } | ||||
| } | ||||
|  |  | |||
|  | @ -1,57 +1,68 @@ | |||
| use core::{mem, str}; | ||||
| 
 | ||||
| use arch::interrupt::irq::COUNTS; | ||||
| use context; | ||||
| use syscall::{Error, Result}; | ||||
| use super::Scheme; | ||||
| use arch::interrupt::irq::{ACKS, COUNTS, acknowledge}; | ||||
| use syscall::error::*; | ||||
| use syscall::scheme::Scheme; | ||||
| 
 | ||||
| pub struct IrqScheme; | ||||
| 
 | ||||
| impl Scheme for IrqScheme { | ||||
|     fn open(&mut self, path: &[u8], _flags: usize) -> Result<usize> { | ||||
|         let path_str = str::from_utf8(path).or(Err(Error::NoEntry))?; | ||||
|         let id = path_str.parse::<usize>().or(Err(Error::NoEntry))?; | ||||
|     fn open(&self, path: &[u8], _flags: usize) -> Result<usize> { | ||||
|         let path_str = str::from_utf8(path).or(Err(Error::new(ENOENT)))?; | ||||
| 
 | ||||
|         let id = path_str.parse::<usize>().or(Err(Error::new(ENOENT)))?; | ||||
| 
 | ||||
|         if id < COUNTS.lock().len() { | ||||
|             Ok(id) | ||||
|         } else { | ||||
|             Err(Error::NoEntry) | ||||
|             Err(Error::new(ENOENT)) | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
|     fn dup(&mut self, file: usize) -> Result<usize> { | ||||
|     fn dup(&self, file: usize) -> Result<usize> { | ||||
|         Ok(file) | ||||
|     } | ||||
| 
 | ||||
|     fn read(&mut self, file: usize, buffer: &mut [u8]) -> Result<usize> { | ||||
|     fn read(&self, file: usize, buffer: &mut [u8]) -> Result<usize> { | ||||
|         // Ensures that the length of the buffer is larger than the size of a usize
 | ||||
|         if buffer.len() >= mem::size_of::<usize>() { | ||||
|             let ack = ACKS.lock()[file]; | ||||
|             let current = COUNTS.lock()[file]; | ||||
|             loop { | ||||
|                 let next = COUNTS.lock()[file]; | ||||
|                 if next != current { | ||||
|                     // Safe if the length of the buffer is larger than the size of a usize
 | ||||
|                     assert!(buffer.len() >= mem::size_of::<usize>()); | ||||
|                     unsafe { *(buffer.as_mut_ptr() as *mut usize) = next }; | ||||
|                     return Ok(mem::size_of::<usize>()); | ||||
|                 } else { | ||||
|                     // Safe if all locks have been dropped
 | ||||
|                     unsafe { context::switch(); } | ||||
|                 } | ||||
|             if ack != current { | ||||
|                 // Safe if the length of the buffer is larger than the size of a usize
 | ||||
|                 assert!(buffer.len() >= mem::size_of::<usize>()); | ||||
|                 unsafe { *(buffer.as_mut_ptr() as *mut usize) = current; } | ||||
|                 Ok(mem::size_of::<usize>()) | ||||
|             } else { | ||||
|                 Ok(0) | ||||
|             } | ||||
|         } else { | ||||
|             Err(Error::InvalidValue) | ||||
|             Err(Error::new(EINVAL)) | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
|     fn write(&mut self, _file: usize, _buffer: &[u8]) -> Result<usize> { | ||||
|         Err(Error::NotPermitted) | ||||
|     fn write(&self, file: usize, buffer: &[u8]) -> Result<usize> { | ||||
|         if buffer.len() >= mem::size_of::<usize>() { | ||||
|             assert!(buffer.len() >= mem::size_of::<usize>()); | ||||
|             let ack = unsafe { *(buffer.as_ptr() as *const usize) }; | ||||
|             let current = COUNTS.lock()[file]; | ||||
|             if ack == current { | ||||
|                 ACKS.lock()[file] = ack; | ||||
|                 unsafe { acknowledge(file); } | ||||
|                 Ok(mem::size_of::<usize>()) | ||||
|             } else { | ||||
|                 Ok(0) | ||||
|             } | ||||
|         } else { | ||||
|             Err(Error::new(EINVAL)) | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
|     fn fsync(&mut self, file: usize) -> Result<()> { | ||||
|         Ok(()) | ||||
|     fn fsync(&self, _file: usize) -> Result<usize> { | ||||
|         Ok(0) | ||||
|     } | ||||
| 
 | ||||
|     fn close(&mut self, file: usize) -> Result<()> { | ||||
|         Ok(()) | ||||
|     fn close(&self, _file: usize) -> Result<usize> { | ||||
|         Ok(0) | ||||
|     } | ||||
| } | ||||
|  |  | |||
|  | @ -11,14 +11,16 @@ use alloc::boxed::Box; | |||
| 
 | ||||
| use collections::BTreeMap; | ||||
| 
 | ||||
| use spin::{Once, Mutex, RwLock, RwLockReadGuard, RwLockWriteGuard}; | ||||
| use spin::{Once, RwLock, RwLockReadGuard, RwLockWriteGuard}; | ||||
| 
 | ||||
| use syscall::{Error, Result}; | ||||
| use syscall::error::*; | ||||
| use syscall::scheme::Scheme; | ||||
| 
 | ||||
| use self::debug::DebugScheme; | ||||
| use self::env::EnvScheme; | ||||
| use self::initfs::InitFsScheme; | ||||
| use self::irq::IrqScheme; | ||||
| use self::root::RootScheme; | ||||
| 
 | ||||
| /// Debug scheme
 | ||||
| pub mod debug; | ||||
|  | @ -32,12 +34,18 @@ pub mod initfs; | |||
| /// IRQ handling
 | ||||
| pub mod irq; | ||||
| 
 | ||||
| /// Root scheme
 | ||||
| pub mod root; | ||||
| 
 | ||||
| /// Userspace schemes
 | ||||
| pub mod user; | ||||
| 
 | ||||
| /// Limit on number of schemes
 | ||||
| pub const SCHEME_MAX_SCHEMES: usize = 65536; | ||||
| 
 | ||||
| /// Scheme list type
 | ||||
| pub struct SchemeList { | ||||
|     map: BTreeMap<usize, Arc<Mutex<Box<Scheme + Send>>>>, | ||||
|     map: BTreeMap<usize, Arc<Box<Scheme + Send + Sync>>>, | ||||
|     names: BTreeMap<Box<[u8]>, usize>, | ||||
|     next_id: usize | ||||
| } | ||||
|  | @ -53,11 +61,11 @@ impl SchemeList { | |||
|     } | ||||
| 
 | ||||
|     /// Get the nth scheme.
 | ||||
|     pub fn get(&self, id: usize) -> Option<&Arc<Mutex<Box<Scheme + Send>>>> { | ||||
|     pub fn get(&self, id: usize) -> Option<&Arc<Box<Scheme + Send + Sync>>> { | ||||
|         self.map.get(&id) | ||||
|     } | ||||
| 
 | ||||
|     pub fn get_name(&self, name: &[u8]) -> Option<(usize, &Arc<Mutex<Box<Scheme + Send>>>)> { | ||||
|     pub fn get_name(&self, name: &[u8]) -> Option<(usize, &Arc<Box<Scheme + Send + Sync>>)> { | ||||
|         if let Some(&id) = self.names.get(name) { | ||||
|             self.get(id).map(|scheme| (id, scheme)) | ||||
|         } else { | ||||
|  | @ -66,9 +74,9 @@ impl SchemeList { | |||
|     } | ||||
| 
 | ||||
|     /// Create a new scheme.
 | ||||
|     pub fn insert(&mut self, name: Box<[u8]>, scheme: Arc<Mutex<Box<Scheme + Send>>>) -> Result<&Arc<Mutex<Box<Scheme + Send>>>> { | ||||
|     pub fn insert(&mut self, name: Box<[u8]>, scheme: Arc<Box<Scheme + Send + Sync>>) -> Result<&Arc<Box<Scheme + Send + Sync>>> { | ||||
|         if self.names.contains_key(&name) { | ||||
|             return Err(Error::FileExists); | ||||
|             return Err(Error::new(EEXIST)); | ||||
|         } | ||||
| 
 | ||||
|         if self.next_id >= SCHEME_MAX_SCHEMES { | ||||
|  | @ -80,7 +88,7 @@ impl SchemeList { | |||
|         } | ||||
| 
 | ||||
|         if self.next_id >= SCHEME_MAX_SCHEMES { | ||||
|             return Err(Error::TryAgain); | ||||
|             return Err(Error::new(EAGAIN)); | ||||
|         } | ||||
| 
 | ||||
|         let id = self.next_id; | ||||
|  | @ -99,10 +107,11 @@ static SCHEMES: Once<RwLock<SchemeList>> = Once::new(); | |||
| /// Initialize schemes, called if needed
 | ||||
| fn init_schemes() -> RwLock<SchemeList> { | ||||
|     let mut list: SchemeList = SchemeList::new(); | ||||
|     list.insert(Box::new(*b"debug"), Arc::new(Mutex::new(Box::new(DebugScheme)))).expect("failed to insert debug: scheme"); | ||||
|     list.insert(Box::new(*b"env"), Arc::new(Mutex::new(Box::new(EnvScheme::new())))).expect("failed to insert env: scheme"); | ||||
|     list.insert(Box::new(*b"initfs"), Arc::new(Mutex::new(Box::new(InitFsScheme::new())))).expect("failed to insert initfs: scheme"); | ||||
|     list.insert(Box::new(*b"irq"), Arc::new(Mutex::new(Box::new(IrqScheme)))).expect("failed to insert irq: scheme"); | ||||
|     list.insert(Box::new(*b""), Arc::new(Box::new(RootScheme::new()))).expect("failed to insert root scheme"); | ||||
|     list.insert(Box::new(*b"debug"), Arc::new(Box::new(DebugScheme))).expect("failed to insert debug scheme"); | ||||
|     list.insert(Box::new(*b"env"), Arc::new(Box::new(EnvScheme::new()))).expect("failed to insert env scheme"); | ||||
|     list.insert(Box::new(*b"initfs"), Arc::new(Box::new(InitFsScheme::new()))).expect("failed to insert initfs scheme"); | ||||
|     list.insert(Box::new(*b"irq"), Arc::new(Box::new(IrqScheme))).expect("failed to insert irq scheme"); | ||||
|     RwLock::new(list) | ||||
| } | ||||
| 
 | ||||
|  | @ -115,32 +124,3 @@ pub fn schemes() -> RwLockReadGuard<'static, SchemeList> { | |||
| pub fn schemes_mut() -> RwLockWriteGuard<'static, SchemeList> { | ||||
|     SCHEMES.call_once(init_schemes).write() | ||||
| } | ||||
| 
 | ||||
| /// A scheme trait, implemented by a scheme handler
 | ||||
| pub trait Scheme { | ||||
|     /// Open the file at `path` with `flags`.
 | ||||
|     ///
 | ||||
|     /// Returns a file descriptor or an error
 | ||||
|     fn open(&mut self, path: &[u8], flags: usize) -> Result<usize>; | ||||
| 
 | ||||
|     /// Duplicate an open file descriptor
 | ||||
|     ///
 | ||||
|     /// Returns a file descriptor or an error
 | ||||
|     fn dup(&mut self, file: usize) -> Result<usize>; | ||||
| 
 | ||||
|     /// Read from some file descriptor into the `buffer`
 | ||||
|     ///
 | ||||
|     /// Returns the number of bytes read
 | ||||
|     fn read(&mut self, file: usize, buffer: &mut [u8]) -> Result<usize>; | ||||
| 
 | ||||
|     /// Write the `buffer` to the file descriptor
 | ||||
|     ///
 | ||||
|     /// Returns the number of bytes written
 | ||||
|     fn write(&mut self, file: usize, buffer: &[u8]) -> Result<usize>; | ||||
| 
 | ||||
|     /// Sync the file descriptor
 | ||||
|     fn fsync(&mut self, file: usize) -> Result<()>; | ||||
| 
 | ||||
|     /// Close the file descriptor
 | ||||
|     fn close(&mut self, file: usize) -> Result<()>; | ||||
| } | ||||
|  |  | |||
							
								
								
									
										91
									
								
								kernel/scheme/root.rs
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										91
									
								
								kernel/scheme/root.rs
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,91 @@ | |||
| use alloc::arc::Arc; | ||||
| use alloc::boxed::Box; | ||||
| use collections::BTreeMap; | ||||
| use core::sync::atomic::{AtomicUsize, Ordering}; | ||||
| use spin::RwLock; | ||||
| 
 | ||||
| use context; | ||||
| use syscall::error::*; | ||||
| use syscall::scheme::Scheme; | ||||
| use scheme; | ||||
| use scheme::user::{UserInner, UserScheme}; | ||||
| 
 | ||||
| pub struct RootScheme { | ||||
|     next_id: AtomicUsize, | ||||
|     handles: RwLock<BTreeMap<usize, Arc<UserInner>>> | ||||
| } | ||||
| 
 | ||||
| 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<usize> { | ||||
|         let context = { | ||||
|             let contexts = context::contexts(); | ||||
|             let context = contexts.current().ok_or(Error::new(ESRCH))?; | ||||
|             Arc::downgrade(&context) | ||||
|         }; | ||||
| 
 | ||||
|         let inner = { | ||||
|             let mut schemes = scheme::schemes_mut(); | ||||
|             if schemes.get_name(path).is_some() { | ||||
|                 return Err(Error::new(EEXIST)); | ||||
|             } | ||||
|             let inner = Arc::new(UserInner::new(context)); | ||||
|             schemes.insert(path.to_vec().into_boxed_slice(), Arc::new(Box::new(UserScheme::new(Arc::downgrade(&inner))))).expect("failed to insert user scheme"); | ||||
|             inner | ||||
|         }; | ||||
| 
 | ||||
|         let id = self.next_id.fetch_add(1, Ordering::SeqCst); | ||||
|         self.handles.write().insert(id, inner); | ||||
| 
 | ||||
|         Ok(id) | ||||
|     } | ||||
| 
 | ||||
|     fn dup(&self, file: usize) -> Result<usize> { | ||||
|         let mut handles = self.handles.write(); | ||||
|         let inner = { | ||||
|             let inner = handles.get(&file).ok_or(Error::new(EBADF))?; | ||||
|             inner.clone() | ||||
|         }; | ||||
| 
 | ||||
|         let id = self.next_id.fetch_add(1, Ordering::SeqCst); | ||||
|         handles.insert(id, inner); | ||||
| 
 | ||||
|         Ok(id) | ||||
|     } | ||||
| 
 | ||||
|     fn read(&self, file: usize, buf: &mut [u8]) -> Result<usize> { | ||||
|         let inner = { | ||||
|             let handles = self.handles.read(); | ||||
|             let inner = handles.get(&file).ok_or(Error::new(EBADF))?; | ||||
|             inner.clone() | ||||
|         }; | ||||
| 
 | ||||
|         inner.read(buf) | ||||
|     } | ||||
| 
 | ||||
|     fn write(&self, file: usize, buf: &[u8]) -> Result<usize> { | ||||
|         let inner = { | ||||
|             let handles = self.handles.read(); | ||||
|             let inner = handles.get(&file).ok_or(Error::new(EBADF))?; | ||||
|             inner.clone() | ||||
|         }; | ||||
| 
 | ||||
|         inner.write(buf) | ||||
|     } | ||||
| 
 | ||||
|     fn fsync(&self, _file: usize) -> Result<usize> { | ||||
|         Ok(0) | ||||
|     } | ||||
| 
 | ||||
|     fn close(&self, file: usize) -> Result<usize> { | ||||
|         self.handles.write().remove(&file).ok_or(Error::new(EBADF)).and(Ok(0)) | ||||
|     } | ||||
| } | ||||
							
								
								
									
										258
									
								
								kernel/scheme/user.rs
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										258
									
								
								kernel/scheme/user.rs
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,258 @@ | |||
| use alloc::arc::Weak; | ||||
| use collections::{BTreeMap, VecDeque}; | ||||
| use core::sync::atomic::{AtomicUsize, Ordering}; | ||||
| use core::{mem, usize}; | ||||
| use spin::{Mutex, RwLock}; | ||||
| 
 | ||||
| use arch; | ||||
| use arch::paging::{InactivePageTable, Page, VirtualAddress, entry}; | ||||
| use arch::paging::temporary_page::TemporaryPage; | ||||
| use context::{self, Context}; | ||||
| use context::memory::Grant; | ||||
| use syscall::data::{Packet, Stat}; | ||||
| use syscall::error::*; | ||||
| use syscall::number::*; | ||||
| use syscall::scheme::Scheme; | ||||
| 
 | ||||
| pub struct UserInner { | ||||
|     next_id: AtomicUsize, | ||||
|     context: Weak<RwLock<Context>>, | ||||
|     todo: Mutex<VecDeque<Packet>>, | ||||
|     done: Mutex<BTreeMap<usize, usize>> | ||||
| } | ||||
| 
 | ||||
| impl UserInner { | ||||
|     pub fn new(context: Weak<RwLock<Context>>) -> UserInner { | ||||
|         UserInner { | ||||
|             next_id: AtomicUsize::new(0), | ||||
|             context: context, | ||||
|             todo: Mutex::new(VecDeque::new()), | ||||
|             done: Mutex::new(BTreeMap::new()) | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
|     pub fn call(&self, a: usize, b: usize, c: usize, d: usize) -> Result<usize> { | ||||
|         let id = self.next_id.fetch_add(1, Ordering::SeqCst); | ||||
| 
 | ||||
|         let packet = Packet { | ||||
|             id: id, | ||||
|             a: a, | ||||
|             b: b, | ||||
|             c: c, | ||||
|             d: d | ||||
|         }; | ||||
| 
 | ||||
|         self.todo.lock().push_back(packet); | ||||
| 
 | ||||
|         loop { | ||||
|             { | ||||
|                 let mut done = self.done.lock(); | ||||
|                 if let Some(a) = done.remove(&id) { | ||||
|                     return Error::demux(a); | ||||
|                 } | ||||
|             } | ||||
| 
 | ||||
|             unsafe { context::switch(); } | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
|     pub fn capture(&self, buf: &[u8]) -> Result<usize> { | ||||
|         self.capture_inner(buf.as_ptr() as usize, buf.len(), false) | ||||
|     } | ||||
| 
 | ||||
|     pub fn capture_mut(&self, buf: &mut [u8]) -> Result<usize> { | ||||
|         self.capture_inner(buf.as_mut_ptr() as usize, buf.len(), true) | ||||
|     } | ||||
| 
 | ||||
|     fn capture_inner(&self, address: usize, size: usize, writable: bool) -> Result<usize> { | ||||
|         if size == 0 { | ||||
|             Ok(0) | ||||
|         } else { | ||||
|             let context_lock = self.context.upgrade().ok_or(Error::new(ESRCH))?; | ||||
|             let context = context_lock.read(); | ||||
| 
 | ||||
|             let mut grants = context.grants.lock(); | ||||
| 
 | ||||
|             let mut new_table = unsafe { InactivePageTable::from_address(context.arch.get_page_table()) }; | ||||
|             let mut temporary_page = TemporaryPage::new(Page::containing_address(VirtualAddress::new(arch::USER_TMP_GRANT_OFFSET))); | ||||
| 
 | ||||
|             let from_address = (address/4096) * 4096; | ||||
|             let offset = address - from_address; | ||||
|             let full_size = ((offset + size + 4095)/4096) * 4096; | ||||
|             let mut to_address = arch::USER_GRANT_OFFSET; | ||||
| 
 | ||||
|             let mut flags = entry::PRESENT | entry::NO_EXECUTE; | ||||
|             if writable { | ||||
|                 flags |= entry::WRITABLE; | ||||
|             } | ||||
| 
 | ||||
|             for i in 0 .. grants.len() { | ||||
|                 let start = grants[i].start_address().get(); | ||||
|                 if to_address + full_size < start { | ||||
|                     grants.insert(i, Grant::new( | ||||
|                         VirtualAddress::new(from_address), | ||||
|                         VirtualAddress::new(to_address), | ||||
|                         full_size, | ||||
|                         flags, | ||||
|                         &mut new_table, | ||||
|                         &mut temporary_page | ||||
|                     )); | ||||
| 
 | ||||
|                     return Ok(to_address + offset); | ||||
|                 } else { | ||||
|                     let pages = (grants[i].size() + 4095) / 4096; | ||||
|                     let end = start + pages * 4096; | ||||
|                     to_address = end; | ||||
|                 } | ||||
|             } | ||||
| 
 | ||||
|             grants.push(Grant::new( | ||||
|                 VirtualAddress::new(from_address), | ||||
|                 VirtualAddress::new(to_address), | ||||
|                 full_size, | ||||
|                 flags, | ||||
|                 &mut new_table, | ||||
|                 &mut temporary_page | ||||
|             )); | ||||
| 
 | ||||
|             Ok(to_address + offset) | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
|     pub fn release(&self, address: usize) -> Result<()> { | ||||
|         if address == 0 { | ||||
|             Ok(()) | ||||
|         } else { | ||||
|             let context_lock = self.context.upgrade().ok_or(Error::new(ESRCH))?; | ||||
|             let context = context_lock.read(); | ||||
| 
 | ||||
|             let mut grants = context.grants.lock(); | ||||
| 
 | ||||
|             let mut new_table = unsafe { InactivePageTable::from_address(context.arch.get_page_table()) }; | ||||
|             let mut temporary_page = TemporaryPage::new(Page::containing_address(VirtualAddress::new(arch::USER_TMP_GRANT_OFFSET))); | ||||
| 
 | ||||
|             for i in 0 .. grants.len() { | ||||
|                 let start = grants[i].start_address().get(); | ||||
|                 let end = start + grants[i].size(); | ||||
|                 if address >= start && address < end { | ||||
|                     grants.remove(i).destroy(&mut new_table, &mut temporary_page); | ||||
| 
 | ||||
|                     return Ok(()); | ||||
|                 } | ||||
|             } | ||||
| 
 | ||||
|             Err(Error::new(EFAULT)) | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
|     pub fn read(&self, buf: &mut [u8]) -> Result<usize> { | ||||
|         let packet_size = mem::size_of::<Packet>(); | ||||
|         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<usize> { | ||||
|         let packet_size = mem::size_of::<Packet>(); | ||||
|         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<UserInner> | ||||
| } | ||||
| 
 | ||||
| impl UserScheme { | ||||
|     pub fn new(inner: Weak<UserInner>) -> UserScheme { | ||||
|         UserScheme { | ||||
|             inner: inner | ||||
|         } | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| impl Scheme for UserScheme { | ||||
|     fn open(&self, path: &[u8], flags: usize) -> Result<usize> { | ||||
|         let inner = self.inner.upgrade().ok_or(Error::new(ENODEV))?; | ||||
|         let address = inner.capture(path)?; | ||||
|         let result = inner.call(SYS_OPEN, address, path.len(), flags); | ||||
|         let _ = inner.release(address); | ||||
|         result | ||||
|     } | ||||
| 
 | ||||
|     fn dup(&self, file: usize) -> Result<usize> { | ||||
|         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<usize> { | ||||
|         let inner = self.inner.upgrade().ok_or(Error::new(ENODEV))?; | ||||
|         let address = inner.capture_mut(buf)?; | ||||
|         let result = inner.call(SYS_READ, file, address, buf.len()); | ||||
|         let _ = inner.release(address); | ||||
|         result | ||||
|     } | ||||
| 
 | ||||
|     fn write(&self, file: usize, buf: &[u8]) -> Result<usize> { | ||||
|         let inner = self.inner.upgrade().ok_or(Error::new(ENODEV))?; | ||||
|         let address = inner.capture(buf)?; | ||||
|         let result = inner.call(SYS_WRITE, file, address, buf.len()); | ||||
|         let _ = inner.release(address); | ||||
|         result | ||||
|     } | ||||
| 
 | ||||
|     fn seek(&self, file: usize, position: usize, whence: usize) -> Result<usize> { | ||||
|         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<usize> { | ||||
|         let inner = self.inner.upgrade().ok_or(Error::new(ENODEV))?; | ||||
|         let address = inner.capture_mut(stat)?; | ||||
|         let result = inner.call(SYS_FSTAT, file, address, 0); | ||||
|         let _ = inner.release(address); | ||||
|         result | ||||
|     } | ||||
| 
 | ||||
|     fn fsync(&self, file: usize) -> Result<usize> { | ||||
|         let inner = self.inner.upgrade().ok_or(Error::new(ENODEV))?; | ||||
|         inner.call(SYS_FSYNC, file, 0, 0) | ||||
|     } | ||||
| 
 | ||||
|     fn ftruncate(&self, file: usize, len: usize) -> Result<usize> { | ||||
|         let inner = self.inner.upgrade().ok_or(Error::new(ENODEV))?; | ||||
|         inner.call(SYS_FTRUNCATE, file, len, 0) | ||||
|     } | ||||
| 
 | ||||
|     fn close(&self, file: usize) -> Result<usize> { | ||||
|         let inner = self.inner.upgrade().ok_or(Error::new(ENODEV))?; | ||||
|         inner.call(SYS_CLOSE, file, 0, 0) | ||||
|     } | ||||
| } | ||||
|  | @ -1,67 +0,0 @@ | |||
| use super::{Error, Result}; | ||||
| 
 | ||||
| /// System call list
 | ||||
| /// See http://syscalls.kernelgrok.com/ for numbers
 | ||||
| #[derive(Copy, Clone, Debug, Eq, PartialEq)] | ||||
| #[repr(C)] | ||||
| pub enum Call { | ||||
|     /// Exit syscall
 | ||||
|     Exit = 1, | ||||
|     /// Read syscall
 | ||||
|     Read = 3, | ||||
|     /// Write syscall
 | ||||
|     Write = 4, | ||||
|     /// Open syscall
 | ||||
|     Open = 5, | ||||
|     /// Close syscall
 | ||||
|     Close = 6, | ||||
|     /// Wait for a process
 | ||||
|     WaitPid = 7, | ||||
|     /// Execute syscall
 | ||||
|     Exec = 11, | ||||
|     /// Change working directory
 | ||||
|     ChDir = 12, | ||||
|     /// Get process ID
 | ||||
|     GetPid = 20, | ||||
|     /// Duplicate file descriptor
 | ||||
|     Dup = 41, | ||||
|     /// Set process break
 | ||||
|     Brk = 45, | ||||
|     /// Set process I/O privilege level
 | ||||
|     Iopl = 110, | ||||
|     /// Sync file descriptor
 | ||||
|     FSync = 118, | ||||
|     /// Clone process
 | ||||
|     Clone = 120, | ||||
|     /// Yield to scheduler
 | ||||
|     SchedYield = 158, | ||||
|     /// Get process working directory
 | ||||
|     GetCwd = 183 | ||||
| } | ||||
| 
 | ||||
| /// Convert numbers to calls
 | ||||
| /// See http://syscalls.kernelgrok.com/
 | ||||
| impl Call { | ||||
|     //TODO: Return Option<Call>
 | ||||
|     pub fn from(number: usize) -> Result<Call> { | ||||
|         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,28 +0,0 @@ | |||
| /// The error number for an invalid value
 | ||||
| /// See http://www-numi.fnal.gov/offline_software/srt_public_context/WebDocs/Errors/unix_system_errors.html for numbers
 | ||||
| #[derive(Copy, Clone, Debug, Eq, PartialEq)] | ||||
| #[repr(C)] | ||||
| pub enum Error { | ||||
|     /// Operation not permitted
 | ||||
|     NotPermitted = 1, | ||||
|     /// No such file or directory
 | ||||
|     NoEntry = 2, | ||||
|     /// No such process
 | ||||
|     NoProcess = 3, | ||||
|     /// Invalid executable format
 | ||||
|     NoExec = 8, | ||||
|     /// Bad file number
 | ||||
|     BadFile = 9, | ||||
|     /// Try again
 | ||||
|     TryAgain = 11, | ||||
|     /// File exists
 | ||||
|     FileExists = 17, | ||||
|     /// Invalid argument
 | ||||
|     InvalidValue = 22, | ||||
|     /// Too many open files
 | ||||
|     TooManyFiles = 24, | ||||
|     /// Syscall not implemented
 | ||||
|     NoCall = 38 | ||||
| } | ||||
| 
 | ||||
| pub type Result<T> = ::core::result::Result<T, Error>; | ||||
|  | @ -2,21 +2,23 @@ | |||
| 
 | ||||
| use context; | ||||
| use scheme; | ||||
| use syscall::data::Stat; | ||||
| use syscall::error::*; | ||||
| 
 | ||||
| use super::{Error, Result}; | ||||
| 
 | ||||
| /// Change the current working directory
 | ||||
| pub fn chdir(path: &[u8]) -> Result<usize> { | ||||
|     let contexts = context::contexts(); | ||||
|     let context_lock = contexts.current().ok_or(Error::NoProcess)?; | ||||
|     let context_lock = contexts.current().ok_or(Error::new(ESRCH))?; | ||||
|     let context = context_lock.read(); | ||||
|     let canonical = context.canonicalize(path); | ||||
|     *context.cwd.lock() = canonical; | ||||
|     Ok(0) | ||||
| } | ||||
| 
 | ||||
| /// Get the current working directory
 | ||||
| pub fn getcwd(buf: &mut [u8]) -> Result<usize> { | ||||
|     let contexts = context::contexts(); | ||||
|     let context_lock = contexts.current().ok_or(Error::NoProcess)?; | ||||
|     let context_lock = contexts.current().ok_or(Error::new(ESRCH))?; | ||||
|     let context = context_lock.read(); | ||||
|     let cwd = context.cwd.lock(); | ||||
|     let mut i = 0; | ||||
|  | @ -27,43 +29,11 @@ pub fn getcwd(buf: &mut [u8]) -> Result<usize> { | |||
|     Ok(i) | ||||
| } | ||||
| 
 | ||||
| /// Read syscall
 | ||||
| pub fn read(fd: usize, buf: &mut [u8]) -> Result<usize> { | ||||
|     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<usize> { | ||||
|     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<usize> { | ||||
|     let path_canon = { | ||||
|         let contexts = context::contexts(); | ||||
|         let context_lock = contexts.current().ok_or(Error::NoProcess)?; | ||||
|         let context_lock = contexts.current().ok_or(Error::new(ESRCH))?; | ||||
|         let context = context_lock.read(); | ||||
|         context.canonicalize(path) | ||||
|     }; | ||||
|  | @ -73,65 +43,147 @@ pub fn open(path: &[u8], flags: usize) -> Result<usize> { | |||
|     let reference_opt = parts.next(); | ||||
| 
 | ||||
|     let (scheme_id, file_id) = { | ||||
|         let namespace = namespace_opt.ok_or(Error::NoEntry)?; | ||||
|         let schemes = scheme::schemes(); | ||||
|         let (scheme_id, scheme_mutex) = schemes.get_name(namespace).ok_or(Error::NoEntry)?; | ||||
|         let file_id = scheme_mutex.lock().open(reference_opt.unwrap_or(b""), flags)?; | ||||
|         let namespace = namespace_opt.ok_or(Error::new(ENOENT))?; | ||||
|         let (scheme_id, scheme) = { | ||||
|             let schemes = scheme::schemes(); | ||||
|             let (scheme_id, scheme) = schemes.get_name(namespace).ok_or(Error::new(ENOENT))?; | ||||
|             (scheme_id, scheme.clone()) | ||||
|         }; | ||||
|         let file_id = scheme.open(reference_opt.unwrap_or(b""), flags)?; | ||||
|         (scheme_id, file_id) | ||||
|     }; | ||||
| 
 | ||||
|     let contexts = context::contexts(); | ||||
|     let context_lock = contexts.current().ok_or(Error::NoProcess)?; | ||||
|     let context_lock = contexts.current().ok_or(Error::new(ESRCH))?; | ||||
|     let context = context_lock.read(); | ||||
|     context.add_file(::context::file::File { | ||||
|         scheme: scheme_id, | ||||
|         number: file_id | ||||
|     }).ok_or(Error::TooManyFiles) | ||||
|     }).ok_or(Error::new(EMFILE)) | ||||
| } | ||||
| 
 | ||||
| /// Close syscall
 | ||||
| pub fn close(fd: usize) -> Result<usize> { | ||||
|     let file = { | ||||
|         let contexts = context::contexts(); | ||||
|         let context_lock = contexts.current().ok_or(Error::NoProcess)?; | ||||
|         let context_lock = contexts.current().ok_or(Error::new(ESRCH))?; | ||||
|         let context = context_lock.read(); | ||||
|         let file = context.remove_file(fd).ok_or(Error::BadFile)?; | ||||
|         let file = context.remove_file(fd).ok_or(Error::new(EBADF))?; | ||||
|         file | ||||
|     }; | ||||
| 
 | ||||
|     let schemes = scheme::schemes(); | ||||
|     let scheme_mutex = schemes.get(file.scheme).ok_or(Error::BadFile)?; | ||||
|     let result = scheme_mutex.lock().close(file.number).and(Ok(0)); | ||||
|     result | ||||
|     let scheme = { | ||||
|         let schemes = scheme::schemes(); | ||||
|         let scheme = schemes.get(file.scheme).ok_or(Error::new(EBADF))?; | ||||
|         scheme.clone() | ||||
|     }; | ||||
|     scheme.close(file.number) | ||||
| } | ||||
| 
 | ||||
| /// Duplicate file descriptor
 | ||||
| pub fn dup(fd: usize) -> Result<usize> { | ||||
|     let file = { | ||||
|         let contexts = context::contexts(); | ||||
|         let context_lock = contexts.current().ok_or(Error::NoProcess)?; | ||||
|         let context_lock = contexts.current().ok_or(Error::new(ESRCH))?; | ||||
|         let context = context_lock.read(); | ||||
|         let file = context.get_file(fd).ok_or(Error::BadFile)?; | ||||
|         let file = context.get_file(fd).ok_or(Error::new(EBADF))?; | ||||
|         file | ||||
|     }; | ||||
| 
 | ||||
|     let schemes = scheme::schemes(); | ||||
|     let scheme_mutex = schemes.get(file.scheme).ok_or(Error::BadFile)?; | ||||
|     let result = scheme_mutex.lock().dup(file.number); | ||||
|     result | ||||
|     let scheme = { | ||||
|         let schemes = scheme::schemes(); | ||||
|         let scheme = schemes.get(file.scheme).ok_or(Error::new(EBADF))?; | ||||
|         scheme.clone() | ||||
|     }; | ||||
|     scheme.dup(file.number) | ||||
| } | ||||
| 
 | ||||
| /// Get information about the file
 | ||||
| pub fn fstat(fd: usize, stat: &mut Stat) -> Result<usize> { | ||||
|     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<usize> { | ||||
|     let file = { | ||||
|         let contexts = context::contexts(); | ||||
|         let context_lock = contexts.current().ok_or(Error::NoProcess)?; | ||||
|         let context_lock = contexts.current().ok_or(Error::new(ESRCH))?; | ||||
|         let context = context_lock.read(); | ||||
|         let file = context.get_file(fd).ok_or(Error::BadFile)?; | ||||
|         let file = context.get_file(fd).ok_or(Error::new(EBADF))?; | ||||
|         file | ||||
|     }; | ||||
| 
 | ||||
|     let schemes = scheme::schemes(); | ||||
|     let scheme_mutex = schemes.get(file.scheme).ok_or(Error::BadFile)?; | ||||
|     let result = scheme_mutex.lock().fsync(file.number).and(Ok(0)); | ||||
|     result | ||||
|     let scheme = { | ||||
|         let schemes = scheme::schemes(); | ||||
|         let scheme = schemes.get(file.scheme).ok_or(Error::new(EBADF))?; | ||||
|         scheme.clone() | ||||
|     }; | ||||
|     scheme.fsync(file.number) | ||||
| } | ||||
| 
 | ||||
| /// Seek to an offset
 | ||||
| pub fn lseek(fd: usize, pos: usize, whence: usize) -> Result<usize> { | ||||
|     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<usize> { | ||||
|     let file = { | ||||
|         let contexts = context::contexts(); | ||||
|         let context_lock = contexts.current().ok_or(Error::new(ESRCH))?; | ||||
|         let context = context_lock.read(); | ||||
|         let file = context.get_file(fd).ok_or(Error::new(EBADF))?; | ||||
|         file | ||||
|     }; | ||||
| 
 | ||||
|     let scheme = { | ||||
|         let schemes = scheme::schemes(); | ||||
|         let scheme = schemes.get(file.scheme).ok_or(Error::new(EBADF))?; | ||||
|         scheme.clone() | ||||
|     }; | ||||
|     scheme.read(file.number, buf) | ||||
| } | ||||
| 
 | ||||
| /// Write syscall
 | ||||
| pub fn write(fd: usize, buf: &[u8]) -> Result<usize> { | ||||
|     let file = { | ||||
|         let contexts = context::contexts(); | ||||
|         let context_lock = contexts.current().ok_or(Error::new(ESRCH))?; | ||||
|         let context = context_lock.read(); | ||||
|         let file = context.get_file(fd).ok_or(Error::new(EBADF))?; | ||||
|         file | ||||
|     }; | ||||
| 
 | ||||
|     let scheme = { | ||||
|         let schemes = scheme::schemes(); | ||||
|         let scheme = schemes.get(file.scheme).ok_or(Error::new(EBADF))?; | ||||
|         scheme.clone() | ||||
|     }; | ||||
|     scheme.write(file.number, buf) | ||||
| } | ||||
|  |  | |||
|  | @ -1,58 +1,55 @@ | |||
| ///! Syscall handlers
 | ||||
| 
 | ||||
| pub use self::call::*; | ||||
| pub use self::error::*; | ||||
| extern crate syscall; | ||||
| 
 | ||||
| pub use self::syscall::{data, error, flag, number, scheme}; | ||||
| 
 | ||||
| pub use self::fs::*; | ||||
| pub use self::process::*; | ||||
| pub use self::validate::*; | ||||
| 
 | ||||
| /// System call numbers
 | ||||
| mod call; | ||||
| 
 | ||||
| /// System error codes
 | ||||
| mod error; | ||||
| use self::data::Stat; | ||||
| use self::error::{Error, Result, ENOSYS}; | ||||
| use self::number::*; | ||||
| 
 | ||||
| /// Filesystem syscalls
 | ||||
| mod fs; | ||||
| pub mod fs; | ||||
| 
 | ||||
| /// Process syscalls
 | ||||
| mod process; | ||||
| pub mod process; | ||||
| 
 | ||||
| /// Validate input
 | ||||
| mod validate; | ||||
| pub mod validate; | ||||
| 
 | ||||
| #[no_mangle] | ||||
| pub extern fn syscall(a: usize, b: usize, c: usize, d: usize, e: usize, f: usize, stack: usize) -> usize { | ||||
|     #[inline(always)] | ||||
|     fn inner(a: usize, b: usize, c: usize, d: usize, e: usize, _f: usize, stack: usize) -> Result<usize> { | ||||
|         match Call::from(a) { | ||||
|             Ok(call) => match call { | ||||
|                 Call::Exit => exit(b), | ||||
|                 Call::Read => read(b, validate_slice_mut(c as *mut u8, d)?), | ||||
|                 Call::Write => write(b, validate_slice(c as *const u8, d)?), | ||||
|                 Call::Open => open(validate_slice(b as *const u8, c)?, d), | ||||
|                 Call::Close => close(b), | ||||
|                 Call::WaitPid => waitpid(b, c, d), | ||||
|                 Call::Exec => exec(validate_slice(b as *const u8, c)?, validate_slice(d as *const [usize; 2], e)?), | ||||
|                 Call::ChDir => chdir(validate_slice(b as *const u8, c)?), | ||||
|                 Call::GetPid => getpid(), | ||||
|                 Call::Dup => dup(b), | ||||
|                 Call::Brk => brk(b), | ||||
|                 Call::Iopl => iopl(b), | ||||
|                 Call::FSync => fsync(b), | ||||
|                 Call::Clone => clone(b, stack), | ||||
|                 Call::SchedYield => sched_yield(), | ||||
|                 Call::GetCwd => getcwd(validate_slice_mut(b as *mut u8, c)?) | ||||
|             }, | ||||
|             Err(err) => { | ||||
|         match a { | ||||
|             SYS_EXIT => exit(b), | ||||
|             SYS_READ => read(b, validate_slice_mut(c as *mut u8, d)?), | ||||
|             SYS_WRITE => write(b, validate_slice(c as *const u8, d)?), | ||||
|             SYS_OPEN => open(validate_slice(b as *const u8, c)?, d), | ||||
|             SYS_CLOSE => close(b), | ||||
|             SYS_WAITPID => waitpid(b, c, d), | ||||
|             SYS_EXECVE => exec(validate_slice(b as *const u8, c)?, validate_slice(d as *const [usize; 2], e)?), | ||||
|             SYS_CHDIR => chdir(validate_slice(b as *const u8, c)?), | ||||
|             SYS_LSEEK => lseek(b, c, d), | ||||
|             SYS_GETPID => getpid(), | ||||
|             SYS_FSTAT => fstat(b, &mut validate_slice_mut(b as *mut Stat, 1)?[0]), | ||||
|             SYS_DUP => dup(b), | ||||
|             SYS_BRK => brk(b), | ||||
|             SYS_IOPL => iopl(b), | ||||
|             SYS_FSYNC => fsync(b), | ||||
|             SYS_CLONE => clone(b, stack), | ||||
|             SYS_YIELD => sched_yield(), | ||||
|             SYS_GETCWD => getcwd(validate_slice_mut(b as *mut u8, c)?), | ||||
|             _ => { | ||||
|                 println!("Unknown syscall {}", a); | ||||
|                 Err(err) | ||||
|                 Err(Error::new(ENOSYS)) | ||||
|             } | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
|     match inner(a, b, c, d, e, f, stack) { | ||||
|         Ok(value) => value, | ||||
|         Err(value) => (-(value as isize)) as usize | ||||
|     } | ||||
|     Error::mux(inner(a, b, c, d, e, f, stack)) | ||||
| } | ||||
|  |  | |||
|  | @ -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<usize> { | ||||
|     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<usize> { | |||
| 
 | ||||
|         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<usize> { | |||
|         // Copy from old process
 | ||||
|         { | ||||
|             let contexts = context::contexts(); | ||||
|             let context_lock = contexts.current().ok_or(Error::NoProcess)?; | ||||
|             let context_lock = contexts.current().ok_or(Error::new(ESRCH))?; | ||||
|             let context = context_lock.read(); | ||||
| 
 | ||||
|             ppid = context.id; | ||||
|  | @ -96,11 +97,11 @@ pub fn clone(flags: usize, stack_base: usize) -> Result<usize> { | |||
| 
 | ||||
|             if flags & CLONE_VM == CLONE_VM { | ||||
|                 for memory_shared in context.image.iter() { | ||||
|                     image.push(memory_shared.borrow()); | ||||
|                     image.push(memory_shared.clone()); | ||||
|                 } | ||||
| 
 | ||||
|                 if let Some(ref heap_shared) = context.heap { | ||||
|                     heap_option = Some(heap_shared.borrow()); | ||||
|                     heap_option = Some(heap_shared.clone()); | ||||
|                 } | ||||
|             } else { | ||||
|                 for memory_shared in context.image.iter() { | ||||
|  | @ -174,28 +175,38 @@ pub fn clone(flags: usize, stack_base: usize) -> Result<usize> { | |||
|             if flags & CLONE_FILES == CLONE_FILES { | ||||
|                 files = context.files.clone(); | ||||
|             } else { | ||||
|                 let mut files_vec = Vec::new(); | ||||
|                 for (fd, file_option) in context.files.lock().iter().enumerate() { | ||||
|                     if let Some(file) = *file_option { | ||||
|                         let result = { | ||||
|                 files = Arc::new(Mutex::new(context.files.lock().clone())); | ||||
|             } | ||||
|         } | ||||
| 
 | ||||
|         // If not cloning files, dup to get a new number from scheme
 | ||||
|         // This has to be done outside the context lock to prevent deadlocks
 | ||||
|         if flags & CLONE_FILES == 0 { | ||||
|             for (fd, mut file_option) in files.lock().iter_mut().enumerate() { | ||||
|                 let new_file_option = if let Some(file) = *file_option { | ||||
|                     let result = { | ||||
|                         let scheme = { | ||||
|                             let schemes = scheme::schemes(); | ||||
|                             let scheme_mutex = schemes.get(file.scheme).ok_or(Error::BadFile)?; | ||||
|                             let result = scheme_mutex.lock().dup(file.number); | ||||
|                             result | ||||
|                             let scheme = schemes.get(file.scheme).ok_or(Error::new(EBADF))?; | ||||
|                             scheme.clone() | ||||
|                         }; | ||||
|                         match result { | ||||
|                             Ok(new_number) => { | ||||
|                                 files_vec.push(Some(context::file::File { scheme: file.scheme, number: new_number })); | ||||
|                             }, | ||||
|                             Err(err) => { | ||||
|                                 println!("clone: failed to dup {}: {:?}", fd, err); | ||||
|                             } | ||||
|                         let result = scheme.dup(file.number); | ||||
|                         result | ||||
|                     }; | ||||
|                     match result { | ||||
|                         Ok(new_number) => { | ||||
|                             Some(context::file::File { scheme: file.scheme, number: new_number }) | ||||
|                         }, | ||||
|                         Err(err) => { | ||||
|                             println!("clone: failed to dup {}: {:?}", fd, err); | ||||
|                             None | ||||
|                         } | ||||
|                     } else { | ||||
|                         files_vec.push(None); | ||||
|                     } | ||||
|                 } | ||||
|                 files = Arc::new(Mutex::new(files_vec)); | ||||
|                 } else { | ||||
|                     None | ||||
|                 }; | ||||
| 
 | ||||
|                 *file_option = new_file_option; | ||||
|             } | ||||
|         } | ||||
| 
 | ||||
|  | @ -349,7 +360,7 @@ pub fn exec(path: &[u8], arg_ptrs: &[[usize; 2]]) -> Result<usize> { | |||
|         //TODO: Only read elf header, not entire file. Then read required segments
 | ||||
|         let mut data = vec![]; | ||||
|         loop { | ||||
|             let mut buf = [0; 4096]; | ||||
|             let mut buf = [0; 16384]; | ||||
|             let count = syscall::read(file, &mut buf)?; | ||||
|             if count > 0 { | ||||
|                 data.extend_from_slice(&buf[..count]); | ||||
|  | @ -367,7 +378,7 @@ pub fn exec(path: &[u8], arg_ptrs: &[[usize; 2]]) -> Result<usize> { | |||
|                 drop(arg_ptrs); // Drop so that usage is not allowed after unmapping context
 | ||||
| 
 | ||||
|                 let contexts = context::contexts(); | ||||
|                 let context_lock = contexts.current().ok_or(Error::NoProcess)?; | ||||
|                 let context_lock = contexts.current().ok_or(Error::new(ESRCH))?; | ||||
|                 let mut context = context_lock.write(); | ||||
| 
 | ||||
|                 // Unmap previous image and stack
 | ||||
|  | @ -468,7 +479,7 @@ pub fn exec(path: &[u8], arg_ptrs: &[[usize; 2]]) -> Result<usize> { | |||
|             }, | ||||
|             Err(err) => { | ||||
|                 println!("failed to execute {}: {}", unsafe { str::from_utf8_unchecked(path) }, err); | ||||
|                 return Err(Error::NoExec); | ||||
|                 return Err(Error::new(ENOEXEC)); | ||||
|             } | ||||
|         } | ||||
|     } | ||||
|  | @ -479,7 +490,7 @@ pub fn exec(path: &[u8], arg_ptrs: &[[usize; 2]]) -> Result<usize> { | |||
| 
 | ||||
| pub fn getpid() -> Result<usize> { | ||||
|     let contexts = context::contexts(); | ||||
|     let context_lock = contexts.current().ok_or(Error::NoProcess)?; | ||||
|     let context_lock = contexts.current().ok_or(Error::new(ESRCH))?; | ||||
|     let context = context_lock.read(); | ||||
|     Ok(context.id) | ||||
| } | ||||
|  | @ -502,7 +513,7 @@ pub fn waitpid(pid: usize, status_ptr: usize, _options: usize) -> Result<usize> | |||
| 
 | ||||
|             { | ||||
|                 let contexts = context::contexts(); | ||||
|                 let context_lock = contexts.get(pid).ok_or(Error::NoProcess)?; | ||||
|                 let context_lock = contexts.get(pid).ok_or(Error::new(ESRCH))?; | ||||
|                 let context = context_lock.read(); | ||||
|                 if let context::Status::Exited(status) = context.status { | ||||
|                     if status_ptr != 0 { | ||||
|  | @ -515,7 +526,7 @@ pub fn waitpid(pid: usize, status_ptr: usize, _options: usize) -> Result<usize> | |||
| 
 | ||||
|             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)); | ||||
|             } | ||||
|         } | ||||
| 
 | ||||
|  |  | |||
|  | @ -1,15 +1,39 @@ | |||
| use core::slice; | ||||
| use core::{mem, slice}; | ||||
| 
 | ||||
| use super::Result; | ||||
| use arch::paging::{ActivePageTable, Page, VirtualAddress, entry}; | ||||
| use syscall::error::*; | ||||
| 
 | ||||
| fn validate(address: usize, size: usize, flags: entry::EntryFlags) -> Result<()> { | ||||
|     let active_table = unsafe { ActivePageTable::new() }; | ||||
| 
 | ||||
|     let start_page = Page::containing_address(VirtualAddress::new(address)); | ||||
|     let end_page = Page::containing_address(VirtualAddress::new(address + size - 1)); | ||||
|     for page in Page::range_inclusive(start_page, end_page) { | ||||
|         let page_flags = active_table.translate_page_flags(page).ok_or(Error::new(EFAULT))?; | ||||
|         if ! page_flags.contains(flags) { | ||||
|             return Err(Error::new(EFAULT)); | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
|     Ok(()) | ||||
| } | ||||
| 
 | ||||
| /// Convert a pointer and length to slice, if valid
 | ||||
| /// TODO: Check validity
 | ||||
| pub fn validate_slice<T>(ptr: *const T, len: usize) -> Result<&'static [T]> { | ||||
|     Ok(unsafe { slice::from_raw_parts(ptr, len) }) | ||||
|     if len == 0 { | ||||
|         Ok(&[]) | ||||
|     } else { | ||||
|         validate(ptr as usize, len * mem::size_of::<T>(), entry::PRESENT /* TODO | entry::USER_ACCESSIBLE */)?; | ||||
|         Ok(unsafe { slice::from_raw_parts(ptr, len) }) | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| /// Convert a pointer and length to slice, if valid
 | ||||
| /// TODO: Check validity
 | ||||
| pub fn validate_slice_mut<T>(ptr: *mut T, len: usize) -> Result<&'static mut [T]> { | ||||
|     Ok(unsafe { slice::from_raw_parts_mut(ptr, len) }) | ||||
|     if len == 0 { | ||||
|         Ok(&mut []) | ||||
|     } else { | ||||
|         validate(ptr as usize, len * mem::size_of::<T>(), entry::PRESENT | entry::WRITABLE /* TODO | entry::USER_ACCESSIBLE */)?; | ||||
|         Ok(unsafe { slice::from_raw_parts_mut(ptr, len) }) | ||||
|     } | ||||
| } | ||||
|  |  | |||
|  | @ -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))); | ||||
| } | ||||
|  |  | |||
							
								
								
									
										2
									
								
								libstd
									
										
									
									
									
								
							
							
						
						
									
										2
									
								
								libstd
									
										
									
									
									
								
							|  | @ -1 +1 @@ | |||
| Subproject commit 0d434cc168b1d88211f1a3b72c8290c911432826 | ||||
| Subproject commit ae80aff4d39b2d3a83f7d32bc95739e4e1169184 | ||||
							
								
								
									
										6
									
								
								schemes/example/Cargo.toml
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										6
									
								
								schemes/example/Cargo.toml
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,6 @@ | |||
| [package] | ||||
| name = "example" | ||||
| version = "0.1.0" | ||||
| 
 | ||||
| [dependencies.syscall] | ||||
| path = "../../syscall/" | ||||
							
								
								
									
										39
									
								
								schemes/example/src/main.rs
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										39
									
								
								schemes/example/src/main.rs
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,39 @@ | |||
| extern crate syscall; | ||||
| 
 | ||||
| use std::fs::File; | ||||
| use std::io::{Read, Write}; | ||||
| use std::str; | ||||
| use std::thread; | ||||
| 
 | ||||
| use syscall::{Packet, Result, Scheme}; | ||||
| 
 | ||||
| struct ExampleScheme; | ||||
| 
 | ||||
| impl Scheme for ExampleScheme { | ||||
|     fn open(&self, path: &[u8], _flags: usize) -> Result<usize> { | ||||
|         println!("{}", unsafe { str::from_utf8_unchecked(path) }); | ||||
|         Ok(0) | ||||
|     } | ||||
| 
 | ||||
|     fn dup(&self, file: usize) -> Result<usize> { | ||||
|         Ok(file) | ||||
|     } | ||||
| 
 | ||||
|     fn close(&self, _file: usize) -> Result<usize> { | ||||
|         Ok(0) | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| fn main(){ | ||||
|     thread::spawn(move || { | ||||
|         let mut socket = File::create(":example").expect("example: failed to create example scheme"); | ||||
|         let scheme = ExampleScheme; | ||||
|         loop { | ||||
|             let mut packet = Packet::default(); | ||||
|             socket.read(&mut packet).expect("example: failed to read events from example scheme"); | ||||
|             println!("{:?}", packet); | ||||
|             scheme.handle(&mut packet); | ||||
|             socket.write(&packet).expect("example: failed to write responses to example scheme"); | ||||
|         } | ||||
|     }); | ||||
| } | ||||
							
								
								
									
										69
									
								
								syscall/src/data.rs
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										69
									
								
								syscall/src/data.rs
									
										
									
									
									
										Normal file
									
								
							|  | @ -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::<Packet>()) 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::<Packet>()) 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::<Stat>()) 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::<Stat>()) as &mut [u8] | ||||
|         } | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| #[derive(Copy, Clone, Debug, Default)] | ||||
| #[repr(packed)] | ||||
| pub struct TimeSpec { | ||||
|     pub tv_sec: i64, | ||||
|     pub tv_nsec: i32, | ||||
| } | ||||
|  | @ -1,5 +1,6 @@ | |||
| use core::{fmt, result}; | ||||
| 
 | ||||
| #[derive(Eq, PartialEq)] | ||||
| pub struct Error { | ||||
|     pub errno: isize, | ||||
| } | ||||
|  |  | |||
							
								
								
									
										40
									
								
								syscall/src/flag.rs
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										40
									
								
								syscall/src/flag.rs
									
										
									
									
									
										Normal file
									
								
							|  | @ -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; | ||||
|  | @ -2,105 +2,29 @@ | |||
| #![no_std] | ||||
| 
 | ||||
| pub use self::arch::*; | ||||
| pub use self::data::*; | ||||
| pub use self::error::*; | ||||
| pub use self::flag::*; | ||||
| pub use self::number::*; | ||||
| pub use self::scheme::*; | ||||
| 
 | ||||
| #[cfg(target_arch = "x86")] | ||||
| #[path="x86.rs"] | ||||
| pub mod arch; | ||||
| mod arch; | ||||
| 
 | ||||
| #[cfg(target_arch = "x86_64")] | ||||
| #[path="x86_64.rs"] | ||||
| pub mod arch; | ||||
| mod arch; | ||||
| 
 | ||||
| pub mod data; | ||||
| 
 | ||||
| pub mod error; | ||||
| 
 | ||||
| pub const SYS_BRK: usize = 45; | ||||
| pub const SYS_CHDIR: usize = 12; | ||||
| pub const SYS_CLONE: usize = 120; | ||||
|     pub const CLONE_VM: usize = 0x100; | ||||
|     pub const CLONE_FS: usize = 0x200; | ||||
|     pub const CLONE_FILES: usize = 0x400; | ||||
|     pub const CLONE_VFORK: usize = 0x4000; | ||||
|     /// Mark this clone as supervised.
 | ||||
|     ///
 | ||||
|     /// This means that the process can run in supervised mode, even not being connected to
 | ||||
|     /// a supervisor yet. In other words, the parent can later on supervise the process and handle
 | ||||
|     /// the potential blocking syscall.
 | ||||
|     ///
 | ||||
|     /// This is an important security measure, since otherwise the process would be able to fork it
 | ||||
|     /// self right after starting, making supervising it impossible.
 | ||||
|     pub const CLONE_SUPERVISE: usize = 0x400000; | ||||
| pub const SYS_CLOSE: usize = 6; | ||||
| pub const SYS_CLOCK_GETTIME: usize = 265; | ||||
|     pub const CLOCK_REALTIME: usize = 1; | ||||
|     pub const CLOCK_MONOTONIC: usize = 4; | ||||
| pub const SYS_DUP: usize = 41; | ||||
| pub const SYS_EXECVE: usize = 11; | ||||
| pub const SYS_EXIT: usize = 1; | ||||
| pub const SYS_FPATH: usize = 928; | ||||
| pub const SYS_FSTAT: usize = 28; | ||||
|     pub const MODE_DIR: u16 = 0x4000; | ||||
|     pub const MODE_FILE: u16 = 0x8000; | ||||
|     pub const MODE_ALL: u16 = MODE_DIR | MODE_FILE; | ||||
| pub const SYS_FSYNC: usize = 118; | ||||
| pub const SYS_FTRUNCATE: usize = 93; | ||||
| pub const SYS_FUTEX: usize = 240; | ||||
|     pub const FUTEX_WAIT: usize = 0; | ||||
|     pub const FUTEX_WAKE: usize = 1; | ||||
|     pub const FUTEX_REQUEUE: usize = 2; | ||||
| pub const SYS_GETCWD: usize = 183; | ||||
| pub const SYS_GETPID: usize = 20; | ||||
| pub const SYS_IOPL: usize = 110; | ||||
| pub const SYS_LINK: usize = 9; | ||||
| pub const SYS_LSEEK: usize = 19; | ||||
|     pub const SEEK_SET: usize = 0; | ||||
|     pub const SEEK_CUR: usize = 1; | ||||
|     pub const SEEK_END: usize = 2; | ||||
| pub const SYS_MKDIR: usize = 39; | ||||
| pub const SYS_NANOSLEEP: usize = 162; | ||||
| pub const SYS_OPEN: usize = 5; | ||||
|     pub const O_RDONLY: usize = 0; | ||||
|     pub const O_WRONLY: usize = 1; | ||||
|     pub const O_RDWR: usize = 2; | ||||
|     pub const O_NONBLOCK: usize = 4; | ||||
|     pub const O_APPEND: usize = 8; | ||||
|     pub const O_SHLOCK: usize = 0x10; | ||||
|     pub const O_EXLOCK: usize = 0x20; | ||||
|     pub const O_ASYNC: usize = 0x40; | ||||
|     pub const O_FSYNC: usize = 0x80; | ||||
|     pub const O_CREAT: usize = 0x200; | ||||
|     pub const O_TRUNC: usize = 0x400; | ||||
|     pub const O_EXCL: usize = 0x800; | ||||
| pub const SYS_PIPE2: usize = 331; | ||||
| pub const SYS_READ: usize = 3; | ||||
| pub const SYS_RMDIR: usize = 84; | ||||
| pub const SYS_UNLINK: usize = 10; | ||||
| pub const SYS_WAITPID: usize = 7; | ||||
| pub const SYS_WRITE: usize = 4; | ||||
| pub const SYS_YIELD: usize = 158; | ||||
| pub mod flag; | ||||
| 
 | ||||
| #[derive(Copy, Clone, Debug, Default)] | ||||
| #[repr(packed)] | ||||
| pub struct Stat { | ||||
|     pub st_dev: u16, | ||||
|     pub st_ino: u16, | ||||
|     pub st_mode: u16, | ||||
|     pub st_nlink: u16, | ||||
|     pub st_uid: u16, | ||||
|     pub st_gid: u16, | ||||
|     pub st_rdev: u16, | ||||
|     pub st_size: u32, | ||||
|     pub st_atime: u32, | ||||
|     pub st_mtime: u32, | ||||
|     pub st_ctime: u32 | ||||
| } | ||||
| pub mod number; | ||||
| 
 | ||||
| #[derive(Copy, Clone, Debug, Default)] | ||||
| #[repr(packed)] | ||||
| pub struct TimeSpec { | ||||
|     pub tv_sec: i64, | ||||
|     pub tv_nsec: i32, | ||||
| } | ||||
| pub mod scheme; | ||||
| 
 | ||||
| pub unsafe fn brk(addr: usize) -> Result<usize> { | ||||
|     syscall1(SYS_BRK, addr) | ||||
|  |  | |||
							
								
								
									
										28
									
								
								syscall/src/number.rs
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										28
									
								
								syscall/src/number.rs
									
										
									
									
									
										Normal file
									
								
							|  | @ -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; | ||||
							
								
								
									
										94
									
								
								syscall/src/scheme.rs
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										94
									
								
								syscall/src/scheme.rs
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,94 @@ | |||
| use core::slice; | ||||
| 
 | ||||
| use super::*; | ||||
| 
 | ||||
| pub trait Scheme { | ||||
|     fn handle(&self, packet: &mut Packet) { | ||||
|         packet.a = Error::mux(match packet.a { | ||||
|             SYS_OPEN => self.open(unsafe { slice::from_raw_parts(packet.b as *const u8, packet.c) }, packet.d), | ||||
|             SYS_MKDIR => self.mkdir(unsafe { slice::from_raw_parts(packet.b as *const u8, packet.c) }, packet.d), | ||||
|             SYS_RMDIR => self.rmdir(unsafe { slice::from_raw_parts(packet.b as *const u8, packet.c) }), | ||||
|             SYS_UNLINK => self.unlink(unsafe { slice::from_raw_parts(packet.b as *const u8, packet.c) }), | ||||
| 
 | ||||
|             SYS_DUP => self.dup(packet.b), | ||||
|             SYS_READ => self.read(packet.b, unsafe { slice::from_raw_parts_mut(packet.c as *mut u8, packet.d) }), | ||||
|             SYS_WRITE => self.write(packet.b, unsafe { slice::from_raw_parts(packet.c as *const u8, packet.d) }), | ||||
|             SYS_LSEEK => self.seek(packet.b, packet.c, packet.d), | ||||
|             SYS_FPATH => self.fpath(packet.b, unsafe { slice::from_raw_parts_mut(packet.c as *mut u8, packet.d) }), | ||||
|             SYS_FSTAT => self.fstat(packet.b, unsafe { &mut *(packet.c as *mut Stat) }), | ||||
|             SYS_FSYNC => self.fsync(packet.b), | ||||
|             SYS_FTRUNCATE => self.ftruncate(packet.b, packet.c), | ||||
|             SYS_CLOSE => self.close(packet.b), | ||||
| 
 | ||||
|             _ => Err(Error::new(ENOSYS)) | ||||
|         }); | ||||
|     } | ||||
| 
 | ||||
|     /* Scheme operations */ | ||||
| 
 | ||||
|     #[allow(unused_variables)] | ||||
|     fn open(&self, path: &[u8], flags: usize) -> Result<usize> { | ||||
|         Err(Error::new(ENOENT)) | ||||
|     } | ||||
| 
 | ||||
|     #[allow(unused_variables)] | ||||
|     fn mkdir(&self, path: &[u8], mode: usize) -> Result<usize> { | ||||
|         Err(Error::new(ENOENT)) | ||||
|     } | ||||
| 
 | ||||
|     #[allow(unused_variables)] | ||||
|     fn rmdir(&self, path: &[u8]) -> Result<usize> { | ||||
|         Err(Error::new(ENOENT)) | ||||
|     } | ||||
| 
 | ||||
|     #[allow(unused_variables)] | ||||
|     fn unlink(&self, path: &[u8]) -> Result<usize> { | ||||
|         Err(Error::new(ENOENT)) | ||||
|     } | ||||
| 
 | ||||
|     /* Resource operations */ | ||||
|     #[allow(unused_variables)] | ||||
|     fn dup(&self, old_id: usize) -> Result<usize> { | ||||
|         Err(Error::new(EBADF)) | ||||
|     } | ||||
| 
 | ||||
|     #[allow(unused_variables)] | ||||
|     fn read(&self, id: usize, buf: &mut [u8]) -> Result<usize> { | ||||
|         Err(Error::new(EBADF)) | ||||
|     } | ||||
| 
 | ||||
|     #[allow(unused_variables)] | ||||
|     fn write(&self, id: usize, buf: &[u8]) -> Result<usize> { | ||||
|         Err(Error::new(EBADF)) | ||||
|     } | ||||
| 
 | ||||
|     #[allow(unused_variables)] | ||||
|     fn seek(&self, id: usize, pos: usize, whence: usize) -> Result<usize> { | ||||
|         Err(Error::new(EBADF)) | ||||
|     } | ||||
| 
 | ||||
|     #[allow(unused_variables)] | ||||
|     fn fpath(&self, id: usize, buf: &mut [u8]) -> Result<usize> { | ||||
|         Err(Error::new(EBADF)) | ||||
|     } | ||||
| 
 | ||||
|     #[allow(unused_variables)] | ||||
|     fn fstat(&self, id: usize, stat: &mut Stat) -> Result<usize> { | ||||
|         Err(Error::new(EBADF)) | ||||
|     } | ||||
| 
 | ||||
|     #[allow(unused_variables)] | ||||
|     fn fsync(&self, id: usize) -> Result<usize> { | ||||
|         Err(Error::new(EBADF)) | ||||
|     } | ||||
| 
 | ||||
|     #[allow(unused_variables)] | ||||
|     fn ftruncate(&self, id: usize, len: usize) -> Result<usize> { | ||||
|         Err(Error::new(EBADF)) | ||||
|     } | ||||
| 
 | ||||
|     #[allow(unused_variables)] | ||||
|     fn close(&self, id: usize) -> Result<usize> { | ||||
|         Err(Error::new(EBADF)) | ||||
|     } | ||||
| } | ||||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue
	
	 Jeremy Soller
						Jeremy Soller