Skip to main content

user_lib/
lib.rs

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