1#![allow(dead_code)]
6
7use alloc::{boxed::Box, format, string::String};
8use core::{ptr, slice};
9
10pub(crate) mod memory {
12 use super::*;
13
14 pub(crate) unsafe fn malloc(size: usize) -> *mut u8 {
20 if size == 0 {
21 return ptr::null_mut();
22 }
23
24 let layout = core::alloc::Layout::from_size_align(size, 8)
28 .unwrap_or_else(|_| core::alloc::Layout::from_size_align(1, 1).expect("1-byte layout"));
29
30 alloc::alloc::alloc(layout)
31 }
32
33 pub(crate) unsafe fn calloc(count: usize, size: usize) -> *mut u8 {
40 let total_size = count.saturating_mul(size);
41 if total_size == 0 {
42 return ptr::null_mut();
43 }
44
45 let layout = core::alloc::Layout::from_size_align(total_size, 8)
47 .unwrap_or_else(|_| core::alloc::Layout::from_size_align(1, 1).expect("1-byte layout"));
48
49 alloc::alloc::alloc_zeroed(layout)
50 }
51
52 pub(crate) unsafe fn realloc(ptr: *mut u8, new_size: usize) -> *mut u8 {
60 if ptr.is_null() {
61 return malloc(new_size);
62 }
63
64 if new_size == 0 {
65 free(ptr);
66 return ptr::null_mut();
67 }
68
69 let new_ptr = malloc(new_size);
72 if !new_ptr.is_null() {
73 ptr::copy_nonoverlapping(ptr, new_ptr, new_size.min(1024)); free(ptr);
77 }
78
79 new_ptr
80 }
81
82 pub(crate) unsafe fn free(ptr: *mut u8) {
88 if !ptr.is_null() {
89 let layout = core::alloc::Layout::from_size_align(1, 1).expect("1-byte layout");
92 alloc::alloc::dealloc(ptr, layout);
93 }
94 }
95
96 pub(crate) unsafe fn memcpy(dest: *mut u8, src: *const u8, n: usize) -> *mut u8 {
102 ptr::copy_nonoverlapping(src, dest, n);
103 dest
104 }
105
106 pub(crate) unsafe fn memmove(dest: *mut u8, src: *const u8, n: usize) -> *mut u8 {
111 ptr::copy(src, dest, n);
112 dest
113 }
114
115 pub(crate) unsafe fn memset(dest: *mut u8, value: i32, n: usize) -> *mut u8 {
120 ptr::write_bytes(dest, value as u8, n);
121 dest
122 }
123
124 pub(crate) unsafe fn memcmp(s1: *const u8, s2: *const u8, n: usize) -> i32 {
129 let slice1 = slice::from_raw_parts(s1, n);
130 let slice2 = slice::from_raw_parts(s2, n);
131
132 for i in 0..n {
133 match slice1[i].cmp(&slice2[i]) {
134 core::cmp::Ordering::Less => return -1,
135 core::cmp::Ordering::Greater => return 1,
136 core::cmp::Ordering::Equal => continue,
137 }
138 }
139
140 0
141 }
142}
143
144pub(crate) mod string {
146 use super::*;
147
148 pub(crate) unsafe fn strlen(s: *const u8) -> usize {
153 let mut len = 0;
154 while *s.add(len) != 0 {
155 len += 1;
156 }
157 len
158 }
159
160 pub(crate) unsafe fn strcpy(dest: *mut u8, src: *const u8) -> *mut u8 {
166 let mut i = 0;
167 loop {
168 let c = *src.add(i);
169 *dest.add(i) = c;
170 if c == 0 {
171 break;
172 }
173 i += 1;
174 }
175 dest
176 }
177
178 pub(crate) unsafe fn strncpy(dest: *mut u8, src: *const u8, n: usize) -> *mut u8 {
184 let mut i = 0;
185 while i < n {
186 let c = *src.add(i);
187 *dest.add(i) = c;
188 if c == 0 {
189 break;
190 }
191 i += 1;
192 }
193
194 while i < n {
196 *dest.add(i) = 0;
197 i += 1;
198 }
199
200 dest
201 }
202
203 pub(crate) unsafe fn strcat(dest: *mut u8, src: *const u8) -> *mut u8 {
209 let dest_len = strlen(dest);
210 strcpy(dest.add(dest_len), src);
211 dest
212 }
213
214 pub(crate) unsafe fn strcmp(s1: *const u8, s2: *const u8) -> i32 {
219 let mut i = 0;
220 loop {
221 let c1 = *s1.add(i);
222 let c2 = *s2.add(i);
223
224 if c1 != c2 {
225 return if c1 < c2 { -1 } else { 1 };
226 }
227
228 if c1 == 0 {
229 return 0;
230 }
231
232 i += 1;
233 }
234 }
235
236 pub(crate) unsafe fn strncmp(s1: *const u8, s2: *const u8, n: usize) -> i32 {
242 for i in 0..n {
243 let c1 = *s1.add(i);
244 let c2 = *s2.add(i);
245
246 if c1 != c2 {
247 return if c1 < c2 { -1 } else { 1 };
248 }
249
250 if c1 == 0 {
251 return 0;
252 }
253 }
254
255 0
256 }
257
258 pub(crate) unsafe fn strchr(s: *const u8, c: i32) -> *const u8 {
263 let target = c as u8;
264 let mut i = 0;
265
266 loop {
267 let ch = *s.add(i);
268 if ch == target {
269 return s.add(i);
270 }
271 if ch == 0 {
272 break;
273 }
274 i += 1;
275 }
276
277 ptr::null()
278 }
279
280 pub(crate) unsafe fn strstr(haystack: *const u8, needle: *const u8) -> *const u8 {
286 let needle_len = strlen(needle);
287 if needle_len == 0 {
288 return haystack;
289 }
290
291 let haystack_len = strlen(haystack);
292 if needle_len > haystack_len {
293 return ptr::null();
294 }
295
296 for i in 0..=(haystack_len - needle_len) {
297 if strncmp(haystack.add(i), needle, needle_len) == 0 {
298 return haystack.add(i);
299 }
300 }
301
302 ptr::null()
303 }
304}
305
306pub(crate) mod io {
308 use alloc::sync::Arc;
309
310 use super::*;
311 use crate::fs::{get_vfs, OpenFlags};
312
313 #[allow(dead_code)] pub struct File {
320 node: Arc<dyn crate::fs::VfsNode>,
321 position: usize,
322 flags: OpenFlags,
323 }
324
325 pub const STDIN: i32 = 0;
327 pub const STDOUT: i32 = 1;
328 pub const STDERR: i32 = 2;
329
330 pub const O_RDONLY: i32 = 0;
332 pub const O_WRONLY: i32 = 1;
333 pub const O_RDWR: i32 = 2;
334 pub const O_CREAT: i32 = 0x40;
335 pub const O_TRUNC: i32 = 0x200;
336 pub const O_APPEND: i32 = 0x400;
337
338 pub const SEEK_SET: i32 = 0;
340 pub const SEEK_CUR: i32 = 1;
341 pub const SEEK_END: i32 = 2;
342
343 pub(crate) fn open(path: &str, flags: i32) -> Result<*mut File, crate::error::KernelError> {
345 let open_flags = if flags & O_RDWR != 0 {
346 OpenFlags::read_write()
347 } else if flags & O_WRONLY != 0 {
348 OpenFlags::write_only()
349 } else {
350 OpenFlags::read_only()
351 };
352
353 match get_vfs().read().open(path, open_flags) {
354 Ok(node) => {
355 let file = Box::new(File {
356 node,
357 position: 0,
358 flags: open_flags,
359 });
360 Ok(Box::into_raw(file))
361 }
362 Err(e) => Err(e),
363 }
364 }
365
366 pub(crate) unsafe fn close(file: *mut File) -> i32 {
373 if file.is_null() {
374 return -1;
375 }
376
377 drop(Box::from_raw(file));
378 0
379 }
380
381 pub(crate) unsafe fn read(file: *mut File, buf: *mut u8, count: usize) -> isize {
387 if file.is_null() || buf.is_null() {
388 return -1;
389 }
390
391 let file_ref = &mut *file;
392 let buffer = slice::from_raw_parts_mut(buf, count);
393
394 match file_ref.node.read(file_ref.position, buffer) {
395 Ok(bytes_read) => {
396 file_ref.position += bytes_read;
397 bytes_read as isize
398 }
399 Err(_) => -1,
400 }
401 }
402
403 pub(crate) unsafe fn write(file: *mut File, buf: *const u8, count: usize) -> isize {
409 if file.is_null() || buf.is_null() {
410 return -1;
411 }
412
413 let file_ref = &mut *file;
414 let buffer = slice::from_raw_parts(buf, count);
415
416 match file_ref.node.write(file_ref.position, buffer) {
417 Ok(bytes_written) => {
418 file_ref.position += bytes_written;
419 bytes_written as isize
420 }
421 Err(_) => -1,
422 }
423 }
424
425 pub(crate) unsafe fn seek(file: *mut File, offset: isize, whence: i32) -> isize {
430 if file.is_null() {
431 return -1;
432 }
433
434 let file_ref = &mut *file;
435
436 let new_position = match whence {
437 SEEK_SET => {
438 if offset < 0 {
439 return -1;
440 }
441 offset as usize
442 }
443 SEEK_CUR => {
444 if offset < 0 && (-offset) as usize > file_ref.position {
445 return -1;
446 }
447 if offset >= 0 {
448 file_ref.position + offset as usize
449 } else {
450 file_ref.position - (-offset) as usize
451 }
452 }
453 SEEK_END => {
454 match file_ref.node.metadata() {
456 Ok(meta) => {
457 if offset < 0 && (-offset) as usize > meta.size {
458 return -1;
459 }
460 if offset >= 0 {
461 meta.size + offset as usize
462 } else {
463 meta.size - (-offset) as usize
464 }
465 }
466 Err(_) => return -1,
467 }
468 }
469 _ => return -1,
470 };
471
472 file_ref.position = new_position;
473 new_position as isize
474 }
475
476 pub(crate) fn printf(fmt: &str, args: &[&dyn core::fmt::Display]) -> i32 {
478 let mut output = String::new();
480 let mut arg_index = 0;
481 let mut chars = fmt.chars();
482
483 while let Some(ch) = chars.next() {
484 if ch == '%' {
485 if let Some(next_ch) = chars.next() {
486 match next_ch {
487 's' | 'd' | 'x' | 'c' => {
488 if arg_index < args.len() {
489 output.push_str(&format!("{}", args[arg_index]));
490 arg_index += 1;
491 }
492 }
493 '%' => output.push('%'),
494 _ => {
495 output.push('%');
496 output.push(next_ch);
497 }
498 }
499 } else {
500 output.push('%');
501 }
502 } else {
503 output.push(ch);
504 }
505 }
506
507 crate::print!("{}", output);
508 output.len() as i32
509 }
510
511 pub(crate) fn puts(s: &str) -> i32 {
513 crate::println!("{}", s);
514 (s.len() + 1) as i32
515 }
516}
517
518pub(crate) mod process {
520
521 pub(crate) fn exit(status: i32) -> ! {
523 crate::process::lifecycle::exit_process(status);
524 loop {
528 crate::arch::idle();
529 }
530 }
531
532 pub(crate) fn getpid() -> u32 {
534 crate::process::get_current_process()
535 .map(|p| p.pid.0 as u32)
536 .unwrap_or(0) }
538
539 pub(crate) fn getppid() -> u32 {
541 crate::process::get_current_process()
542 .and_then(|p| p.parent)
543 .map(|ppid| ppid.0 as u32)
544 .unwrap_or(1) }
547
548 pub(crate) fn fork() -> i32 {
555 match crate::process::fork_process() {
556 Ok(child_pid) => {
557 child_pid.0 as i32
560 }
561 Err(_) => -1,
562 }
563 }
564
565 pub(crate) fn exec(path: &str, args: &[&str]) -> i32 {
567 match crate::userspace::load_user_program(path, args, &[]) {
568 Ok(pid) => pid.0 as i32,
569 Err(_) => -1,
570 }
571 }
572
573 pub(crate) unsafe fn wait(status: *mut i32) -> i32 {
584 match crate::process::wait_for_child(None) {
585 Ok((pid, exit_status)) => {
586 if !status.is_null() {
589 *status = exit_status;
590 }
591 pid.0 as i32
592 }
593 Err(_) => -1,
594 }
595 }
596}
597
598pub(crate) mod math {
600 pub(crate) fn abs(x: i32) -> i32 {
602 if x < 0 {
603 -x
604 } else {
605 x
606 }
607 }
608
609 pub(crate) fn fabs(x: f64) -> f64 {
611 if x < 0.0 {
612 -x
613 } else {
614 x
615 }
616 }
617
618 pub(crate) fn pow_int(base: i32, exp: u32) -> i32 {
620 let mut result = 1;
621 let mut b = base;
622 let mut e = exp;
623
624 while e > 0 {
625 if e & 1 != 0 {
626 result *= b;
627 }
628 b *= b;
629 e >>= 1;
630 }
631
632 result
633 }
634
635 pub(crate) fn sqrt_int(x: u32) -> u32 {
637 if x == 0 {
638 return 0;
639 }
640
641 let mut guess = x / 2;
642 let mut last_guess = x;
643
644 while guess != last_guess {
645 last_guess = guess;
646 guess = (guess + x / guess) / 2;
647 }
648
649 guess
650 }
651
652 pub(crate) fn min(a: i32, b: i32) -> i32 {
654 if a < b {
655 a
656 } else {
657 b
658 }
659 }
660
661 pub(crate) fn max(a: i32, b: i32) -> i32 {
663 if a > b {
664 a
665 } else {
666 b
667 }
668 }
669}
670
671pub(crate) mod time {
673 use core::sync::atomic::{AtomicU64, Ordering};
674
675 static BOOT_TIME_SECONDS: AtomicU64 = AtomicU64::new(0);
677
678 pub(crate) fn set_boot_time(seconds_since_epoch: u64) {
680 BOOT_TIME_SECONDS.store(seconds_since_epoch, Ordering::Release);
681 }
682
683 pub(crate) fn time() -> u64 {
689 let ticks = crate::arch::timer::get_ticks();
690 let seconds_since_boot = ticks / 1000;
693
694 BOOT_TIME_SECONDS.load(Ordering::Acquire) + seconds_since_boot
695 }
696
697 pub(crate) fn sleep(seconds: u32) {
699 crate::thread_api::sleep_ms(seconds as u64 * 1000);
700 }
701
702 pub(crate) fn usleep(microseconds: u32) {
704 crate::thread_api::sleep_ms(microseconds as u64 / 1000);
705 }
706}
707
708pub(crate) mod error {
710 pub const EPERM: i32 = 1; pub const ENOENT: i32 = 2; pub const ESRCH: i32 = 3; pub const EINTR: i32 = 4; pub const EIO: i32 = 5; pub const ENXIO: i32 = 6; pub const E2BIG: i32 = 7; pub const ENOEXEC: i32 = 8; pub const EBADF: i32 = 9; pub const ECHILD: i32 = 10; pub const EAGAIN: i32 = 11; pub const ENOMEM: i32 = 12; pub const EACCES: i32 = 13; pub const EFAULT: i32 = 14; pub const EBUSY: i32 = 16; pub const EEXIST: i32 = 17; pub const ENODEV: i32 = 19; pub const ENOTDIR: i32 = 20; pub const EISDIR: i32 = 21; pub const EINVAL: i32 = 22; pub const EMFILE: i32 = 24; pub const ENOSPC: i32 = 28; pub const EROFS: i32 = 30; use core::sync::atomic::{AtomicI32, Ordering};
736
737 static ERRNO: AtomicI32 = AtomicI32::new(0);
738
739 pub(crate) fn get_errno() -> i32 {
741 ERRNO.load(Ordering::Relaxed)
742 }
743
744 pub(crate) fn set_errno(errno: i32) {
746 ERRNO.store(errno, Ordering::Relaxed);
747 }
748
749 pub(crate) fn strerror(errno: i32) -> &'static str {
751 match errno {
752 EPERM => "Operation not permitted",
753 ENOENT => "No such file or directory",
754 ESRCH => "No such process",
755 EINTR => "Interrupted system call",
756 EIO => "I/O error",
757 ENXIO => "No such device or address",
758 E2BIG => "Argument list too long",
759 ENOEXEC => "Exec format error",
760 EBADF => "Bad file number",
761 ECHILD => "No child processes",
762 EAGAIN => "Try again",
763 ENOMEM => "Out of memory",
764 EACCES => "Permission denied",
765 EFAULT => "Bad address",
766 EBUSY => "Device or resource busy",
767 EEXIST => "File exists",
768 ENODEV => "No such device",
769 ENOTDIR => "Not a directory",
770 EISDIR => "Is a directory",
771 EINVAL => "Invalid argument",
772 EMFILE => "Too many open files",
773 ENOSPC => "No space left on device",
774 EROFS => "Read-only file system",
775 _ => "Unknown error",
776 }
777 }
778}
779
780pub(crate) mod random {
782 use core::sync::atomic::{AtomicU32, Ordering};
783
784 static SEED: AtomicU32 = AtomicU32::new(1);
785
786 pub(crate) fn srand(seed: u32) {
788 SEED.store(seed, Ordering::Relaxed);
789 }
790
791 pub(crate) fn rand() -> i32 {
793 let new_seed = SEED
794 .fetch_update(Ordering::Relaxed, Ordering::Relaxed, |s| {
795 Some(s.wrapping_mul(1103515245).wrapping_add(12345))
796 })
797 .unwrap_or(1);
798 let result = new_seed.wrapping_mul(1103515245).wrapping_add(12345);
799 (result / 65536) as i32 % 32768
800 }
801
802 pub(crate) fn rand_range(min: i32, max: i32) -> i32 {
804 if min >= max {
805 return min;
806 }
807 min + (rand() % (max - min))
808 }
809}
810
811pub(crate) mod system {
813 use alloc::{collections::BTreeMap, string::String};
814
815 use spin::RwLock;
816
817 static ENVIRONMENT: RwLock<Option<BTreeMap<String, String>>> = RwLock::new(None);
819
820 pub(crate) fn init_environment() {
822 let mut env = BTreeMap::new();
823 env.insert(
824 String::from("PATH"),
825 String::from("/bin:/usr/bin:/sbin:/usr/sbin"),
826 );
827 env.insert(String::from("HOME"), String::from("/root"));
828 env.insert(String::from("USER"), String::from("root"));
829 env.insert(String::from("SHELL"), String::from("/bin/vsh"));
830 env.insert(String::from("TERM"), String::from("vt100"));
831 env.insert(String::from("PWD"), String::from("/"));
832 env.insert(String::from("LANG"), String::from("C"));
833 *ENVIRONMENT.write() = Some(env);
834 }
835
836 #[derive(Debug)]
838 pub struct SystemInfo {
839 pub os_name: &'static str,
840 pub version: &'static str,
841 pub architecture: &'static str,
842 pub total_memory: u64,
843 pub available_memory: u64,
844 pub cpu_count: u32,
845 pub uptime: u64,
846 }
847
848 pub(crate) fn get_system_info() -> SystemInfo {
850 SystemInfo {
851 os_name: "VeridianOS",
852 version: "0.2.1",
853 architecture: if cfg!(target_arch = "x86_64") {
854 "x86_64"
855 } else if cfg!(target_arch = "aarch64") {
856 "aarch64"
857 } else if cfg!(target_arch = "riscv64") {
858 "riscv64"
859 } else {
860 "unknown"
861 },
862 total_memory: 1024 * 1024 * 1024, available_memory: 512 * 1024 * 1024, cpu_count: 1,
865 uptime: 0,
866 }
867 }
868
869 pub(crate) fn getenv(name: &str) -> Option<String> {
874 let env_guard = ENVIRONMENT.read();
875 if let Some(ref env) = *env_guard {
876 env.get(name).cloned()
877 } else {
878 match name {
880 "PATH" => Some(String::from("/bin:/usr/bin")),
881 "HOME" => Some(String::from("/root")),
882 "USER" => Some(String::from("root")),
883 _ => None,
884 }
885 }
886 }
887
888 pub(crate) fn setenv(name: &str, value: &str) -> i32 {
893 let mut env_guard = ENVIRONMENT.write();
894 if env_guard.is_none() {
895 *env_guard = Some(BTreeMap::new());
897 }
898
899 if let Some(ref mut env) = *env_guard {
900 env.insert(String::from(name), String::from(value));
901 0
902 } else {
903 -1
904 }
905 }
906
907 pub(crate) fn unsetenv(name: &str) -> i32 {
912 let mut env_guard = ENVIRONMENT.write();
913 if let Some(ref mut env) = *env_guard {
914 if env.remove(name).is_some() {
915 0
916 } else {
917 -1
918 }
919 } else {
920 -1
921 }
922 }
923
924 pub(crate) fn get_all_env() -> BTreeMap<String, String> {
928 let env_guard = ENVIRONMENT.read();
929 if let Some(ref env) = *env_guard {
930 env.clone()
931 } else {
932 BTreeMap::new()
933 }
934 }
935}
936
937pub fn init() {
939 system::init_environment();
941 crate::println!("[STDLIB] Standard library foundation initialized");
942}