From 815c471aed044d05060f19a182fad4da81b30e5a Mon Sep 17 00:00:00 2001 From: Jeremy Soller Date: Thu, 13 Oct 2016 17:21:42 -0600 Subject: [PATCH] Orbital (#16) * Port previous ethernet scheme * Add ipd * Fix initfs rebuilds, use QEMU user networking addresses in ipd * Add tcp/udp, netutils, dns, and network config * Add fsync to network driver * Add dns, router, subnet by default * Fix e1000 driver. Make ethernet and IP non-blocking to avoid deadlocks * Add orbital server, WIP * Add futex * Add orbutils and orbital * Update libstd, orbutils, and orbital Move ANSI key encoding to vesad * Add orbital assets * Update orbital * Update to add login manager * Add blocking primitives, block for most things except waitpid, update orbital * Wait in waitpid and IRQ, improvements for other waits * Fevent in root scheme * WIP: Switch to using fevent * Reorganize * Event based e1000d driver * Superuser-only access to some network schemes, display, and disk * Superuser root and irq schemes * Fix orbital --- ahcid/Cargo.toml | 4 +- ahcid/src/ahci/hba.rs | 26 ++++++-- ahcid/src/main.rs | 40 +++++++++--- ahcid/src/scheme.rs | 22 ++++--- dma/Cargo.toml | 6 -- dma/src/lib.rs | 80 ------------------------ e1000d/Cargo.toml | 5 +- e1000d/src/device.rs | 41 ++++++++++--- e1000d/src/main.rs | 73 ++++++++++++++++++---- io/Cargo.toml | 3 - io/src/io.rs | 67 -------------------- io/src/lib.rs | 14 ----- io/src/mmio.rs | 31 ---------- io/src/pio.rs | 89 --------------------------- ps2d/Cargo.toml | 4 +- ps2d/src/keyboard.rs | 72 +++------------------- ps2d/src/main.rs | 1 + ps2d/src/mouse.rs | 22 ++++--- vesad/Cargo.toml | 1 + vesad/src/main.rs | 1 + vesad/src/scheme.rs | 75 +++++++++++++++++------ vesad/src/screen/graphic.rs | 119 +++++++++++++++++++++++++++++++++++- vesad/src/screen/mod.rs | 26 +++++++- vesad/src/screen/text.rs | 110 +++++++++++++++++++++++++++------ 24 files changed, 483 insertions(+), 449 deletions(-) delete mode 100644 dma/Cargo.toml delete mode 100644 dma/src/lib.rs delete mode 100644 io/Cargo.toml delete mode 100644 io/src/io.rs delete mode 100644 io/src/lib.rs delete mode 100644 io/src/mmio.rs delete mode 100644 io/src/pio.rs diff --git a/ahcid/Cargo.toml b/ahcid/Cargo.toml index 80725d7b71..324ea857b2 100644 --- a/ahcid/Cargo.toml +++ b/ahcid/Cargo.toml @@ -4,7 +4,7 @@ version = "0.1.0" [dependencies] bitflags = "*" -dma = { path = "../dma/" } -io = { path = "../io/" } +dma = { path = "../../crates/dma/" } +io = { path = "../../crates/io/" } spin = "*" syscall = { path = "../../syscall/" } diff --git a/ahcid/src/ahci/hba.rs b/ahcid/src/ahci/hba.rs index 43d29e1f1b..e5ff7ca3d9 100644 --- a/ahcid/src/ahci/hba.rs +++ b/ahcid/src/ahci/hba.rs @@ -25,6 +25,10 @@ const HBA_SIG_ATAPI: u32 = 0xEB140101; const HBA_SIG_PM: u32 = 0x96690101; const HBA_SIG_SEMB: u32 = 0xC33C0101; +fn pause() { + unsafe { asm!("pause" : : : "memory" : "intel", "volatile"); } +} + #[derive(Debug)] pub enum HbaPortType { None, @@ -119,7 +123,9 @@ impl HbaPort { cmdfis.counth.write(0); } - while self.tfd.readf((ATA_DEV_BUSY | ATA_DEV_DRQ) as u32) {} + while self.tfd.readf((ATA_DEV_BUSY | ATA_DEV_DRQ) as u32) { + pause(); + } self.ci.writef(1 << slot, true); @@ -127,6 +133,7 @@ impl HbaPort { if self.is.readf(HBA_PORT_IS_TFES) { return None; } + pause(); } if self.is.readf(HBA_PORT_IS_TFES) { @@ -194,7 +201,9 @@ impl HbaPort { } pub fn start(&mut self) { - while self.cmd.readf(HBA_PORT_CMD_CR) {} + while self.cmd.readf(HBA_PORT_CMD_CR) { + pause(); + } self.cmd.writef(HBA_PORT_CMD_FRE, true); self.cmd.writef(HBA_PORT_CMD_ST, true); @@ -203,7 +212,9 @@ impl HbaPort { pub fn stop(&mut self) { self.cmd.writef(HBA_PORT_CMD_ST, false); - while self.cmd.readf(HBA_PORT_CMD_FR | HBA_PORT_CMD_CR) {} + while self.cmd.readf(HBA_PORT_CMD_FR | HBA_PORT_CMD_CR) { + pause(); + } self.cmd.writef(HBA_PORT_CMD_FRE, false); } @@ -267,7 +278,9 @@ impl HbaPort { cmdfis.counth.write((sectors >> 8) as u8); } - while self.tfd.readf((ATA_DEV_BUSY | ATA_DEV_DRQ) as u32) {} + while self.tfd.readf((ATA_DEV_BUSY | ATA_DEV_DRQ) as u32) { + pause(); + } self.ci.writef(1 << slot, true); @@ -276,6 +289,7 @@ impl HbaPort { println!("IS_TFES set in CI loop TFS {:X} SERR {:X}", self.tfd.read(), self.serr.read()); return Err(Error::new(EIO)); } + pause(); } if self.is.readf(HBA_PORT_IS_TFES) { @@ -312,7 +326,9 @@ pub struct HbaMem { impl HbaMem { pub fn reset(&mut self) { self.ghc.writef(1, true); - while self.ghc.readf(1) {} + while self.ghc.readf(1) { + pause(); + } } } diff --git a/ahcid/src/main.rs b/ahcid/src/main.rs index 7f5ccdad25..880177b65b 100644 --- a/ahcid/src/main.rs +++ b/ahcid/src/main.rs @@ -8,10 +8,11 @@ extern crate io; extern crate spin; extern crate syscall; +use std::{env, thread, usize}; use std::fs::File; use std::io::{Read, Write}; -use std::{env, thread, usize}; -use syscall::{iopl, physmap, physunmap, MAP_WRITE, Packet, Scheme}; +use std::os::unix::io::AsRawFd; +use syscall::{EVENT_READ, MAP_WRITE, Event, Packet, Scheme}; use scheme::DiskScheme; @@ -29,21 +30,42 @@ fn main() { thread::spawn(move || { unsafe { - iopl(3).expect("ahcid: failed to get I/O permission"); + syscall::iopl(3).expect("ahcid: failed to get I/O permission"); asm!("cli" :::: "intel", "volatile"); } - let address = unsafe { physmap(bar, 4096, MAP_WRITE).expect("ahcid: failed to map address") }; + let address = unsafe { syscall::physmap(bar, 4096, MAP_WRITE).expect("ahcid: failed to map address") }; { let mut socket = File::create(":disk").expect("ahcid: failed to create disk scheme"); + let socket_fd = socket.as_raw_fd(); + syscall::fevent(socket_fd, EVENT_READ).expect("ahcid: failed to fevent disk scheme"); + + let mut irq_file = File::open(&format!("irq:{}", irq)).expect("ahcid: failed to open irq file"); + let irq_fd = irq_file.as_raw_fd(); + syscall::fevent(irq_fd, EVENT_READ).expect("ahcid: failed to fevent irq file"); + + let mut event_file = File::open("event:").expect("ahcid: failed to open event file"); + let scheme = DiskScheme::new(ahci::disks(address, irq)); loop { - let mut packet = Packet::default(); - socket.read(&mut packet).expect("ahcid: failed to read disk scheme"); - scheme.handle(&mut packet); - socket.write(&mut packet).expect("ahcid: failed to read disk scheme"); + let mut event = Event::default(); + event_file.read(&mut event).expect("ahcid: failed to read event file"); + if event.id == socket_fd { + let mut packet = Packet::default(); + socket.read(&mut packet).expect("ahcid: failed to read disk scheme"); + scheme.handle(&mut packet); + socket.write(&mut packet).expect("ahcid: failed to write disk scheme"); + } else if event.id == irq_fd { + let mut irq = [0; 8]; + if irq_file.read(&mut irq).expect("ahcid: failed to read irq file") >= irq.len() { + println!("IRQ"); + irq_file.write(&irq).expect("ahcid: failed to write irq file"); + } + } else { + println!("Unknown event {}", event.id); + } } } - unsafe { let _ = physunmap(address); } + unsafe { let _ = syscall::physunmap(address); } }); } diff --git a/ahcid/src/scheme.rs b/ahcid/src/scheme.rs index eb2ec12a12..790e920197 100644 --- a/ahcid/src/scheme.rs +++ b/ahcid/src/scheme.rs @@ -3,7 +3,7 @@ use std::{cmp, str}; use std::sync::Arc; use std::sync::atomic::{AtomicUsize, Ordering}; use spin::Mutex; -use syscall::{Error, EBADF, EINVAL, ENOENT, Result, Scheme, Stat, MODE_FILE, SEEK_CUR, SEEK_END, SEEK_SET}; +use syscall::{Error, EACCES, EBADF, EINVAL, ENOENT, Result, Scheme, Stat, MODE_FILE, SEEK_CUR, SEEK_END, SEEK_SET}; use ahci::disk::Disk; @@ -29,17 +29,21 @@ impl DiskScheme { } impl Scheme for DiskScheme { - fn open(&self, path: &[u8], _flags: usize, _uid: u32, _gid: u32) -> Result { - let path_str = str::from_utf8(path).or(Err(Error::new(ENOENT)))?; + fn open(&self, path: &[u8], _flags: usize, uid: u32, _gid: u32) -> Result { + if uid == 0 { + let path_str = str::from_utf8(path).or(Err(Error::new(ENOENT)))?; - let i = path_str.parse::().or(Err(Error::new(ENOENT)))?; + let i = path_str.parse::().or(Err(Error::new(ENOENT)))?; - if let Some(disk) = self.disks.get(i) { - let id = self.next_id.fetch_add(1, Ordering::SeqCst); - self.handles.lock().insert(id, (disk.clone(), 0)); - Ok(id) + if let Some(disk) = self.disks.get(i) { + let id = self.next_id.fetch_add(1, Ordering::SeqCst); + self.handles.lock().insert(id, (disk.clone(), 0)); + Ok(id) + } else { + Err(Error::new(ENOENT)) + } } else { - Err(Error::new(ENOENT)) + Err(Error::new(EACCES)) } } diff --git a/dma/Cargo.toml b/dma/Cargo.toml deleted file mode 100644 index e05c929079..0000000000 --- a/dma/Cargo.toml +++ /dev/null @@ -1,6 +0,0 @@ -[package] -name = "dma" -version = "0.1.0" - -[dependencies] -syscall = { path = "../../syscall/" } diff --git a/dma/src/lib.rs b/dma/src/lib.rs deleted file mode 100644 index fa8e3d12da..0000000000 --- a/dma/src/lib.rs +++ /dev/null @@ -1,80 +0,0 @@ -#![feature(question_mark)] - -extern crate syscall; - -use std::{mem, ptr}; -use std::ops::{Deref, DerefMut}; - -use syscall::Result; - -struct PhysBox { - address: usize, - size: usize -} - -impl PhysBox { - fn new(size: usize) -> Result { - let address = unsafe { syscall::physalloc(size)? }; - Ok(PhysBox { - address: address, - size: size - }) - } -} - -impl Drop for PhysBox { - fn drop(&mut self) { - let _ = unsafe { syscall::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 { syscall::physmap(phys.address, phys.size, syscall::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 { syscall::physmap(phys.address, phys.size, syscall::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 { syscall::physunmap(self.virt as usize) }; - } -} diff --git a/e1000d/Cargo.toml b/e1000d/Cargo.toml index eacd0d12d8..01413fe6a2 100644 --- a/e1000d/Cargo.toml +++ b/e1000d/Cargo.toml @@ -4,7 +4,8 @@ version = "0.1.0" [dependencies] bitflags = "*" -dma = { path = "../dma/" } -io = { path = "../io/" } +dma = { path = "../../crates/dma/" } +event = { path = "../../crates/event/" } +io = { path = "../../crates/io/" } spin = "*" syscall = { path = "../../syscall/" } diff --git a/e1000d/src/device.rs b/e1000d/src/device.rs index ffe87749da..6674c7c15b 100644 --- a/e1000d/src/device.rs +++ b/e1000d/src/device.rs @@ -1,7 +1,7 @@ use std::{cmp, mem, ptr, slice}; use dma::Dma; -use syscall::error::Result; +use syscall::error::{Error, EACCES, EWOULDBLOCK, Result}; use syscall::scheme::Scheme; const CTRL: u32 = 0x00; @@ -96,12 +96,16 @@ pub struct Intel8254x { receive_buffer: [Dma<[u8; 16384]>; 16], receive_ring: Dma<[Rd; 16]>, transmit_buffer: [Dma<[u8; 16384]>; 16], - transmit_ring: Dma<[Td; 16]>, + transmit_ring: Dma<[Td; 16]> } impl Scheme for Intel8254x { - fn open(&self, _path: &[u8], _flags: usize, _uid: u32, _gid: u32) -> Result { - Ok(0) + fn open(&self, _path: &[u8], _flags: usize, uid: u32, _gid: u32) -> Result { + if uid == 0 { + Ok(0) + } else { + Err(Error::new(EACCES)) + } } fn dup(&self, id: usize) -> Result { @@ -109,7 +113,15 @@ impl Scheme for Intel8254x { } fn read(&self, _id: usize, buf: &mut [u8]) -> Result { - for tail in 0..self.receive_ring.len() { + let head = unsafe { self.read(RDH) }; + let mut tail = unsafe { self.read(RDT) }; + + tail += 1; + if tail >= self.receive_ring.len() as u32 { + tail = 0; + } + + if tail != head { let rd = unsafe { &mut * (self.receive_ring.as_ptr().offset(tail as isize) as *mut Rd) }; if rd.status & RD_DD == RD_DD { rd.status = 0; @@ -121,11 +133,14 @@ impl Scheme for Intel8254x { buf[i] = data[i]; i += 1; } + + unsafe { self.write(RDT, tail) }; + return Ok(i); } } - Ok(0) + Err(Error::new(EWOULDBLOCK)) } fn write(&self, _id: usize, buf: &[u8]) -> Result { @@ -166,8 +181,12 @@ impl Scheme for Intel8254x { return Ok(i); } - } + unsafe { asm!("pause" : : : "memory" : "intel", "volatile"); } + } + } + + fn fsync(&self, _id: usize) -> Result { Ok(0) } @@ -198,6 +217,11 @@ impl Intel8254x { Ok(module) } + pub unsafe fn irq(&self) -> bool { + let icr = self.read(ICR); + icr != 0 + } + pub unsafe fn read(&self, register: u32) -> u32 { ptr::read_volatile((self.base + register as usize) as *mut u32) } @@ -271,8 +295,7 @@ impl Intel8254x { self.write(TDH, 0); self.write(TDT, 0); - //self.write(IMS, IMS_RXT | IMS_RX | IMS_RXDMT | IMS_RXSEQ | IMS_LSC | IMS_TXQE | IMS_TXDW); - self.write(IMS, 0); + self.write(IMS, IMS_RXT | IMS_RX | IMS_RXDMT | IMS_RXSEQ); // | IMS_LSC | IMS_TXQE | IMS_TXDW self.flag(RCTL, RCTL_EN, true); self.flag(RCTL, RCTL_UPE, true); diff --git a/e1000d/src/main.rs b/e1000d/src/main.rs index 9156aab7ee..3b097dfa96 100644 --- a/e1000d/src/main.rs +++ b/e1000d/src/main.rs @@ -2,13 +2,19 @@ #![feature(question_mark)] extern crate dma; +extern crate event; extern crate syscall; +use std::cell::RefCell; use std::{env, thread}; use std::fs::File; -use std::io::{Read, Write}; +use std::io::{Read, Write, Result}; +use std::os::unix::io::AsRawFd; +use std::sync::Arc; -use syscall::{iopl, physmap, physunmap, Packet, Scheme, MAP_WRITE}; +use event::EventQueue; +use syscall::{Packet, Scheme, MAP_WRITE}; +use syscall::error::EWOULDBLOCK; pub mod device; @@ -23,21 +29,66 @@ fn main() { thread::spawn(move || { unsafe { - iopl(3).expect("e1000d: failed to get I/O permission"); + syscall::iopl(3).expect("e1000d: failed to get I/O permission"); asm!("cli" :::: "intel", "volatile"); } - let address = unsafe { physmap(bar, 128*1024, MAP_WRITE).expect("e1000d: failed to map address") }; + let socket = Arc::new(RefCell::new(File::create(":network").expect("e1000d: failed to create network scheme"))); + + let address = unsafe { syscall::physmap(bar, 128*1024, MAP_WRITE).expect("e1000d: failed to map address") }; { - let mut device = unsafe { device::Intel8254x::new(address, irq).expect("e1000d: failed to allocate device") }; - let mut socket = File::create(":network").expect("e1000d: failed to create network scheme"); - loop { + let device = Arc::new(unsafe { device::Intel8254x::new(address, irq).expect("e1000d: failed to allocate device") }); + + let mut event_queue = EventQueue::<()>::new().expect("e1000d: failed to create event queue"); + + let todo = Arc::new(RefCell::new(Vec::::new())); + + let device_irq = device.clone(); + let socket_irq = socket.clone(); + let todo_irq = todo.clone(); + let mut irq_file = File::open(format!("irq:{}", irq)).expect("e1000d: failed to open IRQ file"); + event_queue.add(irq_file.as_raw_fd(), move |_count: usize| -> Result> { + let mut irq = [0; 8]; + irq_file.read(&mut irq)?; + if unsafe { device_irq.irq() } { + irq_file.write(&mut irq)?; + + let mut todo = todo_irq.borrow_mut(); + let mut i = 0; + while i < todo.len() { + let a = todo[i].a; + device_irq.handle(&mut todo[i]); + if todo[i].a == (-EWOULDBLOCK) as usize { + todo[i].a = a; + i += 1; + } else { + socket_irq.borrow_mut().write(&mut todo[i])?; + todo.remove(i); + } + } + } + Ok(None) + }).expect("e1000d: failed to catch events on IRQ file"); + + let socket_fd = socket.borrow().as_raw_fd(); + event_queue.add(socket_fd, move |_count: usize| -> Result> { let mut packet = Packet::default(); - socket.read(&mut packet).expect("e1000d: failed to read network scheme"); + socket.borrow_mut().read(&mut packet)?; + + let a = packet.a; device.handle(&mut packet); - socket.write(&mut packet).expect("e1000d: failed to read network scheme"); - } + if packet.a == (-EWOULDBLOCK) as usize { + packet.a = a; + todo.borrow_mut().push(packet); + } else { + socket.borrow_mut().write(&mut packet)?; + } + + Ok(None) + }).expect("e1000d: failed to catch events on IRQ file"); + + event_queue.run().expect("e1000d: failed to handle events"); } - unsafe { let _ = physunmap(address); } + unsafe { let _ = syscall::physunmap(address); } }); } diff --git a/io/Cargo.toml b/io/Cargo.toml deleted file mode 100644 index b0ee40b297..0000000000 --- a/io/Cargo.toml +++ /dev/null @@ -1,3 +0,0 @@ -[package] -name = "io" -version = "0.1.0" diff --git a/io/src/io.rs b/io/src/io.rs deleted file mode 100644 index fb866b581b..0000000000 --- a/io/src/io.rs +++ /dev/null @@ -1,67 +0,0 @@ -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/io/src/lib.rs b/io/src/lib.rs deleted file mode 100644 index 22f8eb72c0..0000000000 --- a/io/src/lib.rs +++ /dev/null @@ -1,14 +0,0 @@ -//! I/O functions - -#![feature(asm)] -#![feature(const_fn)] -#![feature(core_intrinsics)] -#![no_std] - -pub use self::io::*; -pub use self::mmio::*; -pub use self::pio::*; - -mod io; -mod mmio; -mod pio; diff --git a/io/src/mmio.rs b/io/src/mmio.rs deleted file mode 100644 index 1a1d1996d1..0000000000 --- a/io/src/mmio.rs +++ /dev/null @@ -1,31 +0,0 @@ -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/io/src/pio.rs b/io/src/pio.rs deleted file mode 100644 index 91ae310b62..0000000000 --- a/io/src/pio.rs +++ /dev/null @@ -1,89 +0,0 @@ -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/ps2d/Cargo.toml b/ps2d/Cargo.toml index 665e3c19c8..31bb2526a5 100644 --- a/ps2d/Cargo.toml +++ b/ps2d/Cargo.toml @@ -4,6 +4,6 @@ version = "0.1.0" [dependencies] bitflags = "*" -io = { path = "../io/" } -spin = "*" +io = { path = "../../crates/io/" } +orbclient = "0.1" syscall = { path = "../../syscall/" } diff --git a/ps2d/src/keyboard.rs b/ps2d/src/keyboard.rs index 8eb28583f3..5384d696b7 100644 --- a/ps2d/src/keyboard.rs +++ b/ps2d/src/keyboard.rs @@ -1,7 +1,8 @@ use std::fs::File; use std::io::{Read, Write}; use std::mem; -use std::thread; + +use orbclient::KeyEvent; use keymap; @@ -9,7 +10,6 @@ pub fn keyboard() { let mut file = File::open("irq:1").expect("ps2d: failed to open irq:1"); let mut input = File::open("display:input").expect("ps2d: failed to open display:input"); - let mut ctrl = false; let mut lshift = false; let mut rshift = false; loop { @@ -28,71 +28,17 @@ pub fn keyboard() { (data, true) }; - if scancode == 0x1D { - ctrl = pressed; - } else if scancode == 0x2A { + if scancode == 0x2A { lshift = pressed; } else if scancode == 0x36 { rshift = pressed; - } else if pressed { - match scancode { - f @ 0x3B ... 0x44 => { // F1 through F10 - input.write(&[(f - 0x3B) + 0xF4]).unwrap(); - }, - 0x57 => { // F11 - input.write(&[0xFE]).unwrap(); - }, - 0x58 => { // F12 - input.write(&[0xFF]).unwrap(); - }, - 0x47 => { // Home - input.write(b"\x1B[H").unwrap(); - }, - 0x48 => { // Up - input.write(b"\x1B[A").unwrap(); - }, - 0x49 => { // Page up - input.write(b"\x1B[5~").unwrap(); - }, - 0x4B => { // Left - input.write(b"\x1B[D").unwrap(); - }, - 0x4D => { // Right - input.write(b"\x1B[C").unwrap(); - }, - 0x4F => { // End - input.write(b"\x1B[F").unwrap(); - }, - 0x50 => { // Down - input.write(b"\x1B[B").unwrap(); - }, - 0x51 => { // Page down - input.write(b"\x1B[6~").unwrap(); - }, - 0x52 => { // Insert - input.write(b"\x1B[2~").unwrap(); - }, - 0x53 => { // Delete - input.write(b"\x1B[3~").unwrap(); - }, - _ => { - let c = if ctrl { - match keymap::get_char(scancode, false) { - c @ 'a' ... 'z' => ((c as u8 - b'a') + b'\x01') as char, - c => c - } - } else { - keymap::get_char(scancode, lshift || rshift) - }; - - if c != '\0' { - input.write(&[c as u8]).unwrap(); - } - } - } } - } else { - thread::yield_now(); + + input.write(&KeyEvent { + character: keymap::get_char(scancode, lshift || rshift), + scancode: scancode, + pressed: pressed + }.to_event()).expect("ps2d: failed to write key event"); } } } diff --git a/ps2d/src/main.rs b/ps2d/src/main.rs index 4a3888eab8..60d1bfc3ba 100644 --- a/ps2d/src/main.rs +++ b/ps2d/src/main.rs @@ -3,6 +3,7 @@ #[macro_use] extern crate bitflags; extern crate io; +extern crate orbclient; extern crate syscall; use std::thread; diff --git a/ps2d/src/mouse.rs b/ps2d/src/mouse.rs index f273de9670..f16c9c7e26 100644 --- a/ps2d/src/mouse.rs +++ b/ps2d/src/mouse.rs @@ -1,7 +1,8 @@ use std::fs::File; use std::io::{Read, Write}; use std::mem; -use std::thread; + +use orbclient::MouseEvent; bitflags! { flags MousePacketFlags: u8 { @@ -18,6 +19,7 @@ bitflags! { pub fn mouse(extra_packet: bool) { let mut file = File::open("irq:12").expect("ps2d: failed to open irq:12"); + let mut input = File::open("display:input").expect("ps2d: failed to open display:input"); let mut packets = [0; 4]; let mut packet_i = 0; @@ -40,23 +42,29 @@ pub fn mouse(extra_packet: bool) { 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; + let mut dx = packets[1] as i32; if flags.contains(X_SIGN) { dx -= 0x100; } - let mut dy = packets[2] as isize; + let mut dy = -(packets[2] as i32); if flags.contains(Y_SIGN) { - dy -= 0x100; + dy += 0x100; } - let extra = if extra_packet { + let _extra = if extra_packet { packets[3] } else { 0 }; - print!("ps2d: IRQ {:?}, {}, {}, {}\n", flags, dx, dy, extra); + input.write(&MouseEvent { + x: dx, + y: dy, + left_button: flags.contains(LEFT_BUTTON), + middle_button: flags.contains(MIDDLE_BUTTON), + right_button: flags.contains(RIGHT_BUTTON) + }.to_event()).expect("ps2d: failed to write mouse event"); } else { println!("ps2d: overflow {:X} {:X} {:X} {:X}", packets[0], packets[1], packets[2], packets[3]); } @@ -66,8 +74,6 @@ pub fn mouse(extra_packet: bool) { } file.write(&irqs).expect("ps2d: failed to write irq:12"); - } else { - thread::yield_now(); } } } diff --git a/vesad/Cargo.toml b/vesad/Cargo.toml index ebfdf0bba1..f0dcc23be5 100644 --- a/vesad/Cargo.toml +++ b/vesad/Cargo.toml @@ -3,6 +3,7 @@ name = "vesad" version = "0.1.0" [dependencies] +orbclient = "0.1" ransid = { git = "https://github.com/redox-os/ransid.git", branch = "new_api" } rusttype = { git = "https://github.com/dylanede/rusttype.git", optional = true } syscall = { path = "../../syscall/" } diff --git a/vesad/src/main.rs b/vesad/src/main.rs index 57a13b3ca1..167c111e7f 100644 --- a/vesad/src/main.rs +++ b/vesad/src/main.rs @@ -4,6 +4,7 @@ #![feature(question_mark)] extern crate alloc; +extern crate orbclient; extern crate syscall; use std::fs::File; diff --git a/vesad/src/scheme.rs b/vesad/src/scheme.rs index 4c9155d038..1e48cb211e 100644 --- a/vesad/src/scheme.rs +++ b/vesad/src/scheme.rs @@ -1,26 +1,26 @@ use std::cell::{Cell, RefCell}; use std::collections::BTreeMap; -use std::str; +use std::{mem, slice, str}; -use syscall::{Result, Error, EBADF, ENOENT, Scheme}; +use orbclient::{Event, EventOption}; +use syscall::{Result, Error, EACCES, EBADF, ENOENT, Scheme}; use display::Display; -use screen::TextScreen; +use screen::{Screen, GraphicScreen, TextScreen}; pub struct DisplayScheme { width: usize, height: usize, onscreen: usize, active: Cell, - screens: RefCell> + screens: RefCell>> } impl DisplayScheme { pub fn new(width: usize, height: usize, onscreen: usize) -> DisplayScheme { - let mut screens = BTreeMap::new(); - for i in 1..7 { - screens.insert(i, TextScreen::new(Display::new(width, height, onscreen))); - } + let mut screens: BTreeMap> = BTreeMap::new(); + screens.insert(1, Box::new(TextScreen::new(Display::new(width, height, onscreen)))); + screens.insert(2, Box::new(GraphicScreen::new(Display::new(width, height, onscreen)))); DisplayScheme { width: width, @@ -42,9 +42,13 @@ impl DisplayScheme { } impl Scheme for DisplayScheme { - fn open(&self, path: &[u8], _flags: usize, _uid: u32, _gid: u32) -> Result { + fn open(&self, path: &[u8], _flags: usize, uid: u32, _gid: u32) -> Result { if path == b"input" { - Ok(0) + if uid == 0 { + Ok(0) + } else { + Err(Error::new(EACCES)) + } } else { let path_str = str::from_utf8(path).unwrap_or(""); let id = path_str.parse::().unwrap_or(0); @@ -63,9 +67,7 @@ impl Scheme for DisplayScheme { fn fevent(&self, id: usize, flags: usize) -> Result { let mut screens = self.screens.borrow_mut(); if let Some(mut screen) = screens.get_mut(&id) { - println!("fevent {:X}", flags); - screen.requested = flags; - Ok(0) + screen.event(flags) } else { Err(Error::new(EBADF)) } @@ -76,7 +78,7 @@ impl Scheme for DisplayScheme { let path_str = if id == 0 { format!("display:input") } else if let Some(screen) = screens.get(&id) { - format!("display:{}/{}/{}", id, screen.console.w, screen.console.h) + format!("display:{}/{}/{}", id, screen.width(), screen.height()) } else { return Err(Error::new(EBADF)); }; @@ -124,11 +126,39 @@ impl Scheme for DisplayScheme { } Ok(1) } else { - if let Some(mut screen) = screens.get_mut(&self.active.get()) { - screen.input(buf) - } else { - Err(Error::new(EBADF)) + let events = unsafe { slice::from_raw_parts(buf.as_ptr() as *const Event, buf.len()/mem::size_of::()) }; + + for event in events.iter() { + let new_active_opt = if let EventOption::Key(key_event) = event.to_option() { + match key_event.scancode { + f @ 0x3B ... 0x44 => { // F1 through F10 + Some((f - 0x3A) as usize) + }, + 0x57 => { // F11 + Some(11) + }, + 0x58 => { // F12 + Some(12) + }, + _ => None + } + } else { + None + }; + + if let Some(new_active) = new_active_opt { + if let Some(mut screen) = screens.get_mut(&new_active) { + self.active.set(new_active); + screen.redraw(); + } + } else { + if let Some(mut screen) = screens.get_mut(&self.active.get()) { + screen.input(event); + } + } } + + Ok(events.len() * mem::size_of::()) } } else if let Some(mut screen) = screens.get_mut(&id) { screen.write(buf, id == self.active.get()) @@ -137,6 +167,15 @@ impl Scheme for DisplayScheme { } } + fn seek(&self, id: usize, pos: usize, whence: usize) -> Result { + let mut screens = self.screens.borrow_mut(); + if let Some(mut screen) = screens.get_mut(&id) { + screen.seek(pos, whence) + } else { + Err(Error::new(EBADF)) + } + } + fn close(&self, _id: usize) -> Result { Ok(0) } diff --git a/vesad/src/screen/graphic.rs b/vesad/src/screen/graphic.rs index 9e6b71aa08..11a6e2e935 100644 --- a/vesad/src/screen/graphic.rs +++ b/vesad/src/screen/graphic.rs @@ -1 +1,118 @@ -pub struct GraphicScreen; +use std::collections::VecDeque; +use std::{cmp, mem, slice}; + +use orbclient::{Event, EventOption}; +use syscall::error::*; +use syscall::flag::{SEEK_SET, SEEK_CUR, SEEK_END}; + +use display::Display; +use primitive::fast_copy; +use screen::Screen; + +pub struct GraphicScreen { + pub display: Display, + pub seek: usize, + pub mouse_x: i32, + pub mouse_y: i32, + pub input: VecDeque, + pub requested: usize +} + +impl GraphicScreen { + pub fn new(display: Display) -> GraphicScreen { + GraphicScreen { + display: display, + seek: 0, + mouse_x: 0, + mouse_y: 0, + input: VecDeque::new(), + requested: 0 + } + } +} + +impl Screen for GraphicScreen { + fn width(&self) -> usize { + self.display.width + } + + fn height(&self) -> usize { + self.display.height + } + + fn event(&mut self, flags: usize) -> Result { + self.requested = flags; + Ok(0) + } + + fn input(&mut self, event: &Event) { + if let EventOption::Mouse(mut mouse_event) = event.to_option() { + let x = cmp::max(0, cmp::min(self.display.width as i32, self.mouse_x + mouse_event.x)); + let y = cmp::max(0, cmp::min(self.display.height as i32, self.mouse_y + mouse_event.y)); + + mouse_event.x = x; + self.mouse_x = x; + mouse_event.y = y; + self.mouse_y = y; + + self.input.push_back(mouse_event.to_event()); + } else { + self.input.push_back(*event); + } + } + + fn read(&mut self, buf: &mut [u8]) -> Result { + let mut i = 0; + + let event_buf = unsafe { slice::from_raw_parts_mut(buf.as_mut_ptr() as *mut Event, buf.len()/mem::size_of::()) }; + + while i < event_buf.len() && ! self.input.is_empty() { + event_buf[i] = self.input.pop_front().unwrap(); + i += 1; + } + + Ok(i * mem::size_of::()) + } + + fn will_block(&self) -> bool { + self.input.is_empty() + } + + fn write(&mut self, buf: &[u8], sync: bool) -> Result { + let size = cmp::max(0, cmp::min(self.display.offscreen.len() as isize - self.seek as isize, (buf.len()/4) as isize)) as usize; + + if size > 0 { + unsafe { + fast_copy(self.display.offscreen.as_mut_ptr().offset(self.seek as isize) as *mut u8, buf.as_ptr(), size * 4); + if sync { + fast_copy(self.display.onscreen.as_mut_ptr().offset(self.seek as isize) as *mut u8, buf.as_ptr(), size * 4); + } + } + } + + Ok(size * 4) + } + + fn seek(&mut self, pos: usize, whence: usize) -> Result { + let size = self.display.offscreen.len(); + + self.seek = match whence { + SEEK_SET => cmp::min(size, (pos/4)), + SEEK_CUR => cmp::max(0, cmp::min(size as isize, self.seek as isize + (pos/4) as isize)) as usize, + SEEK_END => cmp::max(0, cmp::min(size as isize, size as isize + (pos/4) as isize)) as usize, + _ => return Err(Error::new(EINVAL)) + }; + + Ok(self.seek * 4) + } + + fn sync(&mut self) { + self.redraw(); + } + + fn redraw(&mut self) { + let width = self.display.width; + let height = self.display.height; + self.display.sync(0, 0, width, height); + } +} diff --git a/vesad/src/screen/mod.rs b/vesad/src/screen/mod.rs index 01e1583213..6a0d5fdfad 100644 --- a/vesad/src/screen/mod.rs +++ b/vesad/src/screen/mod.rs @@ -1,10 +1,30 @@ pub use self::graphic::GraphicScreen; pub use self::text::TextScreen; +use orbclient::Event; +use syscall::Result; + mod graphic; mod text; -pub enum Screen { - Graphic(GraphicScreen), - Text(TextScreen) +pub trait Screen { + fn width(&self) -> usize; + + fn height(&self) -> usize; + + fn event(&mut self, flags: usize) -> Result; + + fn input(&mut self, event: &Event); + + fn read(&mut self, buf: &mut [u8]) -> Result; + + fn will_block(&self) -> bool; + + fn write(&mut self, buf: &[u8], sync: bool) -> Result; + + fn seek(&mut self, pos: usize, whence: usize) -> Result; + + fn sync(&mut self); + + fn redraw(&mut self); } diff --git a/vesad/src/screen/text.rs b/vesad/src/screen/text.rs index bf187b78d2..d61fe7ac5c 100644 --- a/vesad/src/screen/text.rs +++ b/vesad/src/screen/text.rs @@ -2,15 +2,17 @@ extern crate ransid; use std::collections::{BTreeSet, VecDeque}; -use self::ransid::{Console, Event}; +use orbclient::{Event, EventOption}; use syscall::Result; use display::Display; +use screen::Screen; pub struct TextScreen { - pub console: Console, + pub console: ransid::Console, pub display: Display, pub changed: BTreeSet, + pub ctrl: bool, pub input: VecDeque, pub end_of_input: bool, pub cooked: VecDeque, @@ -20,17 +22,88 @@ pub struct TextScreen { impl TextScreen { pub fn new(display: Display) -> TextScreen { TextScreen { - console: Console::new(display.width/8, display.height/16), + console: ransid::Console::new(display.width/8, display.height/16), display: display, changed: BTreeSet::new(), + ctrl: false, input: VecDeque::new(), end_of_input: false, cooked: VecDeque::new(), requested: 0 } } +} + +impl Screen for TextScreen { + fn width(&self) -> usize { + self.console.w + } + + fn height(&self) -> usize { + self.console.h + } + + fn event(&mut self, flags: usize) -> Result { + self.requested = flags; + Ok(0) + } + + fn input(&mut self, event: &Event) { + let mut buf = vec![]; + + match event.to_option() { + EventOption::Key(key_event) => { + if key_event.scancode == 0x1D { + self.ctrl = key_event.pressed; + } else if key_event.pressed { + match key_event.scancode { + 0x47 => { // Home + buf.extend_from_slice(b"\x1B[H"); + }, + 0x48 => { // Up + buf.extend_from_slice(b"\x1B[A"); + }, + 0x49 => { // Page up + buf.extend_from_slice(b"\x1B[5~"); + }, + 0x4B => { // Left + buf.extend_from_slice(b"\x1B[D"); + }, + 0x4D => { // Right + buf.extend_from_slice(b"\x1B[C"); + }, + 0x4F => { // End + buf.extend_from_slice(b"\x1B[F"); + }, + 0x50 => { // Down + buf.extend_from_slice(b"\x1B[B"); + }, + 0x51 => { // Page down + buf.extend_from_slice(b"\x1B[6~"); + }, + 0x52 => { // Insert + buf.extend_from_slice(b"\x1B[2~"); + }, + 0x53 => { // Delete + buf.extend_from_slice(b"\x1B[3~"); + }, + _ => { + let c = match key_event.character { + c @ 'A' ... 'Z' if self.ctrl => ((c as u8 - b'A') + b'\x01') as char, + c @ 'a' ... 'z' if self.ctrl => ((c as u8 - b'a') + b'\x01') as char, + c => c + }; + + if c != '\0' { + buf.extend_from_slice(&[c as u8]); + } + } + } + } + }, + _ => () //TODO: Mouse in terminal + } - pub fn input(&mut self, buf: &[u8]) -> Result { if self.console.raw_mode { for &b in buf.iter() { self.input.push_back(b); @@ -40,11 +113,11 @@ impl TextScreen { match b { b'\x03' => { self.end_of_input = true; - self.write(b"^C\n", true)?; + let _ = self.write(b"^C\n", true); }, b'\x08' | b'\x7F' => { if let Some(_c) = self.cooked.pop_back() { - self.write(b"\x08", true)?; + let _ = self.write(b"\x08", true); } }, b'\n' | b'\r' => { @@ -52,19 +125,18 @@ impl TextScreen { while let Some(c) = self.cooked.pop_front() { self.input.push_back(c); } - self.write(b"\n", true)?; + let _ = self.write(b"\n", true); }, _ => { self.cooked.push_back(b); - self.write(&[b], true)?; + let _ = self.write(&[b], true); } } } } - Ok(buf.len()) } - pub fn read(&mut self, buf: &mut [u8]) -> Result { + fn read(&mut self, buf: &mut [u8]) -> Result { let mut i = 0; while i < buf.len() && ! self.input.is_empty() { @@ -79,11 +151,11 @@ impl TextScreen { Ok(i) } - pub fn will_block(&self) -> bool { + fn will_block(&self) -> bool { self.input.is_empty() && ! self.end_of_input } - pub fn write(&mut self, buf: &[u8], sync: bool) -> Result { + fn write(&mut self, buf: &[u8], sync: bool) -> Result { if self.console.cursor && self.console.x < self.console.w && self.console.y < self.console.h { let x = self.console.x; let y = self.console.y; @@ -97,17 +169,17 @@ impl TextScreen { let changed = &mut self.changed; self.console.write(buf, |event| { match event { - Event::Char { x, y, c, color, bold, .. } => { + ransid::Event::Char { x, y, c, color, bold, .. } => { display.char(x * 8, y * 16, c, color.data, bold, false); changed.insert(y); }, - Event::Rect { x, y, w, h, color } => { + ransid::Event::Rect { x, y, w, h, color } => { display.rect(x * 8, y * 16, w * 8, h * 16, color.data); for y2 in y..y + h { changed.insert(y2); } }, - Event::Scroll { rows, color } => { + ransid::Event::Scroll { rows, color } => { display.scroll(rows * 16, color.data); for y in 0..display.height/16 { changed.insert(y); @@ -132,7 +204,11 @@ impl TextScreen { Ok(buf.len()) } - pub fn sync(&mut self) { + fn seek(&mut self, pos: usize, whence: usize) -> Result { + Ok(0) + } + + fn sync(&mut self) { let width = self.display.width; for change in self.changed.iter() { self.display.sync(0, change * 16, width, 16); @@ -140,7 +216,7 @@ impl TextScreen { self.changed.clear(); } - pub fn redraw(&mut self) { + fn redraw(&mut self) { let width = self.display.width; let height = self.display.height; self.display.sync(0, 0, width, height);