diff options
Diffstat (limited to 'kernel')
-rw-r--r-- | kernel/fs/fs.c | 7 | ||||
-rw-r--r-- | kernel/fs/tar.c | 262 | ||||
-rw-r--r-- | kernel/include/comus/fs/tar.h | 18 | ||||
-rw-r--r-- | kernel/include/comus/user.h | 2 | ||||
-rw-r--r-- | kernel/main.c | 38 | ||||
-rw-r--r-- | kernel/user.c | 36 |
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, §, §_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, §, 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, §, 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 |