├── .gitignore ├── .gitlab-ci.yml ├── Cargo.toml ├── LICENSE ├── README.md └── src ├── arch ├── aarch64.rs ├── riscv64.rs ├── x86.rs └── x86_64.rs ├── call.rs ├── data.rs ├── dirent.rs ├── error.rs ├── flag.rs ├── io ├── io.rs ├── mmio.rs ├── mod.rs └── pio.rs ├── lib.rs ├── number.rs ├── scheme ├── generate.sh ├── mod.rs ├── scheme.rs ├── scheme_block.rs ├── scheme_block_mut.rs ├── scheme_mut.rs └── seek.rs ├── schemev2.rs └── sigabi.rs /.gitignore: -------------------------------------------------------------------------------- 1 | Cargo.lock 2 | target 3 | -------------------------------------------------------------------------------- /.gitlab-ci.yml: -------------------------------------------------------------------------------- 1 | image: "redoxos/redoxer" 2 | 3 | stages: 4 | - build 5 | 6 | cache: 7 | paths: 8 | - target/ 9 | 10 | build:linux: 11 | stage: build 12 | script: cargo +nightly build --verbose 13 | 14 | build:redox: 15 | stage: build 16 | script: redoxer build --verbose 17 | -------------------------------------------------------------------------------- /Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "redox_syscall" 3 | version = "0.5.12" 4 | description = "A Rust library to access raw Redox system calls" 5 | license = "MIT" 6 | authors = ["Jeremy Soller "] 7 | repository = "https://gitlab.redox-os.org/redox-os/syscall" 8 | documentation = "https://docs.rs/redox_syscall" 9 | edition = "2021" 10 | 11 | [lib] 12 | name = "syscall" 13 | 14 | [features] 15 | default = ["userspace"] 16 | rustc-dep-of-std = ["core", "bitflags/rustc-dep-of-std"] 17 | userspace = [] 18 | std = [] 19 | 20 | [dependencies] 21 | bitflags = "2.4" 22 | core = { version = "1.0.0", optional = true, package = "rustc-std-workspace-core" } 23 | 24 | [target.'cfg(loom)'.dev-dependencies] 25 | loom = "0.7" 26 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Copyright (c) 2017 Redox OS Developers 2 | 3 | MIT License 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining 6 | a copy of this software and associated documentation files (the 7 | "Software"), to deal in the Software without restriction, including 8 | without limitation the rights to use, copy, modify, merge, publish, 9 | distribute, sublicense, and/or sell copies of the Software, and to 10 | permit persons to whom the Software is furnished to do so, subject to 11 | the following conditions: 12 | 13 | The above copyright notice and this permission notice shall be 14 | included in all copies or substantial portions of the Software. 15 | 16 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 17 | EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 18 | MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 19 | NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE 20 | LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION 21 | OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION 22 | WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 23 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # syscall 2 | [Redox OS](https://gitlab.redox-os.org/redox-os/redox)'s syscall API 3 | 4 | [![MIT licensed](https://img.shields.io/badge/license-MIT-blue.svg)](./LICENSE) 5 | [![crates.io](http://meritbadge.herokuapp.com/redox_syscall)](https://crates.io/crates/redox_syscall) 6 | [![docs.rs](https://docs.rs/redox_syscall/badge.svg)](https://docs.rs/redox_syscall) 7 | -------------------------------------------------------------------------------- /src/arch/aarch64.rs: -------------------------------------------------------------------------------- 1 | use core::{ 2 | mem, 3 | ops::{Deref, DerefMut}, 4 | slice, 5 | }; 6 | 7 | use super::error::{Error, Result}; 8 | 9 | pub const PAGE_SIZE: usize = 4096; 10 | 11 | #[cfg(feature = "userspace")] 12 | macro_rules! syscall { 13 | ($($name:ident($a:ident, $($b:ident, $($c:ident, $($d:ident, $($e:ident, $($f:ident, )?)?)?)?)?);)+) => { 14 | $( 15 | pub unsafe fn $name($a: usize, $($b: usize, $($c: usize, $($d: usize, $($e: usize, $($f: usize)?)?)?)?)?) -> Result { 16 | let ret: usize; 17 | 18 | core::arch::asm!( 19 | "svc 0", 20 | in("x8") $a, 21 | $( 22 | in("x0") $b, 23 | $( 24 | in("x1") $c, 25 | $( 26 | in("x2") $d, 27 | $( 28 | in("x3") $e, 29 | $( 30 | in("x4") $f, 31 | )? 32 | )? 33 | )? 34 | )? 35 | )? 36 | lateout("x0") ret, 37 | options(nostack), 38 | ); 39 | 40 | Error::demux(ret) 41 | } 42 | )+ 43 | }; 44 | } 45 | 46 | #[cfg(feature = "userspace")] 47 | syscall! { 48 | syscall0(a,); 49 | syscall1(a, b,); 50 | syscall2(a, b, c,); 51 | syscall3(a, b, c, d,); 52 | syscall4(a, b, c, d, e,); 53 | syscall5(a, b, c, d, e, f,); 54 | } 55 | 56 | #[derive(Copy, Clone, Debug, Default)] 57 | #[repr(C)] 58 | pub struct IntRegisters { 59 | pub x30: usize, 60 | pub x29: usize, 61 | pub x28: usize, 62 | pub x27: usize, 63 | pub x26: usize, 64 | pub x25: usize, 65 | pub x24: usize, 66 | pub x23: usize, 67 | pub x22: usize, 68 | pub x21: usize, 69 | pub x20: usize, 70 | pub x19: usize, 71 | pub x18: usize, 72 | pub x17: usize, 73 | pub x16: usize, 74 | pub x15: usize, 75 | pub x14: usize, 76 | pub x13: usize, 77 | pub x12: usize, 78 | pub x11: usize, 79 | pub x10: usize, 80 | pub x9: usize, 81 | pub x8: usize, 82 | pub x7: usize, 83 | pub x6: usize, 84 | pub x5: usize, 85 | pub x4: usize, 86 | pub x3: usize, 87 | pub x2: usize, 88 | pub x1: usize, 89 | pub x0: usize, 90 | } 91 | 92 | impl Deref for IntRegisters { 93 | type Target = [u8]; 94 | fn deref(&self) -> &[u8] { 95 | unsafe { 96 | slice::from_raw_parts( 97 | self as *const IntRegisters as *const u8, 98 | mem::size_of::(), 99 | ) 100 | } 101 | } 102 | } 103 | 104 | impl DerefMut for IntRegisters { 105 | fn deref_mut(&mut self) -> &mut [u8] { 106 | unsafe { 107 | slice::from_raw_parts_mut( 108 | self as *mut IntRegisters as *mut u8, 109 | mem::size_of::(), 110 | ) 111 | } 112 | } 113 | } 114 | 115 | #[derive(Clone, Copy, Debug, Default)] 116 | #[repr(C, packed)] 117 | pub struct FloatRegisters { 118 | pub fp_simd_regs: [u128; 32], 119 | pub fpsr: u32, 120 | pub fpcr: u32, 121 | } 122 | 123 | impl Deref for FloatRegisters { 124 | type Target = [u8]; 125 | fn deref(&self) -> &[u8] { 126 | unsafe { 127 | slice::from_raw_parts( 128 | self as *const FloatRegisters as *const u8, 129 | mem::size_of::(), 130 | ) 131 | } 132 | } 133 | } 134 | 135 | impl DerefMut for FloatRegisters { 136 | fn deref_mut(&mut self) -> &mut [u8] { 137 | unsafe { 138 | slice::from_raw_parts_mut( 139 | self as *mut FloatRegisters as *mut u8, 140 | mem::size_of::(), 141 | ) 142 | } 143 | } 144 | } 145 | 146 | #[derive(Clone, Copy, Debug, Default)] 147 | #[repr(C, packed)] 148 | pub struct EnvRegisters { 149 | pub tpidr_el0: usize, 150 | pub tpidrro_el0: usize, 151 | } 152 | impl Deref for EnvRegisters { 153 | type Target = [u8]; 154 | fn deref(&self) -> &[u8] { 155 | unsafe { 156 | slice::from_raw_parts( 157 | self as *const EnvRegisters as *const u8, 158 | mem::size_of::(), 159 | ) 160 | } 161 | } 162 | } 163 | 164 | impl DerefMut for EnvRegisters { 165 | fn deref_mut(&mut self) -> &mut [u8] { 166 | unsafe { 167 | slice::from_raw_parts_mut( 168 | self as *mut EnvRegisters as *mut u8, 169 | mem::size_of::(), 170 | ) 171 | } 172 | } 173 | } 174 | #[derive(Clone, Copy, Debug, Default)] 175 | #[repr(C, packed)] 176 | pub struct Exception { 177 | pub kind: usize, 178 | // TODO 179 | } 180 | impl Deref for Exception { 181 | type Target = [u8]; 182 | fn deref(&self) -> &[u8] { 183 | unsafe { 184 | slice::from_raw_parts( 185 | self as *const Exception as *const u8, 186 | mem::size_of::(), 187 | ) 188 | } 189 | } 190 | } 191 | 192 | impl DerefMut for Exception { 193 | fn deref_mut(&mut self) -> &mut [u8] { 194 | unsafe { 195 | slice::from_raw_parts_mut( 196 | self as *mut Exception as *mut u8, 197 | mem::size_of::(), 198 | ) 199 | } 200 | } 201 | } 202 | -------------------------------------------------------------------------------- /src/arch/riscv64.rs: -------------------------------------------------------------------------------- 1 | use super::error::{Error, Result}; 2 | use core::arch::asm; 3 | use core::{ 4 | mem, 5 | ops::{Deref, DerefMut}, 6 | slice, 7 | }; 8 | 9 | pub const PAGE_SIZE: usize = 4096; 10 | 11 | #[cfg(feature = "userspace")] 12 | macro_rules! syscall { 13 | ($($name:ident($a:ident, $($b:ident, $($c:ident, $($d:ident, $($e:ident, $($f:ident, )?)?)?)?)?);)+) => { 14 | $( 15 | pub unsafe fn $name($a: usize, $($b: usize, $($c: usize, $($d: usize, $($e: usize, $($f: usize)?)?)?)?)?) -> Result { 16 | let ret: usize; 17 | 18 | asm!( 19 | "ecall", 20 | in("a7") $a, 21 | $( 22 | in("a0") $b, 23 | $( 24 | in("a1") $c, 25 | $( 26 | in("a2") $d, 27 | $( 28 | in("a3") $e, 29 | $( 30 | in("a4") $f, 31 | )? 32 | )? 33 | )? 34 | )? 35 | )? 36 | lateout("a0") ret, 37 | options(nostack), 38 | ); 39 | 40 | Error::demux(ret) 41 | } 42 | )+ 43 | }; 44 | } 45 | 46 | #[cfg(feature = "userspace")] 47 | syscall! { 48 | syscall0(a,); 49 | syscall1(a, b,); 50 | syscall2(a, b, c,); 51 | syscall3(a, b, c, d,); 52 | syscall4(a, b, c, d, e,); 53 | syscall5(a, b, c, d, e, f,); 54 | } 55 | 56 | #[derive(Copy, Clone, Debug, Default)] 57 | #[repr(C)] 58 | pub struct IntRegisters { 59 | pub pc: usize, 60 | pub x31: usize, 61 | pub x30: usize, 62 | pub x29: usize, 63 | pub x28: usize, 64 | pub x27: usize, 65 | pub x26: usize, 66 | pub x25: usize, 67 | pub x24: usize, 68 | pub x23: usize, 69 | pub x22: usize, 70 | pub x21: usize, 71 | pub x20: usize, 72 | pub x19: usize, 73 | pub x18: usize, 74 | pub x17: usize, 75 | pub x16: usize, 76 | pub x15: usize, 77 | pub x14: usize, 78 | pub x13: usize, 79 | pub x12: usize, 80 | pub x11: usize, 81 | pub x10: usize, 82 | pub x9: usize, 83 | pub x8: usize, 84 | pub x7: usize, 85 | pub x6: usize, 86 | pub x5: usize, 87 | // x4(tp) is in env 88 | // x3(gp) is a platform scratch register 89 | pub x2: usize, 90 | pub x1: usize, 91 | } 92 | 93 | impl Deref for IntRegisters { 94 | type Target = [u8]; 95 | fn deref(&self) -> &[u8] { 96 | unsafe { 97 | slice::from_raw_parts( 98 | self as *const IntRegisters as *const u8, 99 | mem::size_of::(), 100 | ) 101 | } 102 | } 103 | } 104 | 105 | impl DerefMut for IntRegisters { 106 | fn deref_mut(&mut self) -> &mut [u8] { 107 | unsafe { 108 | slice::from_raw_parts_mut( 109 | self as *mut IntRegisters as *mut u8, 110 | mem::size_of::(), 111 | ) 112 | } 113 | } 114 | } 115 | 116 | #[derive(Clone, Copy, Debug, Default)] 117 | #[repr(C, packed)] 118 | pub struct FloatRegisters { 119 | pub fregs: [u64; 32], 120 | pub fcsr: u32, 121 | } 122 | 123 | impl Deref for FloatRegisters { 124 | type Target = [u8]; 125 | fn deref(&self) -> &[u8] { 126 | unsafe { 127 | slice::from_raw_parts( 128 | self as *const FloatRegisters as *const u8, 129 | mem::size_of::(), 130 | ) 131 | } 132 | } 133 | } 134 | 135 | impl DerefMut for FloatRegisters { 136 | fn deref_mut(&mut self) -> &mut [u8] { 137 | unsafe { 138 | slice::from_raw_parts_mut( 139 | self as *mut FloatRegisters as *mut u8, 140 | mem::size_of::(), 141 | ) 142 | } 143 | } 144 | } 145 | 146 | #[derive(Clone, Copy, Debug, Default)] 147 | #[repr(packed)] 148 | pub struct EnvRegisters { 149 | pub tp: usize, 150 | } 151 | impl Deref for EnvRegisters { 152 | type Target = [u8]; 153 | fn deref(&self) -> &[u8] { 154 | unsafe { 155 | slice::from_raw_parts( 156 | self as *const EnvRegisters as *const u8, 157 | mem::size_of::(), 158 | ) 159 | } 160 | } 161 | } 162 | 163 | impl DerefMut for EnvRegisters { 164 | fn deref_mut(&mut self) -> &mut [u8] { 165 | unsafe { 166 | slice::from_raw_parts_mut( 167 | self as *mut EnvRegisters as *mut u8, 168 | mem::size_of::(), 169 | ) 170 | } 171 | } 172 | } 173 | #[derive(Clone, Copy, Debug, Default)] 174 | #[repr(C, packed)] 175 | pub struct Exception { 176 | pub kind: usize, 177 | // TODO 178 | } 179 | impl Deref for Exception { 180 | type Target = [u8]; 181 | fn deref(&self) -> &[u8] { 182 | unsafe { 183 | slice::from_raw_parts( 184 | self as *const Exception as *const u8, 185 | mem::size_of::(), 186 | ) 187 | } 188 | } 189 | } 190 | 191 | impl DerefMut for Exception { 192 | fn deref_mut(&mut self) -> &mut [u8] { 193 | unsafe { 194 | slice::from_raw_parts_mut( 195 | self as *mut Exception as *mut u8, 196 | mem::size_of::(), 197 | ) 198 | } 199 | } 200 | } 201 | -------------------------------------------------------------------------------- /src/arch/x86.rs: -------------------------------------------------------------------------------- 1 | use core::{ 2 | arch::asm, 3 | mem, 4 | ops::{Deref, DerefMut}, 5 | slice, 6 | }; 7 | 8 | use super::error::{Error, Result}; 9 | 10 | pub const PAGE_SIZE: usize = 4096; 11 | 12 | #[cfg(feature = "userspace")] 13 | macro_rules! syscall { 14 | ($($name:ident($a:ident, $($b:ident, $($c:ident, $($d:ident, $($e:ident, $($f:ident, )?)?)?)?)?);)+) => { 15 | $( 16 | pub unsafe fn $name(mut $a: usize, $($b: usize, $($c: usize, $($d: usize, $($e: usize, $($f: usize)?)?)?)?)?) -> Result { 17 | asm!( 18 | "int 0x80", 19 | inout("eax") $a, 20 | $( 21 | in("ebx") $b, 22 | $( 23 | in("ecx") $c, 24 | $( 25 | in("edx") $d, 26 | $( 27 | in("esi") $e, 28 | $( 29 | in("edi") $f, 30 | )? 31 | )? 32 | )? 33 | )? 34 | )? 35 | options(nostack), 36 | ); 37 | 38 | Error::demux($a) 39 | } 40 | )+ 41 | }; 42 | } 43 | 44 | #[cfg(feature = "userspace")] 45 | syscall! { 46 | syscall0(a,); 47 | syscall1(a, b,); 48 | syscall2(a, b, c,); 49 | syscall3(a, b, c, d,); 50 | // Must be done custom because LLVM reserves ESI 51 | //syscall4(a, b, c, d, e,); 52 | //syscall5(a, b, c, d, e, f,); 53 | } 54 | 55 | #[cfg(feature = "userspace")] 56 | pub unsafe fn syscall4(mut a: usize, b: usize, c: usize, d: usize, e: usize) -> Result { 57 | asm!( 58 | "xchg esi, {e} 59 | int 0x80 60 | xchg esi, {e}", 61 | e = in(reg) e, 62 | inout("eax") a, 63 | in("ebx") b, 64 | in("ecx") c, 65 | in("edx") d, 66 | options(nostack), 67 | ); 68 | 69 | Error::demux(a) 70 | } 71 | 72 | #[cfg(feature = "userspace")] 73 | pub unsafe fn syscall5( 74 | mut a: usize, 75 | b: usize, 76 | c: usize, 77 | d: usize, 78 | e: usize, 79 | f: usize, 80 | ) -> Result { 81 | asm!( 82 | "xchg esi, {e} 83 | int 0x80 84 | xchg esi, {e}", 85 | e = in(reg) e, 86 | inout("eax") a, 87 | in("ebx") b, 88 | in("ecx") c, 89 | in("edx") d, 90 | in("edi") f, 91 | options(nostack), 92 | ); 93 | 94 | Error::demux(a) 95 | } 96 | 97 | #[derive(Copy, Clone, Debug, Default)] 98 | #[repr(C)] 99 | pub struct IntRegisters { 100 | // TODO: Some of these don't get set by Redox yet. Should they? 101 | pub ebp: usize, 102 | pub esi: usize, 103 | pub edi: usize, 104 | pub ebx: usize, 105 | pub eax: usize, 106 | pub ecx: usize, 107 | pub edx: usize, 108 | // pub orig_rax: usize, 109 | pub eip: usize, 110 | pub cs: usize, 111 | pub eflags: usize, 112 | pub esp: usize, 113 | pub ss: usize, 114 | // pub fs_base: usize, 115 | // pub gs_base: usize, 116 | // pub ds: usize, 117 | // pub es: usize, 118 | pub fs: usize, 119 | // pub gs: usize 120 | } 121 | 122 | impl Deref for IntRegisters { 123 | type Target = [u8]; 124 | fn deref(&self) -> &[u8] { 125 | unsafe { 126 | slice::from_raw_parts( 127 | self as *const IntRegisters as *const u8, 128 | mem::size_of::(), 129 | ) 130 | } 131 | } 132 | } 133 | 134 | impl DerefMut for IntRegisters { 135 | fn deref_mut(&mut self) -> &mut [u8] { 136 | unsafe { 137 | slice::from_raw_parts_mut( 138 | self as *mut IntRegisters as *mut u8, 139 | mem::size_of::(), 140 | ) 141 | } 142 | } 143 | } 144 | 145 | #[derive(Clone, Copy, Debug, Default)] 146 | #[repr(C, packed)] 147 | pub struct FloatRegisters { 148 | pub fcw: u16, 149 | pub fsw: u16, 150 | pub ftw: u8, 151 | pub _reserved: u8, 152 | pub fop: u16, 153 | pub fip: u64, 154 | pub fdp: u64, 155 | pub mxcsr: u32, 156 | pub mxcsr_mask: u32, 157 | pub st_space: [u128; 8], 158 | pub xmm_space: [u128; 16], 159 | // TODO: YMM/ZMM 160 | } 161 | 162 | impl Deref for FloatRegisters { 163 | type Target = [u8]; 164 | fn deref(&self) -> &[u8] { 165 | unsafe { 166 | slice::from_raw_parts( 167 | self as *const FloatRegisters as *const u8, 168 | mem::size_of::(), 169 | ) 170 | } 171 | } 172 | } 173 | 174 | impl DerefMut for FloatRegisters { 175 | fn deref_mut(&mut self) -> &mut [u8] { 176 | unsafe { 177 | slice::from_raw_parts_mut( 178 | self as *mut FloatRegisters as *mut u8, 179 | mem::size_of::(), 180 | ) 181 | } 182 | } 183 | } 184 | 185 | #[derive(Clone, Copy, Debug, Default)] 186 | #[repr(C, packed)] 187 | pub struct EnvRegisters { 188 | pub fsbase: u32, 189 | pub gsbase: u32, 190 | } 191 | 192 | impl Deref for EnvRegisters { 193 | type Target = [u8]; 194 | fn deref(&self) -> &[u8] { 195 | unsafe { 196 | slice::from_raw_parts( 197 | self as *const EnvRegisters as *const u8, 198 | mem::size_of::(), 199 | ) 200 | } 201 | } 202 | } 203 | 204 | impl DerefMut for EnvRegisters { 205 | fn deref_mut(&mut self) -> &mut [u8] { 206 | unsafe { 207 | slice::from_raw_parts_mut( 208 | self as *mut EnvRegisters as *mut u8, 209 | mem::size_of::(), 210 | ) 211 | } 212 | } 213 | } 214 | 215 | #[derive(Clone, Copy, Debug, Default)] 216 | #[repr(C, packed)] 217 | pub struct Exception { 218 | pub kind: usize, 219 | pub code: usize, 220 | pub address: usize, 221 | } 222 | impl Deref for Exception { 223 | type Target = [u8]; 224 | fn deref(&self) -> &[u8] { 225 | unsafe { 226 | slice::from_raw_parts( 227 | self as *const Exception as *const u8, 228 | mem::size_of::(), 229 | ) 230 | } 231 | } 232 | } 233 | 234 | impl DerefMut for Exception { 235 | fn deref_mut(&mut self) -> &mut [u8] { 236 | unsafe { 237 | slice::from_raw_parts_mut( 238 | self as *mut Exception as *mut u8, 239 | mem::size_of::(), 240 | ) 241 | } 242 | } 243 | } 244 | -------------------------------------------------------------------------------- /src/arch/x86_64.rs: -------------------------------------------------------------------------------- 1 | use core::{ 2 | mem, 3 | ops::{Deref, DerefMut}, 4 | slice, 5 | }; 6 | 7 | pub const PAGE_SIZE: usize = 4096; 8 | 9 | #[cfg(feature = "userspace")] 10 | macro_rules! syscall { 11 | ($($name:ident($a:ident, $($b:ident, $($c:ident, $($d:ident, $($e:ident, $($f:ident, )?)?)?)?)?);)+) => { 12 | $( 13 | pub unsafe fn $name(mut $a: usize, $($b: usize, $($c: usize, $($d: usize, $($e: usize, $($f: usize)?)?)?)?)?) -> crate::error::Result { 14 | core::arch::asm!( 15 | "syscall", 16 | inout("rax") $a, 17 | $( 18 | in("rdi") $b, 19 | $( 20 | in("rsi") $c, 21 | $( 22 | in("rdx") $d, 23 | $( 24 | in("r10") $e, 25 | $( 26 | in("r8") $f, 27 | )? 28 | )? 29 | )? 30 | )? 31 | )? 32 | out("rcx") _, 33 | out("r11") _, 34 | options(nostack), 35 | ); 36 | 37 | crate::error::Error::demux($a) 38 | } 39 | )+ 40 | }; 41 | } 42 | 43 | #[cfg(feature = "userspace")] 44 | syscall! { 45 | syscall0(a,); 46 | syscall1(a, b,); 47 | syscall2(a, b, c,); 48 | syscall3(a, b, c, d,); 49 | syscall4(a, b, c, d, e,); 50 | syscall5(a, b, c, d, e, f,); 51 | } 52 | 53 | #[derive(Copy, Clone, Debug, Default)] 54 | #[repr(C)] 55 | pub struct IntRegisters { 56 | pub r15: usize, 57 | pub r14: usize, 58 | pub r13: usize, 59 | pub r12: usize, 60 | pub rbp: usize, 61 | pub rbx: usize, 62 | pub r11: usize, 63 | pub r10: usize, 64 | pub r9: usize, 65 | pub r8: usize, 66 | pub rax: usize, 67 | pub rcx: usize, 68 | pub rdx: usize, 69 | pub rsi: usize, 70 | pub rdi: usize, 71 | pub rip: usize, 72 | pub cs: usize, 73 | pub rflags: usize, 74 | pub rsp: usize, 75 | pub ss: usize, 76 | } 77 | 78 | impl Deref for IntRegisters { 79 | type Target = [u8]; 80 | fn deref(&self) -> &[u8] { 81 | unsafe { slice::from_raw_parts(self as *const Self as *const u8, mem::size_of::()) } 82 | } 83 | } 84 | 85 | impl DerefMut for IntRegisters { 86 | fn deref_mut(&mut self) -> &mut [u8] { 87 | unsafe { slice::from_raw_parts_mut(self as *mut Self as *mut u8, mem::size_of::()) } 88 | } 89 | } 90 | 91 | #[derive(Clone, Copy, Debug, Default)] 92 | #[repr(C, packed)] 93 | pub struct FloatRegisters { 94 | pub fcw: u16, 95 | pub fsw: u16, 96 | pub ftw: u8, 97 | pub _reserved: u8, 98 | pub fop: u16, 99 | pub fip: u64, 100 | pub fdp: u64, 101 | pub mxcsr: u32, 102 | pub mxcsr_mask: u32, 103 | pub st_space: [u128; 8], 104 | pub xmm_space: [u128; 16], 105 | // TODO: YMM/ZMM 106 | } 107 | 108 | impl Deref for FloatRegisters { 109 | type Target = [u8]; 110 | fn deref(&self) -> &[u8] { 111 | unsafe { 112 | slice::from_raw_parts( 113 | self as *const FloatRegisters as *const u8, 114 | mem::size_of::(), 115 | ) 116 | } 117 | } 118 | } 119 | 120 | impl DerefMut for FloatRegisters { 121 | fn deref_mut(&mut self) -> &mut [u8] { 122 | unsafe { 123 | slice::from_raw_parts_mut( 124 | self as *mut FloatRegisters as *mut u8, 125 | mem::size_of::(), 126 | ) 127 | } 128 | } 129 | } 130 | #[derive(Clone, Copy, Debug, Default)] 131 | #[repr(C, packed)] 132 | pub struct EnvRegisters { 133 | pub fsbase: u64, 134 | pub gsbase: u64, 135 | // TODO: PKRU? 136 | } 137 | impl Deref for EnvRegisters { 138 | type Target = [u8]; 139 | fn deref(&self) -> &[u8] { 140 | unsafe { 141 | slice::from_raw_parts( 142 | self as *const EnvRegisters as *const u8, 143 | mem::size_of::(), 144 | ) 145 | } 146 | } 147 | } 148 | 149 | impl DerefMut for EnvRegisters { 150 | fn deref_mut(&mut self) -> &mut [u8] { 151 | unsafe { 152 | slice::from_raw_parts_mut( 153 | self as *mut EnvRegisters as *mut u8, 154 | mem::size_of::(), 155 | ) 156 | } 157 | } 158 | } 159 | 160 | #[derive(Clone, Copy, Debug, Default)] 161 | #[repr(C, packed)] 162 | pub struct Exception { 163 | pub kind: usize, 164 | pub code: usize, 165 | pub address: usize, 166 | } 167 | impl Deref for Exception { 168 | type Target = [u8]; 169 | fn deref(&self) -> &[u8] { 170 | unsafe { 171 | slice::from_raw_parts( 172 | self as *const Exception as *const u8, 173 | mem::size_of::(), 174 | ) 175 | } 176 | } 177 | } 178 | 179 | impl DerefMut for Exception { 180 | fn deref_mut(&mut self) -> &mut [u8] { 181 | unsafe { 182 | slice::from_raw_parts_mut( 183 | self as *mut Exception as *mut u8, 184 | mem::size_of::(), 185 | ) 186 | } 187 | } 188 | } 189 | -------------------------------------------------------------------------------- /src/call.rs: -------------------------------------------------------------------------------- 1 | use super::{ 2 | arch::*, 3 | data::{Map, Stat, StatVfs, TimeSpec}, 4 | error::Result, 5 | flag::*, 6 | number::*, 7 | }; 8 | 9 | use core::mem; 10 | 11 | /// Close a file 12 | pub fn close(fd: usize) -> Result { 13 | unsafe { syscall1(SYS_CLOSE, fd) } 14 | } 15 | 16 | /// Get the current system time 17 | pub fn clock_gettime(clock: usize, tp: &mut TimeSpec) -> Result { 18 | unsafe { syscall2(SYS_CLOCK_GETTIME, clock, tp as *mut TimeSpec as usize) } 19 | } 20 | 21 | /// Copy and transform a file descriptor 22 | pub fn dup(fd: usize, buf: &[u8]) -> Result { 23 | unsafe { syscall3(SYS_DUP, fd, buf.as_ptr() as usize, buf.len()) } 24 | } 25 | 26 | /// Copy and transform a file descriptor 27 | pub fn dup2(fd: usize, newfd: usize, buf: &[u8]) -> Result { 28 | unsafe { syscall4(SYS_DUP2, fd, newfd, buf.as_ptr() as usize, buf.len()) } 29 | } 30 | 31 | /// Change file permissions 32 | pub fn fchmod(fd: usize, mode: u16) -> Result { 33 | unsafe { syscall2(SYS_FCHMOD, fd, mode as usize) } 34 | } 35 | 36 | /// Change file ownership 37 | pub fn fchown(fd: usize, uid: u32, gid: u32) -> Result { 38 | unsafe { syscall3(SYS_FCHOWN, fd, uid as usize, gid as usize) } 39 | } 40 | 41 | /// Change file descriptor flags 42 | pub fn fcntl(fd: usize, cmd: usize, arg: usize) -> Result { 43 | unsafe { syscall3(SYS_FCNTL, fd, cmd, arg) } 44 | } 45 | 46 | /// Map a file into memory, but with the ability to set the address to map into, either as a hint 47 | /// or as a requirement of the map. 48 | /// 49 | /// # Errors 50 | /// `EACCES` - the file descriptor was not open for reading 51 | /// `EBADF` - if the file descriptor was invalid 52 | /// `ENODEV` - mmapping was not supported 53 | /// `EINVAL` - invalid combination of flags 54 | /// `EEXIST` - if [`MapFlags::MAP_FIXED`] was set, and the address specified was already in use. 55 | /// 56 | pub unsafe fn fmap(fd: usize, map: &Map) -> Result { 57 | syscall3( 58 | SYS_FMAP, 59 | fd, 60 | map as *const Map as usize, 61 | mem::size_of::(), 62 | ) 63 | } 64 | 65 | /// Unmap whole (or partial) continous memory-mapped files 66 | pub unsafe fn funmap(addr: usize, len: usize) -> Result { 67 | syscall2(SYS_FUNMAP, addr, len) 68 | } 69 | 70 | /// Retrieve the canonical path of a file 71 | pub fn fpath(fd: usize, buf: &mut [u8]) -> Result { 72 | unsafe { syscall3(SYS_FPATH, fd, buf.as_mut_ptr() as usize, buf.len()) } 73 | } 74 | 75 | /// Create a link to a file 76 | pub fn flink>(fd: usize, path: T) -> Result { 77 | let path = path.as_ref(); 78 | unsafe { syscall3(SYS_FLINK, fd, path.as_ptr() as usize, path.len()) } 79 | } 80 | 81 | /// Rename a file 82 | pub fn frename>(fd: usize, path: T) -> Result { 83 | let path = path.as_ref(); 84 | unsafe { syscall3(SYS_FRENAME, fd, path.as_ptr() as usize, path.len()) } 85 | } 86 | 87 | /// Get metadata about a file 88 | pub fn fstat(fd: usize, stat: &mut Stat) -> Result { 89 | unsafe { 90 | syscall3( 91 | SYS_FSTAT, 92 | fd, 93 | stat as *mut Stat as usize, 94 | mem::size_of::(), 95 | ) 96 | } 97 | } 98 | 99 | /// Get metadata about a filesystem 100 | pub fn fstatvfs(fd: usize, stat: &mut StatVfs) -> Result { 101 | unsafe { 102 | syscall3( 103 | SYS_FSTATVFS, 104 | fd, 105 | stat as *mut StatVfs as usize, 106 | mem::size_of::(), 107 | ) 108 | } 109 | } 110 | 111 | /// Sync a file descriptor to its underlying medium 112 | pub fn fsync(fd: usize) -> Result { 113 | unsafe { syscall1(SYS_FSYNC, fd) } 114 | } 115 | 116 | /// Truncate or extend a file to a specified length 117 | pub fn ftruncate(fd: usize, len: usize) -> Result { 118 | unsafe { syscall2(SYS_FTRUNCATE, fd, len) } 119 | } 120 | 121 | // Change modify and/or access times 122 | pub fn futimens(fd: usize, times: &[TimeSpec]) -> Result { 123 | unsafe { 124 | syscall3( 125 | SYS_FUTIMENS, 126 | fd, 127 | times.as_ptr() as usize, 128 | times.len() * mem::size_of::(), 129 | ) 130 | } 131 | } 132 | 133 | /// Fast userspace mutex 134 | pub unsafe fn futex( 135 | addr: *mut i32, 136 | op: usize, 137 | val: i32, 138 | val2: usize, 139 | addr2: *mut i32, 140 | ) -> Result { 141 | syscall5( 142 | SYS_FUTEX, 143 | addr as usize, 144 | op, 145 | (val as isize) as usize, 146 | val2, 147 | addr2 as usize, 148 | ) 149 | } 150 | 151 | /// Seek to `offset` bytes in a file descriptor 152 | pub fn lseek(fd: usize, offset: isize, whence: usize) -> Result { 153 | unsafe { syscall3(SYS_LSEEK, fd, offset as usize, whence) } 154 | } 155 | 156 | /// Make a new scheme namespace 157 | pub fn mkns(schemes: &[[usize; 2]]) -> Result { 158 | unsafe { syscall2(SYS_MKNS, schemes.as_ptr() as usize, schemes.len()) } 159 | } 160 | 161 | /// Change mapping flags 162 | pub unsafe fn mprotect(addr: usize, size: usize, flags: MapFlags) -> Result { 163 | syscall3(SYS_MPROTECT, addr, size, flags.bits()) 164 | } 165 | 166 | /// Sleep for the time specified in `req` 167 | pub fn nanosleep(req: &TimeSpec, rem: &mut TimeSpec) -> Result { 168 | unsafe { 169 | syscall2( 170 | SYS_NANOSLEEP, 171 | req as *const TimeSpec as usize, 172 | rem as *mut TimeSpec as usize, 173 | ) 174 | } 175 | } 176 | 177 | /// Open a file 178 | pub fn open>(path: T, flags: usize) -> Result { 179 | let path = path.as_ref(); 180 | unsafe { syscall3(SYS_OPEN, path.as_ptr() as usize, path.len(), flags) } 181 | } 182 | 183 | /// Open a file at a specific path 184 | pub fn openat>(fd: usize, path: T, flags: usize) -> Result { 185 | let path = path.as_ref(); 186 | unsafe { syscall4(SYS_OPENAT, fd, path.as_ptr() as usize, path.len(), flags) } 187 | } 188 | 189 | /// Read from a file descriptor into a buffer 190 | pub fn read(fd: usize, buf: &mut [u8]) -> Result { 191 | unsafe { syscall3(SYS_READ, fd, buf.as_mut_ptr() as usize, buf.len()) } 192 | } 193 | 194 | /// Remove a directory 195 | pub fn rmdir>(path: T) -> Result { 196 | let path = path.as_ref(); 197 | unsafe { syscall2(SYS_RMDIR, path.as_ptr() as usize, path.len()) } 198 | } 199 | 200 | /// Remove a file 201 | pub fn unlink>(path: T) -> Result { 202 | let path = path.as_ref(); 203 | unsafe { syscall2(SYS_UNLINK, path.as_ptr() as usize, path.len()) } 204 | } 205 | 206 | /// Write a buffer to a file descriptor 207 | /// 208 | /// The kernel will attempt to write the bytes in `buf` to the file descriptor `fd`, returning 209 | /// either an `Err`, explained below, or `Ok(count)` where `count` is the number of bytes which 210 | /// were written. 211 | /// 212 | /// # Errors 213 | /// 214 | /// * `EAGAIN` - the file descriptor was opened with `O_NONBLOCK` and writing would block 215 | /// * `EBADF` - the file descriptor is not valid or is not open for writing 216 | /// * `EFAULT` - `buf` does not point to the process's addressible memory 217 | /// * `EIO` - an I/O error occurred 218 | /// * `ENOSPC` - the device containing the file descriptor has no room for data 219 | /// * `EPIPE` - the file descriptor refers to a pipe or socket whose reading end is closed 220 | pub fn write(fd: usize, buf: &[u8]) -> Result { 221 | unsafe { syscall3(SYS_WRITE, fd, buf.as_ptr() as usize, buf.len()) } 222 | } 223 | 224 | /// Yield the process's time slice to the kernel 225 | /// 226 | /// This function will return Ok(0) on success 227 | pub fn sched_yield() -> Result { 228 | unsafe { syscall0(SYS_YIELD) } 229 | } 230 | 231 | /// Send a file descriptor `fd`, handled by the scheme providing `receiver_socket`. `flags` is 232 | /// currently unused (must be zero), and `arg` is included in the scheme call. 233 | /// 234 | /// The scheme can return an arbitrary value. 235 | pub fn sendfd(receiver_socket: usize, fd: usize, flags: usize, arg: u64) -> Result { 236 | #[cfg(target_pointer_width = "32")] 237 | unsafe { 238 | syscall5( 239 | SYS_SENDFD, 240 | receiver_socket, 241 | fd, 242 | flags, 243 | arg as u32 as usize, 244 | (arg >> 32) as u32 as usize, 245 | ) 246 | } 247 | 248 | #[cfg(target_pointer_width = "64")] 249 | unsafe { 250 | syscall4(SYS_SENDFD, receiver_socket, fd, flags, arg as usize) 251 | } 252 | } 253 | -------------------------------------------------------------------------------- /src/data.rs: -------------------------------------------------------------------------------- 1 | use core::{ 2 | mem, 3 | ops::{Deref, DerefMut}, 4 | slice, 5 | }; 6 | 7 | use crate::flag::{EventFlags, MapFlags, PtraceFlags}; 8 | 9 | #[derive(Copy, Clone, Debug, Default)] 10 | #[repr(C)] 11 | pub struct Event { 12 | pub id: usize, 13 | pub flags: EventFlags, 14 | pub data: usize, 15 | } 16 | 17 | impl Deref for Event { 18 | type Target = [u8]; 19 | fn deref(&self) -> &[u8] { 20 | unsafe { slice::from_raw_parts(self as *const Event as *const u8, mem::size_of::()) } 21 | } 22 | } 23 | 24 | impl DerefMut for Event { 25 | fn deref_mut(&mut self) -> &mut [u8] { 26 | unsafe { slice::from_raw_parts_mut(self as *mut Event as *mut u8, mem::size_of::()) } 27 | } 28 | } 29 | 30 | #[derive(Copy, Clone, Debug, Default)] 31 | #[repr(C)] 32 | pub struct ITimerSpec { 33 | pub it_interval: TimeSpec, 34 | pub it_value: TimeSpec, 35 | } 36 | 37 | impl Deref for ITimerSpec { 38 | type Target = [u8]; 39 | fn deref(&self) -> &[u8] { 40 | unsafe { 41 | slice::from_raw_parts( 42 | self as *const ITimerSpec as *const u8, 43 | mem::size_of::(), 44 | ) 45 | } 46 | } 47 | } 48 | 49 | impl DerefMut for ITimerSpec { 50 | fn deref_mut(&mut self) -> &mut [u8] { 51 | unsafe { 52 | slice::from_raw_parts_mut( 53 | self as *mut ITimerSpec as *mut u8, 54 | mem::size_of::(), 55 | ) 56 | } 57 | } 58 | } 59 | 60 | #[derive(Copy, Clone, Debug, Default)] 61 | #[repr(C)] 62 | pub struct OldMap { 63 | pub offset: usize, 64 | pub size: usize, 65 | pub flags: MapFlags, 66 | } 67 | 68 | impl Deref for OldMap { 69 | type Target = [u8]; 70 | fn deref(&self) -> &[u8] { 71 | unsafe { 72 | slice::from_raw_parts(self as *const OldMap as *const u8, mem::size_of::()) 73 | } 74 | } 75 | } 76 | 77 | impl DerefMut for OldMap { 78 | fn deref_mut(&mut self) -> &mut [u8] { 79 | unsafe { 80 | slice::from_raw_parts_mut(self as *mut OldMap as *mut u8, mem::size_of::()) 81 | } 82 | } 83 | } 84 | #[derive(Copy, Clone, Debug, Default)] 85 | #[repr(C)] 86 | pub struct Map { 87 | /// The offset inside the file that is being mapped. 88 | pub offset: usize, 89 | 90 | /// The size of the memory map. 91 | pub size: usize, 92 | 93 | /// Contains both prot and map flags. 94 | pub flags: MapFlags, 95 | 96 | /// Functions as a hint to where in the virtual address space of the running process, to place 97 | /// the memory map. If [`MapFlags::MAP_FIXED`] is set, then this address must be the address to 98 | /// map to. 99 | pub address: usize, 100 | } 101 | 102 | impl Deref for Map { 103 | type Target = [u8]; 104 | fn deref(&self) -> &[u8] { 105 | unsafe { slice::from_raw_parts(self as *const Map as *const u8, mem::size_of::()) } 106 | } 107 | } 108 | 109 | impl DerefMut for Map { 110 | fn deref_mut(&mut self) -> &mut [u8] { 111 | unsafe { slice::from_raw_parts_mut(self as *mut Map as *mut u8, mem::size_of::()) } 112 | } 113 | } 114 | 115 | #[derive(Copy, Clone, Debug, Default)] 116 | #[repr(C)] 117 | pub struct Packet { 118 | pub id: u64, 119 | pub pid: usize, 120 | pub uid: u32, 121 | pub gid: u32, 122 | pub a: usize, 123 | pub b: usize, 124 | pub c: usize, 125 | pub d: usize, 126 | } 127 | 128 | impl Deref for Packet { 129 | type Target = [u8]; 130 | fn deref(&self) -> &[u8] { 131 | unsafe { 132 | slice::from_raw_parts(self as *const Packet as *const u8, mem::size_of::()) 133 | } 134 | } 135 | } 136 | 137 | impl DerefMut for Packet { 138 | fn deref_mut(&mut self) -> &mut [u8] { 139 | unsafe { 140 | slice::from_raw_parts_mut(self as *mut Packet as *mut u8, mem::size_of::()) 141 | } 142 | } 143 | } 144 | 145 | #[derive(Copy, Clone, Debug, Default, PartialEq)] 146 | #[repr(C)] 147 | pub struct Stat { 148 | pub st_dev: u64, 149 | pub st_ino: u64, 150 | pub st_mode: u16, 151 | pub st_nlink: u32, 152 | pub st_uid: u32, 153 | pub st_gid: u32, 154 | pub st_size: u64, 155 | pub st_blksize: u32, 156 | pub st_blocks: u64, 157 | pub st_mtime: u64, 158 | pub st_mtime_nsec: u32, 159 | pub st_atime: u64, 160 | pub st_atime_nsec: u32, 161 | pub st_ctime: u64, 162 | pub st_ctime_nsec: u32, 163 | } 164 | 165 | impl Deref for Stat { 166 | type Target = [u8]; 167 | fn deref(&self) -> &[u8] { 168 | unsafe { slice::from_raw_parts(self as *const Stat as *const u8, mem::size_of::()) } 169 | } 170 | } 171 | 172 | impl DerefMut for Stat { 173 | fn deref_mut(&mut self) -> &mut [u8] { 174 | unsafe { slice::from_raw_parts_mut(self as *mut Stat as *mut u8, mem::size_of::()) } 175 | } 176 | } 177 | 178 | #[derive(Copy, Clone, Debug, Default, PartialEq)] 179 | #[repr(C)] 180 | pub struct StatVfs { 181 | pub f_bsize: u32, 182 | pub f_blocks: u64, 183 | pub f_bfree: u64, 184 | pub f_bavail: u64, 185 | } 186 | 187 | impl Deref for StatVfs { 188 | type Target = [u8]; 189 | fn deref(&self) -> &[u8] { 190 | unsafe { 191 | slice::from_raw_parts( 192 | self as *const StatVfs as *const u8, 193 | mem::size_of::(), 194 | ) 195 | } 196 | } 197 | } 198 | 199 | impl DerefMut for StatVfs { 200 | fn deref_mut(&mut self) -> &mut [u8] { 201 | unsafe { 202 | slice::from_raw_parts_mut(self as *mut StatVfs as *mut u8, mem::size_of::()) 203 | } 204 | } 205 | } 206 | 207 | #[derive(Copy, Clone, Debug, Default, PartialEq)] 208 | #[repr(C)] 209 | pub struct TimeSpec { 210 | pub tv_sec: i64, 211 | pub tv_nsec: i32, 212 | } 213 | 214 | impl Deref for TimeSpec { 215 | type Target = [u8]; 216 | fn deref(&self) -> &[u8] { 217 | unsafe { 218 | slice::from_raw_parts( 219 | self as *const TimeSpec as *const u8, 220 | mem::size_of::(), 221 | ) 222 | } 223 | } 224 | } 225 | 226 | impl DerefMut for TimeSpec { 227 | fn deref_mut(&mut self) -> &mut [u8] { 228 | unsafe { 229 | slice::from_raw_parts_mut(self as *mut TimeSpec as *mut u8, mem::size_of::()) 230 | } 231 | } 232 | } 233 | 234 | #[derive(Clone, Copy, Debug, Default)] 235 | #[repr(C)] 236 | pub struct PtraceEvent { 237 | pub cause: PtraceFlags, 238 | pub a: usize, 239 | pub b: usize, 240 | pub c: usize, 241 | pub d: usize, 242 | pub e: usize, 243 | pub f: usize, 244 | } 245 | 246 | impl Deref for PtraceEvent { 247 | type Target = [u8]; 248 | fn deref(&self) -> &[u8] { 249 | unsafe { 250 | slice::from_raw_parts( 251 | self as *const PtraceEvent as *const u8, 252 | mem::size_of::(), 253 | ) 254 | } 255 | } 256 | } 257 | 258 | impl DerefMut for PtraceEvent { 259 | fn deref_mut(&mut self) -> &mut [u8] { 260 | unsafe { 261 | slice::from_raw_parts_mut( 262 | self as *mut PtraceEvent as *mut u8, 263 | mem::size_of::(), 264 | ) 265 | } 266 | } 267 | } 268 | 269 | #[macro_export] 270 | macro_rules! ptrace_event { 271 | ($cause:expr $(, $a:expr $(, $b:expr $(, $c:expr)?)?)?) => { 272 | $crate::data::PtraceEvent { 273 | cause: $cause, 274 | $(a: $a, 275 | $(b: $b, 276 | $(c: $c,)? 277 | )? 278 | )? 279 | ..Default::default() 280 | } 281 | } 282 | } 283 | 284 | bitflags::bitflags! { 285 | #[derive(PartialEq, Eq, PartialOrd, Ord, Hash, Debug, Clone, Copy, Default)] 286 | pub struct GrantFlags: usize { 287 | const GRANT_READ = 0x0000_0001; 288 | const GRANT_WRITE = 0x0000_0002; 289 | const GRANT_EXEC = 0x0000_0004; 290 | 291 | const GRANT_SHARED = 0x0000_0008; 292 | const GRANT_LAZY = 0x0000_0010; 293 | const GRANT_SCHEME = 0x0000_0020; 294 | const GRANT_PHYS = 0x0000_0040; 295 | const GRANT_PINNED = 0x0000_0080; 296 | const GRANT_PHYS_CONTIGUOUS = 0x0000_0100; 297 | } 298 | } 299 | 300 | impl GrantFlags { 301 | #[deprecated = "use the safe `from_bits_retain` method instead"] 302 | pub unsafe fn from_bits_unchecked(bits: usize) -> Self { 303 | Self::from_bits_retain(bits) 304 | } 305 | } 306 | 307 | #[derive(Clone, Copy, Debug, Default)] 308 | #[repr(C)] 309 | pub struct GrantDesc { 310 | pub base: usize, 311 | pub size: usize, 312 | pub flags: GrantFlags, 313 | pub offset: u64, 314 | } 315 | 316 | impl Deref for GrantDesc { 317 | type Target = [u8]; 318 | fn deref(&self) -> &[u8] { 319 | unsafe { 320 | slice::from_raw_parts( 321 | self as *const GrantDesc as *const u8, 322 | mem::size_of::(), 323 | ) 324 | } 325 | } 326 | } 327 | 328 | impl DerefMut for GrantDesc { 329 | fn deref_mut(&mut self) -> &mut [u8] { 330 | unsafe { 331 | slice::from_raw_parts_mut( 332 | self as *mut GrantDesc as *mut u8, 333 | mem::size_of::(), 334 | ) 335 | } 336 | } 337 | } 338 | 339 | #[derive(Clone, Copy, Debug, Default)] 340 | #[repr(C)] 341 | pub struct SetSighandlerData { 342 | pub user_handler: usize, 343 | pub excp_handler: usize, 344 | pub thread_control_addr: usize, 345 | pub proc_control_addr: usize, 346 | } 347 | 348 | impl Deref for SetSighandlerData { 349 | type Target = [u8]; 350 | fn deref(&self) -> &[u8] { 351 | unsafe { slice::from_raw_parts(self as *const Self as *const u8, mem::size_of::()) } 352 | } 353 | } 354 | 355 | impl DerefMut for SetSighandlerData { 356 | fn deref_mut(&mut self) -> &mut [u8] { 357 | unsafe { slice::from_raw_parts_mut(self as *mut Self as *mut u8, mem::size_of::()) } 358 | } 359 | } 360 | pub use crate::sigabi::*; 361 | 362 | /// UNSTABLE 363 | #[derive(Copy, Clone, Debug, Default, PartialEq)] 364 | #[repr(C)] 365 | pub struct ProcSchemeAttrs { 366 | pub pid: u32, 367 | pub euid: u32, 368 | pub egid: u32, 369 | pub ens: u32, 370 | pub debug_name: [u8; 32], 371 | } 372 | impl Deref for ProcSchemeAttrs { 373 | type Target = [u8]; 374 | fn deref(&self) -> &[u8] { 375 | unsafe { slice::from_raw_parts(self as *const Self as *const u8, mem::size_of::()) } 376 | } 377 | } 378 | impl DerefMut for ProcSchemeAttrs { 379 | fn deref_mut(&mut self) -> &mut [u8] { 380 | unsafe { 381 | slice::from_raw_parts_mut( 382 | self as *mut ProcSchemeAttrs as *mut u8, 383 | mem::size_of::(), 384 | ) 385 | } 386 | } 387 | } 388 | #[derive(Copy, Clone, Debug, Default)] 389 | #[repr(C)] 390 | pub struct CtxtStsBuf { 391 | pub status: usize, 392 | pub excp: crate::Exception, 393 | } 394 | impl Deref for CtxtStsBuf { 395 | type Target = [u8]; 396 | fn deref(&self) -> &[u8] { 397 | unsafe { slice::from_raw_parts(self as *const Self as *const u8, mem::size_of::()) } 398 | } 399 | } 400 | impl DerefMut for CtxtStsBuf { 401 | fn deref_mut(&mut self) -> &mut [u8] { 402 | unsafe { 403 | slice::from_raw_parts_mut( 404 | self as *mut CtxtStsBuf as *mut u8, 405 | mem::size_of::(), 406 | ) 407 | } 408 | } 409 | } 410 | -------------------------------------------------------------------------------- /src/dirent.rs: -------------------------------------------------------------------------------- 1 | use core::{ 2 | mem::size_of, 3 | ops::{Deref, DerefMut}, 4 | slice, 5 | }; 6 | 7 | use crate::{ 8 | error::{Error, Result, EINVAL}, 9 | ENAMETOOLONG, 10 | }; 11 | 12 | #[derive(Clone, Copy, Debug, Default)] 13 | #[repr(packed)] 14 | pub struct DirentHeader { 15 | pub inode: u64, 16 | /// A filesystem-specific opaque value used to uniquely identify directory entries. This value, 17 | /// in the last returned entry from a SYS_GETDENTS invocation, shall be passed to the next 18 | /// call. 19 | pub next_opaque_id: u64, 20 | // This struct intentionally does not include a "next" offset field, unlike Linux, to easily 21 | // guarantee the iterator will be reasonably deterministic, even if the scheme is adversarial. 22 | pub record_len: u16, 23 | /// A `DirentKind`. 24 | /// 25 | /// May not be directly available (Unspecified), and if so needs to be looked using fstat. 26 | pub kind: u8, 27 | } 28 | 29 | impl Deref for DirentHeader { 30 | type Target = [u8]; 31 | fn deref(&self) -> &[u8] { 32 | unsafe { slice::from_raw_parts(self as *const Self as *const u8, size_of::()) } 33 | } 34 | } 35 | 36 | impl DerefMut for DirentHeader { 37 | fn deref_mut(&mut self) -> &mut [u8] { 38 | unsafe { slice::from_raw_parts_mut(self as *mut Self as *mut u8, size_of::()) } 39 | } 40 | } 41 | #[derive(Clone, Copy, Debug, Default)] 42 | #[repr(u8)] 43 | pub enum DirentKind { 44 | #[default] 45 | Unspecified = 0, 46 | 47 | Regular = 1, 48 | Directory = 2, 49 | Symlink = 3, 50 | BlockDev = 4, 51 | CharDev = 5, 52 | Socket = 6, 53 | } 54 | impl DirentKind { 55 | // TODO: derive(FromPrimitive) 56 | pub fn try_from_raw(raw: u8) -> Option { 57 | Some(match raw { 58 | 0 => Self::Unspecified, 59 | 60 | 1 => Self::Regular, 61 | 2 => Self::Directory, 62 | 3 => Self::Symlink, 63 | 4 => Self::BlockDev, 64 | 5 => Self::CharDev, 65 | 6 => Self::Socket, 66 | 67 | _ => return None, 68 | }) 69 | } 70 | } 71 | 72 | pub struct DirentIter<'a>(&'a [u8]); 73 | 74 | impl<'a> DirentIter<'a> { 75 | pub const fn new(buffer: &'a [u8]) -> Self { 76 | Self(buffer) 77 | } 78 | } 79 | #[derive(Debug)] 80 | pub struct Invalid; 81 | 82 | impl<'a> Iterator for DirentIter<'a> { 83 | type Item = Result<(&'a DirentHeader, &'a [u8]), Invalid>; 84 | 85 | fn next(&mut self) -> Option { 86 | if self.0.len() < size_of::() { 87 | return None; 88 | } 89 | let header = unsafe { &*(self.0.as_ptr().cast::()) }; 90 | if self.0.len() < usize::from(header.record_len) { 91 | return Some(Err(Invalid)); 92 | } 93 | let (this, remaining) = self.0.split_at(usize::from(header.record_len)); 94 | self.0 = remaining; 95 | 96 | let name_and_nul = &this[size_of::()..]; 97 | let name = &name_and_nul[..name_and_nul.len() - 1]; 98 | 99 | Some(Ok((header, name))) 100 | } 101 | } 102 | 103 | #[derive(Debug)] 104 | pub struct DirentBuf { 105 | buffer: B, 106 | 107 | // Exists in order to allow future extensions to the DirentHeader struct. 108 | 109 | // TODO: Might add an upper bound to protect against cache miss DoS. The kernel currently 110 | // forbids any other value than size_of::(). 111 | header_size: u16, 112 | 113 | written: usize, 114 | } 115 | /// Abstraction between &mut [u8] and the kernel's UserSliceWo. 116 | pub trait Buffer<'a>: Sized + 'a { 117 | fn empty() -> Self; 118 | fn length(&self) -> usize; 119 | 120 | /// Split all of `self` into two disjoint contiguous subbuffers of lengths `index` and `length 121 | /// - index` respectively. 122 | /// 123 | /// Returns None if and only if `index > length`. 124 | fn split_at(self, index: usize) -> Option<[Self; 2]>; 125 | 126 | /// Copy from `src`, lengths must match exactly. 127 | /// 128 | /// Allowed to overwrite subsequent buffer space, for performance reasons. Can be changed in 129 | /// the future if too restrictive. 130 | fn copy_from_slice_exact(self, src: &[u8]) -> Result<()>; 131 | 132 | /// Write zeroes to this part of the buffer. 133 | /// 134 | /// Allowed to overwrite subsequent buffer space, for performance reasons. Can be changed in 135 | /// the future if too restrictive. 136 | fn zero_out(self) -> Result<()>; 137 | } 138 | impl<'a> Buffer<'a> for &'a mut [u8] { 139 | fn empty() -> Self { 140 | &mut [] 141 | } 142 | fn length(&self) -> usize { 143 | self.len() 144 | } 145 | 146 | fn split_at(self, index: usize) -> Option<[Self; 2]> { 147 | self.split_at_mut_checked(index).map(|(a, b)| [a, b]) 148 | } 149 | fn copy_from_slice_exact(self, src: &[u8]) -> Result<()> { 150 | self.copy_from_slice(src); 151 | Ok(()) 152 | } 153 | fn zero_out(self) -> Result<()> { 154 | self.fill(0); 155 | Ok(()) 156 | } 157 | } 158 | 159 | pub struct DirEntry<'name> { 160 | pub inode: u64, 161 | pub next_opaque_id: u64, 162 | pub name: &'name str, 163 | pub kind: DirentKind, 164 | } 165 | 166 | impl<'a, B: Buffer<'a>> DirentBuf { 167 | pub fn new(buffer: B, header_size: u16) -> Option { 168 | if usize::from(header_size) < size_of::() { 169 | return None; 170 | } 171 | 172 | Some(Self { 173 | buffer, 174 | header_size, 175 | written: 0, 176 | }) 177 | } 178 | pub fn entry(&mut self, entry: DirEntry<'_>) -> Result<()> { 179 | let name16 = u16::try_from(entry.name.len()).map_err(|_| Error::new(EINVAL))?; 180 | let record_len = self 181 | .header_size 182 | .checked_add(name16) 183 | // XXX: NUL byte. Unfortunately this is probably the only performant way to be 184 | // compatible with C. 185 | .and_then(|l| l.checked_add(1)) 186 | .ok_or(Error::new(ENAMETOOLONG))?; 187 | 188 | let [this, remaining] = core::mem::replace(&mut self.buffer, B::empty()) 189 | .split_at(usize::from(record_len)) 190 | .ok_or(Error::new(EINVAL))?; 191 | 192 | let [this_header_variable, this_name_and_nul] = this 193 | .split_at(usize::from(self.header_size)) 194 | .expect("already know header_size + ... >= header_size"); 195 | 196 | let [this_name, this_name_nul] = this_name_and_nul 197 | .split_at(usize::from(name16)) 198 | .expect("already know name.len() <= name.len() + 1"); 199 | 200 | // Every write here is currently sequential, allowing the buffer trait to do optimizations 201 | // where subbuffer writes are out-of-bounds (but inside the total buffer). 202 | 203 | let [this_header, this_header_extra] = this_header_variable 204 | .split_at(size_of::()) 205 | .expect("already checked header_size <= size_of Header"); 206 | 207 | this_header.copy_from_slice_exact(&DirentHeader { 208 | record_len, 209 | next_opaque_id: entry.next_opaque_id, 210 | inode: entry.inode, 211 | kind: entry.kind as u8, 212 | })?; 213 | this_header_extra.zero_out()?; 214 | this_name.copy_from_slice_exact(entry.name.as_bytes())?; 215 | this_name_nul.copy_from_slice_exact(&[0])?; 216 | 217 | self.written += usize::from(record_len); 218 | self.buffer = remaining; 219 | 220 | Ok(()) 221 | } 222 | pub fn finalize(self) -> usize { 223 | self.written 224 | } 225 | } 226 | -------------------------------------------------------------------------------- /src/error.rs: -------------------------------------------------------------------------------- 1 | use core::{fmt, result}; 2 | 3 | #[derive(Clone, Copy, Eq, PartialEq)] 4 | pub struct Error { 5 | pub errno: i32, 6 | } 7 | 8 | pub type Result = result::Result; 9 | 10 | impl Error { 11 | pub fn new(errno: i32) -> Error { 12 | Error { errno } 13 | } 14 | 15 | pub fn mux(result: Result) -> usize { 16 | match result { 17 | Ok(value) => value, 18 | Err(error) => -error.errno as usize, 19 | } 20 | } 21 | 22 | pub fn demux(value: usize) -> Result { 23 | let errno = -(value as i32); 24 | if errno >= 1 && errno < STR_ERROR.len() as i32 { 25 | Err(Error::new(errno)) 26 | } else { 27 | Ok(value) 28 | } 29 | } 30 | 31 | pub fn text(&self) -> &'static str { 32 | STR_ERROR 33 | .get(self.errno as usize) 34 | .map(|&x| x) 35 | .unwrap_or("Unknown Error") 36 | } 37 | } 38 | 39 | impl fmt::Debug for Error { 40 | fn fmt(&self, f: &mut fmt::Formatter) -> result::Result<(), fmt::Error> { 41 | f.write_str(self.text()) 42 | } 43 | } 44 | 45 | impl fmt::Display for Error { 46 | fn fmt(&self, f: &mut fmt::Formatter) -> result::Result<(), fmt::Error> { 47 | f.write_str(self.text()) 48 | } 49 | } 50 | #[cfg(feature = "std")] 51 | impl std::error::Error for Error {} 52 | 53 | #[cfg(feature = "std")] 54 | impl From for std::io::Error { 55 | fn from(value: Error) -> Self { 56 | std::io::Error::from_raw_os_error(value.errno) 57 | } 58 | } 59 | 60 | pub const EPERM: i32 = 1; /* Operation not permitted */ 61 | pub const ENOENT: i32 = 2; /* No such file or directory */ 62 | pub const ESRCH: i32 = 3; /* No such process */ 63 | pub const EINTR: i32 = 4; /* Interrupted system call */ 64 | pub const EIO: i32 = 5; /* I/O error */ 65 | pub const ENXIO: i32 = 6; /* No such device or address */ 66 | pub const E2BIG: i32 = 7; /* Argument list too long */ 67 | pub const ENOEXEC: i32 = 8; /* Exec format error */ 68 | pub const EBADF: i32 = 9; /* Bad file number */ 69 | pub const ECHILD: i32 = 10; /* No child processes */ 70 | pub const EAGAIN: i32 = 11; /* Try again */ 71 | pub const ENOMEM: i32 = 12; /* Out of memory */ 72 | pub const EACCES: i32 = 13; /* Permission denied */ 73 | pub const EFAULT: i32 = 14; /* Bad address */ 74 | pub const ENOTBLK: i32 = 15; /* Block device required */ 75 | pub const EBUSY: i32 = 16; /* Device or resource busy */ 76 | pub const EEXIST: i32 = 17; /* File exists */ 77 | pub const EXDEV: i32 = 18; /* Cross-device link */ 78 | pub const ENODEV: i32 = 19; /* No such device */ 79 | pub const ENOTDIR: i32 = 20; /* Not a directory */ 80 | pub const EISDIR: i32 = 21; /* Is a directory */ 81 | pub const EINVAL: i32 = 22; /* Invalid argument */ 82 | pub const ENFILE: i32 = 23; /* File table overflow */ 83 | pub const EMFILE: i32 = 24; /* Too many open files */ 84 | pub const ENOTTY: i32 = 25; /* Not a typewriter */ 85 | pub const ETXTBSY: i32 = 26; /* Text file busy */ 86 | pub const EFBIG: i32 = 27; /* File too large */ 87 | pub const ENOSPC: i32 = 28; /* No space left on device */ 88 | pub const ESPIPE: i32 = 29; /* Illegal seek */ 89 | pub const EROFS: i32 = 30; /* Read-only file system */ 90 | pub const EMLINK: i32 = 31; /* Too many links */ 91 | pub const EPIPE: i32 = 32; /* Broken pipe */ 92 | pub const EDOM: i32 = 33; /* Math argument out of domain of func */ 93 | pub const ERANGE: i32 = 34; /* Math result not representable */ 94 | pub const EDEADLK: i32 = 35; /* Resource deadlock would occur */ 95 | pub const ENAMETOOLONG: i32 = 36; /* File name too long */ 96 | pub const ENOLCK: i32 = 37; /* No record locks available */ 97 | pub const ENOSYS: i32 = 38; /* Function not implemented */ 98 | pub const ENOTEMPTY: i32 = 39; /* Directory not empty */ 99 | pub const ELOOP: i32 = 40; /* Too many symbolic links encountered */ 100 | pub const EWOULDBLOCK: i32 = 41; /* Operation would block */ 101 | pub const ENOMSG: i32 = 42; /* No message of desired type */ 102 | pub const EIDRM: i32 = 43; /* Identifier removed */ 103 | pub const ECHRNG: i32 = 44; /* Channel number out of range */ 104 | pub const EL2NSYNC: i32 = 45; /* Level 2 not synchronized */ 105 | pub const EL3HLT: i32 = 46; /* Level 3 halted */ 106 | pub const EL3RST: i32 = 47; /* Level 3 reset */ 107 | pub const ELNRNG: i32 = 48; /* Link number out of range */ 108 | pub const EUNATCH: i32 = 49; /* Protocol driver not attached */ 109 | pub const ENOCSI: i32 = 50; /* No CSI structure available */ 110 | pub const EL2HLT: i32 = 51; /* Level 2 halted */ 111 | pub const EBADE: i32 = 52; /* Invalid exchange */ 112 | pub const EBADR: i32 = 53; /* Invalid request descriptor */ 113 | pub const EXFULL: i32 = 54; /* Exchange full */ 114 | pub const ENOANO: i32 = 55; /* No anode */ 115 | pub const EBADRQC: i32 = 56; /* Invalid request code */ 116 | pub const EBADSLT: i32 = 57; /* Invalid slot */ 117 | pub const EDEADLOCK: i32 = 58; /* Resource deadlock would occur */ 118 | pub const EBFONT: i32 = 59; /* Bad font file format */ 119 | pub const ENOSTR: i32 = 60; /* Device not a stream */ 120 | pub const ENODATA: i32 = 61; /* No data available */ 121 | pub const ETIME: i32 = 62; /* Timer expired */ 122 | pub const ENOSR: i32 = 63; /* Out of streams resources */ 123 | pub const ENONET: i32 = 64; /* Machine is not on the network */ 124 | pub const ENOPKG: i32 = 65; /* Package not installed */ 125 | pub const EREMOTE: i32 = 66; /* Object is remote */ 126 | pub const ENOLINK: i32 = 67; /* Link has been severed */ 127 | pub const EADV: i32 = 68; /* Advertise error */ 128 | pub const ESRMNT: i32 = 69; /* Srmount error */ 129 | pub const ECOMM: i32 = 70; /* Communication error on send */ 130 | pub const EPROTO: i32 = 71; /* Protocol error */ 131 | pub const EMULTIHOP: i32 = 72; /* Multihop attempted */ 132 | pub const EDOTDOT: i32 = 73; /* RFS specific error */ 133 | pub const EBADMSG: i32 = 74; /* Not a data message */ 134 | pub const EOVERFLOW: i32 = 75; /* Value too large for defined data type */ 135 | pub const ENOTUNIQ: i32 = 76; /* Name not unique on network */ 136 | pub const EBADFD: i32 = 77; /* File descriptor in bad state */ 137 | pub const EREMCHG: i32 = 78; /* Remote address changed */ 138 | pub const ELIBACC: i32 = 79; /* Can not access a needed shared library */ 139 | pub const ELIBBAD: i32 = 80; /* Accessing a corrupted shared library */ 140 | pub const ELIBSCN: i32 = 81; /* .lib section in a.out corrupted */ 141 | pub const ELIBMAX: i32 = 82; /* Attempting to link in too many shared libraries */ 142 | pub const ELIBEXEC: i32 = 83; /* Cannot exec a shared library directly */ 143 | pub const EILSEQ: i32 = 84; /* Illegal byte sequence */ 144 | pub const ERESTART: i32 = 85; /* Interrupted system call should be restarted */ 145 | pub const ESTRPIPE: i32 = 86; /* Streams pipe error */ 146 | pub const EUSERS: i32 = 87; /* Too many users */ 147 | pub const ENOTSOCK: i32 = 88; /* Socket operation on non-socket */ 148 | pub const EDESTADDRREQ: i32 = 89; /* Destination address required */ 149 | pub const EMSGSIZE: i32 = 90; /* Message too long */ 150 | pub const EPROTOTYPE: i32 = 91; /* Protocol wrong type for socket */ 151 | pub const ENOPROTOOPT: i32 = 92; /* Protocol not available */ 152 | pub const EPROTONOSUPPORT: i32 = 93; /* Protocol not supported */ 153 | pub const ESOCKTNOSUPPORT: i32 = 94; /* Socket type not supported */ 154 | pub const EOPNOTSUPP: i32 = 95; /* Operation not supported on transport endpoint */ 155 | pub const EPFNOSUPPORT: i32 = 96; /* Protocol family not supported */ 156 | pub const EAFNOSUPPORT: i32 = 97; /* Address family not supported by protocol */ 157 | pub const EADDRINUSE: i32 = 98; /* Address already in use */ 158 | pub const EADDRNOTAVAIL: i32 = 99; /* Cannot assign requested address */ 159 | pub const ENETDOWN: i32 = 100; /* Network is down */ 160 | pub const ENETUNREACH: i32 = 101; /* Network is unreachable */ 161 | pub const ENETRESET: i32 = 102; /* Network dropped connection because of reset */ 162 | pub const ECONNABORTED: i32 = 103; /* Software caused connection abort */ 163 | pub const ECONNRESET: i32 = 104; /* Connection reset by peer */ 164 | pub const ENOBUFS: i32 = 105; /* No buffer space available */ 165 | pub const EISCONN: i32 = 106; /* Transport endpoint is already connected */ 166 | pub const ENOTCONN: i32 = 107; /* Transport endpoint is not connected */ 167 | pub const ESHUTDOWN: i32 = 108; /* Cannot send after transport endpoint shutdown */ 168 | pub const ETOOMANYREFS: i32 = 109; /* Too many references: cannot splice */ 169 | pub const ETIMEDOUT: i32 = 110; /* Connection timed out */ 170 | pub const ECONNREFUSED: i32 = 111; /* Connection refused */ 171 | pub const EHOSTDOWN: i32 = 112; /* Host is down */ 172 | pub const EHOSTUNREACH: i32 = 113; /* No route to host */ 173 | pub const EALREADY: i32 = 114; /* Operation already in progress */ 174 | pub const EINPROGRESS: i32 = 115; /* Operation now in progress */ 175 | pub const ESTALE: i32 = 116; /* Stale NFS file handle */ 176 | pub const EUCLEAN: i32 = 117; /* Structure needs cleaning */ 177 | pub const ENOTNAM: i32 = 118; /* Not a XENIX named type file */ 178 | pub const ENAVAIL: i32 = 119; /* No XENIX semaphores available */ 179 | pub const EISNAM: i32 = 120; /* Is a named type file */ 180 | pub const EREMOTEIO: i32 = 121; /* Remote I/O error */ 181 | pub const EDQUOT: i32 = 122; /* Quota exceeded */ 182 | pub const ENOMEDIUM: i32 = 123; /* No medium found */ 183 | pub const EMEDIUMTYPE: i32 = 124; /* Wrong medium type */ 184 | pub const ECANCELED: i32 = 125; /* Operation Canceled */ 185 | pub const ENOKEY: i32 = 126; /* Required key not available */ 186 | pub const EKEYEXPIRED: i32 = 127; /* Key has expired */ 187 | pub const EKEYREVOKED: i32 = 128; /* Key has been revoked */ 188 | pub const EKEYREJECTED: i32 = 129; /* Key was rejected by service */ 189 | pub const EOWNERDEAD: i32 = 130; /* Owner died */ 190 | pub const ENOTRECOVERABLE: i32 = 131; /* State not recoverable */ 191 | pub const ESKMSG: i32 = 132; /* Scheme-kernel message code */ 192 | 193 | pub static STR_ERROR: [&'static str; 133] = [ 194 | "Success", 195 | "Operation not permitted", 196 | "No such file or directory", 197 | "No such process", 198 | "Interrupted system call", 199 | "I/O error", 200 | "No such device or address", 201 | "Argument list too long", 202 | "Exec format error", 203 | "Bad file number", 204 | "No child processes", 205 | "Try again", 206 | "Out of memory", 207 | "Permission denied", 208 | "Bad address", 209 | "Block device required", 210 | "Device or resource busy", 211 | "File exists", 212 | "Cross-device link", 213 | "No such device", 214 | "Not a directory", 215 | "Is a directory", 216 | "Invalid argument", 217 | "File table overflow", 218 | "Too many open files", 219 | "Not a typewriter", 220 | "Text file busy", 221 | "File too large", 222 | "No space left on device", 223 | "Illegal seek", 224 | "Read-only file system", 225 | "Too many links", 226 | "Broken pipe", 227 | "Math argument out of domain of func", 228 | "Math result not representable", 229 | "Resource deadlock would occur", 230 | "File name too long", 231 | "No record locks available", 232 | "Function not implemented", 233 | "Directory not empty", 234 | "Too many symbolic links encountered", 235 | "Operation would block", 236 | "No message of desired type", 237 | "Identifier removed", 238 | "Channel number out of range", 239 | "Level 2 not synchronized", 240 | "Level 3 halted", 241 | "Level 3 reset", 242 | "Link number out of range", 243 | "Protocol driver not attached", 244 | "No CSI structure available", 245 | "Level 2 halted", 246 | "Invalid exchange", 247 | "Invalid request descriptor", 248 | "Exchange full", 249 | "No anode", 250 | "Invalid request code", 251 | "Invalid slot", 252 | "Resource deadlock would occur", 253 | "Bad font file format", 254 | "Device not a stream", 255 | "No data available", 256 | "Timer expired", 257 | "Out of streams resources", 258 | "Machine is not on the network", 259 | "Package not installed", 260 | "Object is remote", 261 | "Link has been severed", 262 | "Advertise error", 263 | "Srmount error", 264 | "Communication error on send", 265 | "Protocol error", 266 | "Multihop attempted", 267 | "RFS specific error", 268 | "Not a data message", 269 | "Value too large for defined data type", 270 | "Name not unique on network", 271 | "File descriptor in bad state", 272 | "Remote address changed", 273 | "Can not access a needed shared library", 274 | "Accessing a corrupted shared library", 275 | ".lib section in a.out corrupted", 276 | "Attempting to link in too many shared libraries", 277 | "Cannot exec a shared library directly", 278 | "Illegal byte sequence", 279 | "Interrupted system call should be restarted", 280 | "Streams pipe error", 281 | "Too many users", 282 | "Socket operation on non-socket", 283 | "Destination address required", 284 | "Message too long", 285 | "Protocol wrong type for socket", 286 | "Protocol not available", 287 | "Protocol not supported", 288 | "Socket type not supported", 289 | "Operation not supported on transport endpoint", 290 | "Protocol family not supported", 291 | "Address family not supported by protocol", 292 | "Address already in use", 293 | "Cannot assign requested address", 294 | "Network is down", 295 | "Network is unreachable", 296 | "Network dropped connection because of reset", 297 | "Software caused connection abort", 298 | "Connection reset by peer", 299 | "No buffer space available", 300 | "Transport endpoint is already connected", 301 | "Transport endpoint is not connected", 302 | "Cannot send after transport endpoint shutdown", 303 | "Too many references: cannot splice", 304 | "Connection timed out", 305 | "Connection refused", 306 | "Host is down", 307 | "No route to host", 308 | "Operation already in progress", 309 | "Operation now in progress", 310 | "Stale NFS file handle", 311 | "Structure needs cleaning", 312 | "Not a XENIX named type file", 313 | "No XENIX semaphores available", 314 | "Is a named type file", 315 | "Remote I/O error", 316 | "Quota exceeded", 317 | "No medium found", 318 | "Wrong medium type", 319 | "Operation Canceled", 320 | "Required key not available", 321 | "Key has expired", 322 | "Key has been revoked", 323 | "Key was rejected by service", 324 | "Owner died", 325 | "State not recoverable", 326 | "Scheme-kernel message code", 327 | ]; 328 | -------------------------------------------------------------------------------- /src/flag.rs: -------------------------------------------------------------------------------- 1 | use bitflags::bitflags as inner_bitflags; 2 | use core::{mem, ops::Deref, slice}; 3 | 4 | macro_rules! bitflags { 5 | ( 6 | $(#[$outer:meta])* 7 | pub struct $BitFlags:ident: $T:ty { 8 | $( 9 | $(#[$inner:ident $($args:tt)*])* 10 | const $Flag:ident = $value:expr; 11 | )+ 12 | } 13 | ) => { 14 | // First, use the inner bitflags 15 | inner_bitflags! { 16 | #[derive(PartialEq, Eq, PartialOrd, Ord, Hash, Debug, Clone, Copy, Default)] 17 | $(#[$outer])* 18 | pub struct $BitFlags: $T { 19 | $( 20 | $(#[$inner $($args)*])* 21 | const $Flag = $value; 22 | )+ 23 | } 24 | } 25 | 26 | impl $BitFlags { 27 | #[deprecated = "use the safe `from_bits_retain` method instead"] 28 | pub unsafe fn from_bits_unchecked(bits: $T) -> Self { 29 | Self::from_bits_retain(bits) 30 | } 31 | } 32 | 33 | // Secondly, re-export all inner constants 34 | // (`pub use self::Struct::*` doesn't work) 35 | $( 36 | $(#[$inner $($args)*])* 37 | pub const $Flag: $BitFlags = $BitFlags::$Flag; 38 | )+ 39 | } 40 | } 41 | 42 | pub const CLOCK_REALTIME: usize = 1; 43 | pub const CLOCK_MONOTONIC: usize = 4; 44 | 45 | bitflags! { 46 | pub struct EventFlags: usize { 47 | const EVENT_NONE = 0; 48 | const EVENT_READ = 1; 49 | const EVENT_WRITE = 2; 50 | } 51 | } 52 | 53 | pub const F_DUPFD: usize = 0; 54 | pub const F_GETFD: usize = 1; 55 | pub const F_SETFD: usize = 2; 56 | pub const F_GETFL: usize = 3; 57 | pub const F_SETFL: usize = 4; 58 | 59 | pub const FUTEX_WAIT: usize = 0; 60 | pub const FUTEX_WAKE: usize = 1; 61 | pub const FUTEX_REQUEUE: usize = 2; 62 | pub const FUTEX_WAIT64: usize = 3; 63 | 64 | // packet.c = fd 65 | pub const SKMSG_FRETURNFD: usize = 0; 66 | 67 | // packet.uid:packet.gid = offset, packet.c = base address, packet.d = page count 68 | pub const SKMSG_PROVIDE_MMAP: usize = 1; 69 | 70 | // packet.id provides state, packet.c = dest fd or pointer to dest fd, packet.d = flags 71 | pub const SKMSG_FOBTAINFD: usize = 2; 72 | 73 | // TODO: Split SendFdFlags into caller flags and flags that the scheme receives? 74 | bitflags::bitflags! { 75 | #[derive(Clone, Copy, Debug)] 76 | pub struct SendFdFlags: usize { 77 | /// If set, the kernel will enforce that the file descriptor is exclusively owned. 78 | /// 79 | /// That is, there will no longer exist any other reference to that FD when removed from 80 | /// the file table (SYS_SENDFD always removes the FD from the file table, but without this 81 | /// flag, it can be retained by SYS_DUPing it first). 82 | const EXCLUSIVE = 1; 83 | } 84 | } 85 | bitflags::bitflags! { 86 | #[derive(Clone, Copy, Debug)] 87 | pub struct FobtainFdFlags: usize { 88 | /// If set, `packet.c` specifies the destination file descriptor slot, otherwise the lowest 89 | /// available slot will be selected, and placed in the usize pointed to by `packet.c`. 90 | const MANUAL_FD = 1; 91 | 92 | // If set, the file descriptor received is guaranteed to be exclusively owned (by the file 93 | // table the obtainer is running in). 94 | const EXCLUSIVE = 2; 95 | 96 | // No, cloexec won't be stored in the kernel in the future, when the stable ABI is moved to 97 | // relibc, so no flag for that! 98 | } 99 | } 100 | 101 | bitflags! { 102 | pub struct MapFlags: usize { 103 | // TODO: Downgrade PROT_NONE to global constant? (bitflags specifically states zero flags 104 | // can cause buggy behavior). 105 | const PROT_NONE = 0x0000_0000; 106 | 107 | const PROT_EXEC = 0x0001_0000; 108 | const PROT_WRITE = 0x0002_0000; 109 | const PROT_READ = 0x0004_0000; 110 | 111 | const MAP_SHARED = 0x0001; 112 | const MAP_PRIVATE = 0x0002; 113 | 114 | const MAP_FIXED = 0x0004; 115 | const MAP_FIXED_NOREPLACE = 0x000C; 116 | 117 | /// For *userspace-backed mmaps*, return from the mmap call before all pages have been 118 | /// provided by the scheme. This requires the scheme to be trusted, as the current context 119 | /// can block indefinitely, if the scheme does not respond to the page fault handler's 120 | /// request, as it tries to map the page by requesting it from the scheme. 121 | /// 122 | /// In some cases however, such as the program loader, the data needs to be trusted as much 123 | /// with or without MAP_LAZY, and if so, mapping lazily will not cause insecureness by 124 | /// itself. 125 | /// 126 | /// For kernel-backed mmaps, this flag has no effect at all. It is unspecified whether 127 | /// kernel mmaps are lazy or not. 128 | const MAP_LAZY = 0x0010; 129 | } 130 | } 131 | bitflags! { 132 | pub struct MunmapFlags: usize { 133 | /// Indicates whether the funmap call must implicitly do an msync, for the changes to 134 | /// become visible later. 135 | /// 136 | /// This flag will currently be set if and only if MAP_SHARED | PROT_WRITE are set. 137 | const NEEDS_SYNC = 1; 138 | } 139 | } 140 | 141 | pub const MODE_TYPE: u16 = 0xF000; 142 | pub const MODE_DIR: u16 = 0x4000; 143 | pub const MODE_FILE: u16 = 0x8000; 144 | pub const MODE_SYMLINK: u16 = 0xA000; 145 | pub const MODE_FIFO: u16 = 0x1000; 146 | pub const MODE_CHR: u16 = 0x2000; 147 | 148 | pub const MODE_PERM: u16 = 0x0FFF; 149 | pub const MODE_SETUID: u16 = 0o4000; 150 | pub const MODE_SETGID: u16 = 0o2000; 151 | 152 | pub const O_RDONLY: usize = 0x0001_0000; 153 | pub const O_WRONLY: usize = 0x0002_0000; 154 | pub const O_RDWR: usize = 0x0003_0000; 155 | pub const O_NONBLOCK: usize = 0x0004_0000; 156 | pub const O_APPEND: usize = 0x0008_0000; 157 | pub const O_SHLOCK: usize = 0x0010_0000; 158 | pub const O_EXLOCK: usize = 0x0020_0000; 159 | pub const O_ASYNC: usize = 0x0040_0000; 160 | pub const O_FSYNC: usize = 0x0080_0000; 161 | pub const O_CLOEXEC: usize = 0x0100_0000; 162 | pub const O_CREAT: usize = 0x0200_0000; 163 | pub const O_TRUNC: usize = 0x0400_0000; 164 | pub const O_EXCL: usize = 0x0800_0000; 165 | pub const O_DIRECTORY: usize = 0x1000_0000; 166 | pub const O_STAT: usize = 0x2000_0000; 167 | pub const O_SYMLINK: usize = 0x4000_0000; 168 | pub const O_NOFOLLOW: usize = 0x8000_0000; 169 | pub const O_ACCMODE: usize = O_RDONLY | O_WRONLY | O_RDWR; 170 | 171 | // The top 48 bits of PTRACE_* are reserved, for now 172 | 173 | // NOT ABI STABLE! 174 | #[derive(Clone, Copy, Debug, Default, Eq, PartialEq)] 175 | #[repr(usize)] 176 | pub enum ContextStatus { 177 | Runnable, 178 | Blocked, 179 | NotYetStarted, 180 | Dead, 181 | ForceKilled, 182 | Stopped, 183 | UnhandledExcp, 184 | #[default] 185 | Other, // reserved 186 | } 187 | 188 | #[derive(Clone, Copy, Debug, Eq, PartialEq)] 189 | #[repr(usize)] 190 | pub enum ContextVerb { 191 | Stop = 1, 192 | Unstop = 2, 193 | Interrupt = 3, 194 | ForceKill = usize::MAX, 195 | } 196 | impl ContextVerb { 197 | pub fn try_from_raw(raw: usize) -> Option { 198 | Some(match raw { 199 | 1 => Self::Stop, 200 | 2 => Self::Unstop, 201 | 3 => Self::Interrupt, 202 | usize::MAX => Self::ForceKill, 203 | _ => return None, 204 | }) 205 | } 206 | } 207 | 208 | // NOT ABI STABLE! 209 | #[derive(Clone, Copy, Debug, Eq, PartialEq)] 210 | #[repr(u8)] 211 | pub enum ProcSchemeVerb { 212 | Iopl = 255, 213 | } 214 | impl ProcSchemeVerb { 215 | pub fn try_from_raw(verb: u8) -> Option { 216 | Some(match verb { 217 | 255 => Self::Iopl, 218 | _ => return None, 219 | }) 220 | } 221 | } 222 | 223 | bitflags! { 224 | pub struct PtraceFlags: u64 { 225 | /// Stop before a syscall is handled. Send PTRACE_FLAG_IGNORE to not 226 | /// handle the syscall. 227 | const PTRACE_STOP_PRE_SYSCALL = 0x0000_0000_0000_0001; 228 | /// Stop after a syscall is handled. 229 | const PTRACE_STOP_POST_SYSCALL = 0x0000_0000_0000_0002; 230 | /// Stop after exactly one instruction. TODO: This may not handle 231 | /// fexec/signal boundaries. Should it? 232 | const PTRACE_STOP_SINGLESTEP = 0x0000_0000_0000_0004; 233 | /// Stop before a signal is handled. Send PTRACE_FLAG_IGNORE to not 234 | /// handle signal. 235 | const PTRACE_STOP_SIGNAL = 0x0000_0000_0000_0008; 236 | /// Stop on a software breakpoint, such as the int3 instruction for 237 | /// x86_64. 238 | const PTRACE_STOP_BREAKPOINT = 0x0000_0000_0000_0010; 239 | /// Stop just before exiting for good. 240 | const PTRACE_STOP_EXIT = 0x0000_0000_0000_0020; 241 | 242 | const PTRACE_STOP_MASK = 0x0000_0000_0000_00FF; 243 | 244 | 245 | /// Sent when a child is cloned, giving you the opportunity to trace it. 246 | /// If you don't catch this, the child is started as normal. 247 | const PTRACE_EVENT_CLONE = 0x0000_0000_0000_0100; 248 | 249 | /// Sent when current-addrspace is changed, allowing the tracer to reopen the memory file. 250 | const PTRACE_EVENT_ADDRSPACE_SWITCH = 0x0000_0000_0000_0200; 251 | 252 | const PTRACE_EVENT_MASK = 0x0000_0000_0000_0F00; 253 | 254 | /// Special meaning, depending on the event. Usually, when fired before 255 | /// an action, it will skip performing that action. 256 | const PTRACE_FLAG_IGNORE = 0x0000_0000_0000_1000; 257 | 258 | const PTRACE_FLAG_MASK = 0x0000_0000_0000_F000; 259 | } 260 | } 261 | impl Deref for PtraceFlags { 262 | type Target = [u8]; 263 | fn deref(&self) -> &Self::Target { 264 | // Same as to_ne_bytes but in-place 265 | unsafe { 266 | slice::from_raw_parts(&self.bits() as *const _ as *const u8, mem::size_of::()) 267 | } 268 | } 269 | } 270 | 271 | pub const SEEK_SET: usize = 0; 272 | pub const SEEK_CUR: usize = 1; 273 | pub const SEEK_END: usize = 2; 274 | 275 | pub const SIGCHLD: usize = 17; 276 | pub const SIGTSTP: usize = 20; 277 | pub const SIGTTIN: usize = 21; 278 | pub const SIGTTOU: usize = 22; 279 | 280 | pub const ADDRSPACE_OP_MMAP: usize = 0; 281 | pub const ADDRSPACE_OP_MUNMAP: usize = 1; 282 | pub const ADDRSPACE_OP_MPROTECT: usize = 2; 283 | pub const ADDRSPACE_OP_TRANSFER: usize = 3; 284 | 285 | bitflags! { 286 | pub struct MremapFlags: usize { 287 | const FIXED = 1; 288 | const FIXED_REPLACE = 3; 289 | /// Alias's memory region at `old_address` to `new_address` such that both regions share 290 | /// the same frames. 291 | const KEEP_OLD = 1 << 2; 292 | // TODO: MAYMOVE, DONTUNMAP 293 | } 294 | } 295 | bitflags! { 296 | pub struct RwFlags: u32 { 297 | const NONBLOCK = 1; 298 | const APPEND = 2; 299 | // TODO: sync/dsync 300 | // TODO: O_DIRECT? 301 | } 302 | } 303 | bitflags! { 304 | pub struct SigcontrolFlags: usize { 305 | /// Prevents the kernel from jumping the context to the signal trampoline, but otherwise 306 | /// has absolutely no effect on which signals are blocked etc. Meant to be used for 307 | /// short-lived critical sections inside libc. 308 | const INHIBIT_DELIVERY = 1; 309 | } 310 | } 311 | bitflags! { 312 | pub struct CallFlags: usize { 313 | // reserved 314 | const RSVD0 = 1 << 0; 315 | const RSVD1 = 1 << 1; 316 | const RSVD2 = 1 << 2; 317 | const RSVD3 = 1 << 3; 318 | const RSVD4 = 1 << 4; 319 | const RSVD5 = 1 << 5; 320 | const RSVD6 = 1 << 6; 321 | const RSVD7 = 1 << 7; 322 | 323 | /// Remove the fd from the caller's file table before sending the message. 324 | const CONSUME = 1 << 8; 325 | } 326 | } 327 | -------------------------------------------------------------------------------- /src/io/io.rs: -------------------------------------------------------------------------------- 1 | use core::{ 2 | cmp::PartialEq, 3 | ops::{BitAnd, BitOr, Not}, 4 | }; 5 | 6 | pub trait Io { 7 | type Value: Copy 8 | + PartialEq 9 | + BitAnd 10 | + BitOr 11 | + Not; 12 | 13 | fn read(&self) -> Self::Value; 14 | fn write(&mut self, value: Self::Value); 15 | 16 | #[inline(always)] 17 | fn readf(&self, flags: Self::Value) -> bool { 18 | (self.read() & flags) as Self::Value == flags 19 | } 20 | 21 | #[inline(always)] 22 | fn writef(&mut self, flags: Self::Value, value: bool) { 23 | let tmp: Self::Value = match value { 24 | true => self.read() | flags, 25 | false => self.read() & !flags, 26 | }; 27 | self.write(tmp); 28 | } 29 | } 30 | 31 | pub struct ReadOnly { 32 | inner: I, 33 | } 34 | 35 | impl ReadOnly { 36 | pub const fn new(inner: I) -> ReadOnly { 37 | ReadOnly { inner: inner } 38 | } 39 | } 40 | 41 | impl ReadOnly { 42 | #[inline(always)] 43 | pub fn read(&self) -> I::Value { 44 | self.inner.read() 45 | } 46 | 47 | #[inline(always)] 48 | pub fn readf(&self, flags: I::Value) -> bool { 49 | self.inner.readf(flags) 50 | } 51 | } 52 | 53 | pub struct WriteOnly { 54 | inner: I, 55 | } 56 | 57 | impl WriteOnly { 58 | pub const fn new(inner: I) -> WriteOnly { 59 | WriteOnly { inner: inner } 60 | } 61 | } 62 | 63 | impl WriteOnly { 64 | #[inline(always)] 65 | pub fn write(&mut self, value: I::Value) { 66 | self.inner.write(value) 67 | } 68 | 69 | #[inline(always)] 70 | pub fn writef(&mut self, flags: I::Value, value: bool) { 71 | self.inner.writef(flags, value) 72 | } 73 | } 74 | -------------------------------------------------------------------------------- /src/io/mmio.rs: -------------------------------------------------------------------------------- 1 | #[cfg(not(any(target_arch = "x86", target_arch = "x86_64")))] 2 | use core::ops::{BitAnd, BitOr, Not}; 3 | use core::{mem::MaybeUninit, ptr}; 4 | 5 | use super::io::Io; 6 | 7 | #[repr(transparent)] 8 | pub struct Mmio { 9 | value: MaybeUninit, 10 | } 11 | 12 | impl Mmio { 13 | pub unsafe fn zeroed() -> Self { 14 | Self { 15 | value: MaybeUninit::zeroed(), 16 | } 17 | } 18 | pub unsafe fn uninit() -> Self { 19 | Self { 20 | value: MaybeUninit::uninit(), 21 | } 22 | } 23 | pub const fn from(value: T) -> Self { 24 | Self { 25 | value: MaybeUninit::new(value), 26 | } 27 | } 28 | } 29 | 30 | // Generic implementation (WARNING: requires aligned pointers!) 31 | #[cfg(not(any(target_arch = "x86", target_arch = "x86_64")))] 32 | impl Io for Mmio 33 | where 34 | T: Copy + PartialEq + BitAnd + BitOr + Not, 35 | { 36 | type Value = T; 37 | 38 | fn read(&self) -> T { 39 | unsafe { ptr::read_volatile(ptr::addr_of!(self.value).cast::()) } 40 | } 41 | 42 | fn write(&mut self, value: T) { 43 | unsafe { ptr::write_volatile(ptr::addr_of_mut!(self.value).cast::(), value) }; 44 | } 45 | } 46 | 47 | // x86 u8 implementation 48 | #[cfg(any(target_arch = "x86", target_arch = "x86_64"))] 49 | impl Io for Mmio { 50 | type Value = u8; 51 | 52 | fn read(&self) -> Self::Value { 53 | unsafe { 54 | let value: Self::Value; 55 | let ptr: *const Self::Value = ptr::addr_of!(self.value).cast::(); 56 | core::arch::asm!( 57 | "mov {}, [{}]", 58 | out(reg_byte) value, 59 | in(reg) ptr 60 | ); 61 | value 62 | } 63 | } 64 | 65 | fn write(&mut self, value: Self::Value) { 66 | unsafe { 67 | let ptr: *mut Self::Value = ptr::addr_of_mut!(self.value).cast::(); 68 | core::arch::asm!( 69 | "mov [{}], {}", 70 | in(reg) ptr, 71 | in(reg_byte) value, 72 | ); 73 | } 74 | } 75 | } 76 | 77 | // x86 u16 implementation 78 | #[cfg(any(target_arch = "x86", target_arch = "x86_64"))] 79 | impl Io for Mmio { 80 | type Value = u16; 81 | 82 | fn read(&self) -> Self::Value { 83 | unsafe { 84 | let value: Self::Value; 85 | let ptr: *const Self::Value = ptr::addr_of!(self.value).cast::(); 86 | core::arch::asm!( 87 | "mov {:x}, [{}]", 88 | out(reg) value, 89 | in(reg) ptr 90 | ); 91 | value 92 | } 93 | } 94 | 95 | fn write(&mut self, value: Self::Value) { 96 | unsafe { 97 | let ptr: *mut Self::Value = ptr::addr_of_mut!(self.value).cast::(); 98 | core::arch::asm!( 99 | "mov [{}], {:x}", 100 | in(reg) ptr, 101 | in(reg) value, 102 | ); 103 | } 104 | } 105 | } 106 | 107 | // x86 u32 implementation 108 | #[cfg(any(target_arch = "x86", target_arch = "x86_64"))] 109 | impl Io for Mmio { 110 | type Value = u32; 111 | 112 | fn read(&self) -> Self::Value { 113 | unsafe { 114 | let value: Self::Value; 115 | let ptr: *const Self::Value = ptr::addr_of!(self.value).cast::(); 116 | core::arch::asm!( 117 | "mov {:e}, [{}]", 118 | out(reg) value, 119 | in(reg) ptr 120 | ); 121 | value 122 | } 123 | } 124 | 125 | fn write(&mut self, value: Self::Value) { 126 | unsafe { 127 | let ptr: *mut Self::Value = ptr::addr_of_mut!(self.value).cast::(); 128 | core::arch::asm!( 129 | "mov [{}], {:e}", 130 | in(reg) ptr, 131 | in(reg) value, 132 | ); 133 | } 134 | } 135 | } 136 | 137 | // x86 u64 implementation (x86_64 only) 138 | #[cfg(target_arch = "x86_64")] 139 | impl Io for Mmio { 140 | type Value = u64; 141 | 142 | fn read(&self) -> Self::Value { 143 | unsafe { 144 | let value: Self::Value; 145 | let ptr: *const Self::Value = ptr::addr_of!(self.value).cast::(); 146 | core::arch::asm!( 147 | "mov {:r}, [{}]", 148 | out(reg) value, 149 | in(reg) ptr 150 | ); 151 | value 152 | } 153 | } 154 | 155 | fn write(&mut self, value: Self::Value) { 156 | unsafe { 157 | let ptr: *mut Self::Value = ptr::addr_of_mut!(self.value).cast::(); 158 | core::arch::asm!( 159 | "mov [{}], {:r}", 160 | in(reg) ptr, 161 | in(reg) value, 162 | ); 163 | } 164 | } 165 | } 166 | -------------------------------------------------------------------------------- /src/io/mod.rs: -------------------------------------------------------------------------------- 1 | //! I/O functions 2 | 3 | pub use self::{io::*, mmio::*}; 4 | 5 | #[cfg(any(target_arch = "x86", target_arch = "x86_64"))] 6 | pub use self::pio::*; 7 | 8 | mod io; 9 | mod mmio; 10 | 11 | #[cfg(any(target_arch = "x86", target_arch = "x86_64"))] 12 | mod pio; 13 | -------------------------------------------------------------------------------- /src/io/pio.rs: -------------------------------------------------------------------------------- 1 | use core::{arch::asm, marker::PhantomData}; 2 | 3 | use super::io::Io; 4 | 5 | /// Generic PIO 6 | #[derive(Copy, Clone)] 7 | pub struct Pio { 8 | port: u16, 9 | value: PhantomData, 10 | } 11 | 12 | impl Pio { 13 | /// Create a PIO from a given port 14 | pub const fn new(port: u16) -> Self { 15 | Pio:: { 16 | port, 17 | value: PhantomData, 18 | } 19 | } 20 | } 21 | 22 | /// Read/Write for byte PIO 23 | impl Io for Pio { 24 | type Value = u8; 25 | 26 | /// Read 27 | #[inline(always)] 28 | fn read(&self) -> u8 { 29 | let value: u8; 30 | unsafe { 31 | asm!("in al, dx", in("dx") self.port, out("al") value, options(nostack, nomem, preserves_flags)); 32 | } 33 | value 34 | } 35 | 36 | /// Write 37 | #[inline(always)] 38 | fn write(&mut self, value: u8) { 39 | unsafe { 40 | asm!("out dx, al", in("dx") self.port, in("al") value, options(nostack, nomem, preserves_flags)); 41 | } 42 | } 43 | } 44 | 45 | /// Read/Write for word PIO 46 | impl Io for Pio { 47 | type Value = u16; 48 | 49 | /// Read 50 | #[inline(always)] 51 | fn read(&self) -> u16 { 52 | let value: u16; 53 | unsafe { 54 | asm!("in ax, dx", in("dx") self.port, out("ax") value, options(nostack, nomem, preserves_flags)); 55 | } 56 | value 57 | } 58 | 59 | /// Write 60 | #[inline(always)] 61 | fn write(&mut self, value: u16) { 62 | unsafe { 63 | asm!("out dx, ax", in("dx") self.port, in("ax") value, options(nostack, nomem, preserves_flags)); 64 | } 65 | } 66 | } 67 | 68 | /// Read/Write for doubleword PIO 69 | impl Io for Pio { 70 | type Value = u32; 71 | 72 | /// Read 73 | #[inline(always)] 74 | fn read(&self) -> u32 { 75 | let value: u32; 76 | unsafe { 77 | asm!("in eax, dx", in("dx") self.port, out("eax") value, options(nostack, nomem, preserves_flags)); 78 | } 79 | value 80 | } 81 | 82 | /// Write 83 | #[inline(always)] 84 | fn write(&mut self, value: u32) { 85 | unsafe { 86 | asm!("out dx, eax", in("dx") self.port, in("eax") value, options(nostack, nomem, preserves_flags)); 87 | } 88 | } 89 | } 90 | -------------------------------------------------------------------------------- /src/lib.rs: -------------------------------------------------------------------------------- 1 | #![cfg_attr(not(any(feature = "std", test)), no_std)] 2 | #![allow(unexpected_cfgs)] // why does this even exist? 3 | 4 | #[cfg(test)] 5 | extern crate core; 6 | 7 | pub use self::{arch::*, data::*, error::*, flag::*, io::*, number::*}; 8 | 9 | #[cfg(target_arch = "aarch64")] 10 | #[path = "arch/aarch64.rs"] 11 | mod arch; 12 | 13 | #[cfg(target_arch = "riscv64")] 14 | #[path = "arch/riscv64.rs"] 15 | mod arch; 16 | 17 | #[cfg(target_arch = "x86")] 18 | #[path = "arch/x86.rs"] 19 | mod arch; 20 | 21 | #[cfg(target_arch = "x86_64")] 22 | #[path = "arch/x86_64.rs"] 23 | mod arch; 24 | 25 | /// Function definitions 26 | #[cfg(feature = "userspace")] 27 | pub mod call; 28 | 29 | #[cfg(feature = "userspace")] 30 | pub use call::*; 31 | 32 | /// Complex structures that are used for some system calls 33 | pub mod data; 34 | 35 | pub mod dirent; 36 | 37 | /// All errors that can be generated by a system call 38 | pub mod error; 39 | 40 | /// Flags used as an argument to many system calls 41 | pub mod flag; 42 | 43 | /// Functions for low level hardware control 44 | pub mod io; 45 | 46 | /// Call numbers used by each system call 47 | pub mod number; 48 | 49 | /// ABI for shared memory based signals 50 | pub mod sigabi; 51 | 52 | /// V2 scheme format 53 | pub mod schemev2; 54 | 55 | pub mod scheme; 56 | pub use scheme::*; 57 | -------------------------------------------------------------------------------- /src/number.rs: -------------------------------------------------------------------------------- 1 | pub const SYS_CLASS: usize = 0xF000_0000; 2 | pub const SYS_CLASS_PATH: usize = 0x1000_0000; 3 | pub const SYS_CLASS_FILE: usize = 0x2000_0000; 4 | 5 | pub const SYS_ARG: usize = 0x0F00_0000; 6 | pub const SYS_ARG_SLICE: usize = 0x0100_0000; 7 | pub const SYS_ARG_MSLICE: usize = 0x0200_0000; 8 | pub const SYS_ARG_PATH: usize = 0x0300_0000; 9 | 10 | pub const SYS_RET: usize = 0x00F0_0000; 11 | pub const SYS_RET_FILE: usize = 0x0010_0000; 12 | 13 | pub const SYS_OPEN: usize = SYS_CLASS_PATH | SYS_RET_FILE | 5; 14 | pub const SYS_OPENAT: usize = SYS_CLASS_PATH | SYS_RET_FILE | 7; 15 | pub const SYS_RMDIR: usize = SYS_CLASS_PATH | 84; 16 | pub const SYS_UNLINK: usize = SYS_CLASS_PATH | 10; 17 | 18 | pub const SYS_CLOSE: usize = SYS_CLASS_FILE | 6; 19 | pub const SYS_DUP: usize = SYS_CLASS_FILE | SYS_RET_FILE | 41; 20 | pub const SYS_DUP2: usize = SYS_CLASS_FILE | SYS_RET_FILE | 63; 21 | pub const SYS_READ: usize = SYS_CLASS_FILE | SYS_ARG_MSLICE | 3; 22 | pub const SYS_READ2: usize = SYS_CLASS_FILE | SYS_ARG_MSLICE | 35; 23 | pub const SYS_WRITE: usize = SYS_CLASS_FILE | SYS_ARG_SLICE | 4; 24 | pub const SYS_WRITE2: usize = SYS_CLASS_FILE | SYS_ARG_SLICE | 45; 25 | pub const SYS_LSEEK: usize = SYS_CLASS_FILE | 19; 26 | pub const SYS_FCHMOD: usize = SYS_CLASS_FILE | 94; 27 | pub const SYS_FCHOWN: usize = SYS_CLASS_FILE | 207; 28 | pub const SYS_FCNTL: usize = SYS_CLASS_FILE | 55; 29 | pub const SYS_FEVENT: usize = SYS_CLASS_FILE | 927; 30 | 31 | // SYS_CALL, fd, inout buf ptr, inout buf len, flags, metadata buf ptr, metadata buf len 32 | pub const SYS_CALL: usize = SYS_CLASS_FILE | SYS_ARG_SLICE | SYS_ARG_MSLICE | 0xCA11; 33 | 34 | pub const SYS_SENDFD: usize = SYS_CLASS_FILE | 34; 35 | pub const SYS_GETDENTS: usize = SYS_CLASS_FILE | 43; 36 | 37 | // TODO: Rename FMAP/FUNMAP to MMAP/MUNMAP 38 | pub const SYS_FMAP_OLD: usize = SYS_CLASS_FILE | SYS_ARG_SLICE | 90; 39 | pub const SYS_FMAP: usize = SYS_CLASS_FILE | SYS_ARG_SLICE | 900; 40 | // TODO: SYS_FUNMAP should be SYS_CLASS_FILE 41 | // TODO: Remove FMAP/FMAP_OLD 42 | pub const SYS_FUNMAP_OLD: usize = SYS_CLASS_FILE | 91; 43 | pub const SYS_FUNMAP: usize = SYS_CLASS_FILE | 92; 44 | pub const SYS_MREMAP: usize = 155; 45 | 46 | pub const SYS_FLINK: usize = SYS_CLASS_FILE | SYS_ARG_PATH | 9; 47 | pub const SYS_FPATH: usize = SYS_CLASS_FILE | SYS_ARG_MSLICE | 928; 48 | pub const SYS_FRENAME: usize = SYS_CLASS_FILE | SYS_ARG_PATH | 38; 49 | pub const SYS_FSTAT: usize = SYS_CLASS_FILE | SYS_ARG_MSLICE | 28; 50 | pub const SYS_FSTATVFS: usize = SYS_CLASS_FILE | SYS_ARG_MSLICE | 100; 51 | pub const SYS_FSYNC: usize = SYS_CLASS_FILE | 118; 52 | pub const SYS_FTRUNCATE: usize = SYS_CLASS_FILE | 93; 53 | pub const SYS_FUTIMENS: usize = SYS_CLASS_FILE | SYS_ARG_SLICE | 320; 54 | 55 | // b = file, c = flags, d = required_page_count, uid:gid = offset 56 | pub const KSMSG_MMAP: usize = SYS_CLASS_FILE | 72; 57 | 58 | // b = file, c = flags, d = page_count, uid:gid = offset 59 | pub const KSMSG_MSYNC: usize = SYS_CLASS_FILE | 73; 60 | 61 | // b = file, c = page_count, uid:gid = offset 62 | pub const KSMSG_MUNMAP: usize = SYS_CLASS_FILE | 74; 63 | 64 | // b = file, c = flags, d = page_count, uid:gid = offset 65 | pub const KSMSG_MMAP_PREP: usize = SYS_CLASS_FILE | 75; 66 | 67 | // b = target_packetid_lo32, c = target_packetid_hi32 68 | pub const KSMSG_CANCEL: usize = SYS_CLASS_FILE | 76; 69 | 70 | pub const SYS_CLOCK_GETTIME: usize = 265; 71 | pub const SYS_FUTEX: usize = 240; 72 | pub const SYS_MPROTECT: usize = 125; 73 | pub const SYS_MKNS: usize = 984; 74 | pub const SYS_NANOSLEEP: usize = 162; 75 | pub const SYS_YIELD: usize = 158; 76 | -------------------------------------------------------------------------------- /src/scheme/generate.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | set -e 4 | 5 | echo "Generating SchemeMut from Scheme" 6 | sed 's/trait Scheme/trait SchemeMut/' scheme.rs \ 7 | | sed 's/\&self/\&mut self/g' \ 8 | > scheme_mut.rs 9 | 10 | echo "Generating SchemeBlock from Scheme" 11 | sed 's/trait Scheme/trait SchemeBlock/' scheme.rs \ 12 | | sed 's/fn handle(\&self, packet: \&mut Packet)/fn handle(\&self, packet: \&Packet) -> Option/' \ 13 | | sed 's/packet.a = Error::mux(res);/res.transpose().map(Error::mux)/' \ 14 | | sed 's/\.map(|f| f\.bits())/\.map(|f| f.map(|f| f.bits()))/' \ 15 | | sed 's/\.map(|o| o as usize)/.map(|o| o.map(|o| o as usize))/' \ 16 | | sed 's/Ok(0)/Ok(Some(0))/g' \ 17 | | sed 's/Result<\([^>]\+\)>/Result>/g' \ 18 | | sed 's/convert_to_this_scheme/convert_to_this_scheme_block/g' \ 19 | | sed 's/convert_in_scheme_handle/convert_in_scheme_handle_block/g' \ 20 | > scheme_block.rs 21 | 22 | echo "Generating SchemeBlockMut from SchemeBlock" 23 | sed 's/trait SchemeBlock/trait SchemeBlockMut/' scheme_block.rs \ 24 | | sed 's/\&self/\&mut self/g' \ 25 | > scheme_block_mut.rs 26 | -------------------------------------------------------------------------------- /src/scheme/mod.rs: -------------------------------------------------------------------------------- 1 | use core::{slice, str}; 2 | 3 | use crate::{Error, Packet, Result, EOPNOTSUPP, ESKMSG, SKMSG_FRETURNFD}; 4 | 5 | pub use self::{ 6 | scheme::Scheme, scheme_block::SchemeBlock, scheme_block_mut::SchemeBlockMut, 7 | scheme_mut::SchemeMut, seek::*, 8 | }; 9 | 10 | unsafe fn str_from_raw_parts(ptr: *const u8, len: usize) -> Option<&'static str> { 11 | let slice = slice::from_raw_parts(ptr, len); 12 | str::from_utf8(slice).ok() 13 | } 14 | 15 | mod scheme; 16 | mod scheme_block; 17 | mod scheme_block_mut; 18 | mod scheme_mut; 19 | mod seek; 20 | 21 | pub struct CallerCtx { 22 | pub pid: usize, 23 | pub uid: u32, 24 | pub gid: u32, 25 | } 26 | 27 | pub enum OpenResult { 28 | ThisScheme { number: usize }, 29 | OtherScheme { fd: usize }, 30 | } 31 | 32 | // TODO: Find a better solution than generate.sh 33 | pub(crate) fn convert_to_this_scheme(r: Result) -> Result { 34 | r.map(|number| OpenResult::ThisScheme { number }) 35 | } 36 | pub(crate) fn convert_to_this_scheme_block(r: Result>) -> Result> { 37 | r.map(|o| o.map(|number| OpenResult::ThisScheme { number })) 38 | } 39 | pub(crate) fn convert_in_scheme_handle_block( 40 | _: &Packet, 41 | result: Result>, 42 | ) -> Result> { 43 | match result { 44 | Ok(Some(OpenResult::ThisScheme { number })) => Ok(Some(number)), 45 | Ok(Some(OpenResult::OtherScheme { .. })) => Err(Error::new(EOPNOTSUPP)), 46 | Ok(None) => Ok(None), 47 | Err(err) => Err(err), 48 | } 49 | } 50 | pub(crate) fn convert_in_scheme_handle( 51 | packet: &mut Packet, 52 | result: Result, 53 | ) -> Result { 54 | match result { 55 | Ok(OpenResult::ThisScheme { number }) => Ok(number), 56 | Ok(OpenResult::OtherScheme { fd }) => { 57 | packet.b = SKMSG_FRETURNFD; 58 | packet.c = fd; 59 | Err(Error::new(ESKMSG)) 60 | } 61 | Err(err) => Err(err), 62 | } 63 | } 64 | 65 | impl CallerCtx { 66 | pub fn from_packet(packet: &Packet) -> Self { 67 | Self { 68 | pid: packet.pid, 69 | uid: packet.uid, 70 | gid: packet.gid, 71 | } 72 | } 73 | } 74 | -------------------------------------------------------------------------------- /src/scheme/scheme.rs: -------------------------------------------------------------------------------- 1 | use core::{mem, slice}; 2 | 3 | use crate::{data::*, error::*, flag::*, number::*, scheme::*, CallerCtx, OpenResult}; 4 | 5 | pub trait Scheme { 6 | fn handle(&self, packet: &mut Packet) { 7 | let res = match packet.a { 8 | SYS_OPEN => { 9 | if let Some(path) = unsafe { str_from_raw_parts(packet.b as *const u8, packet.c) } { 10 | convert_in_scheme_handle( 11 | packet, 12 | self.xopen(path, packet.d, &CallerCtx::from_packet(&packet)), 13 | ) 14 | } else { 15 | Err(Error::new(EINVAL)) 16 | } 17 | } 18 | SYS_RMDIR => { 19 | if let Some(path) = unsafe { str_from_raw_parts(packet.b as *const u8, packet.c) } { 20 | self.rmdir(path, packet.uid, packet.gid) 21 | } else { 22 | Err(Error::new(EINVAL)) 23 | } 24 | } 25 | SYS_UNLINK => { 26 | if let Some(path) = unsafe { str_from_raw_parts(packet.b as *const u8, packet.c) } { 27 | self.unlink(path, packet.uid, packet.gid) 28 | } else { 29 | Err(Error::new(EINVAL)) 30 | } 31 | } 32 | 33 | SYS_DUP => convert_in_scheme_handle( 34 | packet, 35 | self.xdup( 36 | packet.b, 37 | unsafe { slice::from_raw_parts(packet.c as *const u8, packet.d) }, 38 | &CallerCtx::from_packet(&packet), 39 | ), 40 | ), 41 | SYS_READ => self.read(packet.b, unsafe { 42 | slice::from_raw_parts_mut(packet.c as *mut u8, packet.d) 43 | }), 44 | SYS_WRITE => self.write(packet.b, unsafe { 45 | slice::from_raw_parts(packet.c as *const u8, packet.d) 46 | }), 47 | SYS_LSEEK => self 48 | .seek(packet.b, packet.c as isize, packet.d) 49 | .map(|o| o as usize), 50 | SYS_FCHMOD => self.fchmod(packet.b, packet.c as u16), 51 | SYS_FCHOWN => self.fchown(packet.b, packet.c as u32, packet.d as u32), 52 | SYS_FCNTL => self.fcntl(packet.b, packet.c, packet.d), 53 | SYS_FEVENT => self 54 | .fevent(packet.b, EventFlags::from_bits_truncate(packet.c)) 55 | .map(|f| f.bits()), 56 | SYS_FLINK => { 57 | if let Some(path) = unsafe { str_from_raw_parts(packet.c as *const u8, packet.d) } { 58 | self.flink(packet.b, path, packet.uid, packet.gid) 59 | } else { 60 | Err(Error::new(EINVAL)) 61 | } 62 | } 63 | SYS_FPATH => self.fpath(packet.b, unsafe { 64 | slice::from_raw_parts_mut(packet.c as *mut u8, packet.d) 65 | }), 66 | SYS_FRENAME => { 67 | if let Some(path) = unsafe { str_from_raw_parts(packet.c as *const u8, packet.d) } { 68 | self.frename(packet.b, path, packet.uid, packet.gid) 69 | } else { 70 | Err(Error::new(EINVAL)) 71 | } 72 | } 73 | SYS_FSTAT => { 74 | if packet.d >= mem::size_of::() { 75 | self.fstat(packet.b, unsafe { &mut *(packet.c as *mut Stat) }) 76 | } else { 77 | Err(Error::new(EFAULT)) 78 | } 79 | } 80 | SYS_FSTATVFS => { 81 | if packet.d >= mem::size_of::() { 82 | self.fstatvfs(packet.b, unsafe { &mut *(packet.c as *mut StatVfs) }) 83 | } else { 84 | Err(Error::new(EFAULT)) 85 | } 86 | } 87 | SYS_FSYNC => self.fsync(packet.b), 88 | SYS_FTRUNCATE => self.ftruncate(packet.b, packet.c), 89 | SYS_FUTIMENS => { 90 | if packet.d >= mem::size_of::() { 91 | self.futimens(packet.b, unsafe { 92 | slice::from_raw_parts( 93 | packet.c as *const TimeSpec, 94 | packet.d / mem::size_of::(), 95 | ) 96 | }) 97 | } else { 98 | Err(Error::new(EFAULT)) 99 | } 100 | } 101 | SYS_CLOSE => self.close(packet.b), 102 | 103 | KSMSG_MMAP_PREP => self.mmap_prep( 104 | packet.b, 105 | u64::from(packet.uid) | (u64::from(packet.gid) << 32), 106 | packet.c, 107 | MapFlags::from_bits_truncate(packet.d), 108 | ), 109 | KSMSG_MUNMAP => self.munmap( 110 | packet.b, 111 | u64::from(packet.uid) | (u64::from(packet.gid) << 32), 112 | packet.c, 113 | MunmapFlags::from_bits_truncate(packet.d), 114 | ), 115 | 116 | _ => Err(Error::new(ENOSYS)), 117 | }; 118 | 119 | packet.a = Error::mux(res); 120 | } 121 | 122 | /* Scheme operations */ 123 | 124 | #[allow(unused_variables)] 125 | fn open(&self, path: &str, flags: usize, uid: u32, gid: u32) -> Result { 126 | Err(Error::new(ENOENT)) 127 | } 128 | #[allow(unused_variables)] 129 | fn xopen(&self, path: &str, flags: usize, ctx: &CallerCtx) -> Result { 130 | convert_to_this_scheme(self.open(path, flags, ctx.uid, ctx.gid)) 131 | } 132 | 133 | #[allow(unused_variables)] 134 | fn chmod(&self, path: &str, mode: u16, uid: u32, gid: u32) -> Result { 135 | Err(Error::new(ENOENT)) 136 | } 137 | 138 | #[allow(unused_variables)] 139 | fn rmdir(&self, path: &str, uid: u32, gid: u32) -> Result { 140 | Err(Error::new(ENOENT)) 141 | } 142 | 143 | #[allow(unused_variables)] 144 | fn unlink(&self, path: &str, uid: u32, gid: u32) -> Result { 145 | Err(Error::new(ENOENT)) 146 | } 147 | 148 | /* Resource operations */ 149 | #[allow(unused_variables)] 150 | fn dup(&self, old_id: usize, buf: &[u8]) -> Result { 151 | Err(Error::new(EBADF)) 152 | } 153 | 154 | #[allow(unused_variables)] 155 | fn xdup(&self, old_id: usize, buf: &[u8], ctx: &CallerCtx) -> Result { 156 | convert_to_this_scheme(self.dup(old_id, buf)) 157 | } 158 | 159 | #[allow(unused_variables)] 160 | fn read(&self, id: usize, buf: &mut [u8]) -> Result { 161 | Err(Error::new(EBADF)) 162 | } 163 | 164 | #[allow(unused_variables)] 165 | fn write(&self, id: usize, buf: &[u8]) -> Result { 166 | Err(Error::new(EBADF)) 167 | } 168 | 169 | #[allow(unused_variables)] 170 | fn seek(&self, id: usize, pos: isize, whence: usize) -> Result { 171 | Err(Error::new(EBADF)) 172 | } 173 | 174 | #[allow(unused_variables)] 175 | fn fchmod(&self, id: usize, mode: u16) -> Result { 176 | Err(Error::new(EBADF)) 177 | } 178 | 179 | #[allow(unused_variables)] 180 | fn fchown(&self, id: usize, uid: u32, gid: u32) -> Result { 181 | Err(Error::new(EBADF)) 182 | } 183 | 184 | #[allow(unused_variables)] 185 | fn fcntl(&self, id: usize, cmd: usize, arg: usize) -> Result { 186 | Err(Error::new(EBADF)) 187 | } 188 | 189 | #[allow(unused_variables)] 190 | fn fevent(&self, id: usize, flags: EventFlags) -> Result { 191 | Err(Error::new(EBADF)) 192 | } 193 | 194 | #[allow(unused_variables)] 195 | fn flink(&self, id: usize, path: &str, uid: u32, gid: u32) -> Result { 196 | Err(Error::new(EBADF)) 197 | } 198 | 199 | #[allow(unused_variables)] 200 | fn fpath(&self, id: usize, buf: &mut [u8]) -> Result { 201 | Err(Error::new(EBADF)) 202 | } 203 | 204 | #[allow(unused_variables)] 205 | fn frename(&self, id: usize, path: &str, uid: u32, gid: u32) -> Result { 206 | Err(Error::new(EBADF)) 207 | } 208 | 209 | #[allow(unused_variables)] 210 | fn fstat(&self, id: usize, stat: &mut Stat) -> Result { 211 | Err(Error::new(EBADF)) 212 | } 213 | 214 | #[allow(unused_variables)] 215 | fn fstatvfs(&self, id: usize, stat: &mut StatVfs) -> Result { 216 | Err(Error::new(EBADF)) 217 | } 218 | 219 | #[allow(unused_variables)] 220 | fn fsync(&self, id: usize) -> Result { 221 | Err(Error::new(EBADF)) 222 | } 223 | 224 | #[allow(unused_variables)] 225 | fn ftruncate(&self, id: usize, len: usize) -> Result { 226 | Err(Error::new(EBADF)) 227 | } 228 | 229 | #[allow(unused_variables)] 230 | fn futimens(&self, id: usize, times: &[TimeSpec]) -> Result { 231 | Err(Error::new(EBADF)) 232 | } 233 | 234 | #[allow(unused_variables)] 235 | fn close(&self, id: usize) -> Result { 236 | Err(Error::new(EBADF)) 237 | } 238 | 239 | #[allow(unused_variables)] 240 | fn mmap_prep(&self, id: usize, offset: u64, size: usize, flags: MapFlags) -> Result { 241 | Err(Error::new(EOPNOTSUPP)) 242 | } 243 | 244 | #[allow(unused_variables)] 245 | fn munmap(&self, id: usize, offset: u64, size: usize, flags: MunmapFlags) -> Result { 246 | Err(Error::new(EOPNOTSUPP)) 247 | } 248 | } 249 | -------------------------------------------------------------------------------- /src/scheme/scheme_block.rs: -------------------------------------------------------------------------------- 1 | use core::{mem, slice}; 2 | 3 | use crate::{data::*, error::*, flag::*, number::*, scheme::*, CallerCtx, OpenResult}; 4 | 5 | pub trait SchemeBlock { 6 | fn handle(&self, packet: &Packet) -> Option { 7 | let res = match packet.a { 8 | SYS_OPEN => { 9 | if let Some(path) = unsafe { str_from_raw_parts(packet.b as *const u8, packet.c) } { 10 | convert_in_scheme_handle_block( 11 | packet, 12 | self.xopen(path, packet.d, &CallerCtx::from_packet(&packet)), 13 | ) 14 | } else { 15 | Err(Error::new(EINVAL)) 16 | } 17 | } 18 | SYS_RMDIR => { 19 | if let Some(path) = unsafe { str_from_raw_parts(packet.b as *const u8, packet.c) } { 20 | self.rmdir(path, packet.uid, packet.gid) 21 | } else { 22 | Err(Error::new(EINVAL)) 23 | } 24 | } 25 | SYS_UNLINK => { 26 | if let Some(path) = unsafe { str_from_raw_parts(packet.b as *const u8, packet.c) } { 27 | self.unlink(path, packet.uid, packet.gid) 28 | } else { 29 | Err(Error::new(EINVAL)) 30 | } 31 | } 32 | 33 | SYS_DUP => convert_in_scheme_handle_block( 34 | packet, 35 | self.xdup( 36 | packet.b, 37 | unsafe { slice::from_raw_parts(packet.c as *const u8, packet.d) }, 38 | &CallerCtx::from_packet(&packet), 39 | ), 40 | ), 41 | SYS_READ => self.read(packet.b, unsafe { 42 | slice::from_raw_parts_mut(packet.c as *mut u8, packet.d) 43 | }), 44 | SYS_WRITE => self.write(packet.b, unsafe { 45 | slice::from_raw_parts(packet.c as *const u8, packet.d) 46 | }), 47 | SYS_LSEEK => self 48 | .seek(packet.b, packet.c as isize, packet.d) 49 | .map(|o| o.map(|o| o as usize)), 50 | SYS_FCHMOD => self.fchmod(packet.b, packet.c as u16), 51 | SYS_FCHOWN => self.fchown(packet.b, packet.c as u32, packet.d as u32), 52 | SYS_FCNTL => self.fcntl(packet.b, packet.c, packet.d), 53 | SYS_FEVENT => self 54 | .fevent(packet.b, EventFlags::from_bits_truncate(packet.c)) 55 | .map(|f| f.map(|f| f.bits())), 56 | SYS_FLINK => { 57 | if let Some(path) = unsafe { str_from_raw_parts(packet.c as *const u8, packet.d) } { 58 | self.flink(packet.b, path, packet.uid, packet.gid) 59 | } else { 60 | Err(Error::new(EINVAL)) 61 | } 62 | } 63 | SYS_FPATH => self.fpath(packet.b, unsafe { 64 | slice::from_raw_parts_mut(packet.c as *mut u8, packet.d) 65 | }), 66 | SYS_FRENAME => { 67 | if let Some(path) = unsafe { str_from_raw_parts(packet.c as *const u8, packet.d) } { 68 | self.frename(packet.b, path, packet.uid, packet.gid) 69 | } else { 70 | Err(Error::new(EINVAL)) 71 | } 72 | } 73 | SYS_FSTAT => { 74 | if packet.d >= mem::size_of::() { 75 | self.fstat(packet.b, unsafe { &mut *(packet.c as *mut Stat) }) 76 | } else { 77 | Err(Error::new(EFAULT)) 78 | } 79 | } 80 | SYS_FSTATVFS => { 81 | if packet.d >= mem::size_of::() { 82 | self.fstatvfs(packet.b, unsafe { &mut *(packet.c as *mut StatVfs) }) 83 | } else { 84 | Err(Error::new(EFAULT)) 85 | } 86 | } 87 | SYS_FSYNC => self.fsync(packet.b), 88 | SYS_FTRUNCATE => self.ftruncate(packet.b, packet.c), 89 | SYS_FUTIMENS => { 90 | if packet.d >= mem::size_of::() { 91 | self.futimens(packet.b, unsafe { 92 | slice::from_raw_parts( 93 | packet.c as *const TimeSpec, 94 | packet.d / mem::size_of::(), 95 | ) 96 | }) 97 | } else { 98 | Err(Error::new(EFAULT)) 99 | } 100 | } 101 | SYS_CLOSE => self.close(packet.b), 102 | 103 | KSMSG_MMAP_PREP => self.mmap_prep( 104 | packet.b, 105 | u64::from(packet.uid) | (u64::from(packet.gid) << 32), 106 | packet.c, 107 | MapFlags::from_bits_truncate(packet.d), 108 | ), 109 | KSMSG_MUNMAP => self.munmap( 110 | packet.b, 111 | u64::from(packet.uid) | (u64::from(packet.gid) << 32), 112 | packet.c, 113 | MunmapFlags::from_bits_truncate(packet.d), 114 | ), 115 | 116 | _ => Err(Error::new(ENOSYS)), 117 | }; 118 | 119 | res.transpose().map(Error::mux) 120 | } 121 | 122 | /* Scheme operations */ 123 | 124 | #[allow(unused_variables)] 125 | fn open(&self, path: &str, flags: usize, uid: u32, gid: u32) -> Result> { 126 | Err(Error::new(ENOENT)) 127 | } 128 | #[allow(unused_variables)] 129 | fn xopen(&self, path: &str, flags: usize, ctx: &CallerCtx) -> Result> { 130 | convert_to_this_scheme_block(self.open(path, flags, ctx.uid, ctx.gid)) 131 | } 132 | 133 | #[allow(unused_variables)] 134 | fn chmod(&self, path: &str, mode: u16, uid: u32, gid: u32) -> Result> { 135 | Err(Error::new(ENOENT)) 136 | } 137 | 138 | #[allow(unused_variables)] 139 | fn rmdir(&self, path: &str, uid: u32, gid: u32) -> Result> { 140 | Err(Error::new(ENOENT)) 141 | } 142 | 143 | #[allow(unused_variables)] 144 | fn unlink(&self, path: &str, uid: u32, gid: u32) -> Result> { 145 | Err(Error::new(ENOENT)) 146 | } 147 | 148 | /* Resource operations */ 149 | #[allow(unused_variables)] 150 | fn dup(&self, old_id: usize, buf: &[u8]) -> Result> { 151 | Err(Error::new(EBADF)) 152 | } 153 | 154 | #[allow(unused_variables)] 155 | fn xdup(&self, old_id: usize, buf: &[u8], ctx: &CallerCtx) -> Result> { 156 | convert_to_this_scheme_block(self.dup(old_id, buf)) 157 | } 158 | 159 | #[allow(unused_variables)] 160 | fn read(&self, id: usize, buf: &mut [u8]) -> Result> { 161 | Err(Error::new(EBADF)) 162 | } 163 | 164 | #[allow(unused_variables)] 165 | fn write(&self, id: usize, buf: &[u8]) -> Result> { 166 | Err(Error::new(EBADF)) 167 | } 168 | 169 | #[allow(unused_variables)] 170 | fn seek(&self, id: usize, pos: isize, whence: usize) -> Result> { 171 | Err(Error::new(EBADF)) 172 | } 173 | 174 | #[allow(unused_variables)] 175 | fn fchmod(&self, id: usize, mode: u16) -> Result> { 176 | Err(Error::new(EBADF)) 177 | } 178 | 179 | #[allow(unused_variables)] 180 | fn fchown(&self, id: usize, uid: u32, gid: u32) -> Result> { 181 | Err(Error::new(EBADF)) 182 | } 183 | 184 | #[allow(unused_variables)] 185 | fn fcntl(&self, id: usize, cmd: usize, arg: usize) -> Result> { 186 | Err(Error::new(EBADF)) 187 | } 188 | 189 | #[allow(unused_variables)] 190 | fn fevent(&self, id: usize, flags: EventFlags) -> Result> { 191 | Err(Error::new(EBADF)) 192 | } 193 | 194 | #[allow(unused_variables)] 195 | fn flink(&self, id: usize, path: &str, uid: u32, gid: u32) -> Result> { 196 | Err(Error::new(EBADF)) 197 | } 198 | 199 | #[allow(unused_variables)] 200 | fn fpath(&self, id: usize, buf: &mut [u8]) -> Result> { 201 | Err(Error::new(EBADF)) 202 | } 203 | 204 | #[allow(unused_variables)] 205 | fn frename(&self, id: usize, path: &str, uid: u32, gid: u32) -> Result> { 206 | Err(Error::new(EBADF)) 207 | } 208 | 209 | #[allow(unused_variables)] 210 | fn fstat(&self, id: usize, stat: &mut Stat) -> Result> { 211 | Err(Error::new(EBADF)) 212 | } 213 | 214 | #[allow(unused_variables)] 215 | fn fstatvfs(&self, id: usize, stat: &mut StatVfs) -> Result> { 216 | Err(Error::new(EBADF)) 217 | } 218 | 219 | #[allow(unused_variables)] 220 | fn fsync(&self, id: usize) -> Result> { 221 | Err(Error::new(EBADF)) 222 | } 223 | 224 | #[allow(unused_variables)] 225 | fn ftruncate(&self, id: usize, len: usize) -> Result> { 226 | Err(Error::new(EBADF)) 227 | } 228 | 229 | #[allow(unused_variables)] 230 | fn futimens(&self, id: usize, times: &[TimeSpec]) -> Result> { 231 | Err(Error::new(EBADF)) 232 | } 233 | 234 | #[allow(unused_variables)] 235 | fn close(&self, id: usize) -> Result> { 236 | Err(Error::new(EBADF)) 237 | } 238 | 239 | #[allow(unused_variables)] 240 | fn mmap_prep(&self, id: usize, offset: u64, size: usize, flags: MapFlags) -> Result> { 241 | Err(Error::new(EOPNOTSUPP)) 242 | } 243 | 244 | #[allow(unused_variables)] 245 | fn munmap(&self, id: usize, offset: u64, size: usize, flags: MunmapFlags) -> Result> { 246 | Err(Error::new(EOPNOTSUPP)) 247 | } 248 | } 249 | -------------------------------------------------------------------------------- /src/scheme/scheme_block_mut.rs: -------------------------------------------------------------------------------- 1 | use core::{mem, slice}; 2 | 3 | use crate::{data::*, error::*, flag::*, number::*, scheme::*, CallerCtx, OpenResult}; 4 | 5 | pub trait SchemeBlockMut { 6 | fn handle(&mut self, packet: &Packet) -> Option { 7 | let res = match packet.a { 8 | SYS_OPEN => { 9 | if let Some(path) = unsafe { str_from_raw_parts(packet.b as *const u8, packet.c) } { 10 | convert_in_scheme_handle_block( 11 | packet, 12 | self.xopen(path, packet.d, &CallerCtx::from_packet(&packet)), 13 | ) 14 | } else { 15 | Err(Error::new(EINVAL)) 16 | } 17 | } 18 | SYS_RMDIR => { 19 | if let Some(path) = unsafe { str_from_raw_parts(packet.b as *const u8, packet.c) } { 20 | self.rmdir(path, packet.uid, packet.gid) 21 | } else { 22 | Err(Error::new(EINVAL)) 23 | } 24 | } 25 | SYS_UNLINK => { 26 | if let Some(path) = unsafe { str_from_raw_parts(packet.b as *const u8, packet.c) } { 27 | self.unlink(path, packet.uid, packet.gid) 28 | } else { 29 | Err(Error::new(EINVAL)) 30 | } 31 | } 32 | 33 | SYS_DUP => convert_in_scheme_handle_block( 34 | packet, 35 | self.xdup( 36 | packet.b, 37 | unsafe { slice::from_raw_parts(packet.c as *const u8, packet.d) }, 38 | &CallerCtx::from_packet(&packet), 39 | ), 40 | ), 41 | SYS_READ => self.read(packet.b, unsafe { 42 | slice::from_raw_parts_mut(packet.c as *mut u8, packet.d) 43 | }), 44 | SYS_WRITE => self.write(packet.b, unsafe { 45 | slice::from_raw_parts(packet.c as *const u8, packet.d) 46 | }), 47 | SYS_LSEEK => self 48 | .seek(packet.b, packet.c as isize, packet.d) 49 | .map(|o| o.map(|o| o as usize)), 50 | SYS_FCHMOD => self.fchmod(packet.b, packet.c as u16), 51 | SYS_FCHOWN => self.fchown(packet.b, packet.c as u32, packet.d as u32), 52 | SYS_FCNTL => self.fcntl(packet.b, packet.c, packet.d), 53 | SYS_FEVENT => self 54 | .fevent(packet.b, EventFlags::from_bits_truncate(packet.c)) 55 | .map(|f| f.map(|f| f.bits())), 56 | SYS_FLINK => { 57 | if let Some(path) = unsafe { str_from_raw_parts(packet.c as *const u8, packet.d) } { 58 | self.flink(packet.b, path, packet.uid, packet.gid) 59 | } else { 60 | Err(Error::new(EINVAL)) 61 | } 62 | } 63 | SYS_FPATH => self.fpath(packet.b, unsafe { 64 | slice::from_raw_parts_mut(packet.c as *mut u8, packet.d) 65 | }), 66 | SYS_FRENAME => { 67 | if let Some(path) = unsafe { str_from_raw_parts(packet.c as *const u8, packet.d) } { 68 | self.frename(packet.b, path, packet.uid, packet.gid) 69 | } else { 70 | Err(Error::new(EINVAL)) 71 | } 72 | } 73 | SYS_FSTAT => { 74 | if packet.d >= mem::size_of::() { 75 | self.fstat(packet.b, unsafe { &mut *(packet.c as *mut Stat) }) 76 | } else { 77 | Err(Error::new(EFAULT)) 78 | } 79 | } 80 | SYS_FSTATVFS => { 81 | if packet.d >= mem::size_of::() { 82 | self.fstatvfs(packet.b, unsafe { &mut *(packet.c as *mut StatVfs) }) 83 | } else { 84 | Err(Error::new(EFAULT)) 85 | } 86 | } 87 | SYS_FSYNC => self.fsync(packet.b), 88 | SYS_FTRUNCATE => self.ftruncate(packet.b, packet.c), 89 | SYS_FUTIMENS => { 90 | if packet.d >= mem::size_of::() { 91 | self.futimens(packet.b, unsafe { 92 | slice::from_raw_parts( 93 | packet.c as *const TimeSpec, 94 | packet.d / mem::size_of::(), 95 | ) 96 | }) 97 | } else { 98 | Err(Error::new(EFAULT)) 99 | } 100 | } 101 | SYS_CLOSE => self.close(packet.b), 102 | 103 | KSMSG_MMAP_PREP => self.mmap_prep( 104 | packet.b, 105 | u64::from(packet.uid) | (u64::from(packet.gid) << 32), 106 | packet.c, 107 | MapFlags::from_bits_truncate(packet.d), 108 | ), 109 | KSMSG_MUNMAP => self.munmap( 110 | packet.b, 111 | u64::from(packet.uid) | (u64::from(packet.gid) << 32), 112 | packet.c, 113 | MunmapFlags::from_bits_truncate(packet.d), 114 | ), 115 | 116 | _ => Err(Error::new(ENOSYS)), 117 | }; 118 | 119 | res.transpose().map(Error::mux) 120 | } 121 | 122 | /* Scheme operations */ 123 | 124 | #[allow(unused_variables)] 125 | fn open(&mut self, path: &str, flags: usize, uid: u32, gid: u32) -> Result> { 126 | Err(Error::new(ENOENT)) 127 | } 128 | #[allow(unused_variables)] 129 | fn xopen(&mut self, path: &str, flags: usize, ctx: &CallerCtx) -> Result> { 130 | convert_to_this_scheme_block(self.open(path, flags, ctx.uid, ctx.gid)) 131 | } 132 | 133 | #[allow(unused_variables)] 134 | fn chmod(&mut self, path: &str, mode: u16, uid: u32, gid: u32) -> Result> { 135 | Err(Error::new(ENOENT)) 136 | } 137 | 138 | #[allow(unused_variables)] 139 | fn rmdir(&mut self, path: &str, uid: u32, gid: u32) -> Result> { 140 | Err(Error::new(ENOENT)) 141 | } 142 | 143 | #[allow(unused_variables)] 144 | fn unlink(&mut self, path: &str, uid: u32, gid: u32) -> Result> { 145 | Err(Error::new(ENOENT)) 146 | } 147 | 148 | /* Resource operations */ 149 | #[allow(unused_variables)] 150 | fn dup(&mut self, old_id: usize, buf: &[u8]) -> Result> { 151 | Err(Error::new(EBADF)) 152 | } 153 | 154 | #[allow(unused_variables)] 155 | fn xdup(&mut self, old_id: usize, buf: &[u8], ctx: &CallerCtx) -> Result> { 156 | convert_to_this_scheme_block(self.dup(old_id, buf)) 157 | } 158 | 159 | #[allow(unused_variables)] 160 | fn read(&mut self, id: usize, buf: &mut [u8]) -> Result> { 161 | Err(Error::new(EBADF)) 162 | } 163 | 164 | #[allow(unused_variables)] 165 | fn write(&mut self, id: usize, buf: &[u8]) -> Result> { 166 | Err(Error::new(EBADF)) 167 | } 168 | 169 | #[allow(unused_variables)] 170 | fn seek(&mut self, id: usize, pos: isize, whence: usize) -> Result> { 171 | Err(Error::new(EBADF)) 172 | } 173 | 174 | #[allow(unused_variables)] 175 | fn fchmod(&mut self, id: usize, mode: u16) -> Result> { 176 | Err(Error::new(EBADF)) 177 | } 178 | 179 | #[allow(unused_variables)] 180 | fn fchown(&mut self, id: usize, uid: u32, gid: u32) -> Result> { 181 | Err(Error::new(EBADF)) 182 | } 183 | 184 | #[allow(unused_variables)] 185 | fn fcntl(&mut self, id: usize, cmd: usize, arg: usize) -> Result> { 186 | Err(Error::new(EBADF)) 187 | } 188 | 189 | #[allow(unused_variables)] 190 | fn fevent(&mut self, id: usize, flags: EventFlags) -> Result> { 191 | Err(Error::new(EBADF)) 192 | } 193 | 194 | #[allow(unused_variables)] 195 | fn flink(&mut self, id: usize, path: &str, uid: u32, gid: u32) -> Result> { 196 | Err(Error::new(EBADF)) 197 | } 198 | 199 | #[allow(unused_variables)] 200 | fn fpath(&mut self, id: usize, buf: &mut [u8]) -> Result> { 201 | Err(Error::new(EBADF)) 202 | } 203 | 204 | #[allow(unused_variables)] 205 | fn frename(&mut self, id: usize, path: &str, uid: u32, gid: u32) -> Result> { 206 | Err(Error::new(EBADF)) 207 | } 208 | 209 | #[allow(unused_variables)] 210 | fn fstat(&mut self, id: usize, stat: &mut Stat) -> Result> { 211 | Err(Error::new(EBADF)) 212 | } 213 | 214 | #[allow(unused_variables)] 215 | fn fstatvfs(&mut self, id: usize, stat: &mut StatVfs) -> Result> { 216 | Err(Error::new(EBADF)) 217 | } 218 | 219 | #[allow(unused_variables)] 220 | fn fsync(&mut self, id: usize) -> Result> { 221 | Err(Error::new(EBADF)) 222 | } 223 | 224 | #[allow(unused_variables)] 225 | fn ftruncate(&mut self, id: usize, len: usize) -> Result> { 226 | Err(Error::new(EBADF)) 227 | } 228 | 229 | #[allow(unused_variables)] 230 | fn futimens(&mut self, id: usize, times: &[TimeSpec]) -> Result> { 231 | Err(Error::new(EBADF)) 232 | } 233 | 234 | #[allow(unused_variables)] 235 | fn close(&mut self, id: usize) -> Result> { 236 | Err(Error::new(EBADF)) 237 | } 238 | 239 | #[allow(unused_variables)] 240 | fn mmap_prep(&mut self, id: usize, offset: u64, size: usize, flags: MapFlags) -> Result> { 241 | Err(Error::new(EOPNOTSUPP)) 242 | } 243 | 244 | #[allow(unused_variables)] 245 | fn munmap(&mut self, id: usize, offset: u64, size: usize, flags: MunmapFlags) -> Result> { 246 | Err(Error::new(EOPNOTSUPP)) 247 | } 248 | } 249 | -------------------------------------------------------------------------------- /src/scheme/scheme_mut.rs: -------------------------------------------------------------------------------- 1 | use core::{mem, slice}; 2 | 3 | use crate::{data::*, error::*, flag::*, number::*, scheme::*, CallerCtx, OpenResult}; 4 | 5 | pub trait SchemeMut { 6 | fn handle(&mut self, packet: &mut Packet) { 7 | let res = match packet.a { 8 | SYS_OPEN => { 9 | if let Some(path) = unsafe { str_from_raw_parts(packet.b as *const u8, packet.c) } { 10 | convert_in_scheme_handle( 11 | packet, 12 | self.xopen(path, packet.d, &CallerCtx::from_packet(&packet)), 13 | ) 14 | } else { 15 | Err(Error::new(EINVAL)) 16 | } 17 | } 18 | SYS_RMDIR => { 19 | if let Some(path) = unsafe { str_from_raw_parts(packet.b as *const u8, packet.c) } { 20 | self.rmdir(path, packet.uid, packet.gid) 21 | } else { 22 | Err(Error::new(EINVAL)) 23 | } 24 | } 25 | SYS_UNLINK => { 26 | if let Some(path) = unsafe { str_from_raw_parts(packet.b as *const u8, packet.c) } { 27 | self.unlink(path, packet.uid, packet.gid) 28 | } else { 29 | Err(Error::new(EINVAL)) 30 | } 31 | } 32 | 33 | SYS_DUP => convert_in_scheme_handle( 34 | packet, 35 | self.xdup( 36 | packet.b, 37 | unsafe { slice::from_raw_parts(packet.c as *const u8, packet.d) }, 38 | &CallerCtx::from_packet(&packet), 39 | ), 40 | ), 41 | SYS_READ => self.read(packet.b, unsafe { 42 | slice::from_raw_parts_mut(packet.c as *mut u8, packet.d) 43 | }), 44 | SYS_WRITE => self.write(packet.b, unsafe { 45 | slice::from_raw_parts(packet.c as *const u8, packet.d) 46 | }), 47 | SYS_LSEEK => self 48 | .seek(packet.b, packet.c as isize, packet.d) 49 | .map(|o| o as usize), 50 | SYS_FCHMOD => self.fchmod(packet.b, packet.c as u16), 51 | SYS_FCHOWN => self.fchown(packet.b, packet.c as u32, packet.d as u32), 52 | SYS_FCNTL => self.fcntl(packet.b, packet.c, packet.d), 53 | SYS_FEVENT => self 54 | .fevent(packet.b, EventFlags::from_bits_truncate(packet.c)) 55 | .map(|f| f.bits()), 56 | SYS_FLINK => { 57 | if let Some(path) = unsafe { str_from_raw_parts(packet.c as *const u8, packet.d) } { 58 | self.flink(packet.b, path, packet.uid, packet.gid) 59 | } else { 60 | Err(Error::new(EINVAL)) 61 | } 62 | } 63 | SYS_FPATH => self.fpath(packet.b, unsafe { 64 | slice::from_raw_parts_mut(packet.c as *mut u8, packet.d) 65 | }), 66 | SYS_FRENAME => { 67 | if let Some(path) = unsafe { str_from_raw_parts(packet.c as *const u8, packet.d) } { 68 | self.frename(packet.b, path, packet.uid, packet.gid) 69 | } else { 70 | Err(Error::new(EINVAL)) 71 | } 72 | } 73 | SYS_FSTAT => { 74 | if packet.d >= mem::size_of::() { 75 | self.fstat(packet.b, unsafe { &mut *(packet.c as *mut Stat) }) 76 | } else { 77 | Err(Error::new(EFAULT)) 78 | } 79 | } 80 | SYS_FSTATVFS => { 81 | if packet.d >= mem::size_of::() { 82 | self.fstatvfs(packet.b, unsafe { &mut *(packet.c as *mut StatVfs) }) 83 | } else { 84 | Err(Error::new(EFAULT)) 85 | } 86 | } 87 | SYS_FSYNC => self.fsync(packet.b), 88 | SYS_FTRUNCATE => self.ftruncate(packet.b, packet.c), 89 | SYS_FUTIMENS => { 90 | if packet.d >= mem::size_of::() { 91 | self.futimens(packet.b, unsafe { 92 | slice::from_raw_parts( 93 | packet.c as *const TimeSpec, 94 | packet.d / mem::size_of::(), 95 | ) 96 | }) 97 | } else { 98 | Err(Error::new(EFAULT)) 99 | } 100 | } 101 | SYS_CLOSE => self.close(packet.b), 102 | 103 | KSMSG_MMAP_PREP => self.mmap_prep( 104 | packet.b, 105 | u64::from(packet.uid) | (u64::from(packet.gid) << 32), 106 | packet.c, 107 | MapFlags::from_bits_truncate(packet.d), 108 | ), 109 | KSMSG_MUNMAP => self.munmap( 110 | packet.b, 111 | u64::from(packet.uid) | (u64::from(packet.gid) << 32), 112 | packet.c, 113 | MunmapFlags::from_bits_truncate(packet.d), 114 | ), 115 | 116 | _ => Err(Error::new(ENOSYS)), 117 | }; 118 | 119 | packet.a = Error::mux(res); 120 | } 121 | 122 | /* Scheme operations */ 123 | 124 | #[allow(unused_variables)] 125 | fn open(&mut self, path: &str, flags: usize, uid: u32, gid: u32) -> Result { 126 | Err(Error::new(ENOENT)) 127 | } 128 | #[allow(unused_variables)] 129 | fn xopen(&mut self, path: &str, flags: usize, ctx: &CallerCtx) -> Result { 130 | convert_to_this_scheme(self.open(path, flags, ctx.uid, ctx.gid)) 131 | } 132 | 133 | #[allow(unused_variables)] 134 | fn chmod(&mut self, path: &str, mode: u16, uid: u32, gid: u32) -> Result { 135 | Err(Error::new(ENOENT)) 136 | } 137 | 138 | #[allow(unused_variables)] 139 | fn rmdir(&mut self, path: &str, uid: u32, gid: u32) -> Result { 140 | Err(Error::new(ENOENT)) 141 | } 142 | 143 | #[allow(unused_variables)] 144 | fn unlink(&mut self, path: &str, uid: u32, gid: u32) -> Result { 145 | Err(Error::new(ENOENT)) 146 | } 147 | 148 | /* Resource operations */ 149 | #[allow(unused_variables)] 150 | fn dup(&mut self, old_id: usize, buf: &[u8]) -> Result { 151 | Err(Error::new(EBADF)) 152 | } 153 | 154 | #[allow(unused_variables)] 155 | fn xdup(&mut self, old_id: usize, buf: &[u8], ctx: &CallerCtx) -> Result { 156 | convert_to_this_scheme(self.dup(old_id, buf)) 157 | } 158 | 159 | #[allow(unused_variables)] 160 | fn read(&mut self, id: usize, buf: &mut [u8]) -> Result { 161 | Err(Error::new(EBADF)) 162 | } 163 | 164 | #[allow(unused_variables)] 165 | fn write(&mut self, id: usize, buf: &[u8]) -> Result { 166 | Err(Error::new(EBADF)) 167 | } 168 | 169 | #[allow(unused_variables)] 170 | fn seek(&mut self, id: usize, pos: isize, whence: usize) -> Result { 171 | Err(Error::new(EBADF)) 172 | } 173 | 174 | #[allow(unused_variables)] 175 | fn fchmod(&mut self, id: usize, mode: u16) -> Result { 176 | Err(Error::new(EBADF)) 177 | } 178 | 179 | #[allow(unused_variables)] 180 | fn fchown(&mut self, id: usize, uid: u32, gid: u32) -> Result { 181 | Err(Error::new(EBADF)) 182 | } 183 | 184 | #[allow(unused_variables)] 185 | fn fcntl(&mut self, id: usize, cmd: usize, arg: usize) -> Result { 186 | Err(Error::new(EBADF)) 187 | } 188 | 189 | #[allow(unused_variables)] 190 | fn fevent(&mut self, id: usize, flags: EventFlags) -> Result { 191 | Err(Error::new(EBADF)) 192 | } 193 | 194 | #[allow(unused_variables)] 195 | fn flink(&mut self, id: usize, path: &str, uid: u32, gid: u32) -> Result { 196 | Err(Error::new(EBADF)) 197 | } 198 | 199 | #[allow(unused_variables)] 200 | fn fpath(&mut self, id: usize, buf: &mut [u8]) -> Result { 201 | Err(Error::new(EBADF)) 202 | } 203 | 204 | #[allow(unused_variables)] 205 | fn frename(&mut self, id: usize, path: &str, uid: u32, gid: u32) -> Result { 206 | Err(Error::new(EBADF)) 207 | } 208 | 209 | #[allow(unused_variables)] 210 | fn fstat(&mut self, id: usize, stat: &mut Stat) -> Result { 211 | Err(Error::new(EBADF)) 212 | } 213 | 214 | #[allow(unused_variables)] 215 | fn fstatvfs(&mut self, id: usize, stat: &mut StatVfs) -> Result { 216 | Err(Error::new(EBADF)) 217 | } 218 | 219 | #[allow(unused_variables)] 220 | fn fsync(&mut self, id: usize) -> Result { 221 | Err(Error::new(EBADF)) 222 | } 223 | 224 | #[allow(unused_variables)] 225 | fn ftruncate(&mut self, id: usize, len: usize) -> Result { 226 | Err(Error::new(EBADF)) 227 | } 228 | 229 | #[allow(unused_variables)] 230 | fn futimens(&mut self, id: usize, times: &[TimeSpec]) -> Result { 231 | Err(Error::new(EBADF)) 232 | } 233 | 234 | #[allow(unused_variables)] 235 | fn close(&mut self, id: usize) -> Result { 236 | Err(Error::new(EBADF)) 237 | } 238 | 239 | #[allow(unused_variables)] 240 | fn mmap_prep(&mut self, id: usize, offset: u64, size: usize, flags: MapFlags) -> Result { 241 | Err(Error::new(EOPNOTSUPP)) 242 | } 243 | 244 | #[allow(unused_variables)] 245 | fn munmap(&mut self, id: usize, offset: u64, size: usize, flags: MunmapFlags) -> Result { 246 | Err(Error::new(EOPNOTSUPP)) 247 | } 248 | } 249 | -------------------------------------------------------------------------------- /src/scheme/seek.rs: -------------------------------------------------------------------------------- 1 | use crate::{error::*, flag::*}; 2 | use core::{cmp, convert::TryFrom}; 3 | 4 | /// Helper for seek calls 5 | /// In most cases it's easier to use a usize to track the offset and buffer size internally, 6 | /// but the seek interface uses isize. This wrapper ensures EOVERFLOW errors are returned 7 | /// as appropriate if the value in the usize can't fit in the isize. 8 | pub fn calc_seek_offset_usize( 9 | cur_offset: usize, 10 | pos: isize, 11 | whence: usize, 12 | buf_len: usize, 13 | ) -> Result { 14 | let cur_offset = isize::try_from(cur_offset).or_else(|_| Err(Error::new(EOVERFLOW)))?; 15 | let buf_len = isize::try_from(buf_len).or_else(|_| Err(Error::new(EOVERFLOW)))?; 16 | calc_seek_offset_isize(cur_offset, pos, whence, buf_len) 17 | } 18 | 19 | /// Helper for seek calls 20 | /// Result is guaranteed to be positive. 21 | /// EOVERFLOW returned if the arguments would cause an overflow. 22 | /// EINVAL returned if the new offset is out of bounds. 23 | pub fn calc_seek_offset_isize( 24 | cur_offset: isize, 25 | pos: isize, 26 | whence: usize, 27 | buf_len: isize, 28 | ) -> Result { 29 | let new_offset = match whence { 30 | SEEK_CUR => pos.checked_add(cur_offset), 31 | SEEK_END => pos.checked_add(buf_len), 32 | SEEK_SET => Some(pos), 33 | _ => None, 34 | }; 35 | 36 | match new_offset { 37 | Some(new_offset) if new_offset < 0 => Err(Error::new(EINVAL)), 38 | Some(new_offset) => Ok(cmp::min(new_offset, buf_len)), 39 | None => Err(Error::new(EOVERFLOW)), 40 | } 41 | } 42 | -------------------------------------------------------------------------------- /src/schemev2.rs: -------------------------------------------------------------------------------- 1 | use core::{ 2 | mem, 3 | ops::{Deref, DerefMut}, 4 | slice, 5 | }; 6 | 7 | use bitflags::bitflags; 8 | 9 | #[repr(C)] 10 | #[derive(Clone, Copy, Debug, Default)] 11 | pub struct Sqe { 12 | pub opcode: u8, 13 | pub sqe_flags: SqeFlags, 14 | pub _rsvd: u16, // TODO: priority 15 | pub tag: u32, 16 | pub args: [u64; 6], 17 | pub caller: u64, 18 | } 19 | impl Deref for Sqe { 20 | type Target = [u8]; 21 | fn deref(&self) -> &[u8] { 22 | unsafe { slice::from_raw_parts(self as *const Sqe as *const u8, mem::size_of::()) } 23 | } 24 | } 25 | 26 | impl DerefMut for Sqe { 27 | fn deref_mut(&mut self) -> &mut [u8] { 28 | unsafe { slice::from_raw_parts_mut(self as *mut Sqe as *mut u8, mem::size_of::()) } 29 | } 30 | } 31 | 32 | bitflags! { 33 | #[derive(Clone, Copy, Debug, Default)] 34 | pub struct SqeFlags: u8 { 35 | // If zero, the message is bidirectional, and the scheme is expected to pass the Ksmsg's 36 | // tag field to the Skmsg. Some opcodes require this flag to be set. 37 | const ONEWAY = 1; 38 | } 39 | } 40 | 41 | #[repr(C)] 42 | #[derive(Clone, Copy, Debug, Default)] 43 | pub struct Cqe { 44 | pub flags: u8, // bits 3:0 are CqeOpcode 45 | pub extra_raw: [u8; 3], 46 | pub tag: u32, 47 | pub result: u64, 48 | } 49 | impl Deref for Cqe { 50 | type Target = [u8]; 51 | fn deref(&self) -> &[u8] { 52 | unsafe { slice::from_raw_parts(self as *const Cqe as *const u8, mem::size_of::()) } 53 | } 54 | } 55 | 56 | impl DerefMut for Cqe { 57 | fn deref_mut(&mut self) -> &mut [u8] { 58 | unsafe { slice::from_raw_parts_mut(self as *mut Cqe as *mut u8, mem::size_of::()) } 59 | } 60 | } 61 | 62 | bitflags! { 63 | #[derive(Clone, Copy, Debug, Default, Eq, PartialEq)] 64 | pub struct NewFdFlags: u8 { 65 | const POSITIONED = 1; 66 | } 67 | } 68 | 69 | impl Cqe { 70 | pub fn extra(&self) -> u32 { 71 | u32::from_ne_bytes([self.extra_raw[0], self.extra_raw[1], self.extra_raw[2], 0]) 72 | } 73 | } 74 | 75 | #[repr(u8)] 76 | #[derive(Clone, Copy, Debug, Eq, PartialEq)] 77 | pub enum CqeOpcode { 78 | RespondRegular, 79 | RespondWithFd, 80 | SendFevent, // no tag 81 | ObtainFd, 82 | // TODO: ProvideMmap 83 | } 84 | impl CqeOpcode { 85 | pub fn try_from_raw(raw: u8) -> Option { 86 | Some(match raw { 87 | 0 => Self::RespondRegular, 88 | 1 => Self::RespondWithFd, 89 | 2 => Self::SendFevent, 90 | 3 => Self::ObtainFd, 91 | _ => return None, 92 | }) 93 | } 94 | } 95 | 96 | #[repr(u8)] 97 | #[non_exhaustive] 98 | #[derive(Clone, Copy, Debug)] 99 | pub enum Opcode { 100 | Open = 0, // path_ptr, path_len (utf8), flags 101 | Rmdir = 1, // path_ptr, path_len (utf8) 102 | Unlink = 2, // path_ptr, path_len (utf8) 103 | Close = 3, // fd 104 | Dup = 4, // old fd, buf_ptr, buf_len 105 | Read = 5, // fd, buf_ptr, buf_len, TODO offset, TODO flags, _ 106 | Write = 6, // fd, buf_ptr, buf_len, TODO offset, TODO flags) 107 | Fsize = 7, // fd 108 | Fchmod = 8, // fd, new mode 109 | Fchown = 9, // fd, new uid, new gid 110 | Fcntl = 10, // fd, cmd, arg 111 | Fevent = 11, // fd, requested mask 112 | Sendfd = 12, 113 | Fpath = 13, // fd, buf_ptr, buf_len 114 | Frename = 14, 115 | Fstat = 15, // fd, buf_ptr, buf_len 116 | Fstatvfs = 16, // fd, buf_ptr, buf_len 117 | Fsync = 17, // fd 118 | Ftruncate = 18, // fd, new len 119 | Futimens = 19, // fd, times_buf, times_len 120 | 121 | MmapPrep = 20, 122 | RequestMmap = 21, 123 | Mremap = 22, 124 | Munmap = 23, 125 | Msync = 24, // TODO 126 | 127 | Cancel = 25, // @tag 128 | 129 | Getdents = 26, 130 | CloseMsg = 27, 131 | Call = 28, 132 | 133 | OpenAt = 29, // fd, buf_ptr, buf_len, flags 134 | Flink = 30, 135 | } 136 | 137 | impl Opcode { 138 | pub fn try_from_raw(raw: u8) -> Option { 139 | use Opcode::*; 140 | 141 | // TODO: Use a library where this match can be automated. 142 | Some(match raw { 143 | 0 => Open, 144 | 1 => Rmdir, 145 | 2 => Unlink, 146 | 3 => Close, 147 | 4 => Dup, 148 | 5 => Read, 149 | 6 => Write, 150 | 7 => Fsize, 151 | 8 => Fchmod, 152 | 9 => Fchown, 153 | 10 => Fcntl, 154 | 11 => Fevent, 155 | 12 => Sendfd, 156 | 13 => Fpath, 157 | 14 => Frename, 158 | 15 => Fstat, 159 | 16 => Fstatvfs, 160 | 17 => Fsync, 161 | 18 => Ftruncate, 162 | 19 => Futimens, 163 | 164 | 20 => MmapPrep, 165 | 21 => RequestMmap, 166 | 22 => Mremap, 167 | 23 => Munmap, 168 | 24 => Msync, 169 | 170 | 25 => Cancel, 171 | 26 => Getdents, 172 | 27 => CloseMsg, 173 | 28 => Call, 174 | 175 | 29 => OpenAt, 176 | 30 => Flink, 177 | 178 | _ => return None, 179 | }) 180 | } 181 | } 182 | -------------------------------------------------------------------------------- /src/sigabi.rs: -------------------------------------------------------------------------------- 1 | use core::sync::atomic::{AtomicUsize, Ordering}; 2 | 3 | /// Signal runtime struct for the entire process 4 | #[derive(Debug)] 5 | #[repr(C, align(4096))] 6 | pub struct SigProcControl { 7 | pub pending: AtomicU64, 8 | pub actions: [RawAction; 64], 9 | pub sender_infos: [AtomicU64; 32], 10 | //pub queue: [RealtimeSig; 32], TODO 11 | // qhead, qtail TODO 12 | } 13 | /*#[derive(Debug)] 14 | #[repr(transparent)] 15 | pub struct RealtimeSig { 16 | pub arg: NonatomicUsize, 17 | }*/ 18 | #[derive(Debug, Default)] 19 | #[repr(C, align(16))] 20 | pub struct RawAction { 21 | /// Only two MSBs are interesting for the kernel. If bit 63 is set, signal is ignored. If bit 22 | /// 62 is set and the signal is SIGTSTP/SIGTTIN/SIGTTOU, it's equivalent to the action of 23 | /// Stop. 24 | pub first: AtomicU64, 25 | /// Completely ignored by the kernel, but exists so userspace can (when 16-byte atomics exist) 26 | /// atomically set both the handler, sigaction flags, and sigaction mask. 27 | pub user_data: AtomicU64, 28 | } 29 | 30 | /// Signal runtime struct for a thread 31 | #[derive(Debug, Default)] 32 | #[repr(C)] 33 | pub struct Sigcontrol { 34 | // composed of [lo "pending" | lo "unmasked", hi "pending" | hi "unmasked"] 35 | pub word: [AtomicU64; 2], 36 | 37 | // lo = sender pid, hi = sender ruid 38 | pub sender_infos: [AtomicU64; 32], 39 | 40 | pub control_flags: SigatomicUsize, 41 | 42 | pub saved_ip: NonatomicUsize, // rip/eip/pc 43 | pub saved_archdep_reg: NonatomicUsize, // rflags(x64)/eflags(x86)/x0(aarch64)/t0(riscv64) 44 | } 45 | #[derive(Clone, Copy, Debug)] 46 | pub struct SenderInfo { 47 | pub pid: u32, 48 | pub ruid: u32, 49 | } 50 | impl SenderInfo { 51 | #[inline] 52 | pub fn raw(self) -> u64 { 53 | u64::from(self.pid) | (u64::from(self.ruid) << 32) 54 | } 55 | #[inline] 56 | pub const fn from_raw(raw: u64) -> Self { 57 | Self { 58 | pid: raw as u32, 59 | ruid: (raw >> 32) as u32, 60 | } 61 | } 62 | } 63 | 64 | impl Sigcontrol { 65 | pub fn currently_pending_unblocked(&self, proc: &SigProcControl) -> u64 { 66 | let proc_pending = proc.pending.load(Ordering::Relaxed); 67 | let [w0, w1] = core::array::from_fn(|i| { 68 | let w = self.word[i].load(Ordering::Relaxed); 69 | ((w | (proc_pending >> (i * 32))) & 0xffff_ffff) & (w >> 32) 70 | }); 71 | //core::sync::atomic::fence(Ordering::Acquire); 72 | w0 | (w1 << 32) 73 | } 74 | pub fn set_allowset(&self, new_allowset: u64) -> u64 { 75 | //core::sync::atomic::fence(Ordering::Release); 76 | let [w0, w1] = self.word.each_ref().map(|w| w.load(Ordering::Relaxed)); 77 | let old_a0 = w0 & 0xffff_ffff_0000_0000; 78 | let old_a1 = w1 & 0xffff_ffff_0000_0000; 79 | let new_a0 = (new_allowset & 0xffff_ffff) << 32; 80 | let new_a1 = new_allowset & 0xffff_ffff_0000_0000; 81 | 82 | let prev_w0 = self.word[0].fetch_add(new_a0.wrapping_sub(old_a0), Ordering::Relaxed); 83 | let prev_w1 = self.word[0].fetch_add(new_a1.wrapping_sub(old_a1), Ordering::Relaxed); 84 | //core::sync::atomic::fence(Ordering::Acquire); 85 | let up0 = prev_w0 & (prev_w0 >> 32); 86 | let up1 = prev_w1 & (prev_w1 >> 32); 87 | 88 | up0 | (up1 << 32) 89 | } 90 | } 91 | 92 | #[derive(Debug, Default)] 93 | #[repr(transparent)] 94 | pub struct SigatomicUsize(AtomicUsize); 95 | 96 | impl SigatomicUsize { 97 | #[inline] 98 | pub fn load(&self, ordering: Ordering) -> usize { 99 | let value = self.0.load(Ordering::Relaxed); 100 | if ordering != Ordering::Relaxed { 101 | core::sync::atomic::compiler_fence(ordering); 102 | } 103 | value 104 | } 105 | #[inline] 106 | pub fn store(&self, value: usize, ordering: Ordering) { 107 | if ordering != Ordering::Relaxed { 108 | core::sync::atomic::compiler_fence(ordering); 109 | } 110 | self.0.store(value, Ordering::Relaxed); 111 | } 112 | } 113 | #[derive(Debug, Default)] 114 | #[repr(transparent)] 115 | pub struct NonatomicUsize(AtomicUsize); 116 | 117 | impl NonatomicUsize { 118 | #[inline] 119 | pub const fn new(a: usize) -> Self { 120 | Self(AtomicUsize::new(a)) 121 | } 122 | 123 | #[inline] 124 | pub fn get(&self) -> usize { 125 | self.0.load(Ordering::Relaxed) 126 | } 127 | #[inline] 128 | pub fn set(&self, value: usize) { 129 | self.0.store(value, Ordering::Relaxed); 130 | } 131 | } 132 | 133 | pub fn sig_bit(sig: usize) -> u64 { 134 | 1 << (sig - 1) 135 | } 136 | impl SigProcControl { 137 | // TODO: Move to redox_rt? 138 | pub fn signal_will_ign(&self, sig: usize, is_parent_sigchld: bool) -> bool { 139 | let flags = self.actions[sig - 1].first.load(Ordering::Relaxed); 140 | let will_ign = flags & (1 << 63) != 0; 141 | let sig_specific = flags & (1 << 62) != 0; // SA_NOCLDSTOP if sig == SIGCHLD 142 | 143 | will_ign || (sig == SIGCHLD && is_parent_sigchld && sig_specific) 144 | } 145 | // TODO: Move to redox_rt? 146 | pub fn signal_will_stop(&self, sig: usize) -> bool { 147 | use crate::flag::*; 148 | matches!(sig, SIGTSTP | SIGTTIN | SIGTTOU) 149 | && self.actions[sig - 1].first.load(Ordering::Relaxed) & (1 << 62) != 0 150 | } 151 | } 152 | 153 | #[cfg(not(target_arch = "x86"))] 154 | pub use core::sync::atomic::AtomicU64; 155 | 156 | use crate::SIGCHLD; 157 | 158 | #[cfg(target_arch = "x86")] 159 | pub use self::atomic::AtomicU64; 160 | 161 | #[cfg(target_arch = "x86")] 162 | mod atomic { 163 | use core::{cell::UnsafeCell, sync::atomic::Ordering}; 164 | 165 | #[derive(Debug, Default)] 166 | pub struct AtomicU64(UnsafeCell); 167 | 168 | unsafe impl Send for AtomicU64 {} 169 | unsafe impl Sync for AtomicU64 {} 170 | 171 | impl AtomicU64 { 172 | pub const fn new(inner: u64) -> Self { 173 | Self(UnsafeCell::new(inner)) 174 | } 175 | pub fn compare_exchange( 176 | &self, 177 | old: u64, 178 | new: u64, 179 | _success: Ordering, 180 | _failure: Ordering, 181 | ) -> Result { 182 | let old_hi = (old >> 32) as u32; 183 | let old_lo = old as u32; 184 | let new_hi = (new >> 32) as u32; 185 | let new_lo = new as u32; 186 | let mut out_hi; 187 | let mut out_lo; 188 | 189 | unsafe { 190 | core::arch::asm!("lock cmpxchg8b [{}]", in(reg) self.0.get(), inout("edx") old_hi => out_hi, inout("eax") old_lo => out_lo, in("ecx") new_hi, in("ebx") new_lo); 191 | } 192 | 193 | if old_hi == out_hi && old_lo == out_lo { 194 | Ok(old) 195 | } else { 196 | Err(u64::from(out_lo) | (u64::from(out_hi) << 32)) 197 | } 198 | } 199 | pub fn load(&self, ordering: Ordering) -> u64 { 200 | match self.compare_exchange(0, 0, ordering, ordering) { 201 | Ok(new) => new, 202 | Err(new) => new, 203 | } 204 | } 205 | pub fn store(&self, new: u64, ordering: Ordering) { 206 | let mut old = 0; 207 | 208 | loop { 209 | match self.compare_exchange(old, new, ordering, Ordering::Relaxed) { 210 | Ok(_) => break, 211 | Err(new) => { 212 | old = new; 213 | core::hint::spin_loop(); 214 | } 215 | } 216 | } 217 | } 218 | pub fn fetch_update( 219 | &self, 220 | set_order: Ordering, 221 | fetch_order: Ordering, 222 | mut f: impl FnMut(u64) -> Option, 223 | ) -> Result { 224 | let mut old = self.load(fetch_order); 225 | 226 | loop { 227 | let new = f(old).ok_or(old)?; 228 | match self.compare_exchange(old, new, set_order, Ordering::Relaxed) { 229 | Ok(_) => return Ok(new), 230 | Err(changed) => { 231 | old = changed; 232 | core::hint::spin_loop(); 233 | } 234 | } 235 | } 236 | } 237 | pub fn fetch_or(&self, bits: u64, order: Ordering) -> u64 { 238 | self.fetch_update(order, Ordering::Relaxed, |b| Some(b | bits)) 239 | .unwrap() 240 | } 241 | pub fn fetch_and(&self, bits: u64, order: Ordering) -> u64 { 242 | self.fetch_update(order, Ordering::Relaxed, |b| Some(b & bits)) 243 | .unwrap() 244 | } 245 | pub fn fetch_add(&self, term: u64, order: Ordering) -> u64 { 246 | self.fetch_update(order, Ordering::Relaxed, |b| Some(b.wrapping_add(term))) 247 | .unwrap() 248 | } 249 | } 250 | } 251 | 252 | #[cfg(test)] 253 | mod tests { 254 | use std::sync::{ 255 | atomic::{AtomicU64, Ordering}, 256 | Arc, 257 | }; 258 | 259 | #[cfg(not(loom))] 260 | use std::{sync::Mutex, thread}; 261 | #[cfg(not(loom))] 262 | fn model(f: impl FnOnce()) { 263 | f() 264 | } 265 | 266 | #[cfg(loom)] 267 | use loom::{model, sync::Mutex, thread}; 268 | 269 | use crate::{RawAction, SigProcControl, Sigcontrol}; 270 | 271 | struct FakeThread { 272 | ctl: Sigcontrol, 273 | pctl: SigProcControl, 274 | ctxt: Mutex<()>, 275 | } 276 | impl Default for FakeThread { 277 | fn default() -> Self { 278 | Self { 279 | ctl: Sigcontrol::default(), 280 | pctl: SigProcControl { 281 | pending: AtomicU64::new(0), 282 | actions: core::array::from_fn(|_| RawAction::default()), 283 | sender_infos: Default::default(), 284 | }, 285 | ctxt: Default::default(), 286 | } 287 | } 288 | } 289 | 290 | #[test] 291 | fn singlethread_mask() { 292 | model(|| { 293 | let fake_thread = Arc::new(FakeThread::default()); 294 | 295 | let thread = { 296 | let fake_thread = Arc::clone(&fake_thread); 297 | 298 | thread::spawn(move || { 299 | fake_thread.ctl.set_allowset(!0); 300 | { 301 | let _g = fake_thread.ctxt.lock(); 302 | if fake_thread 303 | .ctl 304 | .currently_pending_unblocked(&fake_thread.pctl) 305 | == 0 306 | { 307 | drop(_g); 308 | thread::park(); 309 | } 310 | } 311 | }) 312 | }; 313 | 314 | for sig in 1..=64 { 315 | let _g = fake_thread.ctxt.lock(); 316 | 317 | let idx = sig - 1; 318 | let bit = 1 << (idx % 32); 319 | 320 | fake_thread.ctl.word[idx / 32].fetch_or(bit, Ordering::Relaxed); 321 | let w = fake_thread.ctl.word[idx / 32].load(Ordering::Relaxed); 322 | 323 | if w & (w >> 32) != 0 { 324 | thread.thread().unpark(); 325 | } 326 | } 327 | 328 | thread.join().unwrap(); 329 | }); 330 | } 331 | } 332 | --------------------------------------------------------------------------------