summaryrefslogtreecommitdiff
path: root/kernel
diff options
context:
space:
mode:
Diffstat (limited to '')
-rw-r--r--kernel/fs/fs.c7
-rw-r--r--kernel/fs/tar.c262
-rw-r--r--kernel/include/comus/fs/tar.h18
-rw-r--r--kernel/include/comus/user.h2
-rw-r--r--kernel/main.c38
-rw-r--r--kernel/user.c36
6 files changed, 338 insertions, 25 deletions
diff --git a/kernel/fs/fs.c b/kernel/fs/fs.c
index a887ca4..01dea20 100644
--- a/kernel/fs/fs.c
+++ b/kernel/fs/fs.c
@@ -1,5 +1,6 @@
#include <lib.h>
#include <comus/fs.h>
+#include <comus/fs/tar.h>
#include <comus/mboot.h>
#include <comus/error.h>
@@ -50,9 +51,9 @@ static void load_fs(struct disk *disk)
fs->fs_id = disk->d_id;
fs->fs_present = 1;
- // // try examplefs
- // if (example_mount(fs) == SUCCESS)
- // return;
+ // try tarfs
+ if (tar_mount(fs) == SUCCESS)
+ return;
fs->fs_present = 0;
WARN("failed to load fs on disk %u", disk->d_id);
diff --git a/kernel/fs/tar.c b/kernel/fs/tar.c
new file mode 100644
index 0000000..7f34107
--- /dev/null
+++ b/kernel/fs/tar.c
@@ -0,0 +1,262 @@
+#include <comus/fs.h>
+#include <lib.h>
+
+struct tar_hdr {
+ char name[100];
+ char mode[8];
+ char uid[8];
+ char gid[8];
+ char size[12];
+ char mtime[12];
+ char chksum[8];
+ char typeflag;
+ char linkname[100];
+ char magic[6];
+ char version[2];
+ char uname[32];
+ char gname[32];
+ char devmajor[8];
+ char devminor[8];
+ char prefix[155];
+ char unused[12];
+};
+
+struct tar_file {
+ struct file file;
+ struct file_system *fs;
+ size_t len;
+ size_t offset;
+ size_t sect;
+};
+
+#define TAR_SECT_SIZE 512
+
+#define TMAGIC "ustar"
+#define TMAGLEN 6
+#define TVERSION "00"
+#define TVERSLEN 2
+
+#define REGTYPE '0'
+#define DIRTYPE '5'
+
+static int read_tar_hdr(struct disk *disk, uint32_t sect, struct tar_hdr *hdr)
+{
+ if (disk_read(disk, sect * TAR_SECT_SIZE, TAR_SECT_SIZE, hdr) <
+ TAR_SECT_SIZE)
+ return 1;
+
+ // check magic
+ if (memcmp(hdr->magic, TMAGIC, TMAGLEN) != 0)
+ return 1;
+
+ // check version
+ if (memcmp(hdr->version, TVERSION, TVERSLEN) != 0)
+ return 1;
+
+ return 0;
+}
+
+static int tar_to_fs_type(char typeflag)
+{
+ switch (typeflag) {
+ case REGTYPE:
+ return F_REG;
+ case DIRTYPE:
+ return F_DIR;
+ default:
+ return -1;
+ }
+}
+
+static int tar_locate(struct file_system *fs, const char *path,
+ struct tar_hdr *out_hdr, size_t *out_sect,
+ size_t *in_sect, bool partial)
+{
+ struct tar_hdr hdr;
+ size_t sect = 0;
+
+ if (in_sect != NULL)
+ sect = *in_sect;
+
+ while (1) {
+ size_t filesize, sects;
+ int cmp;
+
+ if (read_tar_hdr(fs->fs_disk, sect, &hdr))
+ return 1;
+
+ filesize = strtoull(hdr.size, NULL, 8);
+ sects = (filesize + TAR_SECT_SIZE - 1) / TAR_SECT_SIZE;
+
+ if (partial) {
+ size_t len = MIN(strlen(path), strlen(hdr.name));
+ cmp = memcmp(hdr.name, path, len);
+ } else {
+ cmp = memcmp(hdr.name, path, strlen(path) + 1);
+ }
+
+ if (cmp) {
+ // not our file, goto next
+ sect += sects + 1;
+ continue;
+ }
+
+ // we found our file!
+ *out_hdr = hdr;
+ *out_sect = sect;
+ if (in_sect != NULL)
+ *in_sect = sect + sects + 1;
+ return 0;
+ }
+
+ return 1;
+}
+
+int tar_read(struct file *in, char *buf, size_t len)
+{
+ struct tar_file *file = (struct tar_file *)in;
+ size_t max_bytes = file->len - file->offset;
+ long bytes = MIN(max_bytes, len);
+
+ if (file->file.f_type != F_REG)
+ return 1;
+
+ if (bytes < 1)
+ return 0;
+
+ bytes = disk_read(file->fs->fs_disk,
+ (file->sect + 1) * TAR_SECT_SIZE + file->offset, bytes,
+ buf);
+ if (bytes < 0)
+ return bytes; // return err code
+
+ file->offset += bytes;
+ return bytes;
+}
+
+int tar_write(struct file *in, const char *buf, size_t len)
+{
+ (void)in;
+ (void)buf;
+ (void)len;
+
+ // cannot write to tar balls
+ return -1;
+}
+
+int tar_seek(struct file *in, long int off, int whence)
+{
+ struct tar_file *file = (struct tar_file *)in;
+ switch (whence) {
+ case SEEK_SET:
+ file->offset = off;
+ return 0;
+ case SEEK_CUR:
+ file->offset += off;
+ return 0;
+ case SEEK_END:
+ file->offset = file->len + off;
+ return 0;
+ default:
+ return 1;
+ }
+}
+
+int tar_ents(struct file *in, struct dirent *ent, size_t entry)
+{
+ struct tar_file *file;
+ struct tar_hdr dir, hdr;
+ size_t sect;
+ size_t sect_off = 0;
+ size_t idx = 0;
+
+ file = (struct tar_file *)in;
+ sect = 0;
+
+ if (file->file.f_type != F_DIR)
+ return -1;
+
+ if (read_tar_hdr(file->fs->fs_disk, sect, &dir))
+ return 1;
+
+ while (1) {
+ if (tar_locate(file->fs, dir.name, &hdr, &sect, &sect_off, true))
+ return 1;
+
+ if (idx != entry) {
+ idx++;
+ continue;
+ }
+
+ ent->d_offset = entry;
+ ent->d_namelen = strlen(hdr.name);
+ memcpy(ent->d_name, hdr.name, ent->d_namelen + 1);
+ return 0;
+ }
+
+ return 1;
+}
+
+void tar_close(struct file *file)
+{
+ kfree(file);
+}
+
+int tar_open(struct file_system *fs, const char *path, struct file **out)
+{
+ struct tar_file *file;
+ struct tar_hdr hdr;
+ size_t sect;
+
+ if (tar_locate(fs, path, &hdr, &sect, NULL, false))
+ return 1;
+
+ file = kalloc(sizeof(struct tar_file));
+ if (file == NULL)
+ return 1;
+
+ file->file.f_type = tar_to_fs_type(hdr.typeflag);
+ file->file.read = tar_read;
+ file->file.write = tar_write;
+ file->file.seek = tar_seek;
+ file->file.ents = tar_ents;
+ file->file.close = tar_close;
+ file->fs = fs;
+ file->len = strtoull(hdr.size, NULL, 8);
+ file->offset = 0;
+ file->sect = sect;
+ *out = (struct file *)file;
+
+ return 0;
+}
+
+int tar_stat(struct file_system *fs, const char *path, struct stat *stat)
+{
+ struct tar_hdr hdr;
+ size_t sect;
+
+ if (tar_locate(fs, path, &hdr, &sect, NULL, false))
+ return 1;
+
+ stat->s_length = strtoull(hdr.size, NULL, 8);
+ stat->s_type = tar_to_fs_type(hdr.typeflag);
+
+ return 0;
+}
+
+int tar_mount(struct file_system *fs)
+{
+ struct tar_hdr hdr;
+
+ // if first tar hdr is valid, assume valid tarball
+ if (read_tar_hdr(fs->fs_disk, 0, &hdr))
+ return 1;
+
+ fs->fs_present = true;
+ fs->fs_name = "tar";
+ fs->open = tar_open;
+ fs->stat = tar_stat;
+
+ INFO("loaded tarfs on disk %d", fs->fs_disk->d_id);
+ return 0;
+}
diff --git a/kernel/include/comus/fs/tar.h b/kernel/include/comus/fs/tar.h
new file mode 100644
index 0000000..084c8bd
--- /dev/null
+++ b/kernel/include/comus/fs/tar.h
@@ -0,0 +1,18 @@
+/**
+ * @file tar.h
+ *
+ * Tarball
+ */
+
+#ifndef TAR_FS_H_
+#define TAR_FS_H_
+
+#include <comus/fs.h>
+
+/**
+ * Attempts to mount tar filesystem on disk
+ * @returns 0 on success
+ */
+int tar_mount(struct file_system *fs);
+
+#endif /* fs.h */
diff --git a/kernel/include/comus/user.h b/kernel/include/comus/user.h
index f51ada5..a1a718b 100644
--- a/kernel/include/comus/user.h
+++ b/kernel/include/comus/user.h
@@ -15,7 +15,7 @@
/**
* Load a user elf program from a file into a pcb
*/
-int user_load(struct pcb *pcb, struct disk *disk);
+int user_load(struct pcb *pcb, struct file *file);
/**
* Clone a user process. Used for fork().
diff --git a/kernel/main.c b/kernel/main.c
index c15c38d..a306e2b 100644
--- a/kernel/main.c
+++ b/kernel/main.c
@@ -22,6 +22,36 @@ void kreport(void)
gpu_report();
}
+void load_init(void)
+{
+ struct file_system *fs;
+ struct file *file;
+
+ if (pcb_alloc(&init_pcb))
+ return;
+
+ // get root fs
+ fs = fs_get_root_file_system();
+ if (fs == NULL)
+ return;
+
+ // get init bin
+ if (fs->open(fs, "bin/apple", &file))
+ return;
+
+ if (user_load(init_pcb, file)) {
+ file->close(file);
+ return;
+ }
+
+ // close file
+ file->close(file);
+
+ // schedule and dispatch init
+ schedule(init_pcb);
+ dispatch();
+}
+
__attribute__((noreturn)) void main(long magic, volatile void *mboot)
{
// initalize idt and pic
@@ -49,11 +79,7 @@ __attribute__((noreturn)) void main(long magic, volatile void *mboot)
kreport();
// load init process
- pcb_alloc(&init_pcb);
- if (user_load(init_pcb, &fs_disks[0]))
- panic("failed to load init");
+ load_init();
- // schedule and dispatch init
- schedule(init_pcb);
- dispatch();
+ panic("failed to load init");
}
diff --git a/kernel/user.c b/kernel/user.c
index e22248a..4007383 100644
--- a/kernel/user.c
+++ b/kernel/user.c
@@ -14,13 +14,13 @@
#define USER_STACK_LEN (4 * PAGE_SIZE)
#define BLOCK_SIZE (PAGE_SIZE * 1000)
-static uint8_t *load_buffer = NULL;
+static char *load_buffer = NULL;
#define USER_CODE 0x18
#define USER_DATA 0x20
#define RING3 3
-static int user_load_segment(struct pcb *pcb, struct disk *disk, int idx)
+static int user_load_segment(struct pcb *pcb, struct file *file, int idx)
{
Elf64_Phdr hdr;
size_t mem_bytes, mem_pages;
@@ -56,14 +56,17 @@ static int user_load_segment(struct pcb *pcb, struct disk *disk, int idx)
if (mapADDR == NULL)
return 1;
+ // seek to start of segment
+ if (file->seek(file, hdr.p_offset, SEEK_SET))
+ return 1;
+
// load data
size_t total_read = 0;
while (total_read < file_bytes) {
size_t read = BLOCK_SIZE;
if (read > file_bytes - total_read)
read = file_bytes - total_read;
- if ((read = disk_read(disk, hdr.p_offset + total_read, read,
- load_buffer)) < 1) {
+ if ((read = file->read(file, load_buffer, read)) < 1) {
kunmapaddr(mapADDR);
return 1;
}
@@ -79,7 +82,7 @@ static int user_load_segment(struct pcb *pcb, struct disk *disk, int idx)
return 0;
}
-static int user_load_segments(struct pcb *pcb, struct disk *disk)
+static int user_load_segments(struct pcb *pcb, struct file *file)
{
int ret = 0;
@@ -91,7 +94,7 @@ static int user_load_segments(struct pcb *pcb, struct disk *disk)
return 1;
for (int i = 0; i < pcb->n_elf_segments; i++)
- if ((ret = user_load_segment(pcb, disk, i)))
+ if ((ret = user_load_segment(pcb, file, i)))
return ret;
if (pcb->heap_start == NULL) {
@@ -144,11 +147,13 @@ static int validate_elf_hdr(struct pcb *pcb)
return 0;
}
-static int user_load_elf(struct pcb *pcb, struct disk *disk)
+static int user_load_elf(struct pcb *pcb, struct file *file)
{
int ret = 0;
- ret = disk_read(disk, 0, sizeof(Elf64_Ehdr), &pcb->elf_header);
+ if (file->seek(file, 0, SEEK_SET))
+ return 1;
+ ret = file->read(file, (char *)&pcb->elf_header, sizeof(Elf64_Ehdr));
if (ret < 0)
return 1;
@@ -156,9 +161,10 @@ static int user_load_elf(struct pcb *pcb, struct disk *disk)
return 1;
pcb->n_elf_segments = pcb->elf_header.e_phnum;
- ret = disk_read(disk, pcb->elf_header.e_phoff,
- sizeof(Elf64_Phdr) * pcb->elf_header.e_phnum,
- &pcb->elf_segments);
+ if (file->seek(file, pcb->elf_header.e_phoff, SEEK_SET))
+ return 1;
+ ret = file->read(file, (char *)&pcb->elf_segments,
+ sizeof(Elf64_Phdr) * pcb->elf_header.e_phnum);
if (ret < 0)
return 1;
@@ -199,10 +205,10 @@ static int user_setup_stack(struct pcb *pcb)
return 0;
}
-int user_load(struct pcb *pcb, struct disk *disk)
+int user_load(struct pcb *pcb, struct file *file)
{
// check inputs
- if (pcb == NULL || disk == NULL)
+ if (pcb == NULL || file == NULL)
return 1;
// allocate memory context
@@ -211,11 +217,11 @@ int user_load(struct pcb *pcb, struct disk *disk)
goto fail;
// load elf information
- if (user_load_elf(pcb, disk))
+ if (user_load_elf(pcb, file))
goto fail;
// load segments into memory
- if (user_load_segments(pcb, disk))
+ if (user_load_segments(pcb, file))
goto fail;
// setup process stack