logboi_srv/
lib.rs

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