CeDOS - Commit 67647dff

Merge branch 'feature/files' into develop Files are now actual structures containing information, and different file operations are encapsuled into a file_operations struct
Celina Sophie Kalus
Tue, 25 Apr 2023 21:35:58 +0200
19 files changed, 301 insertions(+), 76 deletions(-)
M include/assert.hinclude/assert.h

@@ -1,6 +1,8 @@

#ifndef ASSERT_H #define ASSERT_H +#include "cedos/core.h" + #include <stdint.h> #define assert(cond) if (!(cond)) { kpanic("Assertion failed: " #cond); }
A include/cedos/drivers/tty.h

@@ -0,0 +1,15 @@

+#ifndef TTY_H +#define TTY_H + +#include "cedos/file.h" +#include "cedos/drivers/keyboard.h" +#include "cedos/drivers/console.h" + +int tty_open(const char *pathname, int flags); +int tty_openat(int fd, const char *fname, int flags); +int tty_read(int fd, char *buffer, uint32_t size); +int tty_write(int fd, char *buffer, uint32_t size); + +extern file_operations_t tty_fops; + +#endif
M include/cedos/fat.hinclude/cedos/fat.h

@@ -3,12 +3,14 @@ #define FAT_H

#include <stdint.h> +#include "cedos/file.h" + void FAT_init(); -//void *FAT_read_sector_offset(uint32_t lba, uint32_t *offset); -//void *FAT_read_cluster(uint16_t cluster, void *buffer); -//uint16_t FAT_next_cluster(uint16_t cluster); -int FAT_root_dir_next(int index, char *fname_buffer, uint16_t *first_cluster, uint32_t *file_size); -uint32_t FAT_read_file(const char *fname, void *buffer); -int FAT_dir_next(int fd, int index, char *fname_buffer); +int FAT_dir_next(file_t *file, int index, char *fname_buffer); +int FAT_openat(file_t *root, file_t *handle, const char *fname, int flags); +uint32_t FAT_read(file_t *file, void *buffer, int count); + +extern file_operations_t FAT_fops; + #endif
M include/cedos/file.hinclude/cedos/file.h

@@ -5,6 +5,30 @@ #include <stdint.h>

#include "cedos/mm/paging.h" +typedef uint32_t fpos_t; + +struct file; +struct file_operations; + +typedef struct file file_t; +typedef struct file_operations file_operations_t; + +struct file { + file_operations_t *fops; + uint32_t stdio_id; + uint32_t fat_cluster; + fpos_t pos; +}; + +struct file_operations { + int (*open)(const char *pathname, int flags); + int (*openat)(file_t *root, file_t *handle, const char *fname, int flags); + int (*read)(file_t *file, char *buffer, uint32_t size); + int (*write)(file_t *file, char *buffer, uint32_t size); + int (*dir_next)(file_t *file, int index, char *fname_buffer); +}; + +int file_init(); int file_open(const char *pathname, int flags); int file_openat(int fd, const char *fname, int flags); int file_read(int fd, char *buffer, uint32_t size);
A include/cedos/pipe.h

@@ -0,0 +1,11 @@

+#ifndef PIPE_H +#define PIPE_H + +#include "cedos/file.h" + +int pipe_read(int fd, char *buffer, uint32_t size); +int pipe_write(int fd, char *buffer, uint32_t size); + +extern file_operations_t pipe_fops; + +#endif
M include/cedos/sched/process.hinclude/cedos/sched/process.h

@@ -67,6 +67,12 @@

//! String of arguments for the process char *args; + //! process stdin + int stdin; + + //! process stdout + int stdout; + /* * String buffers for name and args * TODO: eventually move to a malloc solution
M include/cedos/sched/sched.hinclude/cedos/sched/sched.h

@@ -32,7 +32,7 @@

/*! * Spawns a new process, loads it from the given ELF file, and returns its process ID. */ -PROCESS_ID sched_spawn(const char *name, char *args); +PROCESS_ID sched_spawn(const char *name, char *args, int flags); /*! * Return the ID of the current process.
M makefilemakefile

@@ -27,7 +27,9 @@

# common flags CCFLAGS := $(CCFLAGS) -Wno-write-strings CCFLAGS := $(CCFLAGS) -Qn +CCFLAGS := $(CCFLAGS) -pedantic -Wold-style-definition CCFLAGS := $(CCFLAGS) -Wall -Wextra -fno-exceptions +CCFLAGS := $(CCFLAGS) -Werror-implicit-function-declaration CCFLAGS := $(CCFLAGS) -nostdlib -nostartfiles -ffreestanding CCFLAGS := $(CCFLAGS) -mgeneral-regs-only -mno-red-zone CCFLAGS := $(CCFLAGS) --prefix=$(CROSS_COMP)

@@ -112,7 +114,7 @@ > $(RM) -r $(CURRENT_DIR)/build/* 2> /dev/null; true

.PHONY: run run: -> ./run.sh +> ./run.sh $(GLOBAL_BUILD)/cedos.img .PHONY: docs docs:
M run.shrun.sh

@@ -1,1 +1,1 @@

-qemu-system-i386 -drive index=0,if=floppy,format=raw,file=./build/release/cedos.img -m 64 -monitor stdio -no-reboot -d int,cpu_reset,exec,in_asm -vga std -vnc :0 2> log/run_err.log +qemu-system-i386 -drive index=0,if=floppy,format=raw,file=${1} -m 64 -monitor stdio -no-reboot -d int,cpu_reset,exec,in_asm -vga std -vnc :0 2> log/run_err.log
A src/kernel/drivers/tty.c

@@ -0,0 +1,44 @@

+#include "cedos/file.h" +#include "cedos/drivers/tty.h" + +#include "cedos/drivers/console.h" +#include "cedos/drivers/keyboard.h" + +file_operations_t tty_fops = { + tty_open, /* open */ + tty_openat, /* openat */ + tty_read, /* read */ + tty_write, /* write */ + NULL /* dir_next */ +}; + +int tty_open(const char *pathname, int flags) { + +} + +int tty_openat(int fd, const char *fname, int flags) { + +} + +int tty_read(int fd, char *buffer, uint32_t size) { + uint32_t i = 0; + while (i < size) { + char table[] = { + '^', 0x1B, '1', '2', '3', '4', '5', '6', '7', '8', '9', '0', '\\', '`', 0x08, + '\t', 'q', 'w', 'e', 'r', 't', 'z', 'u', 'i', 'o', 'p', '?', '+', '\n', + 0, 'a', 's', 'd', 'f', 'g', 'h', 'j', 'k', 'l', '?', '?', '#', + 0, '<', 'y', 'x', 'c', 'v', 'b', 'n', 'm', ',', '.', '-', 0, 0, 0, ' ' }; + uint32_t scancode = std_kb->read(); + char c = scancode <= 60 ? table[scancode] : 0; + if (c == 0) { continue; } + buffer[i++] = c; + } + return size; +} + +int tty_write(int fd, char *buffer, uint32_t size) { + for (uint32_t i = 0; i < size; i++) { + std_con->write_c(buffer[i]); + } + return size; +}
M src/kernel/elf.csrc/kernel/elf.c

@@ -129,6 +129,8 @@ PRINT_DBG("Loading ELF executable \"%s\".\n", fname);

VIRT_ADDR elf_addr = (VIRT_ADDR*)(0xA0000000); // TODO: needs to change when we have other file systems int fd = file_open(fname, 0); + PRINT_DBG("File handle: %i\n", fd); + if (fd == -1) { printk("Executable file not found: %s\n", fname); return -1;
M src/kernel/fat.csrc/kernel/fat.c

@@ -1,6 +1,17 @@

+#include "cedos/file.h" #include "cedos/fat.h" #include "string.h" +#include "assert.h" + #include <stdint.h> + +file_operations_t FAT_fops = { + NULL, /* open */ + FAT_openat, /* openat */ + FAT_read, /* read */ + NULL, /* write */ + FAT_dir_next /* dir_next */ +}; typedef struct { char jmp[3];

@@ -168,15 +179,12 @@ return index + 1;

} } -int FAT_dir_next(int fd, int index, char *fname_buffer) { +int FAT_dir_next(file_t *file, int index, char *fname_buffer) { uint16_t first_cluster; uint32_t file_size; - if (fd == 0x1000) { - return FAT_root_dir_next(index, fname_buffer, &first_cluster, &file_size); - } else { - return -1; - } + // TODO: subdirectories + return FAT_root_dir_next(index, fname_buffer, &first_cluster, &file_size); } uint16_t FAT_next_cluster(uint16_t cluster) {

@@ -196,16 +204,10 @@ return low | high;

} } -int FAT_openat(int fd, const char *fname, int flags) { +int FAT_openat(file_t *root, file_t *handle, const char *fname, int flags) { int i = 0; // TODO: take fd into consideration (open file in that subdirectory) - - - if (!(fd & 0x1000)) { return -1; } - - fd &= 0x0FFF; - uint16_t first_cluster; while (1) { char buffer[832];

@@ -216,15 +218,15 @@ if (i <= 0) { return -1; }

if (strcmp(buffer, fname) == 0) { // file found - return first_cluster | 0x1000; + handle->fops = &FAT_fops; + handle->fat_cluster = first_cluster; + return 0; } } } -uint32_t FAT_read(int fd, void *buffer, int count) { - if (!(fd & 0x1000)) { return -1; } - - uint16_t cluster = fd & 0xFFF; +uint32_t FAT_read(file_t *file, void *buffer, int count) { + uint16_t cluster = file->fat_cluster; uint32_t size = 0; while (1) {
M src/kernel/file.csrc/kernel/file.c

@@ -1,59 +1,107 @@

#include "cedos/file.h" #include "cedos/fat.h" +#include "cedos/pipe.h" -#include "cedos/drivers/console.h" -#include "cedos/drivers/keyboard.h" +#include "cedos/drivers/tty.h" +#include "cedos/core.h" + +#include "cedos/sched/sched.h" +#include "cedos/sched/process.h" -const int root_fd = 0x1000; +#ifdef DEBUG +#define PRINT_DBG(...) printk("[" __FILE__ "] " __VA_ARGS__) +#else +#define PRINT_DBG(...) {} +#endif + +//const int root_fd = 0x1000; + +file_t file_table[256]; +int next_free = 0; + +int stdin, stdout, fat_root, pipe; + +int file_init() { + file_table[next_free].fops = &tty_fops; + file_table[next_free].stdio_id = 0; + file_table[next_free].fat_cluster = 0; + stdin = next_free++; + + file_table[next_free].fops = &tty_fops; + file_table[next_free].stdio_id = 1; + file_table[next_free].fat_cluster = 0; + stdout = next_free++; + + // FAT root + file_table[next_free].fops = &FAT_fops; + file_table[next_free].stdio_id = 0; + file_table[next_free].fat_cluster = 0; + fat_root = next_free++; + + // pipe + file_table[next_free].fops = &pipe_fops; + pipe = next_free++; + + return 0; +} int file_open(const char *pathname, int flags) { while (*pathname == '/') { pathname++; } - return file_openat(0x1000, pathname, flags); + return file_openat(fat_root, pathname, flags); +} + +file_t *get_process_local_file(int fd) { + if (fd > 1) { return &file_table[fd]; } + + PROCESS_ID pid = get_current_process(); + PRINT_DBG("pid: %i\n", pid); + PROCESS *p = get_process(pid); + + if (fd == 0) { return &file_table[p->stdin]; } + if (fd == 1) { return &file_table[p->stdout]; } + + return NULL; } int file_openat(int fd, const char *fname, int flags) { - if (fd & 0x1000) { - return FAT_openat(fd, fname, flags); - } else { - // open other files - return 0; - } + int new_fd = next_free++; + + PRINT_DBG("Given fd: %i\n", fd); + PRINT_DBG("New fd: %i\n", new_fd); + + file_t *root = get_process_local_file(fd); + file_t *handle = &file_table[new_fd]; + + if (root->fops->openat == NULL) { return -1; } + + if (root->fops->openat(root, handle, fname, flags)) { return -1; } + + return new_fd; } int file_read(int fd, char *buffer, uint32_t size) { - if (fd & 0x1000) { - return FAT_read(fd, buffer, size); - } else { - uint32_t i = 0; - while (i < size) { - char table[] = { - '^', 0x1B, '1', '2', '3', '4', '5', '6', '7', '8', '9', '0', '\\', '`', 0x08, - '\t', 'q', 'w', 'e', 'r', 't', 'z', 'u', 'i', 'o', 'p', '?', '+', '\n', - 0, 'a', 's', 'd', 'f', 'g', 'h', 'j', 'k', 'l', '?', '?', '#', - 0, '<', 'y', 'x', 'c', 'v', 'b', 'n', 'm', ',', '.', '-', 0, 0, 0, ' ' }; - uint32_t scancode = std_kb->read(); - char c = scancode <= 60 ? table[scancode] : 0; - if (c == 0) { continue; } - buffer[i++] = c; - } - return size; - } + file_t *file = get_process_local_file(fd); + + if (file->fops->read == NULL) { return -1; } + + file->fops->read(file, buffer, size); } int file_write(int fd, char *buffer, uint32_t size) { - for (uint32_t i = 0; i < size; i++) { - std_con->write_c(buffer[i]); - } - return size; + file_t *file = get_process_local_file(fd); + + if (file->fops->write == NULL) { return -1; } + + file->fops->write(file, buffer, size); } int file_dir_next(int fd, int index, char *fname_buffer) { - if (fd & 0x1000) { - return FAT_dir_next(fd, index, fname_buffer); - } else { - return -1; - } + file_t *file = get_process_local_file(fd); + + if (file->fops->dir_next == NULL) { return -1; } + + file->fops->dir_next(file, index, fname_buffer); }
M src/kernel/main.csrc/kernel/main.c

@@ -16,6 +16,7 @@ #include "cedos/core.h"

#include "cedos/elf.h" +#include "cedos/file.h" #include "cedos/fat.h" #include "linker.h"

@@ -65,7 +66,11 @@ printk("Initializing keyboard...");

ps2_kb.init(); printk("done.\n"); - printk("Initializing root file system..."); + printk("Initializing files..."); + file_init(); + printk("done.\n"); + + printk("Initializing FAT file system..."); FAT_init(); printk("done.\n");

@@ -123,7 +128,7 @@ // create test tasks

printk("Creating tasks.\n"); - int pid = sched_spawn("shelf", "Hello World!"); + int pid = sched_spawn("shelf", "Hello World!", 0); assert(pid != -1); //sched_spawn("fibonacci.o", "Hello World!"); //sched_spawn("fibonacci.o", "Hello World!");
A src/kernel/pipe.c

@@ -0,0 +1,49 @@

+#include "cedos/file.h" +#include "cedos/pipe.h" +#include "cedos/sched/sched.h" + +file_operations_t pipe_fops = { + NULL, /* open */ + NULL, /* openat */ + pipe_read, /* read */ + pipe_write, /* write */ + NULL /* dir_next */ +}; + +#define PIPE_BUFFER_SIZE 512 + +uint8_t pipe_buffer[PIPE_BUFFER_SIZE]; +int read_head = 0; +int write_head = 0; + +uint8_t pipe_readc() { + while (write_head == read_head) { + sched_yield(); + } + + int rh_next = (read_head + 1) % PIPE_BUFFER_SIZE; + uint8_t res = pipe_buffer[read_head]; + read_head = rh_next; + return res; +} + +void pipe_writec(uint8_t c) { + int wh_next = (write_head + 1) % PIPE_BUFFER_SIZE; + while (wh_next == read_head) { + sched_yield(); + } + pipe_buffer[write_head] = c; + write_head = wh_next; +} + +int pipe_read(int fd, char *buffer, uint32_t size) { + for (int i = 0; i < size; i++) { + buffer[i] = pipe_readc(); + } +} + +int pipe_write(int fd, char *buffer, uint32_t size) { + for (int i = 0; i < size; i++) { + pipe_writec(buffer[i]); + } +}
M src/kernel/sched/sched.csrc/kernel/sched/sched.c

@@ -52,8 +52,12 @@

/*! * Spawn a new process and returns its process ID. */ -PROCESS_ID sched_spawn(const char *name, char *args) { +PROCESS_ID sched_spawn(const char *name, char *args, int flags) { crit_enter(); + + PRINT_DBG("process name: %s\n", name); + PRINT_DBG("process args: %s\n", args); + PRINT_DBG("process flags: %i\n", flags); if (name != NULL) { int fd = file_open(name, 0);

@@ -70,6 +74,14 @@ p->ebp = USER_STACK;

p->esp = USER_STACK - sizeof(SCHED_FRAME); p->eflags = PROCESS_STD_EFLAGS; p->entry = (PROCESS_MAIN*)(0xDEADBEEF); + + if (flags != 0) { + p->stdin = (int)(flags & 0xFF); + p->stdout = (int)(flags >> 8); + } else { + p->stdin = 0; + p->stdout = 1; + } // TODO: implement with malloc strcpy(p->name_buf, name);

@@ -185,7 +197,7 @@

current_pid = 0; // create idle process - PROCESS_ID idle = sched_spawn(NULL, NULL); + PROCESS_ID idle = sched_spawn(NULL, NULL, 0); assert(idle != -1); return 1;
M src/libcedos/cedos.csrc/libcedos/cedos.c

@@ -20,12 +20,6 @@ interrupt(0x30, res, 3, 0, 0, 0);

return res; } -int file_openat(int fd, const char *fname, int flags) { - volatile uint32_t res = 0; - interrupt(0x30, res, 6, fd, fname, flags); - return res; -} - int sc_file_read(int fd, char *buffer, uint32_t size) { volatile uint32_t res = 0; interrupt(0x30, res, 0, fd, buffer, size);

@@ -44,12 +38,18 @@ interrupt(0x30, res, 4, fname, args, 0);

return res; } +int process_spawn_pipe(const char *fname, const char *args, int stdin, int stdout) { + volatile uint32_t res = 0; + interrupt(0x30, res, 4, fname, args, stdin | (stdout << 8)); + return res; +} + void process_wait(int pid) { volatile uint32_t res = 0; interrupt(0x30, res, 5, pid, 0, 0); } -int sc_file_open(char *pathname, int flags) { +int sc_file_open(char *pathname, uint32_t flags) { volatile uint32_t res = 0; interrupt(0x30, res, 6, pathname, flags, 0); return res;
M src/libcedos/include/cedos.hsrc/libcedos/include/cedos.h

@@ -9,13 +9,14 @@ int sysprint(const char *fmt, int arg1, int arg2);

int yield(); int get_pid(); int process_spawn(const char *fname, const char *args); +int process_spawn_pipe(const char *fname, const char *args, int stdin, int stdout); void process_wait(int pid); void graphics_set_mode(int mode); int sc_file_read(int fd, char *buffer, uint32_t size); int sc_file_write(int fd, char *buffer, uint32_t size); -int sc_file_openat(int fd, char *buffer, uint32_t size); +int sc_file_open(char *buffer, uint32_t flags); void hard_reset();
M src/shell/ls.csrc/shell/ls.c

@@ -9,7 +9,7 @@

int index = 0; while (1) { - int next = dir_next(0x1000, index, buffer); + int next = dir_next(2, index, buffer); if (next == -1) { return; }