os/vfs/impls/
stdio_file.rs

1//! 标准 I/O 文件实现
2//!
3//! 提供标准输入、输出、错误输出的文件接口,直接操作控制台,不依赖 Inode。
4
5use crate::{
6    sync::SpinLock,
7    uapi::ioctl::Termios,
8    uapi::time::TimeSpec,
9    vfs::{File, FileMode, FsError, InodeMetadata, InodeType},
10};
11use alloc::sync::Arc;
12
13/// 全局终端设置(所有标准I/O文件共享)
14static STDIO_TERMIOS: SpinLock<Termios> = SpinLock::new(Termios::DEFAULT);
15
16/// 全局窗口大小(所有标准I/O文件共享)
17static STDIO_WINSIZE: SpinLock<crate::uapi::ioctl::WinSize> =
18    SpinLock::new(crate::uapi::ioctl::WinSize {
19        ws_row: 24,
20        ws_col: 80,
21        ws_xpixel: 0,
22        ws_ypixel: 0,
23    });
24
25/// 标准输入文件
26///
27/// 从控制台读取输入,行缓冲模式。
28pub struct StdinFile;
29
30impl File for StdinFile {
31    fn readable(&self) -> bool {
32        true
33    }
34
35    fn writable(&self) -> bool {
36        false
37    }
38
39    fn read(&self, buf: &mut [u8]) -> Result<usize, FsError> {
40        use crate::arch::lib::sbi::console_getchar;
41
42        let mut count = 0;
43        for byte in buf.iter_mut() {
44            let ch = console_getchar();
45            // SBI console_getchar 返回 -1 (usize::MAX) 表示无输入
46            if ch == usize::MAX {
47                break;
48            }
49
50            *byte = ch as u8;
51            count += 1;
52
53            if ch == b'\n' as usize {
54                break;
55            }
56        }
57
58        Ok(count)
59    }
60
61    fn write(&self, _buf: &[u8]) -> Result<usize, FsError> {
62        Err(FsError::PermissionDenied)
63    }
64
65    fn metadata(&self) -> Result<InodeMetadata, FsError> {
66        Ok(InodeMetadata {
67            inode_no: 0,
68            inode_type: InodeType::CharDevice,
69            mode: FileMode::S_IFCHR | FileMode::S_IRUSR,
70            uid: 0,
71            gid: 0,
72            size: 0,
73            atime: TimeSpec::now(),
74            mtime: TimeSpec::now(),
75            ctime: TimeSpec::now(),
76            nlinks: 1,
77            blocks: 0,
78            rdev: 0,
79        })
80    }
81
82    fn ioctl(&self, request: u32, arg: usize) -> Result<isize, FsError> {
83        stdio_ioctl(request, arg)
84    }
85
86    // lseek 使用默认实现 (返回 NotSupported)
87    fn as_any(&self) -> &dyn core::any::Any {
88        self
89    }
90}
91
92/// 标准输出文件
93///
94/// 输出到控制台,全缓冲模式。
95pub struct StdoutFile;
96
97impl File for StdoutFile {
98    fn readable(&self) -> bool {
99        false
100    }
101
102    fn writable(&self) -> bool {
103        true
104    }
105
106    fn read(&self, _buf: &mut [u8]) -> Result<usize, FsError> {
107        Err(FsError::PermissionDenied)
108    }
109
110    fn write(&self, buf: &[u8]) -> Result<usize, FsError> {
111        use crate::arch::lib::sbi::console_putchar;
112        for &byte in buf {
113            console_putchar(byte as usize);
114        }
115        Ok(buf.len())
116    }
117
118    fn metadata(&self) -> Result<InodeMetadata, FsError> {
119        Ok(InodeMetadata {
120            inode_no: 1,
121            inode_type: InodeType::CharDevice,
122            mode: FileMode::S_IFCHR | FileMode::S_IWUSR,
123            uid: 0,
124            gid: 0,
125            size: 0,
126            atime: TimeSpec::now(),
127            mtime: TimeSpec::now(),
128            ctime: TimeSpec::now(),
129            nlinks: 1,
130            blocks: 0,
131            rdev: 0,
132        })
133    }
134
135    fn ioctl(&self, request: u32, arg: usize) -> Result<isize, FsError> {
136        stdio_ioctl(request, arg)
137    }
138    fn as_any(&self) -> &dyn core::any::Any {
139        self
140    }
141}
142
143/// 标准错误输出文件
144///
145/// 输出到控制台(与 stdout 相同),无缓冲模式。
146pub struct StderrFile;
147
148impl File for StderrFile {
149    fn readable(&self) -> bool {
150        false
151    }
152
153    fn writable(&self) -> bool {
154        true
155    }
156
157    fn read(&self, _buf: &mut [u8]) -> Result<usize, FsError> {
158        Err(FsError::PermissionDenied)
159    }
160
161    fn write(&self, buf: &[u8]) -> Result<usize, FsError> {
162        use crate::arch::lib::sbi::console_putchar;
163        for &byte in buf {
164            console_putchar(byte as usize);
165        }
166        Ok(buf.len())
167    }
168
169    fn metadata(&self) -> Result<InodeMetadata, FsError> {
170        Ok(InodeMetadata {
171            inode_no: 2,
172            inode_type: InodeType::CharDevice,
173            mode: FileMode::S_IFCHR | FileMode::S_IWUSR,
174            uid: 0,
175            gid: 0,
176            size: 0,
177            atime: TimeSpec::now(),
178            mtime: TimeSpec::now(),
179            ctime: TimeSpec::now(),
180            nlinks: 1,
181            blocks: 0,
182            rdev: 0,
183        })
184    }
185
186    fn ioctl(&self, request: u32, arg: usize) -> Result<isize, FsError> {
187        stdio_ioctl(request, arg)
188    }
189    fn as_any(&self) -> &dyn core::any::Any {
190        self
191    }
192}
193
194/// 通用的 stdio ioctl 实现
195fn stdio_ioctl(request: u32, arg: usize) -> Result<isize, FsError> {
196    use crate::arch::trap::SumGuard;
197    use crate::uapi::errno::{EINVAL, ENOTTY};
198    use crate::uapi::ioctl::*;
199
200    match request {
201        TCGETS => {
202            if arg == 0 {
203                return Ok(-EINVAL as isize);
204            }
205
206            unsafe {
207                let _guard = SumGuard::new();
208                let termios_ptr = arg as *mut Termios;
209                if termios_ptr.is_null() {
210                    return Ok(-EINVAL as isize);
211                }
212
213                // 清零结构体(包括 padding),避免泄露内核栈数据
214                core::ptr::write_bytes(termios_ptr, 0, 1);
215
216                // 返回保存的 termios 设置
217                let termios = *STDIO_TERMIOS.lock();
218                core::ptr::write_volatile(termios_ptr, termios);
219
220                // 调试:打印返回的termios内容
221                use crate::earlyprintln;
222                earlyprintln!(
223                    "TCGETS: returning termios: iflag={:#x}, oflag={:#x}, cflag={:#x}, lflag={:#x}, ispeed={:#x}, ospeed={:#x}",
224                    termios.c_iflag,
225                    termios.c_oflag,
226                    termios.c_cflag,
227                    termios.c_lflag,
228                    termios.c_ispeed,
229                    termios.c_ospeed
230                );
231            }
232            Ok(0)
233        }
234
235        TCSETS | TCSETSW | TCSETSF => {
236            if arg == 0 {
237                return Ok(-EINVAL as isize);
238            }
239
240            unsafe {
241                let _guard = SumGuard::new();
242                let termios_ptr = arg as *const Termios;
243                if termios_ptr.is_null() {
244                    return Ok(-EINVAL as isize);
245                }
246
247                // 读取新的 termios 设置并保存
248                let new_termios = core::ptr::read_volatile(termios_ptr);
249
250                // 调试:打印接收到的termios内容
251                use crate::earlyprintln;
252                earlyprintln!(
253                    "TCSETS: received termios: iflag={:#x}, oflag={:#x}, cflag={:#x}, lflag={:#x}, ispeed={:#x}, ospeed={:#x}",
254                    new_termios.c_iflag,
255                    new_termios.c_oflag,
256                    new_termios.c_cflag,
257                    new_termios.c_lflag,
258                    new_termios.c_ispeed,
259                    new_termios.c_ospeed
260                );
261
262                *STDIO_TERMIOS.lock() = new_termios;
263            }
264            Ok(0)
265        }
266
267        TIOCGWINSZ => {
268            if arg == 0 {
269                return Ok(-EINVAL as isize);
270            }
271
272            unsafe {
273                let _guard = SumGuard::new();
274                let winsize_ptr = arg as *mut crate::uapi::ioctl::WinSize;
275                if winsize_ptr.is_null() {
276                    return Ok(-EINVAL as isize);
277                }
278
279                // 清零结构体(包括 padding),避免泄露内核栈数据
280                core::ptr::write_bytes(
281                    winsize_ptr as *mut u8,
282                    0,
283                    core::mem::size_of::<crate::uapi::ioctl::WinSize>(),
284                );
285
286                // 返回保存的窗口大小
287                let winsize = *STDIO_WINSIZE.lock();
288                core::ptr::write_volatile(winsize_ptr, winsize);
289
290                use crate::earlyprintln;
291                earlyprintln!(
292                    "TIOCGWINSZ: returning {}x{} ({}x{} pixels)",
293                    winsize.ws_row,
294                    winsize.ws_col,
295                    winsize.ws_xpixel,
296                    winsize.ws_ypixel
297                );
298            }
299            Ok(0)
300        }
301
302        TIOCSWINSZ => {
303            if arg == 0 {
304                return Ok(-EINVAL as isize);
305            }
306
307            unsafe {
308                let _guard = SumGuard::new();
309                let winsize_ptr = arg as *const crate::uapi::ioctl::WinSize;
310                if winsize_ptr.is_null() {
311                    return Ok(-EINVAL as isize);
312                }
313
314                // 读取新的窗口大小并保存
315                let new_winsize = core::ptr::read_volatile(winsize_ptr);
316                *STDIO_WINSIZE.lock() = new_winsize;
317
318                use crate::earlyprintln;
319                earlyprintln!(
320                    "TIOCSWINSZ: set to {}x{} ({}x{} pixels)",
321                    new_winsize.ws_row,
322                    new_winsize.ws_col,
323                    new_winsize.ws_xpixel,
324                    new_winsize.ws_ypixel
325                );
326            }
327            Ok(0)
328        }
329
330        // 其他 ioctl 命令不支持
331        _ => Ok(-ENOTTY as isize),
332    }
333}
334
335/// 创建标准 I/O 文件对象 (替代 stdio.rs:211-237)
336///
337/// 返回: 三元组 (stdin, stdout, stderr)
338pub fn create_stdio_files() -> (Arc<dyn File>, Arc<dyn File>, Arc<dyn File>) {
339    (
340        Arc::new(StdinFile),
341        Arc::new(StdoutFile),
342        Arc::new(StderrFile),
343    )
344}