Add specification to vesad

Fix piping
Fix bug where resources are not closed
Add arpd
Remove question_mark features
This commit is contained in:
Jeremy Soller 2016-10-14 18:22:57 -06:00
parent 05a5c52f68
commit ad448956d6
12 changed files with 360 additions and 93 deletions

View file

@ -343,6 +343,7 @@ userutils: \
filesystem/bin/sudo filesystem/bin/sudo
schemes: \ schemes: \
filesystem/bin/arpd \
filesystem/bin/ethernetd \ filesystem/bin/ethernetd \
filesystem/bin/example \ filesystem/bin/example \
filesystem/bin/ipd \ filesystem/bin/ipd \

View file

@ -1,5 +1,3 @@
#![feature(question_mark)]
extern crate syscall; extern crate syscall;
use std::{mem, ptr}; use std::{mem, ptr};

View file

@ -1,5 +1,3 @@
#![feature(question_mark)]
extern crate syscall; extern crate syscall;
pub use resource::Resource; pub use resource::Resource;

View file

@ -1,15 +1,14 @@
#![feature(alloc)] #![feature(alloc)]
#![feature(asm)] #![feature(asm)]
#![feature(heap_api)] #![feature(heap_api)]
#![feature(question_mark)]
extern crate alloc; extern crate alloc;
extern crate orbclient; extern crate orbclient;
extern crate syscall; extern crate syscall;
use std::{env, thread};
use std::fs::File; use std::fs::File;
use std::io::{Read, Write}; use std::io::{Read, Write};
use std::thread;
use syscall::{physmap, physunmap, Packet, Scheme, MAP_WRITE, MAP_WRITE_COMBINE}; use syscall::{physmap, physunmap, Packet, Scheme, MAP_WRITE, MAP_WRITE_COMBINE};
use mode_info::VBEModeInfo; use mode_info::VBEModeInfo;
@ -23,6 +22,18 @@ pub mod scheme;
pub mod screen; pub mod screen;
fn main() { 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 width;
let height; let height;
let physbaseptr; 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") }; 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) }; 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(); let mut blocked = Vec::new();
loop { loop {

View file

@ -13,20 +13,30 @@ pub struct DisplayScheme {
height: usize, height: usize,
onscreen: usize, onscreen: usize,
active: Cell<usize>, active: Cell<usize>,
next_screen: Cell<usize>,
screens: RefCell<BTreeMap<usize, Box<Screen>>> screens: RefCell<BTreeMap<usize, Box<Screen>>>
} }
impl DisplayScheme { 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<usize, Box<Screen>> = BTreeMap::new(); let mut screens: BTreeMap<usize, Box<Screen>> = 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 { DisplayScheme {
width: width, width: width,
height: height, height: height,
onscreen: onscreen, onscreen: onscreen,
active: Cell::new(1), active: Cell::new(1),
next_screen: Cell::new(screen_i),
screens: RefCell::new(screens) screens: RefCell::new(screens)
} }
} }

View file

@ -1,11 +1,13 @@
initfs:bin/pcid initfs:etc/pcid.toml initfs:bin/pcid initfs:etc/pcid.toml
initfs:bin/redoxfs disk:0 initfs:bin/redoxfs disk:0
initfs:bin/pcid file:etc/pcid.toml initfs:bin/pcid file:etc/pcid.toml
file:bin/vesad file:bin/vesad T T G
file:bin/ps2d file:bin/ps2d
file:bin/ethernetd file:bin/ethernetd
file:bin/arpd
file:bin/ipd file:bin/ipd
file:bin/tcpd file:bin/tcpd
file:bin/udpd file:bin/udpd
file:bin/getty display:1 file:bin/getty display:1
#file:bin/orbital display:2 file:bin/getty display:2
#file:bin/orbital display:3

View file

@ -1,9 +1,9 @@
use alloc::arc::{Arc, Weak}; use alloc::arc::{Arc, Weak};
use collections::BTreeMap; use collections::{BTreeMap, VecDeque};
use core::sync::atomic::{AtomicUsize, ATOMIC_USIZE_INIT, Ordering}; 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::error::{Error, Result, EBADF, EPIPE};
use syscall::scheme::Scheme; use syscall::scheme::Scheme;
@ -30,8 +30,8 @@ fn pipes_mut() -> RwLockWriteGuard<'static, (BTreeMap<usize, PipeRead>, BTreeMap
pub fn pipe(_flags: usize) -> (usize, usize) { pub fn pipe(_flags: usize) -> (usize, usize) {
let mut pipes = pipes_mut(); let mut pipes = pipes_mut();
let read_id = PIPE_NEXT_ID.fetch_add(1, Ordering::SeqCst); 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 write_id = PIPE_NEXT_ID.fetch_add(1, Ordering::SeqCst);
let read = PipeRead::new();
let write = PipeWrite::new(&read); let write = PipeWrite::new(&read);
pipes.0.insert(read_id, read); pipes.0.insert(read_id, read);
pipes.1.insert(write_id, write); pipes.1.insert(write_id, write);
@ -104,21 +104,43 @@ impl Scheme for PipeScheme {
/// Read side of a pipe /// Read side of a pipe
#[derive(Clone)] #[derive(Clone)]
pub struct PipeRead { pub struct PipeRead {
vec: Arc<WaitQueue<u8>> condition: Arc<WaitCondition>,
vec: Arc<Mutex<VecDeque<u8>>>
} }
impl PipeRead { impl PipeRead {
pub fn new() -> Self { pub fn new() -> Self {
PipeRead { 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<usize> { fn read(&self, buf: &mut [u8]) -> Result<usize> {
if buf.is_empty() || (Arc::weak_count(&self.vec) == 0 && self.vec.is_empty()) { loop {
Ok(0) {
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 { } else {
Ok(self.vec.receive_into(buf)) 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 /// Read side of a pipe
#[derive(Clone)] #[derive(Clone)]
pub struct PipeWrite { pub struct PipeWrite {
vec: Weak<WaitQueue<u8>>, condition: Arc<WaitCondition>,
vec: Weak<Mutex<VecDeque<u8>>>
} }
impl PipeWrite { impl PipeWrite {
pub fn new(read: &PipeRead) -> Self { pub fn new(read: &PipeRead) -> Self {
PipeWrite { PipeWrite {
condition: read.condition.clone(),
vec: Arc::downgrade(&read.vec), vec: Arc::downgrade(&read.vec),
} }
} }
fn write(&self, buf: &[u8]) -> Result<usize> { fn write(&self, buf: &[u8]) -> Result<usize> {
match self.vec.upgrade() { if let Some(vec_lock) = self.vec.upgrade() {
Some(vec) => { let mut vec = vec_lock.lock();
vec.send_from(buf);
for &b in buf.iter() {
vec.push_back(b);
}
self.condition.notify();
Ok(buf.len()) Ok(buf.len())
}, } else {
None => Err(Error::new(EPIPE)) Err(Error::new(EPIPE))
} }
} }
} }
impl Drop for PipeWrite {
fn drop(&mut self) {
self.condition.notify();
}
}

View file

@ -4,7 +4,7 @@ use alloc::boxed::Box;
use collections::{BTreeMap, Vec}; use collections::{BTreeMap, Vec};
use core::{mem, str}; use core::{mem, str};
use core::ops::DerefMut; use core::ops::DerefMut;
use spin::{Mutex, RwLock}; use spin::Mutex;
use arch; use arch;
use arch::externs::memcpy; use arch::externs::memcpy;
@ -596,39 +596,24 @@ pub fn exec(path: &[u8], arg_ptrs: &[[usize; 2]]) -> Result<usize> {
unsafe { usermode(entry, sp); } unsafe { usermode(entry, sp); }
} }
fn terminate(context_lock: Arc<RwLock<context::Context>>, status: usize) { 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()
};
let mut close_files = Vec::new(); let mut close_files = Vec::new();
{ {
let (vfork, ppid) = {
let mut context = context_lock.write(); 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 { if Arc::strong_count(&context.files) == 1 {
mem::swap(context.files.lock().deref_mut(), &mut close_files); mem::swap(context.files.lock().deref_mut(), &mut close_files);
} }
context.files = Arc::new(Mutex::new(Vec::new())); context.files = Arc::new(Mutex::new(Vec::new()));
context.status = context::Status::Exited(status);
let vfork = context.vfork;
context.vfork = false;
context.waitpid.notify();
(vfork, context.ppid)
};
if vfork {
let contexts = context::contexts();
if let Some(parent_lock) = contexts.get(ppid) {
let mut parent = parent_lock.write();
if ! parent.unblock() {
println!("{} not blocked for exit vfork unblock", ppid);
}
} else {
println!("{} not found for exit vfork unblock", ppid);
}
}
} }
/// Files must be closed while context is valid so that messages can be passed
for (fd, file_option) in close_files.drain(..).enumerate() { for (fd, file_option) in close_files.drain(..).enumerate() {
if let Some(file) = file_option { if let Some(file) = file_option {
context::event::unregister(fd, file.scheme, file.number); context::event::unregister(fd, file.scheme, file.number);
@ -642,16 +627,36 @@ fn terminate(context_lock: Arc<RwLock<context::Context>>, status: usize) {
} }
} }
} }
}
pub fn exit(status: usize) -> ! { let (vfork, ppid) = {
{ let mut context = context_lock.write();
let context_lock = {
let contexts = context::contexts(); context.image.clear();
let context_lock = contexts.current().ok_or(Error::new(ESRCH)).expect("exit failed to find context"); drop(context.heap.take());
context_lock.clone() 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)
}; };
terminate(context_lock, status);
if vfork {
let contexts = context::contexts();
if let Some(parent_lock) = contexts.get(ppid) {
let mut parent = parent_lock.write();
if ! parent.unblock() {
println!("{} not blocked for exit vfork unblock", ppid);
}
} else {
println!("{} not found for exit vfork unblock", ppid);
}
}
} }
unsafe { context::switch(); } unsafe { context::switch(); }
@ -702,45 +707,45 @@ pub fn iopl(_level: usize) -> Result<usize> {
pub fn kill(pid: usize, sig: usize) -> Result<usize> { pub fn kill(pid: usize, sig: usize) -> Result<usize> {
use syscall::flag::*; use syscall::flag::*;
let context_lock = { let _context_lock = {
let contexts = context::contexts(); let contexts = context::contexts();
let context_lock = contexts.get(pid).ok_or(Error::new(ESRCH))?; let context_lock = contexts.get(pid).ok_or(Error::new(ESRCH))?;
context_lock.clone() context_lock.clone()
}; };
let term = |context_lock| { let term = || {
terminate(context_lock, !sig); println!("Terminate {}", pid);
}; };
let core = |context_lock| { let core = || {
terminate(context_lock, !sig); println!("Core {}", pid);
}; };
let stop = || { let stop = || {
println!("Stop {}", pid);
}; };
let cont = || { let cont = || {
println!("Continue {}", pid);
}; };
match sig { match sig {
0 => (), 0 => (),
SIGHUP => term(context_lock), SIGHUP => term(),
SIGINT => term(context_lock), SIGINT => term(),
SIGQUIT => core(context_lock), SIGQUIT => core(),
SIGILL => core(context_lock), SIGILL => core(),
SIGTRAP => core(context_lock), SIGTRAP => core(),
SIGABRT => core(context_lock), SIGABRT => core(),
SIGBUS => core(context_lock), SIGBUS => core(),
SIGFPE => core(context_lock), SIGFPE => core(),
SIGKILL => term(context_lock), SIGKILL => term(),
SIGUSR1 => term(context_lock), SIGUSR1 => term(),
SIGSEGV => core(context_lock), SIGSEGV => core(),
SIGPIPE => term(context_lock), SIGPIPE => term(),
SIGALRM => term(context_lock), SIGALRM => term(),
SIGTERM => term(context_lock), SIGTERM => term(),
SIGSTKFLT => term(context_lock), SIGSTKFLT => term(),
SIGCHLD => (), SIGCHLD => (),
SIGCONT => cont(), SIGCONT => cont(),
SIGSTOP => stop(), SIGSTOP => stop(),
@ -748,14 +753,14 @@ pub fn kill(pid: usize, sig: usize) -> Result<usize> {
SIGTTIN => stop(), SIGTTIN => stop(),
SIGTTOU => stop(), SIGTTOU => stop(),
SIGURG => (), SIGURG => (),
SIGXCPU => core(context_lock), SIGXCPU => core(),
SIGXFSZ => core(context_lock), SIGXFSZ => core(),
SIGVTALRM => term(context_lock), SIGVTALRM => term(),
SIGPROF => term(context_lock), SIGPROF => term(),
SIGWINCH => (), SIGWINCH => (),
SIGIO => term(context_lock), SIGIO => term(),
SIGPWR => term(context_lock), SIGPWR => term(),
SIGSYS => core(context_lock), SIGSYS => core(),
_ => return Err(Error::new(EINVAL)) _ => return Err(Error::new(EINVAL))
} }

@ -1 +1 @@
Subproject commit 17896532dc139fcc42237effbb7e90cf5bb95702 Subproject commit b556eefe6071700905abef862967a316dc5b65c7

6
schemes/arpd/Cargo.toml Normal file
View file

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

163
schemes/arpd/src/common.rs Normal file
View file

@ -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::<u8>().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<u8>,
}
impl Arp {
pub fn from_bytes(bytes: &[u8]) -> Option<Self> {
if bytes.len() >= mem::size_of::<ArpHeader>() {
unsafe {
return Some(Arp {
header: *(bytes.as_ptr() as *const ArpHeader),
data: bytes[mem::size_of::<ArpHeader>() ..].to_vec(),
});
}
}
None
}
pub fn to_bytes(&self) -> Vec<u8> {
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::<ArpHeader>()));
ret.extend_from_slice(&self.data);
ret
}
}
}

38
schemes/arpd/src/main.rs Normal file
View file

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