twizzler_abi/syscall/
console.rs

1use core::time::Duration;
2
3use bitflags::bitflags;
4use twizzler_rt_abi::Result;
5
6use super::{convert_codes_to_result, twzerr, Syscall, ThreadSyncSleep};
7use crate::arch::syscall::raw_syscall;
8
9bitflags! {
10    /// Flags to pass to [sys_kernel_console_read].
11    #[derive(Debug, Copy, Clone, PartialEq, Eq)]
12    pub struct KernelConsoleReadFlags: u64 {
13        /// If the read would block, return instead.
14        const NONBLOCKING = 1;
15    }
16}
17
18#[derive(Debug, Copy, Clone, Eq, PartialEq)]
19#[repr(u64)]
20/// Possible sources for a kernel console read syscall.
21pub enum KernelConsoleSource {
22    /// Read from the console itself.
23    Console = 0,
24    /// Read from the kernel write buffer.
25    Buffer = 1,
26    /// Read from the debug console.
27    DebugConsole = 2,
28}
29
30impl From<KernelConsoleSource> for u64 {
31    fn from(x: KernelConsoleSource) -> Self {
32        x as u64
33    }
34}
35
36impl From<u64> for KernelConsoleSource {
37    fn from(x: u64) -> Self {
38        match x {
39            1 => Self::Buffer,
40            2 => Self::DebugConsole,
41            _ => Self::Console,
42        }
43    }
44}
45
46impl From<KernelConsoleReadFlags> for u64 {
47    fn from(x: KernelConsoleReadFlags) -> Self {
48        x.bits()
49    }
50}
51
52/// Read from the specified kernel console input, placing data into `buffer`.
53///
54/// Returns the number of bytes read on success.
55pub fn sys_kernel_console_read(
56    source: KernelConsoleSource,
57    buffer: &mut [u8],
58    flags: KernelConsoleReadFlags,
59) -> Result<usize> {
60    sys_kernel_console_read_interruptable(source, buffer, flags, None, None)
61}
62
63/// Read from the specified kernel console input, placing data into `buffer`.
64///
65/// Returns the number of bytes read on success.
66pub fn sys_kernel_console_read_interruptable(
67    source: KernelConsoleSource,
68    buffer: &mut [u8],
69    flags: KernelConsoleReadFlags,
70    timeout: Option<Duration>,
71    waiter: Option<ThreadSyncSleep>,
72) -> Result<usize> {
73    let timeout = timeout
74        .as_ref()
75        .map_or(core::ptr::null(), |t| t as *const Duration);
76    let waiter = waiter
77        .as_ref()
78        .map_or(core::ptr::null(), |w| w as *const ThreadSyncSleep);
79    let (code, val) = unsafe {
80        raw_syscall(
81            Syscall::KernelConsoleRead,
82            &[
83                source.into(),
84                buffer.as_mut_ptr() as u64,
85                buffer.len() as u64,
86                flags.into(),
87                timeout as u64,
88                waiter as u64,
89            ],
90        )
91    };
92    convert_codes_to_result(code, val, |c, _| c != 0, |_, v| v as usize, twzerr)
93}
94
95bitflags! {
96    /// Flags to pass to [sys_kernel_console_write].
97    #[derive(Debug, Copy, Clone, PartialEq, Eq)]
98    pub struct KernelConsoleWriteFlags: u64 {
99        /// If the buffer is full, discard this write instead of overwriting old data.
100        const DISCARD_ON_FULL = 1;
101    }
102}
103
104/// Write to the kernel console.
105///
106/// This writes first to the kernel console buffer, for later reading by
107/// [sys_kernel_console_read_buffer], and then writes to the underlying kernel console device (if
108/// one is present). By default, if the buffer is full, this write will overwrite old data in the
109/// (circular) buffer, but this behavior can be controlled by the `flags` argument.
110///
111/// This function cannot fail.
112pub fn sys_kernel_console_write(
113    target: KernelConsoleSource,
114    buffer: &[u8],
115    flags: KernelConsoleWriteFlags,
116) {
117    let arg0 = buffer.as_ptr() as usize as u64;
118    let arg1 = buffer.len() as u64;
119    let arg2 = flags.bits();
120    let arg3 = target.into();
121    unsafe {
122        raw_syscall(Syscall::KernelConsoleWrite, &[arg0, arg1, arg2, arg3]);
123    }
124}