aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorAlex Auvolat <alex.auvolat@ens.fr>2015-02-09 19:24:42 +0100
committerAlex Auvolat <alex.auvolat@ens.fr>2015-02-09 19:24:42 +0100
commit440d9dc470703d20a55365b3a560196e71d450d4 (patch)
treebcc864c7aeb0af7a81c4fcd7430fa8c3001f8383 /src
parentcaf842864bdc0794e387f9580af96ab1036996f4 (diff)
downloadkogata-440d9dc470703d20a55365b3a560196e71d450d4.tar.gz
kogata-440d9dc470703d20a55365b3a560196e71d450d4.zip
Start work on filesystems.
Diffstat (limited to 'src')
-rw-r--r--src/common/string.c5
-rw-r--r--src/kernel/Makefile3
-rw-r--r--src/kernel/core/kmain.c49
-rw-r--r--src/kernel/include/devfs.h8
-rw-r--r--src/kernel/include/nullfs.h25
-rw-r--r--src/kernel/include/process.h32
-rw-r--r--src/kernel/include/vfs.h86
-rw-r--r--src/kernel/user/nullfs.c30
-rw-r--r--src/kernel/user/process.c23
-rw-r--r--src/kernel/user/vfs.c126
10 files changed, 320 insertions, 67 deletions
diff --git a/src/common/string.c b/src/common/string.c
index 2c73900..027bf03 100644
--- a/src/common/string.c
+++ b/src/common/string.c
@@ -10,10 +10,9 @@ size_t strlen(const char* str) {
}
char *strchr(const char *str, char c) {
- while (*str) {
+ do {
if (*str == c) return (char*)str;
- str++;
- }
+ } while (*(str++));
return NULL;
}
diff --git a/src/kernel/Makefile b/src/kernel/Makefile
index 3fc7e9c..e847827 100644
--- a/src/kernel/Makefile
+++ b/src/kernel/Makefile
@@ -1,7 +1,8 @@
OBJ = core/loader.o core/kmain.o core/dbglog.o core/sys.o \
core/gdt.o core/idt.o core/interrupt.o core/context_switch.o core/thread.o \
- core/frame.o core/paging.o core/region.o core/kmalloc.o
+ core/frame.o core/paging.o core/region.o core/kmalloc.o \
+ user/vfs.o user/nullfs.o
LIB = ../common/common.lib
diff --git a/src/kernel/core/kmain.c b/src/kernel/core/kmain.c
index 6024b77..2782cc1 100644
--- a/src/kernel/core/kmain.c
+++ b/src/kernel/core/kmain.c
@@ -13,6 +13,9 @@
#include <thread.h>
+#include <vfs.h>
+#include <nullfs.h>
+
#include <slab_alloc.h>
#include <hashtbl.h>
@@ -150,23 +153,8 @@ void test_thread(void* a) {
if (i % 8 == 0) yield();
}
}
-void kernel_init_stage2(void* data) {
- dbg_print_region_info();
- dbg_print_frame_stats();
-
- test_hashtbl_1();
- test_hashtbl_2();
-
- thread_t *tb = new_thread(test_thread, 0);
- resume_thread(tb, false);
- for (int i = 0; i < 120; i++) {
- dbg_printf("a");
- for (int x = 0; x < 100000; x++) asm volatile("xor %%ebx, %%ebx":::"%ebx");
- }
- PANIC("Reached kmain end! Falling off the edge.");
-}
-
+void kernel_init_stage2(void* data);
void kmain(struct multiboot_info_t *mbd, int32_t mb_magic) {
dbglog_setup();
@@ -212,4 +200,33 @@ void kmain(struct multiboot_info_t *mbd, int32_t mb_magic) {
PANIC("Should never come here.");
}
+void kernel_init_stage2(void* data) {
+ dbg_print_region_info();
+ dbg_print_frame_stats();
+
+ test_hashtbl_1();
+ test_hashtbl_2();
+
+ thread_t *tb = new_thread(test_thread, 0);
+ resume_thread(tb, false);
+
+ for (int i = 0; i < 120; i++) {
+ dbg_printf("a");
+ for (int x = 0; x < 100000; x++) asm volatile("xor %%ebx, %%ebx":::"%ebx");
+ }
+
+ register_nullfs_driver();
+ fs_t *devfs = make_fs("nullfs", 0, "");
+ ASSERT(devfs != 0);
+
+ //TODO :
+ // - populate devfs with information regarding kernel command line & modules
+ // - create user process with init module provided on command line
+ // - give it rights to devfs
+ // - launch it
+ // - just return, this thread is done
+
+ PANIC("Reached kmain end! Falling off the edge.");
+}
+
/* vim: set ts=4 sw=4 tw=0 noet :*/
diff --git a/src/kernel/include/devfs.h b/src/kernel/include/devfs.h
new file mode 100644
index 0000000..0dee246
--- /dev/null
+++ b/src/kernel/include/devfs.h
@@ -0,0 +1,8 @@
+#pragma once
+
+#include <vfs.h>
+
+fs_t* init_devfs();
+
+
+/* vim: set ts=4 sw=4 tw=0 noet :*/
diff --git a/src/kernel/include/nullfs.h b/src/kernel/include/nullfs.h
new file mode 100644
index 0000000..16fff87
--- /dev/null
+++ b/src/kernel/include/nullfs.h
@@ -0,0 +1,25 @@
+#pragma once
+
+#include <vfs.h>
+
+#define NULLFS_OPT_CREATE_EN 1
+#define NULLFS_OPT_DELETE_EN 2
+
+typedef struct nullfs nullfs_t;
+
+typedef struct {
+ void* (*open)(void* f, int mode, fs_handle_t *h);
+ size_t (*read)(void* f, size_t offset, size_t len, char* buf);
+ size_t (*write)(void* f, size_t offset, size_t len, const char* buf);
+ void (*close)(void* f);
+ void (*delete)(void* f);
+} nullfs_node_ops_t;
+
+void register_nullfs_driver();
+
+nullfs_t* as_nullfs(fs_t *fs);
+
+bool nullfs_add(nullfs_t *f, const char* name, void* data, nullfs_node_ops_t* ops);
+bool nullfs_add_ram_file(nullfs_t *f, const char* name, void* data, size_t init_sz, int ok_modes);
+
+/* vim: set ts=4 sw=4 tw=0 noet :*/
diff --git a/src/kernel/include/process.h b/src/kernel/include/process.h
index 00ed1d7..a6ca1e9 100644
--- a/src/kernel/include/process.h
+++ b/src/kernel/include/process.h
@@ -3,41 +3,19 @@
// Things described in this file are essentially a public interface
// All implementation details are hidden in process.c
+// A process is a recipient for user code, as well as for mounting File Systems,
+// which allow access to features of the system.
+
#include <thread.h>
#include <hashtbl.h>
-#include <buffer.h>
-
-#define PW_NOT_WAITING 0
-#define PW_WAIT_ANY_MSG 1
-#define PW_WAIT_MSG_ON_CHAN 2
-
-#define PROCESS_MAILBOX_SIZE 42
-
-typedef int chan_id_t;
-typedef struct chan_pair {
- chan_id_t fst, snd;
-} chan_pair_t;
-
-typedef struct message {
- buffer_t *data;
- chan_id_t chan_id;
-} message_t;
struct process;
typedef struct process process_t;
-process_t *new_process(entry_t entry, void* data, chan_pair_t *give_chans);
-
-chan_pair_t new_chan(); // not used very often, but still usefull
-chan_id_t unbox_chan(chan_id_t chan, chan_id_t subchan);
-void detach_chan(chan_id_t chan); // chan ID is freed
-
-int send_message(chan_id_t chan, buffer_t *msg); // nonnull on error (recipient queue is full)
+process_t *new_process(entry_t entry, void* data);
-size_t await_message(); // returns the size of the first message to come
-size_t await_message_on_chan(chan_id_t chan); // returns the size of the first message to come
-message_t get_message(); // gets the first message in the queue (or nothing when queue is empty)
+bool mmap(process_t *proc, void* addr, size_t size, int type);
/* vim: set ts=4 sw=4 tw=0 noet :*/
diff --git a/src/kernel/include/vfs.h b/src/kernel/include/vfs.h
new file mode 100644
index 0000000..5f7a0d8
--- /dev/null
+++ b/src/kernel/include/vfs.h
@@ -0,0 +1,86 @@
+#pragma once
+
+#include <stdbool.h>
+#include <malloc.h>
+
+typedef struct {
+ // TODO
+ // (should also be moved to a user-visible header)
+} stat_t;
+
+#define FM_READ (0x01)
+#define FM_WRITE (0x02)
+#define FM_MMAP (0x04)
+#define FM_CREATE (0x10)
+#define FM_TRUNC (0x20)
+#define FM_APPEND (0x40)
+
+// How to use :
+// - when using a filesystem : never call the operations in fs_*_ops_t directly, use
+// the functions defined bellow
+// - when programming a filesystem : don't worry about allocating the fs_handle_t and fs_t,
+// it is done automatically
+
+
+// Structure defining a handle to an open file
+
+typedef struct {
+ size_t (*read)(void* f, size_t offset, size_t len, char* buf);
+ size_t (*write)(void* f, size_t offset, size_t len, const char* buf);
+ void (*close)(void* f);
+} fs_handle_ops_t;
+
+typedef struct fs_handle {
+ int refs;
+ fs_handle_ops_t *ops;
+ void* data;
+ int mode;
+} fs_handle_t;
+
+// Structure defining a filesystem
+
+typedef struct {
+ bool (*open)(void *fs, const char* file, int mode, fs_handle_t *s);
+ bool (*delete)(void *fs, const char* file);
+ bool (*rename)(void *fs, const char* from, const char* to);
+ bool (*stat)(void *fs, const char* file, stat_t *st);
+ int (*ioctl)(void *fs, const char* file, int command, void* data);
+ bool (*add_source)(void* fs, fs_handle_t* source);
+ void (*shutdown)(void *fs);
+} fs_ops_t;
+
+typedef struct fs {
+ int refs;
+ fs_ops_t *ops;
+ void* data;
+} fs_t;
+
+// Structure defining a filesystem driver
+
+typedef struct {
+ bool (*make)(fs_handle_t *source, char* opts, fs_t *d);
+ bool (*detect)(fs_handle_t *source);
+} fs_driver_ops_t;
+
+// Common functions
+
+void register_fs_driver(const char* name, fs_driver_ops_t *ops);
+
+fs_t* make_fs(const char* driver, fs_handle_t *source, char* opts);
+bool fs_add_source(fs_t *fs, fs_handle_t *source);
+void ref_fs(fs_t *fs);
+void unref_fs(fs_t *fs);
+
+bool fs_delete(fs_t *fs, const char* file);
+bool fs_rename(fs_t *fs, const char* from, const char* to);
+bool fs_stat(fs_t *fs, const char* file, stat_t *st);
+int fs_ioctl(fs_t *fs, const char* file, int command, void* data);
+
+fs_handle_t* fs_open(fs_t *fs, const char* file, int mode);
+void ref_file(fs_handle_t *file);
+void unref_file(fs_handle_t *file);
+size_t file_read(fs_handle_t *f, size_t offset, size_t len, char* buf);
+size_t file_write(fs_handle_t *f, size_t offset, size_t len, const char* buf);
+int file_get_mode(fs_handle_t *f);
+
+/* vim: set ts=4 sw=4 tw=0 noet :*/
diff --git a/src/kernel/user/nullfs.c b/src/kernel/user/nullfs.c
new file mode 100644
index 0000000..3c11198
--- /dev/null
+++ b/src/kernel/user/nullfs.c
@@ -0,0 +1,30 @@
+#include <nullfs.h>
+
+bool nullfs_i_make(fs_handle_t *source, char* opts, fs_t *d);
+
+fs_driver_ops_t nullfs_driver_ops = {
+ .make = nullfs_i_make,
+ .detect = 0,
+};
+
+fs_ops_t nullfs_ops = {
+ 0 //TODO
+};
+
+void register_nullfs_driver() {
+ register_fs_driver("nullfs", &nullfs_driver_ops);
+}
+
+nullfs_t *make_nullfs(char* options) {
+ fs_t *it = make_fs("nullfs", 0, options);
+ if (it == 0) return 0;
+ if (it->ops != &nullfs_ops) return 0;
+ return (nullfs_t*)it->data;
+}
+
+bool nullfs_i_make(fs_handle_t *source, char* opts, fs_t *d) {
+ // TODO
+ return false;
+}
+
+/* vim: set ts=4 sw=4 tw=0 noet :*/
diff --git a/src/kernel/user/process.c b/src/kernel/user/process.c
index 7519dae..22295ef 100644
--- a/src/kernel/user/process.c
+++ b/src/kernel/user/process.c
@@ -2,29 +2,12 @@
#include <process.h>
typedef struct process {
- thread_t *thread;
- int pid;
-
- mutex_t com_mutex;
+ pagedir_t *pd;
- hashtbl_t *chans;
- chan_id_t next_chan_id;
-
- message_t mbox[PROCESS_MAILBOX_SIZE];
- int mbox_size; // number of messages in queue
- int mbox_first; // first message in queue (circular buffer)
+ thread_t *thread;
- // a process can be in several waiting states :
- // - wait for any message
- // - wait for a message on a particular channel
- // in this case, if a message is pushed on this particular channel,
- // then it is put in front of the queue, so that it is the next message read
- // (it is guaranteed that doing await_message_on_chan() immediately followed by get_message()
- // gets the message whose size was returned by await_...)
- int wait_state;
- chan_id_t wait_chan_id; // when waiting for a message on a particular channel
+ int pid, ppid;
} process_t;
-int push_message(process_t *proc, message_t msg); // nonnull on error (process queue is full)
/* vim: set ts=4 sw=4 tw=0 noet :*/
diff --git a/src/kernel/user/vfs.c b/src/kernel/user/vfs.c
new file mode 100644
index 0000000..ebd5808
--- /dev/null
+++ b/src/kernel/user/vfs.c
@@ -0,0 +1,126 @@
+#include <debug.h>
+#include <vfs.h>
+#include <string.h>
+
+// ============================= //
+// FILESYSTEM DRIVER REGISTERING //
+// ============================= //
+
+typedef struct fs_driver {
+ const char* name;
+ fs_driver_ops_t *ops;
+ struct fs_driver *next;
+} fs_driver_t;
+
+fs_driver_t *drivers = 0;
+
+void register_fs_driver(const char* name, fs_driver_ops_t *ops) {
+ fs_driver_t *d = (fs_driver_t*)malloc(sizeof(fs_driver_t));
+ ASSERT(d != 0); // should we fail in a more graceful manner ?
+
+ d->name = name;
+ d->ops = ops;
+ d->next = drivers;
+ drivers = d;
+}
+
+// ================================== //
+// CREATING AND DELETINF FILE SYSTEMS //
+// ================================== //
+
+fs_t *make_fs(const char* drv_name, fs_handle_t *source, char* opts) {
+ // Look for driver
+ fs_driver_t *d = 0;
+ for(fs_driver_t *i = drivers; i != 0; i = i->next) {
+ if (drv_name != 0 && strcmp(i->name, drv_name) == 0) d = i;
+ if (drv_name == 0 && source != 0 && i->ops->detect && i->ops->detect(source)) d = i;
+ if (d != 0) break;
+ }
+
+ // Open file system
+ fs_t *fs = (fs_t*)malloc(sizeof(fs_t));
+ if (fs == 0) return 0;
+
+ if (d->ops->make(source, opts, fs)) {
+ return fs;
+ } else {
+ free(fs);
+ return 0;
+ }
+}
+
+bool fs_add_source(fs_t *fs, fs_handle_t *source) {
+ return fs->ops->add_source && fs->ops->add_source(fs->data, source);
+}
+
+void ref_fs(fs_t *fs) {
+ fs->refs++;
+}
+
+void unref_fs(fs_t *fs) {
+ fs->refs--;
+ if (fs->refs == 0) {
+ fs->ops->shutdown(fs->data);
+ free(fs);
+ }
+}
+
+// DOING THINGS IN FLESYSTEMS //
+
+bool fs_delete(fs_t *fs, const char* file) {
+ return fs->ops->delete && fs->ops->delete(fs->data, file);
+}
+
+bool fs_rename(fs_t *fs, const char* from, const char* to) {
+ return fs->ops->rename && fs->ops->rename(fs->data, from, to);
+}
+
+bool fs_stat(fs_t *fs, const char* name, stat_t *st) {
+ return fs->ops->stat && fs->ops->stat(fs->data, name, st);
+}
+
+int fs_ioctl(fs_t *fs, const char* file, int command, void* data) {
+ return fs->ops->ioctl && fs->ops->ioctl(fs->data, file, command, data);
+}
+
+// =================== //
+// OPERATIONS ON FILES //
+// =================== //
+
+fs_handle_t* fs_open(fs_t *fs, const char* file, int mode) {
+ fs_handle_t *h = (fs_handle_t*)malloc(sizeof(fs_handle_t));
+ if (h == 0) return 0;
+
+ if (fs->ops->open(fs->data, file, mode, h)) {
+ return h;
+ } else {
+ free(h);
+ return 0;
+ }
+}
+
+void ref_file(fs_handle_t *file) {
+ file->refs++;
+}
+
+void unrefe_file(fs_handle_t *file) {
+ file->refs--;
+ if (file->refs == 0) {
+ file->ops->close(file->data);
+ free(file);
+ }
+}
+
+size_t file_read(fs_handle_t *f, size_t offset, size_t len, char* buf) {
+ return f->ops->read && f->ops->read(f->data, offset, len, buf);
+}
+
+size_t file_write(fs_handle_t *f, size_t offset, size_t len, const char* buf) {
+ return f->ops->write && f->ops->write(f->data, offset, len, buf);
+}
+
+int file_get_mode(fs_handle_t *f) {
+ return f->mode;
+}
+
+/* vim: set ts=4 sw=4 tw=0 noet :*/