starting to work on pty drivers, fork(), and scheduler redesign
This commit is contained in:
135
kernel/syscall.c
135
kernel/syscall.c
@@ -1,52 +1,57 @@
|
||||
#include <stdint.h>
|
||||
#include <stddef.h>
|
||||
|
||||
#include <drivers/pty/pty.h>
|
||||
#include "common.h"
|
||||
#include "lib/memory.h"
|
||||
#include "lib/ringbuf.h"
|
||||
#include "memory/mm.h"
|
||||
#include "process.h"
|
||||
#include "scheduler.h"
|
||||
#include "kbd.h"
|
||||
#include "vfs.h"
|
||||
|
||||
#include <drivers/vga/vga.h>
|
||||
|
||||
#include <lib/print.h>
|
||||
#include <lib/string.h>
|
||||
|
||||
typedef struct registers {
|
||||
uint32_t gs, fs, es, ds; // Pushed manually
|
||||
uint32_t edi, esi, ebp, esp, ebx, edx, ecx, eax; // Pushed by pusha
|
||||
uint32_t int_no, err_code; // Pushed manually
|
||||
uint32_t eip, cs, eflags, useresp, ss; // Pushed automatically by CPU
|
||||
} registers_t;
|
||||
|
||||
static int32_t sys_exit(int status) {
|
||||
process_t* task = current_task();
|
||||
task->state = STATE_DEAD;
|
||||
kprintf("Process %d exited with status %d\n", task->pid, status);
|
||||
kprintf("exiting task %d with status %d\n", task->pid, status);
|
||||
exit();
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int32_t sys_write(int fd, const void* buf, size_t count) {
|
||||
if (fd == 1 || fd == 2) { // stdout or stderr
|
||||
const char* cbuf = (const char*)buf;
|
||||
for (size_t i = 0; i < count; i++) {
|
||||
vga_putchar(cbuf[i]);
|
||||
}
|
||||
return count;
|
||||
}
|
||||
return -1;
|
||||
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;
|
||||
}
|
||||
|
||||
static int32_t sys_read(int fd, void* buf, size_t count) {
|
||||
if (fd == 0) {
|
||||
char* cbuf = (char*)buf;
|
||||
size_t bytes_read = 0;
|
||||
if (fd < 0 || fd >= MAX_PROCESS_FDS) return -1;
|
||||
|
||||
while (bytes_read < count) {
|
||||
kbd_wait();
|
||||
|
||||
if (kbd_ready()) {
|
||||
char c = kbd_read();
|
||||
cbuf[bytes_read++] = c;
|
||||
if (c == '\n') break;
|
||||
}
|
||||
}
|
||||
return bytes_read;
|
||||
}
|
||||
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;
|
||||
}
|
||||
|
||||
static int32_t sys_open(const char* filename, int flags) {
|
||||
@@ -84,12 +89,78 @@ static int32_t sys_brk(uint32_t new_break) {
|
||||
return current->heap_end;
|
||||
}
|
||||
|
||||
typedef struct registers {
|
||||
uint32_t gs, fs, es, ds; // Pushed manually
|
||||
uint32_t edi, esi, ebp, esp, ebx, edx, ecx, eax; // Pushed by pusha
|
||||
uint32_t int_no, err_code; // Pushed manually
|
||||
uint32_t eip, cs, eflags, useresp, ss; // Pushed automatically by CPU
|
||||
} registers_t;
|
||||
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;
|
||||
master->finddir = NULL;
|
||||
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;
|
||||
slave->finddir = NULL;
|
||||
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];
|
||||
}
|
||||
|
||||
disable_interrupts();
|
||||
|
||||
uint32_t kstack_size = 4096;
|
||||
void* kstack_alloc = kalloc(kstack_size);
|
||||
child->kstack_top = (uint32_t)kstack_alloc + kstack_size;
|
||||
|
||||
child->cr3 = (uint32_t)clone_task_pd();
|
||||
|
||||
registers_t* child_regs = (registers_t*)(child->kstack_top - sizeof(registers_t));
|
||||
memcpy(child_regs, parent_regs, sizeof(registers_t));
|
||||
child_regs->eax = 0;
|
||||
child->esp = (uint32_t)child_regs;
|
||||
|
||||
enable_interrupts();
|
||||
|
||||
add_task(child);
|
||||
return child->pid;
|
||||
}
|
||||
|
||||
int32_t syscall(registers_t* regs) {
|
||||
switch(regs->eax) {
|
||||
case 1: return sys_exit(regs->ebx);
|
||||
@@ -98,6 +169,8 @@ int32_t syscall(registers_t* regs) {
|
||||
case 5: return sys_open((const char*)regs->ebx, regs->ecx);
|
||||
case 6: return sys_close(regs->ebx);
|
||||
case 12: return sys_brk(regs->ebx);
|
||||
case 20: return sys_pty((int*)regs->ebx);
|
||||
case 21: return sys_fork(regs);
|
||||
default:
|
||||
return -1;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user