diff --git a/Cargo.lock b/Cargo.lock index 2c2d4d9..802395a 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -20,6 +20,15 @@ version = "0.2.20" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "45862d1c77f2228b9e10bc609d5bc203d86ebc9b87ad8d5d5167a6c9abf739d9" +[[package]] +name = "atomic-polyfill" +version = "1.0.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8cf2bce30dfe09ef0bfaef228b9d414faaf7e563035494d7fe092dba54b300f4" +dependencies = [ + "critical-section", +] + [[package]] name = "autocfg" version = "1.4.0" @@ -46,9 +55,12 @@ checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a" [[package]] name = "bitflags" -version = "2.6.0" +version = "2.8.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b048fb63fd8b5923fc5aa7b340d8e156aec7ec02f0c78fa8a6ddc2613f6f71de" +checksum = "8f68f53c83ab957f72c32642f3868eec03eb974d1fb82e453128456482613d36" +dependencies = [ + "serde", +] [[package]] name = "bootloader_api" @@ -65,6 +77,12 @@ dependencies = [ "spin", ] +[[package]] +name = "byteorder" +version = "1.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1fd0f2584146f6f2ef48085050886acf353beff7305ebd1ae69500e27c67f64b" + [[package]] name = "cast" version = "0.3.0" @@ -77,6 +95,18 @@ version = "1.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" +[[package]] +name = "cobs" +version = "0.2.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "67ba02a97a2bd10f4b59b25c7973101c79642302776489e030cd13cdab09ed15" + +[[package]] +name = "critical-section" +version = "1.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "790eea4361631c5e7d22598ecd5723ff611904e3344ce8720784c93e3d83d40b" + [[package]] name = "crossbeam-queue" version = "0.3.11" @@ -109,12 +139,33 @@ version = "0.7.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "4445909572dbd556c457c849c4ca58623d84b27c8fff1e74b0b4227d8b90d17b" +[[package]] +name = "embedded-io" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ef1a6892d9eef45c8fa6b9e0086428a2cca8491aca8f787c534a3d6d0bcb3ced" + +[[package]] +name = "embedded-io" +version = "0.6.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "edd0f118536f44f5ccd48bcb8b111bdc3de888b58c74639dfb034a357d0f206d" + [[package]] name = "gimli" version = "0.28.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "4271d37baee1b8c7e4b708028c57d816cf9d2434acb33a549475f78c181f6253" +[[package]] +name = "hash32" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b0c35f58762feb77d74ebe43bdbc3210f09be9fe6742234d573bacc26ed92b67" +dependencies = [ + "byteorder", +] + [[package]] name = "hashbrown" version = "0.14.5" @@ -125,6 +176,20 @@ dependencies = [ "allocator-api2", ] +[[package]] +name = "heapless" +version = "0.7.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cdc6457c0eb62c71aac4bc17216026d8410337c4126773b9c5daba343f17964f" +dependencies = [ + "atomic-polyfill", + "hash32", + "rustc_version", + "serde", + "spin", + "stable_deref_trait", +] + [[package]] name = "humansize" version = "2.1.3" @@ -148,6 +213,7 @@ name = "kernel" version = "0.1.0" dependencies = [ "az", + "bitflags 2.8.0", "bootloader_api", "buddy_system_allocator", "cast", @@ -159,8 +225,10 @@ dependencies = [ "intrusive-collections", "linked_list_allocator", "pic8259", + "postcard", "replace_with", "saturating_cast", + "serde", "slab", "spin", "static_assertions", @@ -242,6 +310,19 @@ dependencies = [ "x86_64", ] +[[package]] +name = "postcard" +version = "1.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "170a2601f67cc9dba8edd8c4870b15f71a6a2dc196daec8c83f72b59dff628a8" +dependencies = [ + "cobs", + "embedded-io 0.4.0", + "embedded-io 0.6.1", + "heapless", + "serde", +] + [[package]] name = "proc-macro2" version = "1.0.92" @@ -275,6 +356,15 @@ version = "0.1.7" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e3a8614ee435691de62bcffcf4a66d91b3594bf1428a5722e79103249a095690" +[[package]] +name = "rustc_version" +version = "0.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cfcb3a22ef46e85b45de6ee7e79d063319ebb6594faafcf1c225ea92ab6e9b92" +dependencies = [ + "semver", +] + [[package]] name = "rustversion" version = "1.0.18" @@ -293,6 +383,32 @@ version = "1.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "94143f37725109f92c262ed2cf5e59bce7498c01bcc1502d7b9afe439a4e9f49" +[[package]] +name = "semver" +version = "1.0.23" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "61697e0a1c7e512e84a621326239844a24d8207b4669b41bc18b32ea5cbf988b" + +[[package]] +name = "serde" +version = "1.0.218" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e8dfc9d19bdbf6d17e22319da49161d5d0108e4188e8b680aef6299eed22df60" +dependencies = [ + "serde_derive", +] + +[[package]] +name = "serde_derive" +version = "1.0.218" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f09503e191f4e797cb8aac08e9a4a4695c5edf6a2e70e376d961ddd5c969f82b" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.89", +] + [[package]] name = "slab" version = "0.4.9" @@ -320,6 +436,12 @@ dependencies = [ "lock_api", ] +[[package]] +name = "stable_deref_trait" +version = "1.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a8f112729512f8e442d81f95a8a7ddf2b7c6b8a1a6f509a95864142b30cab2d3" + [[package]] name = "static_assertions" version = "1.1.0" @@ -360,7 +482,7 @@ version = "0.3.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0f3702156d45f3b61411186a2555956d57d94f63049bbfaa3fd4856729f7c14a" dependencies = [ - "bitflags 2.6.0", + "bitflags 2.8.0", "log", "memchr", "num-traits", @@ -372,7 +494,7 @@ version = "0.3.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e492212ac378a5e00da953718dafb1340d9fbaf4f27d6f3c5cab03d931d1c049" dependencies = [ - "bitflags 2.6.0", + "bitflags 2.8.0", "rustversion", "x86", ] @@ -426,7 +548,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "4bc79523af8abf92fb1a970c3e086c5a343f6bcc1a0eb890f575cbb3b45743df" dependencies = [ "bit_field", - "bitflags 2.6.0", + "bitflags 2.8.0", "rustversion", "volatile", ] diff --git a/Cargo.toml b/Cargo.toml index 994daaf..975a033 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -29,6 +29,9 @@ humansize = "2.1.3" cast = "0.3.0" az = "1.2.1" unsigned-varint = "0.8.0" +postcard = { version = "1.1.1", features = ["alloc"] } +serde = { version = "1.0.218", features = ["alloc", "derive"], default-features = false } +bitflags = { version = "2.8.0", features = ["serde"] } [features] log-rpc = [] diff --git a/src/interrupts.rs b/src/interrupts.rs index f990fd5..c33b5c2 100644 --- a/src/interrupts.rs +++ b/src/interrupts.rs @@ -1,5 +1,6 @@ use crate::{ bootinfo::BOOTINFO, + ipc_dump::dump_ipc_message, pit::NUM_INTERRUPTS, print, println, tasking::{InvalidPid, IpcMessage, SleepReason}, @@ -176,6 +177,7 @@ pub fn send_ipc_to( )] TASKING.current_pid().unwrap() }; + dump_ipc_message(from, pid, &buffer[0..len]); #[cfg(feature = "log-rpc")] { #[expect( @@ -199,9 +201,9 @@ pub fn send_ipc_to( )] let total_len = padded_len + 16 + (4 * 4); SECOND_PORT.write_u32s(&[ - 0x3, // SPB type - total_len, // Total block length - len.saturating_cast::().saturating_add(16), // Packet length + 0x3, // SPB type + total_len, // Total block length + trunc_len.saturating_cast::().saturating_add(16), // Packet length ]); SECOND_PORT.write_bytes(&pid.to_ne_bytes()); SECOND_PORT.write_bytes(&from.to_ne_bytes()); diff --git a/src/ipc_dump/errno.rs b/src/ipc_dump/errno.rs new file mode 100644 index 0000000..594d476 --- /dev/null +++ b/src/ipc_dump/errno.rs @@ -0,0 +1,567 @@ +use core::fmt::{self, Display, Formatter}; +use serde::{Deserialize, Serialize}; + +#[repr(i32)] +#[derive(Serialize, Deserialize, Debug, Copy, Clone, PartialEq, Eq)] +pub enum Errno { + /// Operation not permitted + EPERM = 1, + /// No such file or directory + ENOENT = 2, + /// No such process + ESRCH = 3, + /// Interrupted system call + EINTR = 4, + /// Input/output error + EIO = 5, + /// No such device or address + ENXIO = 6, + /// Argument list too long + E2BIG = 7, + /// Exec format error + ENOEXEC = 8, + /// Bad file descriptor + EBADF = 9, + /// No child processes + ECHILD = 10, + /// Resource temporarily unavailable + EWOULDBLOCK = 11, + /// Cannot allocate memory + ENOMEM = 12, + /// Permission denied + EACCES = 13, + /// Bad address + EFAULT = 14, + /// Block device required + ENOTBLK = 15, + /// Device or resource busy + EBUSY = 16, + /// File exists + EEXIST = 17, + /// Invalid cross-device link + EXDEV = 18, + /// No such device + ENODEV = 19, + /// Not a directory + ENOTDIR = 20, + /// Is a directory + EISDIR = 21, + /// Invalid argument + EINVAL = 22, + /// Too many open files in system + ENFILE = 23, + /// Too many open files + EMFILE = 24, + /// Inappropriate ioctl for device + ENOTTY = 25, + /// Text file busy + ETXTBSY = 26, + /// File too large + EFBIG = 27, + /// No space left on device + ENOSPC = 28, + /// Illegal seek + ESPIPE = 29, + /// Read-only file system + EROFS = 30, + /// Too many links + EMLINK = 31, + /// Broken pipe + EPIPE = 32, + /// Numerical argument out of domain + EDOM = 33, + /// Numerical result out of range + ERANGE = 34, + /// Resource deadlock avoided + EDEADLK = 35, + /// File name too long + ENAMETOOLONG = 36, + /// No locks available + ENOLCK = 37, + /// Function not implemented + ENOSYS = 38, + /// Directory not empty + ENOTEMPTY = 39, + /// Too many levels of symbolic links + ELOOP = 40, + /// No message of desired type + ENOMSG = 42, + /// Identifier removed + EIDRM = 43, + /// Channel number out of range + ECHRNG = 44, + /// Level 2 not synchronized + EL2NSYNC = 45, + /// Level 3 halted + EL3HLT = 46, + /// Level 3 reset + EL3RST = 47, + /// Link number out of range + ELNRNG = 48, + /// Protocol driver not attached + EUNATCH = 49, + /// No CSI structure available + ENOCSI = 50, + /// Level 2 halted + EL2HLT = 51, + /// Invalid exchange + EBADE = 52, + /// Invalid request descriptor + EBADR = 53, + /// Exchange full + EXFULL = 54, + /// No anode + ENOANO = 55, + /// Invalid request code + EBADRQC = 56, + /// Invalid slot + EBADSLT = 57, + /// Bad font file format + EBFONT = 59, + /// Device not a stream + ENOSTR = 60, + /// No data available + ENODATA = 61, + /// Timer expired + ETIME = 62, + /// Out of streams resources + ENOSR = 63, + /// Machine is not on the network + ENONET = 64, + /// Package not installed + ENOPKG = 65, + /// Object is remote + EREMOTE = 66, + /// Link has been severed + ENOLINK = 67, + /// Advertise error + EADV = 68, + /// Srmount error + ESRMNT = 69, + /// Communication error on send + ECOMM = 70, + /// Protocol error + EPROTO = 71, + /// Multihop attempted + EMULTIHOP = 72, + /// RFS specific error + EDOTDOT = 73, + /// Bad message + EBADMSG = 74, + /// Value too large for defined data type + EOVERFLOW = 75, + /// Name not unique on network + ENOTUNIQ = 76, + /// File descriptor in bad state + EBADFD = 77, + /// Remote address changed + EREMCHG = 78, + /// Can not access a needed shared library + ELIBACC = 79, + /// Accessing a corrupted shared library + ELIBBAD = 80, + /// .lib section in a.out corrupted + ELIBSCN = 81, + /// Attempting to link in too many shared libraries + ELIBMAX = 82, + /// Cannot exec a shared library directly + ELIBEXEC = 83, + /// Invalid or incomplete multibyte or wide character + EILSEQ = 84, + /// Interrupted system call should be restarted + ERESTART = 85, + /// Streams pipe error + ESTRPIPE = 86, + /// Too many users + EUSERS = 87, + /// Socket operation on non-socket + ENOTSOCK = 88, + /// Destination address required + EDESTADDRREQ = 89, + /// Message too long + EMSGSIZE = 90, + /// Protocol wrong type for socket + EPROTOTYPE = 91, + /// Protocol not available + ENOPROTOOPT = 92, + /// Protocol not supported + EPROTONOSUPPORT = 93, + /// Socket type not supported + ESOCKTNOSUPPORT = 94, + /// Operation not supported + ENOTSUP = 95, + /// Protocol family not supported + EPFNOSUPPORT = 96, + /// Address family not supported by protocol + EAFNOSUPPORT = 97, + /// Address already in use + EADDRINUSE = 98, + /// Cannot assign requested address + EADDRNOTAVAIL = 99, + /// Network is down + ENETDOWN = 100, + /// Network is unreachable + ENETUNREACH = 101, + /// Network dropped connection on reset + ENETRESET = 102, + /// Software caused connection abort + ECONNABORTED = 103, + /// Connection reset by peer + ECONNRESET = 104, + /// No buffer space available + ENOBUFS = 105, + /// Transport endpoint is already connected + EISCONN = 106, + /// Transport endpoint is not connected + ENOTCONN = 107, + /// Cannot send after transport endpoint shutdown + ESHUTDOWN = 108, + /// Too many references: cannot splice + ETOOMANYREFS = 109, + /// Connection timed out + ETIMEDOUT = 110, + /// Connection refused + ECONNREFUSED = 111, + /// Host is down + EHOSTDOWN = 112, + /// No route to host + EHOSTUNREACH = 113, + /// Operation already in progress + EALREADY = 114, + /// Operation now in progress + EINPROGRESS = 115, + /// Stale file handle + ESTALE = 116, + /// Structure needs cleaning + EUCLEAN = 117, + /// Not a XENIX named type file + ENOTNAM = 118, + /// No XENIX semaphores available + ENAVAIL = 119, + /// Is a named type file + EISNAM = 120, + /// Remote I/O error + EREMOTEIO = 121, + /// Disk quota exceeded + EDQUOT = 122, + /// No medium found + ENOMEDIUM = 123, + /// Wrong medium type + EMEDIUMTYPE = 124, + /// Operation canceled + ECANCELED = 125, + /// Required key not available + ENOKEY = 126, + /// Key has expired + EKEYEXPIRED = 127, + /// Key has been revoked + EKEYREVOKED = 128, + /// Key was rejected by service + EKEYREJECTED = 129, + /// Owner died + EOWNERDEAD = 130, + /// State not recoverable + ENOTRECOVERABLE = 131, + /// Operation not possible due to RF-kill + ERFKILL = 132, + /// Memory page has hardware error + EHWPOISON = 133, + /// Resource temporarily unavailable + EAGAIN = 134, + /// Unexpected EOF + EEOF = 135, + /// Invalid data + EINVALDAT = 136, + /// Write zero + EWRZERO = 137, +} + +impl TryFrom for Errno { + type Error = i32; + + fn try_from(value: i32) -> Result { + use Errno::*; + match value { + 1 => Ok(EPERM), + 2 => Ok(ENOENT), + 3 => Ok(ESRCH), + 4 => Ok(EINTR), + 5 => Ok(EIO), + 6 => Ok(ENXIO), + 7 => Ok(E2BIG), + 8 => Ok(ENOEXEC), + 9 => Ok(EBADF), + 10 => Ok(ECHILD), + 11 => Ok(EWOULDBLOCK), + 12 => Ok(ENOMEM), + 13 => Ok(EACCES), + 14 => Ok(EFAULT), + 15 => Ok(ENOTBLK), + 16 => Ok(EBUSY), + 17 => Ok(EEXIST), + 18 => Ok(EXDEV), + 19 => Ok(ENODEV), + 20 => Ok(ENOTDIR), + 21 => Ok(EISDIR), + 22 => Ok(EINVAL), + 23 => Ok(ENFILE), + 24 => Ok(EMFILE), + 25 => Ok(ENOTTY), + 26 => Ok(ETXTBSY), + 27 => Ok(EFBIG), + 28 => Ok(ENOSPC), + 29 => Ok(ESPIPE), + 30 => Ok(EROFS), + 31 => Ok(EMLINK), + 32 => Ok(EPIPE), + 33 => Ok(EDOM), + 34 => Ok(ERANGE), + 35 => Ok(EDEADLK), + 36 => Ok(ENAMETOOLONG), + 37 => Ok(ENOLCK), + 38 => Ok(ENOSYS), + 39 => Ok(ENOTEMPTY), + 40 => Ok(ELOOP), + 42 => Ok(ENOMSG), + 43 => Ok(EIDRM), + 44 => Ok(ECHRNG), + 45 => Ok(EL2NSYNC), + 46 => Ok(EL3HLT), + 47 => Ok(EL3RST), + 48 => Ok(ELNRNG), + 49 => Ok(EUNATCH), + 50 => Ok(ENOCSI), + 51 => Ok(EL2HLT), + 52 => Ok(EBADE), + 53 => Ok(EBADR), + 54 => Ok(EXFULL), + 55 => Ok(ENOANO), + 56 => Ok(EBADRQC), + 57 => Ok(EBADSLT), + 59 => Ok(EBFONT), + 60 => Ok(ENOSTR), + 61 => Ok(ENODATA), + 62 => Ok(ETIME), + 63 => Ok(ENOSR), + 64 => Ok(ENONET), + 65 => Ok(ENOPKG), + 66 => Ok(EREMOTE), + 67 => Ok(ENOLINK), + 68 => Ok(EADV), + 69 => Ok(ESRMNT), + 70 => Ok(ECOMM), + 71 => Ok(EPROTO), + 72 => Ok(EMULTIHOP), + 73 => Ok(EDOTDOT), + 74 => Ok(EBADMSG), + 75 => Ok(EOVERFLOW), + 76 => Ok(ENOTUNIQ), + 77 => Ok(EBADFD), + 78 => Ok(EREMCHG), + 79 => Ok(ELIBACC), + 80 => Ok(ELIBBAD), + 81 => Ok(ELIBSCN), + 82 => Ok(ELIBMAX), + 83 => Ok(ELIBEXEC), + 84 => Ok(EILSEQ), + 85 => Ok(ERESTART), + 86 => Ok(ESTRPIPE), + 87 => Ok(EUSERS), + 88 => Ok(ENOTSOCK), + 89 => Ok(EDESTADDRREQ), + 90 => Ok(EMSGSIZE), + 91 => Ok(EPROTOTYPE), + 92 => Ok(ENOPROTOOPT), + 93 => Ok(EPROTONOSUPPORT), + 94 => Ok(ESOCKTNOSUPPORT), + 95 => Ok(ENOTSUP), + 96 => Ok(EPFNOSUPPORT), + 97 => Ok(EAFNOSUPPORT), + 98 => Ok(EADDRINUSE), + 99 => Ok(EADDRNOTAVAIL), + 100 => Ok(ENETDOWN), + 101 => Ok(ENETUNREACH), + 102 => Ok(ENETRESET), + 103 => Ok(ECONNABORTED), + 104 => Ok(ECONNRESET), + 105 => Ok(ENOBUFS), + 106 => Ok(EISCONN), + 107 => Ok(ENOTCONN), + 108 => Ok(ESHUTDOWN), + 109 => Ok(ETOOMANYREFS), + 110 => Ok(ETIMEDOUT), + 111 => Ok(ECONNREFUSED), + 112 => Ok(EHOSTDOWN), + 113 => Ok(EHOSTUNREACH), + 114 => Ok(EALREADY), + 115 => Ok(EINPROGRESS), + 116 => Ok(ESTALE), + 117 => Ok(EUCLEAN), + 118 => Ok(ENOTNAM), + 119 => Ok(ENAVAIL), + 120 => Ok(EISNAM), + 121 => Ok(EREMOTEIO), + 122 => Ok(EDQUOT), + 123 => Ok(ENOMEDIUM), + 124 => Ok(EMEDIUMTYPE), + 125 => Ok(ECANCELED), + 126 => Ok(ENOKEY), + 127 => Ok(EKEYEXPIRED), + 128 => Ok(EKEYREVOKED), + 129 => Ok(EKEYREJECTED), + 130 => Ok(EOWNERDEAD), + 131 => Ok(ENOTRECOVERABLE), + 132 => Ok(ERFKILL), + 133 => Ok(EHWPOISON), + 134 => Ok(EAGAIN), + 135 => Ok(EEOF), + 136 => Ok(EINVALDAT), + 137 => Ok(EWRZERO), + x => Err(x), + } + } +} + +impl Display for Errno { + fn fmt(&self, f: &mut Formatter<'_>) -> Result<(), fmt::Error> { + use Errno::*; + let errno_name = match self { + EPERM => "EPERM", + ENOENT => "ENOENT", + ESRCH => "ESRCH", + EINTR => "EINTR", + EIO => "EIO", + ENXIO => "ENXIO", + E2BIG => "E2BIG", + ENOEXEC => "ENOEXEC", + EBADF => "EBADF", + ECHILD => "ECHILD", + EAGAIN => "EAGAIN", + EWOULDBLOCK => "EWOULDBLOCK", + ENOMEM => "ENOMEM", + EACCES => "EACCES", + EFAULT => "EFAULT", + ENOTBLK => "ENOTBLK", + EBUSY => "EBUSY", + EEXIST => "EEXIST", + EXDEV => "EXDEV", + ENODEV => "ENODEV", + ENOTDIR => "ENOTDIR", + EISDIR => "EISDIR", + EINVAL => "EINVAL", + ENFILE => "ENFILE", + EMFILE => "EMFILE", + ENOTTY => "ENOTTY", + ETXTBSY => "ETXTBSY", + EFBIG => "EFBIG", + ENOSPC => "ENOSPC", + ESPIPE => "ESPIPE", + EROFS => "EROFS", + EMLINK => "EMLINK", + EPIPE => "EPIPE", + EDOM => "EDOM", + ERANGE => "ERANGE", + EDEADLK => "EDEADLK", + ENAMETOOLONG => "ENAMETOOLONG", + ENOLCK => "ENOLCK", + ENOSYS => "ENOSYS", + ENOTEMPTY => "ENOTEMPTY", + ELOOP => "ELOOP", + ENOMSG => "ENOMSG", + EIDRM => "EIDRM", + ECHRNG => "ECHRNG", + EL2NSYNC => "EL2NSYNC", + EL3HLT => "EL3HLT", + EL3RST => "EL3RST", + ELNRNG => "ELNRNG", + EUNATCH => "EUNATCH", + ENOCSI => "ENOCSI", + EL2HLT => "EL2HLT", + EBADE => "EBADE", + EBADR => "EBADR", + EXFULL => "EXFULL", + ENOANO => "ENOANO", + EBADRQC => "EBADRQC", + EBADSLT => "EBADSLT", + EBFONT => "EBFONT", + ENOSTR => "ENOSTR", + ENODATA => "ENODATA", + ETIME => "ETIME", + ENOSR => "ENOSR", + ENONET => "ENONET", + ENOPKG => "ENOPKG", + EREMOTE => "EREMOTE", + ENOLINK => "ENOLINK", + EADV => "EADV", + ESRMNT => "ESRMNT", + ECOMM => "ECOMM", + EPROTO => "EPROTO", + EMULTIHOP => "EMULTIHOP", + EDOTDOT => "EDOTDOT", + EBADMSG => "EBADMSG", + EOVERFLOW => "EOVERFLOW", + ENOTUNIQ => "ENOTUNIQ", + EBADFD => "EBADFD", + EREMCHG => "EREMCHG", + ELIBACC => "ELIBACC", + ELIBBAD => "ELIBBAD", + ELIBSCN => "ELIBSCN", + ELIBMAX => "ELIBMAX", + ELIBEXEC => "ELIBEXEC", + EILSEQ => "EILSEQ", + ERESTART => "ERESTART", + ESTRPIPE => "ESTRPIPE", + EUSERS => "EUSERS", + ENOTSOCK => "ENOTSOCK", + EDESTADDRREQ => "EDESTADDRREQ", + EMSGSIZE => "EMSGSIZE", + EPROTOTYPE => "EPROTOTYPE", + ENOPROTOOPT => "ENOPROTOOPT", + EPROTONOSUPPORT => "EPROTONOSUPPORT", + ESOCKTNOSUPPORT => "ESOCKTNOSUPPORT", + ENOTSUP => "ENOTSUP", + EPFNOSUPPORT => "EPFNOSUPPORT", + EAFNOSUPPORT => "EAFNOSUPPORT", + EADDRINUSE => "EADDRINUSE", + EADDRNOTAVAIL => "EADDRNOTAVAIL", + ENETDOWN => "ENETDOWN", + ENETUNREACH => "ENETUNREACH", + ENETRESET => "ENETRESET", + ECONNABORTED => "ECONNABORTED", + ECONNRESET => "ECONNRESET", + ENOBUFS => "ENOBUFS", + EISCONN => "EISCONN", + ENOTCONN => "ENOTCONN", + ESHUTDOWN => "ESHUTDOWN", + ETOOMANYREFS => "ETOOMANYREFS", + ETIMEDOUT => "ETIMEDOUT", + ECONNREFUSED => "ECONNREFUSED", + EHOSTDOWN => "EHOSTDOWN", + EHOSTUNREACH => "EHOSTUNREACH", + EALREADY => "EALREADY", + EINPROGRESS => "EINPROGRESS", + ESTALE => "ESTALE", + EUCLEAN => "EUCLEAN", + ENOTNAM => "ENOTNAM", + ENAVAIL => "ENAVAIL", + EISNAM => "EISNAM", + EREMOTEIO => "EREMOTEIO", + EDQUOT => "EDQUOT", + ENOMEDIUM => "ENOMEDIUM", + EMEDIUMTYPE => "EMEDIUMTYPE", + ECANCELED => "ECANCELED", + ENOKEY => "ENOKEY", + EKEYEXPIRED => "EKEYEXPIRED", + EKEYREVOKED => "EKEYREVOKED", + EKEYREJECTED => "EKEYREJECTED", + EOWNERDEAD => "EOWNERDEAD", + ENOTRECOVERABLE => "ENOTRECOVERABLE", + ERFKILL => "ERFKILL", + EHWPOISON => "EHWPOISON", + EEOF => "EEOF", + EINVALDAT => "EINVALDAT", + EWRZERO => "EWRZERO", + }; + f.write_str(errno_name) + } +} diff --git a/src/ipc_dump/file_rpc.rs b/src/ipc_dump/file_rpc.rs new file mode 100644 index 0000000..962001e --- /dev/null +++ b/src/ipc_dump/file_rpc.rs @@ -0,0 +1,195 @@ +use core::fmt::Display; + +use alloc::vec; +use alloc::vec::Vec; +use bitflags::bitflags; +use serde::{Deserialize, Serialize}; + +use super::{ + errno::Errno, + message::DissectedMessage, + rpc_header::{RpcHeader, RpcMessageType}, +}; + +#[derive(Deserialize, Serialize, Clone, Copy, Debug)] +pub enum SeekFrom { + Start(u64), + End(i64), + Current(i64), +} + +bitflags! { + #[derive(Serialize, Deserialize, Clone, Copy, Debug)] + pub struct PollEvents: u16 { + const POLLIN = 1<<0 | 1<<1; + const POLLRDNORM = 1<<0; + const POLLRDBAND = 1<<1; + const POLLPRI = 1<<2; + const POLLOUT = 1<<3; + const POLLWRNORM = 1<<3; + const POLLWRBAND = 1<<4; + const POLLERR = 1<<5; + const POLLHUP = 1<<6; + const POLLNVAL = 1<<7; + } +} + +pub enum FileRpcCall { + Read { fd: u64, len: usize }, + Write { fd: u64 }, + Close { fd: u64 }, + Size { fd: u64 }, + Dup { fd: u64 }, + RegisterPoll { fd: u64, events: PollEvents }, + Poll { poll_id: u64 }, + CancelPoll { poll_id: u64 }, + Seek { fd: u64, pos: SeekFrom }, + Invalid, +} + +pub enum FileRpcReturn { + Read(Result<(), Errno>), + Write(Result<(), Errno>), + Close(Result<(), Errno>), + Size(Result), + Dup(Result), + RegisterPoll(u64), + Poll(PollEvents), + CancelPoll, + Seek(Result), + Invalid, +} + +pub enum FileRpcMessage { + Call(FileRpcCall), + Return(FileRpcReturn), +} + +impl FileRpcMessage { + pub fn dissect(buffer: &[u8], message: &DissectedMessage) -> (Self, Vec) { + let rpc_header = message.get_l1(); + match rpc_header.typ { + RpcMessageType::Call => { + let mut rem_data = vec![]; + let call = match rpc_header.func { + 0 => { + let (fd, len) = postcard::from_bytes(buffer).unwrap(); + FileRpcCall::Read { fd, len } + } + 1 => { + let (fd, data) = postcard::from_bytes(buffer).unwrap(); + rem_data = data; + FileRpcCall::Write { fd } + } + 2 => { + let fd = postcard::from_bytes(buffer).unwrap(); + FileRpcCall::Close { fd } + } + 3 => { + let fd = postcard::from_bytes(buffer).unwrap(); + FileRpcCall::Size { fd } + } + 4 => { + let fd = postcard::from_bytes(buffer).unwrap(); + FileRpcCall::Dup { fd } + } + 5 => { + let (fd, events) = postcard::from_bytes(buffer).unwrap(); + FileRpcCall::RegisterPoll { fd, events } + } + 6 => { + let poll_id = postcard::from_bytes(buffer).unwrap(); + FileRpcCall::Poll { poll_id } + } + 7 => { + let poll_id = postcard::from_bytes(buffer).unwrap(); + FileRpcCall::CancelPoll { poll_id } + } + 8 => { + let (fd, pos) = postcard::from_bytes(buffer).unwrap(); + FileRpcCall::Seek { fd, pos } + } + _ => { + rem_data = buffer.to_vec(); + FileRpcCall::Invalid + } + }; + (Self::Call(call), rem_data) + } + RpcMessageType::Return => { + let mut rem_data = vec![]; + let call = match rpc_header.func { + 0 => { + let ret = postcard::from_bytes(buffer).unwrap(); + match ret { + Ok(data) => { + rem_data = data; + FileRpcReturn::Read(Ok(())) + } + Err(e) => FileRpcReturn::Read(Err(e)), + } + } + 1 => FileRpcReturn::Write(postcard::from_bytes(buffer).unwrap()), + 2 => FileRpcReturn::Close(postcard::from_bytes(buffer).unwrap()), + 3 => FileRpcReturn::Size(postcard::from_bytes(buffer).unwrap()), + 4 => FileRpcReturn::Dup(postcard::from_bytes(buffer).unwrap()), + 5 => FileRpcReturn::RegisterPoll(postcard::from_bytes(buffer).unwrap()), + 6 => FileRpcReturn::Poll(postcard::from_bytes(buffer).unwrap()), + 7 => FileRpcReturn::CancelPoll, + 8 => FileRpcReturn::Seek(postcard::from_bytes(buffer).unwrap()), + _ => { + rem_data = buffer.to_vec(); + FileRpcReturn::Invalid + } + }; + (Self::Return(call), rem_data) + } + } + } +} + +impl Display for FileRpcMessage { + fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { + match self { + Self::Call(call) => match call { + FileRpcCall::Read { fd, len } => { + f.write_fmt(format_args!("Read {len:#x} bytes from FD {fd:#x}"))?; + } + FileRpcCall::Write { fd } => f.write_fmt(format_args!("Write to FD {fd:#x}"))?, + FileRpcCall::Close { fd } => f.write_fmt(format_args!("Close FD {fd:#x}"))?, + FileRpcCall::Size { fd } => { + f.write_fmt(format_args!("Get size of FD {fd:#x}"))?; + } + FileRpcCall::Dup { fd } => f.write_fmt(format_args!("Duplicate FD {fd:#x}"))?, + FileRpcCall::RegisterPoll { fd, events } => f.write_fmt(format_args!( + "Register a poll for FD {fd:#x} for events {events:?}" + ))?, + FileRpcCall::Poll { poll_id } => { + f.write_fmt(format_args!("Poll on poll ID {poll_id}"))?; + } + FileRpcCall::CancelPoll { poll_id } => { + f.write_fmt(format_args!("Cancel poll with ID {poll_id}"))?; + } + FileRpcCall::Seek { fd, pos } => { + f.write_fmt(format_args!("Seek FD {fd:#x} to position {pos:?}"))?; + } + FileRpcCall::Invalid => f.write_fmt(format_args!("Invalid call!"))?, + }, + Self::Return(ret) => match ret { + FileRpcReturn::Read(ret) => f.write_fmt(format_args!("Read return {ret:?}"))?, + FileRpcReturn::Write(ret) => f.write_fmt(format_args!("Write return {ret:?}"))?, + FileRpcReturn::Close(ret) => f.write_fmt(format_args!("Close return {ret:?}"))?, + FileRpcReturn::Size(ret) => f.write_fmt(format_args!("Size return {ret:?}"))?, + FileRpcReturn::Dup(ret) => f.write_fmt(format_args!("Duplicate return {ret:?}"))?, + FileRpcReturn::RegisterPoll(ret) => { + f.write_fmt(format_args!("Poll register return {ret}"))?; + } + FileRpcReturn::Poll(ret) => f.write_fmt(format_args!("Poll return {ret:?}"))?, + FileRpcReturn::CancelPoll => f.write_fmt(format_args!("Cancel poll return"))?, + FileRpcReturn::Seek(ret) => f.write_fmt(format_args!("Seek return {ret:?}"))?, + FileRpcReturn::Invalid => f.write_fmt(format_args!("Invalid return!"))?, + }, + }; + Ok(()) + } +} diff --git a/src/ipc_dump/hexdump.rs b/src/ipc_dump/hexdump.rs new file mode 100644 index 0000000..72a2b29 --- /dev/null +++ b/src/ipc_dump/hexdump.rs @@ -0,0 +1,68 @@ +use alloc::fmt::Display; +use cast::{u32, usize}; + +pub struct HexdumpLayer<'a> { + data: &'a [u8], + max_len: usize, +} + +impl<'a> HexdumpLayer<'a> { + pub fn new(data: &'a [u8], max_len: usize) -> Self { + Self { data, max_len } + } +} + +impl Display for HexdumpLayer<'_> { + fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { + let hexdump_len = usize::min(self.data.len(), self.max_len); + let data = &self.data[0..hexdump_len]; + let num_groups = data.len().div_ceil(16); + let offset_char_width = if num_groups == 0 { + 1 + } else if num_groups == 1 { + 2 + } else { + usize(num_groups.next_power_of_two().ilog2().div_ceil(4) + 1) + }; + let mut chunk_iter = data.chunks_exact(16); + for (group_num, chunk) in (&mut chunk_iter).enumerate() { + if group_num == 0 { + f.write_fmt(format_args!("{:01$}:", 0, offset_char_width))?; + } else { + f.write_fmt(format_args!("\n{:01$}0:", group_num, offset_char_width - 1))?; + } + for &byte in chunk { + f.write_fmt(format_args!(" {byte:02x}"))?; + } + f.write_str(" |")?; + for &byte in chunk { + let ch = char::from_u32(u32(byte)).unwrap_or('.'); + let ch = if ch.is_ascii() && !ch.is_ascii_control() { ch } else { '.' }; + f.write_fmt(format_args!("{ch}"))?; + } + } + let chunk = chunk_iter.remainder(); + if !chunk.is_empty() { + let group_num = num_groups - 1; + if group_num == 0 { + f.write_fmt(format_args!("{:01$}:", 0, offset_char_width))?; + } else { + f.write_fmt(format_args!("\n{:01$}0:", group_num, offset_char_width - 1))?; + } + for &byte in chunk { + f.write_fmt(format_args!(" {byte:02x}"))?; + } + let missing_bytes = 16 - chunk.len(); + for _ in 0..missing_bytes { + f.write_str(" ")?; + } + f.write_str(" |")?; + for &byte in chunk { + let ch = char::from_u32(u32(byte)).unwrap_or('.'); + let ch = if ch.is_ascii() && !ch.is_ascii_control() { ch } else { '.' }; + f.write_fmt(format_args!("{ch}"))?; + } + } + Ok(()) + } +} diff --git a/src/ipc_dump/interrupt_proto.rs b/src/ipc_dump/interrupt_proto.rs new file mode 100644 index 0000000..3ee3e85 --- /dev/null +++ b/src/ipc_dump/interrupt_proto.rs @@ -0,0 +1,23 @@ +use cast::usize; +use core::fmt::Display; + +pub struct InterruptProto { + irq: u8, +} +impl InterruptProto { + pub fn dissect(buffer: &[u8]) -> Self { + Self { irq: buffer[0] } + } +} + +static IRQ_NAMES: [&str; 16] = [ + "Timer", "Keyboard", "Cascade", "COM2", "COM1", "LPT2", "Floppy", "LPT1", "RTC", "Free1", + "Free2", "Free3", "Mouse", "FPU", "ATA1", "ATA2", +]; + +impl Display for InterruptProto { + fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { + let irq_name = *IRQ_NAMES.get(usize(self.irq)).unwrap_or(&"Invalid"); + f.write_fmt(format_args!("IRQ {} ({})", self.irq, irq_name)) + } +} diff --git a/src/ipc_dump/message.rs b/src/ipc_dump/message.rs new file mode 100644 index 0000000..a46dd5f --- /dev/null +++ b/src/ipc_dump/message.rs @@ -0,0 +1,190 @@ +use alloc::fmt::{self, Display}; +use alloc::string::{String, ToString}; + +#[derive(Debug, Clone, Copy, PartialEq, Eq)] +pub enum IpcFrom { + Kernel, + Process(usize), +} + +impl IpcFrom { + pub fn as_pid(self) -> usize { + match self { + Self::Kernel => usize::MAX, + Self::Process(pid) => pid, + } + } +} + +impl Display for IpcFrom { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + match self { + Self::Kernel => f.write_str("Kernel"), + Self::Process(pid) => f.write_fmt(format_args!("{pid}")), + } + } +} + +pub trait MessageHeader: Display {} +impl MessageHeader for T {} + +pub struct DissectedMessage { + pub ipc_from: IpcFrom, + pub ipc_dest: usize, + pub ipc_proto: u16, + l1: L1, + l2: L2, + l3: L3, +} + +pub struct NoHeader; + +impl DissectedMessage { + pub fn new(ipc_from: IpcFrom, ipc_dest: usize, ipc_proto: u16) -> Self { + Self { ipc_from, ipc_dest, ipc_proto, l1: NoHeader, l2: NoHeader, l3: NoHeader } + } + + pub fn set_l1(self, l1: T) -> DissectedMessage { + DissectedMessage { + ipc_from: self.ipc_from, + ipc_dest: self.ipc_dest, + ipc_proto: self.ipc_proto, + l1, + l2: NoHeader, + l3: NoHeader, + } + } +} + +impl DissectedMessage { + pub fn get_l1(&self) -> &L1 { + &self.l1 + } + + pub fn set_l2(self, l2: T) -> DissectedMessage { + DissectedMessage { + ipc_from: self.ipc_from, + ipc_dest: self.ipc_dest, + ipc_proto: self.ipc_proto, + l1: self.l1, + l2, + l3: NoHeader, + } + } +} + +impl DissectedMessage { + pub fn get_l2(&self) -> &L2 { + &self.l2 + } + + pub fn set_l3(self, l3: T) -> DissectedMessage { + DissectedMessage { + ipc_from: self.ipc_from, + ipc_dest: self.ipc_dest, + ipc_proto: self.ipc_proto, + l1: self.l1, + l2: self.l2, + l3, + } + } +} + +impl DissectedMessage { + pub fn get_l3(&self) -> &L3 { + &self.l3 + } +} + +impl DissectedMessage { + fn fmt_ipc_header(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + f.write_fmt(format_args!( + "IPC: {} sending to {}, protocol {}", + self.ipc_from, self.ipc_dest, self.ipc_proto, + )) + } +} + +impl DissectedMessage { + fn fmt_l1(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + let l1_raw = self.l1.to_string(); + let l1_indented = + l1_raw.split('\n').map(|line| " ".to_string() + line + "\n").collect::(); + f.write_str(l1_indented.strip_suffix("\n").unwrap()) + } +} + +impl DissectedMessage { + fn fmt_l2(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + let l2_raw = self.l2.to_string(); + let l2_indented = + l2_raw.split('\n').map(|line| " ".to_string() + line + "\n").collect::(); + f.write_str(l2_indented.strip_suffix("\n").unwrap()) + } +} + +impl DissectedMessage { + fn fmt_l3(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + let l3_raw = self.l3.to_string(); + let l3_indented = l3_raw + .split('\n') + .map(|line| " ".to_string() + line + "\n") + .collect::(); + f.write_str(l3_indented.strip_suffix("\n").unwrap()) + } +} + +impl Display for DissectedMessage { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + f.write_str("-----------------------------------------\n")?; + self.fmt_ipc_header(f)?; + f.write_str("\n")?; + f.write_str("-----------------------------------------\n")?; + Ok(()) + } +} + +impl Display for DissectedMessage { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + f.write_str("-----------------------------------------\n")?; + self.fmt_ipc_header(f)?; + f.write_str("\n")?; + self.fmt_l1(f)?; + f.write_str("\n")?; + f.write_str("-----------------------------------------\n")?; + Ok(()) + } +} + +impl Display for DissectedMessage { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + f.write_str("-----------------------------------------\n")?; + self.fmt_ipc_header(f)?; + f.write_str("\n")?; + self.fmt_l1(f)?; + f.write_str("\n")?; + self.fmt_l2(f)?; + f.write_str("\n")?; + f.write_str("-----------------------------------------\n")?; + Ok(()) + } +} + +impl Display + for DissectedMessage +{ + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + f.write_str("-----------------------------------------\n")?; + self.fmt_ipc_header(f)?; + f.write_str("\n")?; + self.fmt_l1(f)?; + f.write_str("\n")?; + self.fmt_l2(f)?; + f.write_str("\n")?; + self.fmt_l3(f)?; + f.write_str("\n")?; + f.write_str("-----------------------------------------\n")?; + + Ok(()) + } +} diff --git a/src/ipc_dump/mod.rs b/src/ipc_dump/mod.rs new file mode 100644 index 0000000..147ec22 --- /dev/null +++ b/src/ipc_dump/mod.rs @@ -0,0 +1,66 @@ +#![allow(clippy::arithmetic_side_effects, reason = "temp for debugging")] +#![allow(clippy::indexing_slicing, reason = "temp for debugging")] +#![allow(clippy::unwrap_used, reason = "temp for debugging")] + +mod errno; +mod file_rpc; +mod hexdump; +mod interrupt_proto; +mod message; +mod proc_man_rpc; +mod rpc_header; +mod syslog_ipc; +mod syslog_msg; +mod syslog_rpc; + +use file_rpc::FileRpcMessage; +use hexdump::HexdumpLayer; +use interrupt_proto::InterruptProto; +use message::{DissectedMessage, IpcFrom}; +use proc_man_rpc::ProcManRpcMessage; +use rpc_header::RpcHeader; +use syslog_ipc::SyslogIpc; +use syslog_rpc::SyslogRpcMessage; + +use crate::println; + +pub fn dump_ipc_message(from: usize, dest: usize, buffer: &[u8]) { + let ipc_proto = u16::from_ne_bytes([buffer[0], buffer[1]]); + let buffer = &buffer[2..]; + let from = if from == usize::MAX { IpcFrom::Kernel } else { IpcFrom::Process(from) }; + let msg = DissectedMessage::new(from, dest, ipc_proto); + if ipc_proto == 0 { + let (rpc_header, buffer) = RpcHeader::dissect(buffer, &msg); + let msg = msg.set_l1(rpc_header); + if msg.get_l1().proto == 1 { + let (file_rpc, rem_data) = FileRpcMessage::dissect(buffer, &msg); + let msg = msg.set_l2(file_rpc); + if rem_data.is_empty() { + println!("{msg}"); + } else { + let msg = msg.set_l3(HexdumpLayer::new(&rem_data, 128)); + println!("{msg}"); + } + } else if msg.get_l1().proto == 5 { + let syslog_rpc = SyslogRpcMessage::dissect(buffer, &msg); + let msg = msg.set_l2(syslog_rpc); + println!("{msg}"); + } else if msg.get_l1().proto == 8 { + let syslog_rpc = ProcManRpcMessage::dissect(buffer, &msg); + let msg = msg.set_l2(syslog_rpc); + println!("{msg}"); + } else { + let msg = msg.set_l2(HexdumpLayer::new(buffer, 128)); + println!("{msg}"); + } + } else if ipc_proto == 1 { + let msg = msg.set_l1(SyslogIpc::dissect(buffer)); + println!("{msg}"); + } else if ipc_proto == 2 { + let msg = msg.set_l1(InterruptProto::dissect(buffer)); + println!("{msg}"); + } else { + let msg = msg.set_l1(HexdumpLayer::new(buffer, 128)); + println!("{msg}"); + } +} diff --git a/src/ipc_dump/proc_man_rpc.rs b/src/ipc_dump/proc_man_rpc.rs new file mode 100644 index 0000000..18f40b5 --- /dev/null +++ b/src/ipc_dump/proc_man_rpc.rs @@ -0,0 +1,207 @@ +use core::fmt::{Debug, Display}; + +use alloc::string::String; +use alloc::vec::Vec; +use serde::{Deserialize, Serialize}; + +use super::{ + errno::Errno, + message::DissectedMessage, + rpc_header::{RpcHeader, RpcMessageType}, +}; + +#[derive(Serialize, Deserialize, Debug)] +pub struct WaitResult { + pub pid: u64, + pub exit_code: u8, +} + +#[derive(Clone, Copy, Debug, Serialize, Deserialize)] +pub enum ProcessStatus { + Running, + Exited(u8), +} + +#[derive(Clone, Debug, Serialize, Deserialize)] +pub struct Process { + pub pid: u64, + pub stdio: [Option<(u64, u64)>; 3], + pub cli_args: Vec, + pub status: ProcessStatus, + pub parent: Option, + pub children: Vec, +} + +#[derive(Deserialize)] +pub struct OsString { + #[expect(unused, reason = "this is a dummy for deserialization")] + kind: u8, + str: String, +} + +impl Debug for OsString { + fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { + f.write_fmt(format_args!("{:?}", self.str)) + } +} + +pub enum ProcManRpcCall { + NewProc { pid: u64, parent: Option }, + SetStdio { pid: u64, stdio: [Option<(u64, u64)>; 3] }, + GetStdio, + SetCliArgs { pid: u64, args: Vec }, + GetCliArgs, + Exit { pid: u64, code: u8 }, + Wait { pid: u64, block: bool }, + GetProcesses, + SetCwd { pid: u64, path: String }, + GetCwd, + Invalid, +} + +pub enum ProcManRpcReturn { + NewProc(Result<(), Errno>), + SetStdio(Result<(), Errno>), + GetStdio([Option<(u64, u64)>; 3]), + SetCliArgs(Result<(), Errno>), + GetCliArgs(Vec), + Wait(Result), + GetProcesses( + #[expect(unused, reason = "currently we do not use the full parsed message in output")] + Vec, + ), + SetCwd(Result<(), Errno>), + GetCwd(String), + Invalid, +} + +pub enum ProcManRpcMessage { + Call(ProcManRpcCall), + Return(ProcManRpcReturn), +} + +impl ProcManRpcMessage { + pub fn dissect(buffer: &[u8], message: &DissectedMessage) -> Self { + let rpc_header = message.get_l1(); + match rpc_header.typ { + RpcMessageType::Call => { + let call = match rpc_header.func { + 0 => { + let (pid, stdio) = postcard::from_bytes(buffer).unwrap(); + ProcManRpcCall::SetStdio { pid, stdio } + } + 1 => ProcManRpcCall::GetStdio, + 2 => { + let (pid, args) = postcard::from_bytes(buffer).unwrap(); + ProcManRpcCall::SetCliArgs { pid, args } + } + 3 => ProcManRpcCall::GetCliArgs, + 4 => { + let (pid, code) = postcard::from_bytes(buffer).unwrap(); + ProcManRpcCall::Exit { pid, code } + } + 5 => { + let (pid, block) = postcard::from_bytes(buffer).unwrap(); + ProcManRpcCall::Wait { pid, block } + } + 6 | 7 => { + let (pid, parent) = postcard::from_bytes(buffer).unwrap(); + ProcManRpcCall::NewProc { pid, parent } + } + 8 => ProcManRpcCall::GetProcesses, + 9 => { + let (pid, path) = postcard::from_bytes(buffer).unwrap(); + ProcManRpcCall::SetCwd { pid, path } + } + 10 => ProcManRpcCall::GetCwd, + _ => ProcManRpcCall::Invalid, + }; + Self::Call(call) + } + RpcMessageType::Return => { + let call = match rpc_header.func { + 0 => ProcManRpcReturn::SetStdio(postcard::from_bytes(buffer).unwrap()), + 1 => ProcManRpcReturn::GetStdio(postcard::from_bytes(buffer).unwrap()), + 2 => ProcManRpcReturn::SetCliArgs(postcard::from_bytes(buffer).unwrap()), + 3 => ProcManRpcReturn::GetCliArgs(postcard::from_bytes(buffer).unwrap()), + 5 => ProcManRpcReturn::Wait(postcard::from_bytes(buffer).unwrap()), + 7 => ProcManRpcReturn::NewProc(postcard::from_bytes(buffer).unwrap()), + 8 => ProcManRpcReturn::GetProcesses(postcard::from_bytes(buffer).unwrap()), + 9 => ProcManRpcReturn::SetCwd(postcard::from_bytes(buffer).unwrap()), + 10 => ProcManRpcReturn::GetCwd(postcard::from_bytes(buffer).unwrap()), + _ => ProcManRpcReturn::Invalid, + }; + Self::Return(call) + } + } + } +} + +impl Display for ProcManRpcMessage { + fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { + match self { + Self::Call(call) => match call { + ProcManRpcCall::NewProc { pid, parent } => { + if let Some(parent) = parent { + f.write_fmt(format_args!( + "New process with PID {pid} and parent {parent}" + ))?; + } else { + f.write_fmt(format_args!("New process with PID {pid} and no parent"))?; + } + } + ProcManRpcCall::SetStdio { pid, stdio } => { + f.write_fmt(format_args!("Set PID {pid}'s stdio to {stdio:?}"))?; + } + ProcManRpcCall::GetStdio => f.write_str("Get stdio")?, + ProcManRpcCall::SetCliArgs { pid, args } => { + f.write_fmt(format_args!("Set PID {pid}'s CLI args to {args:?}"))?; + } + ProcManRpcCall::GetCliArgs => f.write_str("Get CLI args")?, + ProcManRpcCall::Exit { pid, code } => { + f.write_fmt(format_args!("PID {pid} exiting with code {code}"))?; + } + ProcManRpcCall::Wait { pid, block } => { + if *block { + f.write_fmt(format_args!("Wait blocking on PID {pid}"))?; + } else { + f.write_fmt(format_args!("Wait nonblocking on PID {pid}"))?; + } + } + ProcManRpcCall::GetProcesses => f.write_str("Get processes")?, + ProcManRpcCall::SetCwd { pid, path } => { + f.write_fmt(format_args!("Set PID {pid}'s CWD to {path}"))?; + } + ProcManRpcCall::GetCwd => f.write_str("Get CWD")?, + ProcManRpcCall::Invalid => f.write_str("Invalid call!")?, + }, + Self::Return(ret) => match ret { + ProcManRpcReturn::NewProc(ret) => { + f.write_fmt(format_args!("New process return {ret:?}"))?; + } + ProcManRpcReturn::SetStdio(ret) => { + f.write_fmt(format_args!("Set stdio return {ret:?}"))?; + } + ProcManRpcReturn::GetStdio(ret) => { + f.write_fmt(format_args!("Get stdio return {ret:?}"))?; + } + ProcManRpcReturn::SetCliArgs(ret) => { + f.write_fmt(format_args!("Set CLI args return {ret:?}"))?; + } + ProcManRpcReturn::GetCliArgs(ret) => { + f.write_fmt(format_args!("Get CLI args return {ret:?}"))?; + } + ProcManRpcReturn::Wait(ret) => f.write_fmt(format_args!("Wait return {ret:?}"))?, + ProcManRpcReturn::GetProcesses(_) => f.write_str("Get processes return")?, + ProcManRpcReturn::SetCwd(ret) => { + f.write_fmt(format_args!("Set CWD return {ret:?}"))?; + } + ProcManRpcReturn::GetCwd(ret) => { + f.write_fmt(format_args!("Get CWD return {ret:?}"))?; + } + ProcManRpcReturn::Invalid => f.write_str("Invalid return!")?, + }, + }; + Ok(()) + } +} diff --git a/src/ipc_dump/rpc_header.rs b/src/ipc_dump/rpc_header.rs new file mode 100644 index 0000000..13794cd --- /dev/null +++ b/src/ipc_dump/rpc_header.rs @@ -0,0 +1,79 @@ +use alloc::fmt::Display; + +use hashbrown::HashMap; +use spin::{Lazy, Mutex}; + +use super::message::DissectedMessage; + +static RPC_CALL_MAP: Lazy>> = + Lazy::new(|| Mutex::new(HashMap::new())); + +#[derive(Debug, Copy, Clone, PartialEq, Eq)] +pub enum RpcMessageType { + Call, + Return, +} + +pub struct RpcHeader { + pub typ: RpcMessageType, + pub call_id: u64, + pub proto: u16, + pub func: u16, + //from: IpcFrom, + //dest: usize, +} + +impl RpcHeader { + pub fn dissect<'a>(buffer: &'a [u8], message: &DissectedMessage) -> (Self, &'a [u8]) { + let typ = match buffer[0] { + 0 => RpcMessageType::Call, + 1 => RpcMessageType::Return, + _ => panic!(), + }; + let call_id = u64::from_ne_bytes(buffer[1..9].try_into().unwrap()); + let (proto, func) = if typ == RpcMessageType::Call { + let proto = u16::from_ne_bytes(buffer[9..11].try_into().unwrap()); + let func = u16::from_ne_bytes(buffer[11..13].try_into().unwrap()); + RPC_CALL_MAP.lock().insert((message.ipc_from.as_pid(), call_id), (proto, func)); + (proto, func) + } else if let Some((proto, func)) = RPC_CALL_MAP.lock().remove(&(message.ipc_dest, call_id)) + { + (proto, func) + } else { + (u16::MAX, u16::MAX) + }; + let slf = Self { + typ, + call_id, + proto, + func, + //from: message.ipc_from, + //dest: message.ipc_dest, + }; + (slf, &buffer[13..]) + } +} + +impl Display for RpcHeader { + fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { + match self.typ { + RpcMessageType::Call => { + f.write_fmt(format_args!( + "RPC: call w/ID {}, protocol {}, function {}", + self.call_id, self.proto, self.func + ))?; + } + RpcMessageType::Return => { + if self.proto == u16::MAX && self.func == u16::MAX { + f.write_fmt(format_args!("RPC: return for call {} (Not seen!)", self.call_id))?; + } else { + f.write_fmt(format_args!( + "RPC: return for call {} (proto {}, func {})", + self.call_id, self.proto, self.func + ))?; + } + } + } + Ok(()) + } +} diff --git a/src/ipc_dump/syslog_ipc.rs b/src/ipc_dump/syslog_ipc.rs new file mode 100644 index 0000000..8f032b6 --- /dev/null +++ b/src/ipc_dump/syslog_ipc.rs @@ -0,0 +1,18 @@ +use core::fmt::Display; + +use super::syslog_msg::SyslogMessage; + +pub struct SyslogIpc { + message: SyslogMessage, +} +impl SyslogIpc { + pub fn dissect(buffer: &[u8]) -> Self { + Self { message: postcard::from_bytes(buffer).unwrap() } + } +} + +impl Display for SyslogIpc { + fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { + f.write_fmt(format_args!("{}", self.message)) + } +} diff --git a/src/ipc_dump/syslog_msg.rs b/src/ipc_dump/syslog_msg.rs new file mode 100644 index 0000000..46044fe --- /dev/null +++ b/src/ipc_dump/syslog_msg.rs @@ -0,0 +1,37 @@ +use core::fmt::Display; + +use alloc::{string::String, vec::Vec}; +use serde::{Deserialize, Serialize}; + +#[derive(Serialize, Deserialize, Clone, Debug)] +pub struct SyslogMessage { + pub from: String, + pub text: Option, + pub binary: Option, +} + +#[derive(Serialize, Deserialize, Clone, Debug)] +pub struct SyslogBinaryMessage { + pub kind: u64, + pub data: Vec, +} + +impl Display for SyslogMessage { + fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { + match (&self.text, &self.binary) { + (None, None) => f.write_fmt(format_args!("Message from {}", self.from))?, + (None, Some(binary)) => f.write_fmt(format_args!( + "Message from {}: kind {}, data {:?}", + self.from, binary.kind, binary.data + ))?, + (Some(text), None) => { + f.write_fmt(format_args!("Message from {}: {}", self.from, text))?; + } + (Some(text), Some(binary)) => f.write_fmt(format_args!( + "Message from {}: {} (kind {}, data {:?})", + self.from, text, binary.kind, binary.data, + ))?, + }; + Ok(()) + } +} diff --git a/src/ipc_dump/syslog_rpc.rs b/src/ipc_dump/syslog_rpc.rs new file mode 100644 index 0000000..1cf6fdd --- /dev/null +++ b/src/ipc_dump/syslog_rpc.rs @@ -0,0 +1,89 @@ +use core::fmt::Display; + +use alloc::string::String; +use alloc::vec::Vec; + +use super::{ + message::DissectedMessage, + rpc_header::{RpcHeader, RpcMessageType}, + syslog_msg::SyslogMessage, +}; + +pub enum SyslogRpcCall { + SendMessage { message: SyslogMessage }, + SubscribeToText, + SubscribeToBinary { message_from: String, kinds: Vec }, + Invalid, +} + +pub enum SyslogRpcReturn { + SendMessage(Result<(), ()>), + SubscribeToText, + SubscribeToBinary, + Invalid, +} + +pub enum SyslogRpcMessage { + Call(SyslogRpcCall), + Return(SyslogRpcReturn), +} + +impl SyslogRpcMessage { + pub fn dissect(buffer: &[u8], message: &DissectedMessage) -> Self { + let rpc_header = message.get_l1(); + match rpc_header.typ { + RpcMessageType::Call => { + let call = match rpc_header.func { + 0 => { + let message = postcard::from_bytes(buffer).unwrap(); + SyslogRpcCall::SendMessage { message } + } + 1 => SyslogRpcCall::SubscribeToText, + 2 => { + let (message_from, kinds) = postcard::from_bytes(buffer).unwrap(); + SyslogRpcCall::SubscribeToBinary { message_from, kinds } + } + _ => SyslogRpcCall::Invalid, + }; + Self::Call(call) + } + RpcMessageType::Return => { + let call = match rpc_header.func { + 0 => SyslogRpcReturn::SendMessage(postcard::from_bytes(buffer).unwrap()), + 1 => SyslogRpcReturn::SubscribeToText, + 2 => SyslogRpcReturn::SubscribeToBinary, + _ => SyslogRpcReturn::Invalid, + }; + Self::Return(call) + } + } + } +} + +impl Display for SyslogRpcMessage { + fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { + match self { + Self::Call(call) => match call { + SyslogRpcCall::SendMessage { message } => { + f.write_fmt(format_args!("{message}"))?; + } + SyslogRpcCall::SubscribeToText => f.write_str("Subscribe to text")?, + SyslogRpcCall::SubscribeToBinary { message_from, kinds } => { + f.write_fmt(format_args!( + "Subscribe to binary from {message_from} with kinds {kinds:?}", + ))?; + } + SyslogRpcCall::Invalid => f.write_str("Invalid call!")?, + }, + Self::Return(ret) => match ret { + SyslogRpcReturn::SendMessage(ret) => { + f.write_fmt(format_args!("Send message return {ret:?}"))?; + } + SyslogRpcReturn::SubscribeToText => f.write_str("Subscribe to text return")?, + SyslogRpcReturn::SubscribeToBinary => f.write_str("Subscribe to binary return")?, + SyslogRpcReturn::Invalid => f.write_str("Invalid return!")?, + }, + }; + Ok(()) + } +} diff --git a/src/main.rs b/src/main.rs index bec0edd..a2ddffd 100644 --- a/src/main.rs +++ b/src/main.rs @@ -74,6 +74,7 @@ extern crate alloc; mod bootinfo; mod gdt; mod interrupts; +mod ipc_dump; mod kernel_heap; mod panic_handler; mod physical_memory;