1use core::{
4 ffi::{c_char, c_int, c_long, c_uint, c_ulong, c_void},
5 sync::atomic::Ordering,
6};
7
8use crate::{
9 arch::{
10 lib::sbi::shutdown,
11 timer::{TICKS_PER_SEC, TIMER_TICKS, clock_freq},
12 trap::SumGuard,
13 },
14 kernel::{
15 current_task,
16 syscall::util::{check_syslog_permission, validate_syslog_args},
17 time::update_realtime,
18 },
19 log::{
20 DEFAULT_CONSOLE_LEVEL, LogLevel, format_log_entry, get_console_level, read_log,
21 set_console_level,
22 },
23 pr_alert,
24 security::{BiogasPoll, EntropyPool},
25 uapi::{
26 errno::{EINVAL, ENOSYS},
27 log::SyslogAction,
28 reboot::{
29 REBOOT_CMD_POWER_OFF, REBOOT_MAGIC1, REBOOT_MAGIC2, REBOOT_MAGIC2A, REBOOT_MAGIC2B,
30 REBOOT_MAGIC2C,
31 },
32 sysinfo::SysInfo,
33 time::clock_id::{
34 CLOCK_MONOTONIC, CLOCK_MONOTONIC_COARSE, CLOCK_MONOTONIC_RAW, CLOCK_REALTIME,
35 CLOCK_REALTIME_COARSE, MAX_CLOCKS,
36 },
37 types::SizeT,
38 uts_namespace::{UTS_NAME_LEN, UtsNamespace},
39 },
40 util::{
41 cstr_copy,
42 user_buffer::{UserBuffer, write_to_user},
43 },
44 vfs::TimeSpec,
45};
46
47pub fn reboot(magic: c_int, magic2: c_int, op: c_int, _arg: *mut c_void) -> c_int {
57 if magic as u32 != REBOOT_MAGIC1 {
59 return -EINVAL;
60 }
61 if magic2 as u32 != REBOOT_MAGIC2
62 && magic2 as u32 != REBOOT_MAGIC2A
63 && magic2 as u32 != REBOOT_MAGIC2B
64 && magic2 as u32 != REBOOT_MAGIC2C
65 {
66 return -EINVAL;
67 }
68 match op as u32 {
69 REBOOT_CMD_POWER_OFF => {
70 shutdown(true);
71 }
72 _ => {
73 pr_alert!("reboot: unsupported reboot operation code {}\n", op);
74 }
75 }
76 0
77}
78
79pub fn uname(buf: *mut UtsNamespace) -> c_int {
85 let uts = {
86 let task = current_task();
87 let t = task.lock();
88 t.uts_namespace.clone()
89 };
90 let uts_lock = uts.lock();
91 unsafe {
92 write_to_user(buf, uts_lock.clone());
93 }
94 0
95 }
97
98pub fn set_hostname(name: *const c_char, len: usize) -> c_int {
105 if len > UTS_NAME_LEN {
106 return -EINVAL;
107 }
108 let uts = {
109 let task = current_task();
110 let t = task.lock();
111 t.uts_namespace.clone()
112 };
113 let name_buf = UserBuffer::new(name as *mut _, len);
114 let name = unsafe { name_buf.copy_from_user() };
115 {
116 let mut uts_lock = uts.lock();
117 cstr_copy(name.as_ptr(), &mut uts_lock.nodename, len);
118 }
119 0
120 }
122
123pub fn sysinfo(info: *mut SysInfo) -> c_int {
130 let mut sys_info = SysInfo::new();
132 sys_info.uptime = (TIMER_TICKS.load(Ordering::SeqCst) / TICKS_PER_SEC) as c_ulong;
133 unsafe {
134 write_to_user(info, sys_info);
135 }
136 0
137}
138
139pub fn clock_gettime(clk_id: c_int, tp: *mut TimeSpec) -> c_int {
147 let ts = match clk_id {
148 CLOCK_REALTIME | CLOCK_REALTIME_COARSE => TimeSpec::now(),
149 CLOCK_MONOTONIC | CLOCK_MONOTONIC_COARSE | CLOCK_MONOTONIC_RAW => TimeSpec::monotonic_now(),
150 id if id < MAX_CLOCKS as c_int && id >= 0 => {
151 return -ENOSYS;
152 }
153 _ => {
154 return -EINVAL;
155 }
156 };
157
158 unsafe {
159 write_to_user(tp, ts);
160 }
161
162 0
163}
164
165pub fn clock_settime(clk_id: c_int, tp: *const TimeSpec) -> c_int {
173 match clk_id {
174 CLOCK_REALTIME | CLOCK_REALTIME_COARSE => {
175 let ts: TimeSpec = unsafe { core::ptr::read(tp) };
176 update_realtime(&ts);
177 0
178 }
179 CLOCK_MONOTONIC | CLOCK_MONOTONIC_COARSE | CLOCK_MONOTONIC_RAW => {
180 -EINVAL
182 }
183 id if id < MAX_CLOCKS as c_int && id >= 0 => -ENOSYS,
184 _ => -EINVAL,
185 }
186}
187
188pub fn clock_getres(clk_id: c_int, tp: *mut TimeSpec) -> c_int {
196 let res = match clk_id {
197 CLOCK_REALTIME | CLOCK_REALTIME_COARSE => TimeSpec {
198 tv_sec: 0,
199 tv_nsec: 1_000_000_000 / (clock_freq() as c_long),
200 },
201 CLOCK_MONOTONIC | CLOCK_MONOTONIC_COARSE | CLOCK_MONOTONIC_RAW => TimeSpec {
202 tv_sec: 0,
203 tv_nsec: 1_000_000_000 / (clock_freq() as c_long),
204 },
205 id if id < MAX_CLOCKS as c_int && id >= 0 => {
206 return -ENOSYS;
207 }
208 _ => {
209 return -EINVAL;
210 }
211 };
212
213 unsafe {
214 write_to_user(tp, res);
215 }
216
217 0
218}
219
220pub fn syslog(type_: i32, bufp: *mut u8, len: i32) -> isize {
239 let action = match SyslogAction::from_i32(type_) {
241 Ok(a) => a,
242 Err(e) => return -(e as isize),
243 };
244
245 if let Err(e) = validate_syslog_args(action, bufp, len) {
246 return -(e as isize);
247 }
248
249 if let Err(e) = check_syslog_permission(action) {
250 return -(e as isize);
251 }
252
253 match action {
254 SyslogAction::Read => {
256 let buf_len = len as usize;
258 let mut total_written = 0;
259
260 let _guard = SumGuard::new();
262
263 while total_written < buf_len {
264 let entry = match read_log() {
280 Some(e) => e,
281 None => break, };
283
284 let formatted = format_log_entry(&entry);
286 let bytes = formatted.as_bytes();
287
288 if total_written + bytes.len() > buf_len {
290 break;
294 }
295
296 unsafe {
298 core::ptr::copy_nonoverlapping(
299 bytes.as_ptr(),
300 bufp.add(total_written),
301 bytes.len(),
302 );
303 }
304
305 total_written += bytes.len();
306 }
307
308 total_written as isize
311 }
312
313 SyslogAction::ReadAll => {
315 use crate::log::{log_reader_index, log_writer_index, peek_log};
317
318 let buf_len = len as usize;
319 let mut total_written = 0;
320
321 let start_index = log_reader_index();
323 let end_index = log_writer_index();
324
325 let _guard = SumGuard::new();
327
328 let mut current_index = start_index;
330 while current_index < end_index && total_written < buf_len {
331 let entry = match peek_log(current_index) {
344 Some(e) => e,
345 None => break, };
347
348 let formatted = format_log_entry(&entry);
349 let bytes = formatted.as_bytes();
350
351 if total_written + bytes.len() > buf_len {
352 break;
354 }
355
356 unsafe {
357 core::ptr::copy_nonoverlapping(
358 bytes.as_ptr(),
359 bufp.add(total_written),
360 bytes.len(),
361 );
362 }
363
364 total_written += bytes.len();
365 current_index += 1;
366 }
367
368 total_written as isize
371 }
372
373 SyslogAction::ReadClear => {
374 let buf_len = len as usize;
376 let mut total_written = 0;
377
378 let _guard = SumGuard::new();
379
380 while total_written < buf_len {
381 let entry = match read_log() {
382 Some(e) => e,
383 None => break,
384 };
385
386 let formatted = format_log_entry(&entry);
387 let bytes = formatted.as_bytes();
388
389 if total_written + bytes.len() > buf_len {
390 break;
391 }
392
393 unsafe {
394 core::ptr::copy_nonoverlapping(
395 bytes.as_ptr(),
396 bufp.add(total_written),
397 bytes.len(),
398 );
399 }
400
401 total_written += bytes.len();
402 }
403
404 while read_log().is_some() {}
406
407 total_written as isize
408 }
409
410 SyslogAction::Clear => {
412 while read_log().is_some() {}
414 0
415 }
416
417 SyslogAction::ConsoleOff => {
419 set_console_level(LogLevel::Emergency);
422 0
423 }
424
425 SyslogAction::ConsoleOn => {
426 set_console_level(DEFAULT_CONSOLE_LEVEL);
429 0
430 }
431
432 SyslogAction::ConsoleLevel => {
433 let new_level_u8 = (len - 1) as u8; let new_level = LogLevel::from_u8(new_level_u8);
453
454 let old_level = get_console_level();
456 let old_level_u8 = old_level.to_u8();
457
458 set_console_level(new_level);
460
461 (old_level_u8 + 1) as isize
463 }
464
465 SyslogAction::SizeUnread => {
467 use crate::log::log_unread_bytes;
469 log_unread_bytes() as isize
470 }
471
472 SyslogAction::SizeBuffer => {
473 use crate::log::GLOBAL_LOG_BUFFER_SIZE;
475 GLOBAL_LOG_BUFFER_SIZE as isize
476 }
477
478 SyslogAction::Close | SyslogAction::Open => 0,
480 }
481}
482
483pub fn getrandom(buf: *mut c_void, len: SizeT, _flags: c_uint) -> c_int {
492 let mut pool = BiogasPoll::new();
493 for i in 0..len {
494 let byte = match pool.try_fill(core::slice::from_mut(unsafe {
495 &mut *(buf as *mut u8).add(i as usize)
496 })) {
497 Ok(_) => unsafe { *(buf as *mut u8).add(i as usize) },
498 Err(_) => return -EINVAL,
499 };
500 unsafe {
501 *(buf as *mut u8).add(i as usize) = byte;
502 }
503 }
504 len as c_int
505}