2026-06-17 18:16:47 -05:00
|
|
|
#include <stdint.h>
|
2026-06-29 17:00:07 -05:00
|
|
|
#include <stddef.h>
|
2026-06-17 18:16:47 -05:00
|
|
|
|
2026-07-16 23:19:54 -05:00
|
|
|
#include "drivers/serial/serial.h"
|
2026-07-07 00:13:24 -05:00
|
|
|
#include "lib/memory.h"
|
|
|
|
|
#include "lib/ringbuf.h"
|
2026-07-08 21:15:30 -05:00
|
|
|
|
2026-06-29 17:00:07 -05:00
|
|
|
#include "memory/mm.h"
|
2026-07-08 21:15:30 -05:00
|
|
|
|
2026-06-29 17:00:07 -05:00
|
|
|
#include "process.h"
|
2026-06-28 17:58:58 -05:00
|
|
|
#include "scheduler.h"
|
2026-07-07 00:13:24 -05:00
|
|
|
#include "vfs.h"
|
2026-07-08 21:15:30 -05:00
|
|
|
#include "elf.h"
|
2026-06-17 18:16:47 -05:00
|
|
|
|
2026-06-29 17:00:07 -05:00
|
|
|
#include <drivers/vga/vga.h>
|
2026-07-08 21:15:30 -05:00
|
|
|
#include <drivers/pty/pty.h>
|
2026-06-29 17:00:07 -05:00
|
|
|
|
2026-07-01 20:00:22 -05:00
|
|
|
#include <lib/print.h>
|
2026-07-07 00:13:24 -05:00
|
|
|
#include <lib/string.h>
|
2026-07-01 20:00:22 -05:00
|
|
|
|
2026-07-07 00:13:24 -05:00
|
|
|
typedef struct registers {
|
2026-07-07 18:52:22 -05:00
|
|
|
uint32_t ds; // push %ds
|
|
|
|
|
uint32_t edi, esi, ebp, esp, ebx, edx, ecx, eax; // pushal
|
|
|
|
|
uint32_t eip, cs, eflags, useresp, ss; // pushed by cpu
|
|
|
|
|
} __attribute__((packed)) registers_t;
|
2026-06-17 18:16:47 -05:00
|
|
|
|
2026-06-29 17:00:07 -05:00
|
|
|
static int32_t sys_exit(int status) {
|
2026-07-06 22:13:57 -05:00
|
|
|
process_t* task = current_task();
|
2026-07-16 23:19:54 -05:00
|
|
|
task->state = STATE_DEAD;
|
2026-07-20 22:52:47 -05:00
|
|
|
task->exit_status = status;
|
|
|
|
|
if (task->waiting) {
|
|
|
|
|
wake(task->waiting);
|
|
|
|
|
}
|
2026-07-06 22:13:57 -05:00
|
|
|
exit();
|
2026-06-29 17:00:07 -05:00
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static int32_t sys_write(int fd, const void* buf, size_t count) {
|
2026-07-07 00:13:24 -05:00
|
|
|
if (fd < 0 || fd >= MAX_PROCESS_FDS) return -1;
|
|
|
|
|
|
|
|
|
|
file_t* f = current_task()->fd_table[fd];
|
|
|
|
|
if (!f || !f->node) return -1;
|
|
|
|
|
|
|
|
|
|
uint32_t rd = f->node->write(f->node, f->offset, count, (uint8_t*)buf);
|
|
|
|
|
f->offset += rd;
|
|
|
|
|
|
|
|
|
|
return rd;
|
2026-06-17 18:16:47 -05:00
|
|
|
}
|
|
|
|
|
|
2026-06-29 17:00:07 -05:00
|
|
|
static int32_t sys_read(int fd, void* buf, size_t count) {
|
2026-07-07 00:13:24 -05:00
|
|
|
if (fd < 0 || fd >= MAX_PROCESS_FDS) return -1;
|
|
|
|
|
|
|
|
|
|
file_t* f = current_task()->fd_table[fd];
|
|
|
|
|
if (!f || !f->node) return -1;
|
|
|
|
|
|
|
|
|
|
uint32_t rd = f->node->read(f->node, f->offset, count, (uint8_t*)buf);
|
|
|
|
|
f->offset += rd;
|
|
|
|
|
|
|
|
|
|
return rd;
|
2026-06-28 17:58:58 -05:00
|
|
|
}
|
|
|
|
|
|
2026-06-29 17:00:07 -05:00
|
|
|
static int32_t sys_open(const char* filename, int flags) {
|
2026-07-10 07:46:46 -05:00
|
|
|
return vfs_open(filename, flags);
|
2026-06-28 17:58:58 -05:00
|
|
|
}
|
|
|
|
|
|
2026-06-29 17:00:07 -05:00
|
|
|
static int32_t sys_close(int fd) {
|
2026-07-08 21:15:30 -05:00
|
|
|
process_t* task = current_task();
|
|
|
|
|
task->fd_table[fd] = NULL;
|
|
|
|
|
return 1;
|
2026-06-29 17:00:07 -05:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static int32_t sys_brk(uint32_t new_break) {
|
|
|
|
|
process_t* current = current_task();
|
|
|
|
|
|
|
|
|
|
if (new_break == 0) {
|
|
|
|
|
return current->heap_end;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (new_break < current->heap_end) {
|
|
|
|
|
current->heap_end = new_break;
|
|
|
|
|
return current->heap_end;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
uint32_t page_start = (current->heap_end + 4095) & ~4095;
|
|
|
|
|
uint32_t page_end = (new_break + 4095) & ~4095;
|
|
|
|
|
|
|
|
|
|
for (uint32_t addr = page_start; addr < page_end; addr += 4096) {
|
|
|
|
|
// 1. Allocate a physical frame using your PMM (Physical Memory Manager)
|
|
|
|
|
void* phys = p_alloc_frame();
|
|
|
|
|
|
|
|
|
|
// 2. Map it into the current page directory using your VMM (Virtual Memory Manager)
|
|
|
|
|
map_page(addr, (uint32_t)phys, PAGE_PRESENT | PAGE_WRITABLE | PAGE_USER);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
current->heap_end = new_break;
|
|
|
|
|
return current->heap_end;
|
|
|
|
|
}
|
|
|
|
|
|
2026-07-14 00:07:50 -05:00
|
|
|
static int32_t sys_sbrk(int32_t inc) {
|
|
|
|
|
process_t* current = current_task();
|
|
|
|
|
|
|
|
|
|
if (inc <= 0) { // can't shrink yet
|
|
|
|
|
return current->heap_end;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
uint32_t page_start = (current->heap_end + 4095) & ~4095;
|
|
|
|
|
current->heap_end += inc;
|
|
|
|
|
uint32_t page_end = (current->heap_end + 4095) & ~4095;
|
|
|
|
|
|
|
|
|
|
for (uint32_t addr = page_start; addr < page_end; addr += 4096) {
|
|
|
|
|
void* phys = p_alloc_frame();
|
|
|
|
|
map_page(addr, (uint32_t)phys, PAGE_PRESENT | PAGE_WRITABLE | PAGE_USER);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return current->heap_end;
|
|
|
|
|
}
|
|
|
|
|
|
2026-07-07 00:13:24 -05:00
|
|
|
static int32_t sys_pty(int* slave_fd) {
|
|
|
|
|
pty_t* pty = (pty_t*)kalloc(sizeof(pty_t));
|
|
|
|
|
ring_buf_init(&pty->master_rb);
|
|
|
|
|
ring_buf_init(&pty->slave_rb);
|
|
|
|
|
|
|
|
|
|
vfs_node_t* master =(vfs_node_t*)kalloc(sizeof(vfs_node_t));
|
|
|
|
|
master->flags = VFS_CHARDEVICE;
|
|
|
|
|
master->size = 0;
|
|
|
|
|
master->read = pty_master_read;
|
|
|
|
|
master->write = pty_master_write;
|
2026-07-11 10:33:08 -05:00
|
|
|
master->find = NULL;
|
2026-07-07 00:13:24 -05:00
|
|
|
master->data = pty;
|
|
|
|
|
|
|
|
|
|
vfs_node_t* slave =(vfs_node_t*)kalloc(sizeof(vfs_node_t));
|
|
|
|
|
slave->flags = VFS_CHARDEVICE;
|
|
|
|
|
slave->size = 0;
|
|
|
|
|
slave->read = pty_slave_read;
|
|
|
|
|
slave->write = pty_slave_write;
|
2026-07-11 10:33:08 -05:00
|
|
|
slave->find = NULL;
|
2026-07-07 00:13:24 -05:00
|
|
|
slave->data = pty;
|
|
|
|
|
|
|
|
|
|
file_t* fmaster = (file_t*)kalloc(sizeof(file_t));
|
|
|
|
|
fmaster->node = master;
|
|
|
|
|
fmaster->offset = 0;
|
|
|
|
|
fmaster->flags = 0;
|
|
|
|
|
|
|
|
|
|
file_t* fslave = (file_t*)kalloc(sizeof(file_t));
|
|
|
|
|
fslave->node = slave;
|
|
|
|
|
fslave->offset = 0;
|
|
|
|
|
fslave->flags = 0;
|
|
|
|
|
|
|
|
|
|
*slave_fd = alloc_fd(fslave);
|
|
|
|
|
return alloc_fd(fmaster);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static int32_t sys_fork(registers_t* parent_regs) {
|
|
|
|
|
process_t* parent = current_task();
|
|
|
|
|
process_t* child = kalloc(sizeof(process_t));
|
|
|
|
|
if (!child) {
|
|
|
|
|
return -1;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
child->pid = get_next_pid();
|
|
|
|
|
child->state = STATE_READY;
|
|
|
|
|
child->flags = parent->flags;
|
|
|
|
|
child->heap_end = parent->heap_end;
|
|
|
|
|
child->sleep = 0;
|
|
|
|
|
|
|
|
|
|
for (int i = 0; i < MAX_PROCESS_FDS; i++) {
|
|
|
|
|
child->fd_table[i] = parent->fd_table[i];
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
uint32_t kstack_size = 4096;
|
|
|
|
|
void* kstack_alloc = kalloc(kstack_size);
|
|
|
|
|
child->kstack_top = (uint32_t)kstack_alloc + kstack_size;
|
|
|
|
|
|
|
|
|
|
registers_t* child_regs = (registers_t*)(child->kstack_top - sizeof(registers_t));
|
2026-07-07 18:52:22 -05:00
|
|
|
memcpy(parent_regs, child_regs, sizeof(registers_t));
|
2026-07-07 00:13:24 -05:00
|
|
|
child_regs->eax = 0;
|
|
|
|
|
child->esp = (uint32_t)child_regs;
|
|
|
|
|
|
2026-07-08 19:11:39 -05:00
|
|
|
uint32_t cr3 = (uint32_t)clone_current_pd();
|
|
|
|
|
child->cr3 = cr3;
|
2026-07-07 00:13:24 -05:00
|
|
|
|
|
|
|
|
add_task(child);
|
|
|
|
|
return child->pid;
|
|
|
|
|
}
|
|
|
|
|
|
2026-07-08 21:15:30 -05:00
|
|
|
static int32_t sys_exec(registers_t* regs, const char* prgm) {
|
|
|
|
|
clear_current_pd();
|
|
|
|
|
|
|
|
|
|
uint32_t eip = load_elf_program(prgm);
|
2026-07-12 20:13:13 -05:00
|
|
|
if (eip == 0) {
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
2026-07-08 21:15:30 -05:00
|
|
|
|
|
|
|
|
uint32_t stack_sz = PAGE_SIZE * 16;
|
|
|
|
|
uint32_t stack_top = 0xBFFF0000;
|
|
|
|
|
uint32_t stack_bottom = stack_top - stack_sz;
|
|
|
|
|
for (uint32_t vaddr = stack_bottom; vaddr < stack_top; vaddr += PAGE_SIZE) {
|
|
|
|
|
void* phys_frame = p_alloc_frame();
|
|
|
|
|
map_page(vaddr, (uint32_t)phys_frame, PAGE_PRESENT | PAGE_WRITABLE | PAGE_USER);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
uint32_t* u_esp = (uint32_t*)stack_top;
|
|
|
|
|
*(--u_esp) = 0; // envp = NULL
|
|
|
|
|
*(--u_esp) = 0; // argv = NULL
|
|
|
|
|
*(--u_esp) = 0; // argc = 0
|
|
|
|
|
|
|
|
|
|
regs->eax = 0;
|
|
|
|
|
regs->ecx = 0;
|
|
|
|
|
regs->edx = 0;
|
|
|
|
|
regs->ebp = 0;
|
|
|
|
|
regs->esi = 0;
|
|
|
|
|
regs->edi = 0;
|
|
|
|
|
regs->eip = eip;
|
|
|
|
|
regs->useresp = (uint32_t)u_esp;
|
|
|
|
|
|
2026-07-16 23:19:54 -05:00
|
|
|
print_serial("returning from exec\n");
|
2026-07-08 21:15:30 -05:00
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static int32_t sys_dup2(int src, int dst) {
|
|
|
|
|
process_t* task = current_task();
|
|
|
|
|
task->fd_table[dst] = task->fd_table[src];
|
|
|
|
|
return dst;
|
|
|
|
|
}
|
|
|
|
|
|
2026-07-12 04:37:46 -05:00
|
|
|
static int32_t sys_lseek(int fd, size_t offset, int whence) {
|
|
|
|
|
if (fd < 0) return 0;
|
|
|
|
|
process_t* task = current_task();
|
|
|
|
|
file_t* file = task->fd_table[fd];
|
|
|
|
|
if (!file) return 0;
|
|
|
|
|
file->node->seek(file->node, offset, whence);
|
|
|
|
|
return 1;
|
|
|
|
|
}
|
|
|
|
|
|
2026-07-12 20:13:13 -05:00
|
|
|
static int32_t sys_waitpid(int pid, int* exit_status) {
|
|
|
|
|
process_t* current = current_task();
|
|
|
|
|
process_t* child = get_task_by_pid(pid);
|
|
|
|
|
current->state = STATE_BLOCKED;
|
|
|
|
|
child->waiting = current;
|
|
|
|
|
yield();
|
|
|
|
|
*exit_status = child->exit_status;
|
|
|
|
|
return 1;
|
|
|
|
|
}
|
|
|
|
|
|
2026-07-16 14:44:08 -05:00
|
|
|
static int32_t sys_mmap(int fd) {
|
|
|
|
|
if (fd < 0) {
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
process_t* current = current_task();
|
|
|
|
|
if (!current) return 0;
|
|
|
|
|
|
|
|
|
|
file_t* file = current->fd_table[fd];
|
|
|
|
|
if (!file) return 0;
|
|
|
|
|
|
|
|
|
|
if (!(file->node->flags & VFS_CHARDEVICE)) return 0;
|
|
|
|
|
|
2026-07-16 23:19:54 -05:00
|
|
|
uint32_t map_vaddr = 0x20000000;
|
2026-07-16 14:44:08 -05:00
|
|
|
return file->node->mmap(file->node, map_vaddr);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static int32_t sys_ioctl(int fd, uint32_t request, void* args) {
|
|
|
|
|
if (fd < 0) {
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
process_t* current = current_task();
|
|
|
|
|
if (!current) return 0;
|
|
|
|
|
|
|
|
|
|
file_t* file = current->fd_table[fd];
|
|
|
|
|
if (!file) return 0;
|
|
|
|
|
|
|
|
|
|
if (!file->node->ioctl) return 0;
|
|
|
|
|
|
|
|
|
|
return file->node->ioctl(file->node, request, args);
|
|
|
|
|
}
|
|
|
|
|
|
2026-07-07 18:52:22 -05:00
|
|
|
void syscall(registers_t* regs) {
|
|
|
|
|
int32_t ret;
|
2026-06-29 17:00:07 -05:00
|
|
|
switch(regs->eax) {
|
2026-07-07 18:52:22 -05:00
|
|
|
case 1: ret = sys_exit(regs->ebx); break;
|
|
|
|
|
case 3: ret = sys_read(regs->ebx, (void*)regs->ecx, regs->edx); break;
|
|
|
|
|
case 4: ret = sys_write(regs->ebx, (const void*)regs->ecx, regs->edx); break;
|
|
|
|
|
case 5: ret = sys_open((const char*)regs->ebx, regs->ecx); break;
|
|
|
|
|
case 6: ret = sys_close(regs->ebx); break;
|
|
|
|
|
case 12: ret = sys_brk(regs->ebx); break;
|
2026-07-14 00:07:50 -05:00
|
|
|
case 13: ret = sys_sbrk(regs->ebx); break;
|
2026-07-07 18:52:22 -05:00
|
|
|
case 20: ret = sys_pty((int*)regs->ebx); break;
|
|
|
|
|
case 21: ret = sys_fork(regs); break;
|
2026-07-08 21:15:30 -05:00
|
|
|
case 22: ret = sys_exec(regs, (const char*)regs->ebx); break;
|
|
|
|
|
case 23: ret = sys_dup2(regs->ebx, regs->ecx); break;
|
2026-07-12 04:37:46 -05:00
|
|
|
case 24: ret = sys_lseek(regs->ebx, regs->ecx, regs->edx); break;
|
2026-07-12 20:13:13 -05:00
|
|
|
case 25: ret = sys_waitpid(regs->ebx, (int*)regs->ecx); break;
|
2026-07-16 14:44:08 -05:00
|
|
|
case 26: ret = sys_mmap(regs->ebx); break;
|
|
|
|
|
case 27: ret = sys_ioctl(regs->ebx, regs->ecx, (void*)regs->edx); break;
|
2026-07-07 18:52:22 -05:00
|
|
|
default: ret = -1;
|
2026-06-29 17:00:07 -05:00
|
|
|
}
|
2026-07-07 18:52:22 -05:00
|
|
|
regs->eax = ret;
|
2026-06-17 18:16:47 -05:00
|
|
|
}
|