Added I/O syscalls (read/write) and ring reading

This commit is contained in:
Mark 2020-01-31 11:44:47 +02:00
parent 6c9949c2af
commit cf9c511ff3
13 changed files with 182 additions and 14 deletions

View File

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

View File

@ -14,6 +14,8 @@ struct ring {
size_t cap;
char *base;
int flags;
struct thread *reader_head;
};
int ring_readable(struct ring *b);

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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