starting to work on pty drivers, fork(), and scheduler redesign

This commit is contained in:
2026-07-07 00:13:24 -05:00
parent 6d7a23d747
commit 177a0b8fe9
29 changed files with 859 additions and 111 deletions

View File

@@ -9,9 +9,21 @@ cp rocklibc/rlibc.a programs/lib
cd programs
cd rocksh
make clean
bear -- make
cp rocksh.elf ../bin
cd ..
cd ../..
cd vga_text_term
make clean
bear -- make
cp vga_text_term.elf ../bin
cd ..
cd test
make clean
bear -- make
cp test.elf ../bin
cd ..
cd ..

View File

@@ -84,6 +84,23 @@
"file": "/home/slinky/source/RockOS/kernel/drivers/cpio/cpio.c",
"output": "/home/slinky/source/RockOS/obj/kernel/drivers/cpio/cpio.c.o"
},
{
"arguments": [
"/home/slinky/opt/cross/bin/i686-elf-gcc",
"-c",
"-ffreestanding",
"-O2",
"-Wall",
"-Wextra",
"-Ikernel",
"-o",
"obj/kernel/drivers/pty/pty.c.o",
"kernel/drivers/pty/pty.c"
],
"directory": "/home/slinky/source/RockOS",
"file": "/home/slinky/source/RockOS/kernel/drivers/pty/pty.c",
"output": "/home/slinky/source/RockOS/obj/kernel/drivers/pty/pty.c.o"
},
{
"arguments": [
"/home/slinky/opt/cross/bin/i686-elf-gcc",
@@ -305,6 +322,23 @@
"file": "/home/slinky/source/RockOS/kernel/lib/print.c",
"output": "/home/slinky/source/RockOS/obj/kernel/lib/print.c.o"
},
{
"arguments": [
"/home/slinky/opt/cross/bin/i686-elf-gcc",
"-c",
"-ffreestanding",
"-O2",
"-Wall",
"-Wextra",
"-Ikernel",
"-o",
"obj/kernel/lib/ringbuf.c.o",
"kernel/lib/ringbuf.c"
],
"directory": "/home/slinky/source/RockOS",
"file": "/home/slinky/source/RockOS/kernel/lib/ringbuf.c",
"output": "/home/slinky/source/RockOS/obj/kernel/lib/ringbuf.c.o"
},
{
"arguments": [
"/home/slinky/opt/cross/bin/i686-elf-gcc",

62
kernel/drivers/pty/pty.c Normal file
View 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
View 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

View File

@@ -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
View 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
View 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

View File

@@ -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
@@ -191,3 +193,76 @@ void* create_task_pd() {
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;
}

View File

@@ -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);

View File

@@ -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

View File

@@ -11,13 +11,12 @@
#include "scheduler.h"
#include "gdt.h"
static process_t* process_table;
static process_t* process_table = NULL;
static process_t* current_process = NULL;
static process_t* idle_task = NULL;
static int current_process = 0;
static int total_processes = 0;
#define IDLE_TASK_PID 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();
}

View File

@@ -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();

View File

@@ -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();
file_t* f = current_task()->fd_table[fd];
if (!f || !f->node) return -1;
if (kbd_ready()) {
char c = kbd_read();
cbuf[bytes_read++] = c;
if (c == '\n') break;
}
}
return bytes_read;
}
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;
}

View File

@@ -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;
}

View File

@@ -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

Binary file not shown.

View File

@@ -0,0 +1,36 @@
[
{
"arguments": [
"/home/slinky/opt/cross/bin/i686-elf-gcc",
"-ffreestanding",
"-O2",
"-Wall",
"-Wextra",
"-I../../rocklibc/include",
"-c",
"-o",
"crt0.o",
"crt0.S"
],
"directory": "/home/slinky/source/RockOS/programs/test",
"file": "/home/slinky/source/RockOS/programs/test/crt0.S",
"output": "/home/slinky/source/RockOS/programs/test/crt0.o"
},
{
"arguments": [
"/home/slinky/opt/cross/bin/i686-elf-gcc",
"-ffreestanding",
"-O2",
"-Wall",
"-Wextra",
"-I../../rocklibc/include",
"-c",
"-o",
"main.o",
"main.c"
],
"directory": "/home/slinky/source/RockOS/programs/test",
"file": "/home/slinky/source/RockOS/programs/test/main.c",
"output": "/home/slinky/source/RockOS/programs/test/main.o"
}
]

21
programs/test/crt0.S Normal file
View File

@@ -0,0 +1,21 @@
.global _start
.extern exit
.section .text
_start:
xor %ebp, %ebp
mov (%esp), %eax
lea 4(%esp), %ebx
lea 8(%esp,%eax,4), %ecx
and $-16, %esp
push %ecx
push %ebx
push %eax
call main
push %eax
call exit

31
programs/test/linker.ld Normal file
View File

@@ -0,0 +1,31 @@
ENTRY(_start)
SECTIONS
{
. = 0x40000000;
.text ALIGN(4K) :
{
/* Force the crt0.o entry code to be placed FIRST in memory */
KEEP(*crt0.o(.text))
*(.text .text.*)
}
.rodata ALIGN(4K) :
{
*(.rodata .rodata.*)
}
.data ALIGN(4K) :
{
*(.data .data.*)
}
.bss ALIGN(4K) :
{
_bss_start = .;
*(.bss .bss.*)
*(COMMON)
_bss_end = .;
}
}

12
programs/test/main.c Normal file
View File

@@ -0,0 +1,12 @@
#include <unistd.h>
int main(int argc, char *argv[]) {
(void)argc;
(void)argv;
if (!fork()) {
exit(1);
}
return 0;
}

23
programs/test/makefile Normal file
View File

@@ -0,0 +1,23 @@
CC = i686-elf-gcc
LD = i686-elf-ld
CFLAGS = -ffreestanding -O2 -Wall -Wextra -I../../rocklibc/include
LDFLAGS = -m elf_i386 -nostdlib
TARGET = test.elf
all: $(TARGET)
crt0.o: crt0.S
$(CC) $(CFLAGS) -c crt0.S -o crt0.o
main.o: main.c
$(CC) $(CFLAGS) -c main.c -o main.o
$(TARGET): crt0.o main.o ../lib/rlibc.a
$(LD) $(LDFLAGS) -T linker.ld crt0.o main.o ../lib/rlibc.a -o $(TARGET)
clean:
rm -f *.o $(TARGET)
.PHONY: all clean test

View File

@@ -0,0 +1,36 @@
[
{
"arguments": [
"/home/slinky/opt/cross/bin/i686-elf-gcc",
"-ffreestanding",
"-O2",
"-Wall",
"-Wextra",
"-I../../rocklibc/include",
"-c",
"-o",
"crt0.o",
"crt0.S"
],
"directory": "/home/slinky/source/RockOS/programs/vga_text_term",
"file": "/home/slinky/source/RockOS/programs/vga_text_term/crt0.S",
"output": "/home/slinky/source/RockOS/programs/vga_text_term/crt0.o"
},
{
"arguments": [
"/home/slinky/opt/cross/bin/i686-elf-gcc",
"-ffreestanding",
"-O2",
"-Wall",
"-Wextra",
"-I../../rocklibc/include",
"-c",
"-o",
"main.o",
"main.c"
],
"directory": "/home/slinky/source/RockOS/programs/vga_text_term",
"file": "/home/slinky/source/RockOS/programs/vga_text_term/main.c",
"output": "/home/slinky/source/RockOS/programs/vga_text_term/main.o"
}
]

View File

@@ -0,0 +1,21 @@
.global _start
.extern exit
.section .text
_start:
xor %ebp, %ebp
mov (%esp), %eax
lea 4(%esp), %ebx
lea 8(%esp,%eax,4), %ecx
and $-16, %esp
push %ecx
push %ebx
push %eax
call main
push %eax
call exit

View File

@@ -0,0 +1,31 @@
ENTRY(_start)
SECTIONS
{
. = 0x40000000;
.text ALIGN(4K) :
{
/* Force the crt0.o entry code to be placed FIRST in memory */
KEEP(*crt0.o(.text))
*(.text .text.*)
}
.rodata ALIGN(4K) :
{
*(.rodata .rodata.*)
}
.data ALIGN(4K) :
{
*(.data .data.*)
}
.bss ALIGN(4K) :
{
_bss_start = .;
*(.bss .bss.*)
*(COMMON)
_bss_end = .;
}
}

View File

@@ -0,0 +1,5 @@
#include <stdio.h>
int main(int argc, char *argv[]) {
return 0;
}

View File

@@ -0,0 +1,23 @@
CC = i686-elf-gcc
LD = i686-elf-ld
CFLAGS = -ffreestanding -O2 -Wall -Wextra -I../../rocklibc/include
LDFLAGS = -m elf_i386 -nostdlib
TARGET = vga_text_term.elf
all: $(TARGET)
crt0.o: crt0.S
$(CC) $(CFLAGS) -c crt0.S -o crt0.o
main.o: main.c
$(CC) $(CFLAGS) -c main.c -o main.o
$(TARGET): crt0.o main.o ../lib/rlibc.a
$(LD) $(LDFLAGS) -T linker.ld crt0.o main.o ../lib/rlibc.a -o $(TARGET)
clean:
rm -f *.o $(TARGET)
.PHONY: all clean test

View File

@@ -0,0 +1,104 @@
#include <stdint.h>
#include <stddef.h>
#include "memory/mm.h"
#include "process.h"
#include "scheduler.h"
#include "kbd.h"
#include <drivers/vga/vga.h>
#include <lib/print.h>
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);
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;
}
static int32_t sys_read(int fd, void* buf, size_t count) {
if (fd == 0) {
char* cbuf = (char*)buf;
size_t bytes_read = 0;
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;
}
static int32_t sys_open(const char* filename, int flags) {
return -1;
}
static int32_t sys_close(int fd) {
return -1;
}
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;
}
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;
int32_t syscall(registers_t* regs) {
switch(regs->eax) {
case 1: return sys_exit(regs->ebx);
case 3: return sys_read(regs->ebx, (void*)regs->ecx, regs->edx);
case 4: return sys_write(regs->ebx, (const void*)regs->ecx, regs->edx);
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);
default:
return -1;
}
}

View File

@@ -7,6 +7,8 @@
#define SYS_EXIT 1
#define SYS_READ 3
#define SYS_WRITE 4
#define SYS_PTY 20
#define SYS_FORK 21
int write(int fd, const void *buf, size_t count);
int read(int fd, void *buf, size_t count);
@@ -19,4 +21,7 @@ void exit(int status) __attribute__((noreturn));
void *sbrk(intptr_t increment);
int brk(void *addr);
int pty(int* slave);
int fork();
#endif

View File

@@ -35,3 +35,11 @@ int write(int fd, const void* buf, size_t cnt) {
int read(int fd, void* buf, size_t cnt) {
return syscall3(SYS_READ, (uint32_t)fd, (uint32_t)buf, (uint32_t)cnt);
}
int pty(int* slave) {
return syscall1(SYS_PTY, (uint32_t)slave);
}
int fork() {
return syscall1(SYS_FORK, 0);
}