#include "process.h"
#include "uart_console.h"
#include "uaccess.h"
+#include "utils.h"
#include "errno.h"
+#include "elf.h"
#include "stat.h"
+#include "vmm.h"
#include "hal/cpu.h"
fs_node_t* node;
uint32_t offset;
uint32_t flags;
+ uint32_t refcount;
};
+static int fd_alloc(struct file* f);
+static int fd_close(int fd);
+
+struct pipe_state {
+ uint8_t* buf;
+ uint32_t cap;
+ uint32_t rpos;
+ uint32_t wpos;
+ uint32_t count;
+ uint32_t readers;
+ uint32_t writers;
+};
+
+struct pipe_node {
+ fs_node_t node;
+ struct pipe_state* ps;
+ uint32_t is_read_end;
+};
+
+static uint32_t pipe_read(fs_node_t* n, uint32_t offset, uint32_t size, uint8_t* buffer) {
+ (void)offset;
+ struct pipe_node* pn = (struct pipe_node*)n;
+ if (!pn || !pn->ps || !buffer) return 0;
+ if (!pn->is_read_end) return 0;
+
+ struct pipe_state* ps = pn->ps;
+ if (size == 0) return 0;
+
+ uint32_t to_read = size;
+ if (to_read > ps->count) to_read = ps->count;
+
+ for (uint32_t i = 0; i < to_read; i++) {
+ buffer[i] = ps->buf[ps->rpos];
+ ps->rpos++;
+ if (ps->rpos == ps->cap) ps->rpos = 0;
+ }
+ ps->count -= to_read;
+ return to_read;
+}
+
+static uint32_t pipe_write(fs_node_t* n, uint32_t offset, uint32_t size, uint8_t* buffer) {
+ (void)offset;
+ struct pipe_node* pn = (struct pipe_node*)n;
+ if (!pn || !pn->ps || !buffer) return 0;
+ if (pn->is_read_end) return 0;
+
+ struct pipe_state* ps = pn->ps;
+ if (size == 0) return 0;
+ if (ps->readers == 0) return 0;
+
+ uint32_t free = ps->cap - ps->count;
+ uint32_t to_write = size;
+ if (to_write > free) to_write = free;
+
+ for (uint32_t i = 0; i < to_write; i++) {
+ ps->buf[ps->wpos] = buffer[i];
+ ps->wpos++;
+ if (ps->wpos == ps->cap) ps->wpos = 0;
+ }
+ ps->count += to_write;
+ return to_write;
+}
+
+static void pipe_close(fs_node_t* n) {
+ struct pipe_node* pn = (struct pipe_node*)n;
+ if (!pn || !pn->ps) {
+ if (pn) kfree(pn);
+ return;
+ }
+
+ if (pn->is_read_end) {
+ if (pn->ps->readers) pn->ps->readers--;
+ } else {
+ if (pn->ps->writers) pn->ps->writers--;
+ }
+
+ struct pipe_state* ps = pn->ps;
+ kfree(pn);
+
+ if (ps->readers == 0 && ps->writers == 0) {
+ if (ps->buf) kfree(ps->buf);
+ kfree(ps);
+ }
+}
+
+static int pipe_node_create(struct pipe_state* ps, int is_read_end, fs_node_t** out_node) {
+ if (!ps || !out_node) return -1;
+ struct pipe_node* pn = (struct pipe_node*)kmalloc(sizeof(*pn));
+ if (!pn) return -1;
+ memset(pn, 0, sizeof(*pn));
+
+ pn->ps = ps;
+ pn->is_read_end = is_read_end ? 1U : 0U;
+ pn->node.flags = FS_FILE;
+ pn->node.length = 0;
+ pn->node.open = NULL;
+ pn->node.finddir = NULL;
+ pn->node.close = pipe_close;
+ if (pn->is_read_end) {
+ strcpy(pn->node.name, "pipe:r");
+ pn->node.read = pipe_read;
+ pn->node.write = NULL;
+ ps->readers++;
+ } else {
+ strcpy(pn->node.name, "pipe:w");
+ pn->node.read = NULL;
+ pn->node.write = pipe_write;
+ ps->writers++;
+ }
+
+ *out_node = &pn->node;
+ return 0;
+}
+
+static int syscall_pipe_impl(int* user_fds) {
+ if (!user_fds) return -EFAULT;
+ if (user_range_ok(user_fds, sizeof(int) * 2) == 0) return -EFAULT;
+
+ struct pipe_state* ps = (struct pipe_state*)kmalloc(sizeof(*ps));
+ if (!ps) return -ENOMEM;
+ memset(ps, 0, sizeof(*ps));
+ ps->cap = 512;
+ ps->buf = (uint8_t*)kmalloc(ps->cap);
+ if (!ps->buf) {
+ kfree(ps);
+ return -ENOMEM;
+ }
+
+ fs_node_t* rnode = NULL;
+ fs_node_t* wnode = NULL;
+ if (pipe_node_create(ps, 1, &rnode) < 0 || pipe_node_create(ps, 0, &wnode) < 0) {
+ if (rnode) vfs_close(rnode);
+ if (wnode) vfs_close(wnode);
+ if (ps->buf) kfree(ps->buf);
+ kfree(ps);
+ return -ENOMEM;
+ }
+
+ struct file* rf = (struct file*)kmalloc(sizeof(*rf));
+ struct file* wf = (struct file*)kmalloc(sizeof(*wf));
+ if (!rf || !wf) {
+ if (rf) kfree(rf);
+ if (wf) kfree(wf);
+ vfs_close(rnode);
+ vfs_close(wnode);
+ return -ENOMEM;
+ }
+ memset(rf, 0, sizeof(*rf));
+ memset(wf, 0, sizeof(*wf));
+ rf->node = rnode;
+ rf->refcount = 1;
+ wf->node = wnode;
+ wf->refcount = 1;
+
+ int rfd = fd_alloc(rf);
+ if (rfd < 0) {
+ kfree(rf);
+ kfree(wf);
+ vfs_close(rnode);
+ vfs_close(wnode);
+ return -EMFILE;
+ }
+
+ int wfd = fd_alloc(wf);
+ if (wfd < 0) {
+ (void)fd_close(rfd);
+ kfree(wf);
+ vfs_close(wnode);
+ return -EMFILE;
+ }
+
+ int kfds[2];
+ kfds[0] = rfd;
+ kfds[1] = wfd;
+ if (copy_to_user(user_fds, kfds, sizeof(kfds)) < 0) {
+ (void)fd_close(rfd);
+ (void)fd_close(wfd);
+ return -EFAULT;
+ }
+
+ return 0;
+}
+
static int stat_from_node(const fs_node_t* node, struct stat* st) {
if (!node || !st) return -EFAULT;
return 0;
}
+static int fd_alloc_from(int start_fd, struct file* f) {
+ if (!current_process || !f) return -1;
+ if (start_fd < 0) start_fd = 0;
+ if (start_fd >= PROCESS_MAX_FILES) return -1;
+
+ for (int fd = start_fd; fd < PROCESS_MAX_FILES; fd++) {
+ if (current_process->files[fd] == NULL) {
+ current_process->files[fd] = f;
+ return fd;
+ }
+ }
+ return -1;
+}
+
static int fd_alloc(struct file* f) {
if (!current_process || !f) return -1;
struct file* f = current_process->files[fd];
if (!f) return -1;
current_process->files[fd] = NULL;
- kfree(f);
+
+ if (f->refcount > 0) {
+ f->refcount--;
+ }
+ if (f->refcount == 0) {
+ if (f->node) {
+ vfs_close(f->node);
+ }
+ kfree(f);
+ }
return 0;
}
+static int syscall_dup_impl(int oldfd) {
+ struct file* f = fd_get(oldfd);
+ if (!f) return -EBADF;
+ f->refcount++;
+ int newfd = fd_alloc_from(0, f);
+ if (newfd < 0) {
+ f->refcount--;
+ return -EMFILE;
+ }
+ return newfd;
+}
+
+static int syscall_execve_impl(struct registers* regs, const char* user_path, const char* const* user_argv, const char* const* user_envp) {
+ (void)user_argv;
+ (void)user_envp;
+ if (!regs || !user_path) 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;
+ }
+ }
+
+ uintptr_t entry = 0;
+ uintptr_t user_sp = 0;
+ uintptr_t new_as = 0;
+ if (elf32_load_user_from_initrd(path, &entry, &user_sp, &new_as) != 0) {
+ return -ENOENT;
+ }
+
+ uintptr_t old_as = current_process ? current_process->addr_space : 0;
+ if (!current_process) {
+ vmm_as_destroy(new_as);
+ return -EINVAL;
+ }
+
+ current_process->addr_space = new_as;
+ vmm_as_activate(new_as);
+
+ if (old_as && old_as != new_as) {
+ vmm_as_destroy(old_as);
+ }
+
+ regs->eip = (uint32_t)entry;
+ regs->useresp = (uint32_t)user_sp;
+ regs->eax = 0;
+ return 0;
+}
+
+static int syscall_dup2_impl(int oldfd, int newfd) {
+ if (newfd < 0 || newfd >= PROCESS_MAX_FILES) return -EBADF;
+ struct file* f = fd_get(oldfd);
+ if (!f) return -EBADF;
+ if (oldfd == newfd) return newfd;
+
+ if (current_process && current_process->files[newfd]) {
+ (void)fd_close(newfd);
+ }
+
+ f->refcount++;
+ current_process->files[newfd] = f;
+ return newfd;
+}
+
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;
f->node = node;
f->offset = 0;
f->flags = 0;
+ f->refcount = 1;
int fd = fd_alloc(f);
if (fd < 0) {
if (len > 1024 * 1024) return -1;
if (user_range_ok(user_buf, (size_t)len) == 0) return -1;
- if (fd == 0) {
+ if (fd == 0 && (!current_process || !current_process->files[0])) {
return tty_read(user_buf, len);
}
- if (fd == 1 || fd == 2) return -1;
+ if ((fd == 1 || fd == 2) && (!current_process || !current_process->files[fd])) return -1;
struct file* f = fd_get(fd);
if (!f || !f->node) return -1;
if (len > 1024 * 1024) return -EINVAL;
if (user_range_ok(user_buf, (size_t)len) == 0) return -EFAULT;
- if (fd == 1 || fd == 2) {
+ if ((fd == 1 || fd == 2) && (!current_process || !current_process->files[fd])) {
return tty_write((const char*)user_buf, len);
}
if (syscall_no == SYSCALL_EXIT) {
int status = (int)regs->ebx;
- for (int fd = 3; fd < PROCESS_MAX_FILES; fd++) {
+ for (int fd = 0; fd < PROCESS_MAX_FILES; fd++) {
if (current_process && current_process->files[fd]) {
(void)fd_close(fd);
}
return;
}
+ if (syscall_no == SYSCALL_DUP) {
+ int oldfd = (int)regs->ebx;
+ regs->eax = (uint32_t)syscall_dup_impl(oldfd);
+ return;
+ }
+
+ if (syscall_no == SYSCALL_DUP2) {
+ int oldfd = (int)regs->ebx;
+ int newfd = (int)regs->ecx;
+ regs->eax = (uint32_t)syscall_dup2_impl(oldfd, newfd);
+ return;
+ }
+
+ if (syscall_no == SYSCALL_PIPE) {
+ int* user_fds = (int*)regs->ebx;
+ regs->eax = (uint32_t)syscall_pipe_impl(user_fds);
+ return;
+ }
+
+ if (syscall_no == SYSCALL_EXECVE) {
+ const char* path = (const char*)regs->ebx;
+ const char* const* argv = (const char* const*)regs->ecx;
+ const char* const* envp = (const char* const*)regs->edx;
+ regs->eax = (uint32_t)syscall_execve_impl(regs, path, argv, envp);
+ return;
+ }
+
regs->eax = (uint32_t)-1;
}
SYSCALL_LSEEK = 9,
SYSCALL_FSTAT = 10,
SYSCALL_STAT = 11,
+
+ SYSCALL_DUP = 12,
+ SYSCALL_DUP2 = 13,
+ SYSCALL_PIPE = 14,
+ SYSCALL_EXECVE = 15,
};
enum {
return ret;
}
+static int sys_execve(const char* path, const char* const* argv, const char* const* envp) {
+ int ret;
+ __asm__ volatile(
+ "int $0x80"
+ : "=a"(ret)
+ : "a"(SYSCALL_EXECVE), "b"(path), "c"(argv), "d"(envp)
+ : "memory"
+ );
+ return ret;
+}
+
+static int sys_pipe(int fds[2]) {
+ int ret;
+ __asm__ volatile(
+ "int $0x80"
+ : "=a"(ret)
+ : "a"(SYSCALL_PIPE), "b"(fds)
+ : "memory"
+ );
+ return ret;
+}
+
+static int sys_dup(int oldfd) {
+ int ret;
+ __asm__ volatile(
+ "int $0x80"
+ : "=a"(ret)
+ : "a"(SYSCALL_DUP), "b"(oldfd)
+ : "memory"
+ );
+ return ret;
+}
+
+static int sys_dup2(int oldfd, int newfd) {
+ int ret;
+ __asm__ volatile(
+ "int $0x80"
+ : "=a"(ret)
+ : "a"(SYSCALL_DUP2), "b"(oldfd), "c"(newfd)
+ : "memory"
+ );
+ return ret;
+}
+
static int sys_waitpid(int pid, int* status, uint32_t options) {
int ret;
__asm__ volatile(
sys_exit(1);
}
+ if (sys_lseek(fd, 0, SEEK_END) < 0) {
+ sys_write(1, "[init] dup2 prep lseek failed\n",
+ (uint32_t)(sizeof("[init] dup2 prep lseek failed\n") - 1));
+ sys_exit(1);
+ }
+
+ if (sys_dup2(fd, 1) != 1) {
+ sys_write(1, "[init] dup2 failed\n", (uint32_t)(sizeof("[init] dup2 failed\n") - 1));
+ sys_exit(1);
+ }
+
+ (void)sys_close(fd);
+
+ {
+ static const char m[] = "[init] dup2 stdout->file OK\n";
+ if (sys_write(1, m, (uint32_t)(sizeof(m) - 1)) != (int)(sizeof(m) - 1)) {
+ sys_exit(1);
+ }
+ }
+
+ (void)sys_close(1);
+ sys_write(1, "[init] dup2 restore tty OK\n",
+ (uint32_t)(sizeof("[init] dup2 restore tty OK\n") - 1));
+
+ {
+ int pfds[2];
+ if (sys_pipe(pfds) < 0) {
+ sys_write(1, "[init] pipe failed\n", (uint32_t)(sizeof("[init] pipe failed\n") - 1));
+ sys_exit(1);
+ }
+
+ static const char pmsg[] = "pipe-test";
+ if (sys_write(pfds[1], pmsg, (uint32_t)(sizeof(pmsg) - 1)) != (int)(sizeof(pmsg) - 1)) {
+ sys_write(1, "[init] pipe write failed\n",
+ (uint32_t)(sizeof("[init] pipe write failed\n") - 1));
+ sys_exit(1);
+ }
+
+ char rbuf[16];
+ int prd = sys_read(pfds[0], rbuf, (uint32_t)(sizeof(pmsg) - 1));
+ if (prd != (int)(sizeof(pmsg) - 1)) {
+ sys_write(1, "[init] pipe read failed\n",
+ (uint32_t)(sizeof("[init] pipe read failed\n") - 1));
+ sys_exit(1);
+ }
+
+ int ok = 1;
+ for (uint32_t i = 0; i < (uint32_t)(sizeof(pmsg) - 1); i++) {
+ if ((uint8_t)rbuf[i] != (uint8_t)pmsg[i]) ok = 0;
+ }
+ if (!ok) {
+ sys_write(1, "[init] pipe mismatch\n",
+ (uint32_t)(sizeof("[init] pipe mismatch\n") - 1));
+ sys_exit(1);
+ }
+
+ if (sys_dup2(pfds[1], 1) != 1) {
+ sys_write(1, "[init] pipe dup2 failed\n",
+ (uint32_t)(sizeof("[init] pipe dup2 failed\n") - 1));
+ sys_exit(1);
+ }
+
+ static const char p2[] = "dup2-pipe";
+ if (sys_write(1, p2, (uint32_t)(sizeof(p2) - 1)) != (int)(sizeof(p2) - 1)) {
+ sys_exit(1);
+ }
+
+ int prd2 = sys_read(pfds[0], rbuf, (uint32_t)(sizeof(p2) - 1));
+ if (prd2 != (int)(sizeof(p2) - 1)) {
+ sys_write(1, "[init] pipe dup2 read failed\n",
+ (uint32_t)(sizeof("[init] pipe dup2 read failed\n") - 1));
+ sys_exit(1);
+ }
+
+ (void)sys_close(1);
+ (void)sys_close(pfds[0]);
+ (void)sys_close(pfds[1]);
+
+ sys_write(1, "[init] pipe OK\n", (uint32_t)(sizeof("[init] pipe OK\n") - 1));
+ }
+
+ fd = sys_open("/tmp/hello.txt", 0);
+ if (fd < 0) {
+ sys_write(1, "[init] tmpfs open2 failed\n",
+ (uint32_t)(sizeof("[init] tmpfs open2 failed\n") - 1));
+ sys_exit(1);
+ }
+
if (sys_stat("/tmp/hello.txt", &st) < 0) {
sys_write(1, "[init] tmpfs stat failed\n",
(uint32_t)(sizeof("[init] tmpfs stat failed\n") - 1));
static const char wbad[] = "[init] waitpid failed (100 children, explicit)\n";
(void)sys_write(1, wbad, (uint32_t)(sizeof(wbad) - 1));
}
+
+ (void)sys_write(1, "[init] execve(/bin/echo.elf)\n",
+ (uint32_t)(sizeof("[init] execve(/bin/echo.elf)\n") - 1));
+ (void)sys_execve("/bin/echo.elf", (const char* const*)0, (const char* const*)0);
+ (void)sys_write(1, "[init] execve returned (unexpected)\n",
+ (uint32_t)(sizeof("[init] execve returned (unexpected)\n") - 1));
+ sys_exit(1);
sys_exit(0);
}