Skip to main content

strat9_kernel/vfs/
console_scheme.rs

1use alloc::{string::String, sync::Arc};
2use core::sync::atomic::{AtomicU64, Ordering};
3
4use crate::{sync::SpinLock, syscall::error::SyscallError};
5
6use super::{
7    fd::FileDescriptorTable,
8    file::OpenFile,
9    scheme::{
10        finalize_pseudo_stat, DynScheme, FileFlags, FileStat, OpenFlags, OpenResult, Scheme,
11        DEV_CONSOLE,
12    },
13};
14
15static NEXT_ID: AtomicU64 = AtomicU64::new(1);
16static CONSOLE: SpinLock<Option<Arc<ConsoleScheme>>> = SpinLock::new(None);
17
18pub struct ConsoleScheme;
19
20impl ConsoleScheme {
21    /// Creates a new instance.
22    pub fn new() -> Self {
23        ConsoleScheme
24    }
25}
26
27impl Scheme for ConsoleScheme {
28    /// Performs the open operation.
29    fn open(&self, _path: &str, _flags: OpenFlags) -> Result<OpenResult, SyscallError> {
30        let id = NEXT_ID.fetch_add(1, Ordering::Relaxed);
31        Ok(OpenResult {
32            file_id: id,
33            size: None,
34            flags: FileFlags::DEVICE,
35        })
36    }
37
38    /// Performs the read operation.
39    fn read(&self, _file_id: u64, _offset: u64, buf: &mut [u8]) -> Result<usize, SyscallError> {
40        let mut count = 0;
41        for slot in buf.iter_mut() {
42            match crate::arch::x86_64::keyboard::read_char() {
43                Some(ch) => {
44                    *slot = ch;
45                    count += 1;
46                }
47                None => break,
48            }
49        }
50        Ok(count)
51    }
52
53    /// Performs the write operation.
54    fn write(&self, _file_id: u64, _offset: u64, buf: &[u8]) -> Result<usize, SyscallError> {
55        if let Ok(s) = core::str::from_utf8(buf) {
56            crate::serial_print!("{}", s);
57            if crate::arch::x86_64::vga::is_available() {
58                crate::vga_print!("{}", s);
59            }
60        } else {
61            for &b in buf {
62                crate::serial_print!("{}", b as char);
63            }
64        }
65        Ok(buf.len())
66    }
67
68    /// Performs the close operation.
69    fn close(&self, _file_id: u64) -> Result<(), SyscallError> {
70        Ok(())
71    }
72
73    /// Performs the stat operation.
74    fn stat(&self, _file_id: u64) -> Result<FileStat, SyscallError> {
75        Ok(finalize_pseudo_stat(
76            FileStat {
77                st_ino: 0,
78                st_mode: 0o020666,
79                st_nlink: 1,
80                st_size: 0,
81                st_blksize: 1,
82                st_blocks: 0,
83                ..FileStat::zeroed()
84            },
85            DEV_CONSOLE,
86            1,
87        ))
88    }
89}
90
91/// Initializes console scheme.
92pub fn init_console_scheme() -> Arc<ConsoleScheme> {
93    let scheme = Arc::new(ConsoleScheme::new());
94    *CONSOLE.lock() = Some(scheme.clone());
95    scheme
96}
97
98/// Performs the setup stdio operation.
99pub fn setup_stdio(fd_table: &mut FileDescriptorTable) {
100    let scheme = match CONSOLE.lock().clone() {
101        Some(s) => s as DynScheme,
102        None => return,
103    };
104
105    // fd 0 — stdin (read)
106    let r0 = scheme.open("console", OpenFlags::READ).unwrap();
107    let stdin = Arc::new(OpenFile::new(
108        scheme.clone(),
109        r0.file_id,
110        String::from("/dev/console"),
111        OpenFlags::READ,
112        FileFlags::DEVICE,
113        None,
114    ));
115    fd_table.insert_at(0, stdin);
116
117    // fd 1 — stdout (write)
118    let r1 = scheme.open("console", OpenFlags::WRITE).unwrap();
119    let stdout = Arc::new(OpenFile::new(
120        scheme.clone(),
121        r1.file_id,
122        String::from("/dev/console"),
123        OpenFlags::WRITE,
124        FileFlags::DEVICE,
125        None,
126    ));
127    fd_table.insert_at(1, stdout);
128
129    // fd 2 — stderr (write)
130    let r2 = scheme.open("console", OpenFlags::WRITE).unwrap();
131    let stderr = Arc::new(OpenFile::new(
132        scheme,
133        r2.file_id,
134        String::from("/dev/console"),
135        OpenFlags::WRITE,
136        FileFlags::DEVICE,
137        None,
138    ));
139    fd_table.insert_at(2, stderr);
140}