From b5101b25cc8452d4233cc6b4e5b4998a862f8c6c Mon Sep 17 00:00:00 2001 From: Jeremy Soller Date: Mon, 9 Jan 2017 20:12:42 -0700 Subject: [PATCH] Update syscall --- Cargo.toml | 2 +- src/event.rs | 83 ++++++++++++++++++++++++++++++++++++++++++++++ src/io/dma.rs | 76 ++++++++++++++++++++++++++++++++++++++++++ src/io/io.rs | 67 +++++++++++++++++++++++++++++++++++++ src/io/mmio.rs | 31 ++++++++++++++++++ src/io/mod.rs | 16 +++++++++ src/io/pio.rs | 89 ++++++++++++++++++++++++++++++++++++++++++++++++++ src/lib.rs | 8 +++++ 8 files changed, 371 insertions(+), 1 deletion(-) create mode 100644 src/event.rs create mode 100644 src/io/dma.rs create mode 100644 src/io/io.rs create mode 100644 src/io/mmio.rs create mode 100644 src/io/mod.rs create mode 100644 src/io/pio.rs diff --git a/Cargo.toml b/Cargo.toml index a2d3be0..5d90df4 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "redox_syscall" -version = "0.1.15" +version = "0.1.16" description = "A Rust library to access raw Redox system calls" license = "MIT" authors = ["Jeremy Soller "] diff --git a/src/event.rs b/src/event.rs new file mode 100644 index 0000000..a3662a0 --- /dev/null +++ b/src/event.rs @@ -0,0 +1,83 @@ +extern crate syscall; + +use std::collections::BTreeMap; +use std::fs::File; +use std::io::{Read, Error, Result}; +use std::os::unix::io::RawFd; + +pub struct EventQueue { + /// The file to read events from + file: File, + /// A map of registered file descriptors to their handler callbacks + callbacks: BTreeMap Result>>> +} + +impl EventQueue { + /// Create a new event queue + pub fn new() -> Result> { + Ok(EventQueue { + file: File::open("event:")?, + callbacks: BTreeMap::new() + }) + } + + /// Add a file to the event queue, calling a callback when an event occurs + /// + /// The callback is given a mutable reference to the file and the event data + /// (typically the length of data available for read) + /// + /// The callback returns Ok(None) if it wishes to continue the event loop, + /// or Ok(Some(R)) to break the event loop and return the value. + /// Err can be used to allow the callback to return an I/O error, and break the + /// event loop + pub fn add Result> + 'static>(&mut self, fd: RawFd, callback: F) -> Result<()> { + syscall::fevent(fd, syscall::EVENT_READ).map_err(|x| Error::from_raw_os_error(x.errno))?; + + self.callbacks.insert(fd, Box::new(callback)); + + Ok(()) + } + + /// Remove a file from the event queue, returning its callback if found + pub fn remove(&mut self, fd: RawFd) -> Result Result>>>> { + if let Some(callback) = self.callbacks.remove(&fd) { + syscall::fevent(fd, 0).map_err(|x| Error::from_raw_os_error(x.errno))?; + + Ok(Some(callback)) + } else { + Ok(None) + } + } + + /// Send an event to a descriptor callback + pub fn trigger(&mut self, fd: RawFd, count: usize) -> Result> { + if let Some(callback) = self.callbacks.get_mut(&fd) { + callback(count) + } else { + Ok(None) + } + } + + /// Send an event to all descriptor callbacks, useful for cleaning out buffers after init + pub fn trigger_all(&mut self, count: usize) -> Result> { + let mut rets = Vec::new(); + for (_fd, callback) in self.callbacks.iter_mut() { + if let Some(ret) = callback(count)? { + rets.push(ret); + } + } + Ok(rets) + } + + /// Process the event queue until a callback returns Some(R) + pub fn run(&mut self) -> Result { + loop { + let mut event = syscall::Event::default(); + if self.file.read(&mut event)? > 0 { + if let Some(ret) = self.trigger(event.id, event.data)? { + return Ok(ret); + } + } + } + } +} diff --git a/src/io/dma.rs b/src/io/dma.rs new file mode 100644 index 0000000..e2d1b91 --- /dev/null +++ b/src/io/dma.rs @@ -0,0 +1,76 @@ +use std::{mem, ptr}; +use std::ops::{Deref, DerefMut}; + +use Result; + +struct PhysBox { + address: usize, + size: usize +} + +impl PhysBox { + fn new(size: usize) -> Result { + let address = unsafe { ::physalloc(size)? }; + Ok(PhysBox { + address: address, + size: size + }) + } +} + +impl Drop for PhysBox { + fn drop(&mut self) { + let _ = unsafe { ::physfree(self.address, self.size) }; + } +} + +pub struct Dma { + phys: PhysBox, + virt: *mut T +} + +impl Dma { + pub fn new(value: T) -> Result> { + let phys = PhysBox::new(mem::size_of::())?; + let virt = unsafe { ::physmap(phys.address, phys.size, ::MAP_WRITE)? } as *mut T; + unsafe { ptr::write(virt, value); } + Ok(Dma { + phys: phys, + virt: virt + }) + } + + pub fn zeroed() -> Result> { + let phys = PhysBox::new(mem::size_of::())?; + let virt = unsafe { ::physmap(phys.address, phys.size, ::MAP_WRITE)? } as *mut T; + unsafe { ptr::write_bytes(virt as *mut u8, 0, phys.size); } + Ok(Dma { + phys: phys, + virt: virt + }) + } + + pub fn physical(&self) -> usize { + self.phys.address + } +} + +impl Deref for Dma { + type Target = T; + fn deref(&self) -> &T { + unsafe { &*self.virt } + } +} + +impl DerefMut for Dma { + fn deref_mut(&mut self) -> &mut T { + unsafe { &mut *self.virt } + } +} + +impl Drop for Dma { + fn drop(&mut self) { + unsafe { drop(ptr::read(self.virt)); } + let _ = unsafe { ::physunmap(self.virt as usize) }; + } +} diff --git a/src/io/io.rs b/src/io/io.rs new file mode 100644 index 0000000..fb866b5 --- /dev/null +++ b/src/io/io.rs @@ -0,0 +1,67 @@ +use core::cmp::PartialEq; +use core::ops::{BitAnd, BitOr, Not}; + +pub trait Io { + type Value: Copy + PartialEq + BitAnd + BitOr + Not; + + fn read(&self) -> Self::Value; + fn write(&mut self, value: Self::Value); + + #[inline(always)] + fn readf(&self, flags: Self::Value) -> bool { + (self.read() & flags) as Self::Value == flags + } + + #[inline(always)] + fn writef(&mut self, flags: Self::Value, value: bool) { + let tmp: Self::Value = match value { + true => self.read() | flags, + false => self.read() & !flags, + }; + self.write(tmp); + } +} + +pub struct ReadOnly { + inner: I +} + +impl ReadOnly { + pub const fn new(inner: I) -> ReadOnly { + ReadOnly { + inner: inner + } + } + + #[inline(always)] + pub fn read(&self) -> I::Value { + self.inner.read() + } + + #[inline(always)] + pub fn readf(&self, flags: I::Value) -> bool { + self.inner.readf(flags) + } +} + +pub struct WriteOnly { + inner: I +} + +impl WriteOnly { + pub const fn new(inner: I) -> WriteOnly { + WriteOnly { + inner: inner + } + } + + #[inline(always)] + pub fn write(&mut self, value: I::Value) { + self.inner.write(value) + } + + #[inline(always)] + pub fn writef(&mut self, flags: I::Value, value: bool) { + self.inner.writef(flags, value) + } +} diff --git a/src/io/mmio.rs b/src/io/mmio.rs new file mode 100644 index 0000000..1a1d199 --- /dev/null +++ b/src/io/mmio.rs @@ -0,0 +1,31 @@ +use core::intrinsics::{volatile_load, volatile_store}; +use core::mem::uninitialized; +use core::ops::{BitAnd, BitOr, Not}; + +use super::io::Io; + +#[repr(packed)] +pub struct Mmio { + value: T, +} + +impl Mmio { + /// Create a new Mmio without initializing + pub fn new() -> Self { + Mmio { + value: unsafe { uninitialized() } + } + } +} + +impl Io for Mmio where T: Copy + PartialEq + BitAnd + BitOr + Not { + type Value = T; + + fn read(&self) -> T { + unsafe { volatile_load(&self.value) } + } + + fn write(&mut self, value: T) { + unsafe { volatile_store(&mut self.value, value) }; + } +} diff --git a/src/io/mod.rs b/src/io/mod.rs new file mode 100644 index 0000000..367ad5b --- /dev/null +++ b/src/io/mod.rs @@ -0,0 +1,16 @@ +//! I/O functions + +#![feature(asm)] +#![feature(const_fn)] +#![feature(core_intrinsics)] +#![no_std] + +pub use self::dma::*; +pub use self::io::*; +pub use self::mmio::*; +pub use self::pio::*; + +mod dma; +mod io; +mod mmio; +mod pio; diff --git a/src/io/pio.rs b/src/io/pio.rs new file mode 100644 index 0000000..91ae310 --- /dev/null +++ b/src/io/pio.rs @@ -0,0 +1,89 @@ +use core::marker::PhantomData; + +use super::io::Io; + +/// Generic PIO +#[derive(Copy, Clone)] +pub struct Pio { + port: u16, + value: PhantomData, +} + +impl Pio { + /// Create a PIO from a given port + pub const fn new(port: u16) -> Self { + Pio:: { + port: port, + value: PhantomData, + } + } +} + +/// Read/Write for byte PIO +impl Io for Pio { + type Value = u8; + + /// Read + #[inline(always)] + fn read(&self) -> u8 { + let value: u8; + unsafe { + asm!("in $0, $1" : "={al}"(value) : "{dx}"(self.port) : "memory" : "intel", "volatile"); + } + value + } + + /// Write + #[inline(always)] + fn write(&mut self, value: u8) { + unsafe { + asm!("out $1, $0" : : "{al}"(value), "{dx}"(self.port) : "memory" : "intel", "volatile"); + } + } +} + +/// Read/Write for word PIO +impl Io for Pio { + type Value = u16; + + /// Read + #[inline(always)] + fn read(&self) -> u16 { + let value: u16; + unsafe { + asm!("in $0, $1" : "={ax}"(value) : "{dx}"(self.port) : "memory" : "intel", "volatile"); + } + value + } + + /// Write + #[inline(always)] + fn write(&mut self, value: u16) { + unsafe { + asm!("out $1, $0" : : "{ax}"(value), "{dx}"(self.port) : "memory" : "intel", "volatile"); + } + } +} + +/// Read/Write for doubleword PIO +impl Io for Pio { + type Value = u32; + + /// Read + #[inline(always)] + fn read(&self) -> u32 { + let value: u32; + unsafe { + asm!("in $0, $1" : "={eax}"(value) : "{dx}"(self.port) : "memory" : "intel", "volatile"); + } + value + } + + /// Write + #[inline(always)] + fn write(&mut self, value: u32) { + unsafe { + asm!("out $1, $0" : : "{eax}"(value), "{dx}"(self.port) : "memory" : "intel", "volatile"); + } + } +} diff --git a/src/lib.rs b/src/lib.rs index 631c9a3..d394dec 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -5,7 +5,9 @@ pub use self::arch::*; pub use self::call::*; pub use self::data::*; pub use self::error::*; +pub use self::event::*; pub use self::flag::*; +pub use self::io::*; pub use self::number::*; pub use self::scheme::*; @@ -30,9 +32,15 @@ pub mod data; /// All errors that can be generated by a system call pub mod error; +/// Event queue +pub mod event; + /// Flags used as an argument to many system calls pub mod flag; +/// Functions for low level hardware control +pub mod io; + /// Call numbers used by each system call pub mod number;