Files
KatauOS/src/tasking/syscalls.c
T
2025-07-18 21:02:54 +03:00

302 lines
7.7 KiB
C

#include "../include/syscalls.h"
#include <stddef.h>
#include "../include/stdio.h"
#include "../include/liballoc.h"
#include "../include/paging.h"
#include "../include/string.h"
#define STDIN_FILENO 0
#define STDOUT_FILENO 1
#define STDERR_FILENO 2
#define EBADF 9
const char* flags_to_mode_str(int flags) {
static char mode[4] = {0};
int accmode = flags & 3;
if (accmode == 0) { // O_RDONLY
mode[0] = 'r';
mode[1] = '\0';
} else if (accmode == 1) { // O_WRONLY
if (flags & 0x400) { // O_APPEND
mode[0] = 'a';
mode[1] = '\0';
} else {
mode[0] = 'w';
mode[1] = '\0';
}
} else if (accmode == 2) { // O_RDWR
if (flags & 0x400) { // O_APPEND
mode[0] = 'a';
mode[1] = '+';
mode[2] = '\0';
} else if (flags & 0x200) { // O_TRUNC
mode[0] = 'w';
mode[1] = '+';
mode[2] = '\0';
} else {
mode[0] = 'r';
mode[1] = '+';
mode[2] = '\0';
}
} else {
mode[0] = 'r';
mode[1] = '\0';
}
return mode;
}
int sys_exit(TrapFrame *tf)
{
int error_code = tf->ebx;
debug_log("killing task\n");
task_kill(current);
asm("sti");
while(1){}
return error_code;
}
extern void trapret(void);
int sys_fork(TrapFrame *tf)
{
debug_log("FORKFORKFORKFORK\n");
scheduler_lock();
uint32_t* new_pd = copy_page_dir(current->pagedir);
if (!new_pd) {
debug_log("Failed to copy page directory\n");
return -1;
}
debug_log("new_pd: %X\n", new_pd);
void *p_physical = alloc_page();
if (!p_physical) {
destroy_page_dir(new_pd);
return -1;
}
Process* child = (Process*)((uint32_t)p_physical + 0xC0000000);
map_page(p_physical, (void*)child, PAGE_PRESENT | PAGE_RW);
memset(child, 0, sizeof(Process));
child->pid = ++pid_counter;
child->state = Ready;
child->ring = current->ring;
child->pagedir = new_pd;
void *kstack_physical = alloc_page();
if (!kstack_physical) {
destroy_page_dir(new_pd);
free_page(p_physical);
debug_log("Failed to allocate kernel stack\n");
return -1;
}
child->kstack = (char*)((uint32_t)kstack_physical + 0xC0000000);
map_page(kstack_physical, child->kstack, PAGE_PRESENT | PAGE_RW);
debug_log("child->kstack: %X\n", child->kstack);
uint8_t* sp = (uint8_t*)(child->kstack + KSTACKSIZE);
// 1. Place the TrapFrame on the child's stack.
sp -= sizeof(TrapFrame);
child->tf = (TrapFrame*)sp;
memcpy(&child->tf->gs, &tf->gs, 12 * sizeof(uint32_t));
uint32_t* parent_cpu_state_ptr = (uint32_t*)&tf->interrupt;
child->tf->eip = parent_cpu_state_ptr[0];
child->tf->cs = parent_cpu_state_ptr[1];
child->tf->eflags = parent_cpu_state_ptr[2];
child->tf->usermode_esp = parent_cpu_state_ptr[3];
child->tf->usermode_ss = parent_cpu_state_ptr[4];
child->tf->eax = 0; // Child returns 0
debug_log("Parent returns PID: %X, Child returns 0\n", child->pid);
sp -= sizeof(Context);
child->context = (Context*)sp;
memset(child->context, 0, sizeof(Context));
// 5. Set the child's starting instruction pointer to trapret.
// When the child is scheduled, it will execute trapret, which will
// restore the registers from the TrapFrame and iret to user mode.
child->context->eip = (uint32_t)trapret;
// 6. IMPORTANT: Set the child's kernel stack pointer for the scheduler.
child->kesp = (uint32_t)sp;
for (int i = 0; i < MAX_OPEN_FILES; i++) {
child->file_descriptors[i] = current->file_descriptors[i];
}
debug_log("File descriptors copied\n");
Process* curr = queue;
while (curr->next) {
curr = curr->next;
}
curr->next = child;
debug_log("Child added to queue\n");
scheduler_unlock(); // Release the lock
return child->pid;
}
int sys_read(TrapFrame *tf)
{
if(tf->ebx < 3)
{
//TODO: implement stdin handling here
}
else
{
if(current->file_descriptors[tf->ebx] == NULL)
{
return -EBADF;
}
return fat_fread(current->file_descriptors[tf->ebx], (void*)tf->ecx, tf->edx);
}
}
int sys_write(TrapFrame *tf)
{
if(tf->ebx < 3)
{
//stdin, stdout or stderr
if(tf->ebx == STDOUT_FILENO)
{
//debug_log("\n=================SYS_WRITE output to stdout=====================\n");
print((char*)tf->ecx, tf->edx);
//debug_log("\n=================END OF THAT SHIT=====================\n");
return tf->edx;
}
}
else
{
if(current->file_descriptors[tf->ebx] == NULL)
{
return -EBADF;
}
return fat_fwrite(current->file_descriptors[tf->ebx], (void*)tf->ecx, tf->edx);
}
}
int sys_open(TrapFrame *tf)
{
const char* filename = (const char*)tf->ebx;
int flags = tf->ecx;
int fd = -1;
const char* mode_str = flags_to_mode_str(flags);
//debug_log("\n====filename: %s\n", filename);
//debug_log("\n====mode_str: %s\n", mode_str);
for(int i = 3; i < MAX_OPEN_FILES; i++)
{
//debug_log("\n====i: %X\n", i);
if(current->file_descriptors[i] == NULL)
{
current->file_descriptors[i] = malloc(sizeof(file_t)); // Kernel malloc
//debug_log("\n====FILE_DESCRIPTOR: %X\n", i);
int result = fat_fopen(current->file_descriptors[i], filename, mode_str);
if (result < 0) {
free(current->file_descriptors[i]); // Free on failure
current->file_descriptors[i] = NULL;
return result;
}
fd = i;
break;
}
}
return fd;
}
int sys_close(TrapFrame *tf)
{
int fd = tf->ebx;
//debug_log("SYS_CLOSE: fd = 0x%X", fd);
if(current->file_descriptors[fd] != NULL)
{
//debug_log("SYS_CLOSE: current->file_descriptors[fd] != NULL");
int result = fat_fclose(current->file_descriptors[fd]);
//debug_log("SYS_CLOSE: fat_fclose result: 0x%X", result);
free(current->file_descriptors[fd]);
current->file_descriptors[fd] = NULL;
return result;
}
return -1;
}
int sys_chdir(TrapFrame *tf)
{
strcat(current->cwd->fat->path, "/");
strcat(current->cwd->fat->path, (char*)tf->ebx);
return fat_opendir(current->cwd, (const char*)tf->ebx);
}
int sys_getcwd(TrapFrame *tf)
{
strcpy((char*)tf->ebx, current->cwd->fat->path);
return tf->ebx;
}
int sys_getpid(TrapFrame *tf)
{
return current->pid;
}
void handle_syscall(TrapFrame *tf)
{
/*
debug_log("EAX: %X ", tf->eax);
debug_log("EBX: %X ", tf->ebx);
debug_log("ECX: %s ", tf->ecx);
debug_log("EDX: %X\n", tf->edx);
*/
switch(tf->eax)
{
case 1://exit
tf->eax = sys_exit(tf);
break;
case 2://fork
tf->eax = sys_fork(tf);
break;
case 3://read
tf->eax = sys_read(tf);
break;
case 4://write
tf->eax = sys_write(tf);
break;
case 5://open
tf->eax = sys_open(tf);
break;
case 6://close
tf->eax = sys_close(tf);
break;
case 12://chdir
tf->eax = sys_chdir(tf);
break;
case 20://getpid
tf->eax = sys_getpid(tf);
break;
case 183://getcwd
tf->eax = sys_getcwd(tf);
break;
default:
debug_log("unknown syscall: %X\n", tf->eax);
tf->eax = -1;
break;
}
}