#include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include extern long syscall(long nr, long a0, long a1, long a2); long k_handle_syscall(long nr, long a0, long a1, long a2) { return syscall(nr, a0, a1, a2); } // Globals char **environ = NULL; // Safe Userland Allocator (Bump Pointer with Headers) #define HEAP_SIZE (32 * 1024 * 1024) static char heap_memory[HEAP_SIZE]; static size_t heap_ptr = 0; typedef struct { size_t size; size_t magic; } BlockHeader; #define ALLOC_MAGIC 0xCAFEBABE void *malloc(size_t size) { if (size == 0) return NULL; // Align total size (header + data) to 16 bytes size_t required = size + sizeof(BlockHeader); size_t aligned_total = (required + 15) & ~15; if (heap_ptr + aligned_total > HEAP_SIZE) return NULL; BlockHeader *hdr = (BlockHeader *)&heap_memory[heap_ptr]; hdr->size = size; hdr->magic = ALLOC_MAGIC; void *ptr = (void *)((char *)hdr + sizeof(BlockHeader)); heap_ptr += aligned_total; return ptr; } void free(void *ptr) { // No-op bump allocator } void *realloc(void *ptr, size_t size) { if (!ptr) return malloc(size); if (size == 0) return NULL; // Standard says free.. or return NULL? mksh expects NULL or ptr. // Get header BlockHeader *hdr = (BlockHeader *)((char *)ptr - sizeof(BlockHeader)); if (hdr->magic != ALLOC_MAGIC) { // Corrupted ptr? return NULL or fail. return NULL; } // Optimization: If it's the LAST block, simple extend? (Not implemented for simplicity) void *new_ptr = malloc(size); if (!new_ptr) return NULL; size_t copy_size = (hdr->size < size) ? hdr->size : size; memcpy(new_ptr, ptr, copy_size); return new_ptr; } void *calloc(size_t nmemb, size_t size) { size_t total = nmemb * size; void *ptr = malloc(total); if (ptr) memset(ptr, 0, total); return ptr; } // Stubs int fstat(int fd, struct stat *buf) { return 0; } int lstat(const char *path, struct stat *buf) { return 0; } int stat(const char *path, struct stat *buf) { return 0; } int sigemptyset(sigset_t *set) { return 0; } int sigaddset(sigset_t *set, int signum) { return 0; } int sigprocmask(int how, const sigset_t *set, sigset_t *oldset) { return 0; } int sigaction(int signum, const struct sigaction *act, struct sigaction *oldact) { if (oldact) { // Initialize to safe defaults - no handler installed memset(oldact, 0, sizeof(struct sigaction)); oldact->sa_handler = SIG_DFL; // Default handler } return 0; } int sigsuspend(const sigset_t *mask) { return -1; } int kill(pid_t pid, int sig) { return 0; } unsigned int alarm(unsigned int seconds) { return 0; } off_t lseek(int fd, off_t offset, int whence) { return 0; } // ssize_t read(int fd, void *buf, size_t count) { return 0; } // In libc.nim // ssize_t write(int fd, const void *buf, size_t count) { return 0; } // In clib.c // int open(const char *pathname, int flags, ...) { return -1; } // In libc.nim // int close(int fd) { return 0; } // In libc.nim int pipe(int pipefd[2]) { return -1; } int dup2(int oldfd, int newfd) { return newfd; } extern void console_write(const void* p, unsigned long len); static void ksh_debug(const char* s) { console_write(s, (unsigned long)strlen(s)); } int fcntl(int fd, int cmd, ...) { ksh_debug("[mksh] fcntl called\n"); va_list args; va_start(args, cmd); long arg = va_arg(args, long); va_end(args); int res = (int)syscall(0x206, (long)fd, (long)cmd, arg); ksh_debug("[mksh] fcntl returning\n"); return res; } int ioctl(int fd, unsigned long request, ...) { return 0; } // int execve(const char *pathname, char *const argv[], char *const envp[]) { return -1; } // In clib.c // pid_t fork(void) { return -1; } // In clib.c pid_t waitpid(pid_t pid, int *status, int options) { return -1; } pid_t getpid(void) { return 1; } pid_t getppid(void) { return 0; } uid_t getuid(void) { return 0; } uid_t geteuid(void) { return 0; } gid_t getgid(void) { return 0; } gid_t getegid(void) { return 0; } pid_t getpgrp(void) { return 1; } int setuid(uid_t uid) { return 0; } int setgid(gid_t gid) { return 0; } int seteuid(uid_t uid) { return 0; } int setegid(gid_t gid) { return 0; } int setpgid(pid_t pid, pid_t pgid) { return 0; } int tcgetattr(int fd, struct termios *termios_p) { if (termios_p) { // Initialize with safe defaults (using numeric values to avoid missing constants) memset(termios_p, 0, sizeof(struct termios)); // Set basic flags for canonical mode termios_p->c_iflag = 0x0100; // ICRNL termios_p->c_oflag = 0x0001 | 0x0004; // OPOST | ONLCR termios_p->c_cflag = 0x0030 | 0x0080; // CS8 | CREAD termios_p->c_lflag = ISIG | ICANON | ECHO; // These should be defined // Set control characters termios_p->c_cc[VINTR] = 3; // Ctrl-C termios_p->c_cc[VQUIT] = 28; // Ctrl-backslash termios_p->c_cc[VERASE] = 127; // DEL termios_p->c_cc[VKILL] = 21; // Ctrl-U termios_p->c_cc[VEOF] = 4; // Ctrl-D termios_p->c_cc[VMIN] = 1; termios_p->c_cc[VTIME] = 0; } return 0; } int tcsetattr(int fd, int optional_actions, const struct termios *termios_p) { return 0; } pid_t tcgetpgrp(int fd) { return 1; } int tcsetpgrp(int fd, pid_t pgrp) { return 0; } int isatty(int fd) { return 1; } int access(const char *pathname, int mode) { return -1; } int unlink(const char *pathname) { return -1; } int rename(const char *oldpath, const char *newpath) { return -1; } int rmdir(const char *pathname) { return -1; } int chdir(const char *path) { return 0; } char *getcwd(char *buf, size_t size) { if (size > 1) { buf[0]='/'; buf[1]='\0'; return buf; } return NULL; } int mkdir(const char *pathname, mode_t mode) { return -1; } time_t time(time_t *tloc) { return 0; } clock_t times(struct tms *buf) { return 0; } unsigned int sleep(unsigned int seconds) { return 0; } DIR *opendir(const char *name) { return NULL; } struct dirent *readdir(DIR *dirp) { return NULL; } int closedir(DIR *dirp) { return 0; } ssize_t readlink(const char *pathname, char *buf, size_t objsiz) { return -1; } struct passwd *getpwnam(const char *name) { return NULL; } // qsort void qsort(void *base, size_t nmemb, size_t size, int (*compar)(const void *, const void *)) { if (nmemb < 2 || size == 0) return; char *b = (char *)base; char *tmp = malloc(size); for (size_t i = 0; i < nmemb - 1; i++) { for (size_t j = 0; j < nmemb - i - 1; j++) { if (compar(b + j * size, b + (j + 1) * size) > 0) { // swap memcpy(tmp, b + j * size, size); memcpy(b + j * size, b + (j + 1) * size, size); memcpy(b + (j + 1) * size, tmp, size); } } } free(tmp); } // strstr char *strstr(const char *haystack, const char *needle) { if (!*needle) return (char *)haystack; for (char *p = (char *)haystack; *p; p++) { if (*p == *needle) { char *h = p, *n = (char *)needle; while (*h && *n && *h == *n) { h++; n++; } if (!*n) return p; } } return NULL; } mode_t umask(mode_t mask) { return 0; } int c_ulimit(const char **wp) { return 0; } int setjmp(jmp_buf env) { __asm__ volatile ( "sd ra, 0(%0)\n" "sd sp, 8(%0)\n" "sd s0, 16(%0)\n" "sd s1, 24(%0)\n" "sd s2, 32(%0)\n" "sd s3, 40(%0)\n" "sd s4, 48(%0)\n" "sd s5, 56(%0)\n" "sd s6, 64(%0)\n" "sd s7, 72(%0)\n" "sd s8, 80(%0)\n" "sd s9, 88(%0)\n" "sd s10, 96(%0)\n" "sd s11, 104(%0)\n" "li a0, 0\n" : : "r"(env) : "memory", "a0" ); return 0; } void longjmp(jmp_buf env, int val) { __asm__ volatile ( "ld ra, 0(%0)\n" "ld sp, 8(%0)\n" "ld s0, 16(%0)\n" "ld s1, 24(%0)\n" "ld s2, 32(%0)\n" "ld s3, 40(%0)\n" "ld s4, 48(%0)\n" "ld s5, 56(%0)\n" "ld s6, 64(%0)\n" "ld s7, 72(%0)\n" "ld s8, 80(%0)\n" "ld s9, 88(%0)\n" "ld s10, 96(%0)\n" "ld s11, 104(%0)\n" "mv a0, %1\n" "seqz t0, a0\n" "add a0, a0, t0\n" : : "r"(env), "r"(val) : "memory", "a0", "t0" ); // Note: longjmp should not return. In this freestanding env, // the asm above ends with registers restored and we jump back. // However, to be extra safe we could add a ret at the end of asm. __asm__ volatile("ret"); } void exit(int status) { syscall(0x01, (long)status, 0, 0); while(1); }