Add specification to vesad
Fix piping Fix bug where resources are not closed Add arpd Remove question_mark features
This commit is contained in:
parent
05a5c52f68
commit
ad448956d6
1
Makefile
1
Makefile
|
@ -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 \
|
||||||
|
|
|
@ -1,5 +1,3 @@
|
||||||
#![feature(question_mark)]
|
|
||||||
|
|
||||||
extern crate syscall;
|
extern crate syscall;
|
||||||
|
|
||||||
use std::{mem, ptr};
|
use std::{mem, ptr};
|
||||||
|
|
|
@ -1,5 +1,3 @@
|
||||||
#![feature(question_mark)]
|
|
||||||
|
|
||||||
extern crate syscall;
|
extern crate syscall;
|
||||||
|
|
||||||
pub use resource::Resource;
|
pub use resource::Resource;
|
||||||
|
|
|
@ -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 {
|
||||||
|
|
|
@ -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)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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)
|
{
|
||||||
} else {
|
let mut vec = self.vec.lock();
|
||||||
Ok(self.vec.receive_into(buf))
|
|
||||||
|
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
|
/// 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);
|
|
||||||
|
|
||||||
Ok(buf.len())
|
for &b in buf.iter() {
|
||||||
},
|
vec.push_back(b);
|
||||||
None => Err(Error::new(EPIPE))
|
}
|
||||||
|
|
||||||
|
self.condition.notify();
|
||||||
|
|
||||||
|
Ok(buf.len())
|
||||||
|
} else {
|
||||||
|
Err(Error::new(EPIPE))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl Drop for PipeWrite {
|
||||||
|
fn drop(&mut self) {
|
||||||
|
self.condition.notify();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
@ -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,26 +596,56 @@ 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 mut close_files = Vec::new();
|
|
||||||
{
|
{
|
||||||
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();
|
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);
|
}
|
||||||
|
|
||||||
|
/// 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;
|
let vfork = context.vfork;
|
||||||
context.vfork = false;
|
context.vfork = false;
|
||||||
|
|
||||||
|
context.status = context::Status::Exited(status);
|
||||||
|
|
||||||
context.waitpid.notify();
|
context.waitpid.notify();
|
||||||
|
|
||||||
(vfork, context.ppid)
|
(vfork, context.ppid)
|
||||||
};
|
};
|
||||||
|
|
||||||
if vfork {
|
if vfork {
|
||||||
let contexts = context::contexts();
|
let contexts = context::contexts();
|
||||||
if let Some(parent_lock) = contexts.get(ppid) {
|
if let Some(parent_lock) = contexts.get(ppid) {
|
||||||
|
@ -629,31 +659,6 @@ fn terminate(context_lock: Arc<RwLock<context::Context>>, 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(); }
|
unsafe { context::switch(); }
|
||||||
|
|
||||||
unreachable!();
|
unreachable!();
|
||||||
|
@ -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
6
schemes/arpd/Cargo.toml
Normal file
|
@ -0,0 +1,6 @@
|
||||||
|
[package]
|
||||||
|
name = "arpd"
|
||||||
|
version = "0.1.0"
|
||||||
|
|
||||||
|
[dependencies]
|
||||||
|
syscall = { path = "../../syscall/" }
|
163
schemes/arpd/src/common.rs
Normal file
163
schemes/arpd/src/common.rs
Normal 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
38
schemes/arpd/src/main.rs
Normal 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");
|
||||||
|
});
|
||||||
|
}
|
Loading…
Reference in a new issue