Added I/O syscalls (read/write) and ring reading
This commit is contained in:
parent
6c9949c2af
commit
cf9c511ff3
@ -52,7 +52,8 @@ OBJS+=$(O)/sys/debug.o \
|
||||
$(O)/sys/fs/pseudo.o \
|
||||
$(O)/sys/fs/tar.o \
|
||||
$(O)/sys/fs/sysfs.o \
|
||||
$(O)/sys/time.o
|
||||
$(O)/sys/time.o \
|
||||
$(O)/sys/sys_file.o
|
||||
|
||||
DIRS+=$(O)/sys/fs \
|
||||
$(O)/sys/dev
|
||||
|
@ -14,6 +14,8 @@ struct ring {
|
||||
size_t cap;
|
||||
char *base;
|
||||
int flags;
|
||||
|
||||
struct thread *reader_head;
|
||||
};
|
||||
|
||||
int ring_readable(struct ring *b);
|
||||
|
@ -35,6 +35,7 @@
|
||||
#define EDOM 33
|
||||
#define ERANGE 34
|
||||
|
||||
#define ENOSYS 38
|
||||
#define ELOOP 40
|
||||
|
||||
#if defined(__KERNEL__)
|
||||
|
5
include/sys/sys_file.h
Normal file
5
include/sys/sys_file.h
Normal file
@ -0,0 +1,5 @@
|
||||
#pragma once
|
||||
#include "sys/types.h"
|
||||
|
||||
ssize_t sys_read(int fd, void *data, size_t lim);
|
||||
ssize_t sys_write(int fd, const void *data, size_t lim);
|
@ -1,5 +1,8 @@
|
||||
#pragma once
|
||||
|
||||
#define SYSCALL_NR_READ 0
|
||||
#define SYSCALL_NR_WRITE 1
|
||||
|
||||
#define SYSCALL_NR_FORK 57
|
||||
int sys_fork(void *ctx);
|
||||
#define SYSCALL_NR_EXIT 60
|
||||
|
@ -1,11 +1,17 @@
|
||||
#pragma once
|
||||
#include "sys/amd64/asm/asm_thread.h"
|
||||
#include "sys/fs/vfs.h"
|
||||
#include "sys/mm.h"
|
||||
|
||||
#define THREAD_MAX_FDS 16
|
||||
|
||||
struct ofile;
|
||||
|
||||
enum thread_state {
|
||||
THREAD_READY = 1,
|
||||
THREAD_RUNNING,
|
||||
THREAD_WAITING,
|
||||
THREAD_WAITING_IO,
|
||||
THREAD_STOPPED
|
||||
};
|
||||
|
||||
@ -14,6 +20,10 @@ struct thread {
|
||||
struct thread_data data;
|
||||
mm_space_t space;
|
||||
|
||||
// I/O
|
||||
struct vfs_ioctx ioctx;
|
||||
struct ofile *fds[THREAD_MAX_FDS];
|
||||
|
||||
// Wait
|
||||
uint64_t sleep_deadline;
|
||||
struct thread *wait_prev, *wait_next;
|
||||
@ -32,4 +42,5 @@ struct thread {
|
||||
pid_t thread_alloc_pid(int is_user);
|
||||
|
||||
void thread_sleep(struct thread *thr, uint64_t deadline);
|
||||
void thread_ioctx_fork(struct thread *dst, struct thread *src);
|
||||
int thread_init(struct thread *thr, uintptr_t entry, void *arg, int user);
|
||||
|
@ -15,6 +15,8 @@
|
||||
#include "sys/amd64/mm/mm.h"
|
||||
#include "sys/amd64/cpu.h"
|
||||
#include "sys/amd64/fpu.h"
|
||||
#include "sys/fs/ofile.h"
|
||||
#include "sys/fs/fcntl.h"
|
||||
#include "sys/fs/node.h"
|
||||
#include "sys/dev/tty.h"
|
||||
#include "sys/dev/ram.h"
|
||||
@ -29,6 +31,7 @@
|
||||
#include "sys/panic.h"
|
||||
#include "sys/debug.h"
|
||||
#include "sys/sched.h"
|
||||
#include "sys/heap.h"
|
||||
#include "sys/time.h"
|
||||
|
||||
static multiboot_info_t *multiboot_info;
|
||||
@ -39,8 +42,8 @@ extern int sys_execve(const char *path, const char **argp, const char **envp);
|
||||
static void user_init_func(void *arg) {
|
||||
kdebug("Starting user init\n");
|
||||
|
||||
struct vfs_ioctx ioctx = {0};
|
||||
struct vnode *root_dev;
|
||||
struct vfs_ioctx *ioctx = &thread_self->ioctx;
|
||||
struct vnode *root_dev, *tty_dev;
|
||||
int res;
|
||||
// Mount root
|
||||
if ((res = dev_find(DEV_CLASS_BLOCK, "ram0", &root_dev)) != 0) {
|
||||
@ -48,11 +51,39 @@ static void user_init_func(void *arg) {
|
||||
panic("Fail\n");
|
||||
}
|
||||
|
||||
if ((res = vfs_mount(&ioctx, "/", root_dev->dev, "ustar", NULL)) != 0) {
|
||||
if ((res = vfs_mount(ioctx, "/", root_dev->dev, "ustar", NULL)) != 0) {
|
||||
kerror("mount: %s\n", kstrerror(res));
|
||||
panic("Fail\n");
|
||||
}
|
||||
|
||||
// Open STDOUT_FILENO and STDERR_FILENO
|
||||
struct ofile *fd_stdout = kmalloc(sizeof(struct ofile));
|
||||
struct ofile *fd_stdin = kmalloc(sizeof(struct ofile));
|
||||
|
||||
if ((res = dev_find(DEV_CLASS_CHAR, "tty0", &tty_dev)) != 0) {
|
||||
kerror("tty0: %s\n", kstrerror(res));
|
||||
panic("Fail\n");
|
||||
}
|
||||
|
||||
if ((res = vfs_open_vnode(ioctx, fd_stdin, tty_dev, O_RDONLY)) != 0) {
|
||||
kerror("tty0: %s\n", kstrerror(res));
|
||||
panic("Fail\n");
|
||||
}
|
||||
|
||||
if ((res = vfs_open_vnode(ioctx, fd_stdout, tty_dev, O_WRONLY)) != 0) {
|
||||
kerror("tty0: %s\n", kstrerror(res));
|
||||
panic("Fail\n");
|
||||
}
|
||||
|
||||
thread_self->fds[0] = fd_stdin;
|
||||
thread_self->fds[1] = fd_stdout;
|
||||
thread_self->fds[2] = fd_stdout;
|
||||
// Duplicate the FD
|
||||
++fd_stdout->refcount;
|
||||
|
||||
_assert(fd_stdin->refcount == 1);
|
||||
_assert(fd_stdout->refcount == 2);
|
||||
|
||||
sys_execve("/test", NULL, NULL);
|
||||
|
||||
while (1) {
|
||||
@ -76,6 +107,7 @@ void kernel_main(struct amd64_loader_data *data) {
|
||||
// Reinitialize RS232 properly
|
||||
amd64_con_init();
|
||||
rs232_init(RS232_COM1);
|
||||
ps2_init();
|
||||
|
||||
amd64_phys_memory_map((multiboot_memory_map_t *) MM_VIRTUALIZE(multiboot_info->mmap_addr),
|
||||
multiboot_info->mmap_length);
|
||||
@ -84,6 +116,8 @@ void kernel_main(struct amd64_loader_data *data) {
|
||||
amd64_idt_init(0);
|
||||
amd64_mm_init(data);
|
||||
|
||||
ps2_register_device();
|
||||
|
||||
amd64_acpi_init();
|
||||
|
||||
// Print kernel version now
|
||||
|
@ -2,8 +2,11 @@
|
||||
#include "sys/syscall.h"
|
||||
#include "sys/thread.h"
|
||||
#include "sys/debug.h"
|
||||
#include "sys/errno.h"
|
||||
#include "sys/time.h"
|
||||
|
||||
#include "sys/sys_file.h"
|
||||
|
||||
#define MSR_IA32_STAR 0xC0000081
|
||||
#define MSR_IA32_LSTAR 0xC0000082
|
||||
#define MSR_IA32_SFMASK 0xC0000084
|
||||
@ -19,7 +22,8 @@ void sys_debug_sleep(uint64_t ms) {
|
||||
}
|
||||
|
||||
void *syscall_table[256] = {
|
||||
NULL,
|
||||
[SYSCALL_NR_READ] = sys_read,
|
||||
[SYSCALL_NR_WRITE] = sys_write,
|
||||
|
||||
[SYSCALL_NR_EXIT] = sys_exit,
|
||||
|
||||
@ -27,8 +31,9 @@ void *syscall_table[256] = {
|
||||
[SYSCALL_NR_DEBUG_TRACE] = sys_debug_trace,
|
||||
};
|
||||
|
||||
void syscall_undefined(uint64_t rax) {
|
||||
int syscall_undefined(uint64_t rax) {
|
||||
kwarn("Undefined syscall: %d\n", rax);
|
||||
return -ENOSYS;
|
||||
}
|
||||
|
||||
void syscall_init(void) {
|
||||
|
@ -15,6 +15,7 @@ syscall_entry:
|
||||
cmpq $57, %rax
|
||||
jz _syscall_fork
|
||||
|
||||
pushq %rsp
|
||||
pushq %rcx
|
||||
pushq %r11
|
||||
movq get_cpu(CPU_SYSCALL_RSP), %rcx
|
||||
@ -38,6 +39,11 @@ syscall_entry:
|
||||
popq %rdi
|
||||
popq %r11
|
||||
popq %rcx
|
||||
popq %rdx
|
||||
|
||||
//movq get_cpu(CPU_TSS), %rsi
|
||||
//addq $64, %rdx
|
||||
//movq %rdx, TSS_RSP0(%rsi)
|
||||
|
||||
movq %rdi, %rsp
|
||||
|
||||
|
@ -1,6 +1,7 @@
|
||||
#include "sys/dev/ring.h"
|
||||
#include "sys/thread.h"
|
||||
#include "sys/assert.h"
|
||||
#include "sys/sched.h"
|
||||
#include "sys/debug.h"
|
||||
#include "sys/heap.h"
|
||||
|
||||
@ -61,8 +62,14 @@ int ring_getc(struct thread *ctx, struct ring *ring, char *c, int err) {
|
||||
}
|
||||
|
||||
if (!ring_readable(ring)) {
|
||||
panic("Feck\n");
|
||||
//asm volatile ("sti; hlt; cli");
|
||||
asm volatile ("cli");
|
||||
_assert(ctx);
|
||||
|
||||
ctx->wait_prev = NULL;
|
||||
ctx->wait_next = ctx;
|
||||
ring->reader_head = ctx;
|
||||
|
||||
sched_unqueue(ctx, THREAD_WAITING_IO);
|
||||
} else {
|
||||
break;
|
||||
}
|
||||
@ -77,12 +84,25 @@ int ring_getc(struct thread *ctx, struct ring *ring, char *c, int err) {
|
||||
int ring_putc(struct thread *ctx, struct ring *ring, char c, int wait) {
|
||||
if (wait) {
|
||||
while (!ring_writable(ring)) {
|
||||
asm volatile ("sti; hlt; cli");
|
||||
panic("Not implemented\n");
|
||||
}
|
||||
}
|
||||
|
||||
ring->base[ring->wr] = c;
|
||||
ring_advance_write(ring);
|
||||
|
||||
// Notify a single reader a character is available
|
||||
if (ring->reader_head) {
|
||||
struct thread *thr = ring->reader_head;
|
||||
ring->reader_head = NULL; //thr->wait_next;
|
||||
|
||||
sched_queue(thr);
|
||||
|
||||
_assert(thr);
|
||||
_assert(thr->next);
|
||||
_assert(thr->prev);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
@ -104,6 +124,8 @@ int ring_init(struct ring *r, size_t cap) {
|
||||
r->rd = 0;
|
||||
r->wr = 0;
|
||||
r->flags = 0;
|
||||
r->reader_head = NULL;
|
||||
|
||||
if (!(r->base = kmalloc(cap))) {
|
||||
return -1;
|
||||
}
|
||||
|
14
sys/sched.c
14
sys/sched.c
@ -24,6 +24,10 @@ static void *idle(void *arg) {
|
||||
////
|
||||
|
||||
void sched_queue(struct thread *thr) {
|
||||
asm volatile ("cli");
|
||||
_assert(thr);
|
||||
thr->state = THREAD_READY;
|
||||
|
||||
if (queue_head) {
|
||||
struct thread *queue_tail = queue_head->prev;
|
||||
|
||||
@ -40,11 +44,14 @@ void sched_queue(struct thread *thr) {
|
||||
}
|
||||
|
||||
void sched_unqueue(struct thread *thr, enum thread_state new_state) {
|
||||
asm volatile ("cli");
|
||||
struct cpu *cpu = get_cpu();
|
||||
struct thread *prev = thr->prev;
|
||||
struct thread *next = thr->next;
|
||||
|
||||
_assert((new_state == THREAD_WAITING) || (new_state == THREAD_STOPPED));
|
||||
_assert((new_state == THREAD_WAITING) ||
|
||||
(new_state == THREAD_STOPPED) ||
|
||||
(new_state == THREAD_WAITING_IO));
|
||||
thr->state = new_state;
|
||||
|
||||
if (next == thr) {
|
||||
@ -58,6 +65,8 @@ void sched_unqueue(struct thread *thr, enum thread_state new_state) {
|
||||
queue_head = next;
|
||||
}
|
||||
|
||||
_assert(thr && next && prev);
|
||||
|
||||
next->prev = prev;
|
||||
prev->next = next;
|
||||
|
||||
@ -87,6 +96,9 @@ static void sched_debug_tree(int level, struct thread *thr, int depth) {
|
||||
case THREAD_WAITING:
|
||||
debugs(level, "IDLE");
|
||||
break;
|
||||
case THREAD_WAITING_IO:
|
||||
debugs(level, "I/O ");
|
||||
break;
|
||||
case THREAD_STOPPED:
|
||||
debugs(level, "STOP");
|
||||
break;
|
||||
|
38
sys/sys_file.c
Normal file
38
sys/sys_file.c
Normal file
@ -0,0 +1,38 @@
|
||||
#include "sys/amd64/cpu.h"
|
||||
#include "sys/sys_file.h"
|
||||
#include "sys/thread.h"
|
||||
#include "sys/assert.h"
|
||||
#include "sys/debug.h"
|
||||
#include "sys/errno.h"
|
||||
|
||||
ssize_t sys_read(int fd, void *data, size_t lim) {
|
||||
struct thread *thr = thread_self;
|
||||
struct ofile *of;
|
||||
_assert(thr);
|
||||
|
||||
if (fd < 0 || fd >= THREAD_MAX_FDS) {
|
||||
return -EBADF;
|
||||
}
|
||||
|
||||
if ((of = thr->fds[fd]) == NULL) {
|
||||
return -EBADF;
|
||||
}
|
||||
|
||||
return vfs_read(&thr->ioctx, of, data, lim);
|
||||
}
|
||||
|
||||
ssize_t sys_write(int fd, const void *data, size_t lim) {
|
||||
struct thread *thr = thread_self;
|
||||
struct ofile *of;
|
||||
_assert(thr);
|
||||
|
||||
if (fd < 0 || fd >= THREAD_MAX_FDS) {
|
||||
return -EBADF;
|
||||
}
|
||||
|
||||
if ((of = thr->fds[fd]) == NULL) {
|
||||
return -EBADF;
|
||||
}
|
||||
|
||||
return vfs_write(&thr->ioctx, of, data, lim);
|
||||
}
|
36
sys/thread.c
36
sys/thread.c
@ -8,6 +8,7 @@
|
||||
#include "sys/vmalloc.h"
|
||||
#include "sys/fs/vfs.h"
|
||||
#include "sys/assert.h"
|
||||
#include "sys/string.h"
|
||||
#include "sys/thread.h"
|
||||
#include "sys/sched.h"
|
||||
#include "sys/errno.h"
|
||||
@ -44,6 +45,29 @@ pid_t thread_alloc_pid(int is_user) {
|
||||
|
||||
////
|
||||
|
||||
static void thread_ioctx_empty(struct thread *thr) {
|
||||
memset(&thr->ioctx, 0, sizeof(struct vfs_ioctx));
|
||||
memset(thr->fds, 0, sizeof(thr->fds));
|
||||
}
|
||||
|
||||
void thread_ioctx_fork(struct thread *dst, struct thread *src) {
|
||||
thread_ioctx_empty(dst);
|
||||
|
||||
// TODO: increase refcount (when cwd has one)
|
||||
dst->ioctx.cwd_vnode = src->ioctx.cwd_vnode;
|
||||
dst->ioctx.gid = src->ioctx.gid;
|
||||
dst->ioctx.uid = src->ioctx.uid;
|
||||
|
||||
for (int i = 0; i < THREAD_MAX_FDS; ++i) {
|
||||
if (src->fds[i]) {
|
||||
dst->fds[i] = src->fds[i];
|
||||
++dst->fds[i]->refcount;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
////
|
||||
|
||||
int thread_init(struct thread *thr, uintptr_t entry, void *arg, int user) {
|
||||
uintptr_t stack_pages = amd64_phys_alloc_page();
|
||||
_assert(stack_pages != MM_NADDR);
|
||||
@ -80,6 +104,8 @@ int thread_init(struct thread *thr, uintptr_t entry, void *arg, int user) {
|
||||
thr->first_child = NULL;
|
||||
thr->next_child = NULL;
|
||||
|
||||
thread_ioctx_empty(thr);
|
||||
|
||||
// Initial thread context
|
||||
// Entry context
|
||||
if (user) {
|
||||
@ -183,6 +209,8 @@ int sys_fork(struct sys_fork_frame *frame) {
|
||||
dst->data.cr3 = MM_PHYS(space);
|
||||
dst->space = space;
|
||||
|
||||
thread_ioctx_fork(dst, src);
|
||||
|
||||
dst->state = THREAD_READY;
|
||||
dst->parent = src;
|
||||
dst->next_child = src->first_child;
|
||||
@ -253,12 +281,12 @@ int sys_fork(struct sys_fork_frame *frame) {
|
||||
|
||||
int sys_execve(const char *path, const char **argp, const char **envp) {
|
||||
struct thread *thr = thread_self;
|
||||
struct vfs_ioctx ioctx = {0};
|
||||
_assert(thr);
|
||||
struct ofile fd;
|
||||
uintptr_t entry;
|
||||
int res;
|
||||
|
||||
if ((res = vfs_open(&ioctx, &fd, path, O_RDONLY, 0)) != 0) {
|
||||
if ((res = vfs_open(&thr->ioctx, &fd, path, O_RDONLY, 0)) != 0) {
|
||||
kerror("%s: %s\n", path, kstrerror(res));
|
||||
return res;
|
||||
}
|
||||
@ -285,11 +313,11 @@ int sys_execve(const char *path, const char **argp, const char **envp) {
|
||||
mm_space_release(thr->space);
|
||||
}
|
||||
|
||||
if (elf_load(thr, &ioctx, &fd, &entry) != 0) {
|
||||
if (elf_load(thr, &thr->ioctx, &fd, &entry) != 0) {
|
||||
panic("Feck\n");
|
||||
}
|
||||
|
||||
vfs_close(&ioctx, &fd);
|
||||
vfs_close(&thr->ioctx, &fd);
|
||||
|
||||
thr->data.rsp0 = thr->data.rsp0_top;
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user