Merge pull request #7 from redox-os/user_irq

Userspace Schemes and Drivers
This commit is contained in:
Jeremy Soller 2016-09-20 20:18:14 -06:00 committed by GitHub
commit a4ede1d23d
51 changed files with 1431 additions and 648 deletions

View file

@ -10,6 +10,7 @@ crate-type = ["staticlib"]
[dependencies] [dependencies]
bitflags = "*" bitflags = "*"
spin = "*" spin = "*"
syscall = { path = "syscall/" }
[dependencies.goblin] [dependencies.goblin]
git = "https://github.com/m4b/goblin.git" git = "https://github.com/m4b/goblin.git"

View file

@ -26,7 +26,9 @@ clean:
cargo clean --manifest-path libstd/Cargo.toml cargo clean --manifest-path libstd/Cargo.toml
cargo clean --manifest-path init/Cargo.toml cargo clean --manifest-path init/Cargo.toml
cargo clean --manifest-path ion/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 drivers/pcid/Cargo.toml
cargo clean --manifest-path schemes/example/Cargo.toml
rm -rf build rm -rf build
FORCE: FORCE:
@ -133,4 +135,12 @@ $(BUILD)/pcid: drivers/pcid/Cargo.toml drivers/pcid/src/** $(BUILD)/libstd.rlib
$(CARGO) rustc --manifest-path $< $(CARGOFLAGS) -o $@ $(CARGO) rustc --manifest-path $< $(CARGOFLAGS) -o $@
strip $@ 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

View file

@ -5,6 +5,7 @@ version = "0.1.0"
[dependencies] [dependencies]
bitflags = "*" 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" } ransid = { git = "https://github.com/redox-os/ransid.git", branch = "new_api" }
spin = "*" spin = "*"

View file

@ -59,11 +59,11 @@ pub fn init_sdt(sdt: &'static Sdt, active_table: &mut ActivePageTable) {
if ap_local_apic.flags & 1 == 1 { if ap_local_apic.flags & 1 == 1 {
// Allocate a stack // Allocate a stack
// TODO: Allocate contiguous // 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 { for _i in 0..62 {
allocate_frame().expect("no more frames in acpi stack"); 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_ready = TRAMPOLINE as *mut u64;
let ap_cpu_id = unsafe { ap_ready.offset(1) }; let ap_cpu_id = unsafe { ap_ready.offset(1) };

View file

@ -43,6 +43,10 @@ impl Context {
} }
} }
pub fn get_page_table(&self) -> usize {
self.cr3
}
pub fn set_page_table(&mut self, address: usize) { pub fn set_page_table(&mut self, address: usize) {
self.cr3 = address; self.cr3 = address;
} }
@ -52,6 +56,7 @@ impl Context {
} }
/// Switch to the next context by restoring its stack and registers /// Switch to the next context by restoring its stack and registers
#[cold]
#[inline(never)] #[inline(never)]
#[naked] #[naked]
pub unsafe fn switch_to(&mut self, next: &mut Context) { 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 $0, rbp" : "=r"(self.rbp) : : "memory" : "intel", "volatile");
asm!("mov rbp, $0" : : "r"(next.rbp) : "memory" : "intel", "volatile"); asm!("mov rbp, $0" : : "r"(next.rbp) : "memory" : "intel", "volatile");
// Unset global lock, set inside of kernel 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); CONTEXT_SWITCH_LOCK.store(false, Ordering::SeqCst);
} }
}

View file

@ -1,11 +1,9 @@
use paging::ActivePageTable; use paging::ActivePageTable;
pub mod display; pub mod display;
pub mod ps2;
pub mod serial; pub mod serial;
pub unsafe fn init(active_table: &mut ActivePageTable){ pub unsafe fn init(active_table: &mut ActivePageTable){
serial::init(); serial::init();
display::init(active_table); display::init(active_table);
ps2::init();
} }

View file

@ -1,9 +1,9 @@
use spin::Mutex; use spin::Mutex;
use x86::io; use x86::io;
use device::ps2::{PS2_KEYBOARD, PS2_MOUSE};
use device::serial::{COM1, COM2}; 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]); pub static COUNTS: Mutex<[usize; 16]> = Mutex::new([0; 16]);
#[inline(always)] #[inline(always)]
@ -17,6 +17,14 @@ unsafe fn slave_ack() {
master_ack(); master_ack();
} }
pub unsafe fn acknowledge(irq: usize) {
if irq >= 8 {
slave_ack();
} else {
master_ack();
}
}
interrupt!(pit, { interrupt!(pit, {
COUNTS.lock()[0] += 1; COUNTS.lock()[0] += 1;
master_ack(); master_ack();
@ -24,10 +32,6 @@ interrupt!(pit, {
interrupt!(keyboard, { interrupt!(keyboard, {
COUNTS.lock()[1] += 1; COUNTS.lock()[1] += 1;
if let Some(ref mut keyboard) = *PS2_KEYBOARD.lock(){
keyboard.on_irq();
}
master_ack();
}); });
interrupt!(cascade, { interrupt!(cascade, {
@ -84,10 +88,6 @@ interrupt!(pci3, {
interrupt!(mouse, { interrupt!(mouse, {
COUNTS.lock()[12] += 1; COUNTS.lock()[12] += 1;
if let Some(ref mut mouse) = *PS2_MOUSE.lock() {
mouse.on_irq();
}
slave_ack();
}); });
interrupt!(fpu, { interrupt!(fpu, {

View file

@ -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;

View file

@ -15,6 +15,7 @@ extern crate hole_list_allocator as allocator;
#[macro_use] #[macro_use]
extern crate bitflags; extern crate bitflags;
extern crate io;
extern crate ransid; extern crate ransid;
extern crate spin; extern crate spin;
pub extern crate x86; pub extern crate x86;
@ -58,6 +59,9 @@ pub extern crate x86;
/// Size of user stack /// Size of user stack
pub const USER_STACK_SIZE: usize = 1024 * 1024; // 1 MB 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) /// Offset to user temporary image (used when cloning)
pub const USER_TMP_OFFSET: usize = USER_STACK_OFFSET + PML4_SIZE; 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) /// Offset to user temporary stack (used when cloning)
pub const USER_TMP_STACK_OFFSET: usize = USER_TMP_HEAP_OFFSET + PML4_SIZE; 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 /// Print to console
#[macro_export] #[macro_export]
macro_rules! print { macro_rules! print {
($($arg:tt)*) => ({ ($($arg:tt)*) => ({
use core::fmt::Write; use core::fmt::Write;
let mut console = $crate::console::CONSOLE.lock(); let _ = write!($crate::console::CONSOLE.lock(), $($arg)*);
let _ = write!(console, $($arg)*);
}); });
} }
@ -199,9 +205,6 @@ pub mod gdt;
/// Interrupt descriptor table /// Interrupt descriptor table
pub mod idt; pub mod idt;
/// IO Handling
pub mod io;
/// Interrupt instructions /// Interrupt instructions
pub mod interrupt; pub mod interrupt;

View file

@ -93,6 +93,13 @@ impl Mapper {
.and_then(|p1| p1[page.p1_index()].pointed_frame()) .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 /// Translate a virtual address to a physical one
pub fn translate(&self, virtual_address: VirtualAddress) -> Option<PhysicalAddress> { pub fn translate(&self, virtual_address: VirtualAddress) -> Option<PhysicalAddress> {
let offset = virtual_address.get() % PAGE_SIZE; let offset = virtual_address.get() % PAGE_SIZE;

View file

@ -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 { if end > start {
let start_frame = Frame::containing_address(PhysicalAddress::new(start)); let start_frame = Frame::containing_address(PhysicalAddress::new(start));
let end_frame = Frame::containing_address(PhysicalAddress::new(end - 1)); let end_frame = Frame::containing_address(PhysicalAddress::new(end - 1));
for frame in Frame::range_inclusive(start_frame, end_frame) { 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); mapper.map_to(page, frame, flags);
} }
} }
}; };
// Remap stack writable, no execute // 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` // Remap a section with `flags`
let mut remap_section = |start: &u8, end: &u8, flags: EntryFlags| { 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 text read-only
remap_section(& __text_start, & __text_end, PRESENT); 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 { if end > start {
let start_frame = Frame::containing_address(PhysicalAddress::new(start)); let start_frame = Frame::containing_address(PhysicalAddress::new(start));
let end_frame = Frame::containing_address(PhysicalAddress::new(end - 1)); let end_frame = Frame::containing_address(PhysicalAddress::new(end - 1));
for frame in Frame::range_inclusive(start_frame, end_frame) { 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); mapper.map_to(page, frame, flags);
} }
} }
}; };
// Remap stack writable, no execute // 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); active_table.switch(new_table);
@ -328,6 +328,10 @@ impl InactivePageTable {
InactivePageTable { p4_frame: frame } 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 { pub unsafe fn address(&self) -> usize {
self.p4_frame.start_address().get() self.p4_frame.start_address().get()
} }

View file

@ -12,8 +12,8 @@ use externs::memset;
use gdt; use gdt;
use idt; use idt;
use interrupt; use interrupt;
use memory::{self, Frame}; use memory;
use paging::{self, entry, Page, PhysicalAddress, VirtualAddress}; use paging::{self, entry, Page, VirtualAddress};
/// Test of zero values in BSS. /// Test of zero values in BSS.
static BSS_TEST_ZERO: usize = 0; 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); memory::init(0, &__end as *const u8 as usize - ::KERNEL_OFFSET);
// TODO: allocate a stack // TODO: allocate a stack
let stack_start = 0x00080000; let stack_start = 0x00080000 + ::KERNEL_OFFSET;
let stack_end = 0x0009F000; let stack_end = 0x0009F000 + ::KERNEL_OFFSET;
// Initialize paging // Initialize paging
let (mut active_table, tcb_offset) = paging::init(0, stack_start, stack_end); 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); let kernel_table = KERNEL_TABLE.load(Ordering::SeqCst);
// Initialize paging // 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 // Set up GDT for AP
gdt::init(tcb_offset, stack_end); gdt::init(tcb_offset, stack_end);

View file

@ -122,10 +122,11 @@ long_mode:
mov gs, rax mov gs, rax
mov ss, rax mov ss, rax
mov rsp, 0x0009F000 mov rsp, 0xFFFFFF000009F000
;rust init ;rust init
mov rax, [kernel_base + 0x18] mov rax, [kernel_base + 0x18]
xchg bx, bx
jmp rax jmp rax
long_mode_ap: long_mode_ap:

3
drivers/io/Cargo.toml Normal file
View file

@ -0,0 +1,3 @@
[package]
name = "io"
version = "0.1.0"

14
drivers/io/src/lib.rs Normal file
View 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;

View file

@ -1,5 +1,4 @@
use core::marker::PhantomData; use core::marker::PhantomData;
use x86::io;
use super::io::Io; use super::io::Io;
@ -27,13 +26,19 @@ impl Io for Pio<u8> {
/// Read /// Read
#[inline(always)] #[inline(always)]
fn read(&self) -> u8 { 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 /// Write
#[inline(always)] #[inline(always)]
fn write(&mut self, value: u8) { 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 /// Read
#[inline(always)] #[inline(always)]
fn read(&self) -> u16 { 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 /// Write
#[inline(always)] #[inline(always)]
fn write(&mut self, value: u16) { 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 /// Read
#[inline(always)] #[inline(always)]
fn read(&self) -> u32 { 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 /// Write
#[inline(always)] #[inline(always)]
fn write(&mut self, value: u32) { 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
View file

@ -0,0 +1,9 @@
[package]
name = "ps2d"
version = "0.1.0"
[dependencies]
bitflags = "*"
io = { path = "../io/" }
spin = "*"
syscall = { path = "../../syscall/" }

View file

@ -1,17 +1,5 @@
use core::cmp;
use spin::Mutex;
use io::{Io, Pio, ReadOnly, WriteOnly}; 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! { bitflags! {
flags StatusFlags: u8 { flags StatusFlags: u8 {
const OUTPUT_FULL = 1, const OUTPUT_FULL = 1,
@ -85,114 +73,6 @@ enum MouseCommandData {
SetSampleRate = 0xF3, 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 { pub struct Ps2 {
data: Pio<u8>, data: Pio<u8>,
status: ReadOnly<Pio<u8>>, status: ReadOnly<Pio<u8>>,
@ -200,7 +80,7 @@ pub struct Ps2 {
} }
impl Ps2 { impl Ps2 {
const fn new() -> Self { pub fn new() -> Self {
Ps2 { Ps2 {
data: Pio::new(0x60), data: Pio::new(0x60),
status: ReadOnly::new(Pio::new(0x64)), status: ReadOnly::new(Pio::new(0x64)),
@ -278,7 +158,7 @@ impl Ps2 {
self.read() self.read()
} }
fn init(&mut self) -> (Option<Ps2Keyboard>, Option<Ps2Mouse>) { pub fn init(&mut self) -> bool {
// Disable devices // Disable devices
self.command(Command::DisableFirst); self.command(Command::DisableFirst);
self.command(Command::DisableSecond); self.command(Command::DisableSecond);
@ -328,18 +208,6 @@ impl Ps2 {
let mouse_id = self.read(); let mouse_id = self.read();
let mouse_extra = mouse_id == 3; 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 // Set sample rate to maximum
assert_eq!(self.mouse_command_data(MouseCommandData::SetSampleRate, 200), 0xFA); assert_eq!(self.mouse_command_data(MouseCommandData::SetSampleRate, 200), 0xFA);
@ -352,6 +220,7 @@ impl Ps2 {
let mut config = self.config(); let mut config = self.config();
config.remove(FIRST_DISABLED); config.remove(FIRST_DISABLED);
config.remove(SECOND_DISABLED); config.remove(SECOND_DISABLED);
config.insert(FIRST_TRANSLATE);
config.insert(FIRST_INTERRUPT); config.insert(FIRST_INTERRUPT);
config.insert(SECOND_INTERRUPT); config.insert(SECOND_INTERRUPT);
self.set_config(config); self.set_config(config);
@ -359,6 +228,6 @@ impl Ps2 {
self.flush_read(); self.flush_read();
(Some(Ps2Keyboard::new()), Some(Ps2Mouse::new(mouse_extra))) mouse_extra
} }
} }

View 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();
}
}
}

View 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
View 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
View 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();
}
}
}

View file

@ -5,7 +5,7 @@ use spin::Mutex;
use arch; use arch;
use super::file::File; use super::file::File;
use super::memory::{Memory, SharedMemory}; use super::memory::{Grant, Memory, SharedMemory};
#[derive(Copy, Clone, Debug, Eq, PartialEq)] #[derive(Copy, Clone, Debug, Eq, PartialEq)]
pub enum Status { pub enum Status {
@ -33,6 +33,8 @@ pub struct Context {
pub heap: Option<SharedMemory>, pub heap: Option<SharedMemory>,
/// User stack /// User stack
pub stack: Option<Memory>, pub stack: Option<Memory>,
/// User grants
pub grants: Arc<Mutex<Vec<Grant>>>,
/// The current working directory /// The current working directory
pub cwd: Arc<Mutex<Vec<u8>>>, pub cwd: Arc<Mutex<Vec<u8>>>,
/// The open files in the scheme /// The open files in the scheme
@ -51,6 +53,7 @@ impl Context {
image: Vec::new(), image: Vec::new(),
heap: None, heap: None,
stack: None, stack: None,
grants: Arc::new(Mutex::new(Vec::new())),
cwd: Arc::new(Mutex::new(Vec::new())), cwd: Arc::new(Mutex::new(Vec::new())),
files: Arc::new(Mutex::new(Vec::new())) files: Arc::new(Mutex::new(Vec::new()))
} }

View file

@ -1,15 +1,16 @@
use alloc::arc::Arc;
use collections::BTreeMap; use collections::BTreeMap;
use core::mem; use core::mem;
use core::sync::atomic::Ordering; use core::sync::atomic::Ordering;
use spin::RwLock; use spin::RwLock;
use arch; use arch;
use syscall::{Result, Error}; use syscall::error::{Result, Error, EAGAIN};
use super::context::Context; use super::context::Context;
/// Context list type /// Context list type
pub struct ContextList { pub struct ContextList {
map: BTreeMap<usize, RwLock<Context>>, map: BTreeMap<usize, Arc<RwLock<Context>>>,
next_id: usize next_id: usize
} }
@ -23,21 +24,21 @@ impl ContextList {
} }
/// Get the nth context. /// 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) self.map.get(&id)
} }
/// Get the current context. /// 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)) 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() self.map.iter()
} }
/// Create a new context. /// 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 { if self.next_id >= super::CONTEXT_MAX_CONTEXTS {
self.next_id = 1; self.next_id = 1;
} }
@ -47,19 +48,19 @@ impl ContextList {
} }
if self.next_id >= super::CONTEXT_MAX_CONTEXTS { if self.next_id >= super::CONTEXT_MAX_CONTEXTS {
return Err(Error::TryAgain); return Err(Error::new(EAGAIN));
} }
let id = self.next_id; let id = self.next_id;
self.next_id += 1; 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.")) Ok(self.map.get(&id).expect("Failed to insert new context. ID is out of bounds."))
} }
/// Spawn a context from a function. /// 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 context_lock = self.new_context()?;
{ {
let mut context = context_lock.write(); let mut context = context_lock.write();
@ -77,7 +78,7 @@ impl ContextList {
Ok(context_lock) 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) self.map.remove(&id)
} }
} }

View file

@ -1,4 +1,5 @@
use alloc::arc::{Arc, Weak}; use alloc::arc::{Arc, Weak};
use collections::VecDeque;
use spin::Mutex; use spin::Mutex;
use arch::externs::memset; use arch::externs::memset;
@ -7,13 +8,67 @@ use arch::paging::entry::{self, EntryFlags};
use arch::paging::temporary_page::TemporaryPage; use arch::paging::temporary_page::TemporaryPage;
#[derive(Debug)] #[derive(Debug)]
pub struct Memory { pub struct Grant {
start: VirtualAddress, start: VirtualAddress,
size: usize, size: usize,
flags: EntryFlags 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 { pub enum SharedMemory {
Owned(Arc<Mutex<Memory>>), Owned(Arc<Mutex<Memory>>),
Borrowed(Weak<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 { impl Memory {
pub fn new(start: VirtualAddress, size: usize, flags: EntryFlags, flush: bool, clear: bool) -> Self { pub fn new(start: VirtualAddress, size: usize, flags: EntryFlags, flush: bool, clear: bool) -> Self {
let mut memory = Memory { let mut memory = Memory {

View file

@ -54,6 +54,8 @@ pub unsafe fn switch() {
return; return;
} }
//println!("Switch {} to {}", (&*from_ptr).id, (&*to_ptr).id);
(&mut *from_ptr).running = false; (&mut *from_ptr).running = false;
(&mut *to_ptr).running = true; (&mut *to_ptr).running = true;
if let Some(ref stack) = (*to_ptr).kstack { if let Some(ref stack) = (*to_ptr).kstack {

View file

@ -3,8 +3,8 @@ use core::str;
use spin::{Mutex, Once}; use spin::{Mutex, Once};
use context; use context;
use syscall::Result; use syscall::error::*;
use super::Scheme; use syscall::scheme::Scheme;
/// Input /// Input
static INPUT: Once<Mutex<VecDeque<u8>>> = Once::new(); static INPUT: Once<Mutex<VecDeque<u8>>> = Once::new();
@ -23,18 +23,18 @@ pub extern fn debug_input(b: u8) {
pub struct DebugScheme; pub struct DebugScheme;
impl Scheme for 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) Ok(0)
} }
fn dup(&mut self, _file: usize) -> Result<usize> { fn dup(&self, _file: usize) -> Result<usize> {
Ok(0) Ok(0)
} }
/// Read the file `number` into the `buffer` /// Read the file `number` into the `buffer`
/// ///
/// Returns the number of bytes read /// 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 { loop {
let mut i = 0; let mut i = 0;
{ {
@ -56,18 +56,18 @@ impl Scheme for DebugScheme {
/// Write the `buffer` to the `file` /// Write the `buffer` to the `file`
/// ///
/// Returns the number of bytes written /// 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 //TODO: Write bytes, do not convert to str
print!("{}", unsafe { str::from_utf8_unchecked(buffer) }); print!("{}", unsafe { str::from_utf8_unchecked(buffer) });
Ok(buffer.len()) Ok(buffer.len())
} }
fn fsync(&mut self, file: usize) -> Result<()> { fn fsync(&self, _file: usize) -> Result<usize> {
Ok(()) Ok(0)
} }
/// Close the file `number` /// Close the file `number`
fn close(&mut self, _file: usize) -> Result<()> { fn close(&self, _file: usize) -> Result<usize> {
Ok(()) Ok(0)
} }
} }

View file

@ -1,7 +1,11 @@
use collections::BTreeMap; use collections::BTreeMap;
use core::cmp;
use core::sync::atomic::{AtomicUsize, Ordering};
use spin::RwLock;
use syscall::{Error, Result}; use syscall::error::*;
use super::Scheme; use syscall::flag::{SEEK_SET, SEEK_CUR, SEEK_END};
use syscall::scheme::Scheme;
struct Handle { struct Handle {
data: &'static [u8], data: &'static [u8],
@ -9,9 +13,9 @@ struct Handle {
} }
pub struct EnvScheme { pub struct EnvScheme {
next_id: usize, next_id: AtomicUsize,
files: BTreeMap<&'static [u8], &'static [u8]>, files: BTreeMap<&'static [u8], &'static [u8]>,
handles: BTreeMap<usize, Handle> handles: RwLock<BTreeMap<usize, Handle>>
} }
impl EnvScheme { impl EnvScheme {
@ -24,20 +28,19 @@ impl EnvScheme {
files.insert(b"LINES", b"30"); files.insert(b"LINES", b"30");
EnvScheme { EnvScheme {
next_id: 0, next_id: AtomicUsize::new(0),
files: files, files: files,
handles: BTreeMap::new() handles: RwLock::new(BTreeMap::new())
} }
} }
} }
impl Scheme for EnvScheme { impl Scheme for EnvScheme {
fn open(&mut self, path: &[u8], _flags: usize) -> Result<usize> { fn open(&self, path: &[u8], _flags: usize) -> Result<usize> {
let data = self.files.get(path).ok_or(Error::NoEntry)?; let data = self.files.get(path).ok_or(Error::new(ENOENT))?;
let id = self.next_id; let id = self.next_id.fetch_add(1, Ordering::SeqCst);
self.next_id += 1; self.handles.write().insert(id, Handle {
self.handles.insert(id, Handle {
data: data, data: data,
seek: 0 seek: 0
}); });
@ -45,15 +48,15 @@ impl Scheme for EnvScheme {
Ok(id) Ok(id)
} }
fn dup(&mut self, file: usize) -> Result<usize> { fn dup(&self, file: usize) -> Result<usize> {
let (data, seek) = { 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) (handle.data, handle.seek)
}; };
let id = self.next_id; let id = self.next_id.fetch_add(1, Ordering::SeqCst);
self.next_id += 1; self.handles.write().insert(id, Handle {
self.handles.insert(id, Handle {
data: data, data: data,
seek: seek seek: seek
}); });
@ -61,8 +64,9 @@ impl Scheme for EnvScheme {
Ok(id) Ok(id)
} }
fn read(&mut self, file: usize, buffer: &mut [u8]) -> Result<usize> { fn read(&self, file: usize, buffer: &mut [u8]) -> Result<usize> {
let mut handle = self.handles.get_mut(&file).ok_or(Error::BadFile)?; let mut handles = self.handles.write();
let mut handle = handles.get_mut(&file).ok_or(Error::new(EBADF))?;
let mut i = 0; let mut i = 0;
while i < buffer.len() && handle.seek < handle.data.len() { while i < buffer.len() && handle.seek < handle.data.len() {
@ -74,15 +78,25 @@ impl Scheme for EnvScheme {
Ok(i) Ok(i)
} }
fn write(&mut self, _file: usize, _buffer: &[u8]) -> Result<usize> { fn seek(&self, id: usize, pos: usize, whence: usize) -> Result<usize> {
Err(Error::NotPermitted) 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<()> { fn fsync(&self, _file: usize) -> Result<usize> {
Ok(()) Ok(0)
} }
fn close(&mut self, file: usize) -> Result<()> { fn close(&self, file: usize) -> Result<usize> {
self.handles.remove(&file).ok_or(Error::BadFile).and(Ok(())) self.handles.write().remove(&file).ok_or(Error::new(EBADF)).and(Ok(0))
} }
} }

View file

@ -1,7 +1,11 @@
use collections::BTreeMap; use collections::BTreeMap;
use core::cmp;
use core::sync::atomic::{AtomicUsize, Ordering};
use spin::RwLock;
use syscall::{Error, Result}; use syscall::error::*;
use super::Scheme; use syscall::flag::{SEEK_SET, SEEK_CUR, SEEK_END};
use syscall::scheme::Scheme;
struct Handle { struct Handle {
data: &'static [u8], data: &'static [u8],
@ -9,9 +13,9 @@ struct Handle {
} }
pub struct InitFsScheme { pub struct InitFsScheme {
next_id: usize, next_id: AtomicUsize,
files: BTreeMap<&'static [u8], &'static [u8]>, files: BTreeMap<&'static [u8], &'static [u8]>,
handles: BTreeMap<usize, Handle> handles: RwLock<BTreeMap<usize, Handle>>
} }
impl InitFsScheme { impl InitFsScheme {
@ -21,23 +25,24 @@ impl InitFsScheme {
files.insert(b"bin/init", include_bytes!("../../build/userspace/init")); files.insert(b"bin/init", include_bytes!("../../build/userspace/init"));
files.insert(b"bin/ion", include_bytes!("../../build/userspace/ion")); files.insert(b"bin/ion", include_bytes!("../../build/userspace/ion"));
files.insert(b"bin/pcid", include_bytes!("../../build/userspace/pcid")); 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 { InitFsScheme {
next_id: 0, next_id: AtomicUsize::new(0),
files: files, files: files,
handles: BTreeMap::new() handles: RwLock::new(BTreeMap::new())
} }
} }
} }
impl Scheme for InitFsScheme { impl Scheme for InitFsScheme {
fn open(&mut self, path: &[u8], _flags: usize) -> Result<usize> { fn open(&self, path: &[u8], _flags: usize) -> Result<usize> {
let data = self.files.get(path).ok_or(Error::NoEntry)?; let data = self.files.get(path).ok_or(Error::new(ENOENT))?;
let id = self.next_id; let id = self.next_id.fetch_add(1, Ordering::SeqCst);
self.next_id += 1; self.handles.write().insert(id, Handle {
self.handles.insert(id, Handle {
data: data, data: data,
seek: 0 seek: 0
}); });
@ -45,28 +50,29 @@ impl Scheme for InitFsScheme {
Ok(id) Ok(id)
} }
fn dup(&mut self, file: usize) -> Result<usize> { fn dup(&self, id: usize) -> Result<usize> {
let (data, seek) = { 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) (handle.data, handle.seek)
}; };
let id = self.next_id; let new_id = self.next_id.fetch_add(1, Ordering::SeqCst);
self.next_id += 1; self.handles.write().insert(new_id, Handle {
self.handles.insert(id, Handle {
data: data, data: data,
seek: seek seek: seek
}); });
Ok(id) Ok(new_id)
} }
fn read(&mut self, file: usize, buffer: &mut [u8]) -> Result<usize> { fn read(&self, id: usize, buf: &mut [u8]) -> Result<usize> {
let mut handle = self.handles.get_mut(&file).ok_or(Error::BadFile)?; let mut handles = self.handles.write();
let mut handle = handles.get_mut(&id).ok_or(Error::new(EBADF))?;
let mut i = 0; let mut i = 0;
while i < buffer.len() && handle.seek < handle.data.len() { while i < buf.len() && handle.seek < handle.data.len() {
buffer[i] = handle.data[handle.seek]; buf[i] = handle.data[handle.seek];
i += 1; i += 1;
handle.seek += 1; handle.seek += 1;
} }
@ -74,15 +80,25 @@ impl Scheme for InitFsScheme {
Ok(i) Ok(i)
} }
fn write(&mut self, _file: usize, _buffer: &[u8]) -> Result<usize> { fn seek(&self, id: usize, pos: usize, whence: usize) -> Result<usize> {
Err(Error::NotPermitted) 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<()> { fn fsync(&self, _id: usize) -> Result<usize> {
Ok(()) Ok(0)
} }
fn close(&mut self, file: usize) -> Result<()> { fn close(&self, id: usize) -> Result<usize> {
self.handles.remove(&file).ok_or(Error::BadFile).and(Ok(())) self.handles.write().remove(&id).ok_or(Error::new(EBADF)).and(Ok(0))
} }
} }

View file

@ -1,57 +1,68 @@
use core::{mem, str}; use core::{mem, str};
use arch::interrupt::irq::COUNTS; use arch::interrupt::irq::{ACKS, COUNTS, acknowledge};
use context; use syscall::error::*;
use syscall::{Error, Result}; use syscall::scheme::Scheme;
use super::Scheme;
pub struct IrqScheme; pub struct IrqScheme;
impl Scheme for IrqScheme { impl Scheme for IrqScheme {
fn open(&mut self, path: &[u8], _flags: usize) -> Result<usize> { fn open(&self, path: &[u8], _flags: usize) -> Result<usize> {
let path_str = str::from_utf8(path).or(Err(Error::NoEntry))?; let path_str = str::from_utf8(path).or(Err(Error::new(ENOENT)))?;
let id = path_str.parse::<usize>().or(Err(Error::NoEntry))?;
let id = path_str.parse::<usize>().or(Err(Error::new(ENOENT)))?;
if id < COUNTS.lock().len() { if id < COUNTS.lock().len() {
Ok(id) Ok(id)
} else { } 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) 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 // Ensures that the length of the buffer is larger than the size of a usize
if buffer.len() >= mem::size_of::<usize>() { if buffer.len() >= mem::size_of::<usize>() {
let ack = ACKS.lock()[file];
let current = COUNTS.lock()[file]; let current = COUNTS.lock()[file];
loop { if ack != current {
let next = COUNTS.lock()[file];
if next != current {
// Safe if the length of the buffer is larger than the size of a usize // Safe if the length of the buffer is larger than the size of a usize
assert!(buffer.len() >= mem::size_of::<usize>()); assert!(buffer.len() >= mem::size_of::<usize>());
unsafe { *(buffer.as_mut_ptr() as *mut usize) = next }; unsafe { *(buffer.as_mut_ptr() as *mut usize) = current; }
return Ok(mem::size_of::<usize>()); Ok(mem::size_of::<usize>())
} else { } else {
// Safe if all locks have been dropped Ok(0)
unsafe { context::switch(); }
}
} }
} else { } else {
Err(Error::InvalidValue) Err(Error::new(EINVAL))
} }
} }
fn write(&mut self, _file: usize, _buffer: &[u8]) -> Result<usize> { fn write(&self, file: usize, buffer: &[u8]) -> Result<usize> {
Err(Error::NotPermitted) 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<()> { fn fsync(&self, _file: usize) -> Result<usize> {
Ok(()) Ok(0)
} }
fn close(&mut self, file: usize) -> Result<()> { fn close(&self, _file: usize) -> Result<usize> {
Ok(()) Ok(0)
} }
} }

View file

@ -11,14 +11,16 @@ use alloc::boxed::Box;
use collections::BTreeMap; 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::debug::DebugScheme;
use self::env::EnvScheme; use self::env::EnvScheme;
use self::initfs::InitFsScheme; use self::initfs::InitFsScheme;
use self::irq::IrqScheme; use self::irq::IrqScheme;
use self::root::RootScheme;
/// Debug scheme /// Debug scheme
pub mod debug; pub mod debug;
@ -32,12 +34,18 @@ pub mod initfs;
/// IRQ handling /// IRQ handling
pub mod irq; pub mod irq;
/// Root scheme
pub mod root;
/// Userspace schemes
pub mod user;
/// Limit on number of schemes /// Limit on number of schemes
pub const SCHEME_MAX_SCHEMES: usize = 65536; pub const SCHEME_MAX_SCHEMES: usize = 65536;
/// Scheme list type /// Scheme list type
pub struct SchemeList { pub struct SchemeList {
map: BTreeMap<usize, Arc<Mutex<Box<Scheme + Send>>>>, map: BTreeMap<usize, Arc<Box<Scheme + Send + Sync>>>,
names: BTreeMap<Box<[u8]>, usize>, names: BTreeMap<Box<[u8]>, usize>,
next_id: usize next_id: usize
} }
@ -53,11 +61,11 @@ impl SchemeList {
} }
/// Get the nth scheme. /// 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) 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) { if let Some(&id) = self.names.get(name) {
self.get(id).map(|scheme| (id, scheme)) self.get(id).map(|scheme| (id, scheme))
} else { } else {
@ -66,9 +74,9 @@ impl SchemeList {
} }
/// Create a new scheme. /// 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) { if self.names.contains_key(&name) {
return Err(Error::FileExists); return Err(Error::new(EEXIST));
} }
if self.next_id >= SCHEME_MAX_SCHEMES { if self.next_id >= SCHEME_MAX_SCHEMES {
@ -80,7 +88,7 @@ impl SchemeList {
} }
if self.next_id >= SCHEME_MAX_SCHEMES { if self.next_id >= SCHEME_MAX_SCHEMES {
return Err(Error::TryAgain); return Err(Error::new(EAGAIN));
} }
let id = self.next_id; let id = self.next_id;
@ -99,10 +107,11 @@ static SCHEMES: Once<RwLock<SchemeList>> = Once::new();
/// Initialize schemes, called if needed /// Initialize schemes, called if needed
fn init_schemes() -> RwLock<SchemeList> { fn init_schemes() -> RwLock<SchemeList> {
let mut list: SchemeList = SchemeList::new(); 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""), Arc::new(Box::new(RootScheme::new()))).expect("failed to insert root 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"debug"), Arc::new(Box::new(DebugScheme))).expect("failed to insert debug 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"env"), Arc::new(Box::new(EnvScheme::new()))).expect("failed to insert env 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"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) RwLock::new(list)
} }
@ -115,32 +124,3 @@ pub fn schemes() -> RwLockReadGuard<'static, SchemeList> {
pub fn schemes_mut() -> RwLockWriteGuard<'static, SchemeList> { pub fn schemes_mut() -> RwLockWriteGuard<'static, SchemeList> {
SCHEMES.call_once(init_schemes).write() 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
View 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
View 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)
}
}

View file

@ -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)
}
}
}

View file

@ -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>;

View file

@ -2,21 +2,23 @@
use context; use context;
use scheme; 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> { pub fn chdir(path: &[u8]) -> Result<usize> {
let contexts = context::contexts(); 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 context = context_lock.read();
let canonical = context.canonicalize(path); let canonical = context.canonicalize(path);
*context.cwd.lock() = canonical; *context.cwd.lock() = canonical;
Ok(0) Ok(0)
} }
/// Get the current working directory
pub fn getcwd(buf: &mut [u8]) -> Result<usize> { pub fn getcwd(buf: &mut [u8]) -> Result<usize> {
let contexts = context::contexts(); 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 context = context_lock.read();
let cwd = context.cwd.lock(); let cwd = context.cwd.lock();
let mut i = 0; let mut i = 0;
@ -27,43 +29,11 @@ pub fn getcwd(buf: &mut [u8]) -> Result<usize> {
Ok(i) 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 /// Open syscall
pub fn open(path: &[u8], flags: usize) -> Result<usize> { pub fn open(path: &[u8], flags: usize) -> Result<usize> {
let path_canon = { let path_canon = {
let contexts = context::contexts(); 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 context = context_lock.read();
context.canonicalize(path) context.canonicalize(path)
}; };
@ -73,65 +43,147 @@ pub fn open(path: &[u8], flags: usize) -> Result<usize> {
let reference_opt = parts.next(); let reference_opt = parts.next();
let (scheme_id, file_id) = { let (scheme_id, file_id) = {
let namespace = namespace_opt.ok_or(Error::NoEntry)?; let namespace = namespace_opt.ok_or(Error::new(ENOENT))?;
let (scheme_id, scheme) = {
let schemes = scheme::schemes(); let schemes = scheme::schemes();
let (scheme_id, scheme_mutex) = schemes.get_name(namespace).ok_or(Error::NoEntry)?; let (scheme_id, scheme) = schemes.get_name(namespace).ok_or(Error::new(ENOENT))?;
let file_id = scheme_mutex.lock().open(reference_opt.unwrap_or(b""), flags)?; (scheme_id, scheme.clone())
};
let file_id = scheme.open(reference_opt.unwrap_or(b""), flags)?;
(scheme_id, file_id) (scheme_id, file_id)
}; };
let contexts = context::contexts(); 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 context = context_lock.read();
context.add_file(::context::file::File { context.add_file(::context::file::File {
scheme: scheme_id, scheme: scheme_id,
number: file_id number: file_id
}).ok_or(Error::TooManyFiles) }).ok_or(Error::new(EMFILE))
} }
/// Close syscall /// Close syscall
pub fn close(fd: usize) -> Result<usize> { pub fn close(fd: usize) -> Result<usize> {
let file = { let file = {
let contexts = context::contexts(); 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 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 file
}; };
let scheme = {
let schemes = scheme::schemes(); let schemes = scheme::schemes();
let scheme_mutex = schemes.get(file.scheme).ok_or(Error::BadFile)?; let scheme = schemes.get(file.scheme).ok_or(Error::new(EBADF))?;
let result = scheme_mutex.lock().close(file.number).and(Ok(0)); scheme.clone()
result };
scheme.close(file.number)
} }
/// Duplicate file descriptor /// Duplicate file descriptor
pub fn dup(fd: usize) -> Result<usize> { pub fn dup(fd: usize) -> Result<usize> {
let file = { let file = {
let contexts = context::contexts(); 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 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 file
}; };
let scheme = {
let schemes = scheme::schemes(); let schemes = scheme::schemes();
let scheme_mutex = schemes.get(file.scheme).ok_or(Error::BadFile)?; let scheme = schemes.get(file.scheme).ok_or(Error::new(EBADF))?;
let result = scheme_mutex.lock().dup(file.number); scheme.clone()
result };
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> { pub fn fsync(fd: usize) -> Result<usize> {
let file = { let file = {
let contexts = context::contexts(); 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 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 file
}; };
let scheme = {
let schemes = scheme::schemes(); let schemes = scheme::schemes();
let scheme_mutex = schemes.get(file.scheme).ok_or(Error::BadFile)?; let scheme = schemes.get(file.scheme).ok_or(Error::new(EBADF))?;
let result = scheme_mutex.lock().fsync(file.number).and(Ok(0)); scheme.clone()
result };
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)
} }

View file

@ -1,58 +1,55 @@
///! Syscall handlers ///! Syscall handlers
pub use self::call::*; extern crate syscall;
pub use self::error::*;
pub use self::syscall::{data, error, flag, number, scheme};
pub use self::fs::*; pub use self::fs::*;
pub use self::process::*; pub use self::process::*;
pub use self::validate::*; pub use self::validate::*;
/// System call numbers use self::data::Stat;
mod call; use self::error::{Error, Result, ENOSYS};
use self::number::*;
/// System error codes
mod error;
/// Filesystem syscalls /// Filesystem syscalls
mod fs; pub mod fs;
/// Process syscalls /// Process syscalls
mod process; pub mod process;
/// Validate input /// Validate input
mod validate; pub mod validate;
#[no_mangle] #[no_mangle]
pub extern fn syscall(a: usize, b: usize, c: usize, d: usize, e: usize, f: usize, stack: usize) -> usize { pub extern fn syscall(a: usize, b: usize, c: usize, d: usize, e: usize, f: usize, stack: usize) -> usize {
#[inline(always)] #[inline(always)]
fn inner(a: usize, b: usize, c: usize, d: usize, e: usize, _f: usize, stack: usize) -> Result<usize> { fn inner(a: usize, b: usize, c: usize, d: usize, e: usize, _f: usize, stack: usize) -> Result<usize> {
match Call::from(a) { match a {
Ok(call) => match call { SYS_EXIT => exit(b),
Call::Exit => exit(b), SYS_READ => read(b, validate_slice_mut(c as *mut u8, d)?),
Call::Read => read(b, validate_slice_mut(c as *mut u8, d)?), SYS_WRITE => write(b, validate_slice(c as *const u8, d)?),
Call::Write => write(b, validate_slice(c as *const u8, d)?), SYS_OPEN => open(validate_slice(b as *const u8, c)?, d),
Call::Open => open(validate_slice(b as *const u8, c)?, d), SYS_CLOSE => close(b),
Call::Close => close(b), SYS_WAITPID => waitpid(b, c, d),
Call::WaitPid => waitpid(b, c, d), SYS_EXECVE => exec(validate_slice(b as *const u8, c)?, validate_slice(d as *const [usize; 2], e)?),
Call::Exec => 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)?),
Call::ChDir => chdir(validate_slice(b as *const u8, c)?), SYS_LSEEK => lseek(b, c, d),
Call::GetPid => getpid(), SYS_GETPID => getpid(),
Call::Dup => dup(b), SYS_FSTAT => fstat(b, &mut validate_slice_mut(b as *mut Stat, 1)?[0]),
Call::Brk => brk(b), SYS_DUP => dup(b),
Call::Iopl => iopl(b), SYS_BRK => brk(b),
Call::FSync => fsync(b), SYS_IOPL => iopl(b),
Call::Clone => clone(b, stack), SYS_FSYNC => fsync(b),
Call::SchedYield => sched_yield(), SYS_CLONE => clone(b, stack),
Call::GetCwd => getcwd(validate_slice_mut(b as *mut u8, c)?) SYS_YIELD => sched_yield(),
}, SYS_GETCWD => getcwd(validate_slice_mut(b as *mut u8, c)?),
Err(err) => { _ => {
println!("Unknown syscall {}", a); println!("Unknown syscall {}", a);
Err(err) Err(Error::new(ENOSYS))
} }
} }
} }
match inner(a, b, c, d, e, f, stack) { Error::mux(inner(a, b, c, d, e, f, stack))
Ok(value) => value,
Err(value) => (-(value as isize)) as usize
}
} }

View file

@ -15,11 +15,13 @@ use arch::start::usermode;
use context; use context;
use elf::{self, program_header}; use elf::{self, program_header};
use scheme; 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> { pub fn brk(address: usize) -> Result<usize> {
let contexts = context::contexts(); 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 context = context_lock.read();
let current = if let Some(ref heap_shared) = context.heap { let current = if let Some(ref heap_shared) = context.heap {
@ -45,8 +47,7 @@ pub fn brk(address: usize) -> Result<usize> {
Ok(address) Ok(address)
} else { } else {
//TODO: Return correct error Err(Error::new(ENOMEM))
Err(Error::NotPermitted)
} }
} }
@ -75,7 +76,7 @@ pub fn clone(flags: usize, stack_base: usize) -> Result<usize> {
// Copy from old process // Copy from old process
{ {
let contexts = context::contexts(); 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 context = context_lock.read();
ppid = context.id; ppid = context.id;
@ -96,11 +97,11 @@ pub fn clone(flags: usize, stack_base: usize) -> Result<usize> {
if flags & CLONE_VM == CLONE_VM { if flags & CLONE_VM == CLONE_VM {
for memory_shared in context.image.iter() { 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 { if let Some(ref heap_shared) = context.heap {
heap_option = Some(heap_shared.borrow()); heap_option = Some(heap_shared.clone());
} }
} else { } else {
for memory_shared in context.image.iter() { 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 { if flags & CLONE_FILES == CLONE_FILES {
files = context.files.clone(); files = context.files.clone();
} else { } else {
let mut files_vec = Vec::new(); files = Arc::new(Mutex::new(context.files.lock().clone()));
for (fd, file_option) in context.files.lock().iter().enumerate() { }
if let Some(file) = *file_option { }
// 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 result = {
let scheme = {
let schemes = scheme::schemes(); let schemes = scheme::schemes();
let scheme_mutex = schemes.get(file.scheme).ok_or(Error::BadFile)?; let scheme = schemes.get(file.scheme).ok_or(Error::new(EBADF))?;
let result = scheme_mutex.lock().dup(file.number); scheme.clone()
};
let result = scheme.dup(file.number);
result result
}; };
match result { match result {
Ok(new_number) => { Ok(new_number) => {
files_vec.push(Some(context::file::File { scheme: file.scheme, number: new_number })); Some(context::file::File { scheme: file.scheme, number: new_number })
}, },
Err(err) => { Err(err) => {
println!("clone: failed to dup {}: {:?}", fd, err); println!("clone: failed to dup {}: {:?}", fd, err);
None
} }
} }
} else { } else {
files_vec.push(None); None
} };
}
files = Arc::new(Mutex::new(files_vec)); *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 //TODO: Only read elf header, not entire file. Then read required segments
let mut data = vec![]; let mut data = vec![];
loop { loop {
let mut buf = [0; 4096]; let mut buf = [0; 16384];
let count = syscall::read(file, &mut buf)?; let count = syscall::read(file, &mut buf)?;
if count > 0 { if count > 0 {
data.extend_from_slice(&buf[..count]); 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 drop(arg_ptrs); // Drop so that usage is not allowed after unmapping context
let contexts = context::contexts(); 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(); let mut context = context_lock.write();
// Unmap previous image and stack // Unmap previous image and stack
@ -468,7 +479,7 @@ pub fn exec(path: &[u8], arg_ptrs: &[[usize; 2]]) -> Result<usize> {
}, },
Err(err) => { Err(err) => {
println!("failed to execute {}: {}", unsafe { str::from_utf8_unchecked(path) }, 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> { pub fn getpid() -> Result<usize> {
let contexts = context::contexts(); 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 context = context_lock.read();
Ok(context.id) Ok(context.id)
} }
@ -502,7 +513,7 @@ pub fn waitpid(pid: usize, status_ptr: usize, _options: usize) -> Result<usize>
{ {
let contexts = context::contexts(); 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(); let context = context_lock.read();
if let context::Status::Exited(status) = context.status { if let context::Status::Exited(status) = context.status {
if status_ptr != 0 { if status_ptr != 0 {
@ -515,7 +526,7 @@ pub fn waitpid(pid: usize, status_ptr: usize, _options: usize) -> Result<usize>
if exited { if exited {
let mut contexts = context::contexts_mut(); 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));
} }
} }

View file

@ -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 /// 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]> { pub fn validate_slice<T>(ptr: *const T, len: usize) -> Result<&'static [T]> {
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) }) Ok(unsafe { slice::from_raw_parts(ptr, len) })
} }
}
/// Convert a pointer and length to slice, if valid /// 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]> { pub fn validate_slice_mut<T>(ptr: *mut T, len: usize) -> Result<&'static mut [T]> {
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) }) Ok(unsafe { slice::from_raw_parts_mut(ptr, len) })
} }
}

View file

@ -24,6 +24,6 @@ fn stdio() {
/// Test that invalid reads/writes cause errors /// Test that invalid reads/writes cause errors
#[test] #[test]
fn invalid_path() { fn invalid_path() {
assert_eq!(syscall::read(999, &mut []), Err(Error::BadFile)); assert_eq!(syscall::read(999, &mut []), Err(Error::new(EBADF)));
assert_eq!(syscall::write(999, &[]), Err(Error::BadFile)); assert_eq!(syscall::write(999, &[]), Err(Error::new(EBADF)));
} }

2
libstd

@ -1 +1 @@
Subproject commit 0d434cc168b1d88211f1a3b72c8290c911432826 Subproject commit ae80aff4d39b2d3a83f7d32bc95739e4e1169184

View file

@ -0,0 +1,6 @@
[package]
name = "example"
version = "0.1.0"
[dependencies.syscall]
path = "../../syscall/"

View 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
View 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,
}

View file

@ -1,5 +1,6 @@
use core::{fmt, result}; use core::{fmt, result};
#[derive(Eq, PartialEq)]
pub struct Error { pub struct Error {
pub errno: isize, pub errno: isize,
} }

40
syscall/src/flag.rs Normal file
View 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;

View file

@ -2,105 +2,29 @@
#![no_std] #![no_std]
pub use self::arch::*; pub use self::arch::*;
pub use self::data::*;
pub use self::error::*; pub use self::error::*;
pub use self::flag::*;
pub use self::number::*;
pub use self::scheme::*;
#[cfg(target_arch = "x86")] #[cfg(target_arch = "x86")]
#[path="x86.rs"] #[path="x86.rs"]
pub mod arch; mod arch;
#[cfg(target_arch = "x86_64")] #[cfg(target_arch = "x86_64")]
#[path="x86_64.rs"] #[path="x86_64.rs"]
pub mod arch; mod arch;
pub mod data;
pub mod error; pub mod error;
pub const SYS_BRK: usize = 45; pub mod flag;
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;
#[derive(Copy, Clone, Debug, Default)] pub mod number;
#[repr(packed)]
pub struct Stat {
pub st_dev: u16,
pub st_ino: u16,
pub st_mode: u16,
pub st_nlink: u16,
pub st_uid: u16,
pub st_gid: u16,
pub st_rdev: u16,
pub st_size: u32,
pub st_atime: u32,
pub st_mtime: u32,
pub st_ctime: u32
}
#[derive(Copy, Clone, Debug, Default)] pub mod scheme;
#[repr(packed)]
pub struct TimeSpec {
pub tv_sec: i64,
pub tv_nsec: i32,
}
pub unsafe fn brk(addr: usize) -> Result<usize> { pub unsafe fn brk(addr: usize) -> Result<usize> {
syscall1(SYS_BRK, addr) syscall1(SYS_BRK, addr)

28
syscall/src/number.rs Normal file
View 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
View 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))
}
}