#include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include int __cervus_argc; char **__cervus_argv; int __cervus_errno = 0; static long __sys_ret(long r) { if (r < 0 && r > -4096) { __cervus_errno = (int)-r; return -1; } return r; } #define CERVUS_PATH_MAX 512 static char __cervus_cwd[CERVUS_PATH_MAX]; static int __cervus_cwd_inited = 0; static const char *__cervus_get_cwd(void) { if (!__cervus_cwd_inited) { const char *c = get_cwd_flag(__cervus_argc, __cervus_argv); if (!c || !*c) c = "/"; size_t n = strlen(c); if (n >= sizeof(__cervus_cwd)) n = sizeof(__cervus_cwd) - 1; memcpy(__cervus_cwd, c, n); __cervus_cwd[n] = '\0'; __cervus_cwd_inited = 1; } return __cervus_cwd; } static const char *__cervus_resolve(const char *path, char *buf, size_t bufsz) { if (!path) return path; if (path[0] == '/') return path; resolve_path(__cervus_get_cwd(), path, buf, bufsz); return buf; } ssize_t read(int fd, void *buf, size_t n) { return (ssize_t)__sys_ret(syscall3(SYS_READ, fd, buf, n)); } ssize_t write(int fd, const void *buf, size_t n) { return (ssize_t)__sys_ret(syscall3(SYS_WRITE, fd, buf, n)); } int close(int fd) { return (int)__sys_ret(syscall1(SYS_CLOSE, fd)); } off_t lseek(int fd, off_t off, int whence) { return (off_t)__sys_ret(syscall3(SYS_SEEK, fd, (uint64_t)off, whence)); } int dup(int fd) { return (int)__sys_ret(syscall1(SYS_DUP, fd)); } int dup2(int oldfd, int newfd) { return (int)__sys_ret(syscall2(SYS_DUP2, oldfd, newfd)); } int pipe(int fds[2]) { return (int)__sys_ret(syscall1(SYS_PIPE, fds)); } int ioctl(int fd, unsigned long request, ...) { va_list ap; va_start(ap, request); void *arg = va_arg(ap, void *); va_end(ap); return (int)__sys_ret(syscall3(SYS_IOCTL, fd, request, arg)); } int isatty(int fd) { struct winsize ws; long r = syscall3(SYS_IOCTL, fd, TIOCGWINSZ, &ws); if (r < 0) { __cervus_errno = (int)-r; return 0; } return 1; } int unlink(const char *path) { char abs[CERVUS_PATH_MAX]; path = __cervus_resolve(path, abs, sizeof(abs)); return (int)__sys_ret(syscall1(SYS_UNLINK, path)); } int rmdir(const char *path) { char abs[CERVUS_PATH_MAX]; path = __cervus_resolve(path, abs, sizeof(abs)); return (int)__sys_ret(syscall1(SYS_RMDIR, path)); } pid_t getpid(void) { return (pid_t)syscall0(SYS_GETPID); } pid_t getppid(void) { return (pid_t)syscall0(SYS_GETPPID); } uid_t getuid(void) { return (uid_t)syscall0(SYS_GETUID); } gid_t getgid(void) { return (gid_t)syscall0(SYS_GETGID); } int setuid(uid_t u) { return (int)__sys_ret(syscall1(SYS_SETUID, u)); } int setgid(gid_t g) { return (int)__sys_ret(syscall1(SYS_SETGID, g)); } pid_t fork(void) { return (pid_t)__sys_ret(syscall0(SYS_FORK)); } int execve(const char *path, char *const argv[], char *const envp[]) { char abs[CERVUS_PATH_MAX]; path = __cervus_resolve(path, abs, sizeof(abs)); return (int)__sys_ret(syscall3(SYS_EXECVE, path, argv, envp)); } int execv(const char *path, char *const argv[]) { char *empty[] = { NULL }; return execve(path, argv, empty); } int execvp(const char *file, char *const argv[]) { if (!file || !*file) { __cervus_errno = ENOENT; return -1; } int has_slash = 0; for (const char *p = file; *p; p++) if (*p == '/') { has_slash = 1; break; } if (has_slash) return execve(file, argv, NULL); const char *path = getenv("PATH"); if (!path || !*path) path = "/bin:/apps"; char buf[512]; const char *p = path; while (*p) { const char *colon = p; while (*colon && *colon != ':') colon++; size_t dlen = (size_t)(colon - p); size_t flen = strlen(file); if (dlen + 1 + flen + 1 <= sizeof(buf)) { memcpy(buf, p, dlen); buf[dlen] = '/'; memcpy(buf + dlen + 1, file, flen); buf[dlen + 1 + flen] = '\0'; execve(buf, argv, NULL); } p = colon; if (*p == ':') p++; } __cervus_errno = ENOENT; return -1; } void _exit(int status) { syscall1(SYS_EXIT, status); __builtin_unreachable(); } unsigned int sleep(unsigned int sec) { cervus_nanosleep((uint64_t)sec * 1000000000ULL); return 0; } int usleep(unsigned int usec) { return cervus_nanosleep((uint64_t)usec * 1000ULL); } void sched_yield_cervus(void) { syscall0(SYS_YIELD); } char *getcwd(char *buf, size_t size) { if (!buf || size < 2) { __cervus_errno = EINVAL; return NULL; } const char *c = __cervus_get_cwd(); size_t n = strlen(c); if (n + 1 > size) { __cervus_errno = ERANGE; return NULL; } memcpy(buf, c, n + 1); return buf; } int chdir(const char *path) { if (!path || !*path) { __cervus_errno = ENOENT; return -1; } char abs[CERVUS_PATH_MAX]; const char *p = __cervus_resolve(path, abs, sizeof(abs)); struct stat st; if ((int)__sys_ret(syscall2(SYS_STAT, p, &st)) < 0) return -1; if (!S_ISDIR(st.st_mode)) { __cervus_errno = ENOTDIR; return -1; } size_t n = strlen(p); if (n >= sizeof(__cervus_cwd)) { __cervus_errno = ENAMETOOLONG; return -1; } memcpy(__cervus_cwd, p, n + 1); __cervus_cwd_inited = 1; return 0; } void *sbrk(intptr_t incr) { uintptr_t cur = (uintptr_t)syscall1(SYS_BRK, 0); if (incr == 0) return (void *)cur; uintptr_t nw = (uintptr_t)syscall1(SYS_BRK, cur + (uintptr_t)incr); if (nw != cur + (uintptr_t)incr) { __cervus_errno = ENOMEM; return (void *)-1; } return (void *)cur; } int brk(void *addr) { uintptr_t r = (uintptr_t)syscall1(SYS_BRK, (uintptr_t)addr); if (r != (uintptr_t)addr) { __cervus_errno = ENOMEM; return -1; } return 0; } int open(const char *path, int flags, ...) { mode_t mode = 0; if (flags & O_CREAT) { va_list ap; va_start(ap, flags); mode = va_arg(ap, mode_t); va_end(ap); } char abs[CERVUS_PATH_MAX]; path = __cervus_resolve(path, abs, sizeof(abs)); return (int)__sys_ret(syscall3(SYS_OPEN, path, flags, mode)); } int creat(const char *path, mode_t mode) { return open(path, O_WRONLY | O_CREAT | O_TRUNC, mode); } int fcntl(int fd, int cmd, ...) { va_list ap; va_start(ap, cmd); long arg = va_arg(ap, long); va_end(ap); return (int)__sys_ret(syscall3(SYS_FCNTL, fd, cmd, arg)); } int stat(const char *path, struct stat *out) { char abs[CERVUS_PATH_MAX]; path = __cervus_resolve(path, abs, sizeof(abs)); return (int)__sys_ret(syscall2(SYS_STAT, path, out)); } int fstat(int fd, struct stat *out) { return (int)__sys_ret(syscall2(SYS_FSTAT, fd, out)); } int mkdir(const char *path, mode_t mode) { char abs[CERVUS_PATH_MAX]; path = __cervus_resolve(path, abs, sizeof(abs)); return (int)__sys_ret(syscall2(SYS_MKDIR, path, mode)); } int chmod(const char *path, mode_t mode) { (void)path; (void)mode; return 0; } int rename(const char *oldp, const char *newp) { char absa[CERVUS_PATH_MAX], absb[CERVUS_PATH_MAX]; oldp = __cervus_resolve(oldp, absa, sizeof(absa)); newp = __cervus_resolve(newp, absb, sizeof(absb)); return (int)__sys_ret(syscall2(SYS_RENAME, oldp, newp)); } void *mmap(void *a, size_t l, int p, int f, int fd, off_t o) { long r = syscall6(SYS_MMAP, a, l, p, f, fd, (uint64_t)o); if (r < 0 && r > -4096) { __cervus_errno = (int)-r; return MAP_FAILED; } return (void *)r; } int munmap(void *a, size_t l) { return (int)__sys_ret(syscall2(SYS_MUNMAP, a, l)); } pid_t waitpid(pid_t p, int *s, int f) { return (pid_t)__sys_ret(syscall3(SYS_WAIT, p, s, f)); } pid_t wait(int *s) { return waitpid(-1, s, 0); } ssize_t cervus_dbg_print(const char *b, size_t n) { return (ssize_t)syscall2(SYS_DBG_PRINT, b, n); } char *optarg = NULL; int optind = 1; int optopt = 0; int opterr = 1; static int __opt_subidx = 1; int getopt(int argc, char *const argv[], const char *optstring) { if (!optstring) optstring = ""; int colon_mode = (optstring[0] == ':'); const char *opts = colon_mode ? optstring + 1 : optstring; optarg = NULL; if (optind >= argc) return -1; char *cur = argv[optind]; if (!cur || cur[0] != '-' || cur[1] == '\0') return -1; if (cur[0] == '-' && cur[1] == '-' && cur[2] == '\0') { optind++; return -1; } char ch = cur[__opt_subidx]; if (ch == '\0') { optind++; __opt_subidx = 1; return getopt(argc, argv, optstring); } const char *pp = opts; while (*pp && *pp != ch) pp++; if (*pp == '\0' || ch == ':') { optopt = ch; if (opterr && !colon_mode) { const char *prog = argv[0] ? argv[0] : "?"; fprintf(stderr, "%s: invalid option -- '%c'\n", prog, ch); } __opt_subidx++; if (cur[__opt_subidx] == '\0') { optind++; __opt_subidx = 1; } return '?'; } if (pp[1] == ':') { if (cur[__opt_subidx + 1] != '\0') { optarg = &cur[__opt_subidx + 1]; optind++; __opt_subidx = 1; return ch; } if (optind + 1 >= argc) { optopt = ch; optind++; __opt_subidx = 1; if (opterr && !colon_mode) { const char *prog = argv[0] ? argv[0] : "?"; fprintf(stderr, "%s: option requires an argument -- '%c'\n", prog, ch); } return colon_mode ? ':' : '?'; } optarg = argv[optind + 1]; optind += 2; __opt_subidx = 1; return ch; } __opt_subidx++; if (cur[__opt_subidx] == '\0') { optind++; __opt_subidx = 1; } return ch; } int tcgetattr(int fd, struct termios *t) { if (!t) { __cervus_errno = EINVAL; return -1; } return (int)__sys_ret(syscall3(SYS_IOCTL, fd, TCGETS, t)); } int tcsetattr(int fd, int optional_actions, const struct termios *t) { if (!t) { __cervus_errno = EINVAL; return -1; } unsigned long req; switch (optional_actions) { case TCSADRAIN: req = TCSETSW; break; case TCSAFLUSH: req = TCSETSF; break; case TCSANOW: default: req = TCSETS; break; } return (int)__sys_ret(syscall3(SYS_IOCTL, fd, req, t)); } int cervus_task_info(pid_t p, cervus_task_info_t *o) { return (int)__sys_ret(syscall2(SYS_TASK_INFO, p, o)); } int cervus_task_kill(pid_t p) { return (int)__sys_ret(syscall1(SYS_TASK_KILL, p)); } uint64_t cervus_cap_get(void) { return (uint64_t)syscall0(SYS_CAP_GET); } int cervus_cap_drop(uint64_t m) { return (int)__sys_ret(syscall1(SYS_CAP_DROP, m)); } int cervus_meminfo(cervus_meminfo_t *m) { return (int)__sys_ret(syscall1(SYS_MEMINFO, m)); } uint64_t cervus_uptime_ns(void) { return (uint64_t)syscall0(SYS_UPTIME); } int cervus_clock_gettime(int id, cervus_timespec_t *t){ return (int)__sys_ret(syscall2(SYS_CLOCK_GET, id, t)); } int cervus_nanosleep(uint64_t ns) { return (int)__sys_ret(syscall1(SYS_SLEEP_NS, ns)); } int cervus_shutdown(void) { return (int)__sys_ret(syscall0(SYS_SHUTDOWN)); } int cervus_reboot(void) { return (int)__sys_ret(syscall0(SYS_REBOOT)); } int cervus_disk_info(int i, cervus_disk_info_t *o) { return (int)__sys_ret(syscall2(SYS_DISK_INFO, (uint64_t)i, o)); } int cervus_disk_mount(const char *d, const char *p) { return (int)__sys_ret(syscall2(SYS_DISK_MOUNT, d, p)); } int cervus_disk_umount(const char *p) { return (int)__sys_ret(syscall1(SYS_DISK_UMOUNT, p)); } int cervus_disk_format(const char *d, const char *l) { return (int)__sys_ret(syscall2(SYS_DISK_FORMAT, d, l)); } int cervus_disk_mkfs_fat32(const char *d, const char *l) { return (int)__sys_ret(syscall2(SYS_DISK_MKFS_FAT32, d, l)); } int cervus_disk_partition(const char *d, const cervus_mbr_part_t *s, uint64_t n) { return (int)__sys_ret(syscall3(SYS_DISK_PARTITION, d, s, n)); } int cervus_disk_read_raw(const char *d, uint64_t lba, uint64_t c, void *b) { return (int)__sys_ret(syscall4(SYS_DISK_READ_RAW, d, lba, c, b)); } int cervus_disk_write_raw(const char *d, uint64_t lba, uint64_t c, const void *b){ return (int)__sys_ret(syscall4(SYS_DISK_WRITE_RAW, d, lba, c, b)); } long cervus_disk_list_parts(cervus_part_info_t *o, int m) { return __sys_ret(syscall2(SYS_DISK_LIST_PARTS, o, m)); } long cervus_disk_bios_install(const char *d, const void *sd, uint32_t ss) { return __sys_ret(syscall3(SYS_DISK_BIOS_INSTALL, d, sd, ss)); } long cervus_list_mounts(cervus_mount_info_t *o, int m) { return __sys_ret(syscall2(SYS_LIST_MOUNTS, o, m)); } long cervus_statvfs(const char *p, cervus_statvfs_t *o) { return __sys_ret(syscall2(SYS_STATVFS, p, o)); } uint32_t cervus_ioport_read(uint16_t p, int w) { return (uint32_t)syscall2(SYS_IOPORT_READ, p, w); } int cervus_ioport_write(uint16_t p, int w, uint32_t v) { return (int)__sys_ret(syscall3(SYS_IOPORT_WRITE, p, w, v)); } void __cervus_assert_fail(const char *expr, const char *file, int line, const char *func) { printf("assertion failed: %s (%s:%d, %s)\n", expr ? expr : "(null)", file ? file : "(null)", line, func ? func : "(null)"); syscall1(SYS_EXIT, 134); for (;;) { } } #define _CERVUS_FILT_MAX 128 char *__cervus_filtered_argv[_CERVUS_FILT_MAX + 1]; int __cervus_filter_args(int argc, char **argv) { int out = 0; for (int i = 0; i < argc && out < _CERVUS_FILT_MAX; i++) { const char *a = argv[i]; if (i > 0 && a && a[0] == '-' && a[1] == '-' && ((a[2]=='c' && a[3]=='w' && a[4]=='d' && a[5]=='=') || (a[2]=='e' && a[3]=='n' && a[4]=='v' && a[5]==':'))) { continue; } __cervus_filtered_argv[out++] = (char *)a; } __cervus_filtered_argv[out] = NULL; return out; }