feat: Introduce userspace namespace manager and adapt all schemes.

This commit is contained in:
Ibuki Omatsu
2026-01-21 03:56:58 +00:00
committed by Jeremy Soller
parent 1753859f75
commit 334928f151
90 changed files with 3069 additions and 1125 deletions
Generated
+66 -64
View File
@@ -14,7 +14,7 @@ dependencies = [
"pcid",
"redox-scheme",
"redox_event",
"redox_syscall 0.6.0",
"redox_syscall 0.7.0",
"spin 0.9.8",
]
@@ -48,7 +48,7 @@ dependencies = [
"plain",
"redox-scheme",
"redox_event",
"redox_syscall 0.6.0",
"redox_syscall 0.7.0",
"ron",
"rustc-hash",
"serde",
@@ -68,7 +68,7 @@ dependencies = [
"log",
"pcid",
"redox_event",
"redox_syscall 0.6.0",
"redox_syscall 0.7.0",
]
[[package]]
@@ -90,7 +90,7 @@ dependencies = [
"libredox",
"redox-scheme",
"redox_event",
"redox_syscall 0.6.0",
"redox_syscall 0.7.0",
]
[[package]]
@@ -214,7 +214,7 @@ dependencies = [
"libc",
"libredox",
"redox-scheme",
"redox_syscall 0.6.0",
"redox_syscall 0.7.0",
]
[[package]]
@@ -245,7 +245,7 @@ dependencies = [
"fdt 0.2.0-alpha1",
"libredox",
"redox_event",
"redox_syscall 0.6.0",
"redox_syscall 0.7.0",
]
[[package]]
@@ -260,7 +260,7 @@ dependencies = [
"orbclient",
"pcid",
"redox-scheme",
"redox_syscall 0.6.0",
"redox_syscall 0.7.0",
]
[[package]]
@@ -462,7 +462,7 @@ dependencies = [
"libredox",
"log",
"redox-log",
"redox_syscall 0.6.0",
"redox_syscall 0.7.0",
]
[[package]]
@@ -600,7 +600,7 @@ dependencies = [
"log",
"partitionlib",
"redox-scheme",
"redox_syscall 0.6.0",
"redox_syscall 0.7.0",
]
[[package]]
@@ -614,7 +614,7 @@ dependencies = [
"libredox",
"log",
"redox-scheme",
"redox_syscall 0.6.0",
"redox_syscall 0.7.0",
]
[[package]]
@@ -624,7 +624,7 @@ dependencies = [
"daemon",
"libredox",
"redox-scheme",
"redox_syscall 0.6.0",
"redox_syscall 0.7.0",
]
[[package]]
@@ -677,7 +677,7 @@ dependencies = [
"log",
"pcid",
"redox_event",
"redox_syscall 0.6.0",
"redox_syscall 0.7.0",
]
[[package]]
@@ -757,7 +757,7 @@ dependencies = [
"ransid",
"redox-scheme",
"redox_event",
"redox_syscall 0.6.0",
"redox_syscall 0.7.0",
]
[[package]]
@@ -776,7 +776,7 @@ dependencies = [
"ransid",
"redox-scheme",
"redox_event",
"redox_syscall 0.6.0",
"redox_syscall 0.7.0",
]
[[package]]
@@ -903,7 +903,7 @@ dependencies = [
[[package]]
name = "generic-rt"
version = "0.1.0"
source = "git+https://gitlab.redox-os.org/redox-os/relibc.git#3362ca356a9dafdfd7d74fc88d97609f400f7329"
source = "git+https://gitlab.redox-os.org/redox-os/relibc.git#3a8f64aa143184dc11fe1927a4f9e55c33ae3052"
[[package]]
name = "getrandom"
@@ -960,7 +960,7 @@ dependencies = [
"libredox",
"log",
"redox-ioctl",
"redox_syscall 0.6.0",
"redox_syscall 0.7.0",
]
[[package]]
@@ -1019,6 +1019,7 @@ dependencies = [
"common",
"daemon",
"fdt 0.1.5",
"libredox",
"log",
"ron",
]
@@ -1058,7 +1059,7 @@ dependencies = [
"log",
"pcid",
"redox_event",
"redox_syscall 0.6.0",
"redox_syscall 0.7.0",
]
[[package]]
@@ -1073,7 +1074,7 @@ dependencies = [
"pcid",
"redox-scheme",
"redox_event",
"redox_syscall 0.6.0",
"redox_syscall 0.7.0",
"spin 0.9.8",
]
@@ -1097,7 +1098,7 @@ dependencies = [
"range-alloc",
"redox-scheme",
"redox_event",
"redox_syscall 0.6.0",
"redox_syscall 0.7.0",
"void",
]
@@ -1129,7 +1130,7 @@ dependencies = [
"log",
"orbclient",
"redox-scheme",
"redox_syscall 0.6.0",
"redox_syscall 0.7.0",
]
[[package]]
@@ -1154,7 +1155,7 @@ dependencies = [
"redox-rt",
"redox-scheme",
"redox_event",
"redox_syscall 0.6.0",
"redox_syscall 0.7.0",
]
[[package]]
@@ -1180,7 +1181,7 @@ dependencies = [
"libredox",
"pcid",
"redox_event",
"redox_syscall 0.6.0",
"redox_syscall 0.7.0",
]
[[package]]
@@ -1207,14 +1208,14 @@ checksum = "bcc35a38544a891a5f7c865aca548a982ccb3b8650a5b06d0fd33a10283c56fc"
[[package]]
name = "libredox"
version = "0.1.11"
version = "0.1.12"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "df15f6eac291ed1cf25865b1ee60399f57e7c227e7f51bdbd4c5270396a9ed50"
checksum = "3d0b95e02c851351f877147b7deea7b1afb1df71b63aa5f8270716e0c5720616"
dependencies = [
"bitflags 2.10.0",
"ioslice",
"libc",
"redox_syscall 0.6.0",
"redox_syscall 0.7.0",
]
[[package]]
@@ -1238,7 +1239,7 @@ dependencies = [
"driver-block",
"libredox",
"redox_event",
"redox_syscall 0.6.0",
"redox_syscall 0.7.0",
]
[[package]]
@@ -1263,7 +1264,7 @@ dependencies = [
"daemon",
"libredox",
"redox-scheme",
"redox_syscall 0.6.0",
"redox_syscall 0.7.0",
]
[[package]]
@@ -1360,7 +1361,7 @@ dependencies = [
"partitionlib",
"pcid",
"redox_event",
"redox_syscall 0.6.0",
"redox_syscall 0.7.0",
"smallvec 1.15.1",
]
@@ -1486,7 +1487,7 @@ dependencies = [
"pico-args",
"plain",
"redox-scheme",
"redox_syscall 0.6.0",
"redox_syscall 0.7.0",
"serde",
]
@@ -1499,7 +1500,7 @@ dependencies = [
"log",
"pcid",
"pico-args",
"redox_syscall 0.6.0",
"redox_syscall 0.7.0",
"serde",
"toml 0.5.11",
]
@@ -1581,7 +1582,7 @@ dependencies = [
"orbclient",
"redox-scheme",
"redox_event",
"redox_syscall 0.6.0",
"redox_syscall 0.7.0",
]
[[package]]
@@ -1592,7 +1593,7 @@ dependencies = [
"libredox",
"redox-scheme",
"redox_event",
"redox_syscall 0.6.0",
"redox_syscall 0.7.0",
"redox_termios",
]
@@ -1625,7 +1626,7 @@ dependencies = [
"indexmap",
"libredox",
"redox-scheme",
"redox_syscall 0.6.0",
"redox_syscall 0.7.0",
"slab",
]
@@ -1713,7 +1714,7 @@ dependencies = [
"rand_core 0.5.1",
"raw-cpuid",
"redox-scheme",
"redox_syscall 0.6.0",
"redox_syscall 0.7.0",
"sha2",
]
@@ -1778,17 +1779,16 @@ dependencies = [
[[package]]
name = "redox-ioctl"
version = "0.1.0"
source = "git+https://gitlab.redox-os.org/redox-os/relibc.git#3362ca356a9dafdfd7d74fc88d97609f400f7329"
source = "git+https://gitlab.redox-os.org/redox-os/relibc.git#3a8f64aa143184dc11fe1927a4f9e55c33ae3052"
dependencies = [
"drm-sys",
"redox_syscall 0.6.0",
"redox_syscall 0.7.0",
]
[[package]]
name = "redox-log"
version = "0.1.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "81460b1526438123d16f0c968dbe42ba7f61e99645109b70e57864a8b66710fb"
version = "0.1.5"
source = "git+https://gitlab.redox-os.org/redox-os/redox-log.git#ac8cbc40a281879f1fee77483342edcc4de89983"
dependencies = [
"chrono",
"log",
@@ -1805,31 +1805,32 @@ checksum = "436d45c2b6a5b159d43da708e62b25be3a4a3d5550d654b72216ade4c4bfd717"
[[package]]
name = "redox-rt"
version = "0.1.0"
source = "git+https://gitlab.redox-os.org/redox-os/relibc.git#3362ca356a9dafdfd7d74fc88d97609f400f7329"
source = "git+https://gitlab.redox-os.org/redox-os/relibc.git#3a8f64aa143184dc11fe1927a4f9e55c33ae3052"
dependencies = [
"bitflags 2.10.0",
"generic-rt",
"goblin",
"ioslice",
"plain",
"redox-path",
"redox_syscall 0.6.0",
"redox_syscall 0.7.0",
]
[[package]]
name = "redox-scheme"
version = "0.8.3"
version = "0.9.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "2cea2668a5932f878a4298a1d7f8950249bbbb77120fb263da252c589152f5ea"
checksum = "5eb0cee524a5c6e4db180250f699e101ee25f3f79ad2618527e539e028cb6722"
dependencies = [
"libredox",
"redox_syscall 0.6.0",
"redox_syscall 0.7.0",
]
[[package]]
name = "redox_event"
version = "0.4.2"
version = "0.4.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f8eafe403549fab08a0c0862769493ad992625bb5a694aae2df6901e7e4fd05a"
checksum = "c30b73c93693667b5a8e6f54bddcc5a57449ef17c99f4b55c12d5bae4ab79e82"
dependencies = [
"bitflags 2.10.0",
"libredox",
@@ -1847,7 +1848,7 @@ dependencies = [
"redox-rt",
"redox-scheme",
"redox_event",
"redox_syscall 0.6.0",
"redox_syscall 0.7.0",
"smoltcp",
]
@@ -1862,9 +1863,9 @@ dependencies = [
[[package]]
name = "redox_syscall"
version = "0.6.0"
version = "0.7.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ec96166dafa0886eb81fe1c0a388bece180fbef2135f97c1e2cf8302e74b43b5"
checksum = "49f3fe0889e69e2ae9e41f4d6c4c0181701d00e4697b356fb1f74173a5e0ee27"
dependencies = [
"bitflags 2.10.0",
]
@@ -1884,7 +1885,7 @@ dependencies = [
"libredox",
"qemu-exit",
"redox_event",
"redox_syscall 0.6.0",
"redox_syscall 0.7.0",
"redox_termios",
]
@@ -1958,7 +1959,7 @@ dependencies = [
"log",
"pcid",
"redox_event",
"redox_syscall 0.6.0",
"redox_syscall 0.7.0",
]
[[package]]
@@ -1973,7 +1974,7 @@ dependencies = [
"log",
"pcid",
"redox_event",
"redox_syscall 0.6.0",
"redox_syscall 0.7.0",
]
[[package]]
@@ -2011,7 +2012,7 @@ dependencies = [
"log",
"redox-scheme",
"redox_event",
"redox_syscall 0.6.0",
"redox_syscall 0.7.0",
"spin 0.9.8",
]
@@ -2411,6 +2412,7 @@ name = "usbctl"
version = "0.1.0"
dependencies = [
"clap 2.34.0",
"common",
"xhcid",
]
@@ -2423,7 +2425,7 @@ dependencies = [
"inputd",
"log",
"orbclient",
"redox_syscall 0.6.0",
"redox_syscall 0.7.0",
"rehid",
"xhcid",
]
@@ -2434,7 +2436,7 @@ version = "0.1.0"
dependencies = [
"common",
"log",
"redox_syscall 0.6.0",
"redox_syscall 0.7.0",
"xhcid",
]
@@ -2448,7 +2450,7 @@ dependencies = [
"libredox",
"plain",
"redox_event",
"redox_syscall 0.6.0",
"redox_syscall 0.7.0",
"thiserror 1.0.69",
"xhcid",
]
@@ -2486,7 +2488,7 @@ dependencies = [
"orbclient",
"pcid",
"redox_event",
"redox_syscall 0.6.0",
"redox_syscall 0.7.0",
]
[[package]]
@@ -2515,7 +2517,7 @@ dependencies = [
"orbclient",
"ransid",
"redox_event",
"redox_syscall 0.6.0",
"redox_syscall 0.7.0",
]
[[package]]
@@ -2531,7 +2533,7 @@ dependencies = [
"log",
"pcid",
"redox_event",
"redox_syscall 0.6.0",
"redox_syscall 0.7.0",
"spin 0.10.0",
"static_assertions",
"thiserror 1.0.69",
@@ -2550,7 +2552,7 @@ dependencies = [
"log",
"pcid",
"redox_event",
"redox_syscall 0.6.0",
"redox_syscall 0.7.0",
"static_assertions",
"thiserror 1.0.69",
]
@@ -2573,7 +2575,7 @@ dependencies = [
"orbclient",
"pcid",
"redox_event",
"redox_syscall 0.6.0",
"redox_syscall 0.7.0",
"spin 0.9.8",
"static_assertions",
"virtio-core",
@@ -2590,7 +2592,7 @@ dependencies = [
"libredox",
"log",
"pcid",
"redox_syscall 0.6.0",
"redox_syscall 0.7.0",
"static_assertions",
"virtio-core",
]
@@ -2801,7 +2803,7 @@ dependencies = [
"plain",
"redox-scheme",
"redox_event",
"redox_syscall 0.6.0",
"redox_syscall 0.7.0",
"regex",
"serde",
"serde_json",
@@ -2837,7 +2839,7 @@ dependencies = [
"daemon",
"libredox",
"redox-scheme",
"redox_syscall 0.6.0",
"redox_syscall 0.7.0",
]
[[package]]
+5 -7
View File
@@ -77,16 +77,14 @@ exclude = ["bootstrap"]
[workspace.dependencies]
libc = "0.2.180"
log = "0.4"
# libredox 0.1.12 uses redox_syscall 0.7, wait until that is supported
libredox = "=0.1.11"
libredox = "0.1.12"
orbclient = { git = "https://gitlab.redox-os.org/redox-os/orbclient" }
# redox_event 0.4.3 uses redox_syscall 0.7, wait until that is supported
redox_event = "=0.4.2"
redox_event = "0.4.3"
redox-ioctl = { git = "https://gitlab.redox-os.org/redox-os/relibc.git" }
redox-log = "0.1.4"
redox-log = { git = "https://gitlab.redox-os.org/redox-os/redox-log.git" }
redox-rt = { git = "https://gitlab.redox-os.org/redox-os/relibc.git", default-features = false }
redox-scheme = "0.8.3"
redox_syscall = "0.6"
redox-scheme = "0.9.0"
redox_syscall = "0.7"
redox_termios = "0.1.3"
[patch.crates-io]
+15 -11
View File
@@ -8,6 +8,7 @@ use ioslice::IoSlice;
use libredox::flag;
use libredox::{error::Result, Fd};
use redox_scheme::scheme::register_sync_scheme;
use redox_scheme::wrappers::ReadinessBased;
use redox_scheme::Socket;
@@ -47,29 +48,32 @@ fn daemon(daemon: Daemon) -> anyhow::Result<()> {
let pid = libredox::call::getpid()?;
let socket = Socket::create("audio").context("failed to create scheme")?;
let hw_file = Fd::open("/scheme/audiohw", flag::O_WRONLY | flag::O_CLOEXEC, 0)?;
let socket = Socket::create().context("failed to create scheme")?;
let scheme = Arc::new(Mutex::new(AudioScheme::new()));
{
let mut scheme = scheme.lock().unwrap();
register_sync_scheme(&socket, "audio", &mut *scheme)
.expect("audiod: failed to register scheme to namespace");
}
// The scheme is now ready to accept requests, notify the original process
daemon.ready();
let hw_file = Fd::open("/scheme/audiohw", flag::O_WRONLY | flag::O_CLOEXEC, 0)?;
let scheme = Arc::new(Mutex::new(AudioScheme::new()));
// Enter a constrained namespace
let ns = libredox::call::mkns(&[
//IoSlice::new(b"memory"), TODO: already included, uncommenting gives EEXIST
IoSlice::new(b"memory"),
IoSlice::new(b"rand"), // for HashMap
])
.context("failed to make namespace")?;
libredox::call::setrens(ns, ns).context("failed to set namespace")?;
libredox::call::setns(ns).context("failed to set namespace")?;
// Spawn a thread to mix and send audio data
let scheme_thread = scheme.clone();
let _thread = thread::spawn(move || {
libredox::call::setrens(ns, ns).unwrap();
thread(scheme_thread, pid, hw_file)
});
let _thread = thread::spawn(move || thread(scheme_thread, pid, hw_file));
let mut readiness = ReadinessBased::new(&socket, 16);
+25 -2
View File
@@ -1,7 +1,7 @@
use redox_scheme::{CallerCtx, OpenResult};
use std::collections::{BTreeMap, VecDeque};
use std::str;
use syscall::error::{Error, Result, EBADF, EINVAL, ENOENT, EWOULDBLOCK};
use syscall::error::{Error, Result, EACCES, EBADF, EINVAL, ENOENT, EWOULDBLOCK};
use redox_scheme::scheme::SchemeSync;
use syscall::schemev2::NewFdFlags;
@@ -16,6 +16,7 @@ enum Handle {
// TODO: move volume to audiohw:?
// TODO: Use SYS_CALL to handle this better?
Volume,
SchemeRoot,
}
pub struct AudioScheme {
@@ -64,7 +65,27 @@ impl AudioScheme {
}
impl SchemeSync for AudioScheme {
fn open(&mut self, path: &str, _flags: usize, _ctx: &CallerCtx) -> Result<OpenResult> {
fn scheme_root(&mut self) -> Result<usize> {
let id = self.next_id;
self.next_id += 1;
self.handles.insert(id, Handle::SchemeRoot);
Ok(id)
}
fn openat(
&mut self,
dirfd: usize,
path: &str,
_flags: usize,
_fcntl_flags: u32,
_ctx: &CallerCtx,
) -> Result<OpenResult> {
if !matches!(
self.handles.get(&dirfd).ok_or(Error::new(EBADF))?,
Handle::SchemeRoot
) {
return Err(Error::new(EACCES));
}
let (handle, flags) = match path.trim_matches('/') {
"" => (
Handle::Audio {
@@ -109,6 +130,7 @@ impl SchemeSync for AudioScheme {
Ok(len)
}
Handle::SchemeRoot => Err(Error::new(EBADF)),
}
}
@@ -158,6 +180,7 @@ impl SchemeSync for AudioScheme {
Ok(0)
}
}
Handle::SchemeRoot => Err(Error::new(EBADF)),
}
}
}
+15 -8
View File
@@ -41,7 +41,7 @@ checksum = "d9c4f5dac5e15c24eb999c26181a6ca40b39fe946cbe4c263c7209467bc83af2"
[[package]]
name = "generic-rt"
version = "0.1.0"
source = "git+https://gitlab.redox-os.org/redox-os/relibc.git#5d378c146078a58c025ad9c857402c983e5e8b37"
source = "git+https://gitlab.redox-os.org/Ibuki.O/relibc.git?branch=namespace-improvement#aa4bd6493b3682c8bee1f5c391043b54554d2ba2"
[[package]]
name = "goblin"
@@ -63,6 +63,12 @@ dependencies = [
"foldhash",
]
[[package]]
name = "ioslice"
version = "0.6.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5e571352c8a3b89074d12e3ee5173ffe162159105352aaaf1fc5764da747e31b"
[[package]]
name = "libc"
version = "0.2.180"
@@ -71,9 +77,9 @@ checksum = "bcc35a38544a891a5f7c865aca548a982ccb3b8650a5b06d0fd33a10283c56fc"
[[package]]
name = "libredox"
version = "0.1.11"
version = "0.1.12"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "df15f6eac291ed1cf25865b1ee60399f57e7c227e7f51bdbd4c5270396a9ed50"
checksum = "3d0b95e02c851351f877147b7deea7b1afb1df71b63aa5f8270716e0c5720616"
dependencies = [
"bitflags",
"libc",
@@ -144,11 +150,12 @@ checksum = "436d45c2b6a5b159d43da708e62b25be3a4a3d5550d654b72216ade4c4bfd717"
[[package]]
name = "redox-rt"
version = "0.1.0"
source = "git+https://gitlab.redox-os.org/redox-os/relibc.git#5d378c146078a58c025ad9c857402c983e5e8b37"
source = "git+https://gitlab.redox-os.org/Ibuki.O/relibc.git?branch=namespace-improvement#aa4bd6493b3682c8bee1f5c391043b54554d2ba2"
dependencies = [
"bitflags",
"generic-rt",
"goblin",
"ioslice",
"plain",
"redox-path",
"redox_syscall",
@@ -156,9 +163,9 @@ dependencies = [
[[package]]
name = "redox-scheme"
version = "0.8.3"
version = "0.9.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "2cea2668a5932f878a4298a1d7f8950249bbbb77120fb263da252c589152f5ea"
checksum = "5eb0cee524a5c6e4db180250f699e101ee25f3f79ad2618527e539e028cb6722"
dependencies = [
"libredox",
"redox_syscall",
@@ -166,9 +173,9 @@ dependencies = [
[[package]]
name = "redox_syscall"
version = "0.6.0"
version = "0.7.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ec96166dafa0886eb81fe1c0a388bece180fbef2135f97c1e2cf8302e74b43b5"
checksum = "49f3fe0889e69e2ae9e41f4d6c4c0181701d00e4697b356fb1f74173a5e0ee27"
dependencies = [
"bitflags",
]
+4 -5
View File
@@ -15,19 +15,18 @@ hashbrown = { version = "0.15", default-features = false, features = [
"default-hasher",
] }
linked_list_allocator = "0.10"
# libredox 0.1.12 uses redox_syscall 0.7, wait until that is supported
libredox = { version = "=0.1.11", default-features = false }
libredox = { version = "0.1.12", default-features = false }
log = { version = "0.4", default-features = false }
plain = "0.2"
redox-initfs = { path = "../initfs", default-features = false }
redox_syscall = { version = "0.6", default-features = false }
redox-scheme = { version = "0.8.3", default-features = false }
redox_syscall = { version = "0.7", default-features = false }
redox-scheme = { version = "0.9.0", default-features = false }
redox-path = "0.3.1"
slab = { version = "0.4.9", default-features = false }
arrayvec = { version = "0.7.6", default-features = false }
[target.'cfg(target_os = "redox")'.dependencies]
redox-rt = { git = "https://gitlab.redox-os.org/redox-os/relibc.git", default-features = false }
redox-rt = { git = "https://gitlab.redox-os.org/Ibuki.O/relibc.git", branch = "namespace-improvement", default-features = false }
[profile.release]
panic = "abort"
+1 -1
View File
@@ -2,7 +2,7 @@ use core::mem;
use syscall::{data::Map, flag::MapFlags, number::SYS_FMAP};
pub const USERMODE_END: usize = 0x0000_8000_0000_0000;
pub const STACK_START: usize = USERMODE_END - STACK_SIZE;
pub const STACK_START: usize = USERMODE_END - syscall::KERNEL_METADATA_SIZE - STACK_SIZE;
const STACK_SIZE: usize = 64 * 1024; // 64 KiB
static MAP: Map = Map {
+108 -23
View File
@@ -1,13 +1,18 @@
use alloc::sync::Arc;
use core::str::FromStr;
use alloc::borrow::ToOwned;
use alloc::vec::Vec;
use syscall::CallFlags;
use syscall::data::{GlobalSchemes, KernelSchemeInfo};
use syscall::flag::{O_CLOEXEC, O_RDONLY};
use syscall::{Error, EINTR};
use syscall::{EINTR, Error};
use redox_rt::proc::*;
use crate::KernelSchemeMap;
struct Logger;
impl log::Log for Logger {
@@ -27,9 +32,38 @@ impl log::Log for Logger {
fn flush(&self) {}
}
const KERNEL_METADATA_BASE: usize = crate::arch::USERMODE_END - syscall::KERNEL_METADATA_SIZE;
pub fn main() -> ! {
let auth = FdGuard::open("/scheme/kernel.proc/authority", O_CLOEXEC)
.expect("failed to get proc authority");
let mut cursor = KERNEL_METADATA_BASE;
let kernel_scheme_infos = unsafe {
let base_ptr = cursor as *const u8;
let infos_len = *(base_ptr as *const usize);
let infos_ptr = base_ptr.add(core::mem::size_of::<usize>()) as *const KernelSchemeInfo;
let slice = core::slice::from_raw_parts(infos_ptr, infos_len);
cursor += core::mem::size_of::<usize>() // kernel scheme number size
+ infos_len // kernel scheme number
* core::mem::size_of::<KernelSchemeInfo>();
slice
};
let scheme_creation_cap = unsafe {
let base_ptr = cursor as *const u8;
let cap = *(base_ptr as *const usize);
cap
};
let kernel_schemes = KernelSchemeMap::new(kernel_scheme_infos);
let auth = FdGuard::new(
*kernel_schemes
.get(GlobalSchemes::Proc)
.expect("failed to get proc fd"),
);
let pipe_fd = *kernel_schemes
.get(GlobalSchemes::Pipe)
.expect("failed to get pipe fd");
let infos_arc = Arc::new(kernel_schemes);
let this_thr_fd = auth
.dup(b"cur-context")
.expect("failed to open open_via_dup")
@@ -39,8 +73,17 @@ pub fn main() -> ! {
let mut env_bytes = [0_u8; 4096];
let envs = {
let fd = FdGuard::open("/scheme/sys/env", O_RDONLY | O_CLOEXEC)
.expect("bootstrap: failed to open env");
let fd = FdGuard::new(
syscall::openat(
*infos_arc
.get(GlobalSchemes::Sys)
.expect("failed to get sys fd"),
"env",
O_RDONLY | O_CLOEXEC,
0,
)
.expect("bootstrap: failed to open env"),
);
let bytes_read = fd
.read(&mut env_bytes)
.expect("bootstrap: failed to read env");
@@ -80,10 +123,12 @@ pub fn main() -> ! {
(*(core::ptr::addr_of!(__initfs_header) as *const redox_initfs::types::Header)).initfs_size
};
spawn(
let infos_arc_clone = infos_arc.clone();
let initfs_fd = spawn(
"initfs daemon",
&auth,
&this_thr_fd,
pipe_fd,
move |write_fd| unsafe {
// Creating a reference to NULL is UB. Mask the UB for now using black_box.
// FIXME use a raw pointer and inline asm for reading instead for the initfs header.
@@ -93,14 +138,39 @@ pub fn main() -> ! {
crate::initfs::run(
core::slice::from_raw_parts(initfs_start, initfs_length),
write_fd,
&infos_arc_clone,
scheme_creation_cap,
);
},
);
spawn("process manager", &auth, &this_thr_fd, |write_fd| {
crate::procmgr::run(write_fd, &auth)
});
let (init_proc_fd, init_thr_fd) = unsafe { redox_rt::proc::make_init() };
let infos_arc_clone = infos_arc.clone();
let proc_fd = spawn(
"process manager",
&auth,
&this_thr_fd,
pipe_fd,
|write_fd| crate::procmgr::run(write_fd, &auth, &infos_arc_clone, scheme_creation_cap),
);
let infos_arc_clone = infos_arc.clone();
let initns_fd = spawn(
"init namespace manager",
&auth,
&this_thr_fd,
pipe_fd,
|write_fd| {
crate::initnsmgr::run(
write_fd,
&infos_arc_clone,
initfs_fd,
proc_fd,
scheme_creation_cap,
)
},
);
let (init_proc_fd, init_thr_fd) = unsafe { make_init(proc_fd) };
// from this point, this_thr_fd is no longer valid
const CWD: &[u8] = b"/scheme/initfs";
@@ -111,21 +181,27 @@ pub fn main() -> ! {
umask: redox_rt::sys::get_umask(),
thr_fd: init_thr_fd.as_raw_fd(),
proc_fd: init_proc_fd.as_raw_fd(),
ns_fd: Some(initns_fd),
};
let path = "/scheme/initfs/bin/init";
let path = "/bin/init";
let image_file = FdGuard::open(path, O_RDONLY | O_CLOEXEC)
.expect("failed to open init")
.to_upper()
.unwrap();
let image_file = FdGuard::new(
syscall::openat(initfs_fd, path, O_RDONLY | O_CLOEXEC, 0).expect("failed to open init"),
)
.to_upper()
.unwrap();
drop(infos_arc);
let exe_path = alloc::format!("/scheme/initfs{}", path);
fexec_impl(
image_file,
init_thr_fd,
init_proc_fd,
path.as_bytes(),
&[path.as_bytes()],
exe_path.as_bytes(),
&[exe_path.as_bytes()],
&envs,
&extrainfo,
None,
@@ -139,9 +215,10 @@ pub(crate) fn spawn(
name: &str,
auth: &FdGuard,
this_thr_fd: &FdGuardUpper,
inner: impl FnOnce(usize),
) {
let read = syscall::open("/scheme/pipe", O_CLOEXEC).expect("failed to open sync read pipe");
pipe_fd: usize,
inner: impl FnOnce(usize) -> !,
) -> usize {
let read = syscall::openat(pipe_fd, "", O_CLOEXEC, 0).expect("failed to open sync read pipe");
// The write pipe will not inherit O_CLOEXEC, but is closed by the daemon later.
let write = syscall::dup(read, b"write").expect("failed to open sync write pipe");
@@ -157,15 +234,23 @@ pub(crate) fn spawn(
// Return in order to execute init, as the parent.
Ok(_) => {
let _ = syscall::close(write);
let mut new_fd = usize::MAX;
let fd_bytes = unsafe {
core::slice::from_raw_parts_mut(
core::slice::from_mut(&mut new_fd).as_mut_ptr() as *mut u8,
core::mem::size_of::<usize>(),
)
};
loop {
match syscall::read(read, &mut [0]) {
match syscall::call_ro(read, fd_bytes, CallFlags::FD | CallFlags::FD_UPPER, &[]) {
Err(Error { errno: EINTR }) => continue,
_ => break,
}
}
return;
return new_fd;
}
}
inner(write);
inner(write)
}
+1 -1
View File
@@ -3,7 +3,7 @@ use syscall::{data::Map, flag::MapFlags, number::SYS_FMAP};
const STACK_SIZE: usize = 64 * 1024; // 64 KiB
pub const USERMODE_END: usize = 0x8000_0000;
pub const STACK_START: usize = USERMODE_END - STACK_SIZE;
pub const STACK_START: usize = USERMODE_END - syscall::KERNEL_METADATA_SIZE - STACK_SIZE;
static MAP: Map = Map {
offset: 0,
+90 -22
View File
@@ -6,13 +6,12 @@ use core::str;
use alloc::string::String;
use hashbrown::HashMap;
use redox_initfs::{InitFs, Inode, InodeDir, InodeKind, InodeStruct, types::Timespec};
use redox_initfs::{types::Timespec, InitFs, Inode, InodeDir, InodeKind, InodeStruct};
use redox_path::canonicalize_to_standard;
use redox_scheme::{CallerCtx, OpenResult, RequestKind, scheme::SchemeSync};
use redox_scheme::{scheme::SchemeSync, CallerCtx, OpenResult, RequestKind};
use redox_scheme::{SignalBehavior, Socket};
use syscall::PAGE_SIZE;
use syscall::data::Stat;
use syscall::dirent::DirEntry;
use syscall::dirent::DirentBuf;
@@ -20,8 +19,30 @@ use syscall::dirent::DirentKind;
use syscall::error::*;
use syscall::flag::*;
use syscall::schemev2::NewFdFlags;
use syscall::PAGE_SIZE;
struct Handle {
use crate::KernelSchemeMap;
enum Handle {
Node(Node),
SchemeRoot,
}
impl Handle {
fn as_node(&self) -> Result<&Node> {
match self {
Handle::Node(n) => Ok(n),
_ => Err(Error::new(EBADF)),
}
}
fn as_node_mut(&mut self) -> Result<&mut Node> {
match self {
Handle::Node(n) => Ok(n),
_ => Err(Error::new(EBADF)),
}
}
}
struct Node {
inode: Inode,
// TODO: Any better way to implement fpath? Or maybe work around it, e.g. by giving paths such
// as `initfs:__inodes__/<inode>`?
@@ -91,7 +112,20 @@ fn inode_len(inode: InodeStruct<'static>) -> Result<usize> {
}
impl SchemeSync for InitFsScheme {
fn open(&mut self, path: &str, flags: usize, _ctx: &CallerCtx) -> Result<OpenResult> {
fn openat(
&mut self,
dirfd: usize,
path: &str,
flags: usize,
_fcntl_flags: u32,
ctx: &CallerCtx,
) -> Result<OpenResult> {
if !matches!(
self.handles.get(&dirfd).ok_or(Error::new(EBADF))?,
Handle::SchemeRoot
) {
return Err(Error::new(EACCES));
}
let mut components = path
// trim leading and trailing slash
.trim_matches('/')
@@ -158,10 +192,10 @@ impl SchemeSync for InitFsScheme {
let id = self.next_id();
let old = self.handles.insert(
id,
Handle {
Handle::Node(Node {
inode: current_inode,
filename: path.into(),
},
}),
);
assert!(old.is_none());
@@ -183,7 +217,11 @@ impl SchemeSync for InitFsScheme {
return Ok(0);
};
let handle = self.handles.get_mut(&id).ok_or(Error::new(EBADF))?;
let handle = self
.handles
.get_mut(&id)
.ok_or(Error::new(EBADF))?
.as_node_mut()?;
match Self::get_inode(&self.fs, handle.inode)?.kind() {
InodeKind::File(file) => {
@@ -222,7 +260,7 @@ impl SchemeSync for InitFsScheme {
let Ok(offset) = u32::try_from(opaque_offset) else {
return Ok(buf);
};
let handle = self.handles.get(&id).ok_or(Error::new(EBADF))?;
let handle = self.handles.get(&id).ok_or(Error::new(EBADF))?.as_node()?;
let InodeKind::Dir(dir) = Self::get_inode(&self.fs, handle.inode)?.kind() else {
return Err(Error::new(ENOTDIR));
};
@@ -247,19 +285,23 @@ impl SchemeSync for InitFsScheme {
}
fn fsize(&mut self, id: usize, _ctx: &CallerCtx) -> Result<u64> {
let handle = self.handles.get_mut(&id).ok_or(Error::new(EBADF))?;
let handle = self
.handles
.get_mut(&id)
.ok_or(Error::new(EBADF))?
.as_node_mut()?;
Ok(inode_len(Self::get_inode(&self.fs, handle.inode)?)? as u64)
}
fn fcntl(&mut self, id: usize, _cmd: usize, _arg: usize, _ctx: &CallerCtx) -> Result<usize> {
let _handle = self.handles.get(&id).ok_or(Error::new(EBADF))?;
let _handle = self.handles.get(&id).ok_or(Error::new(EBADF))?.as_node()?;
Ok(0)
}
fn fpath(&mut self, id: usize, buf: &mut [u8], _ctx: &CallerCtx) -> Result<usize> {
let handle = self.handles.get(&id).ok_or(Error::new(EBADF))?;
let handle = self.handles.get(&id).ok_or(Error::new(EBADF))?.as_node()?;
// TODO: Copy scheme part in kernel
let scheme_path = b"/scheme/initfs";
@@ -274,7 +316,7 @@ impl SchemeSync for InitFsScheme {
}
fn fstat(&mut self, id: usize, stat: &mut Stat, _ctx: &CallerCtx) -> Result<()> {
let handle = self.handles.get(&id).ok_or(Error::new(EBADF))?;
let handle = self.handles.get(&id).ok_or(Error::new(EBADF))?.as_node()?;
let Timespec { sec, nsec } = self.fs.image_creation_time();
@@ -315,8 +357,10 @@ impl SchemeSync for InitFsScheme {
_ctx: &CallerCtx,
) -> syscall::Result<usize> {
let handle = self.handles.get(&id).ok_or(Error::new(EBADF))?;
let data = match Self::get_inode(&self.fs, handle.inode)?.kind() {
let Handle::Node(node) = handle else {
return Err(Error::new(EBADF));
};
let data = match Self::get_inode(&self.fs, node.inode)?.kind() {
InodeKind::File(file) => file.data().map_err(|_| Error::new(EIO))?,
InodeKind::Dir(_) => return Err(Error::new(EISDIR)),
InodeKind::Link(link) => return Err(Error::new(ELOOP)),
@@ -339,12 +383,30 @@ impl SchemeSync for InitFsScheme {
}
}
pub fn run(bytes: &'static [u8], sync_pipe: usize) -> ! {
pub fn run(
bytes: &'static [u8],
sync_pipe: usize,
kernel_schemes: &KernelSchemeMap,
scheme_creation_cap: usize,
) -> ! {
log::info!("bootstrap: starting initfs scheme");
let mut scheme = InitFsScheme::new(bytes);
let socket = Socket::create("initfs").expect("failed to open initfs scheme socket");
let socket = Socket::create_inner(scheme_creation_cap, false)
.expect("failed to open initfs scheme socket");
let _ = syscall::close(scheme_creation_cap);
let _ = syscall::write(sync_pipe, &[0]);
for fd in kernel_schemes.0.values() {
let _ = syscall::close(*fd);
}
// send open-capability to bootstrap
let new_id = scheme.next_id();
scheme.handles.insert(new_id, Handle::SchemeRoot);
let cap_fd = socket
.create_this_scheme_fd(0, new_id, 0, 0)
.expect("failed to issue initfs root fd");
let _ = syscall::call_rw(sync_pipe, &mut cap_fd.to_ne_bytes(), CallFlags::FD, &[]);
let _ = syscall::close(sync_pipe);
loop {
@@ -380,17 +442,23 @@ pub fn run(bytes: &'static [u8], sync_pipe: usize) -> ! {
#[unsafe(no_mangle)]
pub unsafe extern "C" fn redox_read_v1(fd: usize, ptr: *mut u8, len: usize) -> isize {
Error::mux(syscall::read(fd, core::slice::from_raw_parts_mut(ptr, len))) as isize
Error::mux(syscall::read(fd, unsafe {
core::slice::from_raw_parts_mut(ptr, len)
})) as isize
}
#[unsafe(no_mangle)]
pub unsafe extern "C" fn redox_write_v1(fd: usize, ptr: *const u8, len: usize) -> isize {
Error::mux(syscall::write(fd, core::slice::from_raw_parts(ptr, len))) as isize
Error::mux(syscall::write(fd, unsafe {
core::slice::from_raw_parts(ptr, len)
})) as isize
}
#[unsafe(no_mangle)]
pub unsafe extern "C" fn redox_open_v1(ptr: *const u8, len: usize, flags: usize) -> isize {
Error::mux(syscall::open(core::str::from_raw_parts(ptr, len), flags)) as isize
pub unsafe fn redox_dup_v1(fd: usize, buf: *const u8, len: usize) -> isize {
Error::mux(syscall::dup(fd, unsafe {
core::slice::from_raw_parts(buf, len)
})) as isize
}
#[unsafe(no_mangle)]
+536
View File
@@ -0,0 +1,536 @@
use super::KernelSchemeMap;
use alloc::rc::Rc;
use alloc::string::{String, ToString};
use alloc::vec::Vec;
use core::cell::RefCell;
use core::fmt::Debug;
use core::mem;
use hashbrown::HashMap;
use log::{error, warn};
use redox_path::RedoxPath;
use redox_path::RedoxScheme;
use redox_rt::protocol::{NsDup, NsPermissions};
use redox_scheme::{
CallerCtx, OpenResult, RequestKind, Response, SendFdRequest, SignalBehavior, Socket,
scheme::SchemeSync,
};
use syscall::dirent::{DirEntry, DirentBuf, DirentKind};
use syscall::{CallFlags, FobtainFdFlags, error::*, schemev2::NewFdFlags};
#[derive(Debug, Clone)]
struct Namespace {
schemes: HashMap<String, usize>,
}
impl Namespace {
fn fork(&self, buf: &[u8]) -> Result<Self> {
let mut schemes = HashMap::new();
let mut cursor = 0;
while cursor < buf.len() {
let len = read_num::<usize>(&buf[cursor..])?;
cursor += mem::size_of::<usize>();
let name = String::from_utf8(Vec::from(&buf[cursor..cursor + len]))
.map_err(|_| Error::new(EINVAL))?;
cursor += len;
if name.ends_with('*') {
let prefix = &name[..name.len() - 1];
for (registered_name, fd) in &self.schemes {
if registered_name.starts_with(prefix) {
schemes.insert(registered_name.clone(), *fd);
}
}
} else {
let Some(fd) = self.schemes.get(&name) else {
warn!("Scheme {} not found in namespace", name);
continue;
};
schemes.insert(name, *fd);
}
}
Ok(Self { schemes })
}
fn get_scheme_fd(&self, scheme: &str) -> Option<usize> {
self.schemes.get(scheme).copied()
}
}
#[derive(Debug, Clone)]
struct NamespaceAccess {
namespace: Rc<RefCell<Namespace>>,
permission: NsPermissions,
}
impl NamespaceAccess {
fn has_permission(&self, permission: NsPermissions) -> bool {
self.permission.contains(permission)
}
}
#[derive(Debug, Clone)]
struct SchemeRegister {
target_namespace: Rc<RefCell<Namespace>>,
scheme_name: String,
}
impl SchemeRegister {
fn register(&self, fd: usize) -> Result<()> {
let mut ns = self.target_namespace.borrow_mut();
if ns.schemes.contains_key(&self.scheme_name) {
return Err(Error::new(EEXIST));
}
ns.schemes.insert(self.scheme_name.clone(), fd);
Ok(())
}
}
#[derive(Debug, Clone)]
enum Handle {
Access(NamespaceAccess),
Register(SchemeRegister),
List(NamespaceAccess),
}
pub struct NamespaceScheme<'sock> {
socket: &'sock Socket,
handles: HashMap<usize, Handle>,
root_namespace: Namespace,
next_id: usize,
scheme_creation_cap: usize,
}
const HIGH_PERMISSIONS: NsPermissions = NsPermissions::SCHEME_CREATE;
impl<'sock> NamespaceScheme<'sock> {
pub fn new(
socket: &'sock Socket,
schemes: HashMap<String, usize>,
scheme_creation_cap: usize,
) -> Self {
let mut scheme = Self {
socket,
handles: HashMap::new(),
root_namespace: Namespace { schemes },
next_id: 0,
scheme_creation_cap,
};
scheme
}
fn add_namespace(&mut self, id: usize, schemes: Namespace, permission: NsPermissions) {
let handle = Handle::Access(NamespaceAccess {
namespace: Rc::new(RefCell::new(schemes)),
permission,
});
self.handles.insert(id, handle);
}
fn get_ns_access(&self, id: usize) -> Option<&NamespaceAccess> {
let handle = self.handles.get(&id);
match handle {
Some(Handle::Access(access)) => Some(access),
_ => None,
}
}
fn open_namespace_resource(
&self,
ns_access: &NamespaceAccess,
reference: &str,
_flags: usize,
_fcntl_flags: u32,
_ctx: &CallerCtx,
) -> Result<usize> {
match reference {
"scheme-creation-cap" => {
if !ns_access.has_permission(NsPermissions::SCHEME_CREATE) {
error!("Permission denied to get scheme creation capability");
return Err(Error::new(EACCES));
}
Ok(syscall::dup(self.scheme_creation_cap, &[])?)
}
_ => {
error!("Unknown special reference: {}", reference);
return Err(Error::new(EINVAL));
}
}
}
fn open_scheme_resource(
&self,
ns: &Namespace,
scheme: &str,
reference: &str,
flags: usize,
fcntl_flags: u32,
ctx: &CallerCtx,
) -> Result<usize> {
let Some(cap_fd) = ns.get_scheme_fd(scheme) else {
warn!("Scheme {} not found in namespace", scheme);
return Err(Error::new(ENODEV));
};
let scheme_fd = syscall::openat_with_filter(
cap_fd,
reference,
flags,
fcntl_flags as usize,
ctx.uid,
ctx.gid,
)?;
Ok(scheme_fd)
}
fn fork_namespace(&mut self, namespace: Rc<RefCell<Namespace>>, names: &[u8]) -> Result<usize> {
let new_id = self.next_id;
let new_namespace = namespace.borrow().fork(names).map_err(|e| {
error!("Failed to fork namespace {}: {}", new_id, e);
e
})?;
self.add_namespace(
new_id,
new_namespace,
NsPermissions::all().difference(HIGH_PERMISSIONS),
);
self.next_id += 1;
Ok(new_id)
}
fn shrink_permissions(
&mut self,
mut ns: NamespaceAccess,
permission: NsPermissions,
) -> Result<usize> {
ns.permission = ns.permission.intersection(permission);
let next_id = self.next_id;
self.handles.insert(next_id, Handle::Access(ns));
self.next_id += 1;
Ok(next_id)
}
}
impl<'sock> SchemeSync for NamespaceScheme<'sock> {
fn openat(
&mut self,
fd: usize,
path: &str,
flags: usize,
fcntl_flags: u32,
ctx: &CallerCtx,
) -> Result<OpenResult> {
let ns_access = {
let handle = self.handles.get(&fd);
match handle {
Some(Handle::Access(access)) => Some(access),
_ => None,
}
}
.ok_or_else(|| {
error!("Namespace with ID {} not found", fd);
Error::new(ENOENT)
})?;
let redox_path = RedoxPath::from_absolute(path).ok_or(Error::new(EINVAL))?;
let (scheme, reference) = redox_path.as_parts().ok_or(Error::new(EINVAL))?;
let res_fd = match scheme.as_ref() {
"namespace" => self.open_namespace_resource(
ns_access,
reference.as_ref(),
flags,
fcntl_flags,
ctx,
)?,
"" => {
if !ns_access.has_permission(NsPermissions::LIST) {
error!("Permission denied to list schemes in namespace {}", fd);
return Err(Error::new(EACCES));
}
let new_id = self.next_id;
self.next_id += 1;
self.handles.insert(new_id, Handle::List(ns_access.clone()));
return Ok(OpenResult::ThisScheme {
number: new_id,
flags: NewFdFlags::empty(),
});
}
_ => self.open_scheme_resource(
&ns_access.namespace.borrow(),
scheme.as_ref(),
reference.as_ref(),
flags,
fcntl_flags,
ctx,
)?,
};
Ok(OpenResult::OtherScheme { fd: res_fd })
}
fn dup(&mut self, id: usize, buf: &[u8], _ctx: &CallerCtx) -> Result<OpenResult> {
let ns_access = self.get_ns_access(id).ok_or_else(|| {
error!("Namespace with ID {} not found", id);
Error::new(ENOENT)
})?;
let raw_kind = read_num::<usize>(buf)?;
let Some(kind) = NsDup::try_from_raw(raw_kind) else {
error!("Unknown dup kind: {}", raw_kind);
return Err(Error::new(EINVAL));
};
let payload = &buf[mem::size_of::<NsDup>()..];
let new_id = match kind {
NsDup::ForkNs => {
let ns = ns_access.namespace.clone();
let _ = ns_access;
self.fork_namespace(ns, payload)?
}
NsDup::ShrinkPermissions => self.shrink_permissions(
ns_access.clone(),
NsPermissions::from_bits_truncate(read_num::<usize>(payload)?),
)?,
NsDup::IssueRegister => {
let name = core::str::from_utf8(payload).map_err(|_| Error::new(EINVAL))?;
let scheme_name = RedoxScheme::new(name).ok_or_else(|| {
error!("Invalid scheme name: {}", name);
Error::new(EINVAL)
})?;
if !ns_access.has_permission(NsPermissions::INSERT) {
error!(
"Permission denied to issue register capability for namespace {}",
id
);
return Err(Error::new(EACCES));
}
let new_id = self.next_id;
let register_cap = Handle::Register(SchemeRegister {
target_namespace: ns_access.namespace.clone(),
scheme_name: scheme_name.as_ref().to_string(),
});
self.handles.insert(new_id, register_cap);
self.next_id += 1;
new_id
}
};
Ok(OpenResult::ThisScheme {
number: new_id,
flags: NewFdFlags::empty(),
})
}
fn unlinkat(&mut self, fd: usize, path: &str, flags: usize, ctx: &CallerCtx) -> Result<()> {
let ns_access = {
let handle = self.handles.get(&fd);
match handle {
Some(Handle::Access(access)) => Some(access),
_ => None,
}
}
.ok_or_else(|| {
error!("Namespace with ID {} not found", fd);
Error::new(ENOENT)
})?;
let ns = ns_access.namespace.borrow();
let redox_path = RedoxPath::from_absolute(path).ok_or(Error::new(EINVAL))?;
let (scheme, reference) = redox_path.as_parts().ok_or(Error::new(EINVAL))?;
let Some(cap_fd) = ns.get_scheme_fd(scheme.as_ref()) else {
error!("Scheme {} not found in namespace", scheme);
return Err(Error::new(ENODEV));
};
syscall::unlinkat_with_filter(cap_fd, reference, flags, ctx.uid, ctx.gid)?;
Ok(())
}
fn on_close(&mut self, id: usize) {
self.handles.remove(&id);
}
fn on_sendfd(&mut self, sendfd_request: &SendFdRequest) -> Result<usize> {
let namespace_id = sendfd_request.id();
let num_fds = sendfd_request.num_fds();
let handle = self.handles.get(&namespace_id).ok_or_else(|| {
error!("Namespace with ID {} not found", namespace_id);
Error::new(ENOENT)
})?;
let Handle::Register(register_cap) = handle else {
error!(
"Handle with ID {} is not a register capability",
namespace_id
);
return Err(Error::new(EACCES));
};
if num_fds == 0 {
return Ok(0);
}
if num_fds > 1 {
error!("Can only send one fd at a time");
return Err(Error::new(EINVAL));
}
let mut new_fd = usize::MAX;
if let Err(e) = sendfd_request.obtain_fd(
&self.socket,
FobtainFdFlags::UPPER_TBL,
core::slice::from_mut(&mut new_fd),
) {
error!("on_sendfd: obtain_fd failed with error: {:?}", e);
return Err(e);
}
register_cap.register(new_fd)?;
Ok(num_fds)
}
fn getdents<'buf>(
&mut self,
id: usize,
mut buf: DirentBuf<&'buf mut [u8]>,
opaque_offset: u64,
) -> Result<DirentBuf<&'buf mut [u8]>> {
let Handle::List(ns_access) = self.handles.get(&id).ok_or(Error::new(EBADF))? else {
return Err(Error::new(ENOTDIR));
};
if !ns_access.has_permission(NsPermissions::LIST) {
return Err(Error::new(EACCES));
}
let ns = ns_access.namespace.borrow();
let opaque_offset = opaque_offset as usize;
for (i, (name, _)) in ns.schemes.iter().enumerate().skip(opaque_offset) {
if name.is_empty() {
continue;
}
if let Err(err) = buf.entry(DirEntry {
kind: DirentKind::Unspecified,
name: &name.clone(),
inode: 0,
next_opaque_id: i as u64 + 1,
}) {
if err.errno == EINVAL && i > opaque_offset {
// POSIX allows partial result of getdents
break;
} else {
return Err(err);
}
}
}
Ok(buf)
}
}
trait NumFromBytes: Sized + Debug {
fn from_le_bytes_slice(buffer: &[u8]) -> Result<Self, Error>;
}
macro_rules! num_from_bytes_impl {
($($t:ty),*) => {
$(
impl NumFromBytes for $t {
fn from_le_bytes_slice(buffer: &[u8]) -> Result<Self, Error> {
let size = mem::size_of::<Self>();
let buffer_slice = buffer.get(..size).and_then(|s| s.try_into().ok());
if let Some(slice) = buffer_slice {
Ok(Self::from_le_bytes(slice))
} else {
error!(
"read_num: buffer is too short to read num of size {} (buffer len: {})",
size, buffer.len()
);
Err(Error::new(EINVAL))
}
}
}
)*
};
}
num_from_bytes_impl!(usize);
fn read_num<T>(buffer: &[u8]) -> Result<T, Error>
where
T: NumFromBytes,
{
T::from_le_bytes_slice(buffer)
}
pub fn run(
sync_pipe: usize,
kernel_schemes: &KernelSchemeMap,
initfs_cap: usize,
proc_cap: usize,
scheme_creation_cap: usize,
) -> ! {
let socket = Socket::create_inner(scheme_creation_cap, false)
.expect("failed to open init namespace scheme socket");
let mut schemes = HashMap::default();
for (scheme, fd) in kernel_schemes.0.iter() {
schemes.insert(scheme.as_str().to_string(), *fd);
}
schemes.insert("proc".to_string(), proc_cap);
schemes.insert("initfs".to_string(), initfs_cap);
let mut scheme = NamespaceScheme::new(&socket, schemes, scheme_creation_cap);
// send namespace fd to bootstrap
let new_id = scheme.next_id;
scheme.add_namespace(new_id, scheme.root_namespace.clone(), NsPermissions::all());
scheme.next_id += 1;
let cap_fd = scheme
.socket
.create_this_scheme_fd(0, new_id, 0, 0)
.expect("nsmgr: failed to create namespace fd");
let _ = syscall::call_wo(sync_pipe, &cap_fd.to_ne_bytes(), CallFlags::FD, &[]);
let _ = syscall::close(sync_pipe);
log::info!("bootstrap: namespace scheme start!");
loop {
let Some(req) = socket
.next_request(SignalBehavior::Restart)
.expect("bootstrap: failed to read scheme request from kernel")
else {
break;
};
match req.kind() {
RequestKind::Call(req) => {
let resp = req.handle_sync(&mut scheme);
if !socket
.write_response(resp, SignalBehavior::Restart)
.expect("bootstrap: failed to write scheme response to kernel")
{
break;
}
}
RequestKind::OnClose { id } => scheme.on_close(id),
RequestKind::SendFd(sendfd_request) => {
let result = scheme.on_sendfd(&sendfd_request);
let resp = Response::new(result, sendfd_request);
if !socket
.write_response(resp, SignalBehavior::Restart)
.expect("bootstrap: failed to write scheme response to kernel")
{
break;
}
}
_ => (),
}
}
unreachable!()
}
+59 -34
View File
@@ -1,6 +1,6 @@
#![no_std]
#![allow(internal_features)]
#![feature(core_intrinsics, str_from_raw_parts)]
#![feature(core_intrinsics, str_from_raw_parts, never_type)]
#[cfg(target_arch = "aarch64")]
#[path = "aarch64.rs"]
@@ -20,6 +20,7 @@ pub mod arch;
pub mod exec;
pub mod initfs;
pub mod initnsmgr;
pub mod procmgr;
pub mod start;
@@ -27,7 +28,9 @@ extern crate alloc;
use core::cell::UnsafeCell;
use alloc::collections::btree_map::BTreeMap;
use syscall::data::Map;
use syscall::data::{GlobalSchemes, KernelSchemeInfo};
use syscall::flag::MapFlags;
#[panic_handler]
@@ -71,23 +74,25 @@ const HEAP_INCREASE_BY: usize = SIZE;
unsafe impl alloc::alloc::GlobalAlloc for Allocator {
unsafe fn alloc(&self, layout: core::alloc::Layout) -> *mut u8 {
let state = &mut (*ALLOC_STATE.0.get());
let state = unsafe { &mut (*ALLOC_STATE.0.get()) };
let heap = state.heap.get_or_insert_with(|| {
state.heap_top = HEAP_OFF + SIZE;
let _ = syscall::fmap(
!0,
&Map {
offset: 0,
size: SIZE,
address: HEAP_OFF,
flags: MapFlags::PROT_WRITE
| MapFlags::PROT_READ
| MapFlags::MAP_PRIVATE
| MapFlags::MAP_FIXED_NOREPLACE,
},
)
let _ = unsafe {
syscall::fmap(
!0,
&Map {
offset: 0,
size: SIZE,
address: HEAP_OFF,
flags: MapFlags::PROT_WRITE
| MapFlags::PROT_READ
| MapFlags::MAP_PRIVATE
| MapFlags::MAP_FIXED_NOREPLACE,
},
)
}
.expect("failed to map initial heap");
linked_list_allocator::Heap::new(HEAP_OFF as *mut u8, SIZE)
unsafe { linked_list_allocator::Heap::new(HEAP_OFF as *mut u8, SIZE) }
});
match heap.allocate_first_fit(layout) {
@@ -97,31 +102,51 @@ unsafe impl alloc::alloc::GlobalAlloc for Allocator {
return core::ptr::null_mut();
}
let _ = syscall::fmap(
!0,
&Map {
offset: 0,
size: HEAP_INCREASE_BY,
address: state.heap_top,
flags: MapFlags::PROT_WRITE
| MapFlags::PROT_READ
| MapFlags::MAP_PRIVATE
| MapFlags::MAP_FIXED_NOREPLACE,
},
)
let _ = unsafe {
syscall::fmap(
!0,
&Map {
offset: 0,
size: HEAP_INCREASE_BY,
address: state.heap_top,
flags: MapFlags::PROT_WRITE
| MapFlags::PROT_READ
| MapFlags::MAP_PRIVATE
| MapFlags::MAP_FIXED_NOREPLACE,
},
)
}
.expect("failed to extend heap");
heap.extend(HEAP_INCREASE_BY);
unsafe { heap.extend(HEAP_INCREASE_BY) };
state.heap_top += HEAP_INCREASE_BY;
return self.alloc(layout);
return unsafe { self.alloc(layout) };
}
}
}
unsafe fn dealloc(&self, ptr: *mut u8, layout: core::alloc::Layout) {
(&mut *ALLOC_STATE.0.get())
.heap
.as_mut()
.unwrap()
.deallocate(core::ptr::NonNull::new(ptr).unwrap(), layout)
unsafe {
(&mut *ALLOC_STATE.0.get())
.heap
.as_mut()
.unwrap()
.deallocate(core::ptr::NonNull::new(ptr).unwrap(), layout)
}
}
}
pub struct KernelSchemeMap(BTreeMap<GlobalSchemes, usize>);
impl KernelSchemeMap {
fn new(kernel_scheme_infos: &[KernelSchemeInfo]) -> Self {
let mut map = BTreeMap::new();
for info in kernel_scheme_infos {
if let Some(scheme_id) = GlobalSchemes::try_from_raw(info.scheme_id) {
map.insert(scheme_id, info.fd);
}
}
Self(map)
}
fn get(&self, scheme: GlobalSchemes) -> Option<&usize> {
self.0.get(&scheme)
}
}
+64 -14
View File
@@ -29,15 +29,18 @@ use redox_scheme::{
Socket, Tag,
};
use slab::Slab;
use syscall::data::GlobalSchemes;
use syscall::schemev2::NewFdFlags;
use syscall::{
ContextStatus, ContextVerb, CtxtStsBuf, EACCES, EAGAIN, EBADF, EBADFD, ECANCELED, ECHILD,
EEXIST, EINTR, EINVAL, ENOENT, ENOSYS, EOPNOTSUPP, EOWNERDEAD, EPERM, ERESTART, ESRCH,
CallFlags, ContextStatus, ContextVerb, CtxtStsBuf, EACCES, EAGAIN, EBADF, EBADFD, ECANCELED,
ECHILD, EEXIST, EINTR, EINVAL, ENOENT, ENOSYS, EOPNOTSUPP, EOWNERDEAD, EPERM, ERESTART, ESRCH,
EWOULDBLOCK, Error, Event, EventFlags, FobtainFdFlags, MapFlags, O_ACCMODE, O_CREAT, O_RDONLY,
PAGE_SIZE, ProcSchemeAttrs, Result, SenderInfo, SetSighandlerData, SigProcControl, Sigcontrol,
sig_bit,
};
use crate::KernelSchemeMap;
#[derive(Clone, Copy, Debug, Eq, Hash, Ord, PartialEq, PartialOrd)]
enum VirtualId {
KernelId(Id),
@@ -45,13 +48,31 @@ enum VirtualId {
InternalId(u64),
}
pub fn run(write_fd: usize, auth: &FdGuard) {
let socket = Socket::nonblock("proc").expect("failed to open proc scheme socket");
pub fn run(
write_fd: usize,
auth: &FdGuard,
kernel_schemes: &KernelSchemeMap,
scheme_creation_cap: usize,
) -> ! {
let socket =
Socket::create_inner(scheme_creation_cap, true).expect("failed to open proc scheme socket");
let _ = syscall::close(scheme_creation_cap);
// TODO?
let socket_ident = socket.inner().raw();
let queue = RawEventQueue::new().expect("failed to create event queue");
let queue = RawEventQueue::new(
*kernel_schemes
.get(GlobalSchemes::Event)
.expect("failed to get event fd"),
)
.expect("failed to create event queue");
for (scheme, fd) in kernel_schemes.0.iter() {
if *scheme == GlobalSchemes::Proc {
continue;
}
let _ = syscall::close(*fd);
}
queue
.subscribe(socket.inner().raw(), socket_ident, EventFlags::EVENT_READ)
@@ -59,8 +80,14 @@ pub fn run(write_fd: usize, auth: &FdGuard) {
let mut scheme = ProcScheme::new(auth, &queue);
// send open-capability to bootstrap
let new_id = scheme.handles.insert(Handle::SchemeRoot);
let cap_fd = socket
.create_this_scheme_fd(0, new_id, 0, 0)
.expect("failed to issue procmgr root fd");
log::debug!("process manager started");
let _ = syscall::write(write_fd, &[0]);
let _ = syscall::call_wo(write_fd, &cap_fd.to_ne_bytes(), CallFlags::FD, &[]);
let _ = syscall::close(write_fd);
let mut states = HashMap::<VirtualId, PendingState, DefaultHashBuilder>::new();
@@ -205,8 +232,8 @@ fn handle_scheme<'a>(
Err(req) => return Response::ready_err(ENOSYS, req),
};
match op {
Op::Open(op) => Ready(Response::open_dup_like(
scheme.on_open(op.path(), op.flags, &caller),
Op::OpenAt(op) => Ready(Response::open_dup_like(
scheme.on_openat(op.fd, op.path(), *op.flags(), op.fcntl_flags, &caller),
op,
)),
Op::Dup(op) => Ready(Response::open_dup_like(scheme.on_dup(op.fd, op.buf()), op)),
@@ -523,6 +550,9 @@ enum Handle {
// A handle that grants the holder the capability to obtain process credentials.
ProcCredsCapability,
// A handle that grants the holder the capability to open process scheme resource.
SchemeRoot,
}
#[derive(Clone, Copy, Debug)]
@@ -536,8 +566,10 @@ enum WaitpidTarget {
// backend
struct RawEventQueue(FdGuard);
impl RawEventQueue {
pub fn new() -> Result<Self> {
FdGuard::open("/scheme/event", O_CREAT).map(Self)
pub fn new(cap_fd: usize) -> Result<Self> {
syscall::openat(cap_fd, "", O_CREAT, 0)
.map(FdGuard::new)
.map(Self)
}
pub fn subscribe(&self, fd: usize, ident: usize, flags: EventFlags) -> Result<()> {
self.0.write(&Event {
@@ -586,7 +618,11 @@ impl<'a> ProcScheme<'a> {
match self.handles[req.id()] {
ref mut st @ Handle::Init => {
let mut fd_out = usize::MAX;
if let Err(e) = req.obtain_fd(socket, FobtainFdFlags::empty(), core::slice::from_mut(&mut fd_out)) {
if let Err(e) = req.obtain_fd(
socket,
FobtainFdFlags::empty(),
core::slice::from_mut(&mut fd_out),
) {
return Response::new(Err(e), req);
};
let fd = FdGuard::new(fd_out);
@@ -765,7 +801,18 @@ impl<'a> ProcScheme<'a> {
self.thread_lookup.insert(ident, thread_weak);
Ok(thread)
}
fn on_open(&mut self, path: &str, flags: usize, ctx: &CallerCtx) -> Result<OpenResult> {
fn on_openat(
&mut self,
fd: usize,
path: &str,
flags: usize,
_fcntl_flags: u32,
ctx: &CallerCtx,
) -> Result<OpenResult> {
match self.handles[fd] {
Handle::SchemeRoot => {}
_ => return Err(Error::new(EACCES)),
};
let path = path.trim_start_matches('/');
Ok(match path {
"init" => {
@@ -833,7 +880,7 @@ impl<'a> ProcScheme<'a> {
buf[..len].copy_from_slice(&src_buf[..len]);
Ok(len)
}
Handle::Init | Handle::Thread(_) | Handle::ProcCredsCapability => {
Handle::Init | Handle::Thread(_) | Handle::ProcCredsCapability | Handle::SchemeRoot => {
return Err(Error::new(EBADF));
}
}
@@ -882,7 +929,9 @@ impl<'a> ProcScheme<'a> {
fd: thread.fd.dup(buf)?.take(),
})
}
Handle::Init | Handle::Ps(_) | Handle::ProcCredsCapability => Err(Error::new(EBADF)),
Handle::Init | Handle::Ps(_) | Handle::ProcCredsCapability | Handle::SchemeRoot => {
Err(Error::new(EBADF))
}
}
}
fn on_call(
@@ -1063,6 +1112,7 @@ impl<'a> ProcScheme<'a> {
_ => Response::ready_err(EINVAL, op),
}
}
Handle::SchemeRoot => Response::ready_err(EBADF, op),
}
}
fn on_getpgid(&mut self, caller_pid: ProcessId, target_pid: ProcessId) -> Result<ProcessId> {
+1 -1
View File
@@ -3,7 +3,7 @@ use syscall::{data::Map, flag::MapFlags, number::SYS_FMAP};
const STACK_SIZE: usize = 64 * 1024; // 64 KiB
pub const USERMODE_END: usize = 1 << 47; // Assuming Sv48; it should work with Sv57 also
pub const STACK_START: usize = USERMODE_END - STACK_SIZE;
pub const STACK_START: usize = USERMODE_END - syscall::KERNEL_METADATA_SIZE - STACK_SIZE;
static MAP: Map = Map {
offset: 0,
+33 -29
View File
@@ -46,37 +46,41 @@ pub unsafe extern "C" fn start() -> ! {
let (rodata_start, rodata_end) = offsets::rodata();
let (data_start, data_end) = offsets::data_and_bss();
let _ = syscall::open("/scheme/debug", syscall::O_RDONLY); // stdin
let _ = syscall::open("/scheme/debug", syscall::O_WRONLY); // stdout
let _ = syscall::open("/scheme/debug", syscall::O_WRONLY); // stderr
// NOTE: Assuming the debug scheme root fd is always placed at this position
let debug_fd = syscall::UPPER_FDTBL_TAG + syscall::data::GlobalSchemes::Debug as usize;
let _ = syscall::openat(debug_fd, "", syscall::O_RDONLY, 0); // stdin
let _ = syscall::openat(debug_fd, "", syscall::O_WRONLY, 0); // stdout
let _ = syscall::openat(debug_fd, "", syscall::O_WRONLY, 0); // stderr
let _ = syscall::mprotect(4096, 4096, MapFlags::PROT_READ | MapFlags::MAP_PRIVATE)
.expect("mprotect failed for initfs header page");
unsafe {
let _ = syscall::mprotect(4096, 4096, MapFlags::PROT_READ | MapFlags::MAP_PRIVATE)
.expect("mprotect failed for initfs header page");
let _ = syscall::mprotect(
text_start,
text_end - text_start,
MapFlags::PROT_READ | MapFlags::PROT_EXEC | MapFlags::MAP_PRIVATE,
)
.expect("mprotect failed for .text");
let _ = syscall::mprotect(
rodata_start,
rodata_end - rodata_start,
MapFlags::PROT_READ | MapFlags::MAP_PRIVATE,
)
.expect("mprotect failed for .rodata");
let _ = syscall::mprotect(
data_start,
data_end - data_start,
MapFlags::PROT_READ | MapFlags::PROT_WRITE | MapFlags::MAP_PRIVATE,
)
.expect("mprotect failed for .data/.bss");
let _ = syscall::mprotect(
data_end,
crate::arch::STACK_START - data_end,
MapFlags::PROT_READ | MapFlags::MAP_PRIVATE,
)
.expect("mprotect failed for rest of memory");
let _ = syscall::mprotect(
text_start,
text_end - text_start,
MapFlags::PROT_READ | MapFlags::PROT_EXEC | MapFlags::MAP_PRIVATE,
)
.expect("mprotect failed for .text");
let _ = syscall::mprotect(
rodata_start,
rodata_end - rodata_start,
MapFlags::PROT_READ | MapFlags::MAP_PRIVATE,
)
.expect("mprotect failed for .rodata");
let _ = syscall::mprotect(
data_start,
data_end - data_start,
MapFlags::PROT_READ | MapFlags::PROT_WRITE | MapFlags::MAP_PRIVATE,
)
.expect("mprotect failed for .data/.bss");
let _ = syscall::mprotect(
data_end,
crate::arch::STACK_START - data_end,
MapFlags::PROT_READ | MapFlags::MAP_PRIVATE,
)
.expect("mprotect failed for rest of memory");
}
// FIXME make the initfs read-only
+1 -1
View File
@@ -3,7 +3,7 @@ use syscall::{data::Map, flag::MapFlags, number::SYS_FMAP};
const STACK_SIZE: usize = 64 * 1024; // 64 KiB
pub const USERMODE_END: usize = 0x0000_8000_0000_0000;
pub const STACK_START: usize = USERMODE_END - STACK_SIZE;
pub const STACK_START: usize = USERMODE_END - syscall::KERNEL_METADATA_SIZE - STACK_SIZE;
static MAP: Map = Map {
offset: 0,
+2 -2
View File
@@ -18,11 +18,11 @@ redox_event.workspace = true
rustc-hash = "1.1.0"
thiserror = "1"
ron = "0.8.1"
arrayvec = "0.7.6"
serde = { version = "1.0.228", features = ["derive"] }
amlserde = { path = "../amlserde" }
common = { path = "../common" }
daemon = { path = "../../daemon" }
libredox.workspace = true
redox-scheme.workspace = true
arrayvec = "0.7.6"
serde = { version = "1.0.228", features = ["derive"] }
+16 -11
View File
@@ -257,12 +257,12 @@ impl AmlSymbols {
}
}
pub fn init(&mut self) -> Result<(), Box<dyn Error>> {
pub fn init(&mut self, pci_fd: Option<&libredox::Fd>) -> Result<(), Box<dyn Error>> {
if self.aml_context.is_some() {
return Err("AML interpreter already initialized".into());
}
let format_err = |err| format!("{:?}", err);
let handler = AmlPhysMemHandler::new(Arc::clone(&self.page_cache));
let handler = AmlPhysMemHandler::new(pci_fd, Arc::clone(&self.page_cache));
//TODO: use these parsed tables for the rest of acpid
let rsdp_address = usize::from_str_radix(&std::env::var("RSDP_ADDR")?, 16)?;
let tables =
@@ -276,10 +276,12 @@ impl AmlSymbols {
Ok(())
}
pub fn aml_context_mut(&mut self) -> &mut Interpreter<AmlPhysMemHandler> {
// PCID must be running by this time!
pub fn aml_context_mut(
&mut self,
pci_fd: Option<&libredox::Fd>,
) -> &mut Interpreter<AmlPhysMemHandler> {
if self.aml_context.is_none() {
match self.init() {
match self.init(pci_fd) {
Ok(()) => (),
Err(err) => {
log::error!("failed to initialize AML context: {}", err);
@@ -303,8 +305,8 @@ impl AmlSymbols {
None
}
pub fn build_cache(&mut self) {
let aml_context = self.aml_context_mut();
pub fn build_cache(&mut self, pci_fd: Option<&libredox::Fd>) {
let aml_context = self.aml_context_mut(pci_fd);
let mut symbol_list: Vec<(AmlName, String)> = Vec::with_capacity(5000);
@@ -391,7 +393,7 @@ impl AcpiContext {
args: Vec<AmlSerdeValue>,
) -> Result<AmlSerdeValue, AmlEvalError> {
let mut symbols = self.aml_symbols.write();
let interpreter = symbols.aml_context_mut();
let interpreter = symbols.aml_context_mut(None);
interpreter.acquire_global_lock(16)?;
let args = args
@@ -520,14 +522,17 @@ impl AcpiContext {
}
pub fn aml_lookup(&self, symbol: &str) -> Option<String> {
if let Ok(aml_symbols) = self.aml_symbols() {
if let Ok(aml_symbols) = self.aml_symbols(None) {
aml_symbols.lookup(symbol)
} else {
None
}
}
pub fn aml_symbols(&self) -> Result<RwLockReadGuard<'_, AmlSymbols>, AmlError> {
pub fn aml_symbols(
&self,
pci_fd: Option<&libredox::Fd>,
) -> Result<RwLockReadGuard<'_, AmlSymbols>, AmlError> {
// return the cached value if it exists
let symbols = self.aml_symbols.read();
if !symbols.symbols_cache().is_empty() {
@@ -541,7 +546,7 @@ impl AcpiContext {
let mut aml_symbols = self.aml_symbols.write();
aml_symbols.build_cache();
aml_symbols.build_cache(pci_fd);
// return the cached value
Ok(RwLockWriteGuard::downgrade(aml_symbols))
+11 -16
View File
@@ -146,22 +146,17 @@ pub struct AmlPhysMemHandler {
/// Read from a physical address.
/// Generic parameter must be u8, u16, u32 or u64.
impl AmlPhysMemHandler {
pub fn new(page_cache: Arc<Mutex<AmlPageCache>>) -> Self {
//TODO: have PCID send a socket?
let pci_fd = Arc::new(
match libredox::Fd::open(
"/scheme/pci/access",
libredox::flag::O_RDWR | libredox::flag::O_CLOEXEC,
0,
) {
Ok(fd) => Some(fd),
Err(err) => {
log::error!("failed to open /scheme/pci/access: {}", err);
None
}
},
);
Self { page_cache, pci_fd }
pub fn new(pci_fd_opt: Option<&libredox::Fd>, page_cache: Arc<Mutex<AmlPageCache>>) -> Self {
let pci_fd = if let Some(pci_fd) = pci_fd_opt {
Some(libredox::Fd::new(pci_fd.raw()))
} else {
log::error!("pci_fd is not registered");
None
};
Self {
page_cache,
pci_fd: Arc::new(pci_fd),
}
}
fn pci_call_metadata(kind: u8, addr: PciAddress, off: u16) -> [u64; 2] {
+24 -7
View File
@@ -6,7 +6,10 @@ use std::sync::Arc;
use ::acpi::aml::op_region::{RegionHandler, RegionSpace};
use event::{EventFlags, RawEventQueue};
use redox_scheme::{RequestKind, SignalBehavior, Socket};
use redox_scheme::{
scheme::{register_sync_scheme, SchemeSync},
RequestKind, Response, SignalBehavior, Socket,
};
use syscall::{EAGAIN, EWOULDBLOCK};
mod acpi;
@@ -25,6 +28,8 @@ fn daemon(daemon: daemon::Daemon) -> ! {
common::file_level(),
);
log::info!("acpid start");
let rxsdt_raw_data: Arc<[u8]> = std::fs::read("/scheme/kernel.acpi/rxsdt")
.expect("acpid: failed to read `/scheme/kernel.acpi/rxsdt`")
.into();
@@ -78,11 +83,9 @@ fn daemon(daemon: daemon::Daemon) -> ! {
.expect("acpid: failed to open `/scheme/kernel.acpi/kstop`");
let mut event_queue = RawEventQueue::new().expect("acpid: failed to create event queue");
let socket = Socket::nonblock("acpi").expect("acpid: failed to create disk scheme");
let socket = Socket::nonblock().expect("acpid: failed to create disk scheme");
daemon.ready();
//TODO: needs to open /scheme/pci/access later! libredox::call::setrens(0, 0).expect("acpid: failed to enter null namespace");
let mut scheme = self::scheme::AcpiScheme::new(&acpi_context, &socket);
event_queue
.subscribe(shutdown_pipe.as_raw_fd() as usize, 0, EventFlags::READ)
@@ -91,7 +94,12 @@ fn daemon(daemon: daemon::Daemon) -> ! {
.subscribe(socket.inner().raw(), 1, EventFlags::READ)
.expect("acpid: failed to register scheme socket for event queue");
let mut scheme = self::scheme::AcpiScheme::new(&acpi_context);
register_sync_scheme(&socket, "acpi", &mut scheme)
.expect("acpid: failed to register acpi scheme to namespace");
daemon.ready();
libredox::call::setrens(0, 0).expect("acpid: failed to enter null namespace");
let mut mounted = true;
while mounted {
@@ -119,7 +127,6 @@ fn daemon(daemon: daemon::Daemon) -> ! {
}
}
};
match req.kind() {
RequestKind::Call(call) => {
let response = call.handle_sync(&mut scheme);
@@ -130,6 +137,15 @@ fn daemon(daemon: daemon::Daemon) -> ! {
RequestKind::OnClose { id } => {
scheme.on_close(id);
}
RequestKind::SendFd(sendfd_request) => {
let result = scheme.on_sendfd(&sendfd_request);
socket
.write_response(
Response::new(result, sendfd_request),
SignalBehavior::Restart,
)
.expect("acpid: failed to write response");
}
_ => (),
}
}
@@ -151,5 +167,6 @@ fn daemon(daemon: daemon::Daemon) -> ! {
}
fn main() {
common::init();
daemon::Daemon::new(daemon);
}
+120 -35
View File
@@ -2,29 +2,33 @@ use acpi::aml::namespace::AmlName;
use amlserde::aml_serde_name::to_aml_format;
use amlserde::AmlSerdeValue;
use core::str;
use libredox::Fd;
use parking_lot::RwLockReadGuard;
use redox_scheme::scheme::SchemeSync;
use redox_scheme::{CallerCtx, OpenResult};
use redox_scheme::{CallerCtx, OpenResult, SendFdRequest, Socket};
use ron::de::SpannedError;
use std::collections::BTreeMap;
use std::convert::{TryFrom, TryInto};
use std::str::FromStr;
use syscall::dirent::{DirEntry, DirentBuf, DirentKind};
use syscall::schemev2::NewFdFlags;
use syscall::FobtainFdFlags;
use syscall::data::Stat;
use syscall::error::{Error, Result};
use syscall::error::{EBADF, EBADFD, EINVAL, EIO, EISDIR, ENOENT, ENOTDIR};
use syscall::error::{EACCES, EBADF, EBADFD, EINVAL, EIO, EISDIR, ENOENT, ENOTDIR};
use syscall::flag::{MODE_DIR, MODE_FILE};
use syscall::flag::{O_ACCMODE, O_DIRECTORY, O_RDONLY, O_STAT, O_SYMLINK};
use syscall::{EOPNOTSUPP, EOVERFLOW, EPERM};
use crate::acpi::{AcpiContext, AmlSymbols, SdtSignature};
pub struct AcpiScheme<'acpi> {
pub struct AcpiScheme<'acpi, 'sock> {
ctx: &'acpi AcpiContext,
handles: BTreeMap<usize, Handle<'acpi>>,
next_fd: usize,
pci_fd: Option<Fd>,
socket: &'sock Socket,
}
struct Handle<'a> {
@@ -38,6 +42,8 @@ enum HandleKind<'a> {
Table(SdtSignature),
Symbols(RwLockReadGuard<'a, AmlSymbols>),
Symbol { name: String, description: String },
SchemeRoot,
RegisterPci,
}
impl HandleKind<'_> {
@@ -48,6 +54,8 @@ impl HandleKind<'_> {
Self::Table(_) => false,
Self::Symbols(_) => true,
Self::Symbol { .. } => false,
Self::SchemeRoot => false,
Self::RegisterPci => false,
}
}
fn len(&self, acpi_ctx: &AcpiContext) -> Result<usize> {
@@ -60,16 +68,19 @@ impl HandleKind<'_> {
Self::Symbol { description, .. } => description.len(),
// Directories
Self::TopLevel | Self::Symbols(_) | Self::Tables => 0,
Self::SchemeRoot | Self::RegisterPci => return Err(Error::new(EBADF)),
})
}
}
impl<'acpi> AcpiScheme<'acpi> {
pub fn new(ctx: &'acpi AcpiContext) -> Self {
impl<'acpi, 'sock> AcpiScheme<'acpi, 'sock> {
pub fn new(ctx: &'acpi AcpiContext, socket: &'sock Socket) -> Self {
Self {
ctx,
handles: BTreeMap::new(),
next_fd: 0,
pci_fd: None,
socket,
}
}
}
@@ -148,53 +159,92 @@ fn parse_table(table: &[u8]) -> Option<SdtSignature> {
})
}
impl SchemeSync for AcpiScheme<'_> {
fn open(&mut self, path: &str, flags: usize, ctx: &CallerCtx) -> Result<OpenResult> {
impl SchemeSync for AcpiScheme<'_, '_> {
fn scheme_root(&mut self) -> Result<usize> {
let fd = self.next_fd;
self.next_fd += 1;
self.handles.insert(
fd,
Handle {
stat: false,
kind: HandleKind::SchemeRoot,
allowed_to_eval: false,
},
);
Ok(fd)
}
fn openat(
&mut self,
dirfd: usize,
path: &str,
flags: usize,
_fcntl_flags: u32,
ctx: &CallerCtx,
) -> Result<OpenResult> {
let handle = self.handles.get(&dirfd).ok_or(Error::new(EBADF))?;
let path = path.trim_start_matches('/');
let flag_stat = flags & O_STAT == O_STAT;
let flag_dir = flags & O_DIRECTORY == O_DIRECTORY;
// TODO: arrayvec
let components = {
let mut v = arrayvec::ArrayVec::<&str, 3>::new();
let it = path.split('/');
for component in it.take(3) {
v.push(component);
}
let kind = match handle.kind {
HandleKind::SchemeRoot => {
// TODO: arrayvec
let components = {
let mut v = arrayvec::ArrayVec::<&str, 3>::new();
let it = path.split('/');
for component in it.take(3) {
v.push(component);
}
v
};
v
};
let kind = match &*components {
[""] => HandleKind::TopLevel,
["tables"] => HandleKind::Tables,
match &*components {
[""] => HandleKind::TopLevel,
["register_pci"] => HandleKind::RegisterPci,
["tables"] => HandleKind::Tables,
["tables", table] => {
let signature = parse_table(table.as_bytes()).ok_or(Error::new(ENOENT))?;
HandleKind::Table(signature)
}
["tables", table] => {
let signature = parse_table(table.as_bytes()).ok_or(Error::new(ENOENT))?;
HandleKind::Table(signature)
}
["symbols"] => {
if let Ok(aml_symbols) = self.ctx.aml_symbols() {
HandleKind::Symbols(aml_symbols)
} else {
return Err(Error::new(EIO));
["symbols"] => {
if let Ok(aml_symbols) = self.ctx.aml_symbols(self.pci_fd.as_ref()) {
HandleKind::Symbols(aml_symbols)
} else {
return Err(Error::new(EIO));
}
}
["symbols", symbol] => {
if let Some(description) = self.ctx.aml_lookup(symbol) {
HandleKind::Symbol {
name: (*symbol).to_owned(),
description,
}
} else {
return Err(Error::new(ENOENT));
}
}
_ => return Err(Error::new(ENOENT)),
}
}
["symbols", symbol] => {
if let Some(description) = self.ctx.aml_lookup(symbol) {
HandleKind::Symbols(ref aml_symbols) => {
if let Some(description) = aml_symbols.lookup(path) {
HandleKind::Symbol {
name: (*symbol).to_owned(),
name: (*path).to_owned(),
description,
}
} else {
return Err(Error::new(ENOENT));
}
}
_ => return Err(Error::new(ENOENT)),
_ => return Err(Error::new(EACCES)),
};
if kind.is_dir() && !flag_dir && !flag_stat {
@@ -419,9 +469,44 @@ impl SchemeSync for AcpiScheme<'_> {
Ok(result_len)
}
fn on_sendfd(&mut self, sendfd_request: &SendFdRequest) -> Result<usize> {
let id = sendfd_request.id();
let num_fds = sendfd_request.num_fds();
let handle = self.handles.get(&id).ok_or(Error::new(EBADF))?;
if !matches!(handle.kind, HandleKind::RegisterPci) {
return Err(Error::new(EACCES));
}
if num_fds == 0 {
return Ok(0);
}
if num_fds > 1 {
return Err(Error::new(EINVAL));
}
let mut new_fd = usize::MAX;
if let Err(e) = sendfd_request.obtain_fd(
&self.socket,
FobtainFdFlags::UPPER_TBL,
std::slice::from_mut(&mut new_fd),
) {
return Err(e);
}
let new_fd = libredox::Fd::new(new_fd);
if self.pci_fd.is_some() {
return Err(Error::new(EINVAL));
} else {
self.pci_fd = Some(new_fd);
}
Ok(num_fds)
}
}
impl AcpiScheme<'_> {
impl AcpiScheme<'_, '_> {
pub fn on_close(&mut self, id: usize) {
self.handles.remove(&id);
}
+32 -4
View File
@@ -22,6 +22,7 @@ const SUB_BUFF_SIZE: usize = 2048;
enum Handle {
Todo,
SchemeRoot,
}
#[allow(dead_code)]
@@ -262,7 +263,26 @@ impl Ac97 {
}
impl SchemeSync for Ac97 {
fn open(&mut self, _path: &str, _flags: usize, ctx: &CallerCtx) -> Result<OpenResult> {
fn scheme_root(&mut self) -> Result<usize> {
let id = self.next_id.fetch_add(1, Ordering::SeqCst);
self.handles.lock().insert(id, Handle::SchemeRoot);
Ok(id)
}
fn openat(
&mut self,
dirfd: usize,
_path: &str,
_flags: usize,
_fcntl_flags: u32,
ctx: &CallerCtx,
) -> Result<OpenResult> {
{
let mut handles = self.handles.lock();
let handle = handles.get(&dirfd).ok_or(Error::new(EBADF))?;
if !matches!(handle, Handle::SchemeRoot) {
return Err(Error::new(EACCES));
}
}
if ctx.uid == 0 {
let id = self.next_id.fetch_add(1, Ordering::SeqCst);
self.handles.lock().insert(id, Handle::Todo);
@@ -285,7 +305,10 @@ impl SchemeSync for Ac97 {
) -> Result<usize> {
{
let mut handles = self.handles.lock();
let _handle = handles.get_mut(&id).ok_or(Error::new(EBADF))?;
let handle = handles.get_mut(&id).ok_or(Error::new(EBADF))?;
if !matches!(handle, Handle::Todo) {
return Err(Error::new(EBADF));
}
}
if buf.len() != SUB_BUFF_SIZE {
@@ -310,8 +333,13 @@ impl SchemeSync for Ac97 {
}
fn fpath(&mut self, id: usize, buf: &mut [u8], _ctx: &CallerCtx) -> Result<usize> {
let mut handles = self.handles.lock();
let _handle = handles.get_mut(&id).ok_or(Error::new(EBADF))?;
{
let mut handles = self.handles.lock();
let handle = handles.get_mut(&id).ok_or(Error::new(EBADF))?;
if !matches!(handle, Handle::Todo) {
return Err(Error::new(EBADF));
}
}
let mut i = 0;
let scheme_path = b"/scheme/audiohw";
+5 -1
View File
@@ -11,6 +11,7 @@ use std::usize;
use event::{user_data, EventQueue};
use pcid_interface::PciFunctionHandle;
use redox_scheme::scheme::register_sync_scheme;
use redox_scheme::wrappers::ReadinessBased;
use redox_scheme::Socket;
use std::cell::RefCell;
@@ -19,6 +20,7 @@ use std::cell::RefCell;
pub mod device;
fn main() {
common::init();
pcid_interface::pci_daemon(daemon);
}
@@ -51,10 +53,10 @@ fn daemon(daemon: daemon::Daemon, pcid_handle: PciFunctionHandle) -> ! {
let mut irq_file = irq.irq_handle("ac97d");
let socket = Socket::nonblock().expect("ac97d: failed to create socket");
let device = RefCell::new(unsafe {
device::Ac97::new(bar0, bar1).expect("ac97d: failed to allocate device")
});
let socket = Socket::nonblock("audiohw").expect("ac97d: failed to create socket");
let mut readiness_based = ReadinessBased::new(&socket, 16);
user_data! {
@@ -80,6 +82,8 @@ fn daemon(daemon: daemon::Daemon, pcid_handle: PciFunctionHandle) -> ! {
)
.unwrap();
register_sync_scheme(&socket, "audiohw", &mut *device.borrow_mut())
.expect("ac97d: failed to register audiohw scheme to namespace");
daemon.ready();
libredox::call::setrens(0, 0).expect("ac97d: failed to enter null namespace");
+21 -1
View File
@@ -68,6 +68,7 @@ enum Handle {
Pcmout(usize, usize, usize), // Card, index, block_ptr
Pcmin(usize, usize, usize), // Card, index, block_ptr
StrBuf(Vec<u8>),
SchemeRoot,
}
#[repr(C, packed)]
@@ -984,7 +985,26 @@ impl Drop for IntelHDA {
}
impl SchemeSync for IntelHDA {
fn open(&mut self, path: &str, _flags: usize, ctx: &CallerCtx) -> Result<OpenResult> {
fn scheme_root(&mut self) -> Result<usize> {
let id = self.next_id.fetch_add(1, Ordering::SeqCst);
self.handles.lock().insert(id, Handle::SchemeRoot);
Ok(id)
}
fn openat(
&mut self,
dirfd: usize,
path: &str,
_flags: usize,
_fcntl_flags: u32,
ctx: &CallerCtx,
) -> Result<OpenResult> {
{
let mut handles = self.handles.lock();
let handle = handles.get(&dirfd).ok_or(Error::new(EBADF))?;
if !matches!(handle, Handle::SchemeRoot) {
return Err(Error::new(EACCES));
}
}
//let path: Vec<&str>;
/*
match str::from_utf8(_path) {
+5 -1
View File
@@ -3,6 +3,7 @@ extern crate event;
extern crate spin;
extern crate syscall;
use redox_scheme::scheme::register_sync_scheme;
use redox_scheme::wrappers::ReadinessBased;
use redox_scheme::Socket;
use std::cell::RefCell;
@@ -24,6 +25,7 @@ QEMU ICH9 8086:293E
*/
fn main() {
common::init();
pcid_interface::pci_daemon(daemon);
}
@@ -60,12 +62,14 @@ fn daemon(daemon: daemon::Daemon, mut pcid_handle: PciFunctionHandle) -> ! {
let event_queue =
EventQueue::<Source>::new().expect("ihdad: Could not create event queue.");
let socket = Socket::nonblock().expect("ihdad: failed to create socket");
let device = RefCell::new(unsafe {
hda::IntelHDA::new(address, vend_prod).expect("ihdad: failed to allocate device")
});
let socket = Socket::nonblock("audiohw").expect("ihdad: failed to create socket");
let mut readiness_based = ReadinessBased::new(&socket, 16);
register_sync_scheme(&socket, "audiohw", &mut *device.borrow_mut())
.expect("ihdad: failed to register audiohw scheme to namespace");
daemon.ready();
event_queue
+21 -1
View File
@@ -19,6 +19,7 @@ const SUB_BUFF_SIZE: usize = 2048;
enum Handle {
Todo,
SchemeRoot,
}
#[allow(dead_code)]
@@ -185,7 +186,26 @@ impl Sb16 {
}
impl SchemeSync for Sb16 {
fn open(&mut self, _path: &str, _flags: usize, ctx: &CallerCtx) -> Result<OpenResult> {
fn scheme_root(&mut self) -> Result<usize> {
let id = self.next_id.fetch_add(1, Ordering::SeqCst);
self.handles.lock().insert(id, Handle::SchemeRoot);
Ok(id)
}
fn openat(
&mut self,
dirfd: usize,
_path: &str,
_flags: usize,
_fcntl_flags: u32,
ctx: &CallerCtx,
) -> Result<OpenResult> {
{
let mut handles = self.handles.lock();
let handle = handles.get(&dirfd).ok_or(Error::new(EBADF))?;
if !matches!(handle, Handle::SchemeRoot) {
return Err(Error::new(EACCES));
}
}
if ctx.uid == 0 {
let id = self.next_id.fetch_add(1, Ordering::SeqCst);
self.handles.lock().insert(id, Handle::Todo);
+5 -1
View File
@@ -1,6 +1,7 @@
//#![deny(warnings)]
use libredox::{flag, Fd};
use redox_scheme::scheme::register_sync_scheme;
use redox_scheme::wrappers::ReadinessBased;
use redox_scheme::Socket;
use std::cell::RefCell;
@@ -34,9 +35,9 @@ fn daemon(daemon: daemon::Daemon) -> ! {
common::acquire_port_io_rights().expect("sb16d: failed to acquire port IO rights");
let socket = Socket::nonblock().expect("sb16d: failed to create socket");
let device =
RefCell::new(unsafe { device::Sb16::new(addr).expect("sb16d: failed to allocate device") });
let socket = Socket::nonblock("audiohw").expect("sb16d: failed to create socket");
let mut readiness_based = ReadinessBased::new(&socket, 16);
//TODO: error on multiple IRQs?
@@ -64,6 +65,9 @@ fn daemon(daemon: daemon::Daemon) -> ! {
)
.unwrap();
register_sync_scheme(&socket, "sb16d", &mut *device.borrow_mut())
.expect("sb16d: failed to register audiohw scheme to namespace");
daemon.ready();
libredox::call::setrens(0, 0).expect("sb16d: failed to enter null namespace");
+3 -3
View File
@@ -7,7 +7,7 @@ use libredox::call::MmapArgs;
use libredox::{error::Result, flag, Fd};
use syscall::PAGE_SIZE;
use crate::{MemoryType, VirtaddrTranslationHandle};
use crate::{memory_root_fd, MemoryType, VirtaddrTranslationHandle};
/// Defines the platform-specific memory type for DMA operations
///
@@ -42,8 +42,8 @@ const DMA_MEMTY: MemoryType = {
///
/// - The request for the physical memory fails.
pub(crate) fn phys_contiguous_fd() -> Result<Fd> {
Fd::open(
&format!("/scheme/memory/zeroed@{DMA_MEMTY}?phys_contiguous"),
memory_root_fd().openat(
&format!("zeroed@{DMA_MEMTY}?phys_contiguous"),
flag::O_CLOEXEC,
0,
)
+34 -17
View File
@@ -21,6 +21,28 @@ pub mod timeout;
pub use logger::{file_level, output_level, setup_logging};
use std::sync::OnceLock;
static MEMORY_ROOT_FD: OnceLock<libredox::Fd> = OnceLock::new();
pub fn init() {
if MEMORY_ROOT_FD
.set(
libredox::Fd::open("/scheme/memory/scheme-root", 0, 0)
.expect("drivers common: failed to open memory root fd"),
)
.is_err()
{
panic!("drivers common: failed to set memory root fd");
}
}
pub fn memory_root_fd() -> &'static libredox::Fd {
MEMORY_ROOT_FD
.get()
.expect("acpid: failed to get memory_root_fd")
}
/// Specifies the write behavior for a specific region of memory
///
/// These types indicate to the driver how writes to a specific memory region are handled by the
@@ -136,7 +158,7 @@ pub unsafe fn physmap(
}
let path = format!(
"/scheme/memory/physical@{}",
"physical@{}",
match ty {
MemoryType::Writeback => "wb",
MemoryType::Uncacheable => "uc",
@@ -158,7 +180,7 @@ pub unsafe fn physmap(
prot |= flag::PROT_WRITE;
}
let fd = Fd::open(&path, O_CLOEXEC | mode, 0)?;
let fd = memory_root_fd().openat(&path, O_CLOEXEC | mode, 0)?;
Ok(libredox::call::mmap(MmapArgs {
fd: fd.raw(),
offset: base_phys as u64,
@@ -245,18 +267,6 @@ impl Drop for PhysBorrowed {
}
}
// TODO: temporary wrapper in redox_syscall?
unsafe fn sys_call(fd: usize, buf: &mut [u8], metadata: &[u64]) -> Result<usize> {
Ok(syscall::syscall5(
syscall::SYS_CALL,
fd,
buf.as_mut_ptr() as usize,
buf.len(),
metadata.len(),
metadata.as_ptr() as usize,
)?)
}
/// Instructs the kernel to enable I/O ports for this (usermode) process (x86-specific).
///
/// On Redox, x86 privilege ring 3 represents userspace. Most Redox drivers run in userspace to
@@ -268,7 +278,14 @@ pub fn acquire_port_io_rights() -> Result<()> {
fn redox_cur_thrfd_v0() -> usize;
}
let kernel_fd = syscall::dup(unsafe { redox_cur_thrfd_v0() }, b"open_via_dup")?;
let res = unsafe { sys_call(kernel_fd, &mut [], &[ProcSchemeVerb::Iopl as u64]) };
let res = unsafe {
libredox::call::call_wo(
kernel_fd,
&[],
syscall::CallFlags::empty(),
&[ProcSchemeVerb::Iopl as u64],
)
};
let _ = syscall::close(kernel_fd);
res?;
Ok(())
@@ -287,14 +304,14 @@ impl VirtaddrTranslationHandle {
/// Create a new handle, requires uid=0 but this may change.
pub fn new() -> Result<Self> {
Ok(Self {
fd: Fd::open("/scheme/memory/translation", O_CLOEXEC, 0)?,
fd: memory_root_fd().openat("translation", O_CLOEXEC, 0)?,
})
}
/// Translate physical => virtual.
pub fn translate(&self, physical: usize) -> Result<usize> {
let mut buf = physical.to_ne_bytes();
unsafe {
sys_call(self.fd.raw(), &mut buf, &[])?;
libredox::call::call_ro(self.fd.raw(), &mut buf, syscall::CallFlags::empty(), &[])?;
}
Ok(usize::from_ne_bytes(buf))
}
+1
View File
@@ -20,6 +20,7 @@ pub fn setup_logging(
mut output_level: log::LevelFilter,
file_level: log::LevelFilter,
) {
RedoxLogger::init_timezone();
if let Some(log_level) = read_bootloader_log_level_env(category, subcategory) {
output_level = log_level;
}
+7 -3
View File
@@ -1,8 +1,9 @@
//! <https://www.qemu.org/docs/master/specs/standard-vga.html>
use common::acquire_port_io_rights;
use inputd::ProducerHandle;
use pcid_interface::PciFunctionHandle;
use redox_scheme::{RequestKind, SignalBehavior, Socket};
use redox_scheme::{scheme::register_sync_scheme, RequestKind, SignalBehavior, Socket};
use crate::bga::Bga;
use crate::scheme::BgaScheme;
@@ -13,6 +14,7 @@ mod scheme;
// FIXME add a driver-graphics implementation
fn main() {
common::init();
pcid_interface::pci_daemon(daemon);
}
@@ -32,7 +34,7 @@ fn daemon(daemon: daemon::Daemon, mut pcid_handle: PciFunctionHandle) -> ! {
log::info!("BGA {}", pci_config.func.display());
let socket = Socket::create("bga").expect("bgad: failed to create bga scheme");
let socket = Socket::create().expect("bgad: failed to create bga scheme");
let bar = unsafe { pcid_handle.map_bar(2) }.ptr.as_ptr();
@@ -46,10 +48,12 @@ fn daemon(daemon: daemon::Daemon, mut pcid_handle: PciFunctionHandle) -> ! {
scheme.update_size();
libredox::call::setrens(0, 0).expect("bgad: failed to enter null namespace");
register_sync_scheme(&socket, "bga", &mut scheme).expect("bgad: failed to register bga scheme");
daemon.ready();
libredox::call::setrens(0, 0).expect("bgad: failed to enter null namespace");
loop {
let Some(request) = socket
.next_request(SignalBehavior::Restart)
+16 -1
View File
@@ -27,8 +27,23 @@ impl BgaScheme {
}
}
const SCHEME_ROOT_ID: usize = 1;
impl SchemeSync for BgaScheme {
fn open(&mut self, _path: &str, _flags: usize, ctx: &CallerCtx) -> Result<OpenResult> {
fn scheme_root(&mut self) -> Result<usize> {
Ok(SCHEME_ROOT_ID)
}
fn openat(
&mut self,
dirfd: usize,
_path: &str,
_flags: usize,
_fcntl_flags: u32,
ctx: &CallerCtx,
) -> Result<OpenResult> {
if dirfd != SCHEME_ROOT_ID {
return Err(Error::new(EACCES));
}
if ctx.uid == 0 {
Ok(OpenResult::ThisScheme {
number: 0,
+42 -6
View File
@@ -19,10 +19,12 @@ use graphics_ipc::v1::CursorDamage;
use graphics_ipc::v2::Damage;
use inputd::{VtEvent, VtEventKind};
use libredox::Fd;
use redox_scheme::scheme::SchemeSync;
use redox_scheme::scheme::{register_scheme_inner, SchemeSync};
use redox_scheme::{CallerCtx, OpenResult, RequestKind, SignalBehavior, Socket};
use syscall::schemev2::NewFdFlags;
use syscall::{Error, MapFlags, Result, EAGAIN, EBADF, EINVAL, ENOENT, EOPNOTSUPP};
use syscall::{
CallFlags, Error, MapFlags, Result, EACCES, EAGAIN, EBADF, EINVAL, ENOENT, EOPNOTSUPP,
};
use crate::objects::{DrmObjectId, DrmObjects};
use crate::properties::DrmPropertyKind;
@@ -119,12 +121,13 @@ enum Handle<T: GraphicsAdapter> {
next_id: u32,
fbs: HashMap<u32, Arc<T::Framebuffer>>,
},
SchemeRoot,
}
impl<T: GraphicsAdapter> GraphicsScheme<T> {
pub fn new(mut adapter: T, scheme_name: String) -> Self {
assert!(scheme_name.starts_with("display"));
let socket = Socket::nonblock(&scheme_name).expect("failed to create graphics scheme");
let socket = Socket::nonblock().expect("failed to create graphics scheme");
let disable_graphical_debug = Some(
File::open("/scheme/debug/disable-graphical-debug")
@@ -152,7 +155,7 @@ impl<T: GraphicsAdapter> GraphicsScheme<T> {
adapter.probe_connector(&mut objects, &standard_properties, connector_id)
}
GraphicsScheme {
let mut scheme = GraphicsScheme {
adapter,
scheme_name,
disable_graphical_debug,
@@ -163,7 +166,15 @@ impl<T: GraphicsAdapter> GraphicsScheme<T> {
handles: BTreeMap::new(),
active_vt: 0,
vts: HashMap::new(),
}
};
let cap_id = scheme
.scheme_root()
.expect("failed to get this scheme root");
register_scheme_inner(&scheme.socket, &scheme.scheme_name, cap_id)
.expect("failed to register graphics scheme root");
scheme
}
pub fn event_handle(&self) -> &Fd {
@@ -308,7 +319,26 @@ impl<T: GraphicsAdapter> GraphicsScheme<T> {
const MAP_FAKE_OFFSET_MULTIPLIER: usize = 0x10_000_000;
impl<T: GraphicsAdapter> SchemeSync for GraphicsScheme<T> {
fn open(&mut self, path: &str, _flags: usize, _ctx: &CallerCtx) -> Result<OpenResult> {
fn scheme_root(&mut self) -> Result<usize> {
let id = self.next_id;
self.next_id += 1;
self.handles.insert(id, Handle::SchemeRoot);
Ok(id)
}
fn openat(
&mut self,
dirfd: usize,
path: &str,
_flags: usize,
_fcntl_flags: u32,
_ctx: &CallerCtx,
) -> Result<OpenResult> {
if !matches!(
self.handles.get(&dirfd).ok_or(Error::new(EBADF))?,
Handle::SchemeRoot
) {
return Err(Error::new(EACCES));
}
if path.is_empty() {
return Err(Error::new(EINVAL));
}
@@ -369,6 +399,7 @@ impl<T: GraphicsAdapter> SchemeSync for GraphicsScheme<T> {
next_id: _,
fbs: _,
} => format!("/scheme/{}/v2/{vt}", self.scheme_name),
Handle::SchemeRoot => return Err(Error::new(EOPNOTSUPP)),
};
buf[..path.len()].copy_from_slice(path.as_bytes());
Ok(path.len())
@@ -390,6 +421,7 @@ impl<T: GraphicsAdapter> SchemeSync for GraphicsScheme<T> {
Ok(())
}
Handle::V2 { .. } => Err(Error::new(EOPNOTSUPP)),
Handle::SchemeRoot => Err(Error::new(EOPNOTSUPP)),
}
}
@@ -414,6 +446,7 @@ impl<T: GraphicsAdapter> SchemeSync for GraphicsScheme<T> {
Ok(1)
}
Handle::V2 { .. } => Err(Error::new(EOPNOTSUPP)),
Handle::SchemeRoot => Err(Error::new(EOPNOTSUPP)),
}
}
@@ -493,6 +526,7 @@ impl<T: GraphicsAdapter> SchemeSync for GraphicsScheme<T> {
Ok(buf.len())
}
Handle::V2 { .. } => Err(Error::new(EOPNOTSUPP)),
Handle::SchemeRoot => Err(Error::new(EOPNOTSUPP)),
}
}
@@ -535,6 +569,7 @@ impl<T: GraphicsAdapter> SchemeSync for GraphicsScheme<T> {
Handle::V1Screen { .. } => {
return Err(Error::new(EOPNOTSUPP));
}
Handle::SchemeRoot => return Err(Error::new(EOPNOTSUPP)),
Handle::V2 { vt, next_id, fbs } => match metadata[0] {
ipc::VERSION => ipc::DrmVersion::with(payload, |mut data| {
data.set_version_major(1);
@@ -887,6 +922,7 @@ impl<T: GraphicsAdapter> SchemeSync for GraphicsScheme<T> {
.unwrap(),
offset & (MAP_FAKE_OFFSET_MULTIPLIER as u64 - 1),
),
Handle::SchemeRoot => return Err(Error::new(EOPNOTSUPP)),
};
let ptr = T::map_dumb_framebuffer(&mut self.adapter, framebuffer);
Ok(unsafe { ptr.add(offset as usize) } as usize)
+23 -14
View File
@@ -14,7 +14,7 @@ use event::EventQueue;
use inputd::ConsumerHandleEvent;
use libredox::errno::EAGAIN;
use orbclient::Event;
use redox_scheme::{RequestKind, SignalBehavior, Socket};
use redox_scheme::{scheme::register_sync_scheme, RequestKind, SignalBehavior, Socket};
use crate::scheme::FbbootlogScheme;
@@ -33,17 +33,9 @@ fn daemon(daemon: daemon::Daemon) -> ! {
}
}
let socket =
Socket::nonblock("fbbootlog").expect("fbbootlogd: failed to create fbbootlog scheme");
let socket = Socket::nonblock().expect("fbbootlogd: failed to create fbbootlog scheme");
{
// Add ourself as log sink
let mut log_file = std::fs::OpenOptions::new()
.write(true)
.open("/scheme/log/add_sink")
.unwrap();
log_file.write(b"/scheme/fbbootlog").unwrap();
}
let mut scheme = FbbootlogScheme::new();
event_queue
.subscribe(
@@ -51,9 +43,7 @@ fn daemon(daemon: daemon::Daemon) -> ! {
Source::Scheme,
event::EventFlags::READ,
)
.expect("fbcond: failed to subscribe to scheme events");
let mut scheme = FbbootlogScheme::new();
.expect("fbbootlogd: failed to subscribe to scheme events");
event_queue
.subscribe(
@@ -63,6 +53,25 @@ fn daemon(daemon: daemon::Daemon) -> ! {
)
.expect("fbbootlogd: failed to subscribe to scheme events");
{
let log_fd = socket
.create_this_scheme_fd(0, 0, 0, 0)
.expect("fbbootlogd: failed to create log fd");
// Add ourself as log sink
let mut log_file = libredox::Fd::open(
"/scheme/log/add_sink",
libredox::flag::O_WRONLY | libredox::flag::O_CLOEXEC,
0,
)
.expect("fbbootlogd: failed to open log/add_sink");
log_file
.call_wo(&log_fd.to_ne_bytes(), syscall::CallFlags::FD, &[])
.expect("fbbootlogd: failed to send log fd to log scheme.");
}
register_sync_scheme(&socket, "fbbootlog", &mut scheme)
.expect("fbbootlog: failed to register scheme to namespace");
// This is not possible for now as fbbootlogd needs to open new displays at runtime for graphics
// driver handoff. In the future inputd may directly pass a handle to the display instead.
//libredox::call::setrens(0, 0).expect("fbbootlogd: failed to enter null namespace");
+22 -3
View File
@@ -10,7 +10,7 @@ use orbclient::{Event, EventOption};
use redox_scheme::scheme::SchemeSync;
use redox_scheme::{CallerCtx, OpenResult};
use syscall::schemev2::NewFdFlags;
use syscall::{Error, Result, EINVAL, ENOENT};
use syscall::{Error, Result, EACCES, EBADF, EINVAL, ENOENT};
pub struct FbbootlogScheme {
pub input_handle: ConsumerHandle,
@@ -173,8 +173,24 @@ impl FbbootlogScheme {
}
}
const SCHEME_ROOT_ID: usize = 1;
impl SchemeSync for FbbootlogScheme {
fn open(&mut self, path_str: &str, _flags: usize, _ctx: &CallerCtx) -> Result<OpenResult> {
fn scheme_root(&mut self) -> Result<usize> {
Ok(SCHEME_ROOT_ID)
}
fn openat(
&mut self,
dirfd: usize,
path_str: &str,
flags: usize,
_fcntl_flags: u32,
_ctx: &CallerCtx,
) -> Result<OpenResult> {
if dirfd != SCHEME_ROOT_ID {
return Err(Error::new(EACCES));
}
if !path_str.is_empty() {
return Err(Error::new(ENOENT));
}
@@ -214,12 +230,15 @@ impl SchemeSync for FbbootlogScheme {
fn write(
&mut self,
_id: usize,
id: usize,
buf: &[u8],
_offset: u64,
_fcntl_flags: u32,
_ctx: &CallerCtx,
) -> Result<usize> {
if id == SCHEME_ROOT_ID {
return Err(Error::new(EBADF));
}
if let Some(map) = &mut self.display_map {
Self::handle_resize(map, &mut self.text_screen);
self.text_buffer.write(buf);
+8 -4
View File
@@ -3,13 +3,13 @@ use inputd::ConsumerHandleEvent;
use libredox::errno::{EAGAIN, EINTR};
use orbclient::Event;
use redox_scheme::{
scheme::{Op, SchemeResponse, SchemeSync},
scheme::{register_sync_scheme, Op, SchemeResponse, SchemeSync},
CallerCtx, RequestKind, Response, SignalBehavior, Socket,
};
use std::env;
use syscall::{EOPNOTSUPP, EVENT_READ};
use crate::scheme::{FbconScheme, VtIndex};
use crate::scheme::{FbconScheme, Handle, VtIndex};
mod display;
mod scheme;
@@ -35,7 +35,7 @@ fn daemon(daemon: daemon::Daemon) -> ! {
// FIXME listen for resize events from inputd and handle them
let mut socket = Socket::nonblock("fbcon").expect("fbcond: failed to create fbcon scheme");
let mut socket = Socket::nonblock().expect("fbcond: failed to create fbcon scheme");
event_queue
.subscribe(
socket.inner().raw(),
@@ -46,6 +46,9 @@ fn daemon(daemon: daemon::Daemon) -> ! {
let mut scheme = FbconScheme::new(&vt_ids, &mut event_queue);
register_sync_scheme(&socket, "fbcon", &mut scheme)
.expect("fbcond: failed to register scheme to namespace");
// This is not possible for now as fbcond needs to open new displays at runtime for graphics
// driver handoff. In the future inputd may directly pass a handle to the display instead.
// libredox::call::setrens(0, 0).expect("fbcond: failed to enter null namespace");
@@ -204,7 +207,8 @@ fn handle_event(
for (handle_id, handle) in scheme.handles.iter_mut() {
let handle = match handle {
handle => handle,
Handle::SchemeRoot => continue,
Handle::Vt(handle) => handle,
};
if !handle.events.contains(EVENT_READ) {
+43 -11
View File
@@ -34,10 +34,15 @@ pub struct FdHandle {
pub notified_read: bool,
}
pub enum Handle {
Vt(FdHandle),
SchemeRoot,
}
pub struct FbconScheme {
pub vts: BTreeMap<VtIndex, TextScreen>,
next_id: usize,
pub handles: BTreeMap<usize, FdHandle>,
pub handles: BTreeMap<usize, Handle>,
}
impl FbconScheme {
@@ -65,14 +70,36 @@ impl FbconScheme {
fn get_vt_handle_mut(&mut self, id: usize) -> Result<&mut FdHandle> {
match self.handles.get_mut(&id) {
Some(handle) => Ok(handle),
Some(Handle::Vt(handle)) => Ok(handle),
Some(Handle::SchemeRoot) => Err(Error::new(EBADF)),
None => Err(Error::new(EBADF)),
}
}
}
impl SchemeSync for FbconScheme {
fn open(&mut self, path_str: &str, flags: usize, _ctx: &CallerCtx) -> Result<OpenResult> {
fn scheme_root(&mut self) -> Result<usize> {
let id = self.next_id;
self.next_id += 1;
self.handles.insert(id, Handle::SchemeRoot);
Ok(id)
}
fn openat(
&mut self,
dirfd: usize,
path_str: &str,
flags: usize,
fcntl_flags: u32,
_ctx: &CallerCtx,
) -> Result<OpenResult> {
if !matches!(
self.handles.get(&dirfd).ok_or(Error::new(EBADF))?,
Handle::SchemeRoot
) {
return Err(Error::new(EACCES));
}
let vt_i = VtIndex(path_str.parse::<usize>().map_err(|_| Error::new(ENOENT))?);
if self.vts.contains_key(&vt_i) {
let id = self.next_id;
@@ -80,12 +107,12 @@ impl SchemeSync for FbconScheme {
self.handles.insert(
id,
FdHandle {
Handle::Vt(FdHandle {
vt_i,
flags: flags,
flags: flags | fcntl_flags as usize,
events: EventFlags::empty(),
notified_read: false,
},
}),
);
Ok(OpenResult::ThisScheme {
@@ -104,7 +131,8 @@ impl SchemeSync for FbconScheme {
_ctx: &CallerCtx,
) -> Result<syscall::EventFlags> {
let handle = match self.handles.get_mut(&id) {
Some(handle) => Ok(handle),
Some(Handle::Vt(handle)) => Ok(handle),
Some(Handle::SchemeRoot) => Err(Error::new(EBADF)),
None => Err(Error::new(EBADF)),
}?;
@@ -116,7 +144,8 @@ impl SchemeSync for FbconScheme {
fn fpath(&mut self, id: usize, buf: &mut [u8], _ctx: &CallerCtx) -> Result<usize> {
let handle = match self.handles.get(&id) {
Some(handle) => Ok(handle),
Some(Handle::Vt(handle)) => Ok(handle),
Some(Handle::SchemeRoot) => Err(Error::new(EBADF)),
None => Err(Error::new(EBADF)),
}?;
@@ -134,7 +163,8 @@ impl SchemeSync for FbconScheme {
fn fsync(&mut self, id: usize, _ctx: &CallerCtx) -> Result<()> {
match self.handles.get(&id) {
Some(_) => Ok(()),
Some(Handle::Vt(_)) => Ok(()),
Some(Handle::SchemeRoot) => Err(Error::new(EBADF)),
None => Err(Error::new(EBADF)),
}
}
@@ -155,7 +185,8 @@ impl SchemeSync for FbconScheme {
_ctx: &CallerCtx,
) -> Result<usize> {
let handle = match self.handles.get(&id) {
Some(handle) => Ok(handle),
Some(Handle::Vt(handle)) => Ok(handle),
Some(Handle::SchemeRoot) => Err(Error::new(EBADF)),
None => Err(Error::new(EBADF)),
}?;
@@ -183,7 +214,8 @@ impl SchemeSync for FbconScheme {
_ctx: &CallerCtx,
) -> Result<usize> {
let handle = match self.handles.get(&id) {
Some(handle) => Ok(handle),
Some(Handle::Vt(handle)) => Ok(handle),
Some(Handle::SchemeRoot) => Err(Error::new(EBADF)),
None => Err(Error::new(EBADF)),
}?;
+1
View File
@@ -12,6 +12,7 @@ use crate::scheme::{FbAdapter, FrameBuffer};
mod scheme;
fn main() {
common::init();
daemon::Daemon::new(daemon);
}
fn daemon(daemon: daemon::Daemon) -> ! {
+2 -1
View File
@@ -476,6 +476,7 @@ impl MoveCursor {
static DEVICE: spin::Once<virtio_core::Device> = spin::Once::new();
fn main() {
common::init();
pcid_interface::pci_daemon(daemon_runner);
}
@@ -524,7 +525,6 @@ fn deamon(deamon: daemon::Daemon, mut pcid_handle: PciFunctionHandle) -> anyhow:
device.transport.setup_config_notify(MSIX_PRIMARY_VECTOR);
device.transport.run_device();
deamon.ready();
let (mut scheme, mut inputd_handle) = scheme::GpuScheme::new(
config,
@@ -533,6 +533,7 @@ fn deamon(deamon: daemon::Daemon, mut pcid_handle: PciFunctionHandle) -> anyhow:
device.transport.clone(),
has_edid,
)?;
deamon.ready();
user_data! {
enum Source {
+1
View File
@@ -7,6 +7,7 @@ edition = "2018"
fdt = "0.1.5"
log.workspace = true
ron = "0.8.1"
libredox = { version = "0.1.12", default-features = false, features = ["std", "call"] }
amlserde = { path = "../amlserde" }
common = { path = "../common" }
+14 -2
View File
@@ -20,11 +20,23 @@ impl Backend for AcpiBackend {
fn probe(&mut self) -> Result<(), Box<dyn Error>> {
// Read symbols from acpi scheme
for entry_res in fs::read_dir("/scheme/acpi/symbols")? {
let entries = fs::read_dir("/scheme/acpi/symbols")?;
// TODO: Reimplement with getdents?
let symbols_fd = libredox::Fd::open(
"/scheme/acpi/symbols",
libredox::flag::O_DIRECTORY | libredox::flag::O_RDONLY,
0,
)?;
for entry_res in entries {
let entry = entry_res?;
if let Some(file_name) = entry.file_name().to_str() {
if file_name.ends_with("_CID") || file_name.ends_with("_HID") {
let ron = fs::read_to_string(entry.path())?;
let symbol_fd = symbols_fd.openat(file_name, libredox::flag::O_RDONLY, 0)?;
let stat = symbol_fd.stat()?;
let mut buf: Vec<u8> = vec![0u8; stat.st_size as usize];
let count = symbol_fd.read(&mut buf)?;
buf.truncate(count);
let ron = String::from_utf8(buf)?;
let AmlSerde { name, value } = ron::from_str(&ron)?;
let id = match value {
AmlSerdeValue::Integer(integer) => {
+3
View File
@@ -12,6 +12,9 @@ use std::{env, process};
use common::acquire_port_io_rights;
use event::{user_data, EventQueue};
use inputd::ProducerHandle;
use log::info;
use redox_scheme::{scheme::register_sync_scheme, RequestKind, SignalBehavior, Socket};
use syscall::{EAGAIN, EWOULDBLOCK};
use crate::state::Ps2d;
+1 -1
View File
@@ -186,7 +186,7 @@ fn main() {
interface_num
);
let handle = XhciClientHandle::new(scheme, port);
let handle = XhciClientHandle::new(scheme, port).expect("Faild to open XhciClientHandle");
let desc: DevDesc = handle
.get_standard_descs()
.expect("Failed to get standard descriptors");
+29 -8
View File
@@ -20,13 +20,12 @@ use std::sync::atomic::{AtomicUsize, Ordering};
use inputd::{ControlEvent, VtEvent, VtEventKind};
use libredox::errno::ESTALE;
use log::warn;
use redox_scheme::scheme::SchemeSync;
use redox_scheme::scheme::{register_sync_scheme, SchemeSync};
use redox_scheme::{CallerCtx, OpenResult, RequestKind, Response, SignalBehavior, Socket};
use orbclient::{Event, EventOption};
use syscall::schemev2::NewFdFlags;
use syscall::{Error as SysError, EventFlags, EINVAL};
use syscall::{Error as SysError, EventFlags, EACCES, EBADF, EINVAL};
pub mod keymap;
@@ -54,6 +53,7 @@ enum Handle {
is_earlyfb: bool,
},
Control,
SchemeRoot,
}
struct InputScheme {
@@ -152,7 +152,27 @@ impl InputScheme {
}
impl SchemeSync for InputScheme {
fn open(&mut self, path: &str, _flags: usize, _ctx: &CallerCtx) -> syscall::Result<OpenResult> {
fn scheme_root(&mut self) -> syscall::Result<usize> {
let fd = self.next_id.fetch_add(1, Ordering::SeqCst);
self.handles.insert(fd, Handle::SchemeRoot);
Ok(fd)
}
fn openat(
&mut self,
dirfd: usize,
path: &str,
_flags: usize,
_fcntl_flags: u32,
_ctx: &CallerCtx,
) -> syscall::Result<OpenResult> {
if !matches!(
self.handles.get(&dirfd).ok_or(SysError::new(EINVAL))?,
Handle::SchemeRoot
) {
return Err(SysError::new(EACCES));
}
let mut path_parts = path.split('/');
let command = path_parts.next().ok_or(SysError::new(EINVAL))?;
@@ -167,7 +187,6 @@ impl SchemeSync for InputScheme {
if self.active_vt.is_none() {
self.switch_vt(vt);
}
Handle::Consumer {
events: EventFlags::empty(),
pending: Vec::new(),
@@ -319,6 +338,7 @@ impl SchemeSync for InputScheme {
log::error!("control tried to read");
return Err(SysError::new(EINVAL));
}
Handle::SchemeRoot => return Err(SysError::new(EBADF)),
}
}
@@ -364,6 +384,7 @@ impl SchemeSync for InputScheme {
return Err(SysError::new(EINVAL));
}
Handle::Producer => {}
Handle::SchemeRoot => return Err(SysError::new(EBADF)),
}
if buf.len() == 1 && buf[0] > 0xf4 {
@@ -508,11 +529,10 @@ impl SchemeSync for InputScheme {
log::error!("producer or control tried to use an event queue");
Err(SysError::new(EINVAL))
}
Handle::SchemeRoot => Err(SysError::new(EBADF)),
}
}
}
impl InputScheme {
fn on_close(&mut self, id: usize) {
let handle = self.handles.remove(&id).unwrap();
@@ -534,9 +554,10 @@ impl InputScheme {
fn deamon(deamon: daemon::Daemon) -> anyhow::Result<()> {
// Create the ":input" scheme.
let socket_file = Socket::create("input")?;
let socket_file = Socket::create()?;
let mut scheme = InputScheme::new();
register_sync_scheme(&socket_file, "input", &mut scheme)?;
deamon.ready();
loop {
+16 -1
View File
@@ -1787,8 +1787,23 @@ impl Alx {
}
}
const SCHEME_ROOT_ID: usize = usize::MAX;
impl SchemeSync for Alx {
fn open(&mut self, path: &str, flags: usize, ctx: &CallerCtx) -> Result<OpenResult> {
fn scheme_root(&mut self) -> Result<usize> {
Ok(SCHEME_ROOT_ID)
}
fn openat(
&mut self,
dirfd: usize,
path_str: &str,
flags: usize,
_fcntl_flags: u32,
ctx: &CallerCtx,
) -> Result<OpenResult> {
if dirfd != SCHEME_ROOT_ID {
return Err(Error::new(EACCES));
}
if ctx.uid == 0 {
Ok(OpenResult::ThisScheme {
number: flags,
+11 -5
View File
@@ -12,6 +12,7 @@ use std::os::fd::AsRawFd;
use std::{env, iter};
use event::{user_data, EventQueue};
use redox_scheme::scheme::register_sync_scheme;
use redox_scheme::wrappers::ReadinessBased;
use redox_scheme::Socket;
use std::cell::RefCell;
@@ -19,6 +20,7 @@ use std::cell::RefCell;
pub mod device;
fn main() {
common::init();
daemon::Daemon::new(daemon);
}
@@ -36,11 +38,9 @@ fn daemon(daemon: daemon::Daemon) -> ! {
println!(" + ALX {} on: {:X}, IRQ: {}\n", name, bar, irq);
let socket = Socket::nonblock("network").expect("alxd: failed to create socket");
let socket = Socket::nonblock().expect("alxd: failed to create socket");
let mut readiness_based = ReadinessBased::new(&socket, 16);
daemon.ready();
let mut irq_file =
File::open(format!("/scheme/irq/{}", irq)).expect("alxd: failed to open IRQ file");
@@ -54,10 +54,16 @@ fn daemon(daemon: daemon::Daemon) -> ! {
.expect("alxd: failed to map address") as usize
};
{
let device = RefCell::new(unsafe {
device::Alx::new(address).expect("alxd: failed to allocate device")
let device = RefCell::new({
let mut device =
unsafe { device::Alx::new(address).expect("alxd: failed to allocate device") };
register_sync_scheme(&socket, "network", &mut device)
.expect("alxd: failed to register network scheme to namespace");
device
});
daemon.ready();
user_data! {
enum Source {
Irq,
+31 -3
View File
@@ -52,9 +52,12 @@ impl<T: NetworkAdapter> NetworkScheme<T> {
daemon: daemon::Daemon,
scheme_name: String,
) -> Self {
let socket = Socket::nonblock(&scheme_name).expect("failed to create network scheme");
assert!(scheme_name.starts_with("network"));
let socket = Socket::nonblock().expect("failed to create network scheme");
let adapter = adapter_fn();
let scheme = NetworkSchemeInner::new(adapter, scheme_name.clone());
let mut scheme = NetworkSchemeInner::new(adapter, scheme_name.clone());
redox_scheme::scheme::register_sync_scheme(&socket, &scheme_name, &mut scheme)
.expect("failed to regitster network scheme");
daemon.ready();
Self {
scheme,
@@ -196,6 +199,7 @@ struct NetworkSchemeInner<T: NetworkAdapter> {
enum Handle {
Data,
Mac,
SchemeRoot,
}
impl<T: NetworkAdapter> NetworkSchemeInner<T> {
@@ -210,7 +214,27 @@ impl<T: NetworkAdapter> NetworkSchemeInner<T> {
}
impl<T: NetworkAdapter> SchemeSync for NetworkSchemeInner<T> {
fn open(&mut self, path: &str, _flags: usize, ctx: &CallerCtx) -> Result<OpenResult> {
fn scheme_root(&mut self) -> Result<usize> {
let id = self.next_id;
self.next_id += 1;
self.handles.insert(id, Handle::SchemeRoot);
Ok(id)
}
fn openat(
&mut self,
fd: usize,
path: &str,
_flags: usize,
_fcntl_flags: u32,
ctx: &CallerCtx,
) -> Result<OpenResult> {
if !matches!(
self.handles.get(&fd).ok_or(Error::new(EINVAL))?,
Handle::SchemeRoot
) {
return Err(Error::new(EACCES));
}
if ctx.uid != 0 {
return Err(Error::new(EACCES));
}
@@ -247,6 +271,7 @@ impl<T: NetworkAdapter> SchemeSync for NetworkSchemeInner<T> {
buf[..i].copy_from_slice(&data[..i]);
return Ok(i);
}
_ => return Err(Error::new(EBADF)),
};
match self.adapter.read_packet(buf)? {
@@ -274,6 +299,7 @@ impl<T: NetworkAdapter> SchemeSync for NetworkSchemeInner<T> {
match handle {
Handle::Data => {}
Handle::Mac { .. } => return Err(Error::new(EINVAL)),
_ => return Err(Error::new(EBADF)),
}
Ok(self.adapter.write_packet(buf)?)
@@ -306,6 +332,7 @@ impl<T: NetworkAdapter> SchemeSync for NetworkSchemeInner<T> {
let path = match handle {
Handle::Data { .. } => &b""[..],
Handle::Mac { .. } => &b"mac"[..],
_ => &b""[..],
};
j = 0;
@@ -329,6 +356,7 @@ impl<T: NetworkAdapter> SchemeSync for NetworkSchemeInner<T> {
stat.st_mode = MODE_FILE | 0o400;
stat.st_size = 6;
}
_ => return Err(Error::new(EBADF)),
}
Ok(())
+1
View File
@@ -8,6 +8,7 @@ use pcid_interface::PciFunctionHandle;
pub mod device;
fn main() {
common::init();
pcid_interface::pci_daemon(daemon);
}
+1
View File
@@ -10,6 +10,7 @@ pub mod device;
mod ixgbe;
fn main() {
common::init();
pcid_interface::pci_daemon(daemon);
}
+1
View File
@@ -36,6 +36,7 @@ fn map_bar(pcid_handle: &mut PciFunctionHandle) -> *mut u8 {
}
fn main() {
common::init();
pcid_interface::pci_daemon(daemon);
}
+1
View File
@@ -36,6 +36,7 @@ fn map_bar(pcid_handle: &mut PciFunctionHandle) -> *mut u8 {
}
fn main() {
common::init();
pcid_interface::pci_daemon(daemon);
}
+1
View File
@@ -27,6 +27,7 @@ static_assertions::const_assert_eq!(core::mem::size_of::<VirtHeader>(), 12);
const MAX_BUFFER_LEN: usize = 65535;
fn main() {
common::init();
pcid_interface::pci_daemon(daemon_runner);
}
+1 -1
View File
@@ -90,7 +90,7 @@ fn main() -> Result<()> {
match command.status() {
Ok(status) if !status.success() => {
log::error!("pcid-spawner: driver {command:?} failed with {status}");
log::error!("pcid-spawner: driver {command:?} failed with {status}")
}
Ok(_) => {}
Err(err) => log::error!("pcid-spawner: failed to execute {command:?}: {err}"),
+3 -2
View File
@@ -327,9 +327,10 @@ impl PciFunctionHandle {
}
pub fn connect_by_path(device_path: &Path) -> io::Result<Self> {
let channel_fd = syscall::open(
let channel_fd = libredox::call::open(
device_path.join("channel").to_str().unwrap(),
syscall::O_RDWR,
libredox::flag::O_RDWR,
0,
)
.map_err(|err| io::Error::other(format!("failed to open pcid channel: {}", err)))?;
Ok(Self::connect_common(channel_fd as RawFd))
+41 -5
View File
@@ -10,7 +10,7 @@ use pci_types::{
Bar as TyBar, CommandRegister, EndpointHeader, HeaderType, PciAddress,
PciHeader as TyPciHeader, PciPciBridgeHeader,
};
use redox_scheme::{RequestKind, SignalBehavior};
use redox_scheme::{scheme::register_sync_scheme, RequestKind, SignalBehavior};
use crate::cfg_access::Pcie;
use pcid_interface::{FullDeviceId, LegacyInterruptLine, PciBar, PciFunction, PciRom};
@@ -232,6 +232,7 @@ fn enable_function(
}
fn main() {
common::init();
daemon::Daemon::new(daemon);
}
@@ -245,10 +246,39 @@ fn daemon(daemon: daemon::Daemon) -> ! {
);
let pcie = Pcie::new();
let mut tree = BTreeMap::new();
info!("PCI SG-BS:DV.F VEND:DEVI CL.SC.IN.RV");
let mut scheme = scheme::PciScheme::new(pcie);
let socket = redox_scheme::Socket::create().expect("failed to open pci scheme socket");
{
match libredox::Fd::open("/scheme/acpi/register_pci", libredox::flag::O_WRONLY, 0) {
Ok(register_pci) => {
let access_id = scheme.access();
let access_fd = socket
.create_this_scheme_fd(0, access_id, syscall::O_RDWR, 0)
.expect("failed to issue this resource");
let access_bytes = access_fd.to_ne_bytes();
let _ = register_pci
.call_wo(
&access_bytes,
syscall::CallFlags::WRITE | syscall::CallFlags::FD,
&[],
)
.expect("failed to send pci_fd to acpid");
}
Err(err) => {
if err.errno() == libredox::errno::ENODEV {
debug!("pcid: acpid not found. Running without ACPI integration.");
} else {
warn!("pcid: failed to open acpid register_pci (error: {}). Running without ACPI integration.", err);
}
}
}
}
// FIXME Use full ACPI for enumerating the host bridges. MCFG only describes the first
// host bridge, while multi-processor systems likely have a host bridge for each CPU.
// See also https://www.kernel.org/doc/html/latest/PCI/acpi-info.html
@@ -261,13 +291,19 @@ fn daemon(daemon: daemon::Daemon) -> ! {
bus_i += 1;
for dev_num in 0..32 {
scan_device(&mut tree, &pcie, &mut bus_nums, bus_num, dev_num);
scan_device(
&mut scheme.tree,
&scheme.pcie,
&mut bus_nums,
bus_num,
dev_num,
);
}
}
debug!("Enumeration complete, now starting pci scheme");
let mut scheme = scheme::PciScheme::new(pcie, tree);
let socket = redox_scheme::Socket::create("pci").expect("failed to open pci scheme socket");
register_sync_scheme(&socket, "pci", &mut scheme)
.expect("failed to register pci scheme to namespace");
let _ = daemon.ready();
+54 -5
View File
@@ -14,14 +14,15 @@ use crate::cfg_access::Pcie;
pub struct PciScheme {
handles: BTreeMap<usize, HandleWrapper>,
next_id: usize,
pcie: Pcie,
tree: BTreeMap<PciAddress, crate::Func>,
pub pcie: Pcie,
pub tree: BTreeMap<PciAddress, crate::Func>,
}
enum Handle {
TopLevel { entries: Vec<String> },
Access,
Device,
Channel { addr: PciAddress, st: ChannelState },
SchemeRoot,
}
struct HandleWrapper {
inner: Handle,
@@ -38,6 +39,9 @@ impl Handle {
fn requires_root(&self) -> bool {
matches!(self, Self::Access | Self::Channel { .. })
}
fn is_scheme_root(&self) -> bool {
matches!(self, Self::SchemeRoot)
}
}
enum ChannelState {
@@ -47,8 +51,50 @@ enum ChannelState {
const DEVICE_CONTENTS: &[&str] = &["channel"];
impl PciScheme {
pub fn access(&mut self) -> usize {
let id = self.next_id;
self.next_id += 1;
self.handles.insert(
id,
HandleWrapper {
inner: Handle::Access,
stat: false,
},
);
id
}
}
impl SchemeSync for PciScheme {
fn open(&mut self, path: &str, flags: usize, ctx: &CallerCtx) -> Result<OpenResult> {
fn scheme_root(&mut self) -> Result<usize> {
let id = self.next_id;
self.next_id += 1;
self.handles.insert(
id,
HandleWrapper {
inner: Handle::SchemeRoot,
stat: false,
},
);
Ok(id)
}
fn openat(
&mut self,
dirfd: usize,
path: &str,
flags: usize,
_fcntl_flags: u32,
ctx: &CallerCtx,
) -> Result<OpenResult> {
let handle = self.handles.get(&dirfd).ok_or(Error::new(EBADF))?;
if !handle.inner.is_scheme_root() {
return Err(Error::new(EACCES));
}
log::trace!("OPEN `{}` flags {}", path, flags);
// TODO: Check flags are correct
@@ -108,6 +154,7 @@ impl SchemeSync for PciScheme {
Handle::TopLevel { ref entries } => (entries.len(), MODE_DIR | 0o755),
Handle::Device => (DEVICE_CONTENTS.len(), MODE_DIR | 0o755),
Handle::Access | Handle::Channel { .. } => (0, MODE_CHR | 0o600),
Handle::SchemeRoot => return Err(Error::new(EBADF)),
};
stat.st_size = len as u64;
stat.st_mode = mode;
@@ -134,6 +181,7 @@ impl SchemeSync for PciScheme {
addr: _,
ref mut st,
} => Self::read_channel(st, buf),
Handle::SchemeRoot => Err(Error::new(EBADF)),
_ => Err(Error::new(EBADF)),
}
}
@@ -167,6 +215,7 @@ impl SchemeSync for PciScheme {
}
Handle::Device => DEVICE_CONTENTS,
Handle::Access | Handle::Channel { .. } => return Err(Error::new(ENOTDIR)),
Handle::SchemeRoot => return Err(Error::new(EBADF)),
};
for (i, dent_name) in entries.iter().enumerate().skip(offset) {
@@ -296,12 +345,12 @@ impl PciScheme {
}
impl PciScheme {
pub fn new(pcie: Pcie, tree: BTreeMap<PciAddress, crate::Func>) -> Self {
pub fn new(pcie: Pcie) -> Self {
Self {
handles: BTreeMap::new(),
next_id: 0,
pcie,
tree,
tree: BTreeMap::new(),
}
}
fn parse_after_pci_addr(&mut self, addr: PciAddress, after: &str) -> Result<Handle> {
+21 -22
View File
@@ -9,10 +9,6 @@ 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,
@@ -32,15 +28,15 @@ fn handle(
let mut packet = [0; 4096];
loop {
// Read data from PTY master
let count = match syscall::read(master_fd as usize, &mut packet) {
let count = match libredox::call::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)),
Err(ref err) if err.errno() == libredox::errno::EAGAIN => return Ok(true),
Err(err) => return Err(err.into()),
};
// Write data to stdout
syscall::write(1, &packet[1..count]).map_err(syscall_error)?;
libredox::call::write(1, &packet[1..count])?;
for i in 1..count {
// Write byte to QEMU debugcon (Bochs compatible)
@@ -50,10 +46,10 @@ fn handle(
}
EventData::Timer => {
let mut timespec = syscall::TimeSpec::default();
syscall::read(timeout_fd as usize, &mut timespec).map_err(syscall_error)?;
libredox::call::read(timeout_fd as usize, &mut timespec)?;
timespec.tv_sec += 1;
syscall::write(timeout_fd as usize, &mut timespec).map_err(syscall_error)?;
libredox::call::write(timeout_fd as usize, &mut timespec)?;
Ok(true)
}
@@ -85,25 +81,28 @@ fn handle(
}
fn getpty(columns: u32, lines: u32) -> io::Result<(RawFd, String)> {
let master = syscall::open(
let master = libredox::call::open(
"/scheme/pty",
syscall::O_CLOEXEC | syscall::O_RDWR | syscall::O_CREAT | syscall::O_NONBLOCK,
)
.map_err(syscall_error)?;
libredox::flag::O_CLOEXEC
| libredox::flag::O_RDWR
| libredox::flag::O_CREAT
| libredox::flag::O_NONBLOCK,
0,
)?;
if let Ok(winsize_fd) = syscall::dup(master, b"winsize") {
let _ = syscall::write(
if let Ok(winsize_fd) = libredox::call::dup(master, b"winsize") {
let _ = libredox::call::write(
winsize_fd,
&redox_termios::Winsize {
ws_row: lines as u16,
ws_col: columns as u16,
},
);
let _ = syscall::close(winsize_fd);
let _ = libredox::call::close(winsize_fd);
}
let mut buf: [u8; 4096] = [0; 4096];
let count = syscall::fpath(master, &mut buf).map_err(syscall_error)?;
let count = libredox::call::fpath(master, &mut buf)?;
Ok((master as RawFd, unsafe {
String::from_utf8_unchecked(Vec::from(&buf[..count]))
}))
@@ -118,11 +117,11 @@ fn inner() -> anyhow::Result<()> {
let (columns, lines) = (DEFAULT_COLS, DEFAULT_LINES);
let (master_fd, pty) = getpty(columns, lines)?;
let timeout_fd = syscall::open(
let timeout_fd = libredox::call::open(
"/scheme/time/4",
syscall::O_CLOEXEC | syscall::O_RDWR | syscall::O_NONBLOCK,
)
.map_err(syscall_error)? as RawFd;
libredox::flag::O_CLOEXEC | libredox::flag::O_RDWR | libredox::flag::O_NONBLOCK,
0,
)? as RawFd;
let event_queue = event::EventQueue::new()?;
event_queue.subscribe(master_fd as usize, EventData::Pty, event::EventFlags::READ)?;
+1
View File
@@ -14,6 +14,7 @@ use log::{error, info};
pub mod ahci;
fn main() {
common::init();
pcid_interface::pci_daemon(daemon);
}
+47 -12
View File
@@ -11,13 +11,13 @@ use std::task::Poll;
use executor::LocalExecutor;
use libredox::Fd;
use partitionlib::{LogicalBlockSize, PartitionTable};
use redox_scheme::scheme::SchemeAsync;
use redox_scheme::scheme::{register_scheme_inner, SchemeAsync};
use redox_scheme::{CallerCtx, OpenResult, RequestKind, Response, SignalBehavior, Socket};
use syscall::dirent::DirentBuf;
use syscall::schemev2::NewFdFlags;
use syscall::{
Error, Result, Stat, EACCES, EAGAIN, EBADF, EINTR, EINVAL, EISDIR, ENOENT, ENOLCK, EOPNOTSUPP,
EOVERFLOW, EWOULDBLOCK, MODE_DIR, MODE_FILE, O_DIRECTORY, O_STAT,
CallFlags, Error, Result, Stat, EACCES, EAGAIN, EBADF, EINTR, EINVAL, EISDIR, ENOENT, ENOLCK,
EOPNOTSUPP, EOVERFLOW, EWOULDBLOCK, MODE_DIR, MODE_FILE, O_DIRECTORY, O_STAT,
};
/// Split the read operation into a series of block reads.
@@ -258,6 +258,7 @@ enum Handle {
List(Vec<u8>), // entries
Disk(u32), // disk num
Partition(u32, u32), // disk num, part num
SchemeRoot,
}
pub struct DiskScheme<T> {
@@ -310,14 +311,10 @@ impl<T: Disk> DiskScheme<T> {
executor: &impl ExecutorTrait,
) -> Self {
assert!(scheme_name.starts_with("disk"));
let socket = Socket::nonblock(&scheme_name).expect("failed to create disk scheme");
let socket = Socket::nonblock().expect("failed to create disk scheme");
if let Some(daemon) = daemon {
daemon.ready();
}
Self {
scheme_name,
let mut scheme = Self {
scheme_name: scheme_name,
socket,
disks: disks
.into_iter()
@@ -325,7 +322,19 @@ impl<T: Disk> DiskScheme<T> {
.collect(),
next_id: 0,
handles: BTreeMap::new(),
};
let cap_id = scheme
.scheme_root()
.expect("failed to get this scheme root");
register_scheme_inner(&scheme.socket, &scheme.scheme_name, cap_id)
.expect("failed to register disk scheme root");
if let Some(daemon) = daemon {
daemon.ready();
}
scheme
}
pub fn event_handle(&self) -> &Fd {
@@ -358,7 +367,8 @@ impl<T: Disk> DiskScheme<T> {
// correctly ordered wrt IO on the same fd.
call_request.handle_async(self).await
}
RequestKind::SendFd(sendfd_request) => Response::err(EOPNOTSUPP, sendfd_request),
RequestKind::SendFd(request) => Response::err(EOPNOTSUPP, request),
RequestKind::RecvFd(request) => Response::err(EOPNOTSUPP, request),
RequestKind::Cancellation(_cancellation_request) => {
// FIXME implement cancellation
continue;
@@ -410,7 +420,27 @@ impl<T: Disk> DiskScheme<T> {
}
impl<T: Disk> SchemeAsync for DiskScheme<T> {
async fn open(&mut self, path_str: &str, flags: usize, ctx: &CallerCtx) -> Result<OpenResult> {
fn scheme_root(&mut self) -> Result<usize> {
let id = self.next_id;
self.next_id += 1;
self.handles.insert(id, Handle::SchemeRoot);
Ok(id)
}
async fn openat(
&mut self,
dirfd: usize,
path_str: &str,
flags: usize,
_fcntl_flags: u32,
ctx: &CallerCtx,
) -> Result<OpenResult> {
if !matches!(
self.handles.get(&dirfd).ok_or(Error::new(EBADF))?,
Handle::SchemeRoot
) {
return Err(Error::new(EACCES));
}
if ctx.uid != 0 {
return Err(Error::new(EACCES));
}
@@ -522,6 +552,7 @@ impl<T: Disk> SchemeAsync for DiskScheme<T> {
stat.st_blksize = disk.block_size();
Ok(())
}
Handle::SchemeRoot => Err(Error::new(EBADF)),
}
}
@@ -566,6 +597,7 @@ impl<T: Disk> SchemeAsync for DiskScheme<T> {
j += 1;
}
}
Handle::SchemeRoot => return Err(Error::new(EBADF)),
}
Ok(i)
@@ -599,6 +631,7 @@ impl<T: Disk> SchemeAsync for DiskScheme<T> {
let block = offset / u64::from(disk.block_size());
disk.read(Some(part_num as usize), block, buf).await
}
Handle::SchemeRoot => Err(Error::new(EBADF)),
}
}
@@ -622,6 +655,7 @@ impl<T: Disk> SchemeAsync for DiskScheme<T> {
let block = offset / u64::from(disk.block_size());
disk.write(Some(part_num as usize), block, buf).await
}
Handle::SchemeRoot => Err(Error::new(EBADF)),
}
}
@@ -644,6 +678,7 @@ impl<T: Disk> SchemeAsync for DiskScheme<T> {
part.size * u64::from(disk.block_size())
}
Handle::SchemeRoot => return Err(Error::new(EBADF)),
})
}
}
+1
View File
@@ -20,6 +20,7 @@ use crate::ide::{AtaCommand, AtaDisk, Channel};
pub mod ide;
fn main() {
common::init();
pcid_interface::pci_daemon(daemon);
}
+1
View File
@@ -57,6 +57,7 @@ fn time_arm(time_handle: &mut File, secs: i64) -> io::Result<()> {
}
fn main() {
common::init();
pcid_interface::pci_daemon(daemon);
}
+5 -4
View File
@@ -39,10 +39,8 @@ fn daemon(daemon: daemon::Daemon) -> ! {
let disk_scheme_name = format!("disk.usb-{scheme}+{port}-scsi");
// TODO: Use eventfds.
let handle = XhciClientHandle::new(scheme.to_owned(), port);
// FIXME should this wait notifying readiness until the disk scheme is created?
daemon.ready();
let handle =
XhciClientHandle::new(scheme.to_owned(), port).expect("Faild to open XhciClientHandle");
let desc = handle
.get_standard_descs()
@@ -110,6 +108,9 @@ fn daemon(daemon: daemon::Daemon) -> ! {
&driver_block::FuturesExecutor,
);
// FIXME should this wait notifying readiness until the disk scheme is created?
daemon.ready();
//libredox::call::setrens(0, 0).expect("nvmed: failed to enter null namespace");
event_queue
+1
View File
@@ -9,3 +9,4 @@ edition = "2018"
[dependencies]
clap = "2.33"
xhcid = { path = "../xhcid" }
common = { path = "../../common" }
+3 -1
View File
@@ -2,6 +2,7 @@ use clap::{App, Arg};
use xhcid_interface::{PortId, XhciClientHandle};
fn main() {
common::init();
let matches = App::new("usbctl")
.arg(
Arg::with_name("SCHEME")
@@ -35,7 +36,8 @@ fn main() {
.parse::<PortId>()
.expect("expected PORT ID");
let handle = XhciClientHandle::new(scheme.to_owned(), port);
let handle =
XhciClientHandle::new(scheme.to_owned(), port).expect("Faild to open XhciClientHandle");
if let Some(_status_scmd_matches) = port_scmd_matches.subcommand_matches("status") {
let state = handle.port_state().expect("Failed to get port state");
+5 -2
View File
@@ -6,6 +6,7 @@ use xhcid_interface::{
};
fn main() {
common::init();
let mut args = env::args().skip(1);
const USAGE: &'static str = "usbhubd <scheme> <port> <interface>";
@@ -38,7 +39,8 @@ fn main() {
common::file_level(),
);
let handle = XhciClientHandle::new(scheme.clone(), port_id);
let handle =
XhciClientHandle::new(scheme.clone(), port_id).expect("Faild to open XhciClientHandle");
let desc: DevDesc = handle
.get_standard_descs()
.expect("Failed to get standard descriptors");
@@ -146,7 +148,8 @@ fn main() {
} else {
usb::HubPortStatus::V2(usb::HubPortStatusV2::default())
},
handle: XhciClientHandle::new(scheme.clone(), child_port_id),
handle: XhciClientHandle::new(scheme.clone(), child_port_id)
.expect("Faild to open XhciClientHandle"),
attached: false,
});
}
+50 -27
View File
@@ -2,9 +2,11 @@ pub extern crate serde;
pub extern crate smallvec;
use std::convert::TryFrom;
use std::fs::{File, OpenOptions};
use std::fs::File;
use std::io::prelude::*;
use std::num::NonZeroU8;
use std::os::fd::{FromRawFd, RawFd};
use std::string::FromUtf8Error;
use std::{fmt, io, result, str};
use serde::{Deserialize, Serialize};
@@ -392,11 +394,20 @@ impl str::FromStr for PortId {
}
}
#[derive(Debug)]
pub struct XhciClientHandle {
fd: libredox::Fd,
scheme: String,
port: PortId,
}
impl fmt::Debug for XhciClientHandle {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.debug_struct("XhciClientHandle")
.field("scheme", &self.scheme)
.field("port", &self.port)
.field("fd", &"libredox::Fd")
.finish()
}
}
#[repr(u8)]
#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)]
pub enum PortState {
@@ -522,34 +533,43 @@ impl DeviceReqData<'_> {
}
impl XhciClientHandle {
pub fn new(scheme: String, port: PortId) -> Self {
Self { scheme, port }
pub fn new(scheme: String, port: PortId) -> result::Result<Self, XhciClientHandleError> {
let path = format!("/scheme/{}/port{}", scheme, port);
let fd = libredox::Fd::open(&path, libredox::flag::O_DIRECTORY, 0)?;
Ok(Self { fd, scheme, port })
}
fn read(&self, path: &str) -> result::Result<Vec<u8>, XhciClientHandleError> {
let target_fd = self.fd.openat(path, libredox::flag::O_RDONLY, 0)?;
let stat = target_fd.stat()?;
let mut buf: Vec<u8> = vec![0u8; stat.st_size as usize];
let count = target_fd.read(&mut buf)?;
buf.truncate(count);
Ok(buf)
}
fn read_to_string(&self, path: &str) -> result::Result<String, XhciClientHandleError> {
let buf = self.read(path)?;
Ok(String::from_utf8(buf)?)
}
pub fn attach(&self) -> result::Result<(), XhciClientHandleError> {
let path = format!("/scheme/{}/port{}/attach", self.scheme, self.port);
let mut file = OpenOptions::new().read(false).write(true).open(path)?;
let mut file = self.fd.openat("attach", libredox::flag::O_WRONLY, 0)?;
let _bytes_written = file.write(&[])?;
Ok(())
}
pub fn detach(&self) -> result::Result<(), XhciClientHandleError> {
let path = format!("/scheme/{}/port{}/detach", self.scheme, self.port);
let mut file = OpenOptions::new().read(false).write(true).open(path)?;
let mut file = self.fd.openat("detach", libredox::flag::O_WRONLY, 0)?;
let _bytes_written = file.write(&[])?;
Ok(())
}
pub fn get_standard_descs(&self) -> result::Result<DevDesc, XhciClientHandleError> {
let path = format!("/scheme/{}/port{}/descriptors", self.scheme, self.port);
let json = std::fs::read(path)?;
let json = self.read("descriptors")?;
Ok(serde_json::from_slice(&json)?)
}
pub fn configure_endpoints(
&self,
req: &ConfigureEndpointsReq,
) -> result::Result<(), XhciClientHandleError> {
let path = format!("/scheme/{}/port{}/configure", self.scheme, self.port);
let json = serde_json::to_vec(req)?;
let mut file = OpenOptions::new().read(false).write(true).open(path)?;
let mut file = self.fd.openat("configure", libredox::flag::O_WRONLY, 0)?;
let json_bytes_written = file.write(&json)?;
if json_bytes_written != json.len() {
return Err(XhciClientHandleError::InvalidResponse(Invalid(
@@ -559,23 +579,18 @@ impl XhciClientHandle {
Ok(())
}
pub fn port_state(&self) -> result::Result<PortState, XhciClientHandleError> {
let path = format!("/scheme/{}/port{}/state", self.scheme, self.port);
let string = std::fs::read_to_string(path)?;
let string = self.read_to_string("state")?;
Ok(string.parse()?)
}
pub fn open_endpoint_ctl(&self, num: u8) -> result::Result<File, XhciClientHandleError> {
let path = format!(
"/scheme/{}/port{}/endpoints/{}/ctl",
self.scheme, self.port, num
);
Ok(File::open(path)?)
let path = format!("endpoints/{}/ctl", num);
let fd = self.fd.openat(&path, libredox::flag::O_RDWR, 0)?;
Ok(unsafe { File::from_raw_fd(fd.into_raw() as RawFd) })
}
pub fn open_endpoint_data(&self, num: u8) -> result::Result<File, XhciClientHandleError> {
let path = format!(
"/scheme/{}/port{}/endpoints/{}/data",
self.scheme, self.port, num
);
Ok(File::open(path)?)
let path = format!("endpoints/{}/data", num);
let fd = self.fd.openat(&path, libredox::flag::O_RDWR, 0)?;
Ok(unsafe { File::from_raw_fd(fd.into_raw() as RawFd) })
}
pub fn open_endpoint(&self, num: u8) -> result::Result<XhciEndpHandle, XhciClientHandleError> {
Ok(XhciEndpHandle {
@@ -607,8 +622,7 @@ impl XhciClientHandle {
};
let json = serde_json::to_vec(&req)?;
let path = format!("/scheme/{}/port{}/request", self.scheme, self.port);
let mut file = File::open(path)?;
let file = self.fd.openat("request", libredox::flag::O_RDWR, 0)?;
let json_bytes_written = file.write(&json)?;
if json_bytes_written != json.len() {
@@ -863,4 +877,13 @@ pub enum XhciClientHandleError {
#[error("unexpected short packet of size {0}")]
UnexpectedShortPacket(usize),
#[error("utf8 error: {0}")]
Utf8Error(#[from] FromUtf8Error),
}
impl From<libredox::error::Error> for XhciClientHandleError {
fn from(error: libredox::error::Error) -> Self {
Self::IoError(error.into())
}
}
+8 -5
View File
@@ -37,7 +37,7 @@ use pcid_interface::irq_helpers::{
};
use pcid_interface::{PciFeature, PciFeatureInfo, PciFunctionHandle};
use redox_scheme::{RequestKind, SignalBehavior, Socket};
use redox_scheme::{scheme::register_sync_scheme, RequestKind, SignalBehavior, Socket};
use crate::xhci::{InterruptMethod, Xhci};
@@ -143,14 +143,16 @@ fn daemon_with_context_size<const N: usize>(
log::info!("XHCI {}", pci_config.func.display());
let scheme_name = format!("usb.{}", name);
let socket = Socket::create(scheme_name.clone()).expect("xhcid: failed to create usb scheme");
daemon.ready();
let socket = Socket::create().expect("xhcid: failed to create usb scheme");
let hci = Arc::new(
Xhci::<N>::new(scheme_name, address, interrupt_method, pcid_handle)
Xhci::<N>::new(scheme_name.clone(), address, interrupt_method, pcid_handle)
.expect("xhcid: failed to allocate device"),
);
register_sync_scheme(&socket, &scheme_name, &mut &*hci)
.expect("xhcid: failed to regsiter scheme to namespace");
daemon.ready();
xhci::start_irq_reactor(&hci, irq_file);
xhci::start_device_enumerator(&hci);
@@ -182,6 +184,7 @@ fn daemon_with_context_size<const N: usize>(
}
fn main() {
common::init();
pcid_interface::pci_daemon(daemon);
}
+39 -3
View File
@@ -75,6 +75,8 @@ lazy_static! {
r"port([\d\.]+)/endpoints/(\d{1,3})/(ctl|data)$"
)
.expect("Failed to create the regex for the port<n>/endpoints/<n>/<sub_endpoint> scheme");
static ref REGEX_PORT_ROOT: Regex =
Regex::new(r"^port([\d\.]+)$").expect("Failed to create the regex for the port<n> scheme.");
static ref REGEX_TOP_LEVEL: Regex =
Regex::new(r"^$").expect("Failed to create the regex for the top-level scheme");
}
@@ -141,6 +143,7 @@ pub enum Handle {
ConfigureEndpoints(PortId), // port
AttachDevice(PortId), // port
DetachDevice(PortId), // port
SchemeRoot,
}
/// The type of handle.
@@ -232,6 +235,7 @@ impl Handle {
Handle::DetachDevice(port_num) => {
format!("port{}/detach", port_num)
}
Handle::SchemeRoot => String::from(""),
}
}
@@ -263,6 +267,7 @@ impl Handle {
EndpointHandleTy::Ctl => HandleType::Character,
EndpointHandleTy::Root(_) => HandleType::Directory,
},
&Handle::SchemeRoot => HandleType::Directory,
}
}
@@ -293,6 +298,7 @@ impl Handle {
EndpointHandleTy::Ctl => None,
EndpointHandleTy::Root(ref buf) => Some(buf.len()),
},
&Handle::SchemeRoot => None,
}
}
}
@@ -404,6 +410,9 @@ impl SchemeParameters {
let handle_type = get_string_from_regex(&REGEX_PORT_SUB_ENDPOINT, scheme, 2)?;
Ok(Self::Endpoint(port_num, endpoint_num, handle_type))
} else if REGEX_PORT_ROOT.is_match(scheme) {
let port_num = get_port_id_from_regex(&REGEX_PORT_ROOT, scheme, 0)?;
Ok(Self::Port(port_num))
} else if REGEX_TOP_LEVEL.is_match(scheme) {
Ok(Self::TopLevel)
} else {
@@ -2099,7 +2108,31 @@ impl<const N: usize> Xhci<N> {
}
impl<const N: usize> SchemeSync for &Xhci<N> {
fn open(&mut self, path_str: &str, flags: usize, ctx: &CallerCtx) -> Result<OpenResult> {
fn scheme_root(&mut self) -> Result<usize> {
let fd = self.next_handle.fetch_add(1, atomic::Ordering::Relaxed);
self.handles.insert(fd, Handle::SchemeRoot);
Ok(fd)
}
fn openat(
&mut self,
dirfd: usize,
path_str: &str,
mut flags: usize,
fcntl_flags: u32,
ctx: &CallerCtx,
) -> Result<OpenResult> {
let full_path = match *self.handles.get(&dirfd).ok_or(Error::new(EBADF))? {
Handle::SchemeRoot => path_str.trim_start_matches('/').to_string(),
Handle::Port(port_num, _) => {
let clean_path = path_str.trim_start_matches('/');
if clean_path.is_empty() {
format!("port{}", port_num)
} else {
format!("port{}/{}", port_num, clean_path)
}
}
_ => return Err(Error::new(EACCES)),
};
if ctx.uid != 0 {
return Err(Error::new(EACCES));
}
@@ -2107,7 +2140,9 @@ impl<const N: usize> SchemeSync for &Xhci<N> {
//Parse the scheme, determine if it's in the valid format, return an error if not.
//This doesn't guarantee that the parameters themselves are valid (i.e. bounded correctly)
//only that the scheme itself was parseable.
let scheme_parameters = SchemeParameters::from_scheme(path_str)?;
let scheme_parameters = SchemeParameters::from_scheme(&full_path)?;
flags |= fcntl_flags as usize;
//Once we have our scheme parsed into parameters, we can match on those parameters to
//find the correct routine to open a handle
@@ -2142,7 +2177,7 @@ impl<const N: usize> SchemeSync for &Xhci<N> {
let fd = self.next_handle.fetch_add(1, atomic::Ordering::Relaxed);
trace!("OPENED {} to FD={}, handle: {:?}", path_str, fd, handle);
trace!("OPENED {} to FD={}, handle: {:?}", full_path, fd, handle);
self.handles.insert(fd, handle);
@@ -2228,6 +2263,7 @@ impl<const N: usize> SchemeSync for &Xhci<N> {
Handle::ConfigureEndpoints(_) => Err(Error::new(EBADF)),
Handle::AttachDevice(_) => Err(Error::new(EBADF)),
Handle::DetachDevice(_) => Err(Error::new(EBADF)),
Handle::SchemeRoot => Err(Error::new(EBADF)),
&mut Handle::Endpoint(port_num, endp_num, ref mut st) => match st {
EndpointHandleTy::Ctl => self.on_read_endp_ctl(port_num, endp_num, buf),
+1
View File
@@ -190,6 +190,7 @@ impl VboxGuestInfo {
}
fn main() {
common::init();
pcid_interface::pci_daemon(daemon);
}
+56 -11
View File
@@ -19,6 +19,7 @@ pub struct Listener {
pub enum Extra {
Client(Client),
Listener(Listener),
SchemeRoot,
}
impl Default for Extra {
fn default() -> Self {
@@ -115,16 +116,8 @@ impl<'sock> ChanScheme<'sock> {
Err(err) => Err(err), // Error writing response
}
}
}
impl<'sock> SchemeSync for ChanScheme<'sock> {
// ___ ____ _____ _ _
// / _ \| _ \| ____| \ | |
// | | | | |_) | _| | \| |
// | |_| | __/| |___| |\ |
// \___/|_| |_____|_| \_|
fn open(&mut self, path: &str, flags: usize, _ctx: &CallerCtx) -> Result<OpenResult> {
fn open(&mut self, path: &str, flags: usize) -> Result<OpenResult> {
let new_id = self.next_id;
let mut new = Handle::default();
new.flags = flags;
@@ -164,7 +157,45 @@ impl<'sock> SchemeSync for ChanScheme<'sock> {
flags: NewFdFlags::empty(),
})
}
fn dup(&mut self, id: usize, buf: &[u8], ctx: &CallerCtx) -> Result<OpenResult> {
}
impl<'sock> SchemeSync for ChanScheme<'sock> {
fn scheme_root(&mut self) -> Result<usize> {
let id = self.next_id;
self.next_id += 1;
self.handles.insert(
id,
Handle {
flags: 0,
extra: Extra::SchemeRoot,
path: None,
},
);
Ok(id)
}
// ___ ____ _____ _ _
// / _ \| _ \| ____| \ | |
// | | | | |_) | _| | \| |
// | |_| | __/| |___| |\ |
// \___/|_| |_____|_| \_|
fn openat(
&mut self,
dirfd: usize,
path: &str,
flags: usize,
_fcntl_flags: u32,
_ctx: &CallerCtx,
) -> Result<OpenResult> {
let handle = self.handles.get(&dirfd).ok_or(Error::new(EBADF))?;
if !matches!(handle.extra, Extra::SchemeRoot) {
return Err(Error::new(EACCES));
}
self.open(path, flags)
}
fn dup(&mut self, id: usize, buf: &[u8], _ctx: &CallerCtx) -> Result<OpenResult> {
match buf {
b"listen" => {
loop {
@@ -190,6 +221,7 @@ impl<'sock> SchemeSync for ChanScheme<'sock> {
Extra::Listener(_) => {
panic!("newly created handle can't possibly be a listener")
}
Extra::SchemeRoot => return Err(Error::new(EBADF)),
}
self.post_fevent(remote_id, EVENT_WRITE.bits())?;
@@ -245,8 +277,12 @@ impl<'sock> SchemeSync for ChanScheme<'sock> {
return Err(Error::new(EBADF));
}
if matches!(handle.extra, Extra::SchemeRoot) {
return Err(Error::new(EBADF));
}
let flags = handle.flags;
return self.open(path, flags, ctx);
return self.open(path, flags);
}
}
}
@@ -283,6 +319,7 @@ impl<'sock> SchemeSync for ChanScheme<'sock> {
Extra::Listener(_) => {
panic!("somehow, a client was connected to a listener directly")
}
Extra::SchemeRoot => panic!("somehow, a client was connected to a SchemeRoot"),
}
} else if client.remote == Connection::Closed {
Err(Error::new(EPIPE))
@@ -303,6 +340,9 @@ impl<'sock> SchemeSync for ChanScheme<'sock> {
// Write path
let handle = self.handles.get(&id).ok_or(Error::new(EBADF))?;
if let Extra::SchemeRoot = handle.extra {
return Ok(len);
}
let path = handle.path.as_ref().ok_or(Error::new(EBADF))?;
let len = cmp::min(path.len(), buf.len() - PREFIX.len());
buf[PREFIX.len()..][..len].copy_from_slice(&path.as_bytes()[..len]);
@@ -358,6 +398,9 @@ impl<'sock> SchemeSync for ChanScheme<'sock> {
}
}
Extra::Listener(_) => panic!("a client can't be connected to a listener!"),
Extra::SchemeRoot => {
panic!("a client can't be connected to a scheme root!")
}
}
}
}
@@ -366,6 +409,7 @@ impl<'sock> SchemeSync for ChanScheme<'sock> {
self.listeners.remove(&path);
}
}
Extra::SchemeRoot => {}
}
}
@@ -403,6 +447,7 @@ impl<'sock> SchemeSync for ChanScheme<'sock> {
events |= EVENT_READ | EVENT_WRITE;
}
}
Extra::SchemeRoot => {}
}
Ok(events)
}
+28 -6
View File
@@ -1,5 +1,5 @@
use event::{EventFlags, EventQueue};
use redox_scheme::{wrappers::ReadinessBased, Socket};
use redox_scheme::{scheme::register_sync_scheme, wrappers::ReadinessBased, Socket};
use std::sync::Mutex;
mod chan;
@@ -37,19 +37,19 @@ fn inner(daemon: daemon::Daemon) -> anyhow::Result<()> {
}
// Prepare chan scheme
let chan_socket = Socket::nonblock("chan")
.map_err(|e| anyhow::anyhow!("failed to create chan scheme: {e}"))?;
let chan_socket =
Socket::nonblock().map_err(|e| anyhow::anyhow!("failed to create chan scheme: {e}"))?;
let chan = Mutex::new(ChanScheme::new(&chan_socket));
let mut chan_handler = ReadinessBased::new(&chan_socket, 16);
// Prepare shm scheme
let shm_socket =
Socket::nonblock("shm").map_err(|e| anyhow::anyhow!("failed to create shm socket: {e}"))?;
Socket::nonblock().map_err(|e| anyhow::anyhow!("failed to create shm socket: {e}"))?;
let shm = Mutex::new(ShmScheme::new());
let mut shm_handler = ReadinessBased::new(&shm_socket, 16);
// Prepare uds stream scheme
let uds_stream_socket = Socket::nonblock("uds_stream")
let uds_stream_socket = Socket::nonblock()
.map_err(|e| anyhow::anyhow!("failed to create uds stream scheme: {e}"))?;
let uds_stream = Mutex::new(
UdsStreamScheme::new(&uds_stream_socket)
@@ -58,7 +58,7 @@ fn inner(daemon: daemon::Daemon) -> anyhow::Result<()> {
let mut uds_stream_handler = ReadinessBased::new(&uds_stream_socket, 16);
// Prepare uds dgram scheme
let uds_dgram_socket = Socket::nonblock("uds_dgram")
let uds_dgram_socket = Socket::nonblock()
.map_err(|e| anyhow::anyhow!("failed to create uds dgram scheme: {e}"))?;
let uds_dgram = Mutex::new(
UdsDgramScheme::new(&uds_dgram_socket)
@@ -66,6 +66,28 @@ fn inner(daemon: daemon::Daemon) -> anyhow::Result<()> {
);
let mut uds_dgram_handler = ReadinessBased::new(&uds_dgram_socket, 16);
{
let mut chan_guard = chan.lock().unwrap();
register_sync_scheme(&chan_socket, "chan", &mut *chan_guard)
.map_err(|e| anyhow::anyhow!("failed to register chan scheme: {e}"))?;
}
{
let mut shm_guard = shm.lock().unwrap();
register_sync_scheme(&shm_socket, "shm", &mut *shm_guard)
.map_err(|e| anyhow::anyhow!("failed to register shm scheme: {e}"))?;
}
{
let mut uds_stream_guard = uds_stream.lock().unwrap();
register_sync_scheme(&uds_stream_socket, "uds_stream", &mut *uds_stream_guard)
.map_err(|e| anyhow::anyhow!("failed to register uds stream scheme: {e}"))?;
}
{
let mut uds_dgram_guard = uds_dgram.lock().unwrap();
// Register schemes to namespace
register_sync_scheme(&uds_dgram_socket, "uds_dgram", &mut *uds_dgram_guard)
.map_err(|e| anyhow::anyhow!("failed to register uds dgram scheme: {e}"))?;
}
daemon.ready();
// Create event listener for both files
+19 -11
View File
@@ -47,19 +47,27 @@ impl ShmScheme {
}
impl SchemeSync for ShmScheme {
fn scheme_root(&mut self) -> Result<usize> {
let id = self.next_id;
self.next_id += 1;
self.handles.insert(id, Handle::SchemeRoot);
Ok(id)
}
//FIXME: Handle O_RDONLY/O_WRONLY/O_RDWR
fn open(&mut self, path: &str, flags: usize, _ctx: &CallerCtx) -> Result<OpenResult> {
if path.is_empty() {
let id = self.next_id;
self.next_id += 1;
self.handles.insert(id, Handle::SchemeRoot);
return Ok(OpenResult::ThisScheme {
number: id,
flags: NewFdFlags::empty(),
});
fn openat(
&mut self,
dirfd: usize,
path: &str,
flags: usize,
_fcntl_flags: u32,
_ctx: &CallerCtx,
) -> Result<OpenResult> {
let handle = self.handles.get(&dirfd).ok_or(Error::new(EBADF))?;
if !matches!(handle, Handle::SchemeRoot) {
return Err(Error::new(EACCES));
}
let path = Rc::from(path);
let entry = match self.maps.entry(Rc::clone(&path)) {
Entry::Occupied(e) => {
+118 -51
View File
@@ -22,6 +22,44 @@ use std::{
};
use syscall::{error::*, flag::*, schemev2::NewFdFlags, Error, FobtainFdFlags, Stat};
#[derive(Debug, Default)]
pub struct Socket {
primary_id: usize,
path: Option<String>,
state: State,
peer: Option<usize>,
messages: VecDeque<DataPacket>,
options: HashSet<i32>,
fds: VecDeque<usize>,
flags: usize,
issued_token: Option<u64>,
}
impl Socket {
fn drop_fds(&mut self, num_fd: usize) -> Result<()> {
for i in 0..num_fd {
if self.fds.pop_front().is_none() {
eprintln!("Socket::drop_fds: Attempted to drop FD #{} of {}, but fd queue is empty. State inconsistency.", i + 1, num_fd);
return Err(Error::new(EINVAL));
}
}
Ok(())
}
}
#[derive(Debug, Clone, PartialEq, Eq)]
pub enum State {
Unbound,
Bound,
Closed,
}
impl Default for State {
fn default() -> Self {
Self::Unbound
}
}
impl DataPacket {
pub fn serialize_to_stream(
self,
@@ -70,46 +108,26 @@ impl DataPacket {
}
}
#[derive(Debug, Clone, PartialEq, Eq)]
pub enum State {
Unbound,
Bound,
Closed,
enum Handle {
Socket(Rc<RefCell<Socket>>),
SchemeRoot,
}
impl Default for State {
fn default() -> Self {
Self::Unbound
}
}
#[derive(Debug, Default)]
pub struct Socket {
primary_id: usize,
path: Option<String>,
state: State,
peer: Option<usize>,
messages: VecDeque<DataPacket>,
options: HashSet<i32>,
fds: VecDeque<usize>,
flags: usize,
issued_token: Option<u64>,
}
impl Socket {
fn drop_fds(&mut self, num_fd: usize) -> Result<()> {
for i in 0..num_fd {
if self.fds.pop_front().is_none() {
eprintln!("Socket::drop_fds: Attempted to drop FD #{} of {}, but fd queue is empty. State inconsistency.", i + 1, num_fd);
return Err(Error::new(EINVAL));
}
impl Handle {
fn as_socket(&self) -> Option<&Rc<RefCell<Socket>>> {
if let Self::Socket(socket) = self {
Some(socket)
} else {
None
}
Ok(())
}
fn is_scheme_root(&self) -> bool {
matches!(self, Self::SchemeRoot)
}
}
pub struct UdsDgramScheme<'sock> {
sockets: HashMap<usize, Rc<RefCell<Socket>>>,
handles: HashMap<usize, Handle>,
next_id: usize,
socket_paths: HashMap<String, Rc<RefCell<Socket>>>,
socket_tokens: HashMap<u64, Rc<RefCell<Socket>>>,
@@ -121,15 +139,18 @@ pub struct UdsDgramScheme<'sock> {
impl<'sock> UdsDgramScheme<'sock> {
pub fn new(socket: &'sock SchemeSocket) -> Result<Self> {
Ok(Self {
sockets: HashMap::new(),
handles: HashMap::new(),
next_id: 0,
socket_paths: HashMap::new(),
socket_tokens: HashMap::new(),
socket,
proc_creds_capability: syscall::open(
"/scheme/proc/proc-creds-capability",
syscall::O_RDONLY,
)?,
proc_creds_capability: {
libredox::call::open(
"/scheme/proc/proc-creds-capability",
libredox::flag::O_RDONLY,
0,
)?
},
rng: SmallRng::from_entropy(),
})
}
@@ -147,7 +168,14 @@ impl<'sock> UdsDgramScheme<'sock> {
}
fn get_socket(&self, id: usize) -> Result<&Rc<RefCell<Socket>>, Error> {
self.sockets.get(&id).ok_or(Error::new(EBADF))
self.handles
.get(&id)
.and_then(Handle::as_socket)
.ok_or(Error::new(EBADF))
}
fn insert_socket(&mut self, id: usize, socket: Rc<RefCell<Socket>>) {
self.handles.insert(id, Handle::Socket(socket));
}
fn get_connected_peer(&self, id: usize) -> Result<(usize, Rc<RefCell<Socket>>), Error> {
@@ -177,7 +205,7 @@ impl<'sock> UdsDgramScheme<'sock> {
new.flags = flags;
new.primary_id = new_id;
self.sockets.insert(new_id, Rc::new(RefCell::new(new)));
self.insert_socket(new_id, Rc::new(RefCell::new(new)));
self.next_id += 1;
new_id
}
@@ -473,7 +501,7 @@ impl<'sock> UdsDgramScheme<'sock> {
// why not)
self.post_fevent(id, (EVENT_READ | EVENT_WRITE).bits())?;
self.sockets.insert(new_id, Rc::new(RefCell::new(new)));
self.insert_socket(new_id, Rc::new(RefCell::new(new)));
self.next_id += 1;
@@ -496,7 +524,7 @@ impl<'sock> UdsDgramScheme<'sock> {
let new_id = self.next_id;
self.sockets.insert(new_id, socket_rc.clone());
self.insert_socket(new_id, socket_rc.clone());
self.next_id += 1;
Ok(OpenResult::ThisScheme {
@@ -625,9 +653,45 @@ impl<'sock> UdsDgramScheme<'sock> {
}
impl<'sock> SchemeSync for UdsDgramScheme<'sock> {
fn open(&mut self, path: &str, flags: usize, _ctx: &CallerCtx) -> Result<OpenResult> {
fn scheme_root(&mut self) -> Result<usize> {
let new_id = self.next_id;
self.handles.insert(new_id, Handle::SchemeRoot);
self.next_id += 1;
Ok(new_id)
}
fn openat(
&mut self,
fd: usize,
path: &str,
mut flags: usize,
fcntl_flags: u32,
_ctx: &CallerCtx,
) -> Result<OpenResult> {
{
let Some(handle) = self.handles.get(&fd) else {
return Err(Error::new(EBADF));
};
if !handle.is_scheme_root() {
eprintln!(
"openat(fd: {}, path: '{}'): fd is not an open capability.",
fd, path
);
return Err(Error::new(EACCES));
}
}
flags |= fcntl_flags as usize;
let new_id = if path.is_empty() {
self.handle_unnamed_socket(flags)
if flags & O_CREAT == O_CREAT {
self.handle_unnamed_socket(flags)
} else {
eprintln!(
"open(path: '{}'): Attempting to open an unnamed socket without O_CREAT.",
path
);
return Err(Error::new(EINVAL));
}
} else {
eprintln!(
"open(path: '{}'): Attempting to open a named socket, which is not supported.",
@@ -674,12 +738,15 @@ impl<'sock> SchemeSync for UdsDgramScheme<'sock> {
}
fn fpath(&mut self, id: usize, buf: &mut [u8], _ctx: &CallerCtx) -> Result<usize> {
let socket_rc = self.get_socket(id)?;
let socket = socket_rc.borrow();
let empty = String::new();
let path = socket.path.as_ref().unwrap_or(&empty);
Ok(Self::fpath_inner(path, buf)?)
match self.handles.get(&id).ok_or(Error::new(EBADF))? {
Handle::SchemeRoot => Ok(Self::fpath_inner(&String::new(), buf)?),
Handle::Socket(socket_rc) => {
let socket = socket_rc.borrow();
let empty = String::new();
let path = socket.path.as_ref().unwrap_or(&empty);
Ok(Self::fpath_inner(path, buf)?)
}
}
}
fn fsync(&mut self, id: usize, _ctx: &CallerCtx) -> Result<()> {
@@ -698,7 +765,7 @@ impl<'sock> SchemeSync for UdsDgramScheme<'sock> {
}
fn on_close(&mut self, id: usize) {
let Some(socket_rc) = self.sockets.remove(&id) else {
let Some(Handle::Socket(socket_rc)) = self.handles.remove(&id) else {
return;
};
let mut socket = socket_rc.borrow_mut();
+30 -67
View File
@@ -1,4 +1,5 @@
use redox_rt::protocol::ProcMeta;
use std::fmt::Debug;
use std::{cmp, convert::TryInto, mem};
use syscall::{error::*, Error};
@@ -143,79 +144,41 @@ impl DataPacket {
}
}
trait NumFromBytes: Sized + Debug {
fn from_le_bytes_slice(buffer: &[u8]) -> Result<Self, Error>;
}
macro_rules! num_from_bytes_impl {
($($t:ty),*) => {
$(
impl NumFromBytes for $t {
fn from_le_bytes_slice(buffer: &[u8]) -> Result<Self, Error> {
let size = mem::size_of::<Self>();
let buffer_slice = buffer.get(..size).and_then(|s| s.try_into().ok());
if let Some(slice) = buffer_slice {
Ok(Self::from_le_bytes(slice))
} else {
eprintln!(
"read_num: buffer is too short to read num of size {} (buffer len: {})",
size, buffer.len()
);
Err(Error::new(EINVAL))
}
}
}
)*
};
}
num_from_bytes_impl!(i32, u32, u64, usize);
fn read_num<T>(buffer: &[u8]) -> Result<T, Error>
where
T: NumFromBytes,
{
T::from_le_bytes_slice(buffer)
}
trait NumFromBytes: Sized {
fn from_le_bytes_slice(buffer: &[u8]) -> Result<Self, Error>;
}
impl NumFromBytes for i32 {
fn from_le_bytes_slice(buffer: &[u8]) -> Result<Self> {
Ok(i32::from_le_bytes(
buffer
.get(..mem::size_of::<i32>())
.and_then(|slice| slice.try_into().ok())
.ok_or_else(|| {
eprintln!(
"read_num: buffer is too short to read num len: {}",
buffer.len()
);
Error::new(EINVAL)
})?,
))
}
}
impl NumFromBytes for u32 {
fn from_le_bytes_slice(buffer: &[u8]) -> Result<Self> {
Ok(u32::from_le_bytes(
buffer
.get(..mem::size_of::<u32>())
.and_then(|slice| slice.try_into().ok())
.ok_or_else(|| {
eprintln!(
"read_num: buffer is too short to read num len: {}",
buffer.len()
);
Error::new(EINVAL)
})?,
))
}
}
impl NumFromBytes for u64 {
fn from_le_bytes_slice(buffer: &[u8]) -> Result<Self> {
Ok(u64::from_le_bytes(
buffer
.get(..mem::size_of::<u64>())
.and_then(|slice| slice.try_into().ok())
.ok_or_else(|| {
eprintln!(
"read_num: buffer is too short to read num len: {}",
buffer.len()
);
Error::new(EINVAL)
})?,
))
}
}
impl NumFromBytes for usize {
fn from_le_bytes_slice(buffer: &[u8]) -> Result<Self> {
Ok(usize::from_le_bytes(
buffer
.get(..mem::size_of::<usize>())
.and_then(|slice| slice.try_into().ok())
.ok_or_else(|| {
eprintln!(
"read_num: buffer is too short to read num len: {}",
buffer.len()
);
Error::new(EINVAL)
})?,
))
}
}
fn get_uid_gid_from_pid(cap_fd: usize, target_pid: usize) -> Result<(u32, u32, u32)> {
let mut buffer = [0u8; mem::size_of::<ProcMeta>()];
+86 -18
View File
@@ -364,8 +364,26 @@ impl Socket {
}
}
enum Handle {
Socket(Rc<RefCell<Socket>>),
SchemeRoot,
}
impl Handle {
fn as_socket(&self) -> Option<&Rc<RefCell<Socket>>> {
if let Self::Socket(socket) = self {
Some(socket)
} else {
None
}
}
fn is_scheme_root(&self) -> bool {
matches!(self, Self::SchemeRoot)
}
}
pub struct UdsStreamScheme<'sock> {
sockets: HashMap<usize, Rc<RefCell<Socket>>>,
handles: HashMap<usize, Handle>,
next_id: usize,
socket_paths: HashMap<String, Rc<RefCell<Socket>>>,
socket_tokens: HashMap<u64, Rc<RefCell<Socket>>>,
@@ -377,15 +395,18 @@ pub struct UdsStreamScheme<'sock> {
impl<'sock> UdsStreamScheme<'sock> {
pub fn new(socket: &'sock SchemeSocket) -> Result<Self> {
Ok(Self {
sockets: HashMap::new(),
handles: HashMap::new(),
next_id: 0,
socket_paths: HashMap::new(),
socket_tokens: HashMap::new(),
socket,
proc_creds_capability: syscall::open(
"/scheme/proc/proc-creds-capability",
syscall::O_RDONLY,
)?,
proc_creds_capability: {
libredox::call::open(
"/scheme/proc/proc-creds-capability",
libredox::flag::O_RDONLY,
0,
)?
},
rng: SmallRng::from_entropy(),
})
}
@@ -409,7 +430,14 @@ impl<'sock> UdsStreamScheme<'sock> {
}
fn get_socket(&self, id: usize) -> Result<&Rc<RefCell<Socket>>, Error> {
self.sockets.get(&id).ok_or(Error::new(EBADF))
self.handles
.get(&id)
.and_then(Handle::as_socket)
.ok_or(Error::new(EBADF))
}
fn insert_socket(&mut self, id: usize, socket: Rc<RefCell<Socket>>) {
self.handles.insert(id, Handle::Socket(socket));
}
fn get_connected_peer(&self, id: usize) -> Result<(usize, Rc<RefCell<Socket>>), Error> {
@@ -443,7 +471,7 @@ impl<'sock> UdsStreamScheme<'sock> {
None,
ctx,
);
self.sockets.insert(new_id, Rc::new(RefCell::new(new)));
self.insert_socket(new_id, Rc::new(RefCell::new(new)));
self.next_id += 1;
new_id
}
@@ -850,7 +878,7 @@ impl<'sock> UdsStreamScheme<'sock> {
};
self.next_id += 1;
self.sockets.insert(new_id, Rc::new(RefCell::new(new)));
self.insert_socket(new_id, Rc::new(RefCell::new(new)));
self.post_fevent(client_id, EVENT_READ | EVENT_WRITE)?;
Ok(Some(OpenResult::ThisScheme {
number: new_id,
@@ -961,7 +989,7 @@ impl<'sock> UdsStreamScheme<'sock> {
// why not)
self.post_fevent(id, EVENT_READ | EVENT_WRITE)?;
self.sockets.insert(new_id, Rc::new(RefCell::new(new)));
self.insert_socket(new_id, Rc::new(RefCell::new(new)));
self.next_id += 1;
@@ -1195,9 +1223,45 @@ impl<'sock> UdsStreamScheme<'sock> {
}
impl<'sock> SchemeSync for UdsStreamScheme<'sock> {
fn open(&mut self, path: &str, flags: usize, ctx: &CallerCtx) -> Result<OpenResult> {
fn scheme_root(&mut self) -> Result<usize> {
let new_id = self.next_id;
self.handles.insert(new_id, Handle::SchemeRoot);
self.next_id += 1;
Ok(new_id)
}
fn openat(
&mut self,
fd: usize,
path: &str,
mut flags: usize,
fcntl_flags: u32,
ctx: &CallerCtx,
) -> Result<OpenResult> {
{
let Some(handle) = self.handles.get(&fd) else {
return Err(Error::new(EBADF));
};
if !handle.is_scheme_root() {
eprintln!(
"openat(fd: {}, path: '{}'): fd is not an open capability.",
fd, path
);
return Err(Error::new(EACCES));
}
}
flags |= fcntl_flags as usize;
let new_id = if path.is_empty() {
self.handle_unnamed_socket(flags, ctx)
if flags & O_CREAT == O_CREAT {
self.handle_unnamed_socket(flags, ctx)
} else {
eprintln!(
"open(path: '{}'): Attempting to open an unnamed socket without O_CREAT.",
path
);
return Err(Error::new(EINVAL));
}
} else {
eprintln!(
"open(path: '{}'): Attempting to open a named socket, which is not supported.",
@@ -1243,11 +1307,15 @@ impl<'sock> SchemeSync for UdsStreamScheme<'sock> {
}
fn fpath(&mut self, id: usize, buf: &mut [u8], _ctx: &CallerCtx) -> Result<usize> {
let socket_rc = self.get_socket(id)?;
let socket = socket_rc.borrow();
let empty = String::new();
let path = socket.path.as_ref().unwrap_or(&empty);
Ok(Self::fpath_inner(path, buf)?)
match self.handles.get(&id).ok_or(Error::new(EBADF))? {
Handle::SchemeRoot => Ok(Self::fpath_inner(&String::new(), buf)?),
Handle::Socket(socket_rc) => {
let socket = socket_rc.borrow();
let empty = String::new();
let path = socket.path.as_ref().unwrap_or(&empty);
Ok(Self::fpath_inner(path, buf)?)
}
}
}
fn fsync(&mut self, id: usize, _ctx: &CallerCtx) -> Result<()> {
@@ -1288,7 +1356,7 @@ impl<'sock> SchemeSync for UdsStreamScheme<'sock> {
}
fn on_close(&mut self, id: usize) {
let Some(socket_rc) = self.sockets.remove(&id) else {
let Some(Handle::Socket(socket_rc)) = self.handles.remove(&id) else {
return;
};
+20 -4
View File
@@ -1,4 +1,7 @@
use redox_scheme::{RequestKind, SignalBehavior, Socket};
use redox_scheme::{
scheme::{register_sync_scheme, SchemeSync},
RequestKind, Response, SignalBehavior, Socket,
};
use std::process;
use crate::scheme::LogScheme;
@@ -6,12 +9,17 @@ use crate::scheme::LogScheme;
mod scheme;
fn daemon(daemon: daemon::Daemon) -> ! {
let socket = Socket::create("log").expect("logd: failed to create log scheme");
let socket = Socket::create().expect("logd: failed to create log scheme");
let mut scheme = LogScheme::new(&socket);
register_sync_scheme(&socket, "log", &mut scheme)
.expect("logd: failed to register scheme to namespace");
libredox::call::setrens(0, 0).expect("logd: failed to enter null namespace");
daemon.ready();
let mut scheme = LogScheme::new();
while let Some(request) = socket
.next_request(SignalBehavior::Restart)
.expect("logd: failed to read events from log scheme")
@@ -22,6 +30,14 @@ fn daemon(daemon: daemon::Daemon) -> ! {
scheme.on_close(id);
continue;
}
RequestKind::SendFd(sendfd_request) => {
let result = scheme.on_sendfd(&sendfd_request);
let resp = Response::new(result, sendfd_request);
socket
.write_response(resp, SignalBehavior::Restart)
.expect("logd: failed to write responses to log scheme");
continue;
}
_ => continue,
};
+67 -36
View File
@@ -2,11 +2,12 @@ use std::collections::{BTreeMap, VecDeque};
use std::fs::{File, OpenOptions};
use std::io::{Read, Write};
use std::mem;
use std::os::fd::{FromRawFd, RawFd};
use std::path::PathBuf;
use std::sync::mpsc::{self, Sender};
use redox_scheme::scheme::SchemeSync;
use redox_scheme::{CallerCtx, OpenResult};
use redox_scheme::{CallerCtx, OpenResult, SendFdRequest, Socket};
use syscall::error::*;
use syscall::schemev2::NewFdFlags;
@@ -16,10 +17,12 @@ pub enum LogHandle {
bufs: BTreeMap<usize, Vec<u8>>,
},
AddSink,
SchemeRoot,
}
pub struct LogScheme {
pub struct LogScheme<'sock> {
next_id: usize,
socket: &'sock Socket,
output_tx: Sender<OutputCmd>,
handles: BTreeMap<usize, LogHandle>,
}
@@ -28,16 +31,18 @@ enum OutputCmd {
Log(Vec<u8>),
/// Log a message from the kernel. This skips writing it back to the kernel debug output.
LogKernel(Vec<u8>),
AddSink(PathBuf),
AddSink(usize),
}
impl LogScheme {
pub fn new() -> Self {
impl<'sock> LogScheme<'sock> {
pub fn new(socket: &'sock Socket) -> Self {
let mut kernel_debug = OpenOptions::new()
.write(true)
.open("/scheme/debug")
.unwrap();
let mut kernel_sys_log = std::fs::File::open("/scheme/sys/log").unwrap();
let (output_tx, output_rx) = mpsc::channel::<OutputCmd>();
std::thread::spawn(move || {
@@ -69,20 +74,14 @@ impl LogScheme {
logs.pop_front();
}
}
OutputCmd::AddSink(sink_path) => {
match OpenOptions::new().write(true).open(&sink_path) {
Ok(mut file) => {
for line in &logs {
let _ = file.write(line);
let _ = file.flush();
}
files.push(file)
}
Err(err) => {
eprintln!("logd: failed to open {:?}: {:?}", sink_path, err)
}
OutputCmd::AddSink(log_fd) => {
let mut file = unsafe { File::from_raw_fd(log_fd as RawFd) };
for line in &logs {
let _ = file.write(line);
let _ = file.flush();
}
files.push(file)
}
}
}
@@ -90,12 +89,11 @@ impl LogScheme {
let output_tx2 = output_tx.clone();
std::thread::spawn(move || {
let mut debug_file = std::fs::File::open("/scheme/sys/log").unwrap();
let mut handle_buf = vec![];
let mut buf = [0; 4096];
buf[.."kernel: ".len()].copy_from_slice(b"kernel: ");
loop {
let n = debug_file.read(&mut buf["kernel: ".len()..]).unwrap();
let n = kernel_sys_log.read(&mut buf["kernel: ".len()..]).unwrap();
if n == 0 {
// FIXME currently possible as /scheme/log/kernel presents a snapshot of the log queue
break;
@@ -106,6 +104,7 @@ impl LogScheme {
LogScheme {
next_id: 0,
socket,
output_tx,
handles: BTreeMap::new(),
}
@@ -144,8 +143,28 @@ impl LogScheme {
}
}
impl SchemeSync for LogScheme {
fn open(&mut self, path: &str, _flags: usize, _ctx: &CallerCtx) -> Result<OpenResult> {
impl<'sock> SchemeSync for LogScheme<'sock> {
fn scheme_root(&mut self) -> Result<usize> {
let id = self.next_id;
self.next_id += 1;
self.handles.insert(id, LogHandle::SchemeRoot);
Ok(id)
}
fn openat(
&mut self,
dirfd: usize,
path: &str,
_flags: usize,
_fcntl_flags: u32,
_ctx: &CallerCtx,
) -> Result<OpenResult> {
if !matches!(
self.handles.get(&dirfd).ok_or(Error::new(EBADF))?,
LogHandle::SchemeRoot
) {
return Err(Error::new(EACCES));
}
let id = self.next_id;
self.next_id += 1;
@@ -192,17 +211,7 @@ impl SchemeSync for LogScheme {
) -> Result<usize> {
let (context, bufs) = match self.handles.get_mut(&id).ok_or(Error::new(EBADF))? {
LogHandle::Log { context, bufs } => (context, bufs),
LogHandle::AddSink => {
// FIXME maybe check if root
let sink_path = PathBuf::from(
String::from_utf8(buf.to_owned()).map_err(|_| Error::new(EINVAL))?,
);
self.output_tx.send(OutputCmd::AddSink(sink_path)).unwrap();
return Ok(buf.len());
}
LogHandle::SchemeRoot | LogHandle::AddSink => return Err(Error::new(EBADF)),
};
let handle_buf = bufs.entry(ctx.pid).or_insert_with(|| Vec::new());
@@ -212,6 +221,29 @@ impl SchemeSync for LogScheme {
Ok(buf.len())
}
fn on_sendfd(&mut self, sendfd_request: &SendFdRequest) -> Result<usize> {
let id = sendfd_request.id();
if !matches!(
self.handles.get(&id).ok_or(Error::new(EBADF))?,
LogHandle::AddSink
) {
return Err(Error::new(EBADF));
}
let mut new_fd = usize::MAX;
if let Err(e) = sendfd_request.obtain_fd(
&self.socket,
syscall::FobtainFdFlags::CLOEXEC,
std::slice::from_mut(&mut new_fd),
) {
return Err(e);
}
self.output_tx.send(OutputCmd::AddSink(new_fd)).unwrap();
Ok(1)
}
fn fcntl(&mut self, id: usize, _cmd: usize, _arg: usize, _ctx: &CallerCtx) -> Result<usize> {
let _handle = self.handles.get(&id).ok_or(Error::new(EBADF))?;
@@ -232,6 +264,7 @@ impl SchemeSync for LogScheme {
let path_bytes = match handle {
LogHandle::Log { context, .. } => context.as_bytes(),
LogHandle::AddSink => b"add_sink",
LogHandle::SchemeRoot => return Err(Error::new(EBADF)),
};
let mut j = 0;
while i < buf.len() && j < path_bytes.len() {
@@ -250,10 +283,8 @@ impl SchemeSync for LogScheme {
Ok(())
}
}
impl LogScheme {
pub fn on_close(&mut self, id: usize) {
fn on_close(&mut self, id: usize) {
self.handles.remove(&id);
}
}
+15 -13
View File
@@ -63,24 +63,24 @@ fn run(daemon: daemon::Daemon) -> Result<()> {
.context("failed to get mac address from network adapter")?;
trace!("opening ip scheme socket");
let ip_fd = Socket::nonblock("ip")
.map_err(|e| anyhow!("failed to open create ip scheme socket: {}", e))?;
let ip_fd = Socket::nonblock()
.map_err(|e| anyhow!("failed to open create ip scheme socket: {:?}", e))?;
trace!("opening udp scheme socket");
let udp_fd =
Socket::nonblock("udp").map_err(|e| anyhow!("failed to open udp scheme socket: {}", e))?;
Socket::nonblock().map_err(|e| anyhow!("failed to open udp scheme socket: {:?}", e))?;
trace!("opening tcp scheme socket");
let tcp_fd =
Socket::nonblock("tcp").map_err(|e| anyhow!("failed to open tcp scheme socket: {}", e))?;
Socket::nonblock().map_err(|e| anyhow!("failed to open tcp scheme socket: {:?}", e))?;
trace!("opening icmp scheme socket");
let icmp_fd = Socket::nonblock("icmp")
.map_err(|e| anyhow!("failed to open icmp scheme socket: {}", e))?;
let icmp_fd =
Socket::nonblock().map_err(|e| anyhow!("failed to open icmp scheme socket: {:?}", e))?;
trace!("opening netcfg scheme socket");
let netcfg_fd = Socket::nonblock("netcfg")
.map_err(|e| anyhow!("failed to open netcfg scheme socket {}", e))?;
let netcfg_fd =
Socket::nonblock().map_err(|e| anyhow!("failed to open netcfg scheme socket {:?}", e))?;
let time_path = format!("/scheme/time/{}", syscall::CLOCK_MONOTONIC);
let time_fd = Fd::open(&time_path, O_RDWR, 0).context("failed to open /scheme/time")?;
@@ -97,17 +97,18 @@ fn run(daemon: daemon::Daemon) -> Result<()> {
}
}
let event_queue = EventQueue::<EventSource>::new().context("failed to create event queue")?;
let event_queue = EventQueue::<EventSource>::new()
.map_err(|e| anyhow!("failed to create event queue: {:?}", e))?;
daemon.ready();
event_queue
.subscribe(network_fd.raw(), EventSource::Network, EventFlags::READ)
.context("failed to listen to network events")?;
.map_err(|e| anyhow!("failed to listen to network events: {:?}", e))?;
event_queue
.subscribe(time_fd.raw(), EventSource::Time, EventFlags::READ)
.context("failed to listen to timer events")?;
.map_err(|e| anyhow!("failed to listen to timer events: {:?}", e))?;
event_queue
.subscribe(ip_fd.inner().raw(), EventSource::IpScheme, EventFlags::READ)
@@ -154,7 +155,8 @@ fn run(daemon: daemon::Daemon) -> Result<()> {
icmp_fd,
time_fd,
netcfg_fd,
);
)
.context("smolnetd: failed to initialize smolnetd")?;
libredox::call::setrens(0, 0).context("smolnetd: failed to enter null namespace")?;
@@ -167,7 +169,7 @@ fn run(daemon: daemon::Daemon) -> Result<()> {
.into_iter()
.chain(event_queue.map(|r| r.map(|e| e.user_data)))
{
match event_res? {
match event_res.map_err(|e| anyhow!("event result is error: {:?}", e))? {
EventSource::Network => smolnetd.on_network_scheme_event(),
EventSource::Time => smolnetd.on_time_event(),
EventSource::IpScheme => smolnetd.on_ip_scheme_event(),
+25 -14
View File
@@ -4,7 +4,7 @@ use crate::link::{loopback::LoopbackDevice, DeviceList};
use crate::router::route_table::{RouteTable, Rule};
use crate::router::Router;
use crate::scheme::smoltcp::iface::SocketSet as SmoltcpSocketSet;
use crate::scheme::socket::{SchemeSocket, SocketScheme};
use crate::scheme::socket::{Handle, SchemeSocket, SocketScheme};
use libredox::flag;
use libredox::Fd;
use redox_scheme::{
@@ -87,7 +87,7 @@ impl Smolnetd {
icmp_file: Socket,
time_file: Fd,
netcfg_file: Socket,
) -> Smolnetd {
) -> Result<Smolnetd> {
let protocol_addrs = vec![
//This is a placeholder IP for DHCP
IpCidr::new(IpAddress::v4(0, 0, 0, 0), 8),
@@ -131,43 +131,47 @@ impl Smolnetd {
devices.borrow_mut().push(loopback);
devices.borrow_mut().push(eth0);
Smolnetd {
Ok(Smolnetd {
iface: Rc::clone(&iface),
router_device: network_device,
socket_set: Rc::clone(&socket_set),
timer: ::std::time::Instant::now(),
time_file: unsafe { File::from_raw_fd(time_file.into_raw() as RawFd) },
ip_scheme: IpScheme::new(
"ip",
Rc::clone(&iface),
Rc::clone(&route_table),
Rc::clone(&socket_set),
ip_file,
),
)?,
udp_scheme: UdpScheme::new(
"udp",
Rc::clone(&iface),
Rc::clone(&route_table),
Rc::clone(&socket_set),
udp_file,
),
)?,
tcp_scheme: TcpScheme::new(
"tcp",
Rc::clone(&iface),
Rc::clone(&route_table),
Rc::clone(&socket_set),
tcp_file,
),
)?,
icmp_scheme: IcmpScheme::new(
"icmp",
Rc::clone(&iface),
Rc::clone(&route_table),
Rc::clone(&socket_set),
icmp_file,
),
)?,
netcfg_scheme: NetCfgScheme::new(
Rc::clone(&iface),
netcfg_file,
Rc::clone(&route_table),
Rc::clone(&devices),
),
}
)?,
})
}
pub fn on_network_scheme_event(&mut self) -> Result<()> {
@@ -319,15 +323,19 @@ where
SocketT: SchemeSocket + AnySocket<'static>,
{
pub fn new(
name: &str,
iface: Interface,
route_table: Rc<RefCell<RouteTable>>,
socket_set: Rc<RefCell<SocketSet>>,
scheme_file: Socket,
) -> Self {
Self {
scheme: SocketScheme::<SocketT>::new(iface, route_table, socket_set, scheme_file),
) -> Result<Self> {
Ok(Self {
scheme: SocketScheme::<SocketT>::new(name, iface, route_table, socket_set, scheme_file)
.map_err(|e| {
Error::from_syscall_error(e, &format!("failed to initialize {} scheme", name))
})?,
wait_queue: Vec::new(),
}
})
}
pub fn on_scheme_event(&mut self) -> Result<Option<()>> {
let result = loop {
@@ -442,7 +450,10 @@ where
// Notify non-blocking sockets
let scheme = &mut self.scheme;
for (&fd, ref mut file) in &mut scheme.files {
for (&fd, handle) in &mut scheme.handles {
let Handle::File(file) = handle else {
continue;
};
let events = {
let mut socket_set = scheme.socket_set.borrow_mut();
file.events(&mut socket_set)
+108 -37
View File
@@ -3,7 +3,8 @@ mod nodes;
mod notifier;
use redox_scheme::{
scheme::SchemeSync, CallerCtx, OpenResult, RequestKind, Response, SignalBehavior, Socket,
scheme::register_scheme_inner, scheme::SchemeSync, CallerCtx, OpenResult, RequestKind,
Response, SignalBehavior, Socket,
};
use smoltcp::wire::{EthernetAddress, IpAddress, IpCidr, Ipv4Address};
use std::cell::RefCell;
@@ -324,10 +325,15 @@ impl NetCfgFile {
}
}
enum Handle {
SchemeRoot,
File(NetCfgFile),
}
pub struct NetCfgScheme {
scheme_file: Socket,
next_fd: usize,
files: BTreeMap<usize, NetCfgFile>,
handles: BTreeMap<usize, Handle>,
root_node: CfgNodeRef,
notifier: NotifierRef,
}
@@ -338,15 +344,15 @@ impl NetCfgScheme {
scheme_file: Socket,
route_table: Rc<RefCell<RouteTable>>,
devices: Rc<RefCell<DeviceList>>,
) -> NetCfgScheme {
) -> Result<NetCfgScheme> {
let notifier = Notifier::new_ref();
let dns_config = Rc::new(RefCell::new(DNSConfig {
name_server: Ipv4Address::new(8, 8, 8, 8),
}));
NetCfgScheme {
let mut scheme = NetCfgScheme {
scheme_file,
next_fd: 1,
files: BTreeMap::new(),
handles: BTreeMap::new(),
root_node: mk_root_node(
iface,
Rc::clone(&notifier),
@@ -355,7 +361,14 @@ impl NetCfgScheme {
devices,
),
notifier,
}
};
let cap_id = scheme
.scheme_root()
.map_err(|e| Error::from_syscall_error(e, "failed to get scheme root id"))?;
register_scheme_inner(&scheme.scheme_file, "netcfg", cap_id).map_err(|e| {
Error::from_syscall_error(e, "failed to register netcfg scheme to namespace")
})?;
Ok(scheme)
}
pub fn on_scheme_event(&mut self) -> Result<Option<()>> {
@@ -418,7 +431,32 @@ impl NetCfgScheme {
}
impl SchemeSync for NetCfgScheme {
fn open(&mut self, path: &str, _flags: usize, ctx: &CallerCtx) -> SyscallResult<OpenResult> {
fn scheme_root(&mut self) -> SyscallResult<usize> {
let id = self.next_fd;
self.next_fd += 1;
self.handles.insert(id, Handle::SchemeRoot);
Ok(id)
}
fn openat(
&mut self,
dirfd: usize,
path: &str,
_flags: usize,
_fcntl_flags: u32,
ctx: &CallerCtx,
) -> SyscallResult<OpenResult> {
{
let handle = self
.handles
.get(&dirfd)
.ok_or_else(|| SyscallError::new(syscall::EBADF))?;
if !matches!(handle, Handle::SchemeRoot) {
return Err(SyscallError::new(syscall::EACCES));
}
}
let mut current_node = Rc::clone(&self.root_node);
for part in path.split('/') {
if part.is_empty() {
@@ -435,9 +473,9 @@ impl SchemeSync for NetCfgScheme {
let fd = self.next_fd;
trace!("open {} {}", fd, path);
self.next_fd += 1;
self.files.insert(
self.handles.insert(
fd,
NetCfgFile {
Handle::File(NetCfgFile {
path: path.to_owned(),
is_dir: current_node.is_dir(),
is_writable: current_node.is_writable(),
@@ -452,7 +490,7 @@ impl SchemeSync for NetCfgScheme {
read_buf,
write_buf: vec![],
done: false,
},
}),
);
Ok(OpenResult::ThisScheme {
number: fd,
@@ -462,10 +500,17 @@ impl SchemeSync for NetCfgScheme {
fn on_close(&mut self, fd: usize) {
trace!("close {}", fd);
if let Some(mut file) = self.files.remove(&fd) {
self.notifier.borrow_mut().unsubscribe(&file.path, fd);
if !file.done {
let _ = file.commit().map(|_| 0);
if let Some(handle) = self.handles.remove(&fd) {
match handle {
Handle::SchemeRoot => {
// SchemeRoot closed, nothing specific to clean up
}
Handle::File(mut file) => {
self.notifier.borrow_mut().unsubscribe(&file.path, fd);
if !file.done {
let _ = file.commit().map(|_| 0);
}
}
}
}
}
@@ -478,11 +523,16 @@ impl SchemeSync for NetCfgScheme {
_fcntl_flags: u32,
_ctx: &CallerCtx,
) -> SyscallResult<usize> {
let file = self
.files
let handle = self
.handles
.get_mut(&fd)
.ok_or_else(|| SyscallError::new(syscall::EBADF))?;
let file = match handle {
Handle::File(file) => file,
Handle::SchemeRoot => return Err(SyscallError::new(syscall::EBADF)),
};
if file.done {
return Err(SyscallError::new(syscall::EBADF));
}
@@ -514,11 +564,16 @@ impl SchemeSync for NetCfgScheme {
_fcntl_flags: u32,
_ctx: &CallerCtx,
) -> SyscallResult<usize> {
let file = self
.files
let handle = self
.handles
.get_mut(&fd)
.ok_or_else(|| SyscallError::new(syscall::EBADF))?;
let file = match handle {
Handle::File(file) => file,
Handle::SchemeRoot => return Err(SyscallError::new(syscall::EBADF)),
};
let mut i = 0;
while i < buf.len() && file.pos < file.read_buf.len() {
buf[i] = file.read_buf[file.pos];
@@ -529,21 +584,26 @@ impl SchemeSync for NetCfgScheme {
}
fn fstat(&mut self, fd: usize, stat: &mut Stat, _ctx: &CallerCtx) -> SyscallResult<()> {
let file = self
.files
let handle = self
.handles
.get_mut(&fd)
.ok_or_else(|| SyscallError::new(syscall::EBADF))?;
stat.st_mode = if file.is_dir { MODE_DIR } else { MODE_FILE };
if file.is_writable {
stat.st_mode |= 0o222;
match handle {
Handle::SchemeRoot => return Err(SyscallError::new(syscall::EBADF)),
Handle::File(file) => {
stat.st_mode = if file.is_dir { MODE_DIR } else { MODE_FILE };
if file.is_writable {
stat.st_mode |= 0o222;
}
if file.is_readable {
stat.st_mode |= 0o444;
}
stat.st_uid = 0;
stat.st_gid = 0;
stat.st_size = file.read_buf.len() as u64;
}
}
if file.is_readable {
stat.st_mode |= 0o444;
}
stat.st_uid = 0;
stat.st_gid = 0;
stat.st_size = file.read_buf.len() as u64;
Ok(())
}
@@ -554,24 +614,35 @@ impl SchemeSync for NetCfgScheme {
events: SyscallEventFlags,
_ctx: &CallerCtx,
) -> SyscallResult<SyscallEventFlags> {
let file = self
.files
let handle = self
.handles
.get_mut(&fd)
.ok_or_else(|| SyscallError::new(syscall::EBADF))?;
if events.contains(syscall::EVENT_READ) {
self.notifier.borrow_mut().subscribe(&file.path, fd);
} else {
self.notifier.borrow_mut().unsubscribe(&file.path, fd);
match handle {
Handle::SchemeRoot => return Err(SyscallError::new(syscall::EBADF)),
Handle::File(file) => {
if events.contains(syscall::EVENT_READ) {
self.notifier.borrow_mut().subscribe(&file.path, fd);
} else {
self.notifier.borrow_mut().unsubscribe(&file.path, fd);
}
}
}
Ok(SyscallEventFlags::empty())
}
fn fsync(&mut self, fd: usize, _ctx: &CallerCtx) -> SyscallResult<()> {
let file = self
.files
let handle = self
.handles
.get_mut(&fd)
.ok_or_else(|| SyscallError::new(syscall::EBADF))?;
let file = match handle {
Handle::File(file) => file,
Handle::SchemeRoot => return Err(SyscallError::new(syscall::EBADF)),
};
if !file.done {
let res = file.commit();
file.done = true;
+181 -129
View File
@@ -12,7 +12,7 @@ use std::str;
use libredox::flag::CLOCK_MONOTONIC;
use redox_rt::protocol::SocketCall;
use redox_scheme::{
scheme::{Op, SchemeSync},
scheme::{register_scheme_inner, Op, SchemeSync},
CallerCtx, OpenResult, Socket,
};
use syscall::data::TimeSpec;
@@ -239,13 +239,21 @@ where
fn handle_shutdown(&mut self, file: &mut SchemeFile<Self>, how: usize) -> SyscallResult<usize>;
}
pub enum Handle<SocketT>
where
SocketT: SchemeSocket,
{
SchemeRoot,
Null(NullFile),
File(SchemeFile<SocketT>),
}
pub struct SocketScheme<SocketT>
where
SocketT: SchemeSocket + AnySocket<'static>,
{
next_fd: usize,
nulls: BTreeMap<usize, NullFile>,
pub files: BTreeMap<usize, SchemeFile<SocketT>>,
pub handles: BTreeMap<usize, Handle<SocketT>>,
ref_counts: BTreeMap<SocketHandle, usize>,
context: Context,
pub socket_set: Rc<RefCell<SocketSet>>,
@@ -259,33 +267,36 @@ where
SocketT: SchemeSocket + AnySocket<'static>,
{
pub fn new(
name: &str,
iface: Interface,
route_table: Rc<RefCell<RouteTable>>,
socket_set: Rc<RefCell<SocketSet>>,
scheme_file: Socket,
) -> SocketScheme<SocketT> {
SocketScheme {
) -> SyscallResult<SocketScheme<SocketT>> {
let mut scheme = SocketScheme {
next_fd: 1,
nulls: BTreeMap::new(),
files: BTreeMap::new(),
handles: BTreeMap::new(),
ref_counts: BTreeMap::new(),
socket_set,
scheme_data: SocketT::new_scheme_data(),
scheme_file,
_phantom_socket: PhantomData,
context: Context { iface, route_table },
}
};
let cap_id = scheme.scheme_root()?;
register_scheme_inner(&scheme.scheme_file, name, cap_id)?;
Ok(scheme)
}
pub fn handle_block(&mut self, op: &Op) -> SyscallResult<Option<TimeSpec>> {
let fd = op.file_id().expect("op is not fd based request");
let (read_timeout, write_timeout) = {
let file = self
.files
let handle = self
.handles
.get(&fd)
.ok_or_else(|| SyscallError::new(syscall::EBADF))?;
if let SchemeFile::Socket(ref scheme_file) = *file {
if let Handle::File(SchemeFile::Socket(ref scheme_file)) = *handle {
Ok((scheme_file.read_timeout, scheme_file.write_timeout))
} else {
Err(SyscallError::new(syscall::EBADF))
@@ -319,14 +330,13 @@ where
buf: &mut [u8],
) -> SyscallResult<usize> {
let file = self
.files
.handles
.get_mut(&fd)
.ok_or_else(|| SyscallError::new(syscall::EBADF))?;
let file = match *file {
SchemeFile::Socket(ref mut file) => file,
_ => {
return Err(SyscallError::new(syscall::EBADF));
}
Handle::File(SchemeFile::Socket(ref mut file)) => file,
_ => return Err(SyscallError::new(syscall::EBADF)),
};
match setting {
@@ -369,14 +379,12 @@ where
buf: &[u8],
) -> SyscallResult<usize> {
let file = self
.files
.handles
.get_mut(&fd)
.ok_or_else(|| SyscallError::new(syscall::EBADF))?;
let file = match *file {
SchemeFile::Socket(ref mut file) => file,
_ => {
return Err(SyscallError::new(syscall::EBADF));
}
Handle::File(SchemeFile::Socket(ref mut file)) => file,
_ => return Err(SyscallError::new(syscall::EBADF)),
};
match setting {
Setting::ReadTimeout | Setting::WriteTimeout => {
@@ -445,9 +453,14 @@ where
// SocketCall::GetToken => self.handle_get_token(id, payload),
SocketCall::GetPeerName => {
let file = self
.files
.handles
.get_mut(&fd)
.ok_or_else(|| SyscallError::new(syscall::EBADF))?;
let file = match *file {
Handle::File(ref mut f) => f,
_ => return Err(SyscallError::new(syscall::EBADF)),
};
let mut socket_set = self.socket_set.borrow_mut();
let socket = socket_set.get_mut::<SocketT>(file.socket_handle());
@@ -456,28 +469,31 @@ where
SocketCall::Shutdown => {
let how = metadata[1] as usize;
if let Some(null_file) = self.nulls.get_mut(&fd) {
match how {
0 => null_file.read_enabled = false,
1 => null_file.write_enabled = false,
2 => {
null_file.read_enabled = false;
null_file.write_enabled = false;
}
_ => return Err(SyscallError::new(EINVAL)),
}
return Ok(0);
}
let file = self
.files
match self
.handles
.get_mut(&fd)
.ok_or_else(|| SyscallError::new(syscall::EBADF))?;
.ok_or_else(|| SyscallError::new(syscall::EBADF))?
{
Handle::File(file) => {
let mut socket_set = self.socket_set.borrow_mut();
let socket = socket_set.get_mut::<SocketT>(file.socket_handle());
let mut socket_set = self.socket_set.borrow_mut();
let socket = socket_set.get_mut::<SocketT>(file.socket_handle());
SocketT::handle_shutdown(socket, file, how)
SocketT::handle_shutdown(socket, file, how)
}
Handle::Null(null_file) => {
match how {
0 => null_file.read_enabled = false,
1 => null_file.write_enabled = false,
2 => {
null_file.read_enabled = false;
null_file.write_enabled = false;
}
_ => return Err(SyscallError::new(EINVAL)),
}
Ok(0)
}
Handle::SchemeRoot => Err(SyscallError::new(syscall::EBADF)),
}
}
_ => Err(SyscallError::new(EOPNOTSUPP)),
}
@@ -504,7 +520,7 @@ where
let id = self.next_fd;
self.next_fd += 1;
self.nulls.insert(id, null);
self.handles.insert(id, Handle::Null(null));
Ok(OpenResult::ThisScheme {
number: id,
@@ -536,7 +552,7 @@ where
self.next_fd += 1;
self.ref_counts.insert(socket_handle, 1);
self.files.insert(id, file);
self.handles.insert(id, Handle::File(file));
Ok(OpenResult::ThisScheme {
number: id,
@@ -550,8 +566,30 @@ impl<SocketT> SchemeSync for SocketScheme<SocketT>
where
SocketT: SchemeSocket + AnySocket<'static>,
{
fn open(&mut self, path: &str, flags: usize, ctx: &CallerCtx) -> SyscallResult<OpenResult> {
self.open_inner(path, flags, ctx.uid, ctx.gid, true, true)
fn scheme_root(&mut self) -> SyscallResult<usize> {
let id = self.next_fd;
self.next_fd += 1;
self.handles.insert(id, Handle::SchemeRoot);
Ok(id)
}
fn openat(
&mut self,
fd: usize,
path: &str,
flags: usize,
_fcntl_flags: u32,
ctx: &CallerCtx,
) -> SyscallResult<OpenResult> {
let handle = self
.handles
.get(&fd)
.ok_or_else(|| SyscallError::new(syscall::EBADF))?;
match handle {
Handle::SchemeRoot => self.open_inner(path, flags, ctx.uid, ctx.gid, true, true),
_ => Err(SyscallError::new(syscall::EACCES)),
}
}
fn call(
@@ -565,22 +603,11 @@ where
}
fn on_close(&mut self, fd: usize) {
if let Some(_null) = self.nulls.remove(&fd) {
let handle = if let Some(handle) = self.handles.remove(&fd) {
handle
} else {
return;
}
let socket_handle = {
let Some(file) = self.files.get(&fd) else {
return;
};
file.socket_handle()
};
let scheme_file = self.files.remove(&fd);
let mut socket_set = self.socket_set.borrow_mut();
if let Some(scheme_file) = scheme_file {
let socket = socket_set.get::<SocketT>(socket_handle);
let _ = socket.close_file(&scheme_file, &mut self.scheme_data);
}
// incorrect, and kernel can't send close until all references are gone
/*self.wait_queue.retain(
@@ -590,30 +617,42 @@ where
}| a != fd,
);*/
let remove = match self.ref_counts.entry(socket_handle) {
Entry::Vacant(_) => {
warn!("Closing a socket_handle with no ref");
true
}
Entry::Occupied(mut e) => {
if *e.get() == 0 {
warn!("Closing a socket_handle with no ref");
e.remove();
true
} else {
*e.get_mut() -= 1;
if *e.get() == 0 {
e.remove();
match handle {
Handle::SchemeRoot => return,
Handle::Null(_) => return,
Handle::File(scheme_file) => {
let socket_handle = scheme_file.socket_handle();
let mut socket_set = self.socket_set.borrow_mut();
let socket = socket_set.get::<SocketT>(socket_handle);
let _ = socket.close_file(&scheme_file, &mut self.scheme_data);
let remove = match self.ref_counts.entry(socket_handle) {
Entry::Vacant(_) => {
warn!("Closing a socket_handle with no ref");
true
} else {
false
}
Entry::Occupied(mut e) => {
if *e.get() == 0 {
warn!("Closing a socket_handle with no ref");
e.remove();
true
} else {
*e.get_mut() -= 1;
if *e.get() == 0 {
e.remove();
true
} else {
false
}
}
}
};
if remove {
socket_set.remove(socket_handle);
}
}
};
if remove {
socket_set.remove(socket_handle);
}
}
@@ -627,15 +666,15 @@ where
) -> SyscallResult<usize> {
let (fd, setting) = {
let file = self
.files
.handles
.get_mut(&fd)
.ok_or_else(|| SyscallError::new(syscall::EBADF))?;
match *file {
SchemeFile::Setting(ref setting_handle) => {
Handle::File(SchemeFile::Setting(ref setting_handle)) => {
(setting_handle.fd, setting_handle.setting)
}
SchemeFile::Socket(ref mut file) => {
Handle::File(SchemeFile::Socket(ref mut file)) => {
let mut socket_set = self.socket_set.borrow_mut();
let socket = socket_set.get_mut::<SocketT>(file.socket_handle);
let ret = SocketT::write_buf(socket, file, buf);
@@ -646,6 +685,7 @@ where
}
return ret;
}
_ => return Err(SyscallError::new(syscall::EBADF)),
}
};
self.update_setting(fd, setting, buf)
@@ -661,14 +701,14 @@ where
) -> SyscallResult<usize> {
let (fd, setting) = {
let file = self
.files
.handles
.get_mut(&fd)
.ok_or_else(|| SyscallError::new(syscall::EBADF))?;
match *file {
SchemeFile::Setting(ref setting_handle) => {
Handle::File(SchemeFile::Setting(ref setting_handle)) => {
(setting_handle.fd, setting_handle.setting)
}
SchemeFile::Socket(ref mut file) => {
Handle::File(SchemeFile::Socket(ref mut file)) => {
let mut socket_set = self.socket_set.borrow_mut();
let socket = socket_set.get_mut::<SocketT>(file.socket_handle);
@@ -681,6 +721,7 @@ where
return ret;
}
_ => return Err(SyscallError::new(syscall::EBADF)),
}
};
self.get_setting(fd, setting, buf)
@@ -689,27 +730,28 @@ where
fn dup(&mut self, fd: usize, buf: &[u8], _ctx: &CallerCtx) -> SyscallResult<OpenResult> {
let path = str::from_utf8(buf).or_else(|_| Err(SyscallError::new(syscall::EINVAL)))?;
if let Some((flags, uid, gid, read_enabled, write_enabled)) =
self.nulls.get(&fd).map(|null| {
(
null.flags,
null.uid,
null.gid,
null.read_enabled,
null.write_enabled,
)
})
{
// dup from empty path to a new path
return self.open_inner(path, flags, uid, gid, read_enabled, write_enabled);
}
let new_file = {
let file = self
.files
let handle = self
.handles
.get_mut(&fd)
.ok_or_else(|| SyscallError::new(syscall::EBADF))?;
let file = match *handle {
Handle::SchemeRoot => return Err(SyscallError::new(syscall::EBADF)),
Handle::Null(ref null) => {
let (flags, uid, gid, read_enabled, write_enabled) = (
null.flags,
null.uid,
null.gid,
null.read_enabled,
null.write_enabled,
);
// dup from empty path to a new path
return self.open_inner(path, flags, uid, gid, read_enabled, write_enabled);
}
Handle::File(ref mut file) => file,
};
let socket_handle = file.socket_handle();
let (new_handle, update_with) = match path {
@@ -757,7 +799,10 @@ where
.and_modify(|e| *e = e.saturating_sub(1))
.or_insert(0);
*self.ref_counts.entry(socket_handle).or_insert(0) += 1;
*self
.ref_counts
.entry(new_handle.socket_handle())
.or_insert(0) += 1;
file.socket_handle = socket_handle;
file.data = data;
@@ -771,7 +816,7 @@ where
};
let id = self.next_fd;
self.files.insert(id, new_file);
self.handles.insert(id, Handle::File(new_file));
self.next_fd += 1;
Ok(OpenResult::ThisScheme {
@@ -787,9 +832,15 @@ where
_ctx: &CallerCtx,
) -> SyscallResult<SyscallEventFlags> {
let file = self
.files
.handles
.get_mut(&fd)
.ok_or_else(|| SyscallError::new(syscall::EBADF))?;
let file = match *file {
Handle::File(ref mut f) => f,
_ => return Err(SyscallError::new(syscall::EBADF)),
};
match *file {
SchemeFile::Setting(_) => return Err(SyscallError::new(syscall::EBADF)),
SchemeFile::Socket(ref mut file) => {
@@ -806,7 +857,7 @@ where
fn fsync(&mut self, fd: usize, _ctx: &CallerCtx) -> SyscallResult<()> {
{
let _file = self
.files
.handles
.get_mut(&fd)
.ok_or_else(|| SyscallError::new(syscall::EBADF))?;
}
@@ -817,10 +868,15 @@ where
fn fpath(&mut self, fd: usize, buf: &mut [u8], _ctx: &CallerCtx) -> SyscallResult<usize> {
let file = self
.files
.handles
.get_mut(&fd)
.ok_or_else(|| SyscallError::new(syscall::EBADF))?;
let file = match *file {
Handle::File(ref mut f) => f,
_ => return Err(SyscallError::new(syscall::EBADF)),
};
let socket_set = self.socket_set.borrow();
let socket = socket_set.get::<SocketT>(file.socket_handle());
@@ -834,33 +890,29 @@ where
arg: usize,
_ctx: &CallerCtx,
) -> SyscallResult<usize> {
if let Some(ref mut null) = self.nulls.get_mut(&fd) {
match cmd {
let handle = self
.handles
.get_mut(&fd)
.ok_or_else(|| SyscallError::new(syscall::EBADF))?;
match *handle {
Handle::File(SchemeFile::Socket(ref mut socket_file)) => match cmd {
syscall::F_GETFL => Ok(socket_file.flags),
syscall::F_SETFL => {
socket_file.flags = arg & !syscall::O_ACCMODE;
Ok(0)
}
_ => Err(SyscallError::new(syscall::EINVAL)),
},
Handle::Null(ref mut null) => match cmd {
syscall::F_GETFL => Ok(null.flags),
syscall::F_SETFL => {
null.flags = arg & !syscall::O_ACCMODE;
Ok(0)
}
_ => Err(SyscallError::new(syscall::EINVAL)),
}
} else {
let file = self
.files
.get_mut(&fd)
.ok_or_else(|| SyscallError::new(syscall::EBADF))?;
if let SchemeFile::Socket(ref mut socket_file) = *file {
match cmd {
syscall::F_GETFL => Ok(socket_file.flags),
syscall::F_SETFL => {
socket_file.flags = arg & !syscall::O_ACCMODE;
Ok(0)
}
_ => Err(SyscallError::new(syscall::EINVAL)),
}
} else {
Err(SyscallError::new(syscall::EBADF))
}
},
_ => Err(SyscallError::new(syscall::EBADF)),
}
}
}
+1 -2
View File
@@ -1,9 +1,8 @@
use std::cell::RefCell;
use std::rc::{Rc, Weak};
use syscall::error::{Error, Result, EAGAIN, EINVAL};
use syscall::error::{Error, Result, EAGAIN, EINVAL, EWOULDBLOCK};
use syscall::flag::{EventFlags, F_GETFL, F_SETFL, O_ACCMODE, O_NONBLOCK};
use syscall::EWOULDBLOCK;
use crate::pty::Pty;
use crate::resource::Resource;
+22 -15
View File
@@ -4,7 +4,7 @@ use event::{user_data, EventFlags, EventQueue};
use libredox::{flag, Fd};
use redox_scheme::wrappers::ReadinessBased;
use redox_scheme::{Response, SignalBehavior, Socket};
use redox_scheme::{scheme::register_sync_scheme, Response, SignalBehavior, Socket};
use syscall::data::TimeSpec;
mod controlterm;
@@ -16,7 +16,7 @@ mod subterm;
mod termios;
mod winsize;
use scheme::PtyScheme;
use scheme::{Handle, PtyScheme};
fn main() {
daemon::Daemon::new(daemon);
@@ -36,9 +36,14 @@ fn daemon(daemon: daemon::Daemon) -> ! {
let mut time_file =
Fd::open(&time_path, flag::O_NONBLOCK, 0).expect("pty: failed to open time:");
let socket = redox_scheme::Socket::nonblock("pty").expect("pty: failed to create pty scheme");
let socket = redox_scheme::Socket::nonblock().expect("pty: failed to create pty scheme");
let mut handler = ReadinessBased::new(&socket, 16);
let scheme = RefCell::new(PtyScheme::new());
register_sync_scheme(&socket, "pty", &mut *scheme.borrow_mut())
.expect("ptyd: failed to register scheme to namespace");
daemon.ready();
libredox::call::setrens(0, 0).expect("ptyd: failed to enter null namespace");
event_queue
@@ -48,12 +53,9 @@ fn daemon(daemon: daemon::Daemon) -> ! {
.subscribe(time_file.raw(), EventSource::Time, EventFlags::READ)
.expect("pty: failed to watch events on time:");
daemon.ready();
//TODO: do not set timeout if not necessary
timeout(&mut time_file).expect("pty: failed to set timeout");
let scheme = RefCell::new(PtyScheme::new());
let mut timeout_count = 0u64;
scan_requests(&mut handler, &scheme).expect("pty: could not scan requests");
@@ -74,7 +76,9 @@ fn daemon(daemon: daemon::Daemon) -> ! {
timeout_count = timeout_count.wrapping_add(1);
for (_id, handle) in scheme.borrow_mut().handles.iter_mut() {
handle.timeout(timeout_count);
if let Handle::Resource(res) = handle {
res.timeout(timeout_count);
}
}
handler
@@ -127,14 +131,16 @@ fn scan_requests(
fn issue_events(socket: &Socket, scheme: &mut PtyScheme) {
for (id, handle) in scheme.handles.iter_mut() {
let events = handle.events();
if events != syscall::EventFlags::empty() {
socket
.write_response(
Response::post_fevent(*id, events.bits()),
SignalBehavior::Restart,
)
.expect("pty: failed to send scheme event");
if let Handle::Resource(ref mut res) = handle {
let events = res.events();
if events != syscall::EventFlags::empty() {
socket
.write_response(
Response::post_fevent(*id, events.bits()),
SignalBehavior::Restart,
)
.expect("pty: failed to send scheme event");
}
}
}
}
@@ -143,6 +149,7 @@ fn timeout(time_file: &mut Fd) -> libredox::error::Result<()> {
let mut time = TimeSpec::default();
time_file.read(&mut time)?;
// Set timeout for 100ms
time.tv_nsec += 100_000_000;
while time.tv_nsec >= 1_000_000_000 {
time.tv_sec += 1;
+83 -40
View File
@@ -6,7 +6,7 @@ use std::str;
use redox_scheme::scheme::SchemeSync;
use redox_scheme::{CallerCtx, OpenResult};
use syscall::data::Stat;
use syscall::error::{Error, Result, EBADF, EINVAL, ENOENT};
use syscall::error::{Error, Result, EACCES, EBADF, EINVAL, ENOENT};
use syscall::flag::{EventFlags, MODE_CHR};
use syscall::schemev2::NewFdFlags;
@@ -18,9 +18,14 @@ use crate::subterm::PtySubTerm;
use crate::termios::PtyTermios;
use crate::winsize::PtyWinsize;
pub enum Handle {
Resource(Box<dyn Resource>),
SchemeRoot,
}
pub struct PtyScheme {
next_id: usize,
pub handles: BTreeMap<usize, Box<dyn Resource>>,
pub handles: BTreeMap<usize, Handle>,
}
impl PtyScheme {
@@ -30,24 +35,49 @@ impl PtyScheme {
handles: BTreeMap::new(),
}
}
fn get_resource_mut(&mut self, id: usize) -> Result<&mut Box<dyn Resource>> {
match self.handles.get_mut(&id).ok_or(Error::new(EBADF))? {
Handle::Resource(res) => Ok(res),
Handle::SchemeRoot => Err(Error::new(EBADF)),
}
}
}
impl SchemeSync for PtyScheme {
fn open(&mut self, path: &str, flags: usize, _ctx: &CallerCtx) -> Result<OpenResult> {
fn scheme_root(&mut self) -> Result<usize> {
let id = self.next_id;
self.next_id += 1;
self.handles.insert(id, Handle::SchemeRoot);
Ok(id)
}
fn openat(
&mut self,
dirfd: usize,
path: &str,
flags: usize,
fcntl_flags: u32,
_ctx: &CallerCtx,
) -> Result<OpenResult> {
if !matches!(
self.handles.get(&dirfd).ok_or(Error::new(EBADF))?,
Handle::SchemeRoot
) {
return Err(Error::new(EACCES));
}
let path = path.trim_matches('/');
let id = self.next_id;
self.next_id += 1;
if path.is_empty() {
let id = self.next_id;
self.next_id += 1;
let pty = Rc::new(RefCell::new(Pty::new(id)));
self.handles
.insert(id, Box::new(PtyControlTerm::new(pty, flags)));
Ok(OpenResult::ThisScheme {
number: id,
flags: NewFdFlags::empty(),
})
self.handles.insert(
id,
Handle::Resource(Box::new(PtyControlTerm::new(pty, flags))),
);
} else {
let control_term_id = path.parse::<usize>().or(Err(Error::new(EINVAL)))?;
let pty = {
@@ -55,32 +85,40 @@ impl SchemeSync for PtyScheme {
.handles
.get(&control_term_id)
.ok_or(Error::new(ENOENT))?;
handle.pty()
match handle {
Handle::Resource(res) => res.pty(),
Handle::SchemeRoot => return Err(Error::new(ENOENT)),
}
};
let id = self.next_id;
self.next_id += 1;
self.handles
.insert(id, Box::new(PtySubTerm::new(pty, flags)));
Ok(OpenResult::ThisScheme {
number: id,
flags: NewFdFlags::empty(),
})
self.handles.insert(
id,
Handle::Resource(Box::new(PtySubTerm::new(pty, flags | fcntl_flags as usize))),
);
}
Ok(OpenResult::ThisScheme {
number: id,
flags: NewFdFlags::empty(),
})
}
fn dup(&mut self, old_id: usize, buf: &[u8], _ctx: &CallerCtx) -> Result<OpenResult> {
let handle: Box<dyn Resource> = {
let old_handle = self.handles.get(&old_id).ok_or(Error::new(EBADF))?;
let old_resource = match old_handle {
Handle::Resource(res) => res,
Handle::SchemeRoot => return Err(Error::new(EBADF)),
};
if buf == b"pgrp" {
Box::new(PtyPgrp::new(old_handle.pty(), old_handle.flags()))
Box::new(PtyPgrp::new(old_resource.pty(), old_resource.flags()))
} else if buf == b"termios" {
Box::new(PtyTermios::new(old_handle.pty(), old_handle.flags()))
Box::new(PtyTermios::new(old_resource.pty(), old_resource.flags()))
} else if buf == b"winsize" {
Box::new(PtyWinsize::new(old_handle.pty(), old_handle.flags()))
Box::new(PtyWinsize::new(old_resource.pty(), old_resource.flags()))
} else {
return Err(Error::new(EINVAL));
}
@@ -88,7 +126,7 @@ impl SchemeSync for PtyScheme {
let id = self.next_id;
self.next_id += 1;
self.handles.insert(id, handle);
self.handles.insert(id, Handle::Resource(handle));
Ok(OpenResult::ThisScheme {
number: id,
@@ -104,7 +142,7 @@ impl SchemeSync for PtyScheme {
_fcntl_flags: u32,
_ctx: &CallerCtx,
) -> Result<usize> {
let handle = self.handles.get_mut(&id).ok_or(Error::new(EBADF))?;
let handle = self.get_resource_mut(id)?;
handle.read(buf)
}
@@ -116,42 +154,47 @@ impl SchemeSync for PtyScheme {
_fcntl_flags: u32,
_ctx: &CallerCtx,
) -> Result<usize> {
let handle = self.handles.get_mut(&id).ok_or(Error::new(EBADF))?;
let handle = self.get_resource_mut(id)?;
handle.write(buf)
}
fn fcntl(&mut self, id: usize, cmd: usize, arg: usize, _ctx: &CallerCtx) -> Result<usize> {
let handle = self.handles.get_mut(&id).ok_or(Error::new(EBADF))?;
let handle = self.get_resource_mut(id)?;
handle.fcntl(cmd, arg)
}
fn fevent(&mut self, id: usize, _flags: EventFlags, _ctx: &CallerCtx) -> Result<EventFlags> {
let handle = self.handles.get_mut(&id).ok_or(Error::new(EBADF))?;
let handle = self.get_resource_mut(id)?;
handle.fevent()
}
fn fpath(&mut self, id: usize, buf: &mut [u8], _ctx: &CallerCtx) -> Result<usize> {
let handle = self.handles.get_mut(&id).ok_or(Error::new(EBADF))?;
let handle = self.get_resource_mut(id)?;
handle.path(buf)
}
fn fstat(&mut self, id: usize, stat: &mut Stat, _ctx: &CallerCtx) -> Result<()> {
let _handle = self.handles.get(&id).ok_or(Error::new(EBADF))?;
let handle = self.handles.get(&id).ok_or(Error::new(EBADF))?;
*stat = Stat {
st_mode: MODE_CHR | 0o666,
..Default::default()
};
match handle {
Handle::SchemeRoot => return Err(Error::new(EBADF)),
Handle::Resource(_res) => {
*stat = Stat {
st_mode: MODE_CHR | 0o666,
..Default::default()
};
}
}
Ok(())
}
fn fsync(&mut self, id: usize, _ctx: &CallerCtx) -> Result<()> {
let handle = self.handles.get_mut(&id).ok_or(Error::new(EBADF))?;
let handle = self.get_resource_mut(id)?;
handle.sync()
}
fn on_close(&mut self, id: usize) {
self.handles.remove(&id);
let _ = self.handles.remove(&id);
}
}
+1 -2
View File
@@ -1,9 +1,8 @@
use std::cell::RefCell;
use std::rc::Weak;
use syscall::error::{Error, Result, EAGAIN, EINVAL, EPIPE};
use syscall::error::{Error, Result, EAGAIN, EINVAL, EPIPE, EWOULDBLOCK};
use syscall::flag::{EventFlags, F_GETFL, F_SETFL, O_ACCMODE, O_NONBLOCK};
use syscall::EWOULDBLOCK;
use crate::pty::Pty;
use crate::resource::Resource;
+5 -5
View File
@@ -14,14 +14,14 @@ fn main() {
fn daemon(daemon: daemon::Daemon) -> ! {
let scheme_name = env::args().nth(1).expect("Usage:\n\tramfs SCHEME_NAME");
let socket =
redox_scheme::Socket::create(&scheme_name).expect("ramfs: failed to create socket");
let socket = redox_scheme::Socket::create().expect("ramfs: failed to create socket");
let mut scheme = Scheme::new(scheme_name).expect("ramfs: failed to initialize scheme");
libredox::call::setrens(0, 0).expect("ramfs: failed to enter null namespace");
let mut scheme = Scheme::new(scheme_name.clone()).expect("ramfs: failed to initialize scheme");
redox_scheme::scheme::register_sync_scheme(&socket, &scheme_name, &mut scheme)
.expect("ramfs: failed to register to namespace");
daemon.ready();
libredox::call::setrens(0, 0).expect("ramfs: failed to enter null namespace");
loop {
let Some(request) = socket
+95 -26
View File
@@ -1,3 +1,4 @@
use std::collections::HashMap;
use std::convert::{TryFrom, TryInto};
use std::io::{Cursor, Seek};
use std::iter;
@@ -22,9 +23,19 @@ use redox_scheme::{CallerCtx, OpenResult};
use crate::filesystem::{self, File, FileData, Filesystem, Inode};
enum Handle {
Inode(usize),
SchemeRoot,
}
// TODO: Move to relibc
const AT_REMOVEDIR: usize = 0x200;
pub struct Scheme {
scheme_name: String,
filesystem: Filesystem,
handles: HashMap<usize, Handle>,
next_id: usize,
}
impl Scheme {
/// Create the scheme, with the name being used for `fpath`.
@@ -32,10 +43,11 @@ impl Scheme {
Ok(Self {
scheme_name,
filesystem: Filesystem::new()?,
handles: HashMap::new(),
next_id: 0,
})
}
/// Remove a directory entry, where the entry can be both a file or a directory. Used by both
/// `unlink` and `rmdir`.
/// Remove a directory entry, where the entry can be both a file or a directory. Used by `unlinkat`.
pub fn remove_dentry(&mut self, path: &str, uid: u32, gid: u32, directory: bool) -> Result<()> {
let removed_inode = {
let (parent_dir_inode, name_to_delete) =
@@ -148,7 +160,27 @@ impl Scheme {
}
impl SchemeSync for Scheme {
fn open(&mut self, path: &str, flags: usize, ctx: &CallerCtx) -> Result<OpenResult> {
fn scheme_root(&mut self) -> Result<usize> {
let id = self.next_id;
self.handles.insert(id, Handle::SchemeRoot);
self.next_id += 1;
Ok(id)
}
fn openat(
&mut self,
dirfd: usize,
path: &str,
flags: usize,
fcntl_flags: u32,
ctx: &CallerCtx,
) -> Result<OpenResult> {
if !matches!(
self.handles.get(&dirfd).ok_or(Error::new(EBADF))?,
Handle::SchemeRoot
) {
return Err(Error::new(EACCES));
}
let exists = self.filesystem.resolve(path, 0, 0).is_ok();
if flags & O_CREAT != 0 && flags & O_EXCL != 0 && exists {
return Err(Error::new(EEXIST));
@@ -232,19 +264,26 @@ impl SchemeSync for Scheme {
new_inode_number
} else {
self.open_existing(path, flags, ctx.uid, ctx.gid)?.0
self.open_existing(path, flags | fcntl_flags as usize, ctx.uid, ctx.gid)?
.0
};
let new_id = self.next_id;
self.handles.insert(new_id, Handle::Inode(inode));
self.next_id += 1;
Ok(OpenResult::ThisScheme {
number: inode,
number: new_id,
flags: NewFdFlags::POSITIONED,
})
}
fn unlinkat(&mut self, dirfd: usize, path: &str, flags: usize, ctx: &CallerCtx) -> Result<()> {
let _ = self
.filesystem
.files
.get_mut(&dirfd)
.ok_or(Error::new(EBADFD))?;
{
if !matches!(
self.handles.get(&dirfd).ok_or(Error::new(EBADF))?,
Handle::SchemeRoot
) {
return Err(Error::new(EACCES));
}
}
self.remove_dentry(
path,
ctx.uid,
@@ -254,7 +293,7 @@ impl SchemeSync for Scheme {
}
fn read(
&mut self,
inode: usize,
fd: usize,
buf: &mut [u8],
offset: u64,
fcntl_flags: u32,
@@ -263,7 +302,10 @@ impl SchemeSync for Scheme {
let Ok(offset) = usize::try_from(offset) else {
return Ok(0);
};
let inode = match self.handles.get(&fd).ok_or(Error::new(EBADFD))? {
Handle::Inode(inode) => inode,
Handle::SchemeRoot => return Err(Error::new(EISDIR)),
};
let file = self
.filesystem
.files
@@ -289,13 +331,17 @@ impl SchemeSync for Scheme {
}
fn getdents<'buf>(
&mut self,
inode: usize,
fd: usize,
mut buf: DirentBuf<&'buf mut [u8]>,
opaque_offset: u64,
) -> Result<DirentBuf<&'buf mut [u8]>> {
let Ok(offset) = usize::try_from(opaque_offset) else {
return Ok(buf);
};
let inode = match self.handles.get(&fd).ok_or(Error::new(EBADFD))? {
Handle::Inode(inode) => inode,
Handle::SchemeRoot => return Err(Error::new(EISDIR)),
};
let file = self
.filesystem
.files
@@ -318,7 +364,7 @@ impl SchemeSync for Scheme {
}
fn write(
&mut self,
inode: usize,
fd: usize,
buf: &[u8],
offset: u64,
_fcntl_flags: u32,
@@ -327,7 +373,10 @@ impl SchemeSync for Scheme {
let Ok(offset) = usize::try_from(offset) else {
return Ok(0);
};
let inode = match self.handles.get(&fd).ok_or(Error::new(EBADFD))? {
Handle::Inode(inode) => inode,
Handle::SchemeRoot => return Err(Error::new(EISDIR)),
};
let file = self
.filesystem
.files
@@ -353,7 +402,11 @@ impl SchemeSync for Scheme {
Err(Error::new(EISDIR))
}
}
fn fchmod(&mut self, inode: usize, mode: u16, _ctx: &CallerCtx) -> Result<()> {
fn fchmod(&mut self, fd: usize, mode: u16, _ctx: &CallerCtx) -> Result<()> {
let inode = match self.handles.get(&fd).ok_or(Error::new(EBADFD))? {
Handle::Inode(inode) => inode,
Handle::SchemeRoot => return Err(Error::new(EISDIR)),
};
let file = self
.filesystem
.files
@@ -413,12 +466,12 @@ impl SchemeSync for Scheme {
// TODO
Err(Error::new(ENOSYS))
}
fn fpath(
&mut self,
mut current_inode: usize,
buf: &mut [u8],
_ctx: &CallerCtx,
) -> Result<usize> {
fn fpath(&mut self, fd: usize, buf: &mut [u8], _ctx: &CallerCtx) -> Result<usize> {
let mut current_inode = match *self.handles.get(&fd).ok_or(Error::new(EBADFD))? {
Handle::Inode(inode) => inode,
Handle::SchemeRoot => return Err(Error::new(EISDIR)),
};
let mut chain = Vec::new();
let mut current_info = self
@@ -462,7 +515,12 @@ impl SchemeSync for Scheme {
// TODO
Err(Error::new(ENOSYS))
}
fn fstat(&mut self, inode: usize, stat: &mut Stat, _ctx: &CallerCtx) -> Result<()> {
fn fstat(&mut self, fd: usize, stat: &mut Stat, _ctx: &CallerCtx) -> Result<()> {
let inode = match *self.handles.get(&fd).ok_or(Error::new(EBADFD))? {
Handle::Inode(inode) => inode,
Handle::SchemeRoot => return Err(Error::new(EISDIR)),
};
let block_size = self.filesystem.block_size();
let file = self
.filesystem
@@ -535,7 +593,11 @@ impl SchemeSync for Scheme {
fn fsync(&mut self, _inode: usize, _ctx: &CallerCtx) -> Result<()> {
Ok(())
}
fn ftruncate(&mut self, inode: usize, size: u64, _ctx: &CallerCtx) -> Result<()> {
fn ftruncate(&mut self, fd: usize, size: u64, _ctx: &CallerCtx) -> Result<()> {
let inode = match self.handles.get(&fd).ok_or(Error::new(EBADFD))? {
Handle::Inode(inode) => inode,
Handle::SchemeRoot => return Err(Error::new(EISDIR)),
};
let file = self
.filesystem
.files
@@ -560,7 +622,11 @@ impl SchemeSync for Scheme {
}
Ok(())
}
fn futimens(&mut self, inode: usize, times: &[TimeSpec], _ctx: &CallerCtx) -> Result<()> {
fn futimens(&mut self, fd: usize, times: &[TimeSpec], _ctx: &CallerCtx) -> Result<()> {
let inode = match self.handles.get(&fd).ok_or(Error::new(EBADFD))? {
Handle::Inode(inode) => inode,
Handle::SchemeRoot => return Err(Error::new(EISDIR)),
};
let file = self
.filesystem
.files
@@ -577,7 +643,10 @@ impl SchemeSync for Scheme {
}
}
impl Scheme {
pub fn on_close(&mut self, inode: usize) {
pub fn on_close(&mut self, fd: usize) {
let Some(Handle::Inode(inode)) = self.handles.remove(&fd) else {
return;
};
let Some(inode_info) = self.filesystem.files.get_mut(&inode) else {
return;
};
+199 -146
View File
@@ -13,15 +13,14 @@ pub const MODE_READ: u16 = 0o4;
#[cfg(target_arch = "x86_64")]
use raw_cpuid::CpuId;
use redox_scheme::scheme::SchemeSync;
use redox_scheme::{CallerCtx, OpenResult, RequestKind, SignalBehavior, Socket};
use syscall::data::Stat;
use syscall::flag::EventFlags;
use syscall::schemev2::NewFdFlags;
use syscall::{
Error, Result, EBADF, EEXIST, ENOENT, EPERM, MODE_CHR, O_CREAT, O_EXCL, O_RDONLY, O_RDWR,
O_WRONLY,
use redox_scheme::{
scheme::{register_sync_scheme, SchemeSync},
CallerCtx, OpenResult, RequestKind, Response, SignalBehavior, Socket,
};
use syscall::data::Stat;
use syscall::flag::{EventFlags, O_CREAT, O_EXCL, O_RDONLY, O_RDWR, O_WRONLY};
use syscall::schemev2::NewFdFlags;
use syscall::{Error, Result, EACCES, EBADF, EEXIST, ENOENT, EOPNOTSUPP, EPERM, MODE_CHR};
// Create an RNG Seed to create initial seed from the rdrand intel instruction
use rand_core::SeedableRng;
@@ -100,6 +99,20 @@ impl OpenFileInfo {
}
}
enum Handle {
File(OpenFileInfo),
SchemeRoot,
}
impl Handle {
fn as_file(&self) -> Option<&OpenFileInfo> {
match self {
Self::File(info) => Some(info),
_ => None,
}
}
}
/// Struct to represent the rand scheme.
struct RandScheme {
prng: ChaCha20Rng,
@@ -107,11 +120,11 @@ struct RandScheme {
// https://docs.rs/rand/0.5.0/rand/prng/chacha/struct.ChaChaRng.html
// Allows 2^64 streams of random numbers, which we will equate with file numbers
prng_stat: Stat,
open_descriptors: BTreeMap<usize, OpenFileInfo>, // Cannot use HashMap as the implementation
handles: BTreeMap<usize, Handle>,
// calls the system RNG (us) for entropy to protect against HashDOS attacks.
// Trying to create a HashMap causes a system crash.
// <file number, information about the open file>
next_fd: Wrapping<usize>,
next_id: Wrapping<usize>,
}
impl RandScheme {
@@ -125,19 +138,16 @@ impl RandScheme {
st_uid: 0,
..Default::default()
},
open_descriptors: BTreeMap::new(),
next_fd: Wrapping(0),
handles: BTreeMap::new(),
next_id: Wrapping(0),
}
}
/// Gets the open file info for a file descriptor if it is open - error otherwise.
fn get_fd(&self, fd: usize) -> Result<&OpenFileInfo> {
// Check we've got a valid file descriptor
let file_info = match self.open_descriptors.get(&fd) {
Some(m) => m,
None => return Err(Error::new(EBADF)),
};
Ok(file_info)
let handle = self.handles.get(&fd).ok_or(Error::new(EBADF))?;
handle.as_file().ok_or(Error::new(EBADF))
}
/// Checks to see if the op (MODE_READ, MODE_WRITE) can be performed on the open file
/// descriptor - Will return the open file info if successful, and error if the file
@@ -162,120 +172,19 @@ impl RandScheme {
entropy_array.copy_from_slice(hash.as_slice());
self.prng = ChaCha20Rng::from_seed(entropy_array);
}
}
#[test]
fn test_scheme_perms() {
use syscall::{O_CLOEXEC, O_STAT};
let mut ctx = CallerCtx {
pid: 0,
uid: 1,
gid: 1,
id: unsafe { std::mem::zeroed() }, // Id doesn't have a public constructor
};
let mut scheme = RandScheme::new();
scheme.prng_stat.st_mode = MODE_CHR | 0o200;
scheme.prng_stat.st_uid = 1;
scheme.prng_stat.st_gid = 1;
assert!(scheme.open("/", O_RDWR, &ctx).is_err());
assert!(scheme.open("/", O_RDONLY, &ctx).is_err());
scheme.prng_stat.st_mode = MODE_CHR | 0o400;
let mut fd = match scheme.open("", O_RDONLY, &ctx).unwrap() {
OpenResult::ThisScheme { number, .. } => number,
_ => panic!(),
};
assert!(scheme.can_perform_op_on_fd(fd, MODE_READ).is_ok());
assert!(scheme.can_perform_op_on_fd(fd, MODE_WRITE).is_err());
scheme.on_close(fd);
assert!(scheme.open("", O_WRONLY, &ctx).is_err());
assert!(scheme.open("", O_RDWR, &ctx).is_err());
scheme.prng_stat.st_mode = MODE_CHR | 0o600;
fd = match scheme.open("", O_RDWR, &ctx).unwrap() {
OpenResult::ThisScheme { number, .. } => number,
_ => panic!(),
};
assert!(scheme.can_perform_op_on_fd(fd, MODE_READ).is_ok());
assert!(scheme.can_perform_op_on_fd(fd, MODE_WRITE).is_ok());
scheme.on_close(fd);
ctx.uid = 2;
ctx.gid = 2;
fd = match scheme.open("", O_STAT, &ctx).unwrap() {
OpenResult::ThisScheme { number, .. } => number,
_ => panic!(),
};
assert!(scheme.can_perform_op_on_fd(fd, MODE_READ).is_err());
assert!(scheme.can_perform_op_on_fd(fd, MODE_WRITE).is_err());
scheme.on_close(fd);
fd = match scheme.open("", O_STAT | O_CLOEXEC, &ctx).unwrap() {
OpenResult::ThisScheme { number, .. } => number,
_ => panic!(),
};
assert!(scheme.can_perform_op_on_fd(fd, MODE_READ).is_err());
assert!(scheme.can_perform_op_on_fd(fd, MODE_WRITE).is_err());
scheme.on_close(fd);
// Try another user in group (no group perms)
ctx.uid = 2;
ctx.gid = 1;
fd = match scheme.open("", O_STAT | O_CLOEXEC, &ctx).unwrap() {
OpenResult::ThisScheme { number, .. } => number,
_ => panic!(),
};
assert!(scheme.can_perform_op_on_fd(fd, MODE_READ).is_err());
assert!(scheme.can_perform_op_on_fd(fd, MODE_WRITE).is_err());
scheme.on_close(fd);
scheme.prng_stat.st_mode = MODE_CHR | 0o660;
fd = match scheme.open("", O_STAT | O_CLOEXEC, &ctx).unwrap() {
OpenResult::ThisScheme { number, .. } => number,
_ => panic!(),
};
assert!(scheme.can_perform_op_on_fd(fd, MODE_READ).is_ok());
assert!(scheme.can_perform_op_on_fd(fd, MODE_WRITE).is_ok());
scheme.on_close(fd);
// Check root can do anything
scheme.prng_stat.st_mode = MODE_CHR | 0o000;
ctx.uid = 0;
ctx.gid = 0;
fd = match scheme.open("", O_STAT | O_CLOEXEC, &ctx).unwrap() {
OpenResult::ThisScheme { number, .. } => number,
_ => panic!(),
};
assert!(scheme.can_perform_op_on_fd(fd, MODE_READ).is_ok());
assert!(scheme.can_perform_op_on_fd(fd, MODE_WRITE).is_ok());
scheme.on_close(fd);
// Check the rand:/urandom URL (Equivalent to rand:/)
scheme.prng_stat.st_mode = MODE_CHR | 0o660;
ctx.uid = 2;
ctx.gid = 1;
fd = match scheme.open("/urandom", O_STAT | O_CLOEXEC, &ctx).unwrap() {
OpenResult::ThisScheme { number, .. } => number,
_ => panic!(),
};
assert!(scheme.can_perform_op_on_fd(fd, MODE_READ).is_ok());
assert!(scheme.can_perform_op_on_fd(fd, MODE_WRITE).is_ok());
scheme.on_close(fd);
}
impl SchemeSync for RandScheme {
fn open(&mut self, path: &str, flags: usize, ctx: &CallerCtx) -> Result<OpenResult> {
fn open_inner(&mut self, path: &str, flags: usize, ctx: &CallerCtx) -> Result<OpenResult> {
// We are only allowing
// reads/writes from rand:/ and rand:/urandom - the root directory on its own is passed as an empty slice
// reads/writes from /scheme/rand/ and /scheme/rand/urandom - the root directory on its own is passed as an empty slice
if path != "" && path != "/urandom" {
return Err(Error::new(ENOENT));
}
if flags & (O_CREAT | O_EXCL) == O_CREAT | O_EXCL {
return Err(Error::new(EEXIST));
}
let fd = self.next_fd;
let id = self.next_id;
let open_file_info = OpenFileInfo {
o_flags: flags,
file_stat: self.prng_stat,
@@ -293,38 +202,179 @@ impl SchemeSync for RandScheme {
{
return Err(Error::new(EPERM));
}
self.open_descriptors.insert(fd.0, open_file_info);
// Get the next file descriptor
self.next_fd += Wrapping(1);
self.handles.insert(id.0, Handle::File(open_file_info));
// If we've looped round there's a small chance that the file descriptor still exists, so loop till we get one that doesn't
self.next_id += Wrapping(1);
loop {
if !self.open_descriptors.contains_key(&self.next_fd.0) {
if !self.handles.contains_key(&self.next_id.0) {
break;
} else {
self.next_fd += Wrapping(1);
self.next_id += Wrapping(1);
}
}
Ok(OpenResult::ThisScheme {
number: fd.0,
number: id.0,
flags: NewFdFlags::empty(),
})
}
}
#[test]
fn test_scheme_perms() {
use syscall::{O_CLOEXEC, O_STAT};
let mut ctx = CallerCtx {
pid: 0,
uid: 1,
gid: 1,
id: unsafe { std::mem::zeroed() }, // Id doesn't have a public constructor
};
let mut scheme = RandScheme::new();
scheme.prng_stat.st_mode = MODE_CHR | 0o200;
scheme.prng_stat.st_uid = 1;
scheme.prng_stat.st_gid = 1;
assert!(scheme.open_inner("/", O_RDWR, &ctx).is_err());
assert!(scheme.open_inner("/", O_RDONLY, &ctx).is_err());
scheme.prng_stat.st_mode = MODE_CHR | 0o400;
let mut fd = match scheme.open("", O_RDONLY, &ctx).unwrap() {
OpenResult::ThisScheme { number, .. } => number,
_ => panic!(),
};
assert!(scheme.can_perform_op_on_fd(fd, MODE_READ).is_ok());
assert!(scheme.can_perform_op_on_fd(fd, MODE_WRITE).is_err());
scheme.on_close(fd);
assert!(scheme.open_inner("", O_WRONLY, &ctx).is_err());
assert!(scheme.open_inner("", O_RDWR, &ctx).is_err());
scheme.prng_stat.st_mode = MODE_CHR | 0o600;
fd = match scheme.open_inner("", O_RDWR, &ctx).unwrap() {
OpenResult::ThisScheme { number, .. } => number,
_ => panic!(),
};
assert!(scheme.can_perform_op_on_fd(fd, MODE_READ).is_ok());
assert!(scheme.can_perform_op_on_fd(fd, MODE_WRITE).is_ok());
scheme.on_close(fd);
ctx.uid = 2;
ctx.gid = 2;
fd = match scheme.open_inner("", O_STAT, &ctx).unwrap() {
OpenResult::ThisScheme { number, .. } => number,
_ => panic!(),
};
assert!(scheme.can_perform_op_on_fd(fd, MODE_READ).is_err());
assert!(scheme.can_perform_op_on_fd(fd, MODE_WRITE).is_err());
scheme.on_close(fd);
fd = match scheme.open_inner("", O_STAT | O_CLOEXEC, &ctx).unwrap() {
OpenResult::ThisScheme { number, .. } => number,
_ => panic!(),
};
assert!(scheme.can_perform_op_on_fd(fd, MODE_READ).is_err());
assert!(scheme.can_perform_op_on_fd(fd, MODE_WRITE).is_err());
scheme.on_close(fd);
// Try another user in group (no group perms)
ctx.uid = 2;
ctx.gid = 1;
fd = match scheme.open_inner("", O_STAT | O_CLOEXEC, &ctx).unwrap() {
OpenResult::ThisScheme { number, .. } => number,
_ => panic!(),
};
assert!(scheme.can_perform_op_on_fd(fd, MODE_READ).is_err());
assert!(scheme.can_perform_op_on_fd(fd, MODE_WRITE).is_err());
scheme.on_close(fd);
scheme.prng_stat.st_mode = MODE_CHR | 0o660;
fd = match scheme.open_inner("", O_STAT | O_CLOEXEC, &ctx).unwrap() {
OpenResult::ThisScheme { number, .. } => number,
_ => panic!(),
};
assert!(scheme.can_perform_op_on_fd(fd, MODE_READ).is_ok());
assert!(scheme.can_perform_op_on_fd(fd, MODE_WRITE).is_ok());
scheme.on_close(fd);
// Check root can do anything
scheme.prng_stat.st_mode = MODE_CHR | 0o000;
ctx.uid = 0;
ctx.gid = 0;
fd = match scheme.open_inner("", O_STAT | O_CLOEXEC, &ctx).unwrap() {
OpenResult::ThisScheme { number, .. } => number,
_ => panic!(),
};
assert!(scheme.can_perform_op_on_fd(fd, MODE_READ).is_ok());
assert!(scheme.can_perform_op_on_fd(fd, MODE_WRITE).is_ok());
scheme.on_close(fd);
// Check the rand:/urandom URL (Equivalent to rand:/)
scheme.prng_stat.st_mode = MODE_CHR | 0o660;
ctx.uid = 2;
ctx.gid = 1;
fd = match scheme
.open_inner("/urandom", O_STAT | O_CLOEXEC, &ctx)
.unwrap()
{
OpenResult::ThisScheme { number, .. } => number,
_ => panic!(),
};
assert!(scheme.can_perform_op_on_fd(fd, MODE_READ).is_ok());
assert!(scheme.can_perform_op_on_fd(fd, MODE_WRITE).is_ok());
scheme.on_close(fd);
}
impl SchemeSync for RandScheme {
fn scheme_root(&mut self) -> Result<usize> {
let id = self.next_id;
self.handles.insert(id.0, Handle::SchemeRoot);
// Get the next file descriptor
self.next_id += Wrapping(1);
// If we've looped round there's a small chance that the file descriptor still exists, so loop till we get one that doesn't
loop {
if !self.handles.contains_key(&self.next_id.0) {
break;
} else {
self.next_id += Wrapping(1);
}
}
Ok(id.0)
}
fn openat(
&mut self,
dirfd: usize,
path: &str,
flags: usize,
_fcntl_flags: u32,
ctx: &CallerCtx,
) -> Result<OpenResult> {
if !matches!(
self.handles.get(&dirfd).ok_or(Error::new(EBADF))?,
Handle::SchemeRoot
) {
return Err(Error::new(EACCES));
}
self.open_inner(path, flags, ctx)
}
/* Resource operations */
fn read(
&mut self,
file: usize,
id: usize,
buf: &mut [u8],
_offset: u64,
_flags: u32,
_fcntl_flags: u32,
_ctx: &CallerCtx,
) -> Result<usize> {
// Check fd and permissions
self.can_perform_op_on_fd(file, MODE_READ)?;
self.can_perform_op_on_fd(id, MODE_READ)?;
// Setting the stream will ensure that if two clients are reading concurrently, they won't get the same numbers
self.prng.set_stream(file as u64); // Should probably find a way to re-instate the counter for this stream, but
// not doing so won't make the output any less 'random'
self.prng.set_stream(id as u64); // Should probably find a way to re-instate the counter for this stream, but
// not doing so won't make the output any less 'random'
self.prng.fill_bytes(buf);
Ok(buf.len())
@@ -332,14 +382,14 @@ impl SchemeSync for RandScheme {
fn write(
&mut self,
file: usize,
id: usize,
buf: &[u8],
_offset: u64,
_flags: u32,
_fcntl_flags: u32,
_ctx: &CallerCtx,
) -> Result<usize> {
// Check fd and permissions
self.can_perform_op_on_fd(file, MODE_WRITE)?;
self.can_perform_op_on_fd(id, MODE_WRITE)?;
// TODO - when we support other entropy sources, just add this to an entropy pool
// TODO - consider having trusted and untrusted entropy writing paths
@@ -357,23 +407,23 @@ impl SchemeSync for RandScheme {
Ok(buf.len())
}
fn fchmod(&mut self, file: usize, mode: u16, _ctx: &CallerCtx) -> Result<()> {
fn fchmod(&mut self, id: usize, mode: u16, ctx: &CallerCtx) -> Result<()> {
// Check fd and permissions
let file_info = self.get_fd(file)?;
let file_info = self.get_fd(id)?;
// only root and owner can chmod
if file_info.uid != file_info.file_stat.st_uid && file_info.uid != 0 {
if ctx.uid != file_info.file_stat.st_uid && ctx.uid != 0 {
return Err(Error::new(EPERM));
}
self.prng_stat.st_mode = MODE_CHR | mode;
self.prng_stat.st_mode = MODE_CHR | (mode & MODE_PERM); // Apply mask
Ok(())
}
fn fchown(&mut self, file: usize, uid: u32, gid: u32, _ctx: &CallerCtx) -> Result<()> {
fn fchown(&mut self, id: usize, uid: u32, gid: u32, ctx: &CallerCtx) -> Result<()> {
// Check fd and permissions
let file_info = self.get_fd(file)?;
// only root and owner can chmod
if file_info.uid != file_info.file_stat.st_uid && file_info.uid != 0 {
let file_info = self.get_fd(id)?;
// only root and owner can fchown
if ctx.uid != file_info.file_stat.st_uid && ctx.uid != 0 {
return Err(Error::new(EPERM));
}
@@ -411,15 +461,18 @@ impl SchemeSync for RandScheme {
fn on_close(&mut self, file: usize) {
// just remove the file descriptor from the open descriptors
self.open_descriptors.remove(&file);
let _ = self.handles.remove(&file);
}
}
fn daemon(daemon: daemon::Daemon) -> ! {
let socket = Socket::create("rand").expect("randd: failed to create rand scheme");
let socket = Socket::create().expect("randd: failed to create rand scheme");
let mut scheme = RandScheme::new();
register_sync_scheme(&socket, "rand", &mut scheme)
.expect("randd: failed to register scheme to namespace");
daemon.ready();
libredox::call::setrens(0, 0).expect("randd: failed to enter null namespace");
+6 -5
View File
@@ -1,5 +1,4 @@
use redox_scheme::scheme::SchemeSync;
use redox_scheme::{RequestKind, SignalBehavior, Socket};
use redox_scheme::{scheme::register_sync_scheme, RequestKind, SignalBehavior, Socket};
use scheme::ZeroScheme;
@@ -25,13 +24,16 @@ fn daemon(daemon: daemon::Daemon) -> ! {
Ty::Null => "null",
Ty::Zero => "zero",
};
let socket = Socket::create(name).expect("zerod: failed to create zero scheme");
let socket = Socket::create().expect("zerod: failed to create zero scheme");
let mut zero_scheme = ZeroScheme(ty);
libredox::call::setrens(0, 0).expect("zerod: failed to enter null namespace");
register_sync_scheme(&socket, name, &mut zero_scheme)
.expect("zerod: failed to register scheme to namespace");
daemon.ready();
libredox::call::setrens(0, 0).expect("zerod: failed to enter null namespace");
loop {
let Some(request) = socket
.next_request(SignalBehavior::Restart)
@@ -47,7 +49,6 @@ fn daemon(daemon: daemon::Daemon) -> ! {
.write_response(response, SignalBehavior::Restart)
.expect("zerod: failed to write responses to zero scheme");
}
RequestKind::OnClose { id } => zero_scheme.on_close(id),
_ => (),
}
}
+23 -12
View File
@@ -1,23 +1,36 @@
use redox_scheme::scheme::SchemeSync;
use redox_scheme::{CallerCtx, OpenResult};
use syscall::schemev2::NewFdFlags;
use syscall::{error::*, MODE_CHR};
use syscall::{error::*, schemev2::NewFdFlags, MODE_CHR};
use crate::Ty;
pub struct ZeroScheme(pub Ty);
const SCHEME_ROOT_ID: usize = 1;
impl SchemeSync for ZeroScheme {
fn open(&mut self, _path: &str, _flags: usize, _ctx: &CallerCtx) -> Result<OpenResult> {
fn scheme_root(&mut self) -> Result<usize> {
Ok(SCHEME_ROOT_ID)
}
fn openat(
&mut self,
dirfd: usize,
path: &str,
_flags: usize,
_fcntl_flags: u32,
_ctx: &CallerCtx,
) -> Result<OpenResult> {
if dirfd != SCHEME_ROOT_ID {
return Err(Error::new(EACCES));
}
Ok(OpenResult::ThisScheme {
number: 0,
flags: NewFdFlags::empty(),
})
}
fn read(
&mut self,
_file: usize,
_id: usize,
buf: &mut [u8],
_offset: u64,
_flags: u32,
@@ -34,13 +47,13 @@ impl SchemeSync for ZeroScheme {
fn write(
&mut self,
_file: usize,
buffer: &[u8],
_id: usize,
buf: &[u8],
_offset: u64,
_flags: u32,
_ctx: &CallerCtx,
) -> Result<usize> {
Ok(buffer.len())
Ok(buf.len())
}
fn fcntl(&mut self, _id: usize, _cmd: usize, _arg: usize, _ctx: &CallerCtx) -> Result<usize> {
@@ -62,13 +75,11 @@ impl SchemeSync for ZeroScheme {
Ok(size)
}
fn fsync(&mut self, _file: usize, _ctx: &CallerCtx) -> Result<()> {
fn fsync(&mut self, _id: usize, _ctx: &CallerCtx) -> Result<()> {
Ok(())
}
/// Close the file `number`
fn on_close(&mut self, _file: usize) {}
fn fstat(&mut self, _: usize, stat: &mut syscall::Stat, _ctx: &CallerCtx) -> Result<()> {
fn fstat(&mut self, _id: usize, stat: &mut syscall::Stat, _ctx: &CallerCtx) -> Result<()> {
stat.st_mode = 0o666 | MODE_CHR;
stat.st_size = 0;
stat.st_blocks = 0;