aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rwxr-xr-xrun26
-rw-r--r--src/kernel/fs/ata.c290
-rw-r--r--src/kernel/fs/ata.h119
-rw-r--r--src/kernel/fs/ata_pio.c142
-rw-r--r--src/kernel/fs/ata_pio.h31
-rw-r--r--src/kernel/fs/atapi_pio.c32
-rw-r--r--src/kernel/fs/atapi_pio.h26
-rw-r--r--src/kernel/fs/ext2/ext2.c797
-rw-r--r--src/kernel/fs/ext2/ext2.h211
-rw-r--r--src/kernel/fs/iso9660/iso9660.c59
-rw-r--r--src/kernel/fs/iso9660/iso9660.h22
-rw-r--r--src/kernel/fs/load.c7
-rw-r--r--src/kernel/fs/vfs/vfs.c371
-rw-r--r--src/kernel/fs/vfs/vfs.h149
-rw-r--r--src/kernel/io/io.c2
-rw-r--r--src/kernel/kernel.c8
-rw-r--r--src/kernel/lib/data/generic_tree.c102
-rw-r--r--src/kernel/lib/data/generic_tree.h36
-rw-r--r--src/kernel/lib/data/list.c220
-rw-r--r--src/kernel/lib/data/list.h60
-rw-r--r--src/kernel/lib/string.h6
-rw-r--r--src/kernel/lib/string/strncmp.c16
-rw-r--r--src/kernel/lib/string/strsep.c25
-rw-r--r--src/kernel/lib/string/strstr.c25
-rw-r--r--src/kernel/net/rtl8139.c4
-rw-r--r--src/kernel/pci/pci.c12
-rw-r--r--src/kernel/pci/pci.h4
-rw-r--r--src/kernel/system.c8
-rw-r--r--src/kernel/system.h6
29 files changed, 2486 insertions, 330 deletions
diff --git a/run b/run
index 91f1f73..4a5e4b7 100755
--- a/run
+++ b/run
@@ -120,13 +120,35 @@ make_build() {
cp ./build/user.bin ./iso/user.bin
cp ./build/font.bin ./iso/font.bin
grub-mkrescue -o ./build/melvix.iso ./iso/
- head -c 10485760 /dev/zero >./build/hdd10M.img
+ dd if=/dev/zero of=./build/ext2_hda.img bs=1k count=100000 > /dev/zero
+ mkfs -t ext2 -i 1024 -b 1024 -F ./build/ext2_hda.img > /dev/zero
+ fdisk ./build/ext2_hda.img <<EOF
+x
+c
+10
+h
+16
+s
+63
+r
+n
+p
+1
+2048
+199999
+a
+w
+EOF
+
+ cp ./build/ext2_hda.img ./build/ext2_hdb.img
+ cp ./build/ext2_hda.img ./build/ext2_hdc.img
+ cp ./build/ext2_hda.img ./build/ext2_hdd.img
printf "Build finshed successfully!\n\n"
}
make_test() {
- qemu_with_flags -cdrom ./build/melvix.iso #-drive file=./build/hdd10M.img,format=raw
+ qemu_with_flags -cdrom ./build/melvix.iso -hda ./build/ext2_hda.img -boot d
}
make_debug() {
diff --git a/src/kernel/fs/ata.c b/src/kernel/fs/ata.c
new file mode 100644
index 0000000..52d1040
--- /dev/null
+++ b/src/kernel/fs/ata.c
@@ -0,0 +1,290 @@
+#include <kernel/system.h>
+#include <kernel/io/io.h>
+#include <kernel/fs/ata.h>
+#include <kernel/lib/lib.h>
+#include <kernel/lib/stdlib.h>
+#include <kernel/memory/alloc.h>
+#include <kernel/pci/pci.h>
+#include <kernel/interrupts/interrupts.h>
+
+uint32_t ata_device;
+
+ata_dev_t primary_master = { .slave = 0 };
+ata_dev_t primary_slave = { .slave = 1 };
+ata_dev_t secondary_master = { .slave = 0 };
+ata_dev_t secondary_slave = { .slave = 1 };
+
+void io_wait(ata_dev_t *dev)
+{
+ inb(dev->alt_status);
+ inb(dev->alt_status);
+ inb(dev->alt_status);
+ inb(dev->alt_status);
+}
+
+void software_reset(ata_dev_t *dev)
+{
+ outb(dev->control, CONTROL_SOFTWARE_RESET);
+ io_wait(dev);
+ outb(dev->control, CONTROL_ZERO);
+}
+
+void ata_handler(struct regs *reg)
+{
+ inb(primary_master.status);
+ inb(primary_master.BMR_STATUS);
+ outb(primary_master.BMR_COMMAND, BMR_COMMAND_DMA_STOP);
+ //irq_ack(14);
+}
+
+void ata_open(vfs_node_t *node, uint32_t flags)
+{
+ return;
+}
+
+void ata_close(vfs_node_t *node)
+{
+ return;
+}
+
+uint32_t ata_read(vfs_node_t *node, uint32_t offset, uint32_t size, char *buf)
+{
+ uint32_t start = offset / SECTOR_SIZE;
+ uint32_t start_offset = offset % SECTOR_SIZE;
+
+ uint32_t end = (offset + size - 1) / SECTOR_SIZE;
+ uint32_t end_offset = (offset + size - 1) % SECTOR_SIZE;
+
+ char *buf_curr = buf;
+ uint32_t counter = start;
+ uint32_t read_size;
+ uint32_t off, total = 0;
+
+ while (counter <= end) {
+ off = 0;
+ read_size = SECTOR_SIZE;
+
+ char *ret = ata_read_sector((ata_dev_t *)node->device, counter);
+
+ if (counter == start) {
+ off = start_offset;
+ read_size = SECTOR_SIZE - off;
+ }
+ if (counter == end)
+ read_size = end_offset - off + 1;
+
+ memcpy(buf_curr, ret + off, read_size);
+ buf_curr = buf_curr + read_size;
+ total = total + read_size;
+ counter++;
+ }
+ return total;
+}
+
+uint32_t ata_write(vfs_node_t *node, uint32_t offset, uint32_t size, char *buf)
+{
+ uint32_t start = offset / SECTOR_SIZE;
+ uint32_t start_offset = offset % SECTOR_SIZE;
+
+ uint32_t end = (offset + size - 1) / SECTOR_SIZE;
+ uint32_t end_offset = (offset + size - 1) % SECTOR_SIZE;
+
+ char *buf_curr = buf;
+ uint32_t counter = start;
+ uint32_t write_size;
+ uint32_t off, total = 0;
+
+ while (counter <= end) {
+ off = 0;
+ write_size = SECTOR_SIZE;
+ char *ret = ata_read_sector((ata_dev_t *)node->device, counter);
+ if (counter == start) {
+ off = start_offset;
+ write_size = SECTOR_SIZE - off;
+ }
+ if (counter == end) {
+ write_size = end_offset - off + 1;
+ }
+ memcpy(ret + off, buf_curr, write_size);
+ ata_write_sector((ata_dev_t *)node->device, counter, ret);
+ buf_curr = buf_curr + write_size;
+ total = total + write_size;
+ counter++;
+ }
+ return total;
+}
+
+void ata_write_sector(ata_dev_t *dev, uint32_t lba, char *buf)
+{
+ memcpy(dev->mem_buffer, buf, SECTOR_SIZE);
+
+ outb(dev->BMR_COMMAND, 0);
+ outl(dev->BMR_prdt, (uint32_t)dev->prdt_phys);
+ outb(dev->drive, 0xe0 | dev->slave << 4 | (lba & 0x0f000000) >> 24);
+ outb(dev->sector_count, 1);
+ outb(dev->lba_lo, lba & 0x000000ff);
+ outb(dev->lba_mid, (lba & 0x0000ff00) >> 8);
+ outb(dev->lba_high, (lba & 0x00ff0000) >> 16);
+
+ outb(dev->command, 0xCA);
+
+ outb(dev->BMR_COMMAND, 0x1);
+
+ while (1) {
+ int status = inb(dev->BMR_STATUS);
+ int dstatus = inb(dev->status);
+ if (!(status & 0x04)) {
+ continue;
+ }
+ if (!(dstatus & 0x80)) {
+ break;
+ }
+ }
+}
+
+char *ata_read_sector(ata_dev_t *dev, uint32_t lba)
+{
+ char *buf = kmalloc(SECTOR_SIZE);
+
+ outb(dev->BMR_COMMAND, 0);
+ outl(dev->BMR_prdt, (uint32_t)dev->prdt_phys);
+ outb(dev->drive, 0xe0 | dev->slave << 4 | (lba & 0x0f000000) >> 24);
+ outb(dev->sector_count, 1);
+ outb(dev->lba_lo, lba & 0x000000ff);
+ outb(dev->lba_mid, (lba & 0x0000ff00) >> 8);
+ outb(dev->lba_high, (lba & 0x00ff0000) >> 16);
+
+ outb(dev->command, 0xC8);
+
+ outb(dev->BMR_COMMAND, 0x8 | 0x1);
+
+ while (1) {
+ int status = inb(dev->BMR_STATUS);
+ int dstatus = inb(dev->status);
+ if (!(status & 0x04)) {
+ continue;
+ }
+ if (!(dstatus & 0x80)) {
+ break;
+ }
+ }
+
+ memcpy(buf, dev->mem_buffer, SECTOR_SIZE);
+ return buf;
+}
+
+vfs_node_t *create_ata_device(ata_dev_t *dev)
+{
+ vfs_node_t *t = kcalloc(sizeof(vfs_node_t), 1);
+ strcpy(t->name, "ata device ");
+ t->name[strlen(t->name)] = dev->mountpoint[strlen(dev->mountpoint) - 1];
+ t->device = dev;
+ t->flags = FS_BLOCKDEVICE;
+ t->read = ata_read;
+ t->write = ata_write;
+ t->open = ata_open;
+ t->close = ata_close;
+ return t;
+}
+
+void ata_device_init(ata_dev_t *dev, int primary)
+{
+ dev->prdt = (void *)kmalloc(sizeof(prdt_t));
+ memset(dev->prdt, 0, sizeof(prdt_t));
+ dev->prdt_phys = (uint8_t *)paging_get_phys((uint32_t)dev->prdt);
+ dev->mem_buffer = (void *)kmalloc(4096);
+ memset(dev->mem_buffer, 0, 4096);
+
+ dev->prdt[0].buffer_phys = (uint32_t)paging_get_phys((uint32_t)dev->mem_buffer);
+ dev->prdt[0].transfer_size = SECTOR_SIZE;
+ dev->prdt[0].mark_end = MARK_END;
+
+ uint16_t base_addr = primary ? (0x1F0) : (0x170);
+ uint16_t alt_status = primary ? (0x3F6) : (0x376);
+
+ dev->data = base_addr;
+ dev->error = base_addr + 1;
+ dev->sector_count = base_addr + 2;
+ dev->lba_lo = base_addr + 3;
+ dev->lba_mid = base_addr + 4;
+ dev->lba_high = base_addr + 5;
+ dev->drive = base_addr + 6;
+ dev->command = base_addr + 7;
+ dev->alt_status = alt_status;
+
+ dev->bar4 = pci_read_field(ata_device, PCI_BAR4, 4);
+ if (dev->bar4 & 0x1) {
+ dev->bar4 = dev->bar4 & 0xfffffffc;
+ }
+ dev->BMR_COMMAND = dev->bar4;
+ dev->BMR_STATUS = dev->bar4 + 2;
+ dev->BMR_prdt = dev->bar4 + 4;
+
+ memset(dev->mountpoint, 0, 32);
+ strcpy(dev->mountpoint, "/dev/hd");
+ dev->mountpoint[strlen(dev->mountpoint)] = 'a' + (((!primary) << 1) | dev->slave);
+}
+
+void ata_device_detect(ata_dev_t *dev, int primary)
+{
+ ata_device_init(dev, primary);
+
+ software_reset(dev);
+ io_wait(dev);
+ outb(dev->drive, (0xA + dev->slave) << 4);
+ outb(dev->sector_count, 0);
+ outb(dev->lba_lo, 0);
+ outb(dev->lba_mid, 0);
+ outb(dev->lba_high, 0);
+
+ outb(dev->command, COMMAND_IDENTIFY);
+ if (!inb(dev->status)) {
+ log("ata_detect_device: device does not exist");
+ return;
+ }
+
+ uint8_t lba_lo = inb(dev->lba_lo);
+ uint8_t lba_hi = inb(dev->lba_high);
+ if (lba_lo != 0 || lba_hi != 0) {
+ log("ata_detect_device: not ata device");
+ return;
+ }
+ uint8_t drq = 0, err = 0;
+ while (!drq && !err) {
+ drq = inb(dev->status) & STATUS_DRQ;
+ err = inb(dev->status) & STATUS_ERR;
+ }
+ if (err) {
+ log("ata_detect_device: err when polling");
+ return;
+ }
+
+ for (int i = 0; i < 256; i++)
+ inw(dev->data);
+
+ uint32_t pci_command_reg = pci_read_field(ata_device, PCI_COMMAND, 2);
+ if (!(pci_command_reg & (1 << 2))) {
+ pci_command_reg |= (1 << 2);
+ pci_write_field(ata_device, PCI_COMMAND, pci_command_reg);
+ }
+
+ vfs_mount(dev->mountpoint, create_ata_device(dev));
+}
+
+void ata_find(uint32_t device, uint16_t vendor_id, uint16_t device_id, void *extra)
+{
+ if ((vendor_id == ATA_VENDOR_ID) && (device_id == ATA_DEVICE_ID))
+ *((uint32_t *)extra) = device;
+}
+
+void ata_init()
+{
+ pci_scan(&ata_find, -1, &ata_device);
+
+ irq_install_handler(32 + 14, ata_handler);
+
+ ata_device_detect(&primary_master, 1);
+ ata_device_detect(&primary_slave, 1);
+ ata_device_detect(&secondary_master, 0);
+ ata_device_detect(&secondary_slave, 0);
+}
diff --git a/src/kernel/fs/ata.h b/src/kernel/fs/ata.h
new file mode 100644
index 0000000..049f2bf
--- /dev/null
+++ b/src/kernel/fs/ata.h
@@ -0,0 +1,119 @@
+#ifndef ATA_DRIVER_H
+#define ATA_DRIVER_H
+
+#include <kernel/fs/vfs/vfs.h>
+#include <kernel/memory/paging.h>
+#include <kernel/interrupts/interrupts.h>
+
+typedef struct prdt {
+ uint32_t buffer_phys;
+ uint16_t transfer_size;
+ uint16_t mark_end;
+} __attribute__((packed)) prdt_t;
+
+typedef struct ata_dev {
+ uint16_t data;
+ uint16_t error;
+ uint16_t sector_count;
+
+ union {
+ uint16_t sector_num;
+ uint16_t lba_lo;
+ };
+ union {
+ uint16_t cylinder_low;
+ uint16_t lba_mid;
+ };
+ union {
+ uint16_t cylinder_high;
+ uint16_t lba_high;
+ };
+ union {
+ uint16_t drive;
+ uint16_t head;
+ };
+ union {
+ uint16_t command;
+ uint16_t status;
+ };
+ union {
+ uint16_t control;
+ uint16_t alt_status;
+ };
+
+ int slave;
+ uint32_t bar4;
+ uint32_t BMR_COMMAND;
+ uint32_t BMR_prdt;
+ uint32_t BMR_STATUS;
+
+ prdt_t *prdt;
+ uint8_t *prdt_phys;
+
+ uint8_t *mem_buffer;
+ uint8_t *mem_buffer_phys;
+
+ char mountpoint[32];
+} __attribute__((packed)) ata_dev_t;
+
+// ATA PCI info
+#define ATA_VENDOR_ID 0x8086
+#define ATA_DEVICE_ID 0x7010
+
+// Control reg
+#define CONTROL_STOP_INTERRUPT 0x2
+#define CONTROL_SOFTWARE_RESET 0x4
+#define CONTROL_HIGH_ORDER_BYTE 0x80
+#define CONTROL_ZERO 0x00
+
+// Command reg
+#define COMMAND_IDENTIFY 0xEC
+#define COMMAND_DMA_READ 0xC8
+#define ATA_CMD_READ_PIO 0x20
+
+// Status reg
+#define STATUS_ERR 0x0
+#define STATUS_DRQ 0x8
+#define STATUS_SRV 0x10
+#define STATUS_DF 0x20
+#define STATUS_RDY 0x40
+#define STATUS_BSY 0x80
+
+// Bus Master Reg Command
+#define BMR_COMMAND_DMA_START 0x1
+#define BMR_COMMAND_DMA_STOP 0x0
+#define BMR_COMMAND_READ 0x8
+#define BMR_STATUS_INT 0x4
+#define BMR_STATUS_ERR 0x2
+
+// Prdt
+#define SECTOR_SIZE 512
+#define MARK_END 0x8000
+
+void io_wait(ata_dev_t *dev);
+
+void software_reset(ata_dev_t *dev);
+
+void ata_handler(struct regs *reg);
+
+void ata_open(vfs_node_t *node, uint32_t flags);
+
+void ata_close(vfs_node_t *node);
+
+uint32_t ata_read(vfs_node_t *node, uint32_t offset, uint32_t size, char *buf);
+
+uint32_t ata_write(vfs_node_t *node, uint32_t offset, uint32_t size, char *buf);
+
+void ata_write_sector(ata_dev_t *dev, uint32_t lba, char *buf);
+
+char *ata_read_sector(ata_dev_t *dev, uint32_t lba);
+
+vfs_node_t *create_ata_device(ata_dev_t *dev);
+
+void ata_device_init(ata_dev_t *dev, int primary);
+
+void ata_device_detect(ata_dev_t *dev, int primary);
+
+void ata_init();
+
+#endif
diff --git a/src/kernel/fs/ata_pio.c b/src/kernel/fs/ata_pio.c
deleted file mode 100644
index 0bd64a5..0000000
--- a/src/kernel/fs/ata_pio.c
+++ /dev/null
@@ -1,142 +0,0 @@
-#include <kernel/io/io.h>
-#include <kernel/fs/ata_pio.h>
-#include <kernel/memory/alloc.h>
-
-struct ata_interface *new_ata(uint8_t master, uint16_t port_base)
-{
- struct ata_interface *ret = (struct ata_interface *)kmalloc(sizeof(struct ata_interface));
-
- ret->master = master;
- ret->data_port = port_base;
- ret->error_port = (uint16_t)(port_base + 0x1);
- ret->sector_count_port = (uint16_t)(port_base + 0x2);
- ret->lba_low_port = (uint16_t)(port_base + 0x3);
- ret->lba_mid_port = (uint16_t)(port_base + 0x4);
- ret->lba_high_port = (uint16_t)(port_base + 0x5);
- ret->device_port = (uint16_t)(port_base + 0x6);
- ret->command_port = (uint16_t)(port_base + 0x7);
- ret->control_port = (uint16_t)(port_base + 0x206);
-
- return ret;
-}
-
-uint8_t ata_identify(struct ata_interface *interface, uint16_t *ret_data)
-{
- outb(interface->device_port, (uint8_t)(interface->master ? 0xA0 : 0xB0));
- outb(interface->control_port, 0);
-
- outb(interface->device_port, 0xA0);
- uint8_t status = inb(interface->command_port);
- if (status == 0xFF)
- return 1;
-
- outb(interface->device_port, (uint8_t)(interface->master ? 0xA0 : 0xB0));
- outb(interface->sector_count_port, 0);
- outb(interface->lba_low_port, 0);
- outb(interface->lba_mid_port, 0);
- outb(interface->lba_high_port, 0);
- outb(interface->command_port, 0xEC); // Identify command
-
- status = inb(interface->command_port);
- if (!status)
- return 1;
-
- while (((status & 0x80) == 0x80) && ((status & 0x01) != 0x01)) {
- status = inb(interface->command_port);
- }
-
- if (status & 0x01)
- return 1;
-
- for (int i = 0; i < 256; i++)
- ret_data[i] = inw(interface->data_port);
- return 0;
-}
-
-uint8_t *ata_read28(struct ata_interface *interface, uint32_t sector)
-{
- if (sector > 0x0FFFFFFF)
- return 0;
-
- outb(interface->device_port,
- (uint8_t)((interface->master ? 0xE0 : 0xF0) | ((sector & 0x0F000000) >> 24)));
-
- uint8_t status = 0;
- for (int i = 0; i < 5; i++)
- status = inb(interface->command_port);
- if (status == 0xFF)
- return 0;
-
- outb(interface->error_port, 0);
- outb(interface->sector_count_port, 1);
- outb(interface->lba_low_port, (uint8_t)(sector & 0x000000FF));
- outb(interface->lba_mid_port, (uint8_t)((sector & 0x0000FF00) >> 8));
- outb(interface->lba_high_port, (uint8_t)((sector & 0x00FF0000) >> 16));
- outb(interface->command_port, 0x20); // Read command
-
- status = inb(interface->command_port);
- while ((status & 0x80) && !(status & 0x01))
- status = inb(interface->command_port);
-
- uint8_t *ret = (uint8_t *)kmalloc(BYTES_PER_SECTOR);
- for (int i = 0; i < BYTES_PER_SECTOR; i += 2) {
- uint16_t data = inw(interface->data_port);
- ret[i] = (uint8_t)(data & 0xFF);
- ret[i + 1] = (uint8_t)((data >> 8) & 0xFF);
- }
- return ret;
-}
-
-uint8_t ata_write28(struct ata_interface *interface, uint32_t sector, const uint8_t *contents)
-{
- if (sector > 0x0FFFFFFF)
- return 1;
- cli();
-
- outb(interface->device_port,
- (uint8_t)((interface->master ? 0xE0 : 0xF0) | ((sector & 0x0F000000) >> 24)));
-
- uint8_t status = 0;
- for (int i = 0; i < 5; i++)
- status = inb(interface->command_port);
- if (status == 0xFF)
- return 1;
-
- outb(interface->error_port, 0);
- outb(interface->sector_count_port, 1);
- outb(interface->lba_low_port, (uint8_t)(sector & 0x000000FF));
- outb(interface->lba_mid_port, (uint8_t)((sector & 0x0000FF00) >> 8));
- outb(interface->lba_high_port, (uint8_t)((sector & 0x00FF0000) >> 16));
- outb(interface->command_port, 0x30); // Write command
-
- while ((status & 0x80) || !(status & 0x08))
- status = inb(interface->command_port);
-
- 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;
- outw(interface->data_port, data);
- }
-
- outb(interface->command_port, 0xE7); // Flush command
-
- for (int i = 0; i < 5; i++)
- status = inb(interface->command_port);
- if (!status)
- return 3;
-
- while ((status & 0x80) && !(status & 0x01)) {
- status = inb(interface->command_port);
- }
-
- return 0;
-}
-
-uint8_t ata_clear28(struct ata_interface *interface, uint32_t sector)
-{
- uint8_t empty_sector[512] = { 0 };
- return ata_write28(interface, sector, empty_sector);
-} \ No newline at end of file
diff --git a/src/kernel/fs/ata_pio.h b/src/kernel/fs/ata_pio.h
deleted file mode 100644
index 7fd45e2..0000000
--- a/src/kernel/fs/ata_pio.h
+++ /dev/null
@@ -1,31 +0,0 @@
-#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 data_port;
- uint16_t error_port;
- uint16_t sector_count_port;
- uint16_t lba_low_port;
- uint16_t lba_mid_port;
- uint16_t lba_high_port;
- uint16_t device_port;
- uint16_t command_port;
- uint16_t control_port;
-};
-
-struct ata_interface *new_ata(uint8_t master, uint16_t port_base);
-
-uint8_t ata_identify(struct ata_interface *interface, uint16_t *ret_data);
-
-uint8_t *ata_read28(struct ata_interface *interface, uint32_t sector);
-
-uint8_t ata_write28(struct ata_interface *interface, uint32_t sector, const uint8_t *contents);
-
-uint8_t ata_clear28(struct ata_interface *interface, uint32_t sector);
-
-#endif \ No newline at end of file
diff --git a/src/kernel/fs/atapi_pio.c b/src/kernel/fs/atapi_pio.c
deleted file mode 100644
index 6f0e3a6..0000000
--- a/src/kernel/fs/atapi_pio.c
+++ /dev/null
@@ -1,32 +0,0 @@
-#include <stdint.h>
-#include <kernel/fs/atapi_pio.h>
-#include <kernel/system.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->blk_count = nblocks;
- d->b_offset = ATAPI_PIO_BUFFER;
- d->b_segment = 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;
-
- v86(LBA_READ_INT, &regs);
-}
-
-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
deleted file mode 100644
index 1897d53..0000000
--- a/src/kernel/fs/atapi_pio.h
+++ /dev/null
@@ -1,26 +0,0 @@
-#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 32256
-#define ATAPI_PIO_BUFFER 32768
-#define ATAPI_SECTOR_SIZE 2048
-
-struct dapack {
- uint8_t size;
- uint8_t null;
- uint16_t blk_count;
- uint16_t b_offset;
- uint16_t b_segment;
- 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 \ No newline at end of file
diff --git a/src/kernel/fs/ext2/ext2.c b/src/kernel/fs/ext2/ext2.c
new file mode 100644
index 0000000..fe45547
--- /dev/null
+++ b/src/kernel/fs/ext2/ext2.c
@@ -0,0 +1,797 @@
+#include <stddef.h>
+#include <stdint.h>
+#include <kernel/system.h>
+#include <kernel/lib/stdlib.h>
+#include <kernel/lib/stdio.h>
+#include <kernel/lib/lib.h>
+#include <kernel/memory/alloc.h>
+#include <kernel/fs/ext2/ext2.h>
+
+uint32_t ext2_file_size(vfs_node_t *node)
+{
+ ext2_fs_t *ext2fs = node->device;
+ inode_t *inode = kmalloc(sizeof(inode_t));
+ read_inode_metadata(ext2fs, inode, node->inode_num);
+ uint32_t ret = inode->size;
+ kfree(inode);
+ return ret;
+}
+
+void ext2_mkdir(vfs_node_t *parent, char *name, uint16_t permission)
+{
+ ext2_fs_t *ext2fs = parent->device;
+ uint32_t inode_idx = alloc_inode(ext2fs);
+ inode_t *inode = kmalloc(sizeof(inode_t));
+ read_inode_metadata(ext2fs, inode, inode_idx);
+ inode->permission = EXT2_S_IFDIR;
+ inode->permission |= 0xFFF & permission;
+ inode->atime = 0;
+ inode->ctime = 0;
+ inode->dtime = 0;
+ inode->gid = 0;
+ inode->userid = 0;
+ inode->f_block_addr = 0;
+ inode->num_sectors = 0;
+ inode->size = ext2fs->block_size;
+ inode->hard_links = 2;
+ inode->flags = 0;
+ inode->file_acl = 0;
+ inode->dir_acl = 0;
+ inode->generation = 0;
+ inode->os_specific1 = 0;
+ memset(inode->blocks, 0, sizeof(inode->blocks));
+ memset(inode->os_specific2, 0, 12);
+ alloc_inode_block(ext2fs, inode, inode_idx, 0);
+ write_inode_metadata(ext2fs, inode, inode_idx);
+ ext2_create_entry(parent, name, inode_idx);
+
+ inode_t *p_inode = kmalloc(sizeof(inode_t));
+ read_inode_metadata(ext2fs, p_inode, parent->inode_num);
+ p_inode->hard_links++;
+ write_inode_metadata(ext2fs, p_inode, parent->inode_num);
+ rewrite_bgds(ext2fs);
+}
+
+void ext2_mkfile(vfs_node_t *parent, char *name, uint16_t permission)
+{
+ ext2_fs_t *ext2fs = parent->device;
+ uint32_t inode_idx = alloc_inode(ext2fs);
+ inode_t *inode = kmalloc(sizeof(inode_t));
+ read_inode_metadata(ext2fs, inode, inode_idx);
+ inode->permission = EXT2_S_IFREG;
+ inode->permission |= 0xFFF & permission;
+ inode->atime = 0;
+ inode->ctime = 0;
+ inode->dtime = 0;
+ inode->gid = 0;
+ inode->userid = 0;
+ inode->f_block_addr = 0;
+ inode->num_sectors = 0;
+ inode->size = ext2fs->block_size;
+ inode->hard_links = 2;
+ inode->flags = 0;
+ inode->file_acl = 0;
+ inode->dir_acl = 0;
+ inode->generation = 0;
+ inode->os_specific1 = 0;
+ memset(inode->blocks, 0, sizeof(inode->blocks));
+ memset(inode->os_specific2, 0, 12);
+ alloc_inode_block(ext2fs, inode, inode_idx, 0);
+ write_inode_metadata(ext2fs, inode, inode_idx);
+ ext2_create_entry(parent, name, inode_idx);
+
+ inode_t *p_inode = kmalloc(sizeof(inode_t));
+ read_inode_metadata(ext2fs, p_inode, parent->inode_num);
+ p_inode->hard_links++;
+ write_inode_metadata(ext2fs, p_inode, parent->inode_num);
+ rewrite_bgds(ext2fs);
+}
+
+void ext2_unlink(vfs_node_t *parent, char *name)
+{
+ ext2_fs_t *ext2fs = parent->device;
+ ext2_remove_entry(parent, name);
+
+ inode_t *p_inode = kmalloc(sizeof(inode_t));
+ read_inode_metadata(ext2fs, p_inode, parent->inode_num);
+ p_inode->hard_links--;
+ write_inode_metadata(ext2fs, p_inode, parent->inode_num);
+ rewrite_bgds(ext2fs);
+}
+
+char **ext2_listdir(vfs_node_t *parent)
+{
+ ext2_fs_t *ext2fs = parent->device;
+ inode_t *p_inode = kmalloc(sizeof(inode_t));
+ read_inode_metadata(ext2fs, p_inode, parent->inode_num);
+ uint32_t curr_offset = 0;
+ uint32_t block_offset = 0;
+ uint32_t in_block_offset = 0;
+ int size = 0, cap = 10;
+ char **ret = kmalloc(sizeof(char *) * cap);
+ char *block_buf = read_inode_block(ext2fs, p_inode, block_offset);
+ while (curr_offset < p_inode->size) {
+ if (in_block_offset >= ext2fs->block_size) {
+ block_offset++;
+ in_block_offset = 0;
+ block_buf = read_inode_block(ext2fs, p_inode, block_offset);
+ }
+ if (size + 1 == cap) {
+ ret = krealloc(ret, sizeof(char *) * cap * 2);
+ cap = cap * 2;
+ }
+
+ direntry_t *curr_dir = (direntry_t *)(block_buf + in_block_offset);
+ if (curr_dir->inode != 0) {
+ char *temp = kcalloc(curr_dir->name_len + 1, 1);
+ memcpy(temp, curr_dir->name, curr_dir->name_len);
+ ret[size++] = temp;
+ }
+ uint32_t expected_size =
+ ((sizeof(direntry_t) + curr_dir->name_len) & 0xfffffffc) + 0x4;
+ uint32_t real_size = curr_dir->size;
+ if (real_size != expected_size) {
+ break;
+ }
+ in_block_offset += curr_dir->size;
+ curr_offset += curr_dir->size;
+ }
+ ret[size] = NULL;
+ return ret;
+}
+
+vfs_node_t *vfsnode_from_direntry(ext2_fs_t *ext2fs, direntry_t *dir, inode_t *inode)
+{
+ vfs_node_t *ret = kcalloc(sizeof(vfs_node_t), 1);
+
+ ret->device = (void *)ext2fs;
+ ret->inode_num = dir->inode;
+ memcpy(ret->name, dir->name, dir->name_len);
+
+ ret->uid = inode->userid;
+ ret->uid = inode->gid;
+ ret->size = inode->size;
+ ret->mask = inode->permission & 0xFFF;
+ ret->nlink = inode->hard_links;
+
+ ret->flags = 0;
+ if ((inode->permission & EXT2_S_IFREG) == EXT2_S_IFREG) {
+ ret->flags |= FS_FILE;
+ ret->read = ext2_read;
+ ret->write = ext2_write;
+ ret->unlink = ext2_unlink;
+ ret->get_file_size = ext2_file_size;
+ }
+ if ((inode->permission & EXT2_S_IFDIR) == EXT2_S_IFDIR) {
+ ret->flags |= FS_DIRECTORY;
+ ret->mkdir = ext2_mkdir;
+ ret->finddir = ext2_finddir;
+ ret->unlink = ext2_unlink;
+ ret->create = ext2_mkfile;
+ ret->listdir = ext2_listdir;
+ ret->read = ext2_read;
+ ret->write = ext2_write;
+ }
+ if ((inode->permission & EXT2_S_IFBLK) == EXT2_S_IFBLK) {
+ ret->flags |= FS_BLOCKDEVICE;
+ }
+ if ((inode->permission & EXT2_S_IFCHR) == EXT2_S_IFCHR) {
+ ret->flags |= FS_CHARDEVICE;
+ }
+ if ((inode->permission & EXT2_S_IFIFO) == EXT2_S_IFIFO) {
+ ret->flags |= FS_PIPE;
+ }
+ if ((inode->permission & EXT2_S_IFLNK) == EXT2_S_IFLNK) {
+ ret->flags |= FS_SYMLINK;
+ }
+
+ ret->access_time = inode->atime;
+ ret->modified_time = inode->mtime;
+ ret->create_time = inode->ctime;
+
+ ret->chmod = ext2_chmod;
+ ret->open = ext2_open;
+ ret->close = ext2_close;
+ return ret;
+}
+
+vfs_node_t *ext2_finddir(vfs_node_t *parent, char *name)
+{
+ ext2_fs_t *ext2fs = parent->device;
+ inode_t *p_inode = kmalloc(sizeof(inode_t));
+ read_inode_metadata(ext2fs, p_inode, parent->inode_num);
+ uint32_t expected_size;
+ uint32_t real_size;
+ uint32_t curr_offset = 0;
+ uint32_t block_offset = 0;
+ uint32_t in_block_offset = 0;
+ char *block_buf = read_inode_block(ext2fs, p_inode, block_offset);
+ while (curr_offset < p_inode->size) {
+ if (in_block_offset >= ext2fs->block_size) {
+ block_offset++;
+ in_block_offset = 0;
+ block_buf = read_inode_block(ext2fs, p_inode, block_offset);
+ }
+
+ direntry_t *curr_dir = (direntry_t *)(block_buf + in_block_offset);
+ char *temp = kcalloc(curr_dir->name_len + 1, 1);
+ memcpy(temp, curr_dir->name, curr_dir->name_len);
+ if (curr_dir->inode != 0 && !strcmp(temp, name)) {
+ inode_t *inode = kmalloc(sizeof(inode_t));
+ read_inode_metadata(ext2fs, inode, curr_dir->inode);
+ return vfsnode_from_direntry(ext2fs, curr_dir, inode);
+ }
+ if (((sizeof(direntry_t) + curr_dir->name_len) & 0x00000003) != 0)
+ expected_size =
+ ((sizeof(direntry_t) + curr_dir->name_len) & 0xfffffffc) + 0x4;
+ else
+ expected_size = ((sizeof(direntry_t) + curr_dir->name_len) & 0xfffffffc);
+ real_size = curr_dir->size;
+ if (real_size != expected_size) {
+ break;
+ }
+ in_block_offset += curr_dir->size;
+ curr_offset += curr_dir->size;
+ }
+ return NULL;
+}
+
+void ext2_create_entry(vfs_node_t *parent, char *entry_name, uint32_t entry_inode)
+{
+ ext2_fs_t *ext2fs = parent->device;
+ inode_t *p_inode = kmalloc(sizeof(inode_t));
+ read_inode_metadata(ext2fs, p_inode, parent->inode_num);
+ uint32_t curr_offset = 0;
+ uint32_t block_offset = 0;
+ uint32_t in_block_offset = 0;
+ uint32_t found = 0;
+ uint32_t entry_name_len = strlen(entry_name);
+ char *check = kcalloc(entry_name_len + 1, 1);
+ char *block_buf = read_inode_block(ext2fs, p_inode, block_offset);
+
+ while (curr_offset < p_inode->size) {
+ if (in_block_offset >= ext2fs->block_size) {
+ block_offset++;
+ in_block_offset = 0;
+ block_buf = read_inode_block(ext2fs, p_inode, block_offset);
+ }
+ direntry_t *curr_dir = (direntry_t *)(block_buf + in_block_offset);
+ if (curr_dir->name_len == entry_name_len) {
+ memcpy(check, curr_dir->name, entry_name_len);
+ if (curr_dir->inode != 0 && !strcmp(entry_name, check)) {
+ log("Entry by the same name %s already exist\n", check);
+ return;
+ }
+ }
+ if (found) {
+ curr_dir->inode = entry_inode;
+ curr_dir->size =
+ (uint32_t)block_buf + ext2fs->block_size - (uint32_t)curr_dir;
+ curr_dir->name_len = strlen(entry_name);
+ curr_dir->type = 0;
+ memcpy(curr_dir->name, entry_name, strlen(entry_name));
+ write_inode_block(ext2fs, p_inode, block_offset, block_buf);
+ in_block_offset += curr_dir->size;
+ if (in_block_offset >= ext2fs->block_size) {
+ block_offset++;
+ in_block_offset = 0;
+ block_buf = read_inode_block(ext2fs, p_inode, block_offset);
+ }
+ curr_dir = (direntry_t *)(block_buf + in_block_offset);
+ memset(curr_dir, 0, sizeof(direntry_t));
+ write_inode_block(ext2fs, p_inode, block_offset, block_buf);
+ return;
+ }
+ uint32_t expected_size =
+ ((sizeof(direntry_t) + curr_dir->name_len) & 0xfffffffc) + 0x4;
+ uint32_t real_size = curr_dir->size;
+ if (real_size != expected_size) {
+ found = 1;
+ curr_dir->size = expected_size;
+ in_block_offset += expected_size;
+ curr_offset += expected_size;
+ continue;
+ }
+ in_block_offset += curr_dir->size;
+ curr_offset += curr_dir->size;
+ }
+}
+
+void ext2_remove_entry(vfs_node_t *parent, char *entry_name)
+{
+ ext2_fs_t *ext2fs = parent->device;
+ inode_t *p_inode = kmalloc(sizeof(inode_t));
+ read_inode_metadata(ext2fs, p_inode, parent->inode_num);
+ uint32_t curr_offset = 0;
+ uint32_t block_offset = 0;
+ uint32_t in_block_offset = 0;
+ uint32_t entry_name_len = strlen(entry_name);
+ char *check = kcalloc(entry_name_len + 1, 1);
+ char *block_buf = read_inode_block(ext2fs, p_inode, block_offset);
+ while (curr_offset < p_inode->size) {
+ if (in_block_offset >= ext2fs->block_size) {
+ block_offset++;
+ in_block_offset = 0;
+ block_buf = read_inode_block(ext2fs, p_inode, block_offset);
+ }
+ direntry_t *curr_dir = (direntry_t *)(block_buf + in_block_offset);
+ if (curr_dir->name_len == entry_name_len) {
+ memcpy(check, curr_dir->name, entry_name_len);
+ if (curr_dir->inode != 0 && !strcmp(entry_name, check)) {
+ curr_dir->inode = 0;
+ write_inode_block(ext2fs, p_inode, block_offset, block_buf);
+ return;
+ }
+ }
+ uint32_t expected_size =
+ ((sizeof(direntry_t) + curr_dir->name_len) & 0xfffffffc) + 0x4;
+ uint32_t real_size = curr_dir->size;
+ if (real_size != expected_size)
+ return;
+ in_block_offset += curr_dir->size;
+ curr_offset += curr_dir->size;
+ }
+}
+
+void ext2_chmod(vfs_node_t *file, uint32_t mode)
+{
+ ext2_fs_t *ext2fs = file->device;
+ inode_t *inode = kmalloc(sizeof(inode_t));
+ read_inode_metadata(ext2fs, inode, file->inode_num);
+ inode->permission = (inode->permission & 0xFFFFF000) | mode;
+ write_inode_metadata(ext2fs, inode, file->inode_num);
+}
+
+uint32_t ext2_read(vfs_node_t *file, uint32_t offset, uint32_t size, char *buf)
+{
+ ext2_fs_t *ext2fs = file->device;
+ inode_t *inode = kmalloc(sizeof(inode_t));
+ read_inode_metadata(ext2fs, inode, file->inode_num);
+ read_inode_filedata(ext2fs, inode, offset, size, buf);
+ return size;
+}
+
+uint32_t ext2_write(vfs_node_t *file, uint32_t offset, uint32_t size, char *buf)
+{
+ ext2_fs_t *ext2fs = file->device;
+ inode_t *inode = kmalloc(sizeof(inode_t));
+ read_inode_metadata(ext2fs, inode, file->inode_num);
+ write_inode_filedata(ext2fs, inode, file->inode_num, offset, size, buf);
+ return size;
+}
+
+void ext2_open(vfs_node_t *file, uint32_t flags)
+{
+ ext2_fs_t *ext2fs = file->device;
+ if (flags & O_TRUNC) {
+ inode_t *inode = kmalloc(sizeof(inode_t));
+ read_inode_metadata(ext2fs, inode, file->inode_num);
+ inode->size = 0;
+ write_inode_metadata(ext2fs, inode, file->inode_num);
+ }
+}
+
+void ext2_close()
+{
+ return;
+}
+
+void read_inode_metadata(ext2_fs_t *ext2fs, inode_t *inode, uint32_t inode_idx)
+{
+ uint32_t group = inode_idx / ext2fs->inodes_per_group;
+ uint32_t inode_table_block = ext2fs->bgds[group].inode_table;
+ uint32_t idx_in_group = inode_idx - group * ext2fs->inodes_per_group;
+ uint32_t block_offset = (idx_in_group - 1) * ext2fs->sb->inode_size / ext2fs->block_size;
+ uint32_t offset_in_block =
+ (idx_in_group - 1) - block_offset * (ext2fs->block_size / ext2fs->sb->inode_size);
+ char *block_buf = kmalloc(ext2fs->block_size);
+ read_disk_block(ext2fs, inode_table_block + block_offset, block_buf);
+ memcpy(inode, block_buf + offset_in_block * ext2fs->sb->inode_size, ext2fs->sb->inode_size);
+ kfree(block_buf);
+}
+
+void write_inode_metadata(ext2_fs_t *ext2fs, inode_t *inode, uint32_t inode_idx)
+{
+ uint32_t group = inode_idx / ext2fs->inodes_per_group;
+ uint32_t inode_table_block = ext2fs->bgds[group].inode_table;
+ uint32_t block_offset = (inode_idx - 1) * ext2fs->sb->inode_size / ext2fs->block_size;
+ uint32_t offset_in_block =
+ (inode_idx - 1) - block_offset * (ext2fs->block_size / ext2fs->sb->inode_size);
+ char *block_buf = kmalloc(ext2fs->block_size);
+ read_disk_block(ext2fs, inode_table_block + block_offset, block_buf);
+ memcpy(block_buf + offset_in_block * ext2fs->sb->inode_size, inode, ext2fs->sb->inode_size);
+ write_disk_block(ext2fs, inode_table_block + block_offset, block_buf);
+ kfree(block_buf);
+}
+
+uint32_t read_inode_filedata(ext2_fs_t *ext2fs, inode_t *inode, uint32_t offset, uint32_t size,
+ char *buf)
+{
+ uint32_t end_offset = (inode->size >= offset + size) ? (offset + size) : (inode->size);
+ uint32_t start_block = offset / ext2fs->block_size;
+ uint32_t end_block = end_offset / ext2fs->block_size;
+ uint32_t start_off = offset % ext2fs->block_size;
+ uint32_t end_size = end_offset - end_block * ext2fs->block_size;
+
+ uint32_t i = start_block;
+ uint32_t curr_off = 0;
+ while (i <= end_block) {
+ uint32_t left = 0, right = ext2fs->block_size - 1;
+ char *block_buf = read_inode_block(ext2fs, inode, i);
+ if (i == start_block)
+ left = start_off;
+ if (i == end_block)
+ right = end_size - 1;
+ memcpy(buf + curr_off, block_buf + left, (right - left + 1));
+ curr_off = curr_off + (right - left + 1);
+ kfree(block_buf);
+ i++;
+ }
+ return end_offset - offset;
+}
+
+void write_inode_filedata(ext2_fs_t *ext2fs, inode_t *inode, uint32_t inode_idx, uint32_t offset,
+ uint32_t size, char *buf)
+{
+ if (offset + size > inode->size) {
+ inode->size = offset + size;
+ write_inode_metadata(ext2fs, inode, inode_idx);
+ }
+ uint32_t end_offset = (inode->size >= offset + size) ? (offset + size) : (inode->size);
+ uint32_t start_block = offset / ext2fs->block_size;
+ uint32_t end_block = end_offset / ext2fs->block_size;
+ uint32_t start_off = offset % ext2fs->block_size;
+ uint32_t end_size = end_offset - end_block * ext2fs->block_size;
+
+ uint32_t i = start_block;
+ uint32_t curr_off = 0;
+ while (i <= end_block) {
+ uint32_t left = 0, right = ext2fs->block_size;
+ char *block_buf = read_inode_block(ext2fs, inode, i);
+
+ if (i == start_block)
+ left = start_off;
+ if (i == end_block)
+ right = end_size - 1;
+ memcpy(block_buf + left, buf + curr_off, (right - left + 1));
+ curr_off = curr_off + (right - left + 1);
+ write_inode_block(ext2fs, inode, i, block_buf);
+ kfree(block_buf);
+ i++;
+ }
+}
+
+char *read_inode_block(ext2_fs_t *ext2fs, inode_t *inode, uint32_t iblock)
+{
+ char *buf = kmalloc(ext2fs->block_size);
+ uint32_t disk_block = get_disk_block_number(ext2fs, inode, iblock);
+ read_disk_block(ext2fs, disk_block, buf);
+ return buf;
+}
+
+void write_inode_block(ext2_fs_t *ext2fs, inode_t *inode, uint32_t iblock, char *buf)
+{
+ uint32_t disk_block = get_disk_block_number(ext2fs, inode, iblock);
+ write_disk_block(ext2fs, disk_block, buf);
+}
+
+void read_disk_block(ext2_fs_t *ext2fs, uint32_t block, char *buf)
+{
+ vfs_read(ext2fs->disk_device, ext2fs->block_size * block, ext2fs->block_size, buf);
+}
+
+void write_disk_block(ext2_fs_t *ext2fs, uint32_t block, char *buf)
+{
+ vfs_write(ext2fs->disk_device, ext2fs->block_size * block, ext2fs->block_size, buf);
+}
+
+void rewrite_bgds(ext2_fs_t *ext2fs)
+{
+ for (uint32_t i = 0; i < ext2fs->bgd_blocks; i++)
+ write_disk_block(ext2fs, 2, (void *)ext2fs->bgds + i * ext2fs->block_size);
+}
+
+void rewrite_superblock(ext2_fs_t *ext2fs)
+{
+ write_disk_block(ext2fs, 1, (void *)ext2fs->sb);
+}
+
+int alloc_inode_metadata_block(uint32_t *block_ptr, ext2_fs_t *ext2fs, inode_t *inode,
+ uint32_t inode_idx, char *buffer, unsigned int block_overwrite)
+{
+ if (!(*block_ptr)) {
+ unsigned int block_no = ext2_alloc_block(ext2fs);
+ if (!block_no)
+ return 0;
+ *block_ptr = block_no;
+ if (buffer)
+ write_disk_block(ext2fs, block_overwrite, (void *)buffer);
+ else
+ write_inode_metadata(ext2fs, inode, inode_idx);
+ return 1;
+ }
+ return 0;
+}
+
+uint32_t get_disk_block_number(ext2_fs_t *ext2fs, inode_t *inode, uint32_t inode_block)
+{
+ unsigned int p = ext2fs->block_size / 4;
+ int a, b, c, d, e, f, g;
+ uint32_t *tmp = kmalloc(ext2fs->block_size);
+ uint32_t ret = -1;
+ a = inode_block - EXT2_DIRECT_BLOCKS;
+ if (a < 0) {
+ ret = inode->blocks[inode_block];
+ goto done;
+ }
+ b = a - p;
+ if (b < 0) {
+ read_disk_block(ext2fs, inode->blocks[EXT2_DIRECT_BLOCKS], (void *)tmp);
+ ret = tmp[a];
+ goto done;
+ }
+ c = b - p * p;
+ if (c < 0) {
+ c = b / p;
+ d = b - c * p;
+ read_disk_block(ext2fs, inode->blocks[EXT2_DIRECT_BLOCKS + 1], (void *)tmp);
+ read_disk_block(ext2fs, tmp[c], (void *)tmp);
+ ret = tmp[d];
+ goto done;
+ }
+ d = c - p * p * p;
+ if (d < 0) {
+ e = c / (p * p);
+ f = (c - e * p * p) / p;
+ g = (c - e * p * p - f * p);
+ read_disk_block(ext2fs, inode->blocks[EXT2_DIRECT_BLOCKS + 2], (void *)tmp);
+ read_disk_block(ext2fs, tmp[e], (void *)tmp);
+ read_disk_block(ext2fs, tmp[f], (void *)tmp);
+ ret = tmp[g];
+ goto done;
+ }
+done:
+ kfree(tmp);
+ return ret;
+}
+
+void set_disk_block_number(ext2_fs_t *ext2fs, inode_t *inode, uint32_t inode_idx,
+ uint32_t inode_block, uint32_t disk_block)
+{
+ unsigned int p = ext2fs->block_size / 4;
+ int a, b, c, d, e, f, g;
+ int iblock = inode_block;
+ uint32_t *tmp = kmalloc(ext2fs->block_size);
+
+ a = iblock - EXT2_DIRECT_BLOCKS;
+ if (a <= 0) {
+ inode->blocks[inode_block] = disk_block;
+ goto done;
+ }
+ b = a - p;
+ if (b <= 0) {
+ alloc_inode_metadata_block(&(inode->blocks[EXT2_DIRECT_BLOCKS]), ext2fs, inode,
+ inode_idx, NULL, 0);
+ read_disk_block(ext2fs, inode->blocks[EXT2_DIRECT_BLOCKS], (void *)tmp);
+ ((unsigned int *)tmp)[a] = disk_block;
+ write_disk_block(ext2fs, inode->blocks[EXT2_DIRECT_BLOCKS], (void *)tmp);
+ tmp[a] = disk_block;
+ goto done;
+ }
+ c = b - p * p;
+ if (c <= 0) {
+ c = b / p;
+ d = b - c * p;
+ alloc_inode_metadata_block(&(inode->blocks[EXT2_DIRECT_BLOCKS + 1]), ext2fs, inode,
+ inode_idx, NULL, 0);
+ read_disk_block(ext2fs, inode->blocks[EXT2_DIRECT_BLOCKS + 1], (void *)tmp);
+ alloc_inode_metadata_block(&(tmp[c]), ext2fs, inode, inode_idx, (void *)tmp,
+ inode->blocks[EXT2_DIRECT_BLOCKS + 1]);
+ unsigned int temp = tmp[c];
+ read_disk_block(ext2fs, temp, (void *)tmp);
+ tmp[d] = disk_block;
+ write_disk_block(ext2fs, temp, (void *)tmp);
+ goto done;
+ }
+ d = c - p * p * p;
+ if (d <= 0) {
+ e = c / (p * p);
+ f = (c - e * p * p) / p;
+ g = (c - e * p * p - f * p);
+ alloc_inode_metadata_block(&(inode->blocks[EXT2_DIRECT_BLOCKS + 2]), ext2fs, inode,
+ inode_idx, NULL, 0);
+ read_disk_block(ext2fs, inode->blocks[EXT2_DIRECT_BLOCKS + 2], (void *)tmp);
+ alloc_inode_metadata_block(&(tmp[e]), ext2fs, inode, inode_idx, (void *)tmp,
+ inode->blocks[EXT2_DIRECT_BLOCKS + 2]);
+ unsigned int temp = tmp[e];
+ read_disk_block(ext2fs, tmp[e], (void *)tmp);
+ alloc_inode_metadata_block(&(tmp[f]), ext2fs, inode, inode_idx, (void *)tmp, temp);
+ temp = tmp[f];
+ read_disk_block(ext2fs, tmp[f], (void *)tmp);
+ tmp[g] = disk_block;
+ write_disk_block(ext2fs, temp, (void *)tmp);
+ goto done;
+ }
+done:
+ kfree(tmp);
+}
+
+uint32_t ext2_alloc_block(ext2_fs_t *ext2fs)
+{
+ uint32_t *buf = kcalloc(ext2fs->block_size, 1);
+ for (uint32_t i = 0; i < ext2fs->total_groups; i++) {
+ if (!ext2fs->bgds[i].free_blocks)
+ continue;
+
+ uint32_t bitmap_block = ext2fs->bgds[i].block_bitmap;
+ read_disk_block(ext2fs, bitmap_block, (void *)buf);
+ for (uint32_t j = 0; j < ext2fs->block_size / 4; j++) {
+ uint32_t sub_bitmap = buf[j];
+ if (sub_bitmap == 0xFFFFFFFF)
+ continue;
+ for (uint32_t k = 0; k < 32; k++) {
+ uint32_t free = !((sub_bitmap >> k) & 0x1);
+ if (free) {
+ uint32_t mask = (0x1 << k);
+ buf[j] = buf[j] | mask;
+ write_disk_block(ext2fs, bitmap_block, (void *)buf);
+ ext2fs->bgds[i].free_blocks--;
+ rewrite_bgds(ext2fs);
+ return i * ext2fs->blocks_per_group + j * 32 + k;
+ }
+ }
+ }
+ }
+ panic("We're out of blocks!\n");
+ return (uint32_t)-1;
+}
+
+void ext2_free_block(ext2_fs_t *ext2fs, uint32_t block)
+{
+ uint32_t *buf = kcalloc(ext2fs->block_size, 1);
+ uint32_t group_idx = block / ext2fs->blocks_per_group;
+ uint32_t sub_bitmap_idx = (block - (ext2fs->blocks_per_group * group_idx)) / 4;
+ uint32_t idx = (block - (ext2fs->blocks_per_group * group_idx)) % 4;
+
+ uint32_t bitmap_block = ext2fs->bgds[group_idx].block_bitmap;
+ read_disk_block(ext2fs, bitmap_block, (void *)buf);
+
+ uint32_t mask = ~(0x1 << idx);
+ buf[sub_bitmap_idx] = buf[sub_bitmap_idx] & mask;
+
+ write_disk_block(ext2fs, bitmap_block, (void *)buf);
+
+ ext2fs->bgds[group_idx].free_blocks++;
+ rewrite_bgds(ext2fs);
+}
+
+void alloc_inode_block(ext2_fs_t *ext2fs, inode_t *inode, uint32_t inode_idx, uint32_t block)
+{
+ uint32_t ret = ext2_alloc_block(ext2fs);
+ set_disk_block_number(ext2fs, inode, inode_idx, block, ret);
+ inode->num_sectors = (block + 1) * (ext2fs->block_size / 512);
+ write_inode_metadata(ext2fs, inode, inode_idx);
+}
+
+void free_inode_block(ext2_fs_t *ext2fs, inode_t *inode, uint32_t inode_idx, uint32_t block)
+{
+ uint32_t ret = get_disk_block_number(ext2fs, inode, block);
+ ext2_free_block(ext2fs, ret);
+ set_disk_block_number(ext2fs, inode, inode_idx, ret, 0);
+ write_inode_metadata(ext2fs, inode, inode_idx);
+}
+
+uint32_t alloc_inode(ext2_fs_t *ext2fs)
+{
+ uint32_t *buf = kcalloc(ext2fs->block_size, 1);
+ for (uint32_t i = 0; i < ext2fs->total_groups; i++) {
+ if (!ext2fs->bgds[i].free_inodes)
+ continue;
+
+ uint32_t bitmap_block = ext2fs->bgds[i].inode_bitmap;
+ read_disk_block(ext2fs, bitmap_block, (void *)buf);
+ for (uint32_t j = 0; j < ext2fs->block_size / 4; j++) {
+ uint32_t sub_bitmap = buf[j];
+ if (sub_bitmap == 0xFFFFFFFF)
+ continue;
+ for (uint32_t k = 0; k < 32; k++) {
+ uint32_t free = !((sub_bitmap >> k) & 0x1);
+ if (free) {
+ uint32_t mask = (0x1 << k);
+ buf[j] = buf[j] | mask;
+ write_disk_block(ext2fs, bitmap_block, (void *)buf);
+ ext2fs->bgds[i].free_inodes--;
+ rewrite_bgds(ext2fs);
+ return i * ext2fs->inodes_per_group + j * 32 + k;
+ }
+ }
+ }
+ }
+ panic("We're out of inodes!\n");
+ return (uint32_t)-1;
+}
+
+void free_inode(ext2_fs_t *ext2fs, uint32_t inode)
+{
+ uint32_t *buf = kcalloc(ext2fs->block_size, 1);
+ uint32_t group_idx = inode / ext2fs->inodes_per_group;
+ uint32_t sub_bitmap_idx = (inode - (ext2fs->inodes_per_group * group_idx)) / 4;
+ uint32_t idx = (inode - (ext2fs->inodes_per_group * group_idx)) % 4;
+
+ uint32_t bitmap_block = ext2fs->bgds[group_idx].inode_bitmap;
+ read_disk_block(ext2fs, bitmap_block, (void *)buf);
+
+ uint32_t mask = ~(0x1 << idx);
+ buf[sub_bitmap_idx] = buf[sub_bitmap_idx] & mask;
+
+ write_disk_block(ext2fs, bitmap_block, (void *)buf);
+
+ ext2fs->bgds[group_idx].free_inodes++;
+ rewrite_bgds(ext2fs);
+}
+
+vfs_node_t *get_ext2_root(ext2_fs_t *ext2fs, inode_t *inode)
+{
+ vfs_node_t *ext2root = kcalloc(sizeof(vfs_node_t), 1);
+ strcpy(ext2root->name, "/");
+ ext2root->device = ext2fs;
+ ext2root->mask = inode->permission;
+ ext2root->inode_num = ROOT_INODE_NUMBER;
+
+ ext2root->access_time = inode->atime;
+ ext2root->modified_time = inode->mtime;
+ ext2root->create_time = inode->ctime;
+
+ ext2root->flags |= FS_DIRECTORY;
+ ext2root->read = NULL;
+ ext2root->write = NULL;
+ ext2root->chmod = ext2_chmod;
+ ext2root->open = ext2_open;
+ ext2root->close = ext2_close;
+ ext2root->read = ext2_read;
+ ext2root->write = ext2_write;
+ ext2root->mkdir = ext2_mkdir;
+ ext2root->create = ext2_mkfile;
+ ext2root->listdir = ext2_listdir;
+ ext2root->finddir = ext2_finddir;
+ ext2root->unlink = ext2_unlink;
+ return ext2root;
+}
+
+void ext2_init(char *device_path, char *mountpoint)
+{
+ ext2_fs_t *ext2fs = kcalloc(sizeof(ext2_fs_t), 1);
+ ext2fs->disk_device = file_open(device_path, 0);
+ ext2fs->sb = kmalloc(SUPERBLOCK_SIZE);
+ ext2fs->block_size = 1024;
+ read_disk_block(ext2fs, 1, (void *)ext2fs->sb);
+ ext2fs->block_size = (1024 << ext2fs->sb->log2block_size);
+ ext2fs->blocks_per_group = ext2fs->sb->blocks_per_group;
+ ext2fs->inodes_per_group = ext2fs->sb->inodes_per_group;
+
+ ext2fs->total_groups = ext2fs->sb->total_blocks / ext2fs->blocks_per_group; // REMEMBER: Zero Division Exception
+ log("9");
+ if (ext2fs->blocks_per_group * ext2fs->total_groups < ext2fs->total_groups)
+ ext2fs->total_groups++;
+ log("10");
+
+ ext2fs->bgd_blocks = (ext2fs->total_groups * sizeof(bgd_t)) / ext2fs->block_size;
+ log("11");
+ if (ext2fs->bgd_blocks * ext2fs->block_size < ext2fs->total_groups * sizeof(bgd_t))
+ ext2fs->bgd_blocks++;
+ log("12");
+
+ ext2fs->bgds = kcalloc(sizeof(bgd_t), ext2fs->bgd_blocks * ext2fs->block_size);
+ log("13");
+ for (uint32_t i = 0; i < ext2fs->bgd_blocks; i++) {
+ read_disk_block(ext2fs, 2, (void *)ext2fs->bgds + i * ext2fs->block_size);
+ }
+ log("14");
+
+ inode_t *root_inode = kcalloc(sizeof(inode_t), 1);
+ log("15");
+ read_inode_metadata(ext2fs, root_inode, ROOT_INODE_NUMBER);
+ log("16");
+ vfs_mount(mountpoint, get_ext2_root(ext2fs, root_inode));
+ log("17");
+}
diff --git a/src/kernel/fs/ext2/ext2.h b/src/kernel/fs/ext2/ext2.h
new file mode 100644
index 0000000..3996ba5
--- /dev/null
+++ b/src/kernel/fs/ext2/ext2.h
@@ -0,0 +1,211 @@
+#ifndef MELVIX_EXT2_H
+#define MELVIX_EXT2_H
+
+#include <stdint.h>
+#include <kernel/fs/vfs/vfs.h>
+
+#define EXT2_DIRECT_BLOCKS 12
+
+#define SUPERBLOCK_SIZE 1024
+#define ROOT_INODE_NUMBER 2
+
+#define EXT2_S_IFSOCK 0xC000
+#define EXT2_S_IFLNK 0xA000
+#define EXT2_S_IFREG 0x8000
+#define EXT2_S_IFBLK 0x6000
+#define EXT2_S_IFDIR 0x4000
+#define EXT2_S_IFCHR 0x2000
+#define EXT2_S_IFIFO 0x1000
+
+// http://wiki.osdev.org/Ext2#Locating_the_Superblock
+typedef struct superblock {
+ uint32_t total_inodes;
+ uint32_t total_blocks;
+ uint32_t su_blocks;
+ uint32_t free_blocks;
+ uint32_t free_inodes;
+ uint32_t superblock_idx;
+ uint32_t log2block_size;
+ uint32_t log2frag_size;
+ uint32_t blocks_per_group;
+ uint32_t frags_per_group;
+ uint32_t inodes_per_group;
+
+ uint32_t mtime;
+ uint32_t wtime;
+
+ uint16_t mount_count;
+ uint16_t mount_allowed_count;
+ uint16_t ext2_magic;
+ uint16_t fs_state;
+ uint16_t err;
+ uint16_t minor;
+
+ uint32_t last_check;
+ uint32_t interval;
+ uint32_t os_id;
+ uint32_t major;
+
+ uint16_t r_userid;
+ uint16_t r_groupid;
+
+ // Extensions
+ uint32_t first_inode;
+ uint16_t inode_size;
+ uint16_t superblock_group;
+ uint32_t optional_feature;
+ uint32_t required_feature;
+ uint32_t readonly_feature;
+ char fs_id[16];
+ char vol_name[16];
+ char last_mount_path[64];
+ uint32_t compression_method;
+ uint8_t file_pre_alloc_blocks;
+ uint8_t dir_pre_alloc_blocks;
+ uint16_t unused1;
+ char journal_id[16];
+ uint32_t journal_inode;
+ uint32_t journal_device;
+ uint32_t orphan_head;
+
+ char unused2[1024 - 236];
+} __attribute__((packed)) superblock_t;
+
+typedef struct bgd {
+ uint32_t block_bitmap;
+ uint32_t inode_bitmap;
+ uint32_t inode_table;
+ uint32_t free_blocks;
+ uint32_t free_inodes;
+ uint32_t num_dirs;
+ uint32_t unused1;
+ uint32_t unused2;
+} __attribute__((packed)) bgd_t;
+
+typedef struct direntry {
+ uint32_t inode;
+ uint16_t size;
+ uint8_t name_len;
+ uint8_t type;
+ char name[];
+} __attribute__((packed)) direntry_t;
+
+typedef struct inode {
+ uint16_t permission;
+ uint16_t userid;
+ uint32_t size;
+ uint32_t atime;
+ uint32_t ctime;
+ uint32_t mtime;
+ uint32_t dtime;
+ uint16_t gid;
+ uint16_t hard_links;
+ uint32_t num_sectors;
+ uint32_t flags;
+ uint32_t os_specific1;
+ uint32_t blocks[EXT2_DIRECT_BLOCKS + 3];
+ uint32_t generation;
+ uint32_t file_acl;
+ union {
+ uint32_t dir_acl;
+ uint32_t size_high;
+ };
+ uint32_t f_block_addr;
+ char os_specific2[12];
+} __attribute__((packed)) inode_t;
+
+typedef struct ext2_cache {
+ uint32_t block;
+ uint32_t times;
+ uint8_t dirty;
+ char *block_data;
+} ext2_cache_t;
+
+typedef struct ext2_fs {
+ vfs_node_t *disk_device;
+
+ superblock_t *sb;
+ bgd_t *bgds;
+ uint32_t block_size;
+ uint32_t blocks_per_group;
+ uint32_t inodes_per_group;
+ uint32_t total_groups;
+
+ uint32_t bgd_blocks;
+} ext2_fs_t;
+
+uint32_t ext2_file_size(vfs_node_t *node);
+
+void ext2_mkdir(vfs_node_t *parent, char *name, uint16_t permission);
+
+void ext2_mkfile(vfs_node_t *parent, char *name, uint16_t permission);
+
+void ext2_create_entry(vfs_node_t *parent, char *entry_name, uint32_t entry_inode);
+
+void ext2_unlink(vfs_node_t *parent, char *name);
+
+char **ext2_listdir(vfs_node_t *parent);
+
+vfs_node_t *ext2_finddir(vfs_node_t *parent, char *name);
+
+void ext2_create_entry(vfs_node_t *parent, char *entry_name, uint32_t entry_inode);
+
+void ext2_remove_entry(vfs_node_t *parent, char *entry_name);
+
+void ext2_chmod(vfs_node_t *file, uint32_t mode);
+
+uint32_t ext2_read(vfs_node_t *file, uint32_t offset, uint32_t size, char *buf);
+
+uint32_t ext2_write(vfs_node_t *file, uint32_t offset, uint32_t size, char *buf);
+
+void ext2_open(vfs_node_t *file, uint32_t flags);
+
+void ext2_close();
+
+void read_inode_metadata(ext2_fs_t *ext2fs, inode_t *inode, uint32_t inode_idx);
+
+void write_inode_metadata(ext2_fs_t *ext2fs, inode_t *inode, uint32_t inode_idx);
+
+uint32_t read_inode_filedata(ext2_fs_t *ext2fs, inode_t *inode, uint32_t offset, uint32_t size,
+ char *buf);
+
+void write_inode_filedata(ext2_fs_t *ext2fs, inode_t *inode, uint32_t inode_idx, uint32_t offset,
+ uint32_t size, char *buf);
+
+char *read_inode_block(ext2_fs_t *ext2fs, inode_t *inode, uint32_t iblock);
+
+void write_inode_block(ext2_fs_t *ext2fs, inode_t *inode, uint32_t iblock, char *buf);
+
+void read_disk_block(ext2_fs_t *ext2fs, uint32_t block, char *buf);
+
+void write_disk_block(ext2_fs_t *ext2fs, uint32_t block, char *buf);
+
+void rewrite_bgds(ext2_fs_t *ext2fs);
+
+void rewrite_superblock(ext2_fs_t *ext2fs);
+
+int alloc_inode_metadata_block(uint32_t *block_ptr, ext2_fs_t *ext2fs, inode_t *inode,
+ uint32_t inode_idx, char *buffer, unsigned int block_overwrite);
+
+uint32_t get_disk_block_number(ext2_fs_t *ext2fs, inode_t *inode, uint32_t inode_block);
+
+void set_disk_block_number(ext2_fs_t *ext2fs, inode_t *inode, uint32_t inode_idx,
+ uint32_t inode_block, uint32_t disk_block);
+
+uint32_t ext2_alloc_block(ext2_fs_t *ext2fs);
+
+void ext2_free_block(ext2_fs_t *ext2fs, uint32_t block);
+
+void alloc_inode_block(ext2_fs_t *ext2fs, inode_t *inode, uint32_t inode_idx, uint32_t block);
+
+void free_inode_block(ext2_fs_t *ext2fs, inode_t *inode, uint32_t inode_idx, uint32_t block);
+
+uint32_t alloc_inode(ext2_fs_t *ext2fs);
+
+void free_inode(ext2_fs_t *ext2fs, uint32_t inode);
+
+vfs_node_t *get_ext2_root(ext2_fs_t *ext2fs, inode_t *inode);
+
+void ext2_init(char *device_path, char *mountpoint);
+
+#endif \ No newline at end of file
diff --git a/src/kernel/fs/iso9660/iso9660.c b/src/kernel/fs/iso9660/iso9660.c
deleted file mode 100644
index ab00c31..0000000
--- a/src/kernel/fs/iso9660/iso9660.c
+++ /dev/null
@@ -1,59 +0,0 @@
-#include <stdint.h>
-#include <kernel/fs/atapi_pio.h>
-#include <kernel/fs/iso9660/iso9660.h>
-#include <kernel/lib/stdlib.h>
-#include <kernel/memory/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
deleted file mode 100644
index 6b2e0b0..0000000
--- a/src/kernel/fs/iso9660/iso9660.h
+++ /dev/null
@@ -1,22 +0,0 @@
-#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 \ No newline at end of file
diff --git a/src/kernel/fs/load.c b/src/kernel/fs/load.c
index edfa2cc..ad76c5b 100644
--- a/src/kernel/fs/load.c
+++ b/src/kernel/fs/load.c
@@ -1,8 +1,5 @@
#include <kernel/fs/load.h>
-#include <kernel/fs/ata_pio.h>
-#include <kernel/fs/atapi_pio.h>
#include <kernel/system.h>
-#include <kernel/fs/iso9660/iso9660.h>
#include <kernel/memory/alloc.h>
#include <kernel/lib/stdio.h>
#include <kernel/lib/lib.h>
@@ -15,6 +12,7 @@ void load_binaries()
if (multiboot_header->boot_device != 0xE0FFFFFF) {
panic("Unsupported boot drive!");
} else {
+ /*
char *font_p[] = { "FONT.BIN" };
struct iso9660_entity *font_e = ISO9660_get(font_p, 1);
if (!font_e)
@@ -33,6 +31,7 @@ void load_binaries()
serial_printf("0x%x: WRONG FONT MAGIC!", font->magic);
halt_loop();
}
+ */
}
vga_log("Successfully loaded binaries");
-} \ No newline at end of file
+}
diff --git a/src/kernel/fs/vfs/vfs.c b/src/kernel/fs/vfs/vfs.c
new file mode 100644
index 0000000..bbc3912
--- /dev/null
+++ b/src/kernel/fs/vfs/vfs.c
@@ -0,0 +1,371 @@
+#include <kernel/system.h>
+#include <kernel/fs/ext2/ext2.h>
+#include <kernel/fs/vfs/vfs.h>
+#include <kernel/lib/data/list.h>
+#include <kernel/lib/data/generic_tree.h>
+#include <kernel/memory/alloc.h>
+#include <kernel/lib/stdlib.h>
+#include <kernel/lib/lib.h>
+
+gtree_t *vfs_tree;
+vfs_node_t *vfs_root;
+
+uint32_t vfs_get_file_size(vfs_node_t *node)
+{
+ if (node && node->get_file_size) {
+ return node->get_file_size(node);
+ }
+ return 0;
+}
+
+void vfs_db_listdir(char *name)
+{
+ vfs_node_t *n = file_open(name, 0);
+ if (!n) {
+ log("Could not list a directory that does not exist\n");
+ return;
+ }
+ if (!n->listdir)
+ return;
+ char **files = n->listdir(n);
+ char **save = files;
+ while (*files) {
+ log("%s ", *files);
+ kfree(*files);
+ files++;
+ }
+ kfree(save);
+ log("\n");
+}
+
+void print_vfstree_recur(gtreenode_t *node, int parent_offset)
+{
+ if (!node)
+ return;
+ char *tmp = kmalloc(512);
+ int len = 0;
+ memset(tmp, 0, 512);
+ for (int i = 0; i < parent_offset; ++i) {
+ strcat(tmp, " ");
+ }
+ char *curr = tmp + strlen(tmp);
+ struct vfs_entry *fnode = (struct vfs_entry *)node->value;
+ if (fnode->file) {
+ log(curr, "%s(0x%x, %s)", fnode->name, (uint32_t)fnode->file, fnode->file->name);
+ } else {
+ log(curr, "%s(empty)", fnode->name);
+ }
+ log("%s\n", tmp);
+ len = strlen(fnode->name);
+ kfree(tmp);
+ foreach(child, node->children)
+ {
+ print_vfstree_recur(child->val, parent_offset + len + 1);
+ }
+}
+
+void print_vfstree()
+{
+ print_vfstree_recur(vfs_tree->root, 0);
+}
+
+uint32_t vfs_read(vfs_node_t *node, uint32_t offset, uint32_t size, char *buffer)
+{
+ if (node && node->read) {
+ uint32_t ret = node->read(node, offset, size, buffer);
+ return ret;
+ }
+ return -1;
+}
+
+uint32_t vfs_write(vfs_node_t *node, uint32_t offset, uint32_t size, char *buffer)
+{
+ if (node && node->write) {
+ uint32_t ret = node->write(node, offset, size, buffer);
+ return ret;
+ }
+ return -1;
+}
+
+void vfs_open(struct vfs_node *node, uint32_t flags)
+{
+ if (!node)
+ return;
+ if (node->refcount >= 0)
+ node->refcount++;
+ node->open(node, flags);
+}
+
+void vfs_close(vfs_node_t *node)
+{
+ if (!node || node == vfs_root || node->refcount == -1)
+ return;
+ node->refcount--;
+ if (node->refcount == 0)
+ node->close(node);
+}
+
+void vfs_chmod(vfs_node_t *node, uint32_t mode)
+{
+ if (node->chmod)
+ return node->chmod(node, mode);
+}
+
+struct dirent *vfs_readdir(vfs_node_t *node, uint32_t index)
+{
+ if (node && (node->flags & FS_DIRECTORY) && node->readdir)
+ return node->readdir(node, index);
+ return NULL;
+}
+
+vfs_node_t *vfs_finddir(vfs_node_t *node, char *name)
+{
+ if (node && (node->flags & FS_DIRECTORY) && node->finddir)
+ return node->finddir(node, name);
+ return NULL;
+}
+
+int vfs_ioctl(vfs_node_t *node, int request, void *argp)
+{
+ if (!node)
+ return -1;
+ if (node->ioctl)
+ return node->ioctl(node, request, argp);
+ return -1; // ENOTTY
+}
+
+void vfs_mkdir(char *name, unsigned short permission)
+{
+ // Find parent directory
+ int i = strlen(name);
+ char *dirname = strdup(name);
+ char *save_dirname = dirname;
+ char *parent_path = "/";
+ while (i >= 0) {
+ if (dirname[i] == '/') {
+ if (i != 0) {
+ dirname[i] = '\0';
+ parent_path = dirname;
+ }
+ dirname = &dirname[i + 1];
+ break;
+ }
+ i--;
+ }
+
+ // Open file
+ vfs_node_t *parent_node = file_open(parent_path, 0);
+ if (!parent_node) {
+ kfree(save_dirname);
+ }
+
+ // mkdir
+ if (parent_node->mkdir)
+ parent_node->mkdir(parent_node, dirname, permission);
+ kfree(save_dirname);
+
+ vfs_close(parent_node);
+}
+
+int vfs_create_file(char *name, unsigned short permission)
+{
+ // Find parent directory
+ int i = strlen(name);
+ char *dirname = strdup(name);
+ char *save_dirname = dirname;
+ char *parent_path = "/";
+ while (i >= 0) {
+ if (dirname[i] == '/') {
+ if (i != 0) {
+ dirname[i] = '\0';
+ parent_path = dirname;
+ }
+ dirname = &dirname[i + 1];
+ break;
+ }
+ i--;
+ }
+
+ // Open file
+ vfs_node_t *parent_node = file_open(parent_path, 0);
+ if (!parent_node) {
+ kfree(save_dirname);
+ return -1;
+ }
+ if (parent_node->create)
+ parent_node->create(parent_node, dirname, permission);
+ kfree(save_dirname);
+ vfs_close(parent_node);
+ return 0;
+}
+
+void vfs_unlink(char *name)
+{
+ // Find parent directory
+ int i = strlen(name);
+ char *dirname = strdup(name);
+ char *save_dirname = dirname;
+ char *parent_path = "/";
+ while (i >= 0) {
+ if (dirname[i] == '/') {
+ if (i != 0) {
+ dirname[i] = '\0';
+ parent_path = dirname;
+ }
+ dirname = &dirname[i + 1];
+ break;
+ }
+ i--;
+ }
+
+ // Open file
+ vfs_node_t *parent_node = file_open(parent_path, 0);
+ if (!parent_node) {
+ kfree(save_dirname);
+ }
+ if (parent_node->unlink)
+ parent_node->unlink(parent_node, dirname);
+ kfree(save_dirname);
+ vfs_close(parent_node);
+}
+
+char *expand_path(char *input)
+{
+ list_t *input_list = str_split(input, "/", NULL);
+ char *ret = list2str(input_list, "/");
+ return ret;
+}
+
+vfs_node_t *get_mountpoint_recur(char **path, gtreenode_t *subroot)
+{
+ int found = 0;
+ char *curr_token = strsep(path, "/");
+ if (curr_token == NULL || !strcmp(curr_token, "")) {
+ struct vfs_entry *ent = (struct vfs_entry *)subroot->value;
+ return ent->file;
+ }
+ foreach(child, subroot->children)
+ {
+ gtreenode_t *tchild = (gtreenode_t *)child->val;
+ struct vfs_entry *ent = (struct vfs_entry *)(tchild->value);
+ if (strcmp(ent->name, curr_token) == 0) {
+ found = 1;
+ subroot = tchild;
+ break;
+ }
+ }
+
+ if (!found) {
+ *path = curr_token;
+ return ((struct vfs_entry *)(subroot->value))->file;
+ }
+ return get_mountpoint_recur(path, subroot);
+}
+vfs_node_t *get_mountpoint(char **path)
+{
+ if (strlen(*path) > 1 && (*path)[strlen(*path) - 1] == '/')
+ *(path)[strlen(*path) - 1] = '\0';
+ if (!*path || *(path)[0] != '/')
+ return NULL;
+ if (strlen(*path) == 1) {
+ *path = '\0';
+ struct vfs_entry *ent = (struct vfs_entry *)vfs_tree->root->value;
+ return ent->file;
+ }
+ (*path)++;
+ return get_mountpoint_recur(path, vfs_tree->root);
+}
+
+vfs_node_t *file_open(const char *file_name, uint32_t flags)
+{
+ char *curr_token = NULL;
+ char *filename = strdup(file_name);
+ char *free_filename = filename;
+ char *save = strdup(filename);
+ char *original_filename = filename;
+ char *new_start = NULL;
+ vfs_node_t *nextnode = NULL;
+ vfs_node_t *startpoint = get_mountpoint(&filename);
+ if (!startpoint)
+ return NULL;
+ if (filename)
+ new_start = strstr(save + (filename - original_filename), filename);
+ while (filename != NULL && ((curr_token = strsep(&new_start, "/")) != NULL)) {
+ nextnode = vfs_finddir(startpoint, curr_token);
+ if (!nextnode)
+ return NULL;
+ startpoint = nextnode;
+ }
+ if (!nextnode)
+ nextnode = startpoint;
+ vfs_open(nextnode, flags);
+ kfree(save);
+ kfree(free_filename);
+ return nextnode;
+}
+
+void vfs_init()
+{
+ vfs_tree = tree_create();
+ struct vfs_entry *root = kmalloc(sizeof(struct vfs_entry));
+ root->name = strdup("root");
+ root->file = NULL;
+ tree_insert(vfs_tree, NULL, root);
+}
+
+void vfs_mount_dev(char *mountpoint, vfs_node_t *node)
+{
+ vfs_mount(mountpoint, node);
+}
+
+void vfs_mount_recur(char *path, gtreenode_t *subroot, vfs_node_t *fs_obj)
+{
+ int found = 0;
+ char *curr_token = strsep(&path, "/");
+
+ if (curr_token == NULL || !strcmp(curr_token, "")) {
+ struct vfs_entry *ent = (struct vfs_entry *)subroot->value;
+ if (ent->file) {
+ log("The path is already mounted, plz unmount before mounting again\n");
+ return;
+ }
+ if (!strcmp(ent->name, "/"))
+ vfs_root = fs_obj;
+ ent->file = fs_obj;
+ return;
+ }
+
+ foreach(child, subroot->children)
+ {
+ gtreenode_t *tchild = (gtreenode_t *)child->val;
+ struct vfs_entry *ent = (struct vfs_entry *)(tchild->value);
+ if (strcmp(ent->name, curr_token) == 0) {
+ found = 1;
+ subroot = tchild;
+ }
+ }
+
+ if (!found) {
+ struct vfs_entry *ent = kcalloc(sizeof(struct vfs_entry), 1);
+ ent->name = strdup(curr_token);
+ subroot = tree_insert(vfs_tree, subroot, ent);
+ }
+ vfs_mount_recur(path, subroot, fs_obj);
+}
+
+void vfs_mount(char *path, vfs_node_t *fs_obj)
+{
+ fs_obj->refcount = -1;
+ fs_obj->fs_type = 0;
+ if (path[0] == '/' && strlen(path) == 1) {
+ struct vfs_entry *ent = (struct vfs_entry *)vfs_tree->root->value;
+ if (ent->file) {
+ log("The path is already mounted, plz unmount before mounting again\n");
+ return;
+ }
+ vfs_root = fs_obj;
+ ent->file = fs_obj;
+ return;
+ }
+ vfs_mount_recur(path + 1, vfs_tree->root, fs_obj);
+} \ No newline at end of file
diff --git a/src/kernel/fs/vfs/vfs.h b/src/kernel/fs/vfs/vfs.h
new file mode 100644
index 0000000..b31767e
--- /dev/null
+++ b/src/kernel/fs/vfs/vfs.h
@@ -0,0 +1,149 @@
+#ifndef MELVIX_VFS_H
+#define MELVIX_VFS_H
+
+#include <stdint.h>
+
+#define PATH_SEPARATOR '/'
+#define PATH_SEPARATOR_STRING "/"
+#define PATH_UP ".."
+#define PATH_DOT "."
+#define VFS_EXT2_MAGIC 0xeeee2222
+
+#define O_RDONLY 0x0000
+#define O_WRONLY 0x0001
+#define O_RDWR 0x0002
+#define O_APPEND 0x0008
+#define O_CREAT 0x0200
+#define O_TRUNC 0x0400
+#define O_EXCL 0x0800
+#define O_NOFOLLOW 0x1000
+#define O_PATH 0x2000
+
+#define FS_FILE 0x01
+#define FS_DIRECTORY 0x02
+#define FS_CHARDEVICE 0x04
+#define FS_BLOCKDEVICE 0x08
+#define FS_PIPE 0x10
+#define FS_SYMLINK 0x20
+#define FS_MOUNTPOINT 0x40
+
+#define _IFMT 0170000 /* type of file */
+#define _IFDIR 0040000 /* directory */
+#define _IFCHR 0020000 /* character special */
+#define _IFBLK 0060000 /* block special */
+#define _IFREG 0100000 /* regular */
+#define _IFLNK 0120000 /* symbolic link */
+#define _IFSOCK 0140000 /* socket */
+#define _IFIFO 0010000 /* fifo */
+
+struct vfs_node;
+
+typedef uint32_t (*get_file_size_callback)(struct vfs_node *node);
+typedef uint32_t (*read_callback)(struct vfs_node *, uint32_t, uint32_t, char *);
+typedef uint32_t (*write_callback)(struct vfs_node *, uint32_t, uint32_t, char *);
+typedef void (*open_callback)(struct vfs_node *, uint32_t flags);
+typedef void (*close_callback)(struct vfs_node *);
+typedef struct dirent *(*readdir_callback)(struct vfs_node *, uint32_t);
+typedef struct vfs_node *(*finddir_callback)(struct vfs_node *, char *name);
+typedef void (*create_callback)(struct vfs_node *, char *name, uint16_t permission);
+typedef void (*unlink_callback)(struct vfs_node *, char *name);
+typedef void (*mkdir_callback)(struct vfs_node *, char *name, uint16_t permission);
+typedef int (*ioctl_callback)(struct vfs_node *, int request, void *argp);
+typedef int (*get_size_callback)(struct vfs_node *);
+typedef void (*chmod_callback)(struct vfs_node *, uint32_t mode);
+typedef char **(*listdir_callback)(struct vfs_node *);
+
+typedef struct vfs_node {
+ char name[256];
+ void *device;
+ uint32_t mask;
+ uint32_t uid;
+ uint32_t gid;
+ uint32_t flags;
+ uint32_t inode_num;
+ uint32_t size;
+ uint32_t fs_type;
+ uint32_t open_flags;
+ uint32_t create_time;
+ uint32_t access_time;
+ uint32_t modified_time;
+
+ uint32_t offset;
+ unsigned nlink;
+ int refcount;
+
+ // File operations
+ read_callback read;
+ write_callback write;
+ open_callback open;
+ close_callback close;
+ readdir_callback readdir;
+ finddir_callback finddir;
+ create_callback create;
+ unlink_callback unlink;
+ mkdir_callback mkdir;
+ ioctl_callback ioctl;
+ get_size_callback get_size;
+ chmod_callback chmod;
+ get_file_size_callback get_file_size;
+
+ listdir_callback listdir;
+} vfs_node_t;
+
+struct dirent {
+ char name[256];
+ uint32_t inode_num;
+};
+
+typedef struct vfs_entry {
+ char *name;
+ vfs_node_t *file;
+} vfs_entry_t;
+
+uint32_t vfs_get_file_size(vfs_node_t *node);
+
+uint32_t vfs_read(vfs_node_t *node, uint32_t offset, uint32_t size, char *buffer);
+
+uint32_t vfs_write(vfs_node_t *node, uint32_t offset, uint32_t size, char *buffer);
+
+void vfs_open(struct vfs_node *node, uint32_t flags);
+
+void vfs_close(vfs_node_t *node);
+
+vfs_node_t *vfs_finddir(vfs_node_t *node, char *name);
+
+void vfs_mkdir(char *name, uint16_t permission);
+
+void vfs_mkfile(char *name, uint16_t permission);
+
+int vfs_create_file(char *name, uint16_t permission);
+
+vfs_node_t *file_open(const char *file_name, uint32_t flags);
+
+char *expand_path(char *input);
+
+int vfs_ioctl(vfs_node_t *node, int request, void *argp);
+
+void vfs_chmod(vfs_node_t *node, uint32_t mode);
+
+void vfs_unlink(char *name);
+
+int vfs_symlink(char *value, char *name);
+
+int vfs_readlink(vfs_node_t *node, char *buf, uint32_t size);
+
+void vfs_init();
+
+void vfs_mount(char *path, vfs_node_t *local_root);
+
+typedef vfs_node_t *(*vfs_mount_callback)(char *arg, char *mountpoint);
+
+void vfs_register(char *name, vfs_mount_callback callme);
+
+void vfs_mount_dev(char *mountpoint, vfs_node_t *node);
+
+void print_vfstree();
+
+void vfs_db_listdir(char *name);
+
+#endif \ No newline at end of file
diff --git a/src/kernel/io/io.c b/src/kernel/io/io.c
index 803a78a..1f67c11 100644
--- a/src/kernel/io/io.c
+++ b/src/kernel/io/io.c
@@ -74,4 +74,4 @@ void serial_put(char ch)
while (is_transmit_empty() == 0)
;
outb(0x3f8, (uint8_t)ch);
-} \ No newline at end of file
+}
diff --git a/src/kernel/kernel.c b/src/kernel/kernel.c
index 019e4b4..f116ab8 100644
--- a/src/kernel/kernel.c
+++ b/src/kernel/kernel.c
@@ -15,6 +15,9 @@
#include <kernel/fs/load.h>
#include <kernel/fs/elf.h>
#include <kernel/lib/stdio.h>
+#include <kernel/fs/ata.h>
+#include <kernel/fs/ext2/ext2.h>
+#include <kernel/fs/vfs/vfs.h>
void kernel_main(uint32_t magic, multiboot_info_t *grub_header)
{
@@ -47,6 +50,9 @@ void kernel_main(uint32_t magic, multiboot_info_t *grub_header)
network_install();
sti();
+ vfs_init();
+ ata_init();
+ ext2_init("/dev/hda", "/");
// tasking_install();
// Get hardware information
@@ -68,4 +74,4 @@ void kernel_main(uint32_t magic, multiboot_info_t *grub_header)
// panic("This should NOT happen!");
// asm ("div %0" :: "r"(0)); // Exception testing x/0
-} \ No newline at end of file
+}
diff --git a/src/kernel/lib/data/generic_tree.c b/src/kernel/lib/data/generic_tree.c
new file mode 100644
index 0000000..38caccc
--- /dev/null
+++ b/src/kernel/lib/data/generic_tree.c
@@ -0,0 +1,102 @@
+#include <kernel/lib/data/generic_tree.h>
+#include <kernel/lib/data/list.h>
+#include <kernel/memory/alloc.h>
+
+gtree_t *tree_create()
+{
+ return (gtree_t *)kcalloc(sizeof(gtree_t), 1);
+}
+
+gtreenode_t *treenode_create(void *value)
+{
+ gtreenode_t *n = kcalloc(sizeof(gtreenode_t), 1);
+ n->value = value;
+ n->children = list_create();
+ return n;
+}
+
+gtreenode_t *tree_insert(gtree_t *tree, gtreenode_t *subroot, void *value)
+{
+ gtreenode_t *treenode = kcalloc(sizeof(gtreenode_t), 1);
+ treenode->children = list_create();
+ treenode->value = value;
+
+ if (!tree->root) {
+ tree->root = treenode;
+ return treenode;
+ }
+ list_insert_front(subroot->children, treenode);
+ return treenode;
+}
+
+gtreenode_t *tree_find_parent(gtree_t *tree, gtreenode_t *remove_node, int *child_index)
+{
+ if (remove_node == tree->root)
+ return NULL;
+ return tree_find_parent_recur(tree, remove_node, tree->root, child_index);
+}
+
+gtreenode_t *tree_find_parent_recur(gtree_t *tree, gtreenode_t *remove_node, gtreenode_t *subroot,
+ int *child_index)
+{
+ int idx;
+ if ((idx = list_contain(subroot->children, remove_node)) != -1) {
+ *child_index = idx;
+ return subroot;
+ }
+ foreach(child, subroot->children)
+ {
+ gtreenode_t *ret =
+ tree_find_parent_recur(tree, remove_node, child->val, child_index);
+ if (ret != NULL) {
+ return ret;
+ }
+ }
+ return NULL;
+}
+
+void tree_remove(gtree_t *tree, gtreenode_t *remove_node)
+{
+ int child_index = -1;
+ gtreenode_t *parent = tree_find_parent(tree, remove_node, &child_index);
+ if (parent != NULL) {
+ gtreenode_t *freethis = list_remove_by_index(parent->children, child_index);
+ kfree(freethis);
+ }
+}
+
+void tree2list_recur(gtreenode_t *subroot, list_t *list)
+{
+ if (subroot == NULL)
+ return;
+ foreach(child, subroot->children)
+ {
+ gtreenode_t *curr_treenode = (gtreenode_t *)child->val;
+ void *curr_val = curr_treenode->value;
+ list_insert_back(list, curr_val);
+ tree2list_recur(child->val, list);
+ }
+}
+
+void tree2list(gtree_t *tree, list_t *list)
+{
+ tree2list_recur(tree->root, list);
+}
+
+void tree2array(gtree_t *tree, void **array, int *size)
+{
+ tree2array_recur(tree->root, array, size);
+}
+
+void tree2array_recur(gtreenode_t *subroot, void **array, int *size)
+{
+ if (subroot == NULL)
+ return;
+ void *curr_val = (void *)subroot->value;
+ array[*size] = curr_val;
+ *size = *size + 1;
+ foreach(child, subroot->children)
+ {
+ tree2array_recur(child->val, array, size);
+ }
+} \ No newline at end of file
diff --git a/src/kernel/lib/data/generic_tree.h b/src/kernel/lib/data/generic_tree.h
new file mode 100644
index 0000000..3a630bc
--- /dev/null
+++ b/src/kernel/lib/data/generic_tree.h
@@ -0,0 +1,36 @@
+#ifndef MELVIX_GENERIC_TREE_H
+#define MELVIX_GENERIC_TREE_H
+
+#include <kernel/lib/data/list.h>
+
+typedef struct gtreenode {
+ list_t *children;
+ void *value;
+} gtreenode_t;
+
+typedef struct gtree {
+ gtreenode_t *root;
+} gtree_t;
+
+gtree_t *tree_create();
+
+gtreenode_t *treenode_create(void *value);
+
+gtreenode_t *tree_insert(gtree_t *tree, gtreenode_t *subroot, void *value);
+
+gtreenode_t *tree_find_parent(gtree_t *tree, gtreenode_t *remove_node, int *child_index);
+
+gtreenode_t *tree_find_parent_recur(gtree_t *tree, gtreenode_t *remove_node, gtreenode_t *subroot,
+ int *child_index);
+
+void tree_remove(gtree_t *tree, gtreenode_t *remove_node);
+
+void tree2list_recur(gtreenode_t *subroot, list_t *list);
+
+void tree2list(gtree_t *tree, list_t *list);
+
+void tree2array(gtree_t *tree, void **array, int *size);
+
+void tree2array_recur(gtreenode_t *subroot, void **array, int *size);
+
+#endif \ No newline at end of file
diff --git a/src/kernel/lib/data/list.c b/src/kernel/lib/data/list.c
new file mode 100644
index 0000000..7a0cff2
--- /dev/null
+++ b/src/kernel/lib/data/list.c
@@ -0,0 +1,220 @@
+#include <kernel/lib/data/list.h>
+#include <kernel/memory/alloc.h>
+#include <kernel/lib/stdlib.h>
+#include <kernel/lib/lib.h>
+
+list_t *list_create()
+{
+ list_t *list = kcalloc(sizeof(list_t), 1);
+ return list;
+}
+
+uint32_t list_size(list_t *list)
+{
+ if (!list)
+ return 0;
+ return list->size;
+}
+
+void *list_remove_node(list_t *list, listnode_t *node)
+{
+ void *val = node->val;
+ if (list->head == node)
+ return list_remove_front(list);
+ else if (list->tail == node)
+ return list_remove_back(list);
+ else {
+ node->next->prev = node->prev;
+ node->prev->next = node->next;
+ list->size--;
+ kfree(node);
+ }
+ return val;
+}
+
+listnode_t *list_insert_front(list_t *list, void *val)
+{
+ listnode_t *t = kcalloc(sizeof(listnode_t), 1);
+ list->head->prev = t;
+ t->next = list->head;
+ t->val = val;
+
+ if (!list->head)
+ list->tail = t;
+
+ list->head = t;
+ list->size++;
+ return t;
+}
+
+void list_insert_back(list_t *list, void *val)
+{
+ listnode_t *t = kcalloc(sizeof(listnode_t), 1);
+ t->prev = list->tail;
+ if (list->tail)
+ list->tail->next = t;
+ t->val = val;
+
+ if (!list->head)
+ list->head = t;
+
+ list->tail = t;
+ list->size++;
+}
+
+void *list_remove_front(list_t *list)
+{
+ if (!list->head)
+ return 0;
+ listnode_t *t = list->head;
+ void *val = t->val;
+ list->head = t->next;
+ if (list->head)
+ list->head->prev = NULL;
+ kfree(t);
+ list->size--;
+ return val;
+}
+
+void *list_remove_back(list_t *list)
+{
+ if (!list->head)
+ return NULL;
+ listnode_t *t = list->tail;
+ void *val = t->val;
+ list->tail = t->prev;
+ if (list->tail)
+ list->tail->next = NULL;
+ kfree(t);
+ list->size--;
+ return val;
+}
+
+void list_push(list_t *list, void *val)
+{
+ list_insert_back(list, val);
+}
+
+listnode_t *list_pop(list_t *list)
+{
+ if (!list->head)
+ return NULL;
+ listnode_t *t = list->tail;
+ list->tail = t->prev;
+ if (list->tail)
+ list->tail->next = NULL;
+ list->size--;
+ return t;
+}
+
+void list_enqueue(list_t *list, void *val)
+{
+ list_insert_front(list, val);
+}
+
+listnode_t *list_dequeue(list_t *list)
+{
+ return list_pop(list);
+}
+
+void *list_peek_front(list_t *list)
+{
+ if (!list->head)
+ return NULL;
+ return list->head->val;
+}
+
+void *list_peek_back(list_t *list)
+{
+ if (!list->tail)
+ return NULL;
+ return list->tail->val;
+}
+
+int list_contain(list_t *list, void *val)
+{
+ int idx = 0;
+ foreach(listnode, list)
+ {
+ if (listnode->val == val)
+ return idx;
+ idx++;
+ }
+ return -1;
+}
+
+listnode_t *list_get_node_by_index(list_t *list, int index)
+{
+ if (index < 0 || (uint32_t)index >= list_size(list))
+ return NULL;
+ int curr = 0;
+ foreach(listnode, list)
+ {
+ if (index == curr)
+ return listnode;
+ curr++;
+ }
+ return NULL;
+}
+
+void *list_remove_by_index(list_t *list, int index)
+{
+ listnode_t *node = list_get_node_by_index(list, index);
+ return list_remove_node(list, node);
+}
+
+void list_destroy(list_t *list)
+{
+ listnode_t *node = list->head;
+ while (node != NULL) {
+ listnode_t *save = node;
+ node = node->next;
+ kfree(save);
+ }
+ kfree(list);
+}
+
+void listnode_destroy(listnode_t *node)
+{
+ kfree(node);
+}
+
+char *list2str(list_t *list, const char *delim)
+{
+ char *ret = kmalloc(256);
+ memset(ret, 0, 256);
+ int len = 0, ret_len = 256;
+ while (list_size(list) > 0) {
+ char *temp = list_pop(list)->val;
+ int len_temp = strlen(temp);
+ if (len + len_temp + 1 + 1 > ret_len) {
+ ret_len = ret_len * 2;
+ ret = krealloc(ret, ret_len);
+ len = len + len_temp + 1;
+ }
+ strcat(ret, delim);
+ strcat(ret, temp);
+ }
+ return ret;
+}
+
+list_t *str_split(const char *str, const char *delim, uint32_t *numtokens)
+{
+ list_t *ret_list = list_create();
+ char *s = strdup(str);
+ char *token, *rest = s;
+ while ((token = strsep(&rest, delim)) != NULL) {
+ if (!strcmp(token, "."))
+ continue;
+ if (!strcmp(token, "..")) {
+ if (list_size(ret_list) > 0)
+ list_pop(ret_list);
+ continue;
+ }
+ list_push(ret_list, strdup(token));
+ if (numtokens)
+ (*numtokens)++;
+ }
+ kfree(s);
+ return ret_list;
+} \ No newline at end of file
diff --git a/src/kernel/lib/data/list.h b/src/kernel/lib/data/list.h
new file mode 100644
index 0000000..eeda9b3
--- /dev/null
+++ b/src/kernel/lib/data/list.h
@@ -0,0 +1,60 @@
+#ifndef MELVIX_LIST_H
+#define MELVIX_LIST_H
+
+#include <stdint.h>
+
+typedef struct listnode {
+ struct listnode *prev;
+ struct listnode *next;
+ void *val;
+} listnode_t;
+
+typedef struct list {
+ listnode_t *head;
+ listnode_t *tail;
+ uint32_t size;
+} list_t;
+
+#define foreach(t, list) for (listnode_t *t = list->head; t != NULL; t = t->next)
+
+list_t *list_create();
+
+uint32_t list_size(list_t *list);
+
+listnode_t *list_insert_front(list_t *list, void *val);
+
+void list_insert_back(list_t *list, void *val);
+
+void *list_remove_node(list_t *list, listnode_t *node);
+
+void *list_remove_front(list_t *list);
+
+void *list_remove_back(list_t *list);
+
+void list_push(list_t *list, void *val);
+
+listnode_t *list_pop(list_t *list);
+
+void list_enqueue(list_t *list, void *val);
+
+listnode_t *list_dequeue(list_t *list);
+
+void *list_peek_front(list_t *list);
+
+void *list_peek_back(list_t *list);
+
+void list_destroy(list_t *list);
+
+void listnode_destroy(listnode_t *node);
+
+int list_contain(list_t *list, void *val);
+
+listnode_t *list_get_node_by_index(list_t *list, int index);
+
+void *list_remove_by_index(list_t *list, int index);
+
+char *list2str(list_t *list, const char *delim);
+
+list_t *str_split(const char *str, const char *delim, uint32_t *numtokens);
+
+#endif \ No newline at end of file
diff --git a/src/kernel/lib/string.h b/src/kernel/lib/string.h
index 7375953..3a8dc07 100644
--- a/src/kernel/lib/string.h
+++ b/src/kernel/lib/string.h
@@ -15,8 +15,14 @@ void strcati(char *dest, const char *orig);
char strcmp(const char *a, const char *b);
+int strncmp(const char *s1, const char *s2, int c);
+
char *strdup(const char *orig);
void strinv(char *str);
+char *strstr(const char *in, const char *str);
+
+char *strsep(char **stringp, const char *delim);
+
#endif \ No newline at end of file
diff --git a/src/kernel/lib/string/strncmp.c b/src/kernel/lib/string/strncmp.c
new file mode 100644
index 0000000..4dbac59
--- /dev/null
+++ b/src/kernel/lib/string/strncmp.c
@@ -0,0 +1,16 @@
+int strncmp(const char *s1, const char *s2, int c)
+{
+ int result = 0;
+
+ while (c) {
+ result = *s1 - *s2++;
+
+ if ((result != 0) || (*s1++ == 0)) {
+ break;
+ }
+
+ c--;
+ }
+
+ return result;
+} \ No newline at end of file
diff --git a/src/kernel/lib/string/strsep.c b/src/kernel/lib/string/strsep.c
new file mode 100644
index 0000000..8f5201e
--- /dev/null
+++ b/src/kernel/lib/string/strsep.c
@@ -0,0 +1,25 @@
+#include <stddef.h>
+
+char *strsep(char **stringp, const char *delim)
+{
+ char *s;
+ const char *spanp;
+ int c, sc;
+ char *tok;
+ if ((s = *stringp) == NULL)
+ return (NULL);
+ for (tok = s;;) {
+ c = *s++;
+ spanp = delim;
+ do {
+ if ((sc = *spanp++) == c) {
+ if (c == 0)
+ s = NULL;
+ else
+ s[-1] = 0;
+ *stringp = s;
+ return (tok);
+ }
+ } while (sc != 0);
+ }
+} \ No newline at end of file
diff --git a/src/kernel/lib/string/strstr.c b/src/kernel/lib/string/strstr.c
new file mode 100644
index 0000000..d58b4d5
--- /dev/null
+++ b/src/kernel/lib/string/strstr.c
@@ -0,0 +1,25 @@
+#include <stdint.h>
+#include <kernel/lib/stdlib.h>
+
+char *strstr(const char *in, const char *str)
+{
+ char c;
+ uint32_t len;
+
+ c = *str++;
+ if (!c)
+ return (char *)in;
+
+ len = strlen(str);
+ do {
+ char sc;
+
+ do {
+ sc = *in++;
+ if (!sc)
+ return (char *)0;
+ } while (sc != c);
+ } while (strncmp(in, str, len) != 0);
+
+ return (char *)(in - 1);
+} \ No newline at end of file
diff --git a/src/kernel/net/rtl8139.c b/src/kernel/net/rtl8139.c
index 4da545e..c722632 100644
--- a/src/kernel/net/rtl8139.c
+++ b/src/kernel/net/rtl8139.c
@@ -42,7 +42,7 @@ int rtl8139_init(void)
if (command_reg & (1 << 2)) {
} else {
command_reg |= (1 << 2);
- pci_write_field(rtl_device_pci, PCI_COMMAND, 4, command_reg);
+ pci_write_field(rtl_device_pci, PCI_COMMAND, command_reg);
}
rtl_irq = pci_get_interrupt(rtl_device_pci);
@@ -100,4 +100,4 @@ void rtl8139_install()
if (rtl8139_init() == 0)
info("Installed rtl8139 network driver");
-} \ No newline at end of file
+}
diff --git a/src/kernel/pci/pci.c b/src/kernel/pci/pci.c
index 435752d..abccb00 100644
--- a/src/kernel/pci/pci.c
+++ b/src/kernel/pci/pci.c
@@ -3,7 +3,7 @@
#include <kernel/io/io.h>
#include <kernel/lib/lib.h>
-void pci_write_field(uint32_t device, int field, int size, uint32_t value)
+void pci_write_field(uint32_t device, int field, uint32_t value)
{
outl(PCI_ADDRESS_PORT, pci_get_addr(device, field));
outl(PCI_VALUE_PORT, value);
@@ -107,7 +107,7 @@ void pci_remap()
}
uint32_t out = 0;
memcpy(&out, &pci_remaps, 4);
- pci_write_field(pci_isa, 0x60, 4, out);
+ pci_write_field(pci_isa, 0x60, out);
}
}
@@ -123,17 +123,17 @@ int pci_get_interrupt(uint32_t device)
if (pci_remaps[pirq] >= 0x80) {
if (int_line == 0xFF) {
int_line = 10;
- pci_write_field(device, PCI_INTERRUPT_LINE, 1, (uint32_t)int_line);
+ pci_write_field(device, PCI_INTERRUPT_LINE, (uint32_t)int_line);
}
pci_remaps[pirq] = (uint8_t)int_line;
uint32_t out = 0;
memcpy(&out, &pci_remaps, 4);
- pci_write_field(pci_isa, 0x60, 4, out);
+ pci_write_field(pci_isa, 0x60, out);
return int_line;
}
- pci_write_field(device, PCI_INTERRUPT_LINE, 1, pci_remaps[pirq]);
+ pci_write_field(device, PCI_INTERRUPT_LINE, pci_remaps[pirq]);
return pci_remaps[pirq];
} else {
return (int)pci_read_field(device, PCI_INTERRUPT_LINE, 1);
}
-} \ No newline at end of file
+}
diff --git a/src/kernel/pci/pci.h b/src/kernel/pci/pci.h
index 6c14dfd..fc4bb5d 100644
--- a/src/kernel/pci/pci.h
+++ b/src/kernel/pci/pci.h
@@ -87,7 +87,7 @@ static inline uint32_t pci_box_device(int bus, int slot, int func)
uint32_t pci_read_field(uint32_t device, int field, int size);
-void pci_write_field(uint32_t device, int field, int size, uint32_t value);
+void pci_write_field(uint32_t device, int field, uint32_t value);
uint16_t pci_find_type(uint32_t dev);
@@ -105,4 +105,4 @@ void pci_remap();
int pci_get_interrupt(uint32_t device);
-#endif \ No newline at end of file
+#endif
diff --git a/src/kernel/system.c b/src/kernel/system.c
index c58949e..a8544e6 100644
--- a/src/kernel/system.c
+++ b/src/kernel/system.c
@@ -90,6 +90,14 @@ void warn(const char *fmt, ...)
writec('\n');
}
+void log(const char *fmt, ...)
+{
+ va_list args;
+ va_start(args, fmt);
+ serial_printf(fmt, args);
+ va_end(args);
+}
+
const char *random_message[10] = { "Uh... Did I do that?",
"Layer 8 problem!",
"Oops.",
diff --git a/src/kernel/system.h b/src/kernel/system.h
index 90535f6..29097bd 100644
--- a/src/kernel/system.h
+++ b/src/kernel/system.h
@@ -76,6 +76,12 @@ void info(const char *fmt, ...);
void warn(const char *fmt, ...);
/**
+ * Log into serial console
+ * @param msg The log string
+ */
+void log(const char *fmt, ...);
+
+/**
* Halt the entire system and display a message
* TODO: Add line number and file name
* @param msg The error cause/reason