Convert file descriptors to generic streams

master
Freywar Ulvnaudgari 1 month ago
parent bcf2e5bac6
commit 9761e3e870
  1. 40
      src/kernel/fat16.c
  2. 3
      src/kernel/fat16.h
  3. 4
      src/kernel/fs.c
  4. 3
      src/kernel/fs.h
  5. 5
      src/kernel/kernel.c
  6. 5
      src/kernel/keyboard.c
  7. 2
      src/kernel/panic.h
  8. 11
      src/kernel/path.c
  9. 4
      src/kernel/path.h
  10. 13
      src/kernel/process.c
  11. 11
      src/kernel/process.h
  12. 2
      src/kernel/stream.h
  13. 66
      src/kernel/syscall.c
  14. 5
      src/kernel/vga.c
  15. 8
      src/lib/util.h
  16. 16
      src/user/app/cat/cat.c
  17. 5
      src/user/app/echo/echo.c
  18. 16
      src/user/app/ls/ls.c
  19. 5
      src/user/app/terminal/terminal.c
  20. 5
      src/user/syscall.h

@ -2,6 +2,7 @@
#include "src/kernel/ata.h"
#include "src/kernel/fs.h"
#include "src/kernel/panic.h"
#include "src/kernel/stream.h"
#include "src/lib/memory.h"
#include "src/lib/string.h"
#include "src/lib/util.h"
@ -200,6 +201,45 @@ fs_node_t *fat16_open_again(const fs_node_t *source) {
return result;
}
typedef struct {
stream_t stream;
fs_node_t *node;
uint64_t offset;
} fat16_stream_t;
static uint64_t stream_write(__attribute__((unused)) const stream_t *self, __attribute__((unused)) const char *from,
__attribute__((unused)) uint64_t bytes) {
return (uint64_t)-1;
}
static uint64_t stream_read(const stream_t *self, uint64_t max, char *to) {
fat16_stream_t *fss = (fat16_stream_t *)self;
if (fss->offset >= fss->node->size) {
return 0;
}
uint64_t remaining = fss->node->size - fss->offset;
uint64_t to_read = remaining > max ? max : remaining;
fat16_read(fss->node, fss->offset, to_read, to);
fss->offset += to_read;
return to_read;
}
static void stream_close(stream_t *self) {
fat16_stream_t *fss = (fat16_stream_t *)self;
fat16_close(fss->node);
memory_free(self);
}
stream_t *fat16_open_stream(const fs_node_t *source) {
fat16_stream_t *result = memory_allocate(sizeof(fat16_node_t));
result->stream.read = stream_read;
result->stream.write = stream_write;
result->stream.close = stream_close;
result->node = fat16_open_again(source);
result->offset = 0;
return (stream_t *)result;
}
void fat16_read(const fs_node_t *file, uint64_t offset, uint64_t size, void *to) {
ASSERT(file->type == FAT16, "fat16_read: file is not FAT16");
ASSERT(!file->is_dir, "fat16_read: can not read directory");

@ -1,6 +1,7 @@
#pragma once
#include "src/kernel/fs.h"
#include "src/kernel/stream.h"
#define FAT16 1
@ -12,6 +13,8 @@ fs_node_t *fat16_open_at(const fs_node_t *directory, uint64_t index);
fs_node_t *fat16_open_again(const fs_node_t *source);
stream_t *fat16_open_stream(const fs_node_t *source);
void fat16_read(const fs_node_t *file, uint64_t offset, uint64_t size, void *to);
void fat16_close(fs_node_t *node);

@ -17,6 +17,10 @@ fs_node_t *fs_open_again(const fs_node_t *source) {
return fat16_open_again(source);
}
stream_t *fs_open_stream(const fs_node_t *source) {
return fat16_open_stream(source);
}
void fs_read(const fs_node_t *file, uint64_t offset, uint64_t size, void *to) {
fat16_read(file, offset, size, to);
}

@ -1,5 +1,6 @@
#pragma once
#include "src/kernel/stream.h"
#include <stdint.h>
#define FILENAME_SIZE_LIMIT 255
@ -19,6 +20,8 @@ fs_node_t *fs_open_at(const fs_node_t *directory, uint64_t index);
fs_node_t *fs_open_again(const fs_node_t *source);
stream_t *fs_open_stream(const fs_node_t *source);
void fs_read(const fs_node_t *file, uint64_t offset, uint64_t size, void *to);
void fs_close(fs_node_t *node);

@ -53,8 +53,9 @@ void kernel_main() {
kernel->pml4 = (void *)KERNEL_VIRTUAL_PML4;
kernel->root = fs_mount();
kernel->cwd = memory_allocate(sizeof(path_t));
kernel->stdin = keyboard_init();
kernel->stdout = vga_init();
kernel->fds[0] = keyboard_init();
kernel->fds[1] = vga_init();
kernel->free_fd = 2;
fs_node_t *bin = path_open_file(kernel->root, kernel->cwd, "bin/terminal");

@ -76,7 +76,10 @@ static uint64_t stream_read(__attribute__((unused)) const stream_t *self, uint64
return size;
}
static stream_t stream = {stream_write, stream_read};
static void stream_close(__attribute__((unused)) stream_t *self) {
}
static stream_t stream = {stream_write, stream_read, stream_close};
static void on_key(uint8_t scancode) {
const uint8_t pressed = !(scancode & 0x80);

@ -2,7 +2,7 @@
#define ASSERT(cond, msg) \
if (!(cond)) { \
kernel_panic(msg " (assertion: " #cond ")", __FILE__, __LINE__); \
kernel_panic(msg " (assertion: " #cond ")", __FILE__, __LINE__); \
}
void kernel_panic(const char *msg, const char *file, int line);

@ -1,5 +1,6 @@
#include "src/kernel/path.h"
#include "src/kernel/fs.h"
#include "src/kernel/stream.h"
#include "src/lib/memory.h"
#include "src/lib/string.h"
#include "src/lib/util.h"
@ -86,6 +87,16 @@ fs_node_t *path_open_directory(const fs_node_t *root, const path_t *source, cons
return n;
}
stream_t *path_open_stream(const fs_node_t *root, const path_t *source, const char *path) {
path_t *p = path_open(root, source, path);
if (!p) {
return NUL;
}
stream_t *s = fs_open_stream(p->depth ? p->stack[p->depth - 1] : root);
path_close(p);
return s;
}
void path_close(path_t *path) {
for (uint64_t i = 0; i < path->depth; i++) {
fs_close(path->stack[i]);

@ -1,7 +1,7 @@
#pragma once
#include "src/kernel/fs.h"
#include <stdint.h>
#include "src/kernel/stream.h"
#define PATH_DEPTH 255
@ -18,4 +18,6 @@ fs_node_t *path_open_file(const fs_node_t *root, const path_t *source, const cha
fs_node_t *path_open_directory(const fs_node_t *root, const path_t *source, const char *path);
stream_t *path_open_stream(const fs_node_t *root, const path_t *source, const char *path);
void path_close(path_t *path);

@ -4,6 +4,7 @@
#include "src/kernel/path.h"
#include "src/lib/layout.h"
#include "src/lib/memory.h"
#include "src/lib/util.h"
process_t *current_process;
@ -57,14 +58,22 @@ process_t *process_create(const process_t *parent, const uint8_t *code, uint64_t
proc->cwd = cwd;
proc->root = parent->root;
proc->stdin = parent->stdin;
proc->stdout = parent->stdout;
proc->fds[0] = parent->fds[0];
proc->fds[1] = parent->fds[1];
proc->free_fd = 2;
proc->code = EXIT_CODE_OK;
return proc;
}
void process_destroy(process_t *proc) {
for (uint64_t i = 2; i < MAX_FDS; i++) {
if (proc->fds[i]) {
proc->fds[i]->close(proc->fds[i]);
proc->fds[i] = NUL;
}
}
path_close((path_t *)proc->cwd);
for (uint16_t pml4i = 0; pml4i < 256; pml4i++) {

@ -3,16 +3,12 @@
#include "src/kernel/fs.h"
#include "src/kernel/path.h"
#include "src/kernel/stream.h"
#include "src/lib/util.h"
#define USER_RFLAGS 0x202
#define MAX_FDS 16
typedef struct {
fs_node_t *node;
uint64_t offset;
} fd_entry_t;
typedef struct process {
const struct process *parent;
uint64_t *pml4;
@ -22,10 +18,9 @@ typedef struct process {
void *user_rsp;
const fs_node_t *root;
const path_t *cwd;
const stream_t *stdin;
const stream_t *stdout;
fd_entry_t fds[MAX_FDS];
stream_t *fds[MAX_FDS];
uint64_t free_fd;
exit_code_t code;
} process_t;
typedef void (*app_t)(process_t *proc, uint8_t argc, char **argv);

@ -29,8 +29,10 @@ typedef struct stream stream_t;
typedef uint64_t (*stream_write_t)(const stream_t *self, const char *from, uint64_t bytes);
typedef uint64_t (*stream_read_t)(const stream_t *self, uint64_t max, char *to);
typedef void (*stream_close_t)(stream_t *self);
typedef struct stream {
stream_write_t write;
stream_read_t read;
stream_close_t close;
} stream_t;

@ -3,6 +3,7 @@
#include "src/kernel/gdt.h"
#include "src/kernel/path.h"
#include "src/kernel/process.h"
#include "src/kernel/stream.h"
#include "src/kernel/tss.h"
#include "src/lib/layout.h"
#include "src/lib/memory.h"
@ -34,37 +35,17 @@ void syscall_init() {
}
static uint64_t read(uint64_t fd, uint64_t max, char *to) {
switch (fd) {
case 0:
return current_process->stdin->read(current_process->stdin, max, to);
case 1:
return current_process->stdout->read(current_process->stdout, max, to);
default:
if (!current_process->fds[fd].node) {
return (uint64_t)-1;
}
if (current_process->fds[fd].offset >= current_process->fds[fd].node->size) {
return 0;
}
uint64_t remaining = current_process->fds[fd].node->size - current_process->fds[fd].offset;
uint64_t to_read = remaining > max ? max : remaining;
fs_read(current_process->fds[fd].node, current_process->fds[fd].offset, to_read, to);
current_process->fds[fd].offset += to_read;
return to_read;
if (fd >= MAX_FDS || !current_process->fds[fd]) {
return (uint64_t)-1;
}
return (uint64_t)-1;
return current_process->fds[fd]->read(current_process->fds[fd], max, to);
}
static uint64_t write(uint64_t fd, const char *from, uint64_t bytes) {
switch (fd) {
case 0:
return current_process->stdin->write(current_process->stdin, from, bytes);
case 1:
return current_process->stdout->write(current_process->stdout, from, bytes);
default:
if (fd >= MAX_FDS || !current_process->fds[fd]) {
return (uint64_t)-1;
}
return (uint64_t)-1;
return current_process->fds[fd]->write(current_process->fds[fd], from, bytes);
}
static uint64_t getcwd(uint64_t max, char *to) {
@ -113,13 +94,13 @@ static uint64_t chdir(const char *path) {
return current_process->cwd->depth;
}
static uint64_t spawn(const char *path, uint64_t argc, const char **argv) {
static exit_code_t spawn(const char *path, uint64_t argc, const char **argv) {
fs_node_t *node = path_open_file(current_process->root, current_process->cwd, path);
if (!node) {
return (uint64_t)-1;
return EXIT_CODE_NOT_FOUND;
}
uint8_t *code = memory_allocate(node->size);
fs_read(node, 0, node->size, code);
uint8_t *bin = memory_allocate(node->size);
fs_read(node, 0, node->size, bin);
uint64_t size = 0;
uint64_t sizes[16];
@ -133,9 +114,9 @@ static uint64_t spawn(const char *path, uint64_t argc, const char **argv) {
memory_copy(argv[i], sizes[i], blob + offsets[i]);
}
process_t *child = process_create(current_process, code, node->size);
process_t *child = process_create(current_process, bin, node->size);
memory_free(code);
memory_free(bin);
fs_close(node);
__asm__ volatile("mov %0, %%cr3" : : "r"((uint64_t)VIRT_TO_PHYS((void *)KERNEL_VIRTUAL_PML4)) : "memory");
@ -163,11 +144,12 @@ static uint64_t spawn(const char *path, uint64_t argc, const char **argv) {
process_switch_to(&parent->kernel_rsp, child->kernel_rsp, VIRT_TO_PHYS(child->pml4));
exit_code_t code = child->code;
tss.rsp0 = (uint64_t)parent->kernel_stack;
current_process = parent;
process_destroy(child);
return 0;
return code;
}
static uint64_t readdir(const char *path, uint64_t index, uint64_t max, char *to) {
@ -199,27 +181,25 @@ static uint64_t open(const char *path) {
if (current_process->free_fd >= MAX_FDS) {
return (uint64_t)-1;
}
fs_node_t *node = path_open_node(current_process->root, current_process->cwd, path);
if (!node) {
stream_t *stream = path_open_stream(current_process->root, current_process->cwd, path);
if (!stream) {
return (uint64_t)-1;
}
current_process->fds[current_process->free_fd].node = node;
current_process->fds[current_process->free_fd].offset++;
current_process->free_fd++;
current_process->fds[current_process->free_fd++] = stream;
return current_process->free_fd - 1;
}
static uint64_t close(uint64_t fd) {
if (fd >= MAX_FDS || !current_process->fds[fd].node) {
if (fd >= MAX_FDS || !current_process->fds[fd]) {
return (uint64_t)-1;
}
fs_close(current_process->fds[fd].node);
current_process->fds[fd].node = NUL;
current_process->fds[fd].offset = 0;
current_process->fds[fd]->close(current_process->fds[fd]);
current_process->fds[fd] = NUL;
return 0;
}
static void exit() {
static void exit(exit_code_t code) {
current_process->code = code;
process_switch_to(&current_process->kernel_rsp, current_process->parent->kernel_rsp, VIRT_TO_PHYS(current_process->parent->pml4));
}
@ -242,7 +222,7 @@ uint64_t syscall_dispatch(uint64_t func, uint64_t arg1, uint64_t arg2, uint64_t
case SYSCALL_CLOSE:
return close(arg1);
case SYSCALL_EXIT:
exit();
exit(arg1);
return 0;
default:
return (uint64_t)-1;

@ -155,7 +155,10 @@ static uint64_t stream_read(__attribute__((unused)) const stream_t *self, __attr
return 0;
}
static stream_t stream = {stream_write, stream_read};
static void stream_close(__attribute__((unused)) stream_t *self) {
}
static stream_t stream = {stream_write, stream_read, stream_close};
stream_t *vga_init() {
clear();

@ -1,3 +1,11 @@
#pragma once
#include <stdint.h>
#define NUL 0 // TODO Fix VSCode thinking `NULL` conflicts with some other definition.
typedef uint64_t exit_code_t;
#define EXIT_CODE_OK 0
#define EXIT_CODE_NOT_FOUND ((uint64_t)-2)
#define EXIT_CODE_GENERAL_FAILURE ((uint64_t)-1)

@ -1,3 +1,4 @@
#include "src/lib/util.h"
#include "src/user/syscall.h"
#define BLOCK_SIZE 65536
@ -5,12 +6,12 @@
#define PRINT_S(s) write(1, s, sizeof(s) - 1);
#define PRINT_D(s) write(1, s, string_length(s));
uint64_t cat(const char *path) {
exit_code_t cat(const char *path) {
uint64_t fd = open(path);
if (fd == (uint64_t)-1) {
PRINT_S("cat: path does not exist\n");
return (uint64_t)-1;
return EXIT_CODE_GENERAL_FAILURE;
}
static char buffer[BLOCK_SIZE];
@ -19,7 +20,7 @@ uint64_t cat(const char *path) {
if (bytes == (uint64_t)-1) {
PRINT_S("cat: could not read file\n");
close(fd);
return (uint64_t)-1;
return EXIT_CODE_GENERAL_FAILURE;
}
write(1, buffer, bytes);
}
@ -29,15 +30,16 @@ uint64_t cat(const char *path) {
return 0;
}
uint64_t main(uint64_t argc, const char **argv) {
exit_code_t main(uint64_t argc, const char **argv) {
if (argc == 1) {
return cat(".");
}
uint64_t code = 0;
uint64_t code = EXIT_CODE_OK;
for (uint64_t i = 1; i < argc; i++) {
if (cat(argv[i]) == (uint64_t)-1) {
code = (uint64_t)-1;
exit_code_t c = cat(argv[i]);
if (c != EXIT_CODE_OK) {
code = c;
}
}

@ -1,7 +1,8 @@
#include "src/lib/string.h"
#include "src/lib/util.h"
#include "src/user/syscall.h"
uint64_t main(uint64_t argc, const char **argv) {
exit_code_t main(uint64_t argc, const char **argv) {
for (uint64_t i = 1; i < argc; i++) {
if (i > 1) {
write(1, " ", 1);
@ -9,5 +10,5 @@ uint64_t main(uint64_t argc, const char **argv) {
write(1, argv[i], string_length(argv[i]));
}
write(1, "\n", 1);
return 0;
return EXIT_CODE_OK;
}

@ -1,20 +1,21 @@
#include "src/lib/string.h"
#include "src/lib/util.h"
#include "src/user/syscall.h"
#define PRINT_S(s) write(1, s, sizeof(s) - 1);
#define PRINT_D(s) write(1, s, string_length(s));
uint64_t ls(const char *path) {
exit_code_t ls(const char *path) {
uint64_t i = 0;
while (1) {
char out[100];
uint64_t s = readdir(path, i, 100, out);
if (!s) {
return 0;
return EXIT_CODE_OK;
}
if (s == (uint64_t)-1) {
PRINT_S("ls: path does not exist\n");
return (uint64_t)-1;
return EXIT_CODE_GENERAL_FAILURE;
}
PRINT_D(out);
PRINT_S("\n");
@ -22,20 +23,21 @@ uint64_t ls(const char *path) {
}
}
uint64_t main(uint64_t argc, const char **argv) {
exit_code_t main(uint64_t argc, const char **argv) {
if (argc == 1) {
return ls(".");
}
uint64_t code = 0;
exit_code_t code = EXIT_CODE_OK;
for (uint64_t i = 1; i < argc; i++) {
if (argc > 2) {
PRINT_S("\n");
PRINT_D(argv[i]);
PRINT_S(":\n");
}
if (ls(argv[i]) == (uint64_t)-1) {
code = (uint64_t)-1;
exit_code_t c = ls(argv[i]);
if (c != EXIT_CODE_OK) {
code = c;
}
}

@ -1,5 +1,6 @@
#include "src/lib/memory.h"
#include "src/lib/string.h"
#include "src/lib/util.h"
#include "src/user/syscall.h"
#include <stdint.h>
@ -123,7 +124,7 @@ static void on_enter_pressed() {
char *path = memory_allocate(size);
memory_copy(PATH, sizeof(PATH), path);
memory_copy(argv[0], size - sizeof(PATH), path + sizeof(PATH) - 1);
if (spawn(path, argc, (const char **)argv) == (uint64_t)-1) {
if (spawn(path, argc, (const char **)argv) == EXIT_CODE_NOT_FOUND) {
PRINT_S("terminal: program not found\n");
}
memory_free(path);
@ -140,7 +141,7 @@ static void on_cancel_pressed() {
static void on_disconnect_pressed() {
PRINT_S("^D\n");
exit();
exit(EXIT_CODE_OK);
}
static void on_ctrl_character_pressed(char c) {

@ -1,5 +1,6 @@
#pragma once
#include "src/lib/util.h"
#include <stdint.h>
uint64_t read(int64_t fd, uint64_t max, void *to);
@ -10,7 +11,7 @@ uint64_t getcwd(uint64_t max, void *to);
uint64_t chdir(const char *path);
uint64_t spawn(const char *path, uint64_t argc, const char **argv);
exit_code_t spawn(const char *path, uint64_t argc, const char **argv);
uint64_t readdir(const char *path, uint64_t index, uint64_t max, char *to);
@ -18,4 +19,4 @@ uint64_t open(const char *path);
uint64_t close(uint64_t fd);
void exit();
void exit(exit_code_t code);

Loading…
Cancel
Save