Skip to main content

user_lib/
lib.rs

1#![no_std]
2//!
3//! 教程阅读建议:
4//!
5//! - `_start` 展示用户程序最小运行时(初始化控制台、堆、调用 main);
6//! - 其余辅助函数(sleep/pipe_*)展示了常见 syscall 组合用法。
7
8mod heap;
9
10extern crate alloc;
11
12use tg_console::log;
13
14pub use tg_console::{print, println};
15pub use tg_syscall::*;
16
17#[unsafe(no_mangle)]
18#[unsafe(link_section = ".text.entry")]
19pub extern "C" fn _start() -> ! {
20    // 用户态运行时初始化顺序与内核类似:先 I/O,再堆,再进入 main。
21    tg_console::init_console(&Console);
22    tg_console::set_log_level(option_env!("LOG"));
23    heap::init();
24
25    unsafe extern "C" {
26        fn main() -> i32;
27    }
28
29    // SAFETY: main 函数由用户程序提供,链接器保证其存在且符合 C ABI
30    exit(unsafe { main() });
31    unreachable!()
32}
33
34#[panic_handler]
35fn panic_handler(panic_info: &core::panic::PanicInfo) -> ! {
36    let err = panic_info.message();
37    if let Some(location) = panic_info.location() {
38        log::error!("Panicked at {}:{}, {err}", location.file(), location.line());
39    } else {
40        log::error!("Panicked: {err}");
41    }
42    exit(1);
43    unreachable!()
44}
45
46pub fn getchar() -> u8 {
47    let mut c = [0u8; 1];
48    read(STDIN, &mut c);
49    c[0]
50}
51
52struct Console;
53
54impl tg_console::Console for Console {
55    #[inline]
56    fn put_char(&self, c: u8) {
57        tg_syscall::write(STDOUT, &[c]);
58    }
59
60    #[inline]
61    fn put_str(&self, s: &str) {
62        tg_syscall::write(STDOUT, s.as_bytes());
63    }
64}
65
66pub fn sleep(period_ms: usize) {
67    // 轮询时钟 + 主动让出 CPU 的教学实现,便于理解 time/yield 系统调用协作。
68    let mut time: TimeSpec = TimeSpec::ZERO;
69    clock_gettime(ClockId::CLOCK_MONOTONIC, &mut time as *mut _ as _);
70    let time = time + TimeSpec::from_millsecond(period_ms);
71    loop {
72        let mut now: TimeSpec = TimeSpec::ZERO;
73        clock_gettime(ClockId::CLOCK_MONOTONIC, &mut now as *mut _ as _);
74        if now > time {
75            break;
76        }
77        sched_yield();
78    }
79}
80
81pub fn get_time() -> isize {
82    let mut time: TimeSpec = TimeSpec::ZERO;
83    clock_gettime(ClockId::CLOCK_MONOTONIC, &mut time as *mut _ as _);
84    (time.tv_sec * 1000 + time.tv_nsec / 1_000_000) as isize
85}
86
87pub fn trace_read(ptr: *const u8) -> Option<u8> {
88    let ret = trace(0, ptr as usize, 0);
89    if ret >= 0 && ret <= 255 {
90        Some(ret as u8)
91    } else {
92        None
93    }
94}
95
96pub fn trace_write(ptr: *const u8, value: u8) -> isize {
97    trace(1, ptr as usize, value as usize)
98}
99
100pub fn count_syscall(syscall_id: usize) -> isize {
101    trace(2, syscall_id, 0)
102}
103
104/// 从管道读取数据
105/// 返回实际读取的总字节数,负数表示错误
106pub fn pipe_read(pipe_fd: usize, buffer: &mut [u8]) -> isize {
107    let mut total_read = 0usize;
108    let len = buffer.len();
109    loop {
110        if total_read >= len {
111            return total_read as isize;
112        }
113        let ret = read(pipe_fd, &mut buffer[total_read..]);
114        if ret == -2 {
115            // 暂时无数据,让出 CPU 后重试
116            sched_yield();
117            continue;
118        } else if ret == 0 {
119            // EOF,写端关闭
120            return total_read as isize;
121        } else if ret < 0 {
122            // 其他错误
123            return ret;
124        } else {
125            total_read += ret as usize;
126        }
127    }
128}
129
130/// 向管道写入数据
131/// 返回实际写入的总字节数,负数表示错误
132pub fn pipe_write(pipe_fd: usize, buffer: &[u8]) -> isize {
133    let mut total_write = 0usize;
134    let len = buffer.len();
135    loop {
136        if total_write >= len {
137            return total_write as isize;
138        }
139        let ret = write(pipe_fd, &buffer[total_write..]);
140        if ret == -2 {
141            // 缓冲区满,让出 CPU 后重试
142            sched_yield();
143            continue;
144        } else if ret < 0 {
145            // 其他错误
146            return ret;
147        } else {
148            total_write += ret as usize;
149        }
150    }
151}