starting to work on pty drivers, fork(), and scheduler redesign
This commit is contained in:
@@ -9,9 +9,21 @@ cp rocklibc/rlibc.a programs/lib
|
|||||||
cd programs
|
cd programs
|
||||||
|
|
||||||
cd rocksh
|
cd rocksh
|
||||||
|
|
||||||
make clean
|
make clean
|
||||||
bear -- make
|
bear -- make
|
||||||
cp rocksh.elf ../bin
|
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 ..
|
||||||
@@ -84,6 +84,23 @@
|
|||||||
"file": "/home/slinky/source/RockOS/kernel/drivers/cpio/cpio.c",
|
"file": "/home/slinky/source/RockOS/kernel/drivers/cpio/cpio.c",
|
||||||
"output": "/home/slinky/source/RockOS/obj/kernel/drivers/cpio/cpio.c.o"
|
"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": [
|
"arguments": [
|
||||||
"/home/slinky/opt/cross/bin/i686-elf-gcc",
|
"/home/slinky/opt/cross/bin/i686-elf-gcc",
|
||||||
@@ -305,6 +322,23 @@
|
|||||||
"file": "/home/slinky/source/RockOS/kernel/lib/print.c",
|
"file": "/home/slinky/source/RockOS/kernel/lib/print.c",
|
||||||
"output": "/home/slinky/source/RockOS/obj/kernel/lib/print.c.o"
|
"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": [
|
"arguments": [
|
||||||
"/home/slinky/opt/cross/bin/i686-elf-gcc",
|
"/home/slinky/opt/cross/bin/i686-elf-gcc",
|
||||||
|
|||||||
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; // argv = NULL
|
||||||
*(--u_esp) = 0; // argc = 0
|
*(--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();
|
enable_interrupts();
|
||||||
|
|
||||||
load_pd((void*)kernel_cr3);
|
load_pd((void*)kernel_cr3);
|
||||||
@@ -173,6 +175,6 @@ void kmain(uint32_t magic, multiboot_info* mbi) {
|
|||||||
init_scheduler();
|
init_scheduler();
|
||||||
enable_interrupts();
|
enable_interrupts();
|
||||||
|
|
||||||
kprintf("loading rocksh...\n");
|
kprintf("loading test program\n");
|
||||||
load_root_program("/rocksh.elf");
|
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 "memory/mm.h"
|
||||||
#include "lib/print.h"
|
|
||||||
#include "multiboot.h"
|
#include "multiboot.h"
|
||||||
|
|
||||||
#include <stddef.h>
|
#include <stddef.h>
|
||||||
|
#include <lib/string.h>
|
||||||
|
|
||||||
extern uint8_t __kernel_start;
|
extern uint8_t __kernel_start;
|
||||||
extern uint8_t __kernel_end;
|
extern uint8_t __kernel_end;
|
||||||
@@ -17,6 +17,8 @@ extern uint32_t page_directory[1024];
|
|||||||
#define PAGE_DIRECTORY 0xFFFFF000
|
#define PAGE_DIRECTORY 0xFFFFF000
|
||||||
|
|
||||||
#define TEMP_MAPPING_VADDR 0xDFFF0000
|
#define TEMP_MAPPING_VADDR 0xDFFF0000
|
||||||
|
#define TEMP_COPY_SRC 0xDFFE0000 // Safely 1 page down
|
||||||
|
#define TEMP_COPY_DST 0xDFFD0000
|
||||||
|
|
||||||
#define USR_PAGE 0x07
|
#define USR_PAGE 0x07
|
||||||
#define SUP_PAGE 0x03
|
#define SUP_PAGE 0x03
|
||||||
@@ -191,3 +193,76 @@ void* create_task_pd() {
|
|||||||
kernel_pt[pte] = 0;
|
kernel_pt[pte] = 0;
|
||||||
return (void*)pd_address;
|
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();
|
uint32_t total_free_memory();
|
||||||
|
|
||||||
void* create_task_pd();
|
void* create_task_pd();
|
||||||
|
void* clone_task_pd();
|
||||||
|
|
||||||
void map_page(uint32_t vaddr, uint32_t paddr, uint32_t flags);
|
void map_page(uint32_t vaddr, uint32_t paddr, uint32_t flags);
|
||||||
|
|
||||||
|
|||||||
@@ -3,6 +3,10 @@
|
|||||||
|
|
||||||
#include <stdint.h>
|
#include <stdint.h>
|
||||||
|
|
||||||
|
#include <vfs.h>
|
||||||
|
|
||||||
|
#define MAX_PROCESS_FDS 32
|
||||||
|
|
||||||
typedef enum {
|
typedef enum {
|
||||||
STATE_READY = 1,
|
STATE_READY = 1,
|
||||||
STATE_SLEEPING = 2,
|
STATE_SLEEPING = 2,
|
||||||
@@ -16,7 +20,8 @@ typedef enum {
|
|||||||
PROCESS_FLAG_USER = 1 << 1
|
PROCESS_FLAG_USER = 1 << 1
|
||||||
} process_flags_t;
|
} process_flags_t;
|
||||||
|
|
||||||
typedef struct {
|
struct process_t;
|
||||||
|
typedef struct process_t {
|
||||||
uint32_t pid;
|
uint32_t pid;
|
||||||
uint32_t esp;
|
uint32_t esp;
|
||||||
uint32_t kstack_top;
|
uint32_t kstack_top;
|
||||||
@@ -25,6 +30,8 @@ typedef struct {
|
|||||||
uint32_t sleep;
|
uint32_t sleep;
|
||||||
uint32_t heap_end;
|
uint32_t heap_end;
|
||||||
uint32_t flags;
|
uint32_t flags;
|
||||||
|
file_t* fd_table[MAX_PROCESS_FDS];
|
||||||
|
struct process_t* sched_next;
|
||||||
} __attribute__((packed)) process_t;
|
} __attribute__((packed)) process_t;
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
@@ -11,13 +11,12 @@
|
|||||||
#include "scheduler.h"
|
#include "scheduler.h"
|
||||||
#include "gdt.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;
|
static int total_processes = 0;
|
||||||
|
|
||||||
#define IDLE_TASK_PID 0
|
|
||||||
|
|
||||||
static void lock_scheduler() {
|
static void lock_scheduler() {
|
||||||
disable_interrupts();
|
disable_interrupts();
|
||||||
}
|
}
|
||||||
@@ -26,9 +25,8 @@ static void unlock_scheduler() {
|
|||||||
enable_interrupts();
|
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) {
|
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++) {
|
for (int i = 0; i < total_processes; i++) {
|
||||||
if (process_table[i].state == STATE_SLEEPING) {
|
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;
|
int found_ready = 0;
|
||||||
|
|
||||||
while (1) {
|
while (1) {
|
||||||
next_process = (next_process + 1) % total_processes;
|
next_process = (process_t*)next_process->sched_next;
|
||||||
if (next_process != IDLE_TASK_PID && process_table[next_process].state == STATE_READY) {
|
if (next_process != idle_task && next_process->state == STATE_READY) {
|
||||||
found_ready = 1;
|
found_ready = 1;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@@ -58,53 +56,52 @@ uint32_t switch_context(uint32_t current_esp) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (!found_ready) {
|
if (!found_ready) {
|
||||||
if (process_table[current_process].state == STATE_READY) {
|
if (current_process->state == STATE_READY) {
|
||||||
next_process = current_process;
|
next_process = current_process;
|
||||||
} else {
|
} else {
|
||||||
next_process = IDLE_TASK_PID;
|
next_process = idle_task;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
current_process = next_process;
|
current_process = next_process;
|
||||||
|
|
||||||
uint32_t current_cr3 = fetch_cr3();
|
uint32_t current_cr3 = fetch_cr3();
|
||||||
if (current_cr3 != process_table[current_process].cr3) {
|
if (current_cr3 != current_process->cr3) {
|
||||||
load_pd((void*)process_table[current_process].cr3);
|
load_pd((void*)current_process->cr3);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (process_table[current_process].flags & PROCESS_FLAG_USER) {
|
if (current_process->flags & PROCESS_FLAG_USER) {
|
||||||
tss.esp0 = process_table[current_process].kstack_top;
|
tss.esp0 = current_process->kstack_top;
|
||||||
}
|
}
|
||||||
|
|
||||||
return process_table[current_process].esp;
|
return current_process->esp;
|
||||||
}
|
}
|
||||||
|
|
||||||
void init_scheduler() {
|
void init_scheduler() {
|
||||||
process_table = kalloc(16 * sizeof(process_t));
|
process_t* root = kalloc(sizeof(process_t));
|
||||||
memset((void*)process_table, 0, 16 * sizeof(process_t));
|
root->pid = 0;
|
||||||
total_processes = 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];
|
current_process = root;
|
||||||
process->pid = total_processes;
|
idle_task = root;
|
||||||
process->esp = 0;
|
process_table = root;
|
||||||
process->cr3 = fetch_cr3();
|
|
||||||
process->state = STATE_READY;
|
|
||||||
process->sleep = 0;
|
|
||||||
process->flags = PROCESS_FLAG_KERNEL;
|
|
||||||
total_processes++;
|
|
||||||
|
|
||||||
current_process = 0;
|
total_processes = 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
int create_task(uint32_t entry_point, uint32_t cr3, int user, uint32_t u_esp) {
|
void init_task (
|
||||||
if (total_processes >= 16) {
|
process_t* process,
|
||||||
return 0;
|
uint32_t entry_point,
|
||||||
}
|
uint32_t cr3,
|
||||||
|
int user,
|
||||||
// default to a new task, but if we find a dead one, re use it
|
uint32_t u_esp
|
||||||
process_t* process = &process_table[total_processes];
|
) {
|
||||||
uint32_t pid = total_processes;
|
process->pid = get_next_pid();
|
||||||
process->pid = pid;
|
|
||||||
process->cr3 = cr3;
|
process->cr3 = cr3;
|
||||||
process->state = STATE_READY;
|
process->state = STATE_READY;
|
||||||
process->sleep = 0;
|
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;
|
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() {
|
process_t* current_task() {
|
||||||
lock_scheduler();
|
lock_scheduler();
|
||||||
process_t* rtn = &process_table[current_process];
|
process_t* rtn = current_process;
|
||||||
unlock_scheduler();
|
unlock_scheduler();
|
||||||
return rtn;
|
return rtn;
|
||||||
}
|
}
|
||||||
|
|
||||||
process_t* current_task_unsafe() {
|
|
||||||
return &process_table[current_process];
|
|
||||||
}
|
|
||||||
|
|
||||||
void sleep(uint32_t ms) {
|
void sleep(uint32_t ms) {
|
||||||
if (ms == 0) return;
|
if (ms == 0) return;
|
||||||
lock_scheduler();
|
lock_scheduler();
|
||||||
process_table[current_process].sleep = ms;
|
current_process->sleep = ms;
|
||||||
process_table[current_process].state = STATE_SLEEPING;
|
current_process->state = STATE_SLEEPING;
|
||||||
yield();
|
yield();
|
||||||
unlock_scheduler();
|
unlock_scheduler();
|
||||||
}
|
}
|
||||||
|
|
||||||
void exit() {
|
void exit() {
|
||||||
lock_scheduler();
|
lock_scheduler();
|
||||||
process_table[current_process].state = STATE_DEAD;
|
current_process->state = STATE_DEAD;
|
||||||
yield(); // yield forever
|
yield(); // yield forever
|
||||||
unlock_scheduler();
|
unlock_scheduler();
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -5,10 +5,13 @@
|
|||||||
#include <stdint.h>
|
#include <stdint.h>
|
||||||
|
|
||||||
void init_scheduler();
|
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();
|
process_t* current_task();
|
||||||
|
|
||||||
|
int get_next_pid();
|
||||||
|
void add_task(process_t* task);
|
||||||
|
|
||||||
void sleep(uint32_t ms);
|
void sleep(uint32_t ms);
|
||||||
void yield();
|
void yield();
|
||||||
void exit();
|
void exit();
|
||||||
|
|||||||
133
kernel/syscall.c
133
kernel/syscall.c
@@ -1,52 +1,57 @@
|
|||||||
#include <stdint.h>
|
#include <stdint.h>
|
||||||
#include <stddef.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 "memory/mm.h"
|
||||||
#include "process.h"
|
#include "process.h"
|
||||||
#include "scheduler.h"
|
#include "scheduler.h"
|
||||||
#include "kbd.h"
|
#include "vfs.h"
|
||||||
|
|
||||||
#include <drivers/vga/vga.h>
|
#include <drivers/vga/vga.h>
|
||||||
|
|
||||||
#include <lib/print.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) {
|
static int32_t sys_exit(int status) {
|
||||||
process_t* task = current_task();
|
process_t* task = current_task();
|
||||||
task->state = STATE_DEAD;
|
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();
|
exit();
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int32_t sys_write(int fd, const void* buf, size_t count) {
|
static int32_t sys_write(int fd, const void* buf, size_t count) {
|
||||||
if (fd == 1 || fd == 2) { // stdout or stderr
|
if (fd < 0 || fd >= MAX_PROCESS_FDS) return -1;
|
||||||
const char* cbuf = (const char*)buf;
|
|
||||||
for (size_t i = 0; i < count; i++) {
|
file_t* f = current_task()->fd_table[fd];
|
||||||
vga_putchar(cbuf[i]);
|
if (!f || !f->node) return -1;
|
||||||
}
|
|
||||||
return count;
|
uint32_t rd = f->node->write(f->node, f->offset, count, (uint8_t*)buf);
|
||||||
}
|
f->offset += rd;
|
||||||
return -1;
|
|
||||||
|
return rd;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int32_t sys_read(int fd, void* buf, size_t count) {
|
static int32_t sys_read(int fd, void* buf, size_t count) {
|
||||||
if (fd == 0) {
|
if (fd < 0 || fd >= MAX_PROCESS_FDS) return -1;
|
||||||
char* cbuf = (char*)buf;
|
|
||||||
size_t bytes_read = 0;
|
|
||||||
|
|
||||||
while (bytes_read < count) {
|
file_t* f = current_task()->fd_table[fd];
|
||||||
kbd_wait();
|
if (!f || !f->node) return -1;
|
||||||
|
|
||||||
if (kbd_ready()) {
|
uint32_t rd = f->node->read(f->node, f->offset, count, (uint8_t*)buf);
|
||||||
char c = kbd_read();
|
f->offset += rd;
|
||||||
cbuf[bytes_read++] = c;
|
|
||||||
if (c == '\n') break;
|
return rd;
|
||||||
}
|
|
||||||
}
|
|
||||||
return bytes_read;
|
|
||||||
}
|
|
||||||
return -1;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static int32_t sys_open(const char* filename, int flags) {
|
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;
|
return current->heap_end;
|
||||||
}
|
}
|
||||||
|
|
||||||
typedef struct registers {
|
static int32_t sys_pty(int* slave_fd) {
|
||||||
uint32_t gs, fs, es, ds; // Pushed manually
|
pty_t* pty = (pty_t*)kalloc(sizeof(pty_t));
|
||||||
uint32_t edi, esi, ebp, esp, ebx, edx, ecx, eax; // Pushed by pusha
|
ring_buf_init(&pty->master_rb);
|
||||||
uint32_t int_no, err_code; // Pushed manually
|
ring_buf_init(&pty->slave_rb);
|
||||||
uint32_t eip, cs, eflags, useresp, ss; // Pushed automatically by CPU
|
|
||||||
} registers_t;
|
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) {
|
int32_t syscall(registers_t* regs) {
|
||||||
switch(regs->eax) {
|
switch(regs->eax) {
|
||||||
case 1: return sys_exit(regs->ebx);
|
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 5: return sys_open((const char*)regs->ebx, regs->ecx);
|
||||||
case 6: return sys_close(regs->ebx);
|
case 6: return sys_close(regs->ebx);
|
||||||
case 12: return sys_brk(regs->ebx);
|
case 12: return sys_brk(regs->ebx);
|
||||||
|
case 20: return sys_pty((int*)regs->ebx);
|
||||||
|
case 21: return sys_fork(regs);
|
||||||
default:
|
default:
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|||||||
54
kernel/vfs.c
54
kernel/vfs.c
@@ -1,9 +1,8 @@
|
|||||||
#include "vfs.h"
|
#include <vfs.h>
|
||||||
|
#include <process.h>
|
||||||
|
#include <scheduler.h>
|
||||||
|
|
||||||
#include "lib/memory.h"
|
#include <lib/memory.h>
|
||||||
|
|
||||||
#define MAX_PROCESS_FDS 32
|
|
||||||
file_t fd_table[MAX_PROCESS_FDS];
|
|
||||||
|
|
||||||
vfs_node_t* root = NULL;
|
vfs_node_t* root = NULL;
|
||||||
|
|
||||||
@@ -46,23 +45,22 @@ static vfs_node_t* lookup(const char* path) {
|
|||||||
int open(const char* _path, int flags) {
|
int open(const char* _path, int flags) {
|
||||||
vfs_node_t* file = lookup(_path);
|
vfs_node_t* file = lookup(_path);
|
||||||
if (!file) return -1;
|
if (!file) return -1;
|
||||||
for (int i = 0; i < MAX_PROCESS_FDS; i++) {
|
|
||||||
if (fd_table[i].node == NULL) {
|
file_t* f = (file_t*)kalloc(sizeof(file_t));
|
||||||
fd_table[i].node = file;
|
f->node = file;
|
||||||
fd_table[i].offset = 0;
|
f->offset = 0;
|
||||||
fd_table[i].flags = flags;
|
f->flags = flags;
|
||||||
return i;
|
|
||||||
}
|
return alloc_fd(f);
|
||||||
}
|
|
||||||
return -1;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
int read(int fd, void* buf, size_t sz) {
|
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;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
file_t* file = &fd_table[fd];
|
file_t* file = curr_p->fd_table[fd];
|
||||||
|
|
||||||
if (!file->node->read) return -1;
|
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) {
|
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;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
file_t* src = &fd_table[fd];
|
file_t* src = curr_p->fd_table[fd];
|
||||||
memcpy(src, dst, sizeof(file_t));
|
memcpy(src, dst, sizeof(file_t));
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
int fseek(int fd, size_t offset) {
|
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;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
file_t* file = &fd_table[fd];
|
file_t* file = curr_p->fd_table[fd];
|
||||||
file->offset = offset;
|
file->offset = offset;
|
||||||
return 1;
|
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 fstat(int fd, file_t* _f);
|
||||||
int fseek(int fd, size_t offset);
|
int fseek(int fd, size_t offset);
|
||||||
|
|
||||||
|
int alloc_fd(file_t* f);
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
Binary file not shown.
36
programs/test/compile_commands.json
Normal file
36
programs/test/compile_commands.json
Normal 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
21
programs/test/crt0.S
Normal 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
31
programs/test/linker.ld
Normal 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
12
programs/test/main.c
Normal 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
23
programs/test/makefile
Normal 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
|
||||||
36
programs/vga_text_term/compile_commands.json
Normal file
36
programs/vga_text_term/compile_commands.json
Normal 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"
|
||||||
|
}
|
||||||
|
]
|
||||||
21
programs/vga_text_term/crt0.S
Normal file
21
programs/vga_text_term/crt0.S
Normal 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/vga_text_term/linker.ld
Normal file
31
programs/vga_text_term/linker.ld
Normal 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 = .;
|
||||||
|
}
|
||||||
|
}
|
||||||
5
programs/vga_text_term/main.c
Normal file
5
programs/vga_text_term/main.c
Normal file
@@ -0,0 +1,5 @@
|
|||||||
|
#include <stdio.h>
|
||||||
|
|
||||||
|
int main(int argc, char *argv[]) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
23
programs/vga_text_term/makefile
Normal file
23
programs/vga_text_term/makefile
Normal 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
|
||||||
104
programs/vga_text_term/syscall.c
Normal file
104
programs/vga_text_term/syscall.c
Normal 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;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -4,9 +4,11 @@
|
|||||||
#include <stdint.h>
|
#include <stdint.h>
|
||||||
#include <stddef.h>
|
#include <stddef.h>
|
||||||
|
|
||||||
#define SYS_EXIT 1
|
#define SYS_EXIT 1
|
||||||
#define SYS_READ 3
|
#define SYS_READ 3
|
||||||
#define SYS_WRITE 4
|
#define SYS_WRITE 4
|
||||||
|
#define SYS_PTY 20
|
||||||
|
#define SYS_FORK 21
|
||||||
|
|
||||||
int write(int fd, const void *buf, size_t count);
|
int write(int fd, const void *buf, size_t count);
|
||||||
int read(int fd, 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);
|
void *sbrk(intptr_t increment);
|
||||||
int brk(void *addr);
|
int brk(void *addr);
|
||||||
|
|
||||||
|
int pty(int* slave);
|
||||||
|
int fork();
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
@@ -35,3 +35,11 @@ int write(int fd, const void* buf, size_t cnt) {
|
|||||||
int read(int fd, 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);
|
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);
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user