#include "uart_console.h"
#include "uaccess.h"
+#include "errno.h"
+#include "stat.h"
+
#include "hal/cpu.h"
#include <stddef.h>
uint32_t flags;
};
+static int stat_from_node(const fs_node_t* node, struct stat* st) {
+ if (!node || !st) return -EFAULT;
+
+ st->st_ino = node->inode;
+ st->st_nlink = 1;
+ st->st_size = node->length;
+
+ uint32_t mode = 0;
+ if (node->flags == FS_DIRECTORY) mode |= S_IFDIR;
+ else if (node->flags == FS_CHARDEVICE) mode |= S_IFCHR;
+ else mode |= S_IFREG;
+ st->st_mode = mode;
+ return 0;
+}
+
static int fd_alloc(struct file* f) {
if (!current_process || !f) return -1;
return 0;
}
+static int syscall_stat_impl(const char* user_path, struct stat* user_st) {
+ if (!user_path || !user_st) return -EFAULT;
+ if (user_range_ok(user_st, sizeof(*user_st)) == 0) return -EFAULT;
+
+ char path[128];
+ for (size_t i = 0; i < sizeof(path); i++) {
+ if (copy_from_user(&path[i], &user_path[i], 1) < 0) {
+ return -EFAULT;
+ }
+ if (path[i] == 0) break;
+ if (i + 1 == sizeof(path)) {
+ path[sizeof(path) - 1] = 0;
+ break;
+ }
+ }
+
+ fs_node_t* node = vfs_lookup(path);
+ if (!node) return -ENOENT;
+
+ struct stat st;
+ int rc = stat_from_node(node, &st);
+ if (rc < 0) return rc;
+ if (copy_to_user(user_st, &st, sizeof(st)) < 0) return -EFAULT;
+ return 0;
+}
+
+static int syscall_fstat_impl(int fd, struct stat* user_st) {
+ if (!user_st) return -EFAULT;
+ if (user_range_ok(user_st, sizeof(*user_st)) == 0) return -EFAULT;
+
+ struct file* f = fd_get(fd);
+ if (!f || !f->node) return -EBADF;
+
+ struct stat st;
+ int rc = stat_from_node(f->node, &st);
+ if (rc < 0) return rc;
+ if (copy_to_user(user_st, &st, sizeof(st)) < 0) return -EFAULT;
+ return 0;
+}
+
+static int syscall_lseek_impl(int fd, int32_t offset, int whence) {
+ if (fd == 0 || fd == 1 || fd == 2) return -ESPIPE;
+
+ struct file* f = fd_get(fd);
+ if (!f || !f->node) return -EBADF;
+ if (f->node->flags != FS_FILE) return -ESPIPE;
+
+ int64_t base = 0;
+ if (whence == 0) {
+ base = 0;
+ } else if (whence == 1) {
+ base = (int64_t)f->offset;
+ } else if (whence == 2) {
+ base = (int64_t)f->node->length;
+ } else {
+ return -EINVAL;
+ }
+
+ int64_t noff = base + (int64_t)offset;
+ if (noff < 0) return -EINVAL;
+ if (noff > (int64_t)f->node->length) return -EINVAL;
+
+ f->offset = (uint32_t)noff;
+ return (int)f->offset;
+}
+
static int syscall_open_impl(const char* user_path, uint32_t flags) {
(void)flags;
if (!user_path) return -1;
fs_node_t* node = vfs_lookup(path);
if (!node) return -1;
- if ((node->flags & FS_FILE) == 0) return -1;
+ if (node->flags != FS_FILE) return -1;
struct file* f = (struct file*)kmalloc(sizeof(*f));
if (!f) return -1;
return;
}
+ if (syscall_no == SYSCALL_LSEEK) {
+ int fd = (int)regs->ebx;
+ int32_t off = (int32_t)regs->ecx;
+ int whence = (int)regs->edx;
+ regs->eax = (uint32_t)syscall_lseek_impl(fd, off, whence);
+ return;
+ }
+
+ if (syscall_no == SYSCALL_FSTAT) {
+ int fd = (int)regs->ebx;
+ struct stat* st = (struct stat*)regs->ecx;
+ regs->eax = (uint32_t)syscall_fstat_impl(fd, st);
+ return;
+ }
+
+ if (syscall_no == SYSCALL_STAT) {
+ const char* path = (const char*)regs->ebx;
+ struct stat* st = (struct stat*)regs->ecx;
+ regs->eax = (uint32_t)syscall_stat_impl(path, st);
+ return;
+ }
+
regs->eax = (uint32_t)-1;
}
SYSCALL_CLOSE = 6,
SYSCALL_WAITPID = 7,
SYSCALL_SPAWN = 8,
+ SYSCALL_LSEEK = 9,
+ SYSCALL_FSTAT = 10,
+ SYSCALL_STAT = 11,
+};
+
+enum {
+ SEEK_SET = 0,
+ SEEK_CUR = 1,
+ SEEK_END = 2,
+};
+
+#define S_IFMT 0170000
+#define S_IFREG 0100000
+
+struct stat {
+ uint32_t st_ino;
+ uint32_t st_mode;
+ uint32_t st_nlink;
+ uint32_t st_size;
};
static int sys_write(int fd, const void* buf, uint32_t len) {
return ret;
}
+static int sys_lseek(int fd, int32_t offset, int whence) {
+ int ret;
+ __asm__ volatile(
+ "int $0x80"
+ : "=a"(ret)
+ : "a"(SYSCALL_LSEEK), "b"(fd), "c"(offset), "d"(whence)
+ : "memory"
+ );
+ return ret;
+}
+
+static int sys_fstat(int fd, struct stat* st) {
+ int ret;
+ __asm__ volatile(
+ "int $0x80"
+ : "=a"(ret)
+ : "a"(SYSCALL_FSTAT), "b"(fd), "c"(st)
+ : "memory"
+ );
+ return ret;
+}
+
+static int sys_stat(const char* path, struct stat* st) {
+ int ret;
+ __asm__ volatile(
+ "int $0x80"
+ : "=a"(ret)
+ : "a"(SYSCALL_STAT), "b"(path), "c"(st)
+ : "memory"
+ );
+ return ret;
+}
+
__attribute__((noreturn)) static void sys_exit(int code) {
__asm__ volatile(
"int $0x80\n"
static const char path[] = "/bin/init.elf";
int fd = sys_open(path, 0);
if (fd < 0) {
- static const char emsg[] = "[init] open(/bin/init.elf) failed\n";
- (void)sys_write(1, emsg, (uint32_t)(sizeof(emsg) - 1));
+ sys_write(1, "[init] open failed\n", 18);
sys_exit(1);
}
uint8_t hdr[4];
int rd = sys_read(fd, hdr, (uint32_t)sizeof(hdr));
- (void)sys_close(fd);
+ if (sys_close(fd) < 0) {
+ sys_write(1, "[init] close failed\n", 19);
+ sys_exit(1);
+ }
if (rd == 4 && hdr[0] == 0x7F && hdr[1] == 'E' && hdr[2] == 'L' && hdr[3] == 'F') {
- static const char ok[] = "[init] open/read/close OK (ELF magic)\n";
- (void)sys_write(1, ok, (uint32_t)(sizeof(ok) - 1));
+ sys_write(1, "[init] open/read/close OK (ELF magic)\n",
+ (uint32_t)(sizeof("[init] open/read/close OK (ELF magic)\n") - 1));
} else {
- static const char bad[] = "[init] read failed or bad header\n";
- (void)sys_write(1, bad, (uint32_t)(sizeof(bad) - 1));
+ sys_write(1, "[init] read failed or bad header\n", 30);
+ sys_exit(1);
+ }
+
+ fd = sys_open("/bin/init.elf", 0);
+ if (fd < 0) {
+ sys_write(1, "[init] open2 failed\n", 19);
+ sys_exit(1);
}
+ struct stat st;
+ if (sys_fstat(fd, &st) < 0) {
+ sys_write(1, "[init] fstat failed\n", 19);
+ sys_exit(1);
+ }
+
+ if ((st.st_mode & S_IFMT) != S_IFREG || st.st_size == 0) {
+ sys_write(1, "[init] fstat bad\n", 16);
+ sys_exit(1);
+ }
+
+ if (sys_lseek(fd, 0, SEEK_SET) < 0) {
+ sys_write(1, "[init] lseek set failed\n", 24);
+ sys_exit(1);
+ }
+
+ uint8_t m2[4];
+ if (sys_read(fd, m2, 4) != 4) {
+ sys_write(1, "[init] read2 failed\n", 19);
+ sys_exit(1);
+ }
+ if (m2[0] != 0x7F || m2[1] != 'E' || m2[2] != 'L' || m2[3] != 'F') {
+ sys_write(1, "[init] lseek/read mismatch\n", 27);
+ sys_exit(1);
+ }
+
+ if (sys_close(fd) < 0) {
+ sys_write(1, "[init] close2 failed\n", 20);
+ sys_exit(1);
+ }
+
+ if (sys_stat("/bin/init.elf", &st) < 0) {
+ sys_write(1, "[init] stat failed\n", 18);
+ sys_exit(1);
+ }
+ if ((st.st_mode & S_IFMT) != S_IFREG || st.st_size == 0) {
+ sys_write(1, "[init] stat bad\n", 15);
+ sys_exit(1);
+ }
+
+ sys_write(1, "[init] lseek/stat/fstat OK\n", 27);
+
enum { NCHILD = 100 };
int children[NCHILD];
for (int i = 0; i < NCHILD; i++) {