diff options
author | Marvin Borner | 2019-11-20 22:17:48 +0100 |
---|---|---|
committer | Marvin Borner | 2019-11-20 22:28:30 +0100 |
commit | 0ba991750314310a5e53b0d8135aef5b1352b261 (patch) | |
tree | acae7106a24b85116cd7119bd239c3d9299f2ba8 /src/kernel/fs | |
parent | 6ca5f1bcec7f0716bad5e1cdd38d41be137fe7e5 (diff) |
Began two-stage hdd bootloader and os installer
Diffstat (limited to 'src/kernel/fs')
-rw-r--r-- | src/kernel/fs/ata_pio.c | 125 | ||||
-rw-r--r-- | src/kernel/fs/ata_pio.h | 31 | ||||
-rw-r--r-- | src/kernel/fs/atapi_pio.c | 32 | ||||
-rw-r--r-- | src/kernel/fs/atapi_pio.h | 26 | ||||
-rw-r--r-- | src/kernel/fs/initrd.c | 131 | ||||
-rw-r--r-- | src/kernel/fs/initrd.h | 22 | ||||
-rw-r--r-- | src/kernel/fs/install.c | 61 | ||||
-rw-r--r-- | src/kernel/fs/install.h | 6 | ||||
-rw-r--r-- | src/kernel/fs/iso9660/iso9660.c | 60 | ||||
-rw-r--r-- | src/kernel/fs/iso9660/iso9660.h | 22 | ||||
-rw-r--r-- | src/kernel/fs/marfs/directory.c | 55 | ||||
-rw-r--r-- | src/kernel/fs/marfs/disklevel.c | 23 | ||||
-rw-r--r-- | src/kernel/fs/marfs/marfs.h | 81 | ||||
-rw-r--r-- | src/kernel/fs/marfs/new_file.c | 102 | ||||
-rw-r--r-- | src/kernel/fs/marfs/read_whole_file.c | 65 | ||||
-rw-r--r-- | src/kernel/fs/marfs/sectorlevel.c | 101 |
16 files changed, 790 insertions, 153 deletions
diff --git a/src/kernel/fs/ata_pio.c b/src/kernel/fs/ata_pio.c new file mode 100644 index 0000000..d577ea1 --- /dev/null +++ b/src/kernel/fs/ata_pio.c @@ -0,0 +1,125 @@ +#include <kernel/io/io.h> +#include <kernel/lib/alloc.h> +#include <kernel/fs/ata_pio.h> +#include <kernel/interrupts/interrupts.h> + +struct ATA_INTERFACE *new_ATA(uint8_t master, uint16_t portBase) { + struct ATA_INTERFACE *ret = kmalloc(sizeof(struct ATA_INTERFACE)); + + ret->master = master; + ret->dataPort = portBase; + ret->errorPort = portBase + 0x1; + ret->sectorCountPort = portBase + 0x2; + ret->lbaLowPort = portBase + 0x3; + ret->lbaMidPort = portBase + 0x4; + ret->lbaHiPort = portBase + 0x5; + ret->devicePort = portBase + 0x6; + ret->commandPort = portBase + 0x7; + ret->controlPort = portBase + 0x206; + + // isr_ignore(0x06); + // isr_ignore(0x2E); + // isr_ignore(0x2F); + + return ret; +} + +uint8_t ATA_identify(struct ATA_INTERFACE *iface, uint16_t *retdata) { + send_b(iface->devicePort, iface->master ? 0xA0 : 0xB0); + send_b(iface->controlPort, 0); + + send_b(iface->devicePort, 0xA0); + uint8_t status = receive_b(iface->commandPort); + if (status == 0xFF) return 1; + + send_b(iface->devicePort, iface->master ? 0xA0 : 0xB0); + send_b(iface->sectorCountPort, 0); + send_b(iface->lbaLowPort, 0); + send_b(iface->lbaMidPort, 0); + send_b(iface->lbaHiPort, 0); + send_b(iface->commandPort, 0xEC); // Identify command + + status = receive_b(iface->commandPort); + if (!status) return 1; + + while (((status & 0x80) == 0x80) && ((status & 0x01) != 0x01)) { + status = receive_b(iface->commandPort); + } + + if (status & 0x01) return 1; + + for (int i = 0; i < 256; i++) retdata[i] = receive_w(iface->dataPort); + return 0; +} + +uint8_t *ATA_read28(struct ATA_INTERFACE *iface, uint32_t sector) { + if (sector > 0x0FFFFFFF) return 0; + + send_b(iface->devicePort, (iface->master ? 0xE0 : 0xF0) | ((sector & 0x0F000000) >> 24)); + + uint8_t status; + for (int i = 0; i < 5; i++) status = receive_b(iface->commandPort); + if (status == 0xFF) return 0; + + send_b(iface->errorPort, 0); + send_b(iface->sectorCountPort, 1); + send_b(iface->lbaLowPort, sector & 0x000000FF); + send_b(iface->lbaMidPort, (sector & 0x0000FF00) >> 8); + send_b(iface->lbaHiPort, (sector & 0x00FF0000) >> 16); + send_b(iface->commandPort, 0x20); // Read command + + status = receive_b(iface->commandPort); + while ((status & 0x80) && !(status & 0x01)) status = receive_b(iface->commandPort); + + uint8_t *ret = kmalloc(BYTES_PER_SECTOR); + for (int i = 0; i < BYTES_PER_SECTOR; i += 2) { + uint16_t data = receive_w(iface->dataPort); + ret[i] = data & 0xFF; + ret[i + 1] = (data >> 8) & 0xFF; + } + return ret; +} + +uint8_t ATA_write28(struct ATA_INTERFACE *iface, uint32_t sector, uint8_t *contents) { + if (sector > 0x0FFFFFFF) return 1; + asm volatile ("cli"); + + send_b(iface->devicePort, (iface->master ? 0xE0 : 0xF0) | ((sector & 0x0F000000) >> 24)); + + uint8_t status; + for (int i = 0; i < 5; i++) status = receive_b(iface->commandPort); + if (status == 0xFF) return 1; + + send_b(iface->errorPort, 0); + send_b(iface->sectorCountPort, 1); + send_b(iface->lbaLowPort, sector & 0x000000FF); + send_b(iface->lbaMidPort, (sector & 0x0000FF00) >> 8); + send_b(iface->lbaHiPort, (sector & 0x00FF0000) >> 16); + send_b(iface->commandPort, 0x30); // Write command + + while ((status & 0x80) || !(status & 0x08)) status = receive_b(iface->commandPort); + + if (status & (0x01 || 0x20)) return 2; + + for (int i = 0; i < BYTES_PER_SECTOR; i += 2) { + uint16_t data = contents[i]; + data |= ((uint16_t) contents[i + 1]) << 8; + send_w(iface->dataPort, data); + } + + send_b(iface->commandPort, 0xE7); // Flush command + + for (int i = 0; i < 5; i++) status = receive_b(iface->commandPort); + if (!status) return 3; + + while ((status & 0x80) && !(status & 0x01)) { + status = receive_b(iface->commandPort); + } + + return 0; +} + +uint8_t ATA_clear28(struct ATA_INTERFACE *iface, uint32_t sector) { + uint8_t emptysector[512] = {0}; + return ATA_write28(iface, sector, emptysector); +}
\ No newline at end of file diff --git a/src/kernel/fs/ata_pio.h b/src/kernel/fs/ata_pio.h new file mode 100644 index 0000000..3f1439d --- /dev/null +++ b/src/kernel/fs/ata_pio.h @@ -0,0 +1,31 @@ +#ifndef MELVIX_ATA_PIO_H +#define MELVIX_ATA_PIO_H + +#include <stdint.h> + +#define BYTES_PER_SECTOR 512 + +struct ATA_INTERFACE { + uint8_t master; + uint16_t dataPort; + uint16_t errorPort; + uint16_t sectorCountPort; + uint16_t lbaLowPort; + uint16_t lbaMidPort; + uint16_t lbaHiPort; + uint16_t devicePort; + uint16_t commandPort; + uint16_t controlPort; +}; + +struct ATA_INTERFACE *new_ATA(uint8_t master, uint16_t portBase); + +uint8_t ATA_identify(struct ATA_INTERFACE *iface, uint16_t *retdata); + +uint8_t *ATA_read28(struct ATA_INTERFACE *iface, uint32_t sector); + +uint8_t ATA_write28(struct ATA_INTERFACE *iface, uint32_t sector, uint8_t *contents); + +uint8_t ATA_clear28(struct ATA_INTERFACE *iface, uint32_t sector); + +#endif diff --git a/src/kernel/fs/atapi_pio.c b/src/kernel/fs/atapi_pio.c new file mode 100644 index 0000000..4f986d9 --- /dev/null +++ b/src/kernel/fs/atapi_pio.c @@ -0,0 +1,32 @@ +#include <stdint.h> +#include <kernel/fs/atapi_pio.h> +#include <kernel/system.h> +#include <kernel/paging/paging.h> + +void ATAPI_read(uint16_t nblocks, uint32_t lba) { + struct dapack *d = (struct dapack *) ATAPI_PIO_DAPACK; + d->size = 0x10; + d->null = 0x00; + d->blkcount = nblocks; + d->boffset = ATAPI_PIO_BUFFER; + d->bsegment = 0x0000; + d->start = lba; + d->upper_lba_bits = 0x00000000; + + regs16_t regs; + regs.ax = 0x4200; + regs.dx = ATAPI_PIO_DRIVE; + regs.ds = 0; + regs.si = ATAPI_PIO_DAPACK; + + paging_disable(); + int32(LBA_READ_INT, ®s); + paging_enable(); +} + +void ATAPI_granular_read(uint32_t nblocks, uint32_t lba, uint8_t *output) { + for (uint32_t i = 0; i < nblocks; i++) { + ATAPI_read(1, lba + i); + for (uint16_t j = 0; j < ATAPI_SECTOR_SIZE; j++) output[j + (2048 * i)] = ((uint8_t *) ATAPI_PIO_BUFFER)[j]; + } +}
\ No newline at end of file diff --git a/src/kernel/fs/atapi_pio.h b/src/kernel/fs/atapi_pio.h new file mode 100644 index 0000000..5e89e85 --- /dev/null +++ b/src/kernel/fs/atapi_pio.h @@ -0,0 +1,26 @@ +#ifndef MELVIX_ATAPI_PIO_H +#define MELVIX_ATAPI_PIO_H + +#include <stdint.h> + +#define ATAPI_PIO_DRIVE 0xE0 +#define LBA_READ_INT 0x13 +#define ATAPI_PIO_DAPACK 0x7E00 +#define ATAPI_PIO_BUFFER 0x8000 +#define ATAPI_SECTOR_SIZE 0x800 + +struct dapack { + uint8_t size; + uint8_t null; + uint16_t blkcount; + uint16_t boffset; + uint16_t bsegment; + uint32_t start; + uint32_t upper_lba_bits; +} __attribute__((packed)); + +void ATAPI_read(uint16_t nblocks, uint32_t lba); + +void ATAPI_granular_read(uint32_t nblocks, uint32_t lba, uint8_t *output); + +#endif diff --git a/src/kernel/fs/initrd.c b/src/kernel/fs/initrd.c deleted file mode 100644 index acaceb8..0000000 --- a/src/kernel/fs/initrd.c +++ /dev/null @@ -1,131 +0,0 @@ -#include <stdint.h> -#include <kernel/fs/initrd.h> -#include <kernel/fs/vfs.h> -#include <kernel/lib/lib.h> -#include <kernel/lib/alloc.h> -#include <kernel/io/io.h> -#include <kernel/graphics/vesa.h> - -initrd_header_t *initrd_header; -initrd_file_header_t *file_headers; -fs_node_t *initrd_root; -fs_node_t *initrd_dev; -fs_node_t *root_nodes; -int nroot_nodes; - -struct dirent dirent; - -static uint32_t initrd_read(fs_node_t *node, uint32_t offset, uint32_t size, uint8_t *buffer) { - initrd_file_header_t header = file_headers[node->inode]; - if (offset > header.length) - return 0; - if (offset + size > header.length) - size = header.length - offset; - memcpy(buffer, (uint8_t *) (header.offset + offset), size); - return size; -} - -static struct dirent *initrd_readdir(fs_node_t *node, uint32_t index) { - if (node == initrd_root && index == 0) { - strcpy(dirent.name, "dev"); - dirent.name[3] = 0; - dirent.ino = 0; - return &dirent; - } - - if (index - 1 >= (uint32_t) nroot_nodes) - return 0; - strcpy(dirent.name, root_nodes[index - 1].name); - dirent.name[strlen(root_nodes[index - 1].name)] = 0; - dirent.ino = root_nodes[index - 1].inode; - return &dirent; -} - -static fs_node_t *initrd_finddir(fs_node_t *node, char *name) { - if (node == initrd_root && - !strcmp(name, "dev")) - return initrd_dev; - - int i; - for (i = 0; i < nroot_nodes; i++) - if (!strcmp(name, root_nodes[i].name)) - return &root_nodes[i]; - return 0; -} - -fs_node_t *initialise_initrd(uint32_t location) { - initrd_header = (initrd_header_t *) location; - file_headers = (initrd_file_header_t *) (location + sizeof(initrd_header_t)); - - initrd_root = (fs_node_t *) kmalloc(sizeof(fs_node_t)); - strcpy(initrd_root->name, "initrd"); - initrd_root->mask = initrd_root->uid = initrd_root->gid = initrd_root->inode = initrd_root->length = 0; - initrd_root->flags = FS_DIRECTORY; - initrd_root->read = 0; - initrd_root->write = 0; - initrd_root->open = 0; - initrd_root->close = 0; - initrd_root->readdir = &initrd_readdir; - initrd_root->finddir = &initrd_finddir; - initrd_root->ptr = 0; - initrd_root->impl = 0; - - initrd_dev = (fs_node_t *) kmalloc(sizeof(fs_node_t)); - strcpy(initrd_dev->name, "dev"); - initrd_dev->mask = initrd_dev->uid = initrd_dev->gid = initrd_dev->inode = initrd_dev->length = 0; - initrd_dev->flags = FS_DIRECTORY; - initrd_dev->read = 0; - initrd_dev->write = 0; - initrd_dev->open = 0; - initrd_dev->close = 0; - initrd_dev->readdir = &initrd_readdir; - initrd_dev->finddir = &initrd_finddir; - initrd_dev->ptr = 0; - initrd_dev->impl = 0; - - root_nodes = (fs_node_t *) kmalloc(sizeof(fs_node_t) * initrd_header->nfiles); - nroot_nodes = initrd_header->nfiles; - - for (uint32_t i = 0; i < initrd_header->nfiles; i++) { - file_headers[i].offset += location; - - strcpy(root_nodes[i].name, (const char *) &file_headers[i].name); - root_nodes[i].mask = root_nodes[i].uid = root_nodes[i].gid = 0; - root_nodes[i].length = file_headers[i].length; - root_nodes[i].inode = i; - root_nodes[i].flags = FS_FILE; - root_nodes[i].read = &initrd_read; - root_nodes[i].write = 0; - root_nodes[i].readdir = 0; - root_nodes[i].finddir = 0; - root_nodes[i].open = 0; - root_nodes[i].close = 0; - root_nodes[i].impl = 0; - } - return initrd_root; -} - -void initrd_test() { - int i = 0; - struct dirent *node = 0; - vesa_draw_string("\n"); - while ((node = readdir_fs(fs_root, i)) != 0) { - vesa_draw_string("Found file: "); - vesa_draw_string(node->name); - vesa_draw_string("\n"); - fs_node_t *fsnode = finddir_fs(fs_root, node->name); - - if ((fsnode->flags & 0x7) == FS_DIRECTORY) - vesa_draw_string("\t (directory)\n"); - else { - vesa_draw_string("\t contents: \""); - uint8_t buf[fsnode->length]; - uint32_t sz = read_fs(fsnode, 0, fsnode->length, buf); - for (uint32_t j = 0; j < sz; j++) - vesa_draw_char(buf[j]); - - vesa_draw_string("\"\n"); - } - i++; - } -}
\ No newline at end of file diff --git a/src/kernel/fs/initrd.h b/src/kernel/fs/initrd.h deleted file mode 100644 index bb5c376..0000000 --- a/src/kernel/fs/initrd.h +++ /dev/null @@ -1,22 +0,0 @@ -#ifndef MELVIX_INITRD_H -#define MELVIX_INITRD_H - -#include <stdint.h> -#include <kernel/fs/vfs.h> - -typedef struct { - uint32_t nfiles; -} initrd_header_t; - -typedef struct { - uint8_t magic; - int8_t name[64]; - uint32_t offset; - uint32_t length; -} initrd_file_header_t; - -fs_node_t *initialise_initrd(uint32_t location); - -void initrd_test(); - -#endif diff --git a/src/kernel/fs/install.c b/src/kernel/fs/install.c new file mode 100644 index 0000000..5a2cc61 --- /dev/null +++ b/src/kernel/fs/install.c @@ -0,0 +1,61 @@ +#include <kernel/graphics/vesa.h> +#include <kernel/fs/ata_pio.h> +#include <kernel/fs/marfs/marfs.h> +#include <kernel/lib/alloc.h> +#include <kernel/fs/iso9660/iso9660.h> +#include "atapi_pio.h" + +void install_melvix() { + info("You're booting from a CD, Melvix will only run after an install"); + asm volatile ("cli"); + struct ATA_INTERFACE *primary_master = new_ATA(1, 0x1F0); + if (marfs_init(primary_master) != 0) { + panic("No HDD found!"); + } + + struct marfs_SUPERBLOCK *currentSB = marfs_read_superblock(); + if (currentSB->signature == 0x1083B99F34B59645) { // WEEEOOOWEEEOOO + panic("Melvix seems to be already installed!"); + } + kfree(currentSB); + + info("Installing...\n"); + + // Copy MBR + info("Copying MBR... "); + char *stage1_p[] = {"BOOT", "HDD1.BIN"}; + struct ISO9660_entity *stage1_e = ISO9660_get(stage1_p, 2); + if (!stage1_e) + panic("Couldn't find the first HDD bootloader!"); + uint8_t *stage1 = ISO9660_read(stage1_e); + kfree(stage1_e); + marfs_write_mbr(stage1); + + // Format disk + info("Formatting disk..."); + marfs_format(); + + // Copy second stage + info("Copying second stage..."); + char *stage2_p[] = {"BOOT", "HDD2.BIN"}; + struct ISO9660_entity *stage2_e = ISO9660_get(stage2_p, 2); + if (!stage2_e) + panic("Couldn't find the second HDD bootloader!"); + uint8_t *stage2 = ISO9660_read(stage2_e); + marfs_new_file(stage2_e->length, stage2, 0, 0, 0); + kfree(stage2_e); + + // Copy the kernel + info("Copying the kernel... "); + char *kernel_p[] = {"BOOT", "KERNEL.BIN"}; + struct ISO9660_entity *kernel_e = ISO9660_get(kernel_p, 2); + if (!kernel_e) + panic("WTH Kernel not found!?"); + uint8_t *kernel = kmalloc(kernel_e->length + 2048); + ATAPI_granular_read(1 + (kernel_e->length / 2048), kernel_e->LBA, kernel); + marfs_new_file(kernel_e->length, kernel, 0, 0, 0); + kfree(kernel); + kfree(kernel_e); + + info("Installation successful!"); +}
\ No newline at end of file diff --git a/src/kernel/fs/install.h b/src/kernel/fs/install.h new file mode 100644 index 0000000..8475297 --- /dev/null +++ b/src/kernel/fs/install.h @@ -0,0 +1,6 @@ +#ifndef MELVIX_INSTALL_H +#define MELVIX_INSTALL_H + +void install_melvix(); + +#endif diff --git a/src/kernel/fs/iso9660/iso9660.c b/src/kernel/fs/iso9660/iso9660.c new file mode 100644 index 0000000..728d3cb --- /dev/null +++ b/src/kernel/fs/iso9660/iso9660.c @@ -0,0 +1,60 @@ +#include <stdint.h> +#include <kernel/lib/lib.h> +#include <kernel/fs/atapi_pio.h> +#include <kernel/fs/iso9660/iso9660.h> +#include <kernel/lib/alloc.h> + +struct ISO9660_entity *ISO9660_get(char **dirs, uint8_t dirs_sz) { + ATAPI_read(1, 0x10); + uint32_t last_len = *(uint32_t *) ( + ATAPI_PIO_BUFFER + + ISO9660_ROOT_RECORD_OFFSET + + ISO9660_DIR_EAR_LENGTH + ); + uint32_t last_LBA = *(uint32_t *) ( + ATAPI_PIO_BUFFER + + ISO9660_ROOT_RECORD_OFFSET + + ISO9660_DIR_EAR_LBA + ); + + for (uint8_t dirs_i = 0; dirs_i < dirs_sz; dirs_i++) { + ATAPI_read((last_len % 2048 != 0) + (last_len / 2048), last_LBA); + + uint8_t found = 0; + for (uint32_t i = 0; i < last_len && !found;) { + if (!*(uint8_t *) (ATAPI_PIO_BUFFER + i + ISO9660_DIR_RECORD_LENGTH)) + break; + + char *filename = (char *) (ATAPI_PIO_BUFFER + i + ISO9660_DIR_FILENAME); + + for (uint32_t j = 0; j < ISO9660_DIR_FILENAME_LENGTH; j++) { + if (filename[j] == ';') { + filename[j] = 0; + break; + } + } + + if (strcmp(dirs[dirs_i], filename) == 0) { + found = 1; + last_LBA = *(uint32_t *) (ATAPI_PIO_BUFFER + i + ISO9660_DIR_EAR_LBA); + last_len = *(uint32_t *) (ATAPI_PIO_BUFFER + i + ISO9660_DIR_EAR_LENGTH); + } else { + i += *(uint8_t *) (ATAPI_PIO_BUFFER + i + ISO9660_DIR_RECORD_LENGTH); + } + } + + if (!found) { + return (struct ISO9660_entity *) 0; + } + } + + struct ISO9660_entity *ret = (struct ISO9660_entity *) kmalloc(sizeof(struct ISO9660_entity)); + ret->LBA = last_LBA; + ret->length = last_len; + return ret; +} + +uint8_t *ISO9660_read(struct ISO9660_entity *entity) { + ATAPI_read((entity->length % 2048 != 0) + (entity->length / 2048), entity->LBA); + return (uint8_t *) ATAPI_PIO_BUFFER; +}
\ No newline at end of file diff --git a/src/kernel/fs/iso9660/iso9660.h b/src/kernel/fs/iso9660/iso9660.h new file mode 100644 index 0000000..3de5d1a --- /dev/null +++ b/src/kernel/fs/iso9660/iso9660.h @@ -0,0 +1,22 @@ +#ifndef MELVIX_ISO9660_H +#define MELVIX_ISO9660_H + +#define ISO9660_ROOT_RECORD_OFFSET 156 +#define ISO9660_DIR_RECORD_LENGTH 0 +#define ISO9660_DIR_EAR_LBA 2 +#define ISO9660_DIR_EAR_LENGTH 10 +#define ISO9660_DIR_FILENAME_LENGTH 32 +#define ISO9660_DIR_FILENAME 33 + +#include <stdint.h> + +struct ISO9660_entity { + uint32_t LBA; + uint32_t length; +}; + +struct ISO9660_entity *ISO9660_get(char **dirs, uint8_t dirs_sz); + +uint8_t *ISO9660_read(struct ISO9660_entity *entity); + +#endif diff --git a/src/kernel/fs/marfs/directory.c b/src/kernel/fs/marfs/directory.c new file mode 100644 index 0000000..f7783bb --- /dev/null +++ b/src/kernel/fs/marfs/directory.c @@ -0,0 +1,55 @@ +#include <stdint.h> +#include <kernel/fs/ata_pio.h> +#include <kernel/lib/alloc.h> +#include <kernel/lib/lib.h> +#include "marfs.h" + +uint32_t marfs_new_dir(uint32_t uid) { return marfs_new_file(0, 0, uid, 0, 1); } + + +void marfs_add_to_dir(uint32_t LBAinode, char *filename, uint32_t lba) { + struct marfs_INODE *inode = (struct marfs_INODE *) ATA_read28(iface, LBAinode); + + // Read the content + uint8_t *old = marfs_allocate_and_read_whole_file(LBAinode); + + // Allocate memory + uint8_t *contents = kmalloc(inode->size + strlen(filename) + 1 + 4); + + // Copy the content + uint8_t lastWasNull = 0; + uint64_t newsize = 0; + for (uint64_t i = 0; i < inode->size; i++) { + if (old[i] == 0 && lastWasNull) continue; + + contents[newsize++] = old[i]; + lastWasNull = (old[i] == 0); + } + kfree(old); + + // Append new file + for (uint16_t i = 0; i <= strlen(filename); i++) contents[newsize++] = filename[i]; + for (signed char j = 24; j > 0; j -= 8) contents[newsize++] = (lba >> j) & 0xFF; + + // Free the blocks + uint32_t newsize_in_blocks = newsize / 512; + if (newsize % 512) newsize_in_blocks++; + for (uint32_t i = 0; i < newsize_in_blocks; i++) + marfs_mark_block_as_free(marfs_get_block(inode, i)); + + // Overwrite + uint32_t aux_inode = marfs_new_file(newsize, contents, 0xDEADBEEF, 0, 0); + struct marfs_INODE *real_aux_inode = (struct marfs_INODE *) ATA_read28(iface, aux_inode); + for (uint8_t i = 0; i < 10; i++) inode->DBPs[i] = real_aux_inode->DBPs[i]; + inode->ext_1 = real_aux_inode->ext_1; + inode->ext_2 = real_aux_inode->ext_2; + inode->ext_3 = real_aux_inode->ext_3; + inode->ext_4 = real_aux_inode->ext_4; + real_aux_inode->isUsed = 0; + ATA_write28(iface, aux_inode, (uint8_t *) real_aux_inode); + kfree(real_aux_inode); + + inode->size = newsize; + ATA_write28(iface, LBAinode, (uint8_t *) inode); + kfree(inode); +} diff --git a/src/kernel/fs/marfs/disklevel.c b/src/kernel/fs/marfs/disklevel.c new file mode 100644 index 0000000..b6fc8c2 --- /dev/null +++ b/src/kernel/fs/marfs/disklevel.c @@ -0,0 +1,23 @@ +#include <stdint.h> +#include <kernel/fs/ata_pio.h> +#include "marfs.h" + +void marfs_format(void) { + // Create superblock + struct marfs_SUPERBLOCK sb; + sb.signature = 0x1083B99F34B59645; // Huh, magic?! + sb.n_inodes = (marfs_get_max_lba() - 2) >> 5; + sb.n_chunks = (marfs_get_max_lba() - (2 + sb.n_inodes)) >> 9; + sb.n_first_unallocated_inode = 0; + sb.s_first_inode = 2; + sb.s_first_chunk = 2 + sb.n_inodes; + + // Write to disk + marfs_writeSB(&sb); + + // Initialize the inodes + for (uint32_t i = 0; i < sb.n_inodes; i++) ATA_clear28(iface, 2 + i); + + // Initialize the chunks + for (uint32_t i = 0; i < sb.n_chunks; i++) ATA_clear28(iface, sb.s_first_chunk + i * 512); +} diff --git a/src/kernel/fs/marfs/marfs.h b/src/kernel/fs/marfs/marfs.h new file mode 100644 index 0000000..ba6f0b3 --- /dev/null +++ b/src/kernel/fs/marfs/marfs.h @@ -0,0 +1,81 @@ +#ifndef MELVIX_MARFS_H +#define MELVIX_MARFS_H + +#include <stdint.h> + +struct marfs_SUPERBLOCK { + uint64_t signature; + uint32_t n_inodes; + uint32_t n_chunks; + uint32_t n_first_unallocated_inode; + uint32_t s_first_inode; + uint32_t s_first_chunk; +} __attribute__((packed)); + +struct marfs_INODE { + uint64_t size; + uint32_t creation_time; + uint32_t last_mod_time; + uint32_t last_access_time; + uint32_t n_blocks; + uint32_t DBPs[10]; + uint32_t ext_1; + uint32_t ext_2; + uint32_t ext_3; + uint32_t ext_4; + uint32_t uid; + uint8_t isApp; + uint8_t isDir; + uint8_t isUsed; +} __attribute__((packed)); + +enum marfs_RESERVED_INODES { + marfs_INODE_JBOOT2, + marfs_INODE_KERNEL, + marfs_INODE_ROOT +}; + +struct ATA_INTERFACE *iface; +struct marfs_SUPERBLOCK sb_cache; +uint32_t maxLBA; + +// marfs_sectorlevel.c +uint8_t marfs_init(struct ATA_INTERFACE *iface); + +uint32_t marfs_get_max_lba(void); + +uint8_t marfs_write_mbr(uint8_t *mbr); + +struct marfs_SUPERBLOCK *marfs_read_superblock(); + +uint8_t marfs_writeSB(struct marfs_SUPERBLOCK *sb); + +uint32_t marfs_get_free_lba_block(void); + +uint8_t marfs_mark_block_as_used(uint32_t LBAsector); + +uint8_t marfs_mark_block_as_free(uint32_t LBAsector); + +uint32_t marfs_get_free_lba_inode(void); + +void marfs_mark_inode_as_free(uint32_t LBAsector); + +// marfs_disklevel.c +void marfs_format(void); + +// marfs_new_file.c +uint32_t marfs_new_file(uint64_t size, uint8_t *data, uint32_t uid, uint8_t exec, uint8_t dir); + +// marfs_dir.c +uint32_t marfs_new_dir(uint32_t uid); + +void marfs_add_to_dir(uint32_t LBAinode, char *filename, uint32_t lba); + +// marfs_read_whole_file.c +uint32_t marfs_get_block(struct marfs_INODE *inode, uint32_t i); + +void marfs_read_whole_file(uint32_t LBAinode, uint8_t *buffer); + +uint8_t *marfs_allocate_and_read_whole_file(uint32_t LBAinode); + +#endif diff --git a/src/kernel/fs/marfs/new_file.c b/src/kernel/fs/marfs/new_file.c new file mode 100644 index 0000000..7b06621 --- /dev/null +++ b/src/kernel/fs/marfs/new_file.c @@ -0,0 +1,102 @@ +#include <stdint.h> +#include <kernel/fs/ata_pio.h> +#include <kernel/lib/alloc.h> +#include "marfs.h" + +static uint8_t last_maxlevel = 0; + +void marfs_update_recursive(uint8_t level, uint32_t i, uint32_t recLBA, uint32_t realLBA) { + if (level > last_maxlevel) last_maxlevel = level; + uint32_t *contents = (uint32_t *) ATA_read28(iface, recLBA); + + uint32_t idx = i - 10; + if (last_maxlevel > 1) idx -= 1 << 7; + if (last_maxlevel > 2) idx -= 1 << (7 * 2); + if (last_maxlevel > 3) idx -= 1 << (7 * 3); + idx >>= 7 * (level - 1); + + if (level > 1) { + if (!contents[idx]) { + contents[idx] = marfs_get_free_lba_block(); + marfs_mark_block_as_used(contents[idx]); + } + } else { + contents[idx] = realLBA; + } + + ATA_write28(iface, recLBA, (uint8_t *) contents); + + uint32_t contents_idx = contents[idx]; + kfree(contents); + if (level != 1) { + marfs_update_recursive(level - 1, i, contents_idx, realLBA); + } + last_maxlevel = 0; +} + +uint32_t marfs_new_file(uint64_t size, uint8_t *data, uint32_t uid, uint8_t exec, uint8_t dir) { + struct marfs_INODE *inode = (struct marfs_INODE *) kcalloc(1, 512); + inode->size = size; + inode->creation_time = inode->last_mod_time = inode->last_access_time = 0; // TODO: POSIX time + inode->n_blocks = size / 512; + if (size % 512) inode->n_blocks++; + inode->uid = uid; + inode->isApp = exec; + inode->isDir = dir; + inode->isUsed = 1; + + uint32_t size_in_blocks = inode->n_blocks; + + uint32_t LBA_singly, LBA_doubly, LBA_triply, LBA_quadruply; + LBA_singly = LBA_doubly = LBA_triply = LBA_quadruply = 0; + for (uint32_t i = 0; i < size_in_blocks; i++) { + uint32_t thisblock = marfs_get_free_lba_block(); + if (i != size_in_blocks - 1) { + ATA_write28(iface, thisblock, data); + } else if (size % 512) { + uint8_t contents[512] = {0}; + for (uint16_t i = 0; i < size % 512; i++) contents[i] = data[i]; + ATA_write28(iface, thisblock, contents); + } + data += 512; + marfs_mark_block_as_used(thisblock); + + if (i > 9 + (128 * 128 * 128)) { + if (!LBA_quadruply) { + LBA_quadruply = marfs_get_free_lba_block(); + marfs_mark_block_as_used(LBA_quadruply); + inode->ext_4 = LBA_quadruply; + } + marfs_update_recursive(4, i, LBA_quadruply, thisblock); + } else if (i > 9 + (128 * 128)) { + if (!LBA_triply) { + LBA_triply = marfs_get_free_lba_block(); + marfs_mark_block_as_used(LBA_triply); + inode->ext_3 = LBA_triply; + } + marfs_update_recursive(3, i, LBA_triply, thisblock); + } else if (i > 9 + 128) { + if (!LBA_doubly) { + LBA_doubly = marfs_get_free_lba_block(); + marfs_mark_block_as_used(LBA_doubly); + inode->ext_2 = LBA_doubly; + } + marfs_update_recursive(2, i, LBA_doubly, thisblock); + } else if (i > 9) { + if (!LBA_singly) { + LBA_singly = marfs_get_free_lba_block(); + marfs_mark_block_as_used(LBA_singly); + inode->ext_1 = LBA_singly; + } + marfs_update_recursive(1, i, LBA_singly, thisblock); + } else { + inode->DBPs[i] = thisblock; + } + } + + // Write the inode + uint32_t inode_LBA = marfs_get_free_lba_inode(); + ATA_write28(iface, inode_LBA, (uint8_t *) inode); + + return inode_LBA; +}
\ No newline at end of file diff --git a/src/kernel/fs/marfs/read_whole_file.c b/src/kernel/fs/marfs/read_whole_file.c new file mode 100644 index 0000000..86aae5f --- /dev/null +++ b/src/kernel/fs/marfs/read_whole_file.c @@ -0,0 +1,65 @@ +#include <stdint.h> +#include <kernel/fs/ata_pio.h> +#include <kernel/lib/alloc.h> +#include "marfs.h" + +static uint8_t last_maxlevel = 0; + +uint32_t marfs_get_recursive(uint8_t level, uint32_t i, uint32_t recLBA) { + if (level > last_maxlevel) last_maxlevel = level; + uint32_t *contents = (uint32_t *) ATA_read28(iface, recLBA); + uint32_t idx = i - 10; + if (last_maxlevel > 1) idx -= 1 << 7; + if (last_maxlevel > 2) idx -= 1 << (7 * 2); + if (last_maxlevel > 3) idx -= 1 << (7 * 3); + idx >>= 7 * (level - 1); + + uint32_t next_recLBA = contents[idx]; + kfree(contents); + + uint32_t toRet; + if (level > 1) toRet = marfs_get_recursive(level - 1, i, next_recLBA); + else toRet = next_recLBA; + last_maxlevel = 0; + return toRet; +} + +uint32_t marfs_get_block(struct marfs_INODE *inode, uint32_t i) { + if (i > 9 + (128 * 128 * 128)) { + return marfs_get_recursive(4, i, inode->ext_4); + } else if (i > 9 + (128 * 128)) { + return marfs_get_recursive(3, i, inode->ext_3); + } else if (i > 9 + 128) { + return marfs_get_recursive(2, i, inode->ext_2); + } else if (i > 9) { + return marfs_get_recursive(1, i, inode->ext_1); + } else { + return inode->DBPs[i]; + } +} + +void marfs_read_whole_file(uint32_t LBAinode, uint8_t *buffer) { + struct marfs_INODE *inode = (struct marfs_INODE *) ATA_read28(iface, LBAinode); + + uint32_t size_in_blocks = inode->n_blocks; + for (uint32_t i = 0; i < size_in_blocks; i++) { + uint32_t this_block = marfs_get_block(inode, i); + uint8_t *this_block_contents = ATA_read28(iface, this_block); + uint16_t upper_bound = (i != size_in_blocks - 1) ? 512 : (inode->size % 512); + for (uint16_t j = 0; j < upper_bound; j++) buffer[(i * 512) + j] = this_block_contents[j]; + kfree(this_block_contents); + } + + kfree(inode); +} + +// TODO: Beautify +uint8_t *marfs_allocate_and_read_whole_file(uint32_t LBAinode) { + struct marfs_INODE *inode = (struct marfs_INODE *) ATA_read28(iface, LBAinode); + uint64_t size = inode->size; + kfree(inode); + + uint8_t *buffer = kmalloc(size); + marfs_read_whole_file(LBAinode, buffer); + return buffer; +} diff --git a/src/kernel/fs/marfs/sectorlevel.c b/src/kernel/fs/marfs/sectorlevel.c new file mode 100644 index 0000000..7575f8c --- /dev/null +++ b/src/kernel/fs/marfs/sectorlevel.c @@ -0,0 +1,101 @@ +#include <stdint.h> +#include <kernel/lib/alloc.h> +#include <kernel/fs/ata_pio.h> +#include "marfs.h" + +uint8_t marfs_init(struct ATA_INTERFACE *_iface) { + iface = _iface; + uint16_t identifydata[256 * 2]; + uint8_t ret = ATA_identify(iface, identifydata); + maxLBA = (identifydata[61] << 16) + identifydata[60]; + return ret; +} + +uint32_t marfs_get_max_lba(void) { return maxLBA; } + +uint8_t marfs_write_mbr(uint8_t *mbr) { + return ATA_write28(iface, 0, mbr); +} + +struct marfs_SUPERBLOCK *marfs_read_superblock() { + struct marfs_SUPERBLOCK *p = (struct marfs_SUPERBLOCK *) ATA_read28(iface, 1); + sb_cache = *p; + return p; +} + +uint8_t marfs_writeSB(struct marfs_SUPERBLOCK *sb) { + sb_cache = *sb; + return ATA_write28(iface, 1, (uint8_t *) sb); +} + +uint32_t marfs_get_free_lba_block(void) { + uint32_t offset = 2 + sb_cache.s_first_chunk; + uint8_t *p = 0; + for (uint32_t i = 0; i < sb_cache.n_chunks; i++) { + p = ATA_read28(iface, offset); + if (!(*p & 0x80)) break; + kfree(p); + offset += 512; + } + + offset++; + for (uint16_t i = 1; i < 512; i++) { + if (!p[i]) break; + offset++; + } + kfree(p); + + ATA_clear28(iface, offset); + + return offset; +} + +static uint8_t marfs_mark_block(uint32_t lba_sector, uint8_t mode) { + lba_sector -= 2; + lba_sector -= sb_cache.s_first_chunk; + uint16_t block_in_chunk = lba_sector % 512; + lba_sector /= 512; + lba_sector = 2 + sb_cache.s_first_chunk + (512 * lba_sector); + + uint8_t *p = ATA_read28(iface, lba_sector); + p[block_in_chunk] = mode; + + if (mode == 0) { + p[0] = 0; + } else { + uint8_t full_chunk = 1; + for (uint16_t i = 1; i < 512; i++) { + if (!p[i]) { + full_chunk = 0; + break; + } + } + p[0] = full_chunk; + } + + uint8_t ret = ATA_write28(iface, lba_sector, p); + kfree(p); + return ret; +} + +uint8_t marfs_mark_block_as_free(uint32_t lba_sector) { return marfs_mark_block(lba_sector, 0); } + +uint8_t marfs_mark_block_as_used(uint32_t lba_sector) { return marfs_mark_block(lba_sector, 1); } + +uint32_t marfs_get_free_lba_inode(void) { + uint32_t offset; + for (offset = 2; offset < 2 + sb_cache.n_inodes; offset++) { + struct marfs_INODE *inode = (struct marfs_INODE *) ATA_read28(iface, offset); + uint8_t used = inode->isUsed; + kfree(inode); + if (!used) break; + } + return offset; +} + +void marfs_mark_inode_as_free(uint32_t lba_sector) { + struct marfs_INODE *inode = (struct marfs_INODE *) ATA_read28(iface, lba_sector); + inode->isUsed = 0; + ATA_write28(iface, lba_sector, (uint8_t *) inode); + kfree(inode); +}
\ No newline at end of file |