Move redoxerd and add aarch64 support

This commit is contained in:
Wildan M
2025-12-12 00:13:16 +07:00
parent d17a9d8387
commit 76a86e1969
5 changed files with 270 additions and 0 deletions
Generated
+19
View File
@@ -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"
+2
View File
@@ -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",
+14
View File
@@ -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"
+185
View File
@@ -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();
}
}
}
+50
View File
@@ -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(())
}
}