285 lines
8.8 KiB
C
285 lines
8.8 KiB
C
#include <sys/types.h>
|
|
#include <sys/stat.h>
|
|
#include <sys/time.h>
|
|
#include <sys/times.h>
|
|
#include <sys/wait.h>
|
|
#include <fcntl.h>
|
|
#include <unistd.h>
|
|
#include <signal.h>
|
|
#include <stdio.h>
|
|
#include <stdlib.h>
|
|
#include <dirent.h>
|
|
#include <errno.h>
|
|
#include <string.h>
|
|
#include <setjmp.h>
|
|
#include <termios.h>
|
|
#include <stdarg.h>
|
|
|
|
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);
|
|
}
|