Implement user schemes. Example in pcid. Currently deadlocks in UserInner
This commit is contained in:
parent
c512d04378
commit
791dbfa7ad
2
Makefile
2
Makefile
|
@ -26,7 +26,7 @@ clean:
|
|||
cargo clean --manifest-path libstd/Cargo.toml
|
||||
cargo clean --manifest-path init/Cargo.toml
|
||||
cargo clean --manifest-path ion/Cargo.toml
|
||||
cargo clean --manifest-path drivers/atkbd/Cargo.toml
|
||||
cargo clean --manifest-path drivers/ps2d/Cargo.toml
|
||||
cargo clean --manifest-path drivers/pcid/Cargo.toml
|
||||
rm -rf build
|
||||
|
||||
|
|
|
@ -2,8 +2,10 @@
|
|||
|
||||
extern crate syscall;
|
||||
|
||||
use std::fs::File;
|
||||
use std::io::{Read, Write};
|
||||
use std::thread;
|
||||
use syscall::iopl;
|
||||
use syscall::{iopl, Packet};
|
||||
|
||||
use pci::{Pci, PciBar, PciClass};
|
||||
|
||||
|
@ -75,5 +77,17 @@ fn main() {
|
|||
unsafe { iopl(3).unwrap() };
|
||||
|
||||
enumerate_pci();
|
||||
|
||||
let mut scheme = File::create(":pci").expect("pcid: failed to create pci scheme");
|
||||
loop {
|
||||
let mut packet = Packet::default();
|
||||
scheme.read(&mut packet).expect("pcid: failed to read events from pci scheme");
|
||||
|
||||
println!("{:?}", packet);
|
||||
|
||||
packet.a = 0;
|
||||
|
||||
scheme.write(&packet).expect("pcid: failed to write responses to pci scheme");
|
||||
}
|
||||
});
|
||||
}
|
||||
|
|
|
@ -5,7 +5,7 @@ use std::thread;
|
|||
|
||||
use keymap;
|
||||
|
||||
pub fn keyboard() {
|
||||
pub fn keyboard() {
|
||||
let mut file = File::open("irq:1").expect("ps2d: failed to open irq:1");
|
||||
|
||||
loop {
|
||||
|
|
|
@ -19,6 +19,7 @@ use self::debug::DebugScheme;
|
|||
use self::env::EnvScheme;
|
||||
use self::initfs::InitFsScheme;
|
||||
use self::irq::IrqScheme;
|
||||
use self::root::RootScheme;
|
||||
|
||||
/// Debug scheme
|
||||
pub mod debug;
|
||||
|
@ -32,6 +33,9 @@ pub mod initfs;
|
|||
/// IRQ handling
|
||||
pub mod irq;
|
||||
|
||||
/// Root scheme
|
||||
pub mod root;
|
||||
|
||||
/// Userspace schemes
|
||||
pub mod user;
|
||||
|
||||
|
@ -102,10 +106,11 @@ static SCHEMES: Once<RwLock<SchemeList>> = Once::new();
|
|||
/// Initialize schemes, called if needed
|
||||
fn init_schemes() -> RwLock<SchemeList> {
|
||||
let mut list: SchemeList = SchemeList::new();
|
||||
list.insert(Box::new(*b"debug"), Arc::new(Box::new(DebugScheme))).expect("failed to insert debug: scheme");
|
||||
list.insert(Box::new(*b"env"), Arc::new(Box::new(EnvScheme::new()))).expect("failed to insert env: scheme");
|
||||
list.insert(Box::new(*b"initfs"), Arc::new(Box::new(InitFsScheme::new()))).expect("failed to insert initfs: scheme");
|
||||
list.insert(Box::new(*b"irq"), Arc::new(Box::new(IrqScheme))).expect("failed to insert irq: scheme");
|
||||
list.insert(Box::new(*b""), Arc::new(Box::new(RootScheme::new()))).expect("failed to insert root scheme");
|
||||
list.insert(Box::new(*b"debug"), Arc::new(Box::new(DebugScheme))).expect("failed to insert debug scheme");
|
||||
list.insert(Box::new(*b"env"), Arc::new(Box::new(EnvScheme::new()))).expect("failed to insert env scheme");
|
||||
list.insert(Box::new(*b"initfs"), Arc::new(Box::new(InitFsScheme::new()))).expect("failed to insert initfs scheme");
|
||||
list.insert(Box::new(*b"irq"), Arc::new(Box::new(IrqScheme))).expect("failed to insert irq scheme");
|
||||
RwLock::new(list)
|
||||
}
|
||||
|
||||
|
|
84
kernel/scheme/root.rs
Normal file
84
kernel/scheme/root.rs
Normal file
|
@ -0,0 +1,84 @@
|
|||
use alloc::arc::Arc;
|
||||
use alloc::boxed::Box;
|
||||
use collections::BTreeMap;
|
||||
use core::sync::atomic::{AtomicUsize, Ordering};
|
||||
use core::str;
|
||||
use spin::RwLock;
|
||||
|
||||
use syscall::{Error, Result};
|
||||
use scheme::{self, Scheme};
|
||||
use scheme::user::{UserInner, UserScheme};
|
||||
|
||||
pub struct RootScheme {
|
||||
next_id: AtomicUsize,
|
||||
handles: RwLock<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 inner = {
|
||||
let mut schemes = scheme::schemes_mut();
|
||||
if schemes.get_name(path).is_some() {
|
||||
return Err(Error::FileExists);
|
||||
}
|
||||
let inner = Arc::new(UserInner::new());
|
||||
schemes.insert(path.to_vec().into_boxed_slice(), Arc::new(Box::new(UserScheme::new(Arc::downgrade(&inner))))).expect("failed to insert user scheme");
|
||||
inner
|
||||
};
|
||||
|
||||
let id = self.next_id.fetch_add(1, Ordering::SeqCst);
|
||||
self.handles.write().insert(id, inner);
|
||||
|
||||
Ok(id)
|
||||
}
|
||||
|
||||
fn dup(&self, file: usize) -> Result<usize> {
|
||||
let inner = {
|
||||
let handles = self.handles.read();
|
||||
let inner = handles.get(&file).ok_or(Error::BadFile)?;
|
||||
inner.clone()
|
||||
};
|
||||
|
||||
let id = self.next_id.fetch_add(1, Ordering::SeqCst);
|
||||
self.handles.write().insert(id, inner);
|
||||
|
||||
Ok(id)
|
||||
}
|
||||
|
||||
fn read(&self, file: usize, buf: &mut [u8]) -> Result<usize> {
|
||||
let inner = {
|
||||
let handles = self.handles.read();
|
||||
let inner = handles.get(&file).ok_or(Error::BadFile)?;
|
||||
inner.clone()
|
||||
};
|
||||
|
||||
inner.read(buf)
|
||||
}
|
||||
|
||||
fn write(&self, file: usize, buf: &[u8]) -> Result<usize> {
|
||||
let inner = {
|
||||
let handles = self.handles.read();
|
||||
let inner = handles.get(&file).ok_or(Error::BadFile)?;
|
||||
inner.clone()
|
||||
};
|
||||
|
||||
inner.write(buf)
|
||||
}
|
||||
|
||||
fn fsync(&self, _file: usize) -> Result<()> {
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn close(&self, file: usize) -> Result<()> {
|
||||
self.handles.write().remove(&file).ok_or(Error::BadFile).and(Ok(()))
|
||||
}
|
||||
}
|
|
@ -1,7 +1,8 @@
|
|||
use alloc::arc::Weak;
|
||||
use collections::{BTreeMap, VecDeque};
|
||||
use core::sync::atomic::{AtomicUsize, Ordering};
|
||||
use core::{mem, usize};
|
||||
use spin::RwLock;
|
||||
use spin::Mutex;
|
||||
|
||||
use context;
|
||||
use syscall::{convert_to_result, Call, Error, Result};
|
||||
|
@ -18,109 +19,125 @@ pub struct Packet {
|
|||
pub d: usize
|
||||
}
|
||||
|
||||
/// UserScheme has to be wrapped
|
||||
pub struct UserScheme {
|
||||
pub struct UserInner {
|
||||
next_id: AtomicUsize,
|
||||
todo: RwLock<VecDeque<Packet>>,
|
||||
done: RwLock<BTreeMap<usize, usize>>
|
||||
todo: Mutex<VecDeque<Packet>>,
|
||||
done: Mutex<BTreeMap<usize, usize>>
|
||||
}
|
||||
|
||||
impl UserScheme {
|
||||
fn call(&self, a: Call, b: usize, c: usize, d: usize) -> Result<usize> {
|
||||
impl UserInner {
|
||||
pub fn new() -> UserInner {
|
||||
UserInner {
|
||||
next_id: AtomicUsize::new(0),
|
||||
todo: Mutex::new(VecDeque::new()),
|
||||
done: Mutex::new(BTreeMap::new())
|
||||
}
|
||||
}
|
||||
|
||||
pub fn call(&self, a: Call, b: usize, c: usize, d: usize) -> Result<usize> {
|
||||
let id = self.next_id.fetch_add(1, Ordering::SeqCst);
|
||||
|
||||
self.todo.write().push_back(Packet {
|
||||
let packet = Packet {
|
||||
id: id,
|
||||
a: a as usize,
|
||||
b: b,
|
||||
c: c,
|
||||
d: d
|
||||
});
|
||||
};
|
||||
|
||||
self.todo.lock().push_back(packet);
|
||||
|
||||
loop {
|
||||
if let Some(a) = self.done.write().remove(&id) {
|
||||
if let Some(a) = self.done.lock().remove(&id) {
|
||||
return convert_to_result(a);
|
||||
}
|
||||
|
||||
unsafe { context::switch(); }
|
||||
}
|
||||
}
|
||||
|
||||
pub fn read(&self, buf: &mut [u8]) -> Result<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> {
|
||||
self.call(Call::Open, path.as_ptr() as usize, path.len(), flags)
|
||||
let inner = self.inner.upgrade().ok_or(Error::NoDevice)?;
|
||||
inner.call(Call::Open, path.as_ptr() as usize, path.len(), flags)
|
||||
}
|
||||
|
||||
fn dup(&self, file: usize) -> Result<usize> {
|
||||
if file == usize::MAX {
|
||||
Ok(file)
|
||||
} else {
|
||||
self.call(Call::Dup, file, 0, 0)
|
||||
}
|
||||
let inner = self.inner.upgrade().ok_or(Error::NoDevice)?;
|
||||
inner.call(Call::Dup, file, 0, 0)
|
||||
}
|
||||
|
||||
fn read(&self, file: usize, buf: &mut [u8]) -> Result<usize> {
|
||||
if file == usize::MAX {
|
||||
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.write();
|
||||
while ! todo.is_empty() && i < len {
|
||||
unsafe { *(buf.as_mut_ptr() as *mut Packet).offset(i as isize) = todo.pop_front().unwrap(); }
|
||||
i += 1;
|
||||
}
|
||||
}
|
||||
|
||||
if i > 0 {
|
||||
return Ok(i * packet_size);
|
||||
} else {
|
||||
unsafe { context::switch(); }
|
||||
}
|
||||
}
|
||||
} else {
|
||||
Ok(0)
|
||||
}
|
||||
} else {
|
||||
self.call(Call::Read, file, buf.as_mut_ptr() as usize, buf.len())
|
||||
}
|
||||
let inner = self.inner.upgrade().ok_or(Error::NoDevice)?;
|
||||
inner.call(Call::Read, file, buf.as_mut_ptr() as usize, buf.len())
|
||||
}
|
||||
|
||||
fn write(&self, file: usize, buf: &[u8]) -> Result<usize> {
|
||||
if file == usize::MAX {
|
||||
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.write().insert(packet.id, packet.a);
|
||||
|
||||
i += 1;
|
||||
}
|
||||
|
||||
Ok(i * packet_size)
|
||||
} else {
|
||||
self.call(Call::Write, file, buf.as_ptr() as usize, buf.len())
|
||||
}
|
||||
let inner = self.inner.upgrade().ok_or(Error::NoDevice)?;
|
||||
inner.call(Call::Write, file, buf.as_ptr() as usize, buf.len())
|
||||
}
|
||||
|
||||
fn fsync(&self, file: usize) -> Result<()> {
|
||||
if file == usize::MAX {
|
||||
Ok(())
|
||||
} else {
|
||||
self.call(Call::FSync, file, 0, 0).and(Ok(()))
|
||||
}
|
||||
let inner = self.inner.upgrade().ok_or(Error::NoDevice)?;
|
||||
inner.call(Call::FSync, file, 0, 0).and(Ok(()))
|
||||
}
|
||||
|
||||
fn close(&self, file: usize) -> Result<()> {
|
||||
if file == usize::MAX {
|
||||
println!("Close user scheme");
|
||||
Ok(())
|
||||
} else {
|
||||
self.call(Call::Close, file, 0, 0).and(Ok(()))
|
||||
}
|
||||
let inner = self.inner.upgrade().ok_or(Error::NoDevice)?;
|
||||
inner.call(Call::Close, file, 0, 0).and(Ok(()))
|
||||
}
|
||||
}
|
||||
|
|
2
libstd
2
libstd
|
@ -1 +1 @@
|
|||
Subproject commit 0d434cc168b1d88211f1a3b72c8290c911432826
|
||||
Subproject commit 3d771c76c4cbd82ad699c59d3bfb645556d90f39
|
|
@ -3,16 +3,19 @@
|
|||
|
||||
pub use self::arch::*;
|
||||
pub use self::error::*;
|
||||
pub use self::scheme::*;
|
||||
|
||||
#[cfg(target_arch = "x86")]
|
||||
#[path="x86.rs"]
|
||||
pub mod arch;
|
||||
mod arch;
|
||||
|
||||
#[cfg(target_arch = "x86_64")]
|
||||
#[path="x86_64.rs"]
|
||||
pub mod arch;
|
||||
mod arch;
|
||||
|
||||
pub mod error;
|
||||
mod error;
|
||||
|
||||
mod scheme;
|
||||
|
||||
pub const SYS_BRK: usize = 45;
|
||||
pub const SYS_CHDIR: usize = 12;
|
||||
|
|
29
syscall/src/scheme.rs
Normal file
29
syscall/src/scheme.rs
Normal file
|
@ -0,0 +1,29 @@
|
|||
use core::ops::{Deref, DerefMut};
|
||||
use core::{mem, slice};
|
||||
|
||||
#[derive(Copy, Clone, Debug, Default)]
|
||||
#[repr(packed)]
|
||||
pub struct Packet {
|
||||
pub id: usize,
|
||||
pub a: usize,
|
||||
pub b: usize,
|
||||
pub c: usize,
|
||||
pub d: usize
|
||||
}
|
||||
|
||||
impl Deref for Packet {
|
||||
type Target = [u8];
|
||||
fn deref(&self) -> &[u8] {
|
||||
unsafe {
|
||||
slice::from_raw_parts(self as *const Packet as *const u8, mem::size_of::<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]
|
||||
}
|
||||
}
|
||||
}
|
Loading…
Reference in a new issue