diff --git a/Makefile b/Makefile index 7f4158e..19de26e 100644 --- a/Makefile +++ b/Makefile @@ -343,6 +343,7 @@ userutils: \ filesystem/bin/sudo schemes: \ + filesystem/bin/arpd \ filesystem/bin/ethernetd \ filesystem/bin/example \ filesystem/bin/ipd \ diff --git a/crates/dma/src/lib.rs b/crates/dma/src/lib.rs index fa8e3d1..557b60a 100644 --- a/crates/dma/src/lib.rs +++ b/crates/dma/src/lib.rs @@ -1,5 +1,3 @@ -#![feature(question_mark)] - extern crate syscall; use std::{mem, ptr}; diff --git a/crates/resource_scheme/src/lib.rs b/crates/resource_scheme/src/lib.rs index 266295f..398110d 100644 --- a/crates/resource_scheme/src/lib.rs +++ b/crates/resource_scheme/src/lib.rs @@ -1,5 +1,3 @@ -#![feature(question_mark)] - extern crate syscall; pub use resource::Resource; diff --git a/drivers/vesad/src/main.rs b/drivers/vesad/src/main.rs index 167c111..f1e1519 100644 --- a/drivers/vesad/src/main.rs +++ b/drivers/vesad/src/main.rs @@ -1,15 +1,14 @@ #![feature(alloc)] #![feature(asm)] #![feature(heap_api)] -#![feature(question_mark)] extern crate alloc; extern crate orbclient; extern crate syscall; +use std::{env, thread}; use std::fs::File; use std::io::{Read, Write}; -use std::thread; use syscall::{physmap, physunmap, Packet, Scheme, MAP_WRITE, MAP_WRITE_COMBINE}; use mode_info::VBEModeInfo; @@ -23,6 +22,18 @@ pub mod scheme; pub mod screen; fn main() { + let mut spec = Vec::new(); + + for arg in env::args().skip(1) { + if arg == "T" { + spec.push(false); + } else if arg == "G" { + spec.push(true); + } else { + println!("vesad: unknown screen type: {}", arg); + } + } + let width; let height; let physbaseptr; @@ -46,7 +57,7 @@ fn main() { let onscreen = unsafe { physmap(physbaseptr, size * 4, MAP_WRITE | MAP_WRITE_COMBINE).expect("vesad: failed to map VBE LFB") }; unsafe { fast_set64(onscreen as *mut u64, 0, size/2) }; - let scheme = DisplayScheme::new(width, height, onscreen); + let scheme = DisplayScheme::new(width, height, onscreen, &spec); let mut blocked = Vec::new(); loop { diff --git a/drivers/vesad/src/scheme.rs b/drivers/vesad/src/scheme.rs index 1e48cb2..91484a1 100644 --- a/drivers/vesad/src/scheme.rs +++ b/drivers/vesad/src/scheme.rs @@ -13,20 +13,30 @@ pub struct DisplayScheme { height: usize, onscreen: usize, active: Cell, + next_screen: Cell, screens: RefCell>> } impl DisplayScheme { - pub fn new(width: usize, height: usize, onscreen: usize) -> DisplayScheme { + pub fn new(width: usize, height: usize, onscreen: usize, spec: &[bool]) -> DisplayScheme { 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)))); + + let mut screen_i = 1; + for &screen_type in spec.iter() { + if screen_type { + screens.insert(screen_i, Box::new(GraphicScreen::new(Display::new(width, height, onscreen)))); + } else { + screens.insert(screen_i, Box::new(TextScreen::new(Display::new(width, height, onscreen)))); + } + screen_i += 1; + } DisplayScheme { width: width, height: height, onscreen: onscreen, active: Cell::new(1), + next_screen: Cell::new(screen_i), screens: RefCell::new(screens) } } diff --git a/initfs/etc/init.rc b/initfs/etc/init.rc index 9699741..6061532 100644 --- a/initfs/etc/init.rc +++ b/initfs/etc/init.rc @@ -1,11 +1,13 @@ initfs:bin/pcid initfs:etc/pcid.toml initfs:bin/redoxfs disk:0 initfs:bin/pcid file:etc/pcid.toml -file:bin/vesad +file:bin/vesad T T G file:bin/ps2d file:bin/ethernetd +file:bin/arpd file:bin/ipd file:bin/tcpd file:bin/udpd file:bin/getty display:1 -#file:bin/orbital display:2 +file:bin/getty display:2 +#file:bin/orbital display:3 diff --git a/kernel/scheme/pipe.rs b/kernel/scheme/pipe.rs index a17be8f..fcf8a08 100644 --- a/kernel/scheme/pipe.rs +++ b/kernel/scheme/pipe.rs @@ -1,9 +1,9 @@ use alloc::arc::{Arc, Weak}; -use collections::BTreeMap; +use collections::{BTreeMap, VecDeque}; use core::sync::atomic::{AtomicUsize, ATOMIC_USIZE_INIT, Ordering}; -use spin::{Once, RwLock, RwLockReadGuard, RwLockWriteGuard}; +use spin::{Mutex, Once, RwLock, RwLockReadGuard, RwLockWriteGuard}; -use sync::WaitQueue; +use sync::WaitCondition; use syscall::error::{Error, Result, EBADF, EPIPE}; use syscall::scheme::Scheme; @@ -30,8 +30,8 @@ fn pipes_mut() -> RwLockWriteGuard<'static, (BTreeMap, BTreeMap pub fn pipe(_flags: usize) -> (usize, usize) { let mut pipes = pipes_mut(); let read_id = PIPE_NEXT_ID.fetch_add(1, Ordering::SeqCst); - let read = PipeRead::new(); let write_id = PIPE_NEXT_ID.fetch_add(1, Ordering::SeqCst); + let read = PipeRead::new(); let write = PipeWrite::new(&read); pipes.0.insert(read_id, read); pipes.1.insert(write_id, write); @@ -104,21 +104,43 @@ impl Scheme for PipeScheme { /// Read side of a pipe #[derive(Clone)] pub struct PipeRead { - vec: Arc> + condition: Arc, + vec: Arc>> } impl PipeRead { pub fn new() -> Self { PipeRead { - vec: Arc::new(WaitQueue::new()) + condition: Arc::new(WaitCondition::new()), + vec: Arc::new(Mutex::new(VecDeque::new())), } } fn read(&self, buf: &mut [u8]) -> Result { - if buf.is_empty() || (Arc::weak_count(&self.vec) == 0 && self.vec.is_empty()) { - Ok(0) - } else { - Ok(self.vec.receive_into(buf)) + loop { + { + let mut vec = self.vec.lock(); + + let mut i = 0; + while i < buf.len() { + if let Some(b) = vec.pop_front() { + buf[i] = b; + i += 1; + } else { + break; + } + } + + if i > 0 { + return Ok(i); + } + } + + if Arc::weak_count(&self.vec) == 0 { + return Ok(0); + } else { + self.condition.wait(); + } } } } @@ -126,24 +148,37 @@ impl PipeRead { /// Read side of a pipe #[derive(Clone)] pub struct PipeWrite { - vec: Weak>, + condition: Arc, + vec: Weak>> } impl PipeWrite { pub fn new(read: &PipeRead) -> Self { PipeWrite { + condition: read.condition.clone(), vec: Arc::downgrade(&read.vec), } } fn write(&self, buf: &[u8]) -> Result { - match self.vec.upgrade() { - Some(vec) => { - vec.send_from(buf); + if let Some(vec_lock) = self.vec.upgrade() { + let mut vec = vec_lock.lock(); - Ok(buf.len()) - }, - None => Err(Error::new(EPIPE)) + for &b in buf.iter() { + vec.push_back(b); + } + + self.condition.notify(); + + Ok(buf.len()) + } else { + Err(Error::new(EPIPE)) } } } + +impl Drop for PipeWrite { + fn drop(&mut self) { + self.condition.notify(); + } +} diff --git a/kernel/syscall/process.rs b/kernel/syscall/process.rs index 721211c..5763c89 100644 --- a/kernel/syscall/process.rs +++ b/kernel/syscall/process.rs @@ -4,7 +4,7 @@ use alloc::boxed::Box; use collections::{BTreeMap, Vec}; use core::{mem, str}; use core::ops::DerefMut; -use spin::{Mutex, RwLock}; +use spin::Mutex; use arch; use arch::externs::memcpy; @@ -596,26 +596,56 @@ pub fn exec(path: &[u8], arg_ptrs: &[[usize; 2]]) -> Result { unsafe { usermode(entry, sp); } } -fn terminate(context_lock: Arc>, status: usize) { - let mut close_files = Vec::new(); +pub fn exit(status: usize) -> ! { { - let (vfork, ppid) = { + let context_lock = { + let contexts = context::contexts(); + let context_lock = contexts.current().ok_or(Error::new(ESRCH)).expect("exit failed to find context"); + context_lock.clone() + }; + + let mut close_files = Vec::new(); + { let mut context = context_lock.write(); - context.image.clear(); - drop(context.heap.take()); - drop(context.stack.take()); - context.grants = Arc::new(Mutex::new(Vec::new())); if Arc::strong_count(&context.files) == 1 { mem::swap(context.files.lock().deref_mut(), &mut close_files); } context.files = Arc::new(Mutex::new(Vec::new())); - context.status = context::Status::Exited(status); + } + + /// Files must be closed while context is valid so that messages can be passed + for (fd, file_option) in close_files.drain(..).enumerate() { + if let Some(file) = file_option { + context::event::unregister(fd, file.scheme, file.number); + + let scheme_option = { + let schemes = scheme::schemes(); + schemes.get(file.scheme).map(|scheme| scheme.clone()) + }; + if let Some(scheme) = scheme_option { + let _ = scheme.close(file.number); + } + } + } + + let (vfork, ppid) = { + let mut context = context_lock.write(); + + context.image.clear(); + drop(context.heap.take()); + drop(context.stack.take()); + context.grants = Arc::new(Mutex::new(Vec::new())); let vfork = context.vfork; context.vfork = false; + + context.status = context::Status::Exited(status); + context.waitpid.notify(); + (vfork, context.ppid) }; + if vfork { let contexts = context::contexts(); if let Some(parent_lock) = contexts.get(ppid) { @@ -629,31 +659,6 @@ fn terminate(context_lock: Arc>, status: usize) { } } - for (fd, file_option) in close_files.drain(..).enumerate() { - if let Some(file) = file_option { - context::event::unregister(fd, file.scheme, file.number); - - let scheme_option = { - let schemes = scheme::schemes(); - schemes.get(file.scheme).map(|scheme| scheme.clone()) - }; - if let Some(scheme) = scheme_option { - let _ = scheme.close(file.number); - } - } - } -} - -pub fn exit(status: usize) -> ! { - { - let context_lock = { - let contexts = context::contexts(); - let context_lock = contexts.current().ok_or(Error::new(ESRCH)).expect("exit failed to find context"); - context_lock.clone() - }; - terminate(context_lock, status); - } - unsafe { context::switch(); } unreachable!(); @@ -702,45 +707,45 @@ pub fn iopl(_level: usize) -> Result { pub fn kill(pid: usize, sig: usize) -> Result { use syscall::flag::*; - let context_lock = { + let _context_lock = { let contexts = context::contexts(); let context_lock = contexts.get(pid).ok_or(Error::new(ESRCH))?; context_lock.clone() }; - let term = |context_lock| { - terminate(context_lock, !sig); + let term = || { + println!("Terminate {}", pid); }; - let core = |context_lock| { - terminate(context_lock, !sig); + let core = || { + println!("Core {}", pid); }; let stop = || { - + println!("Stop {}", pid); }; let cont = || { - + println!("Continue {}", pid); }; match sig { 0 => (), - SIGHUP => term(context_lock), - SIGINT => term(context_lock), - SIGQUIT => core(context_lock), - SIGILL => core(context_lock), - SIGTRAP => core(context_lock), - SIGABRT => core(context_lock), - SIGBUS => core(context_lock), - SIGFPE => core(context_lock), - SIGKILL => term(context_lock), - SIGUSR1 => term(context_lock), - SIGSEGV => core(context_lock), - SIGPIPE => term(context_lock), - SIGALRM => term(context_lock), - SIGTERM => term(context_lock), - SIGSTKFLT => term(context_lock), + SIGHUP => term(), + SIGINT => term(), + SIGQUIT => core(), + SIGILL => core(), + SIGTRAP => core(), + SIGABRT => core(), + SIGBUS => core(), + SIGFPE => core(), + SIGKILL => term(), + SIGUSR1 => term(), + SIGSEGV => core(), + SIGPIPE => term(), + SIGALRM => term(), + SIGTERM => term(), + SIGSTKFLT => term(), SIGCHLD => (), SIGCONT => cont(), SIGSTOP => stop(), @@ -748,14 +753,14 @@ pub fn kill(pid: usize, sig: usize) -> Result { SIGTTIN => stop(), SIGTTOU => stop(), SIGURG => (), - SIGXCPU => core(context_lock), - SIGXFSZ => core(context_lock), - SIGVTALRM => term(context_lock), - SIGPROF => term(context_lock), + SIGXCPU => core(), + SIGXFSZ => core(), + SIGVTALRM => term(), + SIGPROF => term(), SIGWINCH => (), - SIGIO => term(context_lock), - SIGPWR => term(context_lock), - SIGSYS => core(context_lock), + SIGIO => term(), + SIGPWR => term(), + SIGSYS => core(), _ => return Err(Error::new(EINVAL)) } diff --git a/programs/userutils b/programs/userutils index 1789653..b556eef 160000 --- a/programs/userutils +++ b/programs/userutils @@ -1 +1 @@ -Subproject commit 17896532dc139fcc42237effbb7e90cf5bb95702 +Subproject commit b556eefe6071700905abef862967a316dc5b65c7 diff --git a/schemes/arpd/Cargo.toml b/schemes/arpd/Cargo.toml new file mode 100644 index 0000000..d49d243 --- /dev/null +++ b/schemes/arpd/Cargo.toml @@ -0,0 +1,6 @@ +[package] +name = "arpd" +version = "0.1.0" + +[dependencies] +syscall = { path = "../../syscall/" } diff --git a/schemes/arpd/src/common.rs b/schemes/arpd/src/common.rs new file mode 100644 index 0000000..93a3d93 --- /dev/null +++ b/schemes/arpd/src/common.rs @@ -0,0 +1,163 @@ +use std::{mem, slice, u8, u16}; + +pub static mut MAC_ADDR: MacAddr = MacAddr { bytes: [0x50, 0x51, 0x52, 0x53, 0x54, 0x55] }; + +pub static mut IP_ADDR: Ipv4Addr = Ipv4Addr { bytes: [10, 0, 2, 15] }; + +#[derive(Copy, Clone)] +#[allow(non_camel_case_types)] +#[repr(packed)] +pub struct n16(u16); + +impl n16 { + pub fn new(value: u16) -> Self { + n16(value.to_be()) + } + + pub fn get(&self) -> u16 { + u16::from_be(self.0) + } + + pub fn set(&mut self, value: u16) { + self.0 = value.to_be(); + } +} + +#[derive(Copy, Clone)] +pub struct MacAddr { + pub bytes: [u8; 6], +} + +impl MacAddr { + pub fn equals(&self, other: Self) -> bool { + for i in 0..6 { + if self.bytes[i] != other.bytes[i] { + return false; + } + } + true + } + + pub fn from_str(string: &str) -> Self { + let mut addr = MacAddr { bytes: [0, 0, 0, 0, 0, 0] }; + + let mut i = 0; + for part in string.split('.') { + let octet = u8::from_str_radix(part, 16).unwrap_or(0); + match i { + 0 => addr.bytes[0] = octet, + 1 => addr.bytes[1] = octet, + 2 => addr.bytes[2] = octet, + 3 => addr.bytes[3] = octet, + 4 => addr.bytes[4] = octet, + 5 => addr.bytes[5] = octet, + _ => break, + } + i += 1; + } + + addr + } + + pub fn to_string(&self) -> String { + let mut string = String::new(); + for i in 0..6 { + if i > 0 { + string.push('.'); + } + string.push_str(&format!("{:X}", self.bytes[i])); + } + string + } +} + +#[derive(Copy, Clone)] +pub struct Ipv4Addr { + pub bytes: [u8; 4], +} + +impl Ipv4Addr { + pub fn equals(&self, other: Self) -> bool { + for i in 0..4 { + if self.bytes[i] != other.bytes[i] { + return false; + } + } + true + } + + pub fn from_str(string: &str) -> Self { + let mut addr = Ipv4Addr { bytes: [0, 0, 0, 0] }; + + let mut i = 0; + for part in string.split('.') { + let octet = part.parse::().unwrap_or(0); + match i { + 0 => addr.bytes[0] = octet, + 1 => addr.bytes[1] = octet, + 2 => addr.bytes[2] = octet, + 3 => addr.bytes[3] = octet, + _ => break, + } + i += 1; + } + + addr + } + + pub fn to_string(&self) -> String { + let mut string = String::new(); + + for i in 0..4 { + if i > 0 { + string = string + "."; + } + string = string + &format!("{}", self.bytes[i]); + } + + string + } +} + +#[derive(Copy, Clone)] +#[repr(packed)] +pub struct ArpHeader { + pub htype: n16, + pub ptype: n16, + pub hlen: u8, + pub plen: u8, + pub oper: n16, + pub src_mac: MacAddr, + pub src_ip: Ipv4Addr, + pub dst_mac: MacAddr, + pub dst_ip: Ipv4Addr, +} + +pub struct Arp { + pub header: ArpHeader, + pub data: Vec, +} + +impl Arp { + pub fn from_bytes(bytes: &[u8]) -> Option { + if bytes.len() >= mem::size_of::() { + unsafe { + return Some(Arp { + header: *(bytes.as_ptr() as *const ArpHeader), + data: bytes[mem::size_of::() ..].to_vec(), + }); + } + } + None + } + + pub fn to_bytes(&self) -> Vec { + unsafe { + let header_ptr: *const ArpHeader = &self.header; + let mut ret = Vec::from(slice::from_raw_parts(header_ptr as *const u8, + mem::size_of::())); + ret.extend_from_slice(&self.data); + ret + } + } +} diff --git a/schemes/arpd/src/main.rs b/schemes/arpd/src/main.rs new file mode 100644 index 0000000..634a31d --- /dev/null +++ b/schemes/arpd/src/main.rs @@ -0,0 +1,38 @@ +extern crate syscall; + +use std::thread; + +use common::{MAC_ADDR, IP_ADDR, Arp}; + +pub mod common; + +fn main() { + thread::spawn(move || { + while let Ok(link) = syscall::open("ethernet:/806", syscall::O_RDWR) { + loop { + let mut bytes = [0; 65536]; + if let Ok(count) = syscall::read(link, &mut bytes) { + if let Some(packet) = Arp::from_bytes(&bytes[..count]) { + if packet.header.oper.get() == 1 && packet.header.dst_ip.equals(unsafe { IP_ADDR }) { + let mut response = Arp { + header: packet.header, + data: packet.data.clone(), + }; + response.header.oper.set(2); + response.header.dst_mac = packet.header.src_mac; + response.header.dst_ip = packet.header.src_ip; + response.header.src_mac = unsafe { MAC_ADDR }; + response.header.src_ip = unsafe { IP_ADDR }; + + let _ = syscall::write(link, &response.to_bytes()); + } + } + } else { + break; + } + } + let _ = syscall::close(link); + } + panic!("ARP: Failed to open ethernet"); + }); +}