aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAlex Auvolat <alex.auvolat@ens.fr>2015-02-24 18:52:09 +0100
committerAlex Auvolat <alex.auvolat@ens.fr>2015-02-24 18:52:09 +0100
commit990e4785820136f2ab4a3bf4c1afbf0e8cf28b3c (patch)
tree26a6df66cdf12d9539e455c3607290ab069a3983
parentd89c862fb2f569275300d6a64caaa0b287367558 (diff)
downloadkogata-990e4785820136f2ab4a3bf4c1afbf0e8cf28b3c.tar.gz
kogata-990e4785820136f2ab4a3bf4c1afbf0e8cf28b3c.zip
Complete ISO9660 impl ; some strange wtf is going on.
-rwxr-xr-xmake_cdrom.sh1
-rw-r--r--menu_cdrom.lst2
-rw-r--r--src/kernel/core/kmain.c16
-rw-r--r--src/kernel/dev/pciide.c1
-rw-r--r--src/kernel/fs/iso9660.c267
-rw-r--r--src/kernel/include/fs/iso9660.h19
6 files changed, 302 insertions, 4 deletions
diff --git a/make_cdrom.sh b/make_cdrom.sh
index cccca8e..b481fcc 100755
--- a/make_cdrom.sh
+++ b/make_cdrom.sh
@@ -10,6 +10,7 @@ fi
cp menu_cdrom.lst cdrom/boot/grub/menu.lst
cp src/kernel/kernel.bin cdrom; strip cdrom/kernel.bin
cp src/apps/init/init.bin cdrom; strip cdrom/init.bin
+cp README.md cdrom
genisoimage -R -b boot/grub/stage2_eltorito -no-emul-boot \
-boot-load-size 4 -boot-info-table -input-charset ascii \
diff --git a/menu_cdrom.lst b/menu_cdrom.lst
index f055427..16cf6b5 100644
--- a/menu_cdrom.lst
+++ b/menu_cdrom.lst
@@ -3,7 +3,7 @@ default 1
title kogata OS
-kernel /kernel.bin root=io:/atapi0 init=root:/init.bin
+kernel /kernel.bin root=io:/atapi0 root_opts=l init=root:/init.bin
title kogata OS without root
kernel /kernel.bin init=io:/mod/init.bin
diff --git a/src/kernel/core/kmain.c b/src/kernel/core/kmain.c
index 8242f99..c08d749 100644
--- a/src/kernel/core/kmain.c
+++ b/src/kernel/core/kmain.c
@@ -155,6 +155,22 @@ void kernel_init_stage2(void* data) {
fs_t *rootfs = 0;
if (btree_find(cmdline, "root") != 0) rootfs = setup_rootfs(cmdline, iofs);
+ if (rootfs != 0) {
+ fs_handle_t *readme = fs_open(rootfs, "/readme.md", FM_READ);
+ if (readme != 0) {
+ char buf[100];
+ dbg_printf("Read %d.\n", file_read(readme, 0, 100, buf));
+ buf[99] = 0;
+ dbg_printf("%s\n", buf);
+ unref_file(readme);
+ }
+ }
+
+ void iter(void* a, void* b) {
+ dbg_printf("'%s': '%s' (0x%p, 0x%p)\n", a, b, a, b);
+ }
+ btree_iter(cmdline, iter);
+
launch_init(cmdline, iofs, rootfs);
// We are done here
diff --git a/src/kernel/dev/pciide.c b/src/kernel/dev/pciide.c
index ad7375b..f4474ba 100644
--- a/src/kernel/dev/pciide.c
+++ b/src/kernel/dev/pciide.c
@@ -754,7 +754,6 @@ int ide_vfs_ioctl(fs_handle_ptr f, int command, void* data) {
if (command == IOCTL_BLOCKDEV_GET_BLOCK_COUNT)
ret = d->c->devices[d->device].size;
- dbg_printf("ioctl (0x%p) %d -> %d\n", f, command, ret);
return ret;
}
diff --git a/src/kernel/fs/iso9660.c b/src/kernel/fs/iso9660.c
index d8c103f..505f279 100644
--- a/src/kernel/fs/iso9660.c
+++ b/src/kernel/fs/iso9660.c
@@ -1,13 +1,71 @@
+#include <string.h>
#include <debug.h>
#include <fs/iso9660.h>
static bool iso9660_make(fs_handle_t *source, const char* opts, fs_t *t);
+static void iso9660_fs_shutdown(fs_ptr f);
+
+static bool iso9660_node_stat(fs_node_ptr n, stat_t *st);
+static void iso9660_node_dispose(fs_node_ptr n);
+static bool iso9660_dir_open(fs_node_ptr n, int mode, fs_handle_t *s);
+static bool iso9660_dir_walk(fs_node_ptr n, const char* file, struct fs_node *node_d);
+static bool iso9660_file_open(fs_node_ptr n, int mode, fs_handle_t *s);
+
+static size_t iso9660_fh_read(fs_handle_ptr f, size_t offset, size_t len, char* buf);
+static void iso9660_fh_close(fs_handle_ptr f);
+static bool iso9660_dh_readdir(fs_handle_ptr f, dirent_t *d);
+static void iso9660_dh_close(fs_handle_ptr f);
static fs_driver_ops_t iso9660_driver_ops = {
.make = iso9660_make,
};
+static fs_ops_t iso9660_fs_ops = {
+ .add_source = 0,
+ .shutdown = iso9660_fs_shutdown
+};
+
+static fs_node_ops_t iso9660_dir_ops = {
+ .open = iso9660_dir_open,
+ .stat = iso9660_node_stat,
+ .walk = iso9660_dir_walk,
+ .dispose = iso9660_node_dispose,
+ .delete = 0,
+ .move = 0,
+ .create = 0,
+};
+
+static fs_node_ops_t iso9660_file_ops = {
+ .open = iso9660_file_open,
+ .stat = iso9660_node_stat,
+ .dispose = iso9660_node_dispose,
+ .walk = 0,
+ .delete = 0,
+ .move = 0,
+ .create = 0,
+};
+
+static fs_handle_ops_t iso9660_dh_ops = {
+ .readdir = iso9660_dh_readdir,
+ .close = iso9660_dh_close,
+ .read = 0,
+ .write = 0,
+ .ioctl = 0,
+ .get_page = 0,
+ .commit_page = 0,
+};
+
+static fs_handle_ops_t iso9660_fh_ops = {
+ .readdir = 0,
+ .close = iso9660_fh_close,
+ .read = iso9660_fh_read,
+ .write = 0,
+ .ioctl = 0,
+ .get_page = 0,
+ .commit_page = 0,
+};
+
void register_iso9660_driver() {
ASSERT(sizeof(iso9660_dr_date_t) == 7);
ASSERT(sizeof(iso9660_dr_t) == 34);
@@ -20,7 +78,7 @@ void register_iso9660_driver() {
// FILESYSTEM DETECTION AND SETUP //
// ============================== //
-static bool iso9660_make(fs_handle_t *source, const char* opts, fs_t *t) {
+bool iso9660_make(fs_handle_t *source, const char* opts, fs_t *t) {
stat_t st;
if (!file_stat(source, &st)) return false;
if ((st.type & FT_BLOCKDEV) == 0) return false;
@@ -38,7 +96,212 @@ static bool iso9660_make(fs_handle_t *source, const char* opts, fs_t *t) {
ent_sect++;
}
- return false; // TODO
+ // Looks like we are good, go ahead.
+ iso9660_fs_t *fs = (iso9660_fs_t*)malloc(sizeof(iso9660_fs_t));
+ if (fs == 0) return false;
+
+ iso9660_node_t *root = (iso9660_node_t*)malloc(sizeof(iso9660_node_t));
+ if (root == 0) {
+ free(fs);
+ return false;
+ }
+
+ memcpy(&fs->vol_descr, &ent.prim, sizeof(iso9660_pvd_t));
+ fs->disk = source;
+ fs->use_lowercase = (strchr(opts, 'l') != 0);
+
+ memcpy(&root->dr, &ent.prim.root_directory, sizeof(iso9660_dr_t));
+ root->fs = fs;
+
+ t->data = fs;
+ t->ops = &iso9660_fs_ops;
+
+ t->root->data = root;
+ t->root->ops = &iso9660_dir_ops;
+
+ return true; // TODO
+}
+
+void iso9660_fs_shutdown(fs_ptr f) {
+ iso9660_fs_t *fs = (iso9660_fs_t*)f;
+ free(fs);
+}
+
+// ======================================= //
+// READING STUFF THAT IS ON THE FILESYSTEM //
+// ======================================= //
+
+static void convert_dr_to_lowercase(iso9660_dr_t *dr) {
+ for (int i = 0; i < dr->name_len; i++) {
+ if (dr->name[i] >= 'A' && dr->name[i] <= 'Z')
+ dr->name[i] += ('a' - 'A');
+ }
+}
+
+static void dr_stat(iso9660_dr_t *dr, stat_t *st) {
+ if (dr->flags & ISO9660_DR_FLAG_DIR) {
+ st->type = FT_DIR;
+ st->access = FM_READDIR;
+ st->size = (dr->size.lsb / 256);
+ } else {
+ st->type = FT_REGULAR;
+ st->access = FM_READ;
+ st->size = dr->size.lsb;
+ }
+}
+
+bool iso9660_node_stat(fs_node_ptr n, stat_t *st) {
+ iso9660_node_t *node = (iso9660_node_t*)n;
+
+ dr_stat(&node->dr, st);
+ return true;
+}
+
+void iso9660_node_dispose(fs_node_ptr n) {
+ iso9660_node_t *node = (iso9660_node_t*)n;
+ free(node);
+}
+
+bool iso9660_dir_open(fs_node_ptr n, int mode, fs_handle_t *s) {
+ iso9660_node_t *node = (iso9660_node_t*)n;
+
+ if (mode != FM_READDIR) return false;
+
+ iso9660_dh_t *handle = (iso9660_dh_t*)malloc(sizeof(iso9660_dh_t));
+ if (handle == 0) return false;
+
+ handle->n = node;
+ handle->pos = 0;
+
+ s->mode = mode;
+ s->data = handle;
+ s->ops = &iso9660_dh_ops;
+
+ return true;
+}
+bool iso9660_dir_walk(fs_node_ptr n, const char* search_for, struct fs_node *node_d) {
+ iso9660_node_t *node = (iso9660_node_t*)n;
+
+ size_t filename_len = strlen(search_for);
+
+ dbg_printf("Looking up %s...\n", search_for);
+
+ char buffer[2048];
+ size_t dr_len = 0;
+ for (size_t pos = 0; pos < node->dr.size.lsb; pos += dr_len) {
+ if (pos % 2048 == 0) {
+ if (file_read(node->fs->disk, node->dr.lba_loc.lsb * 2048 + pos, 2048, buffer) != 2048)
+ return false;
+ }
+
+ iso9660_dr_t *dr = (iso9660_dr_t*)(buffer + (pos % 2048));
+ dr_len = dr->len;
+ if (dr_len == 0) return false;
+
+ if (node->fs->use_lowercase) convert_dr_to_lowercase(dr);
+
+ char* name = dr->name;
+ size_t len = dr->name_len - 2;
+
+ if (name[len] != ';') continue;
+ if (len != filename_len) continue;
+
+ if (strncmp(name, search_for, len) == 0) {
+ // Found it !
+ iso9660_node_t *n = (iso9660_node_t*)malloc(sizeof(iso9660_node_t*));
+ if (n == 0) return false;
+
+ memcpy(&n->dr, dr, sizeof(iso9660_dr_t));
+ n->fs = node->fs;
+
+ node_d->data = n;
+ node_d->ops = (dr->flags & ISO9660_DR_FLAG_DIR ? &iso9660_dir_ops : &iso9660_file_ops);
+
+ return true;
+ }
+ }
+ return false; // not found
+}
+
+bool iso9660_file_open(fs_node_ptr n, int mode, fs_handle_t *s) {
+ iso9660_node_t *node = (iso9660_node_t*)n;
+
+ if (mode != FM_READ) return false;
+
+ s->data = node;
+ s->ops = &iso9660_fh_ops;
+ s->mode = mode;
+ return true;
+}
+
+size_t iso9660_fh_read(fs_handle_ptr f, size_t offset, size_t len, char* buf) {
+ iso9660_node_t *node = (iso9660_node_t*)f;
+
+ if (offset >= node->dr.size.lsb) return 0;
+ if (offset + len > node->dr.size.lsb) len = node->dr.size.lsb - offset;
+
+ size_t ret = 0;
+
+ size_t off0 = offset % 2048;
+ char buffer[2048];
+ for (size_t i = offset - off0; i < offset + len; i += 2048) {
+ if (file_read(node->fs->disk, node->dr.lba_loc.lsb * 2048 + i, 2048, buffer) != 2048) {
+ dbg_printf("Could not read data at %d\n", i);
+ break;
+ }
+
+ size_t block_pos;
+ size_t block_buf_ofs;
+ if (i <= offset) {
+ block_pos = 0;
+ block_buf_ofs = off0;
+ } else {
+ block_pos = i - off0;
+ block_buf_ofs = 0;
+ }
+ size_t block_len = (i + 2048 > offset + len ? offset + len - i : 2048);
+
+ memcpy(buf + block_pos, buffer + block_buf_ofs, block_len);
+ ret += block_len;
+ }
+
+ return ret;
+}
+void iso9660_fh_close(fs_handle_ptr f) {
+ // nothing to do
+}
+bool iso9660_dh_readdir(fs_handle_ptr f, dirent_t *d) {
+ iso9660_dh_t *handle = (iso9660_dh_t*)f;
+ iso9660_node_t *node = handle->n;
+
+ while (true) {
+ if (handle->pos >= node->dr.size.lsb) return false;
+
+ if (handle->pos % 2048 == 0) {
+ if (file_read(node->fs->disk, node->dr.lba_loc.lsb * 2048 + handle->pos, 2048, handle->buffer) != 2048)
+ return false;
+ }
+
+ iso9660_dr_t *dr = (iso9660_dr_t*)(handle->buffer + (handle->pos % 2048));
+ if (node->fs->use_lowercase) convert_dr_to_lowercase(dr);
+
+ handle->pos += dr->len;
+
+ size_t len = dr->name_len - 2;
+ if (dr->name_len > 0 && dr->name[len] == ';') {
+ if (len >= DIR_MAX) len = DIR_MAX - 1;
+ memcpy(d->name, dr->name, len);
+ d->name[len] = 0;
+ dr_stat(dr, &d->st);
+
+ return true;
+ }
+ // else skip this record
+ }
+}
+void iso9660_dh_close(fs_handle_ptr f) {
+ iso9660_dh_t* handle = (iso9660_dh_t*)f;
+ free(handle);
}
/* vim: set ts=4 sw=4 tw=0 noet :*/
diff --git a/src/kernel/include/fs/iso9660.h b/src/kernel/include/fs/iso9660.h
index 292b4dd..85e9b7b 100644
--- a/src/kernel/include/fs/iso9660.h
+++ b/src/kernel/include/fs/iso9660.h
@@ -8,6 +8,8 @@
#define ISO9660_VDT_PARTITION 3
#define ISO9660_VDT_TERMINATOR 255
+#define ISO9660_DR_FLAG_DIR (1 << 1)
+
typedef struct {
uint32_t lsb, msb;
} uint32_lsb_msb_t;
@@ -87,6 +89,23 @@ typedef union {
char buf[2048];
} iso9660_vdt_entry_t;
+typedef struct {
+ iso9660_pvd_t vol_descr;
+ fs_handle_t *disk;
+ bool use_lowercase; // lowercase all names
+} iso9660_fs_t;
+
+typedef struct {
+ iso9660_dr_t dr;
+ iso9660_fs_t *fs;
+} iso9660_node_t;
+
+typedef struct {
+ iso9660_node_t *n;
+ size_t pos;
+ char buffer[2048];
+} iso9660_dh_t; // handle to an open directory
+
void register_iso9660_driver();
/* vim: set ts=4 sw=4 tw=0 noet :*/