1#![no_std]
2mod heap;
9
10extern crate alloc;
11
12use tg_console::log;
13
14pub use tg_console::{print, println};
15pub use tg_syscall::*;
16
17#[cfg(feature = "tangram")]
18pub mod tangram;
19
20pub fn fb_info() -> (u32, u32) {
23 let packed: usize;
24 unsafe {
25 core::arch::asm!(
26 "ecall",
27 in("a7") 2000usize,
28 lateout("a0") packed,
29 );
30 }
31 let width = (packed >> 32) as u32;
32 let height = packed as u32;
33 (width, height)
34}
35
36pub fn fb_write(x: u32, y: u32, w: u32, h: u32, data: *const u8) -> isize {
39 let ret: isize;
40 unsafe {
41 core::arch::asm!(
42 "ecall",
43 in("a7") 2001usize,
44 inlateout("a0") x as usize => ret,
45 in("a1") y as usize,
46 in("a2") w as usize,
47 in("a3") h as usize,
48 in("a4") data as usize,
49 );
50 }
51 ret
52}
53
54#[unsafe(no_mangle)]
55#[unsafe(link_section = ".text.entry")]
56pub extern "C" fn _start() -> ! {
57 tg_console::init_console(&Console);
59 tg_console::set_log_level(option_env!("LOG"));
60 heap::init();
61
62 unsafe extern "C" {
63 fn main() -> i32;
64 }
65
66 exit(unsafe { main() });
68 unreachable!()
69}
70
71#[panic_handler]
72fn panic_handler(panic_info: &core::panic::PanicInfo) -> ! {
73 let err = panic_info.message();
74 if let Some(location) = panic_info.location() {
75 log::error!("Panicked at {}:{}, {err}", location.file(), location.line());
76 } else {
77 log::error!("Panicked: {err}");
78 }
79 exit(1);
80 unreachable!()
81}
82
83pub fn getchar() -> u8 {
84 let mut c = [0u8; 1];
85 read(STDIN, &mut c);
86 c[0]
87}
88
89struct Console;
90
91impl tg_console::Console for Console {
92 #[inline]
93 fn put_char(&self, c: u8) {
94 tg_syscall::write(STDOUT, &[c]);
95 }
96
97 #[inline]
98 fn put_str(&self, s: &str) {
99 tg_syscall::write(STDOUT, s.as_bytes());
100 }
101}
102
103pub fn sleep(period_ms: usize) {
104 let mut time: TimeSpec = TimeSpec::ZERO;
106 clock_gettime(ClockId::CLOCK_MONOTONIC, &mut time as *mut _ as _);
107 let time = time + TimeSpec::from_millsecond(period_ms);
108 loop {
109 let mut now: TimeSpec = TimeSpec::ZERO;
110 clock_gettime(ClockId::CLOCK_MONOTONIC, &mut now as *mut _ as _);
111 if now > time {
112 break;
113 }
114 sched_yield();
115 }
116}
117
118pub fn get_time() -> isize {
119 let mut time: TimeSpec = TimeSpec::ZERO;
120 clock_gettime(ClockId::CLOCK_MONOTONIC, &mut time as *mut _ as _);
121 (time.tv_sec * 1000 + time.tv_nsec / 1_000_000) as isize
122}
123
124pub fn trace_read(ptr: *const u8) -> Option<u8> {
125 let ret = trace(0, ptr as usize, 0);
126 if ret >= 0 && ret <= 255 {
127 Some(ret as u8)
128 } else {
129 None
130 }
131}
132
133pub fn trace_write(ptr: *const u8, value: u8) -> isize {
134 trace(1, ptr as usize, value as usize)
135}
136
137pub fn count_syscall(syscall_id: usize) -> isize {
138 trace(2, syscall_id, 0)
139}
140
141pub fn pipe_read(pipe_fd: usize, buffer: &mut [u8]) -> isize {
144 let mut total_read = 0usize;
145 let len = buffer.len();
146 loop {
147 if total_read >= len {
148 return total_read as isize;
149 }
150 let ret = read(pipe_fd, &mut buffer[total_read..]);
151 if ret == -2 {
152 sched_yield();
154 continue;
155 } else if ret == 0 {
156 return total_read as isize;
158 } else if ret < 0 {
159 return ret;
161 } else {
162 total_read += ret as usize;
163 }
164 }
165}
166
167pub fn pipe_write(pipe_fd: usize, buffer: &[u8]) -> isize {
170 let mut total_write = 0usize;
171 let len = buffer.len();
172 loop {
173 if total_write >= len {
174 return total_write as isize;
175 }
176 let ret = write(pipe_fd, &buffer[total_write..]);
177 if ret == -2 {
178 sched_yield();
180 continue;
181 } else if ret < 0 {
182 return ret;
184 } else {
185 total_write += ret as usize;
186 }
187 }
188}