logboi_srv/
lib.rs

1use std::sync::Mutex;
2
3use secgate::util::{Descriptor, HandleMgr, SimpleBuffer};
4use twizzler_abi::{
5    object::{ObjID, Protections},
6    syscall::{
7        sys_kernel_console_write, sys_object_create, BackingType, KernelConsoleSource,
8        KernelConsoleWriteFlags, LifetimeType, ObjectCreate, ObjectCreateFlags,
9    },
10};
11use twizzler_rt_abi::{
12    error::{ArgumentError, GenericError, ResourceError, TwzError},
13    object::MapFlags,
14};
15
16// Per-client metadata.
17struct LogClient {
18    buffer: SimpleBuffer,
19}
20
21impl LogClient {
22    fn sbid(&self) -> ObjID {
23        self.buffer.handle().id()
24    }
25}
26
27impl LogClient {
28    fn new() -> Option<Self> {
29        // Create and map a handle for the simple buffer.
30        let id = sys_object_create(
31            ObjectCreate::new(
32                BackingType::Normal,
33                LifetimeType::Volatile,
34                None,
35                ObjectCreateFlags::empty(),
36                Protections::all(),
37            ),
38            &[],
39            &[],
40        )
41        .ok()?;
42        let handle =
43            twizzler_rt_abi::object::twz_rt_map_object(id, MapFlags::WRITE | MapFlags::READ)
44                .ok()?;
45        let buffer = SimpleBuffer::new(handle);
46        Some(Self { buffer })
47    }
48}
49
50// internal logging state, protected by a lock.
51struct Logger {
52    handles: HandleMgr<LogClient>,
53    count: usize,
54}
55
56impl Logger {
57    const fn new() -> Self {
58        Self {
59            handles: HandleMgr::new(None),
60            count: 0,
61        }
62    }
63}
64
65struct LogBoi {
66    inner: Mutex<Logger>,
67}
68
69static LOGBOI: LogBoi = LogBoi {
70    inner: Mutex::new(Logger::new()),
71};
72
73#[secgate::entry(lib = "logboi")]
74pub fn logboi_open_handle() -> Result<(Descriptor, ObjID), TwzError> {
75    let info = secgate::get_caller().unwrap();
76    let mut logger = LOGBOI.inner.lock().ok().ok_or(GenericError::Internal)?;
77    let client = LogClient::new().ok_or(ResourceError::Unavailable)?;
78    let id = client.sbid();
79    let desc = logger
80        .handles
81        .insert(info.source_context().unwrap_or(0.into()), client)
82        .ok_or(ResourceError::Unavailable)?;
83
84    Ok((desc, id))
85}
86
87#[secgate::entry(lib = "logboi")]
88pub fn logboi_close_handle(desc: Descriptor) -> Result<(), TwzError> {
89    let info = secgate::get_caller().unwrap();
90    let mut logger = LOGBOI.inner.lock().unwrap();
91    logger
92        .handles
93        .remove(info.source_context().unwrap_or(0.into()), desc);
94    Ok(())
95}
96
97#[secgate::entry(lib = "logboi")]
98pub fn logboi_post(desc: Descriptor, buf_len: usize) -> Result<(), TwzError> {
99    let info = secgate::get_caller().unwrap();
100    let mut buf = vec![0u8; buf_len];
101    let mut logger = LOGBOI.inner.lock().unwrap();
102    let Some(client) = logger
103        .handles
104        .lookup(info.source_context().unwrap_or(0.into()), desc)
105    else {
106        return Err(ArgumentError::BadHandle.into());
107    };
108    let len = client.buffer.read(&mut buf);
109    let msg = format!(
110        "[log:{}] {}\n",
111        logger.count,
112        String::from_utf8_lossy(&buf[0..len])
113    );
114    logger.count += 1;
115    let _ = sys_kernel_console_write(
116        KernelConsoleSource::Console,
117        msg.as_bytes(),
118        KernelConsoleWriteFlags::DISCARD_ON_FULL,
119    );
120    Ok(())
121}