Next Generation WASM Microkernel Operating System
wasm
os
rust
microkernel
1// Copyright 2025. Jonas Kruckenberg
2//
3// Licensed under the Apache License, Version 2.0, <LICENSE-APACHE or
4// http://apache.org/licenses/LICENSE-2.0> or the MIT license <LICENSE-MIT or
5// http://opensource.org/licenses/MIT>, at your option. This file may not be
6// copied, modified, or distributed except according to those terms.
7
8mycelium_bitfield::bitfield! {
9 /// Rules that dictate how a region of virtual memory may be accessed.
10 ///
11 /// # W^X
12 ///
13 /// In order to prevent malicious code execution as proactively as possible,
14 /// [`AccessRules`] can either allow *writes* OR *execution* but never both. This is enforced
15 /// through the [`WriteOrExecute`] enum field.
16 #[derive(PartialEq, Eq)]
17 pub struct AccessRules<u8> {
18 /// If set, reading from the memory region is allowed.
19 pub const READ: bool;
20 /// Whether executing, or writing this memory region is allowed (or neither).
21 pub const WRITE_OR_EXECUTE: WriteOrExecute;
22 /// If set, requires code in the memory region to use aarch64 Branch Target Identification.
23 /// Does nothing on non-aarch64 architectures.
24 pub const BTI: bool;
25 }
26}
27
28/// Whether executing, or writing this memory region is allowed (or neither).
29///
30/// This is an enum to enforce [`W^X`] at the type-level.
31///
32/// [`W^X`]: AccessRules
33#[derive(Copy, Clone, Debug, Eq, PartialEq)]
34#[repr(u8)]
35pub enum WriteOrExecute {
36 /// Neither writing nor execution of the memory region is allowed.
37 Neither = 0b00,
38 /// Writing to the memory region is allowed.
39 Write = 0b01,
40 /// Executing code from the memory region is allowed.
41 Execute = 0b10,
42}
43
44// ===== impl AccessRules =====
45
46impl AccessRules {
47 pub const fn is_read_only(&self) -> bool {
48 const READ_MASK: u8 = AccessRules::READ.max_value();
49 self.0 & READ_MASK == 1
50 }
51
52 pub fn allows_read(&self) -> bool {
53 self.get(Self::READ)
54 }
55
56 pub fn allows_write(&self) -> bool {
57 matches!(self.get(Self::WRITE_OR_EXECUTE), WriteOrExecute::Write)
58 }
59
60 pub fn allows_execution(&self) -> bool {
61 matches!(self.get(Self::WRITE_OR_EXECUTE), WriteOrExecute::Execute)
62 }
63}
64
65// ===== impl WriteOrExecute =====
66
67impl mycelium_bitfield::FromBits<u8> for WriteOrExecute {
68 type Error = core::convert::Infallible;
69
70 /// The number of bits required to represent a value of this type.
71 const BITS: u32 = 2;
72
73 #[inline]
74 fn try_from_bits(bits: u8) -> Result<Self, Self::Error> {
75 match bits {
76 b if b == Self::Neither as u8 => Ok(Self::Neither),
77 b if b == Self::Write as u8 => Ok(Self::Write),
78 b if b == Self::Execute as u8 => Ok(Self::Execute),
79 _ => {
80 // this should never happen unless the bitpacking code is broken
81 unreachable!("invalid memory region access rules {bits:#b}")
82 }
83 }
84 }
85
86 #[inline]
87 fn into_bits(self) -> u8 {
88 self as u8
89 }
90}