starting to work on pty drivers, fork(), and scheduler redesign
This commit is contained in:
62
kernel/drivers/pty/pty.c
Normal file
62
kernel/drivers/pty/pty.c
Normal file
@@ -0,0 +1,62 @@
|
||||
#include "lib/ringbuf.h"
|
||||
#include <drivers/pty/pty.h>
|
||||
|
||||
uint32_t pty_master_read(struct vfs_node* node, uint32_t offset, uint32_t size, uint8_t* buffer) {
|
||||
pty_t* pty = (pty_t*)node->data;
|
||||
uint32_t bytes_read = 0;
|
||||
while (bytes_read < size) {
|
||||
char c;
|
||||
if (ring_buf_read(&pty->slave_rb, &c) == 0) {
|
||||
buffer[bytes_read++] = c;
|
||||
} else {
|
||||
break;
|
||||
}
|
||||
}
|
||||
return bytes_read;
|
||||
}
|
||||
|
||||
uint32_t pty_master_write(struct vfs_node* node, uint32_t offset, uint32_t size, uint8_t* buffer) {
|
||||
pty_t* pty = (pty_t*)node->data;
|
||||
uint32_t bytes_written = 0;
|
||||
|
||||
while (bytes_written < size) {
|
||||
if (ring_buf_write(&pty->master_rb, buffer[bytes_written]) == 0) {
|
||||
bytes_written++;
|
||||
ring_buf_write(&pty->slave_rb, buffer[bytes_written-1]);
|
||||
} else {
|
||||
break;
|
||||
}
|
||||
}
|
||||
return bytes_written;
|
||||
}
|
||||
|
||||
uint32_t pty_slave_read(struct vfs_node* node, uint32_t offset, uint32_t size, uint8_t* buffer) {
|
||||
pty_t* pty = (pty_t*)node->data;
|
||||
uint32_t bytes_read = 0;
|
||||
|
||||
while (bytes_read < size) {
|
||||
char c;
|
||||
if (ring_buf_read(&pty->master_rb, &c) == 0) {
|
||||
buffer[bytes_read++] = c;
|
||||
} else {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return bytes_read;
|
||||
}
|
||||
|
||||
uint32_t pty_slave_write(struct vfs_node* node, uint32_t offset, uint32_t size, uint8_t* buffer) {
|
||||
pty_t* pty = (pty_t*)node->data;
|
||||
uint32_t bytes_written = 0;
|
||||
|
||||
while (bytes_written < size) {
|
||||
if (ring_buf_write(&pty->slave_rb, buffer[bytes_written]) == 0) {
|
||||
bytes_written++;
|
||||
} else {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return bytes_written;
|
||||
}
|
||||
27
kernel/drivers/pty/pty.h
Normal file
27
kernel/drivers/pty/pty.h
Normal file
@@ -0,0 +1,27 @@
|
||||
#ifndef KPTY_H
|
||||
#define KPTY_H
|
||||
|
||||
#include <stdint.h>
|
||||
#include <lib/ringbuf.h>
|
||||
#include <vfs.h>
|
||||
|
||||
typedef struct {
|
||||
|
||||
} wait_queue_t;
|
||||
|
||||
typedef struct {
|
||||
ring_buf_t master_rb;
|
||||
ring_buf_t slave_rb;
|
||||
wait_queue_t master_wq;
|
||||
wait_queue_t slave_wq;
|
||||
uint32_t flags;
|
||||
uint32_t pid;
|
||||
} pty_t;
|
||||
|
||||
uint32_t pty_master_read(struct vfs_node* node, uint32_t offset, uint32_t size, uint8_t* buffer);
|
||||
uint32_t pty_master_write(struct vfs_node* node, uint32_t offset, uint32_t size, uint8_t* buffer);
|
||||
|
||||
uint32_t pty_slave_read(struct vfs_node* node, uint32_t offset, uint32_t size, uint8_t* buffer);
|
||||
uint32_t pty_slave_write(struct vfs_node* node, uint32_t offset, uint32_t size, uint8_t* buffer);
|
||||
|
||||
#endif
|
||||
@@ -129,7 +129,9 @@ void load_root_program(const char* path) {
|
||||
*(--u_esp) = 0; // argv = NULL
|
||||
*(--u_esp) = 0; // argc = 0
|
||||
|
||||
create_task(e_hdr->e_entry, (uint32_t)cr3, 1, (uint32_t)u_esp);
|
||||
process_t* process = kalloc(sizeof(process_t));
|
||||
init_task(process, e_hdr->e_entry, (uint32_t)cr3, 1, (uint32_t)u_esp);
|
||||
add_task(process);
|
||||
enable_interrupts();
|
||||
|
||||
load_pd((void*)kernel_cr3);
|
||||
@@ -173,6 +175,6 @@ void kmain(uint32_t magic, multiboot_info* mbi) {
|
||||
init_scheduler();
|
||||
enable_interrupts();
|
||||
|
||||
kprintf("loading rocksh...\n");
|
||||
load_root_program("/rocksh.elf");
|
||||
kprintf("loading test program\n");
|
||||
load_root_program("/test.elf");
|
||||
}
|
||||
|
||||
34
kernel/lib/ringbuf.c
Normal file
34
kernel/lib/ringbuf.c
Normal file
@@ -0,0 +1,34 @@
|
||||
#include <lib/ringbuf.h>
|
||||
|
||||
void ring_buf_init(ring_buf_t* rb) {
|
||||
rb->head = 0;
|
||||
rb->tail = 0;
|
||||
}
|
||||
|
||||
int ring_buf_is_empty(ring_buf_t* rb) {
|
||||
return rb->head == rb->tail;
|
||||
}
|
||||
|
||||
int ring_buf_is_full(ring_buf_t* rb) {
|
||||
return ((rb->head + 1) % PTY_BUFFER_SIZE) == rb->tail;
|
||||
}
|
||||
|
||||
int ring_buf_write(ring_buf_t *buf, char c) {
|
||||
if (ring_buf_is_full(buf)) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
buf->data[buf->head] = c;
|
||||
buf->head = (buf->head + 1) % PTY_BUFFER_SIZE;
|
||||
return 0;
|
||||
}
|
||||
|
||||
int ring_buf_read(ring_buf_t *buf, char *c) {
|
||||
if (ring_buf_is_empty(buf)) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
*c = buf->data[buf->tail];
|
||||
buf->tail = (buf->tail + 1) % PTY_BUFFER_SIZE;
|
||||
return 0;
|
||||
}
|
||||
20
kernel/lib/ringbuf.h
Normal file
20
kernel/lib/ringbuf.h
Normal file
@@ -0,0 +1,20 @@
|
||||
#ifndef KRINGBUF_H
|
||||
#define KRINGBUF_H
|
||||
|
||||
#include <stddef.h>
|
||||
|
||||
#define PTY_BUFFER_SIZE 1024
|
||||
|
||||
typedef struct {
|
||||
char data[PTY_BUFFER_SIZE];
|
||||
size_t head;
|
||||
size_t tail;
|
||||
} ring_buf_t;
|
||||
|
||||
void ring_buf_init(ring_buf_t* rb);
|
||||
int ring_buf_is_empty(ring_buf_t* rb);
|
||||
int ring_buf_is_full(ring_buf_t* rb);
|
||||
int ring_buf_write(ring_buf_t *buf, char c);
|
||||
int ring_buf_read(ring_buf_t *buf, char *c);
|
||||
|
||||
#endif
|
||||
@@ -1,8 +1,8 @@
|
||||
#include "memory/mm.h"
|
||||
#include "lib/print.h"
|
||||
#include "multiboot.h"
|
||||
|
||||
#include <stddef.h>
|
||||
#include <lib/string.h>
|
||||
|
||||
extern uint8_t __kernel_start;
|
||||
extern uint8_t __kernel_end;
|
||||
@@ -17,6 +17,8 @@ extern uint32_t page_directory[1024];
|
||||
#define PAGE_DIRECTORY 0xFFFFF000
|
||||
|
||||
#define TEMP_MAPPING_VADDR 0xDFFF0000
|
||||
#define TEMP_COPY_SRC 0xDFFE0000 // Safely 1 page down
|
||||
#define TEMP_COPY_DST 0xDFFD0000
|
||||
|
||||
#define USR_PAGE 0x07
|
||||
#define SUP_PAGE 0x03
|
||||
@@ -190,4 +192,77 @@ void* create_task_pd() {
|
||||
uint32_t* kernel_pt = (uint32_t*)(PAGE_TABLES + (pde * PAGE_SIZE));
|
||||
kernel_pt[pte] = 0;
|
||||
return (void*)pd_address;
|
||||
}
|
||||
|
||||
void* clone_task_pd() {
|
||||
uint32_t child_pd_phys = (uint32_t)p_alloc_frame();
|
||||
if (child_pd_phys == 0) return NULL;
|
||||
|
||||
map_page(TEMP_MAPPING_VADDR, child_pd_phys, PAGE_PRESENT | PAGE_WRITABLE);
|
||||
uint32_t* child_pd = (uint32_t*)TEMP_MAPPING_VADDR;
|
||||
uint32_t* parent_pd = (uint32_t*)PAGE_DIRECTORY;
|
||||
|
||||
for (int i = 768; i < 1023; i++) {
|
||||
child_pd[i] = parent_pd[i];
|
||||
}
|
||||
|
||||
child_pd[1023] = child_pd_phys | PAGE_PRESENT | PAGE_WRITABLE;
|
||||
|
||||
for (int i = 0; i < 768; i++) {
|
||||
child_pd[i] = 0;
|
||||
}
|
||||
|
||||
for (int i = 0; i < 768; i++) {
|
||||
uint32_t pde = parent_pd[i];
|
||||
if (!(pde & PAGE_PRESENT)) continue;
|
||||
uint32_t child_pt_phys = (uint32_t)p_alloc_frame();
|
||||
|
||||
child_pd[i] = child_pt_phys | (pde & 0xFFF);
|
||||
|
||||
map_page(TEMP_COPY_SRC, pde & ~(PAGE_SIZE - 1), PAGE_PRESENT | PAGE_WRITABLE);
|
||||
map_page(TEMP_COPY_DST, child_pt_phys, PAGE_PRESENT | PAGE_WRITABLE);
|
||||
flush_tlb();
|
||||
|
||||
uint32_t* src_pt = (uint32_t*)TEMP_COPY_SRC;
|
||||
uint32_t* dst_pt = (uint32_t*)TEMP_COPY_DST;
|
||||
|
||||
for (int j = 0; j < 1024; j++) {
|
||||
uint32_t pte = src_pt[j];
|
||||
if (!(pte & PAGE_PRESENT)) {
|
||||
dst_pt[j] = 0;
|
||||
continue;
|
||||
}
|
||||
|
||||
uint32_t child_frame_phys = (uint32_t)p_alloc_frame();
|
||||
dst_pt[j] = child_frame_phys | (pte & 0xFFF);
|
||||
|
||||
uint32_t parent_data_phys = pte & ~(PAGE_SIZE - 1);
|
||||
|
||||
map_page(TEMP_COPY_SRC, parent_data_phys, PAGE_PRESENT | PAGE_WRITABLE);
|
||||
map_page(TEMP_COPY_DST, child_frame_phys, PAGE_PRESENT | PAGE_WRITABLE);
|
||||
flush_tlb();
|
||||
|
||||
memcpy((void*)TEMP_COPY_DST, (void*)TEMP_COPY_SRC, PAGE_SIZE);
|
||||
|
||||
map_page(TEMP_COPY_SRC, pde & ~(PAGE_SIZE - 1), PAGE_PRESENT | PAGE_WRITABLE);
|
||||
map_page(TEMP_COPY_DST, child_pt_phys, PAGE_PRESENT | PAGE_WRITABLE);
|
||||
flush_tlb();
|
||||
}
|
||||
}
|
||||
|
||||
uint32_t pde_main = TEMP_MAPPING_VADDR >> 22;
|
||||
uint32_t* pt_main = (uint32_t*)(PAGE_TABLES + (pde_main * PAGE_SIZE));
|
||||
pt_main[(TEMP_MAPPING_VADDR >> 12) & 0x3FF] = 0;
|
||||
|
||||
uint32_t pde_src = TEMP_COPY_SRC >> 22;
|
||||
uint32_t* pt_src = (uint32_t*)(PAGE_TABLES + (pde_src * PAGE_SIZE));
|
||||
pt_src[(TEMP_COPY_SRC >> 12) & 0x3FF] = 0;
|
||||
|
||||
uint32_t pde_dst = TEMP_COPY_DST >> 22;
|
||||
uint32_t* pt_dst = (uint32_t*)(PAGE_TABLES + (pde_dst * PAGE_SIZE));
|
||||
pt_dst[(TEMP_COPY_DST >> 12) & 0x3FF] = 0;
|
||||
|
||||
flush_tlb();
|
||||
|
||||
return (void*)child_pd_phys;
|
||||
}
|
||||
@@ -21,6 +21,7 @@ void* p_alloc_frame();
|
||||
uint32_t total_free_memory();
|
||||
|
||||
void* create_task_pd();
|
||||
void* clone_task_pd();
|
||||
|
||||
void map_page(uint32_t vaddr, uint32_t paddr, uint32_t flags);
|
||||
|
||||
|
||||
@@ -3,6 +3,10 @@
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
#include <vfs.h>
|
||||
|
||||
#define MAX_PROCESS_FDS 32
|
||||
|
||||
typedef enum {
|
||||
STATE_READY = 1,
|
||||
STATE_SLEEPING = 2,
|
||||
@@ -16,7 +20,8 @@ typedef enum {
|
||||
PROCESS_FLAG_USER = 1 << 1
|
||||
} process_flags_t;
|
||||
|
||||
typedef struct {
|
||||
struct process_t;
|
||||
typedef struct process_t {
|
||||
uint32_t pid;
|
||||
uint32_t esp;
|
||||
uint32_t kstack_top;
|
||||
@@ -25,6 +30,8 @@ typedef struct {
|
||||
uint32_t sleep;
|
||||
uint32_t heap_end;
|
||||
uint32_t flags;
|
||||
file_t* fd_table[MAX_PROCESS_FDS];
|
||||
struct process_t* sched_next;
|
||||
} __attribute__((packed)) process_t;
|
||||
|
||||
#endif
|
||||
@@ -11,12 +11,11 @@
|
||||
#include "scheduler.h"
|
||||
#include "gdt.h"
|
||||
|
||||
static process_t* process_table;
|
||||
|
||||
static int current_process = 0;
|
||||
static int total_processes = 0;
|
||||
static process_t* process_table = NULL;
|
||||
static process_t* current_process = NULL;
|
||||
static process_t* idle_task = NULL;
|
||||
|
||||
#define IDLE_TASK_PID 0
|
||||
static int total_processes = 0;
|
||||
|
||||
static void lock_scheduler() {
|
||||
disable_interrupts();
|
||||
@@ -26,9 +25,8 @@ static void unlock_scheduler() {
|
||||
enable_interrupts();
|
||||
}
|
||||
|
||||
// called from isr and yield, interrupts are already disabled and re enabled in the isr/yield func
|
||||
uint32_t switch_context(uint32_t current_esp) {
|
||||
process_table[current_process].esp = current_esp;
|
||||
current_process->esp = current_esp;
|
||||
|
||||
for (int i = 0; i < total_processes; i++) {
|
||||
if (process_table[i].state == STATE_SLEEPING) {
|
||||
@@ -42,12 +40,12 @@ uint32_t switch_context(uint32_t current_esp) {
|
||||
}
|
||||
}
|
||||
|
||||
int next_process = current_process;
|
||||
process_t* next_process = current_process;
|
||||
int found_ready = 0;
|
||||
|
||||
while (1) {
|
||||
next_process = (next_process + 1) % total_processes;
|
||||
if (next_process != IDLE_TASK_PID && process_table[next_process].state == STATE_READY) {
|
||||
next_process = (process_t*)next_process->sched_next;
|
||||
if (next_process != idle_task && next_process->state == STATE_READY) {
|
||||
found_ready = 1;
|
||||
break;
|
||||
}
|
||||
@@ -58,53 +56,52 @@ uint32_t switch_context(uint32_t current_esp) {
|
||||
}
|
||||
|
||||
if (!found_ready) {
|
||||
if (process_table[current_process].state == STATE_READY) {
|
||||
if (current_process->state == STATE_READY) {
|
||||
next_process = current_process;
|
||||
} else {
|
||||
next_process = IDLE_TASK_PID;
|
||||
next_process = idle_task;
|
||||
}
|
||||
}
|
||||
|
||||
current_process = next_process;
|
||||
|
||||
uint32_t current_cr3 = fetch_cr3();
|
||||
if (current_cr3 != process_table[current_process].cr3) {
|
||||
load_pd((void*)process_table[current_process].cr3);
|
||||
if (current_cr3 != current_process->cr3) {
|
||||
load_pd((void*)current_process->cr3);
|
||||
}
|
||||
|
||||
if (process_table[current_process].flags & PROCESS_FLAG_USER) {
|
||||
tss.esp0 = process_table[current_process].kstack_top;
|
||||
if (current_process->flags & PROCESS_FLAG_USER) {
|
||||
tss.esp0 = current_process->kstack_top;
|
||||
}
|
||||
|
||||
return process_table[current_process].esp;
|
||||
return current_process->esp;
|
||||
}
|
||||
|
||||
void init_scheduler() {
|
||||
process_table = kalloc(16 * sizeof(process_t));
|
||||
memset((void*)process_table, 0, 16 * sizeof(process_t));
|
||||
total_processes = 0;
|
||||
process_t* root = kalloc(sizeof(process_t));
|
||||
root->pid = 0;
|
||||
root->esp = 0;
|
||||
root->cr3 = fetch_cr3();
|
||||
root->state = STATE_READY;
|
||||
root->sleep = 0;
|
||||
root->flags = PROCESS_FLAG_KERNEL;
|
||||
root->sched_next = NULL;
|
||||
|
||||
process_t* process = &process_table[total_processes];
|
||||
process->pid = total_processes;
|
||||
process->esp = 0;
|
||||
process->cr3 = fetch_cr3();
|
||||
process->state = STATE_READY;
|
||||
process->sleep = 0;
|
||||
process->flags = PROCESS_FLAG_KERNEL;
|
||||
total_processes++;
|
||||
current_process = root;
|
||||
idle_task = root;
|
||||
process_table = root;
|
||||
|
||||
current_process = 0;
|
||||
total_processes = 1;
|
||||
}
|
||||
|
||||
int create_task(uint32_t entry_point, uint32_t cr3, int user, uint32_t u_esp) {
|
||||
if (total_processes >= 16) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
// default to a new task, but if we find a dead one, re use it
|
||||
process_t* process = &process_table[total_processes];
|
||||
uint32_t pid = total_processes;
|
||||
process->pid = pid;
|
||||
void init_task (
|
||||
process_t* process,
|
||||
uint32_t entry_point,
|
||||
uint32_t cr3,
|
||||
int user,
|
||||
uint32_t u_esp
|
||||
) {
|
||||
process->pid = get_next_pid();
|
||||
process->cr3 = cr3;
|
||||
process->state = STATE_READY;
|
||||
process->sleep = 0;
|
||||
@@ -145,32 +142,61 @@ int create_task(uint32_t entry_point, uint32_t cr3, int user, uint32_t u_esp) {
|
||||
}
|
||||
|
||||
process->esp = (uint32_t)esp;
|
||||
return 1;
|
||||
}
|
||||
|
||||
int get_next_pid() {
|
||||
lock_scheduler();
|
||||
int pid = total_processes;
|
||||
total_processes++;
|
||||
unlock_scheduler();
|
||||
return pid;
|
||||
}
|
||||
|
||||
void add_task(process_t* task) {
|
||||
lock_scheduler();
|
||||
|
||||
if (!task) {
|
||||
unlock_scheduler();
|
||||
return;
|
||||
}
|
||||
|
||||
if (process_table->sched_next == NULL) {
|
||||
process_table->sched_next = task;
|
||||
task->sched_next = process_table;
|
||||
unlock_scheduler();
|
||||
return;
|
||||
}
|
||||
|
||||
process_t* curr = process_table;
|
||||
while (curr->sched_next != process_table) {
|
||||
curr = curr->sched_next;
|
||||
}
|
||||
|
||||
curr->sched_next = task;
|
||||
task->sched_next = process_table;
|
||||
|
||||
unlock_scheduler();
|
||||
}
|
||||
|
||||
process_t* current_task() {
|
||||
lock_scheduler();
|
||||
process_t* rtn = &process_table[current_process];
|
||||
process_t* rtn = current_process;
|
||||
unlock_scheduler();
|
||||
return rtn;
|
||||
}
|
||||
|
||||
process_t* current_task_unsafe() {
|
||||
return &process_table[current_process];
|
||||
}
|
||||
|
||||
void sleep(uint32_t ms) {
|
||||
if (ms == 0) return;
|
||||
lock_scheduler();
|
||||
process_table[current_process].sleep = ms;
|
||||
process_table[current_process].state = STATE_SLEEPING;
|
||||
current_process->sleep = ms;
|
||||
current_process->state = STATE_SLEEPING;
|
||||
yield();
|
||||
unlock_scheduler();
|
||||
}
|
||||
|
||||
void exit() {
|
||||
lock_scheduler();
|
||||
process_table[current_process].state = STATE_DEAD;
|
||||
current_process->state = STATE_DEAD;
|
||||
yield(); // yield forever
|
||||
unlock_scheduler();
|
||||
}
|
||||
|
||||
@@ -5,10 +5,13 @@
|
||||
#include <stdint.h>
|
||||
|
||||
void init_scheduler();
|
||||
void init_task(process_t* process, uint32_t entry_point, uint32_t cr3, int user, uint32_t u_esp);
|
||||
|
||||
int create_task(uint32_t entry_point, uint32_t cr3, int user, uint32_t u_esp);
|
||||
process_t* current_task();
|
||||
|
||||
int get_next_pid();
|
||||
void add_task(process_t* task);
|
||||
|
||||
void sleep(uint32_t ms);
|
||||
void yield();
|
||||
void exit();
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
56
kernel/vfs.c
56
kernel/vfs.c
@@ -1,9 +1,8 @@
|
||||
#include "vfs.h"
|
||||
#include <vfs.h>
|
||||
#include <process.h>
|
||||
#include <scheduler.h>
|
||||
|
||||
#include "lib/memory.h"
|
||||
|
||||
#define MAX_PROCESS_FDS 32
|
||||
file_t fd_table[MAX_PROCESS_FDS];
|
||||
#include <lib/memory.h>
|
||||
|
||||
vfs_node_t* root = NULL;
|
||||
|
||||
@@ -46,23 +45,22 @@ static vfs_node_t* lookup(const char* path) {
|
||||
int open(const char* _path, int flags) {
|
||||
vfs_node_t* file = lookup(_path);
|
||||
if (!file) return -1;
|
||||
for (int i = 0; i < MAX_PROCESS_FDS; i++) {
|
||||
if (fd_table[i].node == NULL) {
|
||||
fd_table[i].node = file;
|
||||
fd_table[i].offset = 0;
|
||||
fd_table[i].flags = flags;
|
||||
return i;
|
||||
}
|
||||
}
|
||||
return -1;
|
||||
|
||||
file_t* f = (file_t*)kalloc(sizeof(file_t));
|
||||
f->node = file;
|
||||
f->offset = 0;
|
||||
f->flags = flags;
|
||||
|
||||
return alloc_fd(f);
|
||||
}
|
||||
|
||||
int read(int fd, void* buf, size_t sz) {
|
||||
if (fd < 0 || fd >= MAX_PROCESS_FDS || !fd_table[fd].node) {
|
||||
process_t* curr_p = current_task();
|
||||
if (fd < 0 || fd >= MAX_PROCESS_FDS || !curr_p->fd_table[fd]->node) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
file_t* file = &fd_table[fd];
|
||||
file_t* file = curr_p->fd_table[fd];
|
||||
|
||||
if (!file->node->read) return -1;
|
||||
|
||||
@@ -73,21 +71,37 @@ int read(int fd, void* buf, size_t sz) {
|
||||
}
|
||||
|
||||
int fstat(int fd, file_t* dst) {
|
||||
if (fd < 0 || fd >= MAX_PROCESS_FDS || !fd_table[fd].node) {
|
||||
process_t* curr_p = current_task();
|
||||
if (fd < 0 || fd >= MAX_PROCESS_FDS || !curr_p->fd_table[fd]->node) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
file_t* src = &fd_table[fd];
|
||||
file_t* src = curr_p->fd_table[fd];
|
||||
memcpy(src, dst, sizeof(file_t));
|
||||
return 1;
|
||||
}
|
||||
|
||||
int fseek(int fd, size_t offset) {
|
||||
if (fd < 0 || fd >= MAX_PROCESS_FDS || !fd_table[fd].node) {
|
||||
process_t* curr_p = current_task();
|
||||
if (fd < 0 || fd >= MAX_PROCESS_FDS || !curr_p->fd_table[fd]->node) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
file_t* file = &fd_table[fd];
|
||||
file_t* file = curr_p->fd_table[fd];
|
||||
file->offset = offset;
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
|
||||
int alloc_fd(file_t* f) {
|
||||
process_t* curr_p = current_task();
|
||||
if (!curr_p) return -1;
|
||||
|
||||
for (int i = 0; i < MAX_PROCESS_FDS; i++) {
|
||||
if (curr_p->fd_table[i] == NULL) {
|
||||
curr_p->fd_table[i] = f;
|
||||
return i;
|
||||
}
|
||||
}
|
||||
|
||||
return -1;
|
||||
}
|
||||
@@ -44,4 +44,6 @@ int read(int fd, void* buf, size_t sz);
|
||||
int fstat(int fd, file_t* _f);
|
||||
int fseek(int fd, size_t offset);
|
||||
|
||||
int alloc_fd(file_t* f);
|
||||
|
||||
#endif
|
||||
Reference in New Issue
Block a user