Move redoxerd and add aarch64 support
This commit is contained in:
Generated
+19
@@ -1423,6 +1423,12 @@ dependencies = [
|
||||
"redox_termios",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "qemu-exit"
|
||||
version = "3.0.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "8bb0fd6580eeed0103c054e3fba2c2618ff476943762f28a645b63b8692b21c9"
|
||||
|
||||
[[package]]
|
||||
name = "quote"
|
||||
version = "1.0.42"
|
||||
@@ -1724,6 +1730,19 @@ version = "0.1.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "20145670ba436b55d91fc92d25e71160fbfbdd57831631c8d7d36377a476f1cb"
|
||||
|
||||
[[package]]
|
||||
name = "redoxerd"
|
||||
version = "0.1.0"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"common",
|
||||
"libredox",
|
||||
"qemu-exit",
|
||||
"redox_event",
|
||||
"redox_syscall",
|
||||
"redox_termios",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "regex"
|
||||
version = "1.12.2"
|
||||
|
||||
@@ -51,6 +51,8 @@ members = [
|
||||
"drivers/net/rtl8168d",
|
||||
"drivers/net/virtio-netd",
|
||||
|
||||
"drivers/redoxerd",
|
||||
|
||||
"drivers/storage/ahcid",
|
||||
"drivers/storage/bcm2835-sdhcid",
|
||||
"drivers/storage/driver-block",
|
||||
|
||||
@@ -0,0 +1,14 @@
|
||||
[package]
|
||||
name = "redoxerd"
|
||||
version = "0.1.0"
|
||||
authors = ["Jeremy Soller <jackpot51@gmail.com>"]
|
||||
edition = "2018"
|
||||
|
||||
[dependencies]
|
||||
anyhow = "1.0"
|
||||
libredox = "0.1"
|
||||
redox_event = "0.4.1"
|
||||
redox_syscall = "0.5"
|
||||
redox_termios = "0.1"
|
||||
common = { path = "../common" }
|
||||
qemu-exit = "3.0.2"
|
||||
@@ -0,0 +1,185 @@
|
||||
use anyhow::Context;
|
||||
use std::fs::{self, OpenOptions};
|
||||
use std::io;
|
||||
use std::os::unix::io::{FromRawFd, IntoRawFd, RawFd};
|
||||
use std::process::{Child, Command, ExitStatus, Stdio};
|
||||
|
||||
mod sys;
|
||||
|
||||
const DEFAULT_COLS: u32 = 80;
|
||||
const DEFAULT_LINES: u32 = 30;
|
||||
|
||||
pub fn syscall_error(error: syscall::Error) -> io::Error {
|
||||
io::Error::from_raw_os_error(error.errno)
|
||||
}
|
||||
|
||||
event::user_data! {
|
||||
enum EventData {
|
||||
Pty,
|
||||
Timer,
|
||||
}
|
||||
}
|
||||
|
||||
fn handle(
|
||||
event_queue: event::EventQueue<EventData>,
|
||||
master_fd: RawFd,
|
||||
timeout_fd: RawFd,
|
||||
process: &mut Child,
|
||||
) -> io::Result<ExitStatus> {
|
||||
let handle_event = |event: EventData| -> io::Result<bool> {
|
||||
match event {
|
||||
EventData::Pty => {
|
||||
let mut packet = [0; 4096];
|
||||
loop {
|
||||
// Read data from PTY master
|
||||
let count = match syscall::read(master_fd as usize, &mut packet) {
|
||||
Ok(0) => return Ok(false),
|
||||
Ok(count) => count,
|
||||
Err(ref err) if err.errno == syscall::EAGAIN => return Ok(true),
|
||||
Err(err) => return Err(syscall_error(err)),
|
||||
};
|
||||
|
||||
// Write data to stdout
|
||||
syscall::write(1, &packet[1..count]).map_err(syscall_error)?;
|
||||
|
||||
for i in 1..count {
|
||||
// Write byte to QEMU debugcon (Bochs compatible)
|
||||
sys::debug_char(packet[i]);
|
||||
}
|
||||
}
|
||||
}
|
||||
EventData::Timer => {
|
||||
let mut timespec = syscall::TimeSpec::default();
|
||||
syscall::read(timeout_fd as usize, &mut timespec).map_err(syscall_error)?;
|
||||
|
||||
timespec.tv_sec += 1;
|
||||
syscall::write(timeout_fd as usize, &mut timespec).map_err(syscall_error)?;
|
||||
|
||||
Ok(true)
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
if handle_event(EventData::Pty)? && handle_event(EventData::Timer)? {
|
||||
'events: loop {
|
||||
match process.try_wait() {
|
||||
Ok(status_opt) => match status_opt {
|
||||
Some(status) => return Ok(status),
|
||||
None => (),
|
||||
},
|
||||
Err(err) => match err.kind() {
|
||||
io::ErrorKind::WouldBlock => (),
|
||||
_ => return Err(err),
|
||||
},
|
||||
}
|
||||
|
||||
let event = event_queue.next_event()?;
|
||||
if !handle_event(event.user_data)? {
|
||||
break 'events;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
let _ = process.kill();
|
||||
process.wait()
|
||||
}
|
||||
|
||||
fn getpty(columns: u32, lines: u32) -> io::Result<(RawFd, String)> {
|
||||
let master = syscall::open(
|
||||
"/scheme/pty",
|
||||
syscall::O_CLOEXEC | syscall::O_RDWR | syscall::O_CREAT | syscall::O_NONBLOCK,
|
||||
)
|
||||
.map_err(syscall_error)?;
|
||||
|
||||
if let Ok(winsize_fd) = syscall::dup(master, b"winsize") {
|
||||
let _ = syscall::write(
|
||||
winsize_fd,
|
||||
&redox_termios::Winsize {
|
||||
ws_row: lines as u16,
|
||||
ws_col: columns as u16,
|
||||
},
|
||||
);
|
||||
let _ = syscall::close(winsize_fd);
|
||||
}
|
||||
|
||||
let mut buf: [u8; 4096] = [0; 4096];
|
||||
let count = syscall::fpath(master, &mut buf).map_err(syscall_error)?;
|
||||
Ok((master as RawFd, unsafe {
|
||||
String::from_utf8_unchecked(Vec::from(&buf[..count]))
|
||||
}))
|
||||
}
|
||||
|
||||
fn inner() -> anyhow::Result<()> {
|
||||
common::acquire_port_io_rights()?;
|
||||
|
||||
let config = fs::read_to_string("/etc/redoxerd").context("Failed to read /etc/redoxerd")?;
|
||||
let mut config_lines = config.lines();
|
||||
|
||||
let (columns, lines) = (DEFAULT_COLS, DEFAULT_LINES);
|
||||
let (master_fd, pty) = getpty(columns, lines)?;
|
||||
|
||||
let timeout_fd = syscall::open(
|
||||
"/scheme/time/4",
|
||||
syscall::O_CLOEXEC | syscall::O_RDWR | syscall::O_NONBLOCK,
|
||||
)
|
||||
.map_err(syscall_error)? as RawFd;
|
||||
|
||||
let event_queue = event::EventQueue::new()?;
|
||||
event_queue.subscribe(master_fd as usize, EventData::Pty, event::EventFlags::READ)?;
|
||||
event_queue.subscribe(
|
||||
timeout_fd as usize,
|
||||
EventData::Timer,
|
||||
event::EventFlags::READ,
|
||||
)?;
|
||||
|
||||
let slave_stdin = OpenOptions::new().read(true).open(&pty)?;
|
||||
let slave_stdout = OpenOptions::new().write(true).open(&pty)?;
|
||||
let slave_stderr = OpenOptions::new().write(true).open(&pty)?;
|
||||
|
||||
let Some(name) = config_lines.next() else {
|
||||
anyhow::bail!("/etc/redoxerd does not specify command");
|
||||
};
|
||||
let mut command = Command::new(name);
|
||||
for arg in config_lines {
|
||||
command.arg(arg);
|
||||
}
|
||||
unsafe {
|
||||
command
|
||||
.stdin(Stdio::from_raw_fd(slave_stdin.into_raw_fd()))
|
||||
.stdout(Stdio::from_raw_fd(slave_stdout.into_raw_fd()))
|
||||
.stderr(Stdio::from_raw_fd(slave_stderr.into_raw_fd()))
|
||||
.env("COLUMNS", format!("{}", columns))
|
||||
.env("LINES", format!("{}", lines))
|
||||
.env("TERM", "xterm-256color")
|
||||
.env("TTY", &pty);
|
||||
}
|
||||
|
||||
let mut process = command
|
||||
.spawn()
|
||||
.with_context(|| format!("Failed to spawn {command:?}"))?;
|
||||
let status = handle(event_queue, master_fd, timeout_fd, &mut process)
|
||||
.with_context(|| format!("Failed to run {name}"))?;
|
||||
if status.success() {
|
||||
Ok(())
|
||||
} else {
|
||||
anyhow::bail!("{name} failed with {}", status);
|
||||
}
|
||||
}
|
||||
|
||||
fn main() {
|
||||
match inner() {
|
||||
Ok(()) => {
|
||||
// Exit with success using qemu device
|
||||
sys::exit_success();
|
||||
}
|
||||
Err(err) => {
|
||||
eprintln!("redoxerd: {:#}", err);
|
||||
|
||||
// Wait a bit for the error message to get flushed through the tty subsystem before exiting.
|
||||
std::thread::sleep(std::time::Duration::from_millis(100));
|
||||
|
||||
// Exit with error using qemu device
|
||||
sys::exit_failure();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,50 @@
|
||||
pub fn exit_success() {
|
||||
imp::exit(true);
|
||||
}
|
||||
|
||||
pub fn exit_failure() {
|
||||
imp::exit(false);
|
||||
}
|
||||
|
||||
pub fn debug_char(b: u8) {
|
||||
let _ = imp::write_debug(b);
|
||||
}
|
||||
|
||||
#[cfg(any(target_arch = "x86", target_arch = "x86_64"))]
|
||||
mod imp {
|
||||
use syscall::Io;
|
||||
use syscall::Pio;
|
||||
|
||||
pub fn exit(success: bool) {
|
||||
if success {
|
||||
Pio::<u16>::new(0x604).write(0x2000);
|
||||
Pio::<u8>::new(0x501).write(51 / 2);
|
||||
} else {
|
||||
Pio::<u8>::new(0x501).write(53 / 2);
|
||||
}
|
||||
}
|
||||
|
||||
pub fn write_debug(b: u8) -> syscall::Result<()> {
|
||||
Pio::<u8>::new(0xe9).write(b);
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(target_arch = "aarch64")]
|
||||
mod imp {
|
||||
use qemu_exit::QEMUExit;
|
||||
|
||||
pub fn exit(success: bool) {
|
||||
let q = qemu_exit::AArch64::new();
|
||||
if success {
|
||||
q.exit(51)
|
||||
} else {
|
||||
q.exit(53)
|
||||
}
|
||||
}
|
||||
|
||||
pub fn write_debug(b: u8) -> syscall::Result<()> {
|
||||
// TODO
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user