302 lines
7.7 KiB
C
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;
|
|
}
|
|
} |