From 2d55599dd89ba0f40475c71c2c203d1790af5cca Mon Sep 17 00:00:00 2001 From: Ebrahim Aleem Date: Sun, 8 Mar 2026 11:09:30 -0700 Subject: [PATCH 01/12] switch to ext2 --- Makefile | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Makefile b/Makefile index 90b48e8..ef95510 100644 --- a/Makefile +++ b/Makefile @@ -127,7 +127,7 @@ $(OBJ_DIR)/stub.img: | $(OBJ_DIR)/ parted -s $@ mklabel gpt parted -s $@ mkpart ESP fat32 4MiB 52MiB parted -s $@ set 1 esp on - parted -s $@ mkpart rootfs ext4 52MiB 100% + parted -s $@ mkpart rootfs ext2 52MiB 100% $(OBJ_DIR)/stub-esp.dummy: $(OBJ_DIR)/stub.img $(OBJ_DIR)/modulos $(OBJ_DIR)/esp.img mcopy -o -i $(OBJ_DIR)/esp.img $(OBJ_DIR)/modulos ::/ @@ -137,7 +137,7 @@ $(OBJ_DIR)/stub-esp.dummy: $(OBJ_DIR)/stub.img $(OBJ_DIR)/modulos $(OBJ_DIR)/esp # 54525952 is for 52MiB offset (512 * 1024 * 1024) # 1034240 is for 52MiB initial (4MiB align + 48MiB ESP) and 4MiB tail for gpt $(OBJ_DIR)/stub-fs.dummy: $(OBJ_DIR)/stub.img copy-doc - yes | mke2fs -L rootfs -E offset=54525952 -d $(OBJ_DIR)/rootfs/ -t ext4 \ + yes | mke2fs -L rootfs -E offset=54525952 -d $(OBJ_DIR)/rootfs/ -t ext2 \ -b 4096 $< 1034240 touch $@ From 3b02c261e33e0e04e0b76754c30c63e4722dc71e Mon Sep 17 00:00:00 2001 From: Ebrahim Aleem Date: Sun, 8 Mar 2026 13:48:03 -0700 Subject: [PATCH 02/12] find ext2 superblock --- Makefile | 3 + drivers/Makefile | 8 ++ drivers/disk/disk.c | 14 ++++ drivers/ext2/ext2.c | 149 ++++++++++++++++++++++++++++++++++++ drivers/gpt/gpt.c | 132 ++++++++++++++++++++++++++++++++ drivers/include/disk/disk.h | 4 + drivers/include/ext2/ext2.h | 27 +++++++ drivers/include/gpt/gpt.h | 27 +++++++ kernel/include/lib/hash.h | 2 + kernel/lib/hash.c | 21 +++++ test/lib/test.c | 5 ++ 11 files changed, 392 insertions(+) create mode 100644 drivers/ext2/ext2.c create mode 100644 drivers/gpt/gpt.c create mode 100644 drivers/include/ext2/ext2.h create mode 100644 drivers/include/gpt/gpt.h diff --git a/Makefile b/Makefile index ef95510..06a1ad0 100644 --- a/Makefile +++ b/Makefile @@ -42,6 +42,9 @@ export BUILD_DRIVERS_HPET = 1 export BUILD_DRIVERS_AHCI = 1 +export BUILD_DRIVERS_GPT = 1 +export BUILD_DRIVERS_EXT2 = 1 + # End of options ifdef BUILD_DRIVERS_AHCI diff --git a/drivers/Makefile b/drivers/Makefile index d39735e..8b886e4 100644 --- a/drivers/Makefile +++ b/drivers/Makefile @@ -43,6 +43,14 @@ ifdef BUILD_DRIVERS_SATA $(call add_directory,sata,SATA) endif +ifdef BUILD_DRIVERS_GPT +$(call add_directory,gpt,GPT) +endif + +ifdef BUILD_DRIVERS_EXT2 +$(call add_directory,ext2,EXT2) +endif + include $(SRC_TREE_ROOT)/scripts/Makefile.kcflags include $(SRC_TREE_ROOT)/scripts/Makefile.targets diff --git a/drivers/disk/disk.c b/drivers/disk/disk.c index b6dacbe..b438e65 100644 --- a/drivers/disk/disk.c +++ b/drivers/disk/disk.c @@ -20,6 +20,10 @@ #include +#ifdef GPT +#include +#endif /* GPT */ + #include #include @@ -58,6 +62,12 @@ struct disk_t* disk_add(void* cntx, disk_lba_read_t read, disk_lba_write_t write disk_list = disk; lock_release(&disk_lock); +#ifdef GPT + if (gpt_find_partitions(disk)) { + return disk; + } +#endif /* GPT */ + return disk; } @@ -86,3 +96,7 @@ enum disk_error_t disk_write(struct disk_t* disk, void* buffer, uint64_t lba, ui enum disk_error_t disk_flush(struct disk_t* disk) { return disk->flush(disk->cntx); } + +uint64_t disk_get_id(struct disk_t* disk) { + return disk->id; +} diff --git a/drivers/ext2/ext2.c b/drivers/ext2/ext2.c new file mode 100644 index 0000000..203cd8b --- /dev/null +++ b/drivers/ext2/ext2.c @@ -0,0 +1,149 @@ +/* ext2.c - Second Extended File System driver implementation */ +/* Copyright (C) 2026 Ebrahim Aleem +* +* This program is free software: you can redistribute it and/or modify +* it under the terms of the GNU General Public License as published by +* the Free Software Foundation, either version 3 of the License, or +* (at your option) any later version. +* +* This program is distributed in the hope that it will be useful, +* but WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +* GNU General Public License for more details. +* +* You should have received a copy of the GNU General Public License +* along with this program. If not, see +*/ + +#include + +#include + +#include + +#include +#include + +#define SUPERBLOCK_LBA 2 +#define SUPERBLOCK_SECTORS 2 + +#define EXT2_SUPER_MAGIC 0xEF53 + +struct ext2_superblock_t { + uint32_t s_inodes_count; + uint32_t s_blocks_count; + uint32_t s_r_blocks_count; + uint32_t s_free_blocks_count; + uint32_t s_free_inodes_count; + uint32_t s_first_data_block; + uint32_t s_log_block_size; + uint32_t s_log_frag_size; + uint32_t s_blocks_per_group; + uint32_t s_frags_per_group; + uint32_t s_inodes_per_group; + uint32_t s_mtime; + uint32_t s_wtime; + uint16_t s_mnt_count; + uint16_t s_max_mnt_count; + uint16_t s_magic; + uint16_t s_state; + uint16_t s_errors; + uint16_t s_minor_rev_level; + uint32_t s_lastcheck; + uint32_t s_checkinterval; + uint32_t s_creator_os; + uint32_t s_rev_level; + uint16_t s_def_resuid; + uint16_t s_def_resgid; + + /* ext2_dynamic_rev */ + uint32_t s_first_ino; + uint16_t s_inode_size; + uint16_t s_block_group_nr; + uint32_t s_feature_compat; + uint32_t s_feature_incompat; + uint32_t s_feature_ro_compat; + uint8_t s_uuid[16]; + uint8_t s_volume_name[16]; + uint8_t s_last_mounted[64]; + uint32_t s_algo_bitmap; + + /* perf. hints */ + uint8_t s_prealloc_blocks; + uint8_t s_prealloc_dir_blocks; + uint16_t align; + + /* journaling */ + uint8_t s_journal_uuid[16]; + uint32_t s_hournal_inum; + uint32_t s_journal_dev; + uint32_t s_last_orphan; + + /* dir. indexing */ + uint32_t s_hash_seed[4]; + uint8_t s_def_hash_version; + uint8_t resv0[3]; + + /* other */ + uint32_t s_default_mount_options; + uint32_t s_first_meta_bg; + uint8_t resv1[760]; +} __attribute__((packed)); + +struct ext2_bg_desc_t { + uint32_t bg_block_bitmap; + uint32_t bg_inode_bitmap; + uint32_t bg_inode_table; + uint16_t bg_free_blocks_count; + uint16_t bg_free_inodes_count; + uint16_t bg_used_dirs_count; + uint16_t bg_pad; + uint8_t bg_reserved[12]; +} __attribute__((packed)); + +struct ext2_inode_t { + uint16_t i_mode; + uint16_t i_uid; + uint32_t i_size; + uint32_t i_atime; + uint32_t i_ctime; + uint32_t i_mtime; + uint32_t i_dtime; + uint16_t i_gid; + uint16_t i_links_count; + uint32_t i_blocks; + uint32_t i_flags; + uint32_t i_osd1; + uint32_t i_block[15]; + uint32_t i_generation; + uint32_t i_file_acl; + uint32_t i_dir_acl; + uint32_t i_faddr; + uint8_t i_osd2[12]; +} __attribute__((packed)); + +_Static_assert(sizeof(struct ext2_superblock_t) == 1024, "Bad ext2 superblock size"); +_Static_assert(sizeof(struct ext2_bg_desc_t) == 32, "Bad ext2 bg descriptor size"); +_Static_assert(sizeof(struct ext2_inode_t) == 128, "Bad exte2 inode size"); + +uint8_t ext2_attempt_init(struct disk_t* disk, uint64_t start_lba, uint64_t end_lba) { + struct ext2_superblock_t* superblock = kmalloc(sizeof(struct ext2_superblock_t)); + + (void)end_lba; + + if (disk_read(disk, superblock, start_lba + SUPERBLOCK_LBA, SUPERBLOCK_SECTORS) != DISK_OK) { + logging_log_error("Failed to read disk %lu @ %u/%u", disk_get_id(disk), SUPERBLOCK_LBA, SUPERBLOCK_SECTORS); + kfree(superblock); + return 0; + } + + if (superblock->s_magic != EXT2_SUPER_MAGIC) { + kfree(superblock); + return 0; + } + + logging_log_info("Found ext2 filesystem %16.16s", superblock->s_volume_name); + + kfree(superblock); + return 1; +} diff --git a/drivers/gpt/gpt.c b/drivers/gpt/gpt.c new file mode 100644 index 0000000..0687714 --- /dev/null +++ b/drivers/gpt/gpt.c @@ -0,0 +1,132 @@ +/* gpt.c - GUID partition table driver */ +/* Copyright (C) 2026 Ebrahim Aleem +* +* This program is free software: you can redistribute it and/or modify +* it under the terms of the GNU General Public License as published by +* the Free Software Foundation, either version 3 of the License, or +* (at your option) any later version. +* +* This program is distributed in the hope that it will be useful, +* but WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +* GNU General Public License for more details. +* +* You should have received a copy of the GNU General Public License +* along with this program. If not, see +*/ + +#include + +#include + +#include + +#ifdef EXT2 +#include +#endif /* EXT2 */ + +#include +#include + +#include +#include + +#define GPT_LBA 1 +#define GPT_SIG "EFI PART" + +struct gpt_partition_table_t { + uint8_t sig[8]; + uint32_t rev; + uint32_t header_size; + uint32_t crc32; + uint32_t resv0; + uint64_t curr_lba; + uint64_t alt_lba; + uint64_t first_block; + uint64_t last_block; + uint8_t guid[16]; + uint64_t partition_array_lba; + uint32_t partition_array_entry_count; + uint32_t partition_array_entry_size; + uint32_t partition_array_crc32; +} __attribute__((packed)); + +struct gpt_partition_entry_t { + uint8_t part_type[16]; + uint8_t guid[16]; + uint64_t start_lba; + uint64_t end_lba; + uint64_t attr; + uint8_t name[]; +} __attribute__((packed)); + +uint8_t gpt_find_partitions(struct disk_t* disk) { + struct gpt_partition_table_t* gpt = kmalloc(SECTOR_SIZE); + uint32_t crc; + uint64_t partition_array_size; + void* partition_array_base; + struct gpt_partition_entry_t* entry; + uint8_t j; + uint32_t i; + + if (disk_read(disk, gpt, GPT_LBA, 1) != DISK_OK) { + logging_log_error("Failed to read gpt lba of disk %lu", disk_get_id(disk)); + kfree(gpt); + return 0; + } + + if (kmemcmp(gpt->sig, GPT_SIG, sizeof(gpt->sig))) { + kfree(gpt); + return 0; + } + + logging_log_debug("Found GPT on disk %lu", disk_get_id(disk)); + + crc = gpt->crc32; + gpt->crc32 = 0; + + if (crc32_ansi(gpt, sizeof(*gpt)) != crc) { + logging_log_error("Bad checksum for GPT. Skipping disk"); + kfree(gpt); + return 0; + } + + partition_array_size = gpt->partition_array_entry_count * gpt->partition_array_entry_size; + partition_array_base = kmalloc((partition_array_size / SECTOR_SIZE) + 1); + + if (disk_read(disk, partition_array_base, gpt->partition_array_lba, + (uint16_t)(partition_array_size / SECTOR_SIZE) + 1) != DISK_OK) { + logging_log_error("Failed to read GPT partition array. Skipping disk"); + kfree(gpt); + kfree(partition_array_base); + return 0; + } + + if(crc32_ansi((void*)partition_array_base, partition_array_size) != gpt->partition_array_crc32) { + logging_log_error("Bad checksum for GPT partition array. Skipping disk"); + kfree(gpt); + kfree(partition_array_base); + return 0; + } + + for (i = 0; i < gpt->partition_array_entry_count; i++) { + entry = (struct gpt_partition_entry_t*)((uint64_t)partition_array_base + i * gpt->partition_array_entry_size); + for (j = 0; j < 16; j++) { + if (entry->part_type[j]) { + logging_log_debug("Found GPT partition on %lu @ %u", disk_get_id(disk), i); + +#ifdef EXT2 + if (ext2_attempt_init(disk, entry->start_lba, entry->end_lba)) { + break; + } +#endif /* EXT2 */ + break; + } + } + } + + kfree(gpt); + kfree(partition_array_base); + + return 0; +} diff --git a/drivers/include/disk/disk.h b/drivers/include/disk/disk.h index ef06dae..e237fc4 100644 --- a/drivers/include/disk/disk.h +++ b/drivers/include/disk/disk.h @@ -23,6 +23,8 @@ #define DISK_ID_FIRST 0 +#define SECTOR_SIZE 512 + enum disk_error_t { DISK_OK, DISK_ERROR @@ -44,4 +46,6 @@ extern enum disk_error_t disk_read(struct disk_t* disk, void* pbuffer, uint64_t extern enum disk_error_t disk_write(struct disk_t* disk, void* pbuffer, uint64_t lba, uint16_t count); extern enum disk_error_t disk_flush(struct disk_t* disk); +extern uint64_t disk_get_id(struct disk_t* disk); + #endif /* DRIVERS_DISK_DISK_H */ diff --git a/drivers/include/ext2/ext2.h b/drivers/include/ext2/ext2.h new file mode 100644 index 0000000..99d4a94 --- /dev/null +++ b/drivers/include/ext2/ext2.h @@ -0,0 +1,27 @@ +/* ext2.c - Second Extended File System driver interface */ +/* Copyright (C) 2026 Ebrahim Aleem +* +* This program is free software: you can redistribute it and/or modify +* it under the terms of the GNU General Public License as published by +* the Free Software Foundation, either version 3 of the License, or +* (at your option) any later version. +* +* This program is distributed in the hope that it will be useful, +* but WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +* GNU General Public License for more details. +* +* You should have received a copy of the GNU General Public License +* along with this program. If not, see +*/ + +#ifndef DRIVERS_EXT2_EXT2_H +#define DRIVERS_EXT2_EXT2_H + +#include + +#include + +extern uint8_t ext2_attempt_init(struct disk_t* disk, uint64_t start_lba, uint64_t end_lba); + +#endif /* DRIVERS_EXT2_EXT2_H */ diff --git a/drivers/include/gpt/gpt.h b/drivers/include/gpt/gpt.h new file mode 100644 index 0000000..8f27427 --- /dev/null +++ b/drivers/include/gpt/gpt.h @@ -0,0 +1,27 @@ +/* gpt.h - GUID partition table driver interface */ +/* Copyright (C) 2026 Ebrahim Aleem +* +* This program is free software: you can redistribute it and/or modify +* it under the terms of the GNU General Public License as published by +* the Free Software Foundation, either version 3 of the License, or +* (at your option) any later version. +* +* This program is distributed in the hope that it will be useful, +* but WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +* GNU General Public License for more details. +* +* You should have received a copy of the GNU General Public License +* along with this program. If not, see +*/ + +#ifndef DRIVERS_GPT_GPT_H +#define DRIVERS_GPT_GPT_H + +#include + +#include + +extern uint8_t gpt_find_partitions(struct disk_t* disk); + +#endif /* DRIVERS_GPT_GPT_H */ diff --git a/kernel/include/lib/hash.h b/kernel/include/lib/hash.h index e63b734..763a90d 100644 --- a/kernel/include/lib/hash.h +++ b/kernel/include/lib/hash.h @@ -23,4 +23,6 @@ extern uint8_t hash_byte_sum(const void* ptr, size_t c); +extern uint32_t crc32_ansi(const void* data, size_t length); + #endif /* KERNEL_LIB_HASH_H */ diff --git a/kernel/lib/hash.c b/kernel/lib/hash.c index bddb886..501dcf0 100644 --- a/kernel/lib/hash.c +++ b/kernel/lib/hash.c @@ -29,3 +29,24 @@ uint8_t hash_byte_sum(const void* ptr, size_t c) { return sum; } + +uint32_t crc32_ansi(const void* data, size_t length) { + uint32_t crc = 0xFFFFFFFF; + const uint8_t *p = (const uint8_t*)data; + uint8_t i; + + while (length--) { + crc ^= *p++; + + for (i = 0; i < 8; i++) { + if (crc & 1) { + crc = (crc >> 1) ^ 0xEDB88320; + } + else { + crc >>= 1; + } + } + } + + return crc ^ 0xFFFFFFFF; +} diff --git a/test/lib/test.c b/test/lib/test.c index 7c36b46..88ae2ca 100644 --- a/test/lib/test.c +++ b/test/lib/test.c @@ -72,3 +72,8 @@ TEST("hash_byte_sum") { ASSERT_TRUE(hash_byte_sum((uint8_t*)"\0\1\2\3\0\0\1\2", 8) == 9, "fails basic sum"); ASSERT_TRUE(hash_byte_sum((uint8_t*)"\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF", 8) == 248, "fails overflow"); } + +TEST("crc32_ansi") { + ASSERT_TRUE(crc32_ansi("Hello, World!", 13) == 0xec4ac3d0, "fails expected checksum"); + ASSERT_FALSE(crc32_ansi("Hello, World!", 12) == 0xec4ac3d0, "fails unexpected checksum"); +} From 58c3e1f79912c67dae088a3063795a9adf9c43ef Mon Sep 17 00:00:00 2001 From: Ebrahim Aleem Date: Mon, 9 Mar 2026 11:36:23 -0700 Subject: [PATCH 03/12] minimal root directory stat --- drivers/ahci/ahci.c | 17 ++-- drivers/apic/apic_init.c | 4 + drivers/apic/ipi.c | 124 +++++++++++++++++++++++++++-- drivers/apic/isr.S | 34 ++++++++ drivers/ext2/ext2.c | 118 ++++++++++++++++++++++++++- drivers/gpt/gpt.c | 2 +- drivers/include/apic/ipi.h | 8 ++ drivers/include/apic/isr.h | 2 + kernel/core/cpu_instr.S | 5 ++ kernel/core/fs.c | 136 ++++++++++++++++++++++++++++++++ kernel/core/kentry.c | 5 ++ kernel/core/paging.c | 5 ++ kernel/core/process.c | 2 - kernel/include/core/cpu_instr.h | 2 + kernel/include/core/fs.h | 53 +++++++++++++ 15 files changed, 498 insertions(+), 19 deletions(-) create mode 100644 kernel/core/fs.c create mode 100644 kernel/include/core/fs.h diff --git a/drivers/ahci/ahci.c b/drivers/ahci/ahci.c index 153667f..bcea8c2 100644 --- a/drivers/ahci/ahci.c +++ b/drivers/ahci/ahci.c @@ -77,8 +77,8 @@ #define SSTS_DET_MASK 0x000Fu #define SSTS_DET_EST 0x0003u -#define CL_SIZE 256 -#define FIS_SIZE 1024 +#define CL_SIZE 1024 +#define FIS_SIZE 256 #define SLOT_NO_SLOT 0xFF @@ -174,11 +174,12 @@ static uint8_t find_slot(struct ahci_t* ahci, uint32_t port) { read = hba_read(ahci, PXCI_OFF(port)); for (slot = 0; slot < ahci->num_com_slots; slot++) { - if (!(ahci->used_com && (1u << slot)) && !(read && (1u << slot))) { + if (!(ahci->used_com & (1u << slot)) && !(read & (1u << slot))) { return slot; } } + //TODO: assert valid slot before using return SLOT_NO_SLOT; } @@ -245,7 +246,7 @@ static enum disk_error_t ahci_read_lba(void* cntx, void* buffer, uint64_t lba, u port_clear_errors(ahci, port); - kmemset(&ahci->ports[port]->recv_fis, 0, sizeof(struct ahci_recv_fis_t)); + kmemset(ahci->ports[port]->recv_fis, 0, sizeof(struct ahci_recv_fis_t)); ahci->ports[port]->com_list[slot].flg = 5; ahci->ports[port]->com_list[slot].prdtl = 1; @@ -371,7 +372,7 @@ static enum disk_error_t ahci_write_lba(void* cntx, void* buffer, uint64_t lba, port_clear_errors(ahci, port); - kmemset(&ahci->ports[port]->recv_fis, 0, sizeof(struct ahci_recv_fis_t)); + kmemset(ahci->ports[port]->recv_fis, 0, sizeof(struct ahci_recv_fis_t)); ahci->ports[port]->com_list[slot].flg = 5 | SATA_FIS_CMD_W; ahci->ports[port]->com_list[slot].prdtl = 1; @@ -453,7 +454,7 @@ static enum disk_error_t ahci_flush_cache(void* cntx) { port_clear_errors(ahci, port); - kmemset(&ahci->ports[port]->recv_fis, 0, sizeof(struct ahci_recv_fis_t)); + kmemset(ahci->ports[port]->recv_fis, 0, sizeof(struct ahci_recv_fis_t)); ahci->ports[port]->com_list[slot].flg = 5; ahci->ports[port]->com_list[slot].prdtl = 0; @@ -534,7 +535,7 @@ static void port_identify(struct ahci_t* ahci, uint32_t port) { port_clear_errors(ahci, port); - kmemset(&ahci->ports[port]->recv_fis, 0, sizeof(struct ahci_recv_fis_t)); + kmemset(ahci->ports[port]->recv_fis, 0, sizeof(struct ahci_recv_fis_t)); ahci->ports[port]->com_list[slot].flg = 5; ahci->ports[port]->com_list[slot].prdtl = 1; @@ -565,7 +566,7 @@ static void port_identify(struct ahci_t* ahci, uint32_t port) { lba48 = *(uint64_t*)&identity[100]; - logging_log_info("Found ATA drive %s 0x%lx", &model[0], lba48); + logging_log_debug("Found ATA drive %s 0x%lx", &model[0], lba48); paging_unmap((uint64_t)identity, PAGE_4K); diff --git a/drivers/apic/apic_init.c b/drivers/apic/apic_init.c index b0f4e5f..c31106b 100644 --- a/drivers/apic/apic_init.c +++ b/drivers/apic/apic_init.c @@ -116,6 +116,8 @@ void apic_init(void) { idt_install(timer_vector, (uint64_t)apic_isr_timer, GDT_CODE_SEL, IST_SCHED, IDT_GATE_INT, 0); idt_install(error_vector, (uint64_t)apic_isr_error, GDT_CODE_SEL, 0, IDT_GATE_INT, 0); + apic_init_shootdowns(num_apic); + apic_init_ap(); // init stacks @@ -242,6 +244,8 @@ void apic_init_ap(void) { apic_write_lve(APIC_REG_ERE, error_vector, APIC_LVT_MT_FIXED | APIC_LVT_TRG_EDGE, 0); + apic_register_barrier(apic_id); + // enable apic apic_write_reg(APIC_REG_ESR, 0); apic_write_reg(APIC_REG_SPR, PIC_SPURIOUS_VEC | APIC_ASE); // pic and apic spurious both only iret, so reuse diff --git a/drivers/apic/ipi.c b/drivers/apic/ipi.c index cb7ee82..aecb4f7 100644 --- a/drivers/apic/ipi.c +++ b/drivers/apic/ipi.c @@ -15,19 +15,64 @@ * along with this program. If not, see */ +#include + #include #include +#include #include +#include +#include +#include +#include + +#include -#define ICR_LEVEL 0x8000 -#define ICR_ASSERT 0x4000 -#define ICR_DS 0x1000 -#define ICR_LO_INIT 0x0500 -#define ICR_LO_SIPI (0x0600 | AP_ENTRY_PAGE) +#define ICR_LEVEL 0x8000u +#define ICR_ASSERT 0x4000u +#define ICR_DS 0x1000u +#define ICR_LO_INIT 0x0500u +#define ICR_LO_SIPI (0x0600u | AP_ENTRY_PAGE) #define ICR_PID_SHFT 24 +static uint8_t tlb_shootdown_lock; +static uint8_t* registered_barrier; +static volatile uint8_t* tlb_shootdown_barrier = 0; +static uint8_t tlb_shootdown_vector; +static uint8_t barrier_len; +static volatile uint64_t tlb_shootdown_addr; + +struct shootdown_node_t { + struct shootdown_node_t* next; + uint8_t apic_id; +}; + +static struct shootdown_node_t* shootdown_list; + +static uint8_t ipi_lock; + +void apic_ipi_init(void) { + lock_init(&ipi_lock); +} + +void apic_init_shootdowns(uint8_t num_apic) { + lock_init(&tlb_shootdown_lock); + + registered_barrier = kmalloc(sizeof(uint8_t) * num_apic); + + kmemset(registered_barrier, 0, sizeof(uint8_t) * num_apic); + shootdown_list = 0; + + tlb_shootdown_barrier = kmalloc(sizeof(uint8_t) * num_apic); + barrier_len = num_apic; + + tlb_shootdown_vector = idt_get_vector(); + + idt_install(tlb_shootdown_vector, (uint64_t)apic_isr_tlb_shootdown, GDT_CODE_SEL, 0, IDT_GATE_INT, 0); +} + void apic_wait_for_ipi(void) { while (apic_read_reg(APIC_REG_ICL) & ICR_DS) { cpu_pause(); @@ -35,16 +80,85 @@ void apic_wait_for_ipi(void) { } void apic_send_ipi_init_set(uint8_t apic_id) { + lock_acquire(&ipi_lock); + apic_wait_for_ipi(); apic_write_reg(APIC_REG_ICH, (uint32_t)apic_id << ICR_PID_SHFT); apic_write_reg(APIC_REG_ICL, ICR_LO_INIT | ICR_LEVEL | ICR_ASSERT ); + lock_release(&ipi_lock); } void apic_send_ipi_init_clear(uint8_t apic_id) { + lock_acquire(&ipi_lock); + apic_wait_for_ipi(); apic_write_reg(APIC_REG_ICH, (uint32_t)apic_id << ICR_PID_SHFT); apic_write_reg(APIC_REG_ICL, ICR_LO_INIT | ICR_LEVEL); + lock_release(&ipi_lock); } void apic_send_ipi_sipi(uint8_t apic_id) { + lock_acquire(&ipi_lock); + apic_wait_for_ipi(); apic_write_reg(APIC_REG_ICH, (uint32_t)apic_id << ICR_PID_SHFT); apic_write_reg(APIC_REG_ICL, ICR_LO_SIPI); + lock_release(&ipi_lock); +} + +static inline uint8_t check_barrier(volatile uint8_t* barrier) { + uint8_t i; + for (i = 0; i < barrier_len; i++) { + if (barrier[i]) { + return 1; + } + } + + return 0; +} + +void apic_tlb_shootdown(uint64_t vaddr) { + struct shootdown_node_t* node; + if (!tlb_shootdown_barrier) { + return; + } + + lock_acquire(&tlb_shootdown_lock); + + uint8_t i; + for (i = 0; i < barrier_len; i++) { + tlb_shootdown_barrier[i] = registered_barrier[i]; + } + + tlb_shootdown_addr = vaddr; + + + for (node = shootdown_list; node; node = node->next) { + lock_acquire(&ipi_lock); + apic_wait_for_ipi(); + apic_wait_for_ipi(); + apic_write_reg(APIC_REG_ICH, (uint32_t)node->apic_id << ICR_PID_SHFT); + apic_write_reg(APIC_REG_ICL, tlb_shootdown_vector | ICR_ASSERT); + lock_release(&ipi_lock); + } + + while (check_barrier(tlb_shootdown_barrier)) cpu_pause(); + + lock_release(&tlb_shootdown_lock); +} + +void apic_tlb_shootdown_dispatch(void) { + cpu_invlpg(tlb_shootdown_addr); + + tlb_shootdown_barrier[proc_data_get()->arb_id] = 0; +} + +void apic_register_barrier(uint8_t apic_id) { + struct shootdown_node_t* node = kmalloc(sizeof(struct shootdown_node_t)); + node->apic_id = apic_id; + + lock_acquire(&tlb_shootdown_lock); + + node->next = shootdown_list; + shootdown_list = node; + registered_barrier[proc_data_get()->arb_id] = 1; + + lock_release(&tlb_shootdown_lock); } diff --git a/drivers/apic/isr.S b/drivers/apic/isr.S index f13430e..ea239b5 100644 --- a/drivers/apic/isr.S +++ b/drivers/apic/isr.S @@ -35,6 +35,40 @@ pushq %rbp movq %rsp, %rdi jmp process_preempt_entry +.globl apic_isr_tlb_shootdown +apic_isr_tlb_shootdown: +pushq %rax +pushq %rcx +pushq %rdx +pushq %rsi +pushq %rdi +pushq %r8 +pushq %r9 +pushq %r10 +pushq %r11 +pushq %rbp + +movq %rsp, %rbp +movq %rsp, %rax +andq $0xF, %rax +jz .aligned_tlb +subq %rax, %rsp +.aligned_tlb: +call apic_tlb_shootdown_dispatch +movq %rbp, %rsp + +popq %rbp +popq %r11 +popq %r10 +popq %r9 +popq %r8 +popq %rdi +popq %rsi +popq %rdx +popq %rcx +popq %rax +iretq + .globl apic_isr_error apic_isr_error: pushq %rax diff --git a/drivers/ext2/ext2.c b/drivers/ext2/ext2.c index 203cd8b..90d1199 100644 --- a/drivers/ext2/ext2.c +++ b/drivers/ext2/ext2.c @@ -23,12 +23,22 @@ #include #include +#include +#include + +#include +#include #define SUPERBLOCK_LBA 2 #define SUPERBLOCK_SECTORS 2 #define EXT2_SUPER_MAGIC 0xEF53 +#define ROOT_DIR_INODE 2 + +#define EXT2_S_IFREG 0x8000 +#define EXT2_S_IFDIR 0x4000 + struct ext2_superblock_t { uint32_t s_inodes_count; uint32_t s_blocks_count; @@ -126,10 +136,77 @@ _Static_assert(sizeof(struct ext2_superblock_t) == 1024, "Bad ext2 superblock si _Static_assert(sizeof(struct ext2_bg_desc_t) == 32, "Bad ext2 bg descriptor size"); _Static_assert(sizeof(struct ext2_inode_t) == 128, "Bad exte2 inode size"); +struct ext2_t { + uint64_t start_lba; + uint64_t end_lba; + struct ext2_superblock_t* superblock; + struct ext2_bg_desc_t* bgdt; + struct disk_t* disk; + uint8_t lock; +}; + +struct ext2_inode_handle_t { + struct ext2_t* ext2; + uint64_t inode_index; +}; + +static uint8_t label_rootfs[16] = {'r', 'o', 'o', 't', 'f', 's', 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; + +static uint8_t get_inode(const struct ext2_inode_handle_t* inode_handle, struct ext2_inode_t* inode) { + const struct ext2_superblock_t* superblock = inode_handle->ext2->superblock; + const struct ext2_bg_desc_t* bgdt = inode_handle->ext2->bgdt; + + const uint64_t block_size = 1024u << superblock->s_log_block_size; + const uint64_t block_group = (inode_handle->inode_index - 1) / superblock->s_inodes_per_group; + const uint64_t lcl_inode_idx = (inode_handle->inode_index - 1) % superblock->s_inodes_per_group; + const uint64_t lcl_inode_off = lcl_inode_idx * superblock->s_inode_size; + const uint64_t lcl_inode_blk = lcl_inode_off / block_size; + const uint64_t inode_off = lcl_inode_off % block_size; + + const uint64_t inode_table_block = bgdt[block_group].bg_inode_table + lcl_inode_blk; + void* buffer = kmalloc(block_size); + + if (disk_read( + inode_handle->ext2->disk, + buffer, + inode_handle->ext2->start_lba + inode_table_block * block_size / SECTOR_SIZE, + (uint16_t)(block_size / SECTOR_SIZE)) != DISK_OK) { + logging_log_error("Failed to read inode %lu", inode_handle->inode_index); + kfree(buffer); + return 1; + } + + *inode = *(struct ext2_inode_t*)((uint64_t)buffer + inode_off); + kfree(buffer); + return 0; +} + +static enum fs_error_t ext2_stat(void* handle, struct fs_file_info_t* info) { + struct ext2_inode_t inode; + if (get_inode(handle, &inode)) { + return FS_ERROR_FAIL; + } + + info->size = (uint64_t)inode.i_size | ((uint64_t)inode.i_dir_acl << 32); + + if (inode.i_mode & EXT2_S_IFREG) { + info->type = FS_FILE; + } + else if (inode.i_mode & EXT2_S_IFDIR) { + info->type = FS_DIR; + } + else { + return FS_ERROR_FAIL; + } + + return FS_ERROR_OK; +} + uint8_t ext2_attempt_init(struct disk_t* disk, uint64_t start_lba, uint64_t end_lba) { struct ext2_superblock_t* superblock = kmalloc(sizeof(struct ext2_superblock_t)); - - (void)end_lba; + struct ext2_inode_handle_t* root_handle; + struct ext2_bg_desc_t* bgdt; + uint64_t bgdt_size, adj, bgdt_start_lba; if (disk_read(disk, superblock, start_lba + SUPERBLOCK_LBA, SUPERBLOCK_SECTORS) != DISK_OK) { logging_log_error("Failed to read disk %lu @ %u/%u", disk_get_id(disk), SUPERBLOCK_LBA, SUPERBLOCK_SECTORS); @@ -142,8 +219,43 @@ uint8_t ext2_attempt_init(struct disk_t* disk, uint64_t start_lba, uint64_t end_ return 0; } + bgdt_start_lba = start_lba + (1u << (1 + superblock->s_log_block_size)); + + bgdt_size = (1 + superblock->s_blocks_count / superblock->s_blocks_per_group) * sizeof(struct ext2_bg_desc_t); + adj = bgdt_size % SECTOR_SIZE; + if (adj) { + bgdt_size += SECTOR_SIZE - adj; + } + + bgdt = kmalloc(bgdt_size); + if (disk_read(disk, bgdt, bgdt_start_lba, (uint16_t)(bgdt_size / SECTOR_SIZE)) != DISK_OK) { + logging_log_error("Failed to read disk %lu @ %u/%u", disk_get_id(disk), SUPERBLOCK_LBA, SUPERBLOCK_SECTORS); + kfree(superblock); + kfree(bgdt); + return 0; + } + logging_log_info("Found ext2 filesystem %16.16s", superblock->s_volume_name); - kfree(superblock); + root_handle = kmalloc(sizeof(struct ext2_inode_handle_t)); + root_handle->ext2 = kmalloc(sizeof(struct ext2_t)); + root_handle->ext2->start_lba = start_lba; + root_handle->ext2->end_lba = end_lba; + root_handle->ext2->superblock = superblock; + root_handle->ext2->bgdt = bgdt; + root_handle->ext2->disk = disk; + lock_init(&root_handle->ext2->lock); + root_handle->inode_index = ROOT_DIR_INODE; + + logging_log_debug("ext2 blocks: 0x%x x 0x%x (0x%lX)", + 1024u << superblock->s_log_block_size, superblock->s_blocks_count, + (uint64_t)(1024u << superblock->s_log_block_size) * (uint64_t)superblock->s_blocks_count); + + if (!kmemcmp(label_rootfs, superblock->s_volume_name, sizeof(superblock->s_volume_name))) { + fs_mount(root_handle, ext2_stat, "/"); + } + + //TODO: mount other volumes + return 1; } diff --git a/drivers/gpt/gpt.c b/drivers/gpt/gpt.c index 0687714..524f100 100644 --- a/drivers/gpt/gpt.c +++ b/drivers/gpt/gpt.c @@ -92,7 +92,7 @@ uint8_t gpt_find_partitions(struct disk_t* disk) { } partition_array_size = gpt->partition_array_entry_count * gpt->partition_array_entry_size; - partition_array_base = kmalloc((partition_array_size / SECTOR_SIZE) + 1); + partition_array_base = kmalloc(SECTOR_SIZE * ((partition_array_size / SECTOR_SIZE) + 1)); if (disk_read(disk, partition_array_base, gpt->partition_array_lba, (uint16_t)(partition_array_size / SECTOR_SIZE) + 1) != DISK_OK) { diff --git a/drivers/include/apic/ipi.h b/drivers/include/apic/ipi.h index a854b10..6d6e99e 100644 --- a/drivers/include/apic/ipi.h +++ b/drivers/include/apic/ipi.h @@ -22,9 +22,17 @@ #define AP_ENTRY_PAGE 8 +extern void apic_init_shootdowns(uint8_t num_apic); +extern void apic_ipi_init(void); + extern void apic_wait_for_ipi(void); extern void apic_send_ipi_init_set(uint8_t apic_id); extern void apic_send_ipi_init_clear(uint8_t apic_id); extern void apic_send_ipi_sipi(uint8_t apic_id); +extern void apic_tlb_shootdown(uint64_t vaddr); +extern void apic_tlb_shootdown_dispatch(void); + +extern void apic_register_barrier(uint8_t apic_id); + #endif /* DRIVERS_APIC_IPI_H */ diff --git a/drivers/include/apic/isr.h b/drivers/include/apic/isr.h index 9c20c76..9701eaf 100644 --- a/drivers/include/apic/isr.h +++ b/drivers/include/apic/isr.h @@ -22,4 +22,6 @@ extern void apic_isr_timer(void) __attribute__((noreturn)); extern void apic_isr_error(void); +extern void apic_isr_tlb_shootdown(void); + #endif /* DRIVERS_APIC_ISR_H */ diff --git a/kernel/core/cpu_instr.S b/kernel/core/cpu_instr.S index 4359a14..9c178a6 100644 --- a/kernel/core/cpu_instr.S +++ b/kernel/core/cpu_instr.S @@ -41,6 +41,11 @@ cpu_pause: pause ret +.globl cpu_invlpg +cpu_invlpg: +invlpg (%rdi) +ret + .globl cpu_wait_loop cpu_wait_loop: hlt diff --git a/kernel/core/fs.c b/kernel/core/fs.c new file mode 100644 index 0000000..bd5d7ef --- /dev/null +++ b/kernel/core/fs.c @@ -0,0 +1,136 @@ +/* fs.c - kernel file system layer */ +/* Copyright (C) 2026 Ebrahim Aleem +* +* This program is free software: you can redistribute it and/or modify +* it under the terms of the GNU General Public License as published by +* the Free Software Foundation, either version 3 of the License, or +* (at your option) any later version. +* +* This program is distributed in the hope that it will be useful, +* but WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +* GNU General Public License for more details. +* +* You should have received a copy of the GNU General Public License +* along with this program. If not, see +*/ + +#include + +#include +#include +#include +#include + +#include + +struct fs_file_t { + struct fs_file_info_t info; +}; + +struct fs_mount_t { + fs_stat_t stat; +}; + +struct fs_node_t { + struct fs_node_t* sub; + struct fs_node_t* co; + + struct fs_mount_t* mount; + void* handle; + + const char* name; + uint8_t name_len; +}; + +static enum fs_error_t vfs_stat(void* cntx, struct fs_file_info_t* info) { + (void)cntx; + info->size = 0; + info->type = FS_DIR; + return FS_ERROR_OK; +} + +static struct fs_mount_t vfs_mount = { + .stat = vfs_stat +}; + +static uint8_t root_fs_lock; +static struct fs_node_t vfs_root; + +static uint8_t extract_prefix(const char* path, uint8_t off, char* buf, uint8_t* term) { + uint8_t i = 0; + while (path[off] && path[off] != '/') { + buf[i++] = path[off++]; + } + + if (path[off]) { + buf[i++] = path[off++]; + } + + *term = !path[off]; + + buf[i] = 0; + return off; +} + +static struct fs_node_t* walk_vfs(struct fs_node_t* node, uint8_t off, char* buf, const char* path, uint8_t create) { + struct fs_node_t* walk, * temp; + uint8_t term; + + off = extract_prefix(path, off, buf, &term); + + if (kmemcmp(buf, node->name, node->name_len)) { + return 0; + } + + if (term) { + return node; + } + + for (walk = node->sub; walk; walk = walk->co) { + temp = walk_vfs(walk, off, buf, path, create); + if (temp) { + return temp; + } + } + + //TODO: create + return 0; +} + +void fs_init(void) { + lock_init(&root_fs_lock); + + vfs_root.sub = 0; + vfs_root.co = 0; + vfs_root.mount = &vfs_mount; + vfs_root.name = "/"; + vfs_root.name_len = 1; +} + +void fs_mount(void* root, fs_stat_t stat, const char* path) { + char buf[256]; + struct fs_node_t* node; + struct fs_file_info_t info; + + lock_acquire(&root_fs_lock); + node = walk_vfs(&vfs_root, 0, buf, path, 1); + + if (!node) { + logging_log_error("Failed to mount filesystem"); + } + else { + node->mount = kmalloc(sizeof(struct fs_mount_t)); + node->mount->stat = stat; + node->handle = root; + } + + lock_release(&root_fs_lock); + + if (stat(root, &info) == FS_ERROR_OK) { + logging_log_debug("Mounted %s (0x%lx %u)", path, info.size, info.type); + } + else { + logging_log_error("Failed to stat %s", path); + } +} diff --git a/kernel/core/kentry.c b/kernel/core/kentry.c index d1049ba..5ba3d72 100644 --- a/kernel/core/kentry.c +++ b/kernel/core/kentry.c @@ -30,6 +30,7 @@ #include #include #include +#include #include @@ -80,15 +81,18 @@ void kentry(void) { logging_log_debug("System clock initialized."); logging_log_debug("APIC and IOAPIC init"); + apic_ipi_init(); pic_disab(); apic_init(); apic_timer_calib(apic_get_bsp_id()); apic_nmi_enab(); ioapic_init(); + cpu_sti(); logging_log_debug("APIC and IOAPIC init done"); logging_log_debug("Early PCIE init"); disk_init(); + fs_init(); pcie_init(); pcie_enumerate(); logging_log_debug("Early PCIE init done"); @@ -131,6 +135,7 @@ void kapentry(uint64_t arb_id) { apic_init_ap(); apic_timer_calib(apic_get_bsp_id()); apic_nmi_enab(); + cpu_sti(); logging_log_debug("AP APIC init done"); logging_log_info("AP init complete"); diff --git a/kernel/core/paging.c b/kernel/core/paging.c index 974e902..c8b281c 100644 --- a/kernel/core/paging.c +++ b/kernel/core/paging.c @@ -24,9 +24,12 @@ #include #include #include +#include #include +#include + #define PAGE_PS 0x80 #define PAGE_ADDR_MASK 0x0000FFFFFFFFF000 @@ -137,7 +140,9 @@ void paging_unmap(uint64_t vaddr, enum page_size_t page_size) { return; } + *access = 0; + apic_tlb_shootdown(vaddr); } uint64_t paging_ident(uint64_t paddr) { diff --git a/kernel/core/process.c b/kernel/core/process.c index 5a04c9c..1445b92 100644 --- a/kernel/core/process.c +++ b/kernel/core/process.c @@ -115,13 +115,11 @@ struct pcb_t* process_from_func(process_function_t func, void* cntx) { } void process_kill_current(void) { - cpu_cli(); lock_acquire(&lock_proc); struct pcb_t* pcb = proc_data_get()->current_process; pcb->sched_cntr = SCHED_KILL; logging_log_debug("Killed %ld", pcb->pid); lock_release(&lock_proc); - cpu_sti(); cpu_wait_loop(); } diff --git a/kernel/include/core/cpu_instr.h b/kernel/include/core/cpu_instr.h index e6b4908..c832800 100644 --- a/kernel/include/core/cpu_instr.h +++ b/kernel/include/core/cpu_instr.h @@ -30,6 +30,8 @@ extern void cpu_sti(void); extern void cpu_pause(void); +extern void cpu_invlpg(uint64_t addr); + extern void cpu_wait_loop(void) __attribute__((noreturn)); extern void cpu_halt_loop(void) __attribute__((noreturn)); diff --git a/kernel/include/core/fs.h b/kernel/include/core/fs.h new file mode 100644 index 0000000..29fb80b --- /dev/null +++ b/kernel/include/core/fs.h @@ -0,0 +1,53 @@ +/* fs.c - kernel file system layer interface */ +/* Copyright (C) 2026 Ebrahim Aleem +* +* This program is free software: you can redistribute it and/or modify +* it under the terms of the GNU General Public License as published by +* the Free Software Foundation, either version 3 of the License, or +* (at your option) any later version. +* +* This program is distributed in the hope that it will be useful, +* but WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +* GNU General Public License for more details. +* +* You should have received a copy of the GNU General Public License +* along with this program. If not, see +*/ + +#ifndef KERNEL_CORE_FS_H +#define KERNEL_CORE_FS_H + +#include +#include + +enum fs_file_type_t { + FS_FILE, + FS_DIR, +}; + +enum fs_open_mode_t { + FS_OPEN_NOCREATE = 0, + FS_OPEN_CREATE = 1 +}; + +enum fs_error_t { + FS_ERROR_OK, + FS_ERROR_FAIL +}; + +struct fs_file_info_t { + enum fs_file_type_t type; + size_t size; +}; + +struct fs_file_t; + + +typedef enum fs_error_t (*fs_stat_t)(void*, struct fs_file_info_t*); + +extern void fs_init(void); + +extern void fs_mount(void* root, fs_stat_t stat, const char* path); + +#endif /* KERNEL_CORE_FS_H */ From e5222bde294639c464e79393921d1e5e1a3c0f5f Mon Sep 17 00:00:00 2001 From: Ebrahim Aleem Date: Mon, 9 Mar 2026 23:53:27 -0700 Subject: [PATCH 04/12] minimal ext2 directory enumeration --- Makefile | 4 +- drivers/ext2/ext2.c | 133 +++++++++++++-- kernel/core/fs.c | 359 ++++++++++++++++++++++++++++++++------- kernel/include/core/fs.h | 52 ++++-- 4 files changed, 461 insertions(+), 87 deletions(-) diff --git a/Makefile b/Makefile index 06a1ad0..15af1a7 100644 --- a/Makefile +++ b/Makefile @@ -17,7 +17,7 @@ # Debug options -#export DEBUG = 1 +export DEBUG = 1 export DEBUG_LOGGING = 1 export SUPPRESS_ACPICA_BUILD_OUTPUT = 1 @@ -74,7 +74,7 @@ TEST_TARGETS := \ TEST_CANIDATES := $(patsubst $(OBJ_DIR)/test_%.a,test-%,$(TEST_TARGETS)) TEST_EXEC := $(basename $(TEST_TARGETS)) -COPY_DOC_TO := $(OBJ_DIR)/rootfs/doc/ModulOS/ +COPY_DOC_TO := $(OBJ_DIR)/rootfs/usr/share/doc/ModulOS/ SRC := $(shell find . -type f \( -name "*.c" -o -name "*.S" -o -name "*.h" \)) diff --git a/drivers/ext2/ext2.c b/drivers/ext2/ext2.c index 90d1199..6690d59 100644 --- a/drivers/ext2/ext2.c +++ b/drivers/ext2/ext2.c @@ -25,6 +25,7 @@ #include #include #include +#include #include #include @@ -34,11 +35,13 @@ #define EXT2_SUPER_MAGIC 0xEF53 -#define ROOT_DIR_INODE 2 +#define EXT2_ROOT_INO 2 #define EXT2_S_IFREG 0x8000 #define EXT2_S_IFDIR 0x4000 +#define DIRLS_SET 0x8000000000000000 + struct ext2_superblock_t { uint32_t s_inodes_count; uint32_t s_blocks_count; @@ -132,6 +135,14 @@ struct ext2_inode_t { uint8_t i_osd2[12]; } __attribute__((packed)); +struct ext2_ll_dir_entry_t { + uint32_t inode; + uint16_t rec_len; + uint8_t name_len; + uint8_t file_type; + uint8_t name[]; +} __attribute__((packed)); + _Static_assert(sizeof(struct ext2_superblock_t) == 1024, "Bad ext2 superblock size"); _Static_assert(sizeof(struct ext2_bg_desc_t) == 32, "Bad ext2 bg descriptor size"); _Static_assert(sizeof(struct ext2_inode_t) == 128, "Bad exte2 inode size"); @@ -142,7 +153,6 @@ struct ext2_t { struct ext2_superblock_t* superblock; struct ext2_bg_desc_t* bgdt; struct disk_t* disk; - uint8_t lock; }; struct ext2_inode_handle_t { @@ -150,6 +160,12 @@ struct ext2_inode_handle_t { uint64_t inode_index; }; +struct ext2_dir_track_t { + struct ext2_inode_handle_t* handle; + struct ext2_inode_t dir; + uint64_t off; +}; + static uint8_t label_rootfs[16] = {'r', 'o', 'o', 't', 'f', 's', 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; static uint8_t get_inode(const struct ext2_inode_handle_t* inode_handle, struct ext2_inode_t* inode) { @@ -181,25 +197,89 @@ static uint8_t get_inode(const struct ext2_inode_handle_t* inode_handle, struct return 0; } -static enum fs_error_t ext2_stat(void* handle, struct fs_file_info_t* info) { +static enum fs_status_t ext2_stat(struct fs_file_handle_t* file, struct fs_info_t* info) { struct ext2_inode_t inode; - if (get_inode(handle, &inode)) { - return FS_ERROR_FAIL; + + if (get_inode((struct ext2_inode_handle_t*)file, &inode)) { + return FS_STATUS_ERROR; } - info->size = (uint64_t)inode.i_size | ((uint64_t)inode.i_dir_acl << 32); - + info->size = (uint32_t)inode.i_size | ((uint64_t)inode.i_dir_acl << 32); + if (inode.i_mode & EXT2_S_IFREG) { - info->type = FS_FILE; + info->type = FS_TYPE_FILE; } else if (inode.i_mode & EXT2_S_IFDIR) { - info->type = FS_DIR; + info->type = FS_TYPE_DIR; } else { - return FS_ERROR_FAIL; + return FS_STATUS_ERROR; + } + + return FS_STATUS_OK; +} + +static struct fs_dirls_handle_t* ext2_dirst(struct fs_file_handle_t* handle) { + struct ext2_inode_t inode; + + if (get_inode((struct ext2_inode_handle_t*)handle, &inode)) { + return 0; } - return FS_ERROR_OK; + struct ext2_dir_track_t* dir_track = kmalloc(sizeof(struct ext2_dir_track_t)); + dir_track->handle = (struct ext2_inode_handle_t*)handle; + dir_track->dir = inode; + dir_track->off = 0; + //TODO: support reading from other blocks as well + return (struct fs_dirls_handle_t*)dir_track; +} + +static enum fs_status_t ext2_dirls(struct fs_dirls_handle_t** handle, struct fs_ls_info_t* file) { + struct ext2_dir_track_t* dt = (struct ext2_dir_track_t*)*handle; + + const struct ext2_superblock_t* superblock = dt->handle->ext2->superblock; + + const uint64_t block_size = 1024u << superblock->s_log_block_size; + + if (dt->off >= block_size) { + return FS_STATUS_EOF; + } + + const uint64_t lba = dt->handle->ext2->start_lba + dt->dir.i_block[0] * block_size / SECTOR_SIZE; + + void* buffer = kmalloc(block_size); + + if (disk_read(dt->handle->ext2->disk, buffer, lba, (uint16_t)(block_size / SECTOR_SIZE)) != DISK_OK) { + logging_log_error("Failed to read"); + } + + struct ext2_ll_dir_entry_t* entry = + (struct ext2_ll_dir_entry_t*)((uint64_t)buffer + dt->off); + + if (entry->inode != 0) { + if (entry->name[0] == '.' && (entry->name_len == 1 || (entry->name_len == 2 && entry->name[1] == '.'))) { + file->valid = 0; + } + + else { + kmemcpy(file->name, entry->name, entry->name_len); + file->name_len = entry->name_len; + struct ext2_inode_handle_t* hndl = kmalloc(sizeof(struct ext2_inode_handle_t)); + hndl->ext2 = dt->handle->ext2; + hndl->inode_index = entry->inode; + file->handle = (struct fs_file_handle_t*)hndl; + file->valid = 1; + } + } + + dt->off += entry->rec_len; + + kfree(buffer); + return FS_STATUS_OK; +} + +static void ext2_diren(struct fs_dirls_handle_t* handle) { + kfree(handle); } uint8_t ext2_attempt_init(struct disk_t* disk, uint64_t start_lba, uint64_t end_lba) { @@ -244,17 +324,42 @@ uint8_t ext2_attempt_init(struct disk_t* disk, uint64_t start_lba, uint64_t end_ root_handle->ext2->superblock = superblock; root_handle->ext2->bgdt = bgdt; root_handle->ext2->disk = disk; - lock_init(&root_handle->ext2->lock); - root_handle->inode_index = ROOT_DIR_INODE; + root_handle->inode_index = EXT2_ROOT_INO; logging_log_debug("ext2 blocks: 0x%x x 0x%x (0x%lX)", 1024u << superblock->s_log_block_size, superblock->s_blocks_count, (uint64_t)(1024u << superblock->s_log_block_size) * (uint64_t)superblock->s_blocks_count); if (!kmemcmp(label_rootfs, superblock->s_volume_name, sizeof(superblock->s_volume_name))) { - fs_mount(root_handle, ext2_stat, "/"); + if (fs_mount((struct fs_file_handle_t*)root_handle, "/", + ext2_stat, + ext2_dirst, + ext2_dirls, + ext2_diren + ) != FS_STATUS_OK) { + logging_log_error("Failed to mount rootfs"); + panic(PANIC_STATE); + } + + struct fs_file_t* root_file = fs_open("/."); + if (!root_file) { + logging_log_error("Failed to open root directory"); + panic(PANIC_STATE); + } + + struct fs_info_t root_file_info; + if (fs_stat(root_file, &root_file_info) != FS_STATUS_OK) { + logging_log_error("Failed to stat root directory"); + panic(PANIC_STATE); + } + + logging_log_debug("Root directory (0x%lx) (%u)", root_file_info.size, root_file_info.type); + + fs_close(root_file); } + fs_log_vfs_tree(); + //TODO: mount other volumes return 1; diff --git a/kernel/core/fs.c b/kernel/core/fs.c index bd5d7ef..9e4a643 100644 --- a/kernel/core/fs.c +++ b/kernel/core/fs.c @@ -21,116 +21,359 @@ #include #include #include +#include #include +#include -struct fs_file_t { - struct fs_file_info_t info; -}; +#define VFS_STATUS_CONSISTENT 0x1 +#define VFS_STATUS_MOUNTED 0x2 struct fs_mount_t { + struct fs_mount_t* parent; fs_stat_t stat; + fs_dirst_t dirst; + fs_dirls_t dirls; + fs_diren_t diren; }; struct fs_node_t { + struct fs_node_t* parent; struct fs_node_t* sub; struct fs_node_t* co; struct fs_mount_t* mount; - void* handle; - const char* name; + struct fs_file_handle_t* handle; + + uint64_t accesses; + + char* name; + + struct fs_info_t info; + uint8_t name_len; + uint8_t status; +}; + +struct fs_file_t { + struct fs_node_t* node; + struct fs_info_t info; +}; + +enum node_res_t { + NODE_RES_TRUE, + NODE_RES_FALSE, + NODE_RES_LAST, + NODE_RES_PARENT, }; -static enum fs_error_t vfs_stat(void* cntx, struct fs_file_info_t* info) { - (void)cntx; +static enum fs_status_t vfs_stat(struct fs_file_handle_t* handle, struct fs_info_t* info) { + (void)handle; + info->size = 0; - info->type = FS_DIR; - return FS_ERROR_OK; + info->type = FS_TYPE_DIR; + + return FS_STATUS_OK; +} + +static struct fs_dirls_handle_t* vfs_dirst(struct fs_file_handle_t* handle) { + struct fs_node_t* node = (struct fs_node_t*)handle; + return (struct fs_dirls_handle_t*)node->sub; +} + +static enum fs_status_t vfs_dirls(struct fs_dirls_handle_t** handle, struct fs_ls_info_t* file) { + if (!handle) { + return FS_STATUS_EOF; + } + + struct fs_node_t* walk = (struct fs_node_t*)*handle; + + file->handle = (struct fs_file_handle_t*)walk; + kmemcpy(file->name, walk->name, walk->name_len); + file->name_len = walk->name_len; + + *handle = (struct fs_dirls_handle_t*)walk->co; + + return FS_STATUS_OK; +} + +static void vfs_diren(struct fs_dirls_handle_t* handle) { + (void)handle; } static struct fs_mount_t vfs_mount = { - .stat = vfs_stat + .parent = &vfs_mount, + .stat = vfs_stat, + .dirst = vfs_dirst, + .dirls = vfs_dirls, + .diren = vfs_diren }; -static uint8_t root_fs_lock; +static uint8_t vfs_lock; static struct fs_node_t vfs_root; -static uint8_t extract_prefix(const char* path, uint8_t off, char* buf, uint8_t* term) { - uint8_t i = 0; - while (path[off] && path[off] != '/') { - buf[i++] = path[off++]; +void fs_init(void) { + lock_init(&vfs_lock); + + vfs_root.sub = 0; + vfs_root.co = 0; + vfs_root.parent = &vfs_root; + vfs_root.mount = &vfs_mount; + vfs_root.name = (char*)""; + vfs_root.status = VFS_STATUS_CONSISTENT; + vfs_root.name_len = 0; + vfs_root.handle = (struct fs_file_handle_t*)&vfs_root; + vfs_root.accesses = 1; + vfs_root.info.size = 0; + vfs_root.info.type = FS_TYPE_DIR; +} + +static inline enum fs_status_t assert_consistent(struct fs_node_t* node, uint8_t clear) { + if (node->status & VFS_STATUS_CONSISTENT) { + return FS_STATUS_OK; } - if (path[off]) { - buf[i++] = path[off++]; + if (node->sub && clear) { + logging_log_error("Detected corrupt vfs state. Inconsistent non-leaf node"); + panic(PANIC_STATE); } + struct fs_info_t info; + enum fs_status_t status; + - *term = !path[off]; + struct fs_ls_info_t file; + struct fs_node_t* temp; + struct fs_dirls_handle_t* handle = node->mount->dirst(node->handle); - buf[i] = 0; - return off; -} + if (!handle) { + return FS_STATUS_ERROR; + } + + while (node->mount->dirls(&handle, &file) == FS_STATUS_OK) { + if (!file.valid) { + continue; + } -static struct fs_node_t* walk_vfs(struct fs_node_t* node, uint8_t off, char* buf, const char* path, uint8_t create) { - struct fs_node_t* walk, * temp; - uint8_t term; + if ((status = node->mount->stat(file.handle, &info)) != FS_STATUS_OK) { + node->mount->diren(handle); + return status; + } - off = extract_prefix(path, off, buf, &term); + temp = node->sub; + node->sub = kmalloc(sizeof(struct fs_node_t)); - if (kmemcmp(buf, node->name, node->name_len)) { - return 0; + node->sub->accesses = 0; + node->sub->co = temp; + node->sub->handle = file.handle; + node->sub->mount = node->mount; + node->sub->name_len = file.name_len; + node->sub->name = kmalloc(file.name_len + 1); + kmemcpy(node->sub->name, file.name, file.name_len); + node->sub->name[file.name_len] = 0; + node->sub->parent = node; + node->sub->status = 0; + node->sub->sub = 0; + node->sub->info = info; } - if (term) { - return node; + node->mount->diren(handle); + + node->status |= VFS_STATUS_CONSISTENT; + + return FS_STATUS_OK; +} + +static inline const char* simplify_path(const char* path) { + while ( + *path == '/' || + (*path == '.' && (*(path+1) == '/' || !*(path+1)))) { + path++; } - for (walk = node->sub; walk; walk = walk->co) { - temp = walk_vfs(walk, off, buf, path, create); - if (temp) { - return temp; + return path; +} + +static inline const char* check_path(struct fs_node_t* node, const char* path, enum node_res_t* res) { + uint8_t i = 0; + const char* start; + + for (start = path; *path && *path != '/'; path++) { + i++; + } + + path = simplify_path(path); + + *res = NODE_RES_FALSE; + + if (i == node->name_len && !kmemcmp(node->name, start, i)) { + if (!*path) { + *res = NODE_RES_LAST; + } + else { + *res = NODE_RES_TRUE; } } - //TODO: create - return 0; + if (i == 2 && !kmemcmp("..", start, i)) { + *res = NODE_RES_PARENT; + } + + return path; } -void fs_init(void) { - lock_init(&root_fs_lock); +static struct fs_node_t* resolve_path(struct fs_node_t* root, const char* path) { + enum node_res_t res; + struct fs_node_t* node, * walk; - vfs_root.sub = 0; - vfs_root.co = 0; - vfs_root.mount = &vfs_mount; - vfs_root.name = "/"; - vfs_root.name_len = 1; + path = check_path(root, path, &res); + + switch (res) { + case NODE_RES_LAST: + root->accesses++; + return root; + + case NODE_RES_PARENT: + node = resolve_path(root->parent, path); + if (node) { + root->parent->accesses--; + } + return node; + + case NODE_RES_TRUE: + if (root->info.type != FS_TYPE_DIR) { + return 0; + } + + if (assert_consistent(root, 1) != FS_STATUS_OK) { + return 0; + } + + for (walk = root->sub; walk; walk = walk->co) { + node = resolve_path(walk, path); + if (node) { + root->accesses++; + return node; + } + } + __attribute__((fallthrough)); + case NODE_RES_FALSE: + default: + return 0; + } } -void fs_mount(void* root, fs_stat_t stat, const char* path) { - char buf[256]; - struct fs_node_t* node; - struct fs_file_info_t info; +static void cleanup_path(struct fs_node_t* root, const char* path) { + //TODO: cleanup vfs tree + (void)root; + (void)path; +} - lock_acquire(&root_fs_lock); - node = walk_vfs(&vfs_root, 0, buf, path, 1); +struct fs_file_t* fs_open(const char* path) { + struct fs_node_t* node = resolve_path(&vfs_root, simplify_path(path)); if (!node) { - logging_log_error("Failed to mount filesystem"); + return 0; } - else { - node->mount = kmalloc(sizeof(struct fs_mount_t)); - node->mount->stat = stat; - node->handle = root; + + struct fs_file_t* file = kmalloc(sizeof(struct fs_file_t)); + file->node = node; + return file; +} + +void fs_close(struct fs_file_t* file) { + lock_acquire(&vfs_lock); + cleanup_path(&vfs_root, simplify_path(file->node->name)); + lock_release(&vfs_lock); + + kfree(file); +} + +enum fs_status_t fs_stat(struct fs_file_t* file, struct fs_info_t* info) { + *info = file->node->info; + return FS_STATUS_OK; +} + +extern enum fs_status_t fs_mount( + struct fs_file_handle_t* root, + const char* path, + fs_stat_t stat, + fs_dirst_t dirst, + fs_dirls_t dirls, + fs_diren_t diren) { + + lock_acquire(&vfs_lock); + + struct fs_node_t* node = resolve_path(&vfs_root, path); + + if (node->status & VFS_STATUS_MOUNTED) { + return FS_STATUS_BUSY; } - lock_release(&root_fs_lock); + struct fs_node_t revert; + revert = *node; + struct fs_mount_t* mount = kmalloc(sizeof(struct fs_mount_t)); + mount->parent = node->mount; + mount->stat = stat; + mount->dirst = dirst; + mount->dirls = dirls; + mount->diren = diren; + + node->mount = mount; + node->handle = root; + node->status = VFS_STATUS_MOUNTED; - if (stat(root, &info) == FS_ERROR_OK) { - logging_log_debug("Mounted %s (0x%lx %u)", path, info.size, info.type); + struct fs_info_t info; + enum fs_status_t status = node->mount->stat(node->handle, &info); + if (status != FS_STATUS_OK) { + kfree(mount); + *node = revert; + return status; } - else { - logging_log_error("Failed to stat %s", path); + + node->info = info; + + if ((status = assert_consistent(node, 0)) != FS_STATUS_OK) { + kfree(mount); + *node = revert; + return status; + } + + lock_release(&vfs_lock); + return FS_STATUS_OK; +} + +#ifdef DEBUG + +static void fs_log_tree(struct fs_node_t* node, char* prefix, size_t prefix_len) { + logging_log_debug("vfs tree: %s%256s (%u/0x%lx)", prefix, node->name, node->info.type, node->info.size); + + if (node->info.type != FS_TYPE_DIR) { + return; } + + if (assert_consistent(node, 1) != FS_STATUS_OK) { + logging_log_error("Failed to log vfs tree"); + return; + } + + char* new_prefix = kmalloc(prefix_len + 2); + kmemcpy(new_prefix+2, prefix, prefix_len); + new_prefix[0] = new_prefix[1] = ' '; + + for (struct fs_node_t* walk = node->sub; walk; walk = walk->co) { + fs_log_tree(walk, new_prefix, prefix_len + 2); + } + + kfree(new_prefix); } + +void fs_log_vfs_tree(void) { + lock_acquire(&vfs_lock); + + fs_log_tree(&vfs_root, (char*)"", 1); + + lock_release(&vfs_lock); +} + +#endif /* DEBUG */ diff --git a/kernel/include/core/fs.h b/kernel/include/core/fs.h index 29fb80b..3009bf2 100644 --- a/kernel/include/core/fs.h +++ b/kernel/include/core/fs.h @@ -22,32 +22,58 @@ #include enum fs_file_type_t { - FS_FILE, - FS_DIR, + FS_TYPE_FILE, + FS_TYPE_DIR }; -enum fs_open_mode_t { - FS_OPEN_NOCREATE = 0, - FS_OPEN_CREATE = 1 +enum fs_status_t { + FS_STATUS_OK, + FS_STATUS_ERROR, + FS_STATUS_EOF, + FS_STATUS_FILE_NOT_FOUND, + FS_STATUS_BUSY }; -enum fs_error_t { - FS_ERROR_OK, - FS_ERROR_FAIL -}; - -struct fs_file_info_t { +struct fs_info_t { enum fs_file_type_t type; size_t size; }; +struct fs_ls_info_t { + struct fs_file_handle_t* handle; + char name[256]; + uint8_t name_len; + uint8_t valid; +}; + struct fs_file_t; +struct fs_file_handle_t; +struct fs_dirls_handle_t; +extern void fs_init(void); + +typedef enum fs_status_t (*fs_stat_t)(struct fs_file_handle_t* handle, struct fs_info_t* info); -typedef enum fs_error_t (*fs_stat_t)(void*, struct fs_file_info_t*); +typedef struct fs_dirls_handle_t* (*fs_dirst_t)(struct fs_file_handle_t* handle); +typedef enum fs_status_t (*fs_dirls_t)(struct fs_dirls_handle_t** handle, struct fs_ls_info_t* file); +typedef void (*fs_diren_t)(struct fs_dirls_handle_t* handle); extern void fs_init(void); -extern void fs_mount(void* root, fs_stat_t stat, const char* path); +extern enum fs_status_t fs_mount( + struct fs_file_handle_t* root, + const char* path, + fs_stat_t stat, + fs_dirst_t dirst, + fs_dirls_t dirls, + fs_diren_t diren); + +extern struct fs_file_t* fs_open(const char* path); +extern void fs_close(struct fs_file_t* file); +extern enum fs_status_t fs_stat(struct fs_file_t* file, struct fs_info_t* info); + +#ifdef DEBUG +extern void fs_log_vfs_tree(void); +#endif /* DEBUG */ #endif /* KERNEL_CORE_FS_H */ From 741f8e84ce42d9cdb60833d26f17bb5a8adfd3da Mon Sep 17 00:00:00 2001 From: Ebrahim Aleem Date: Tue, 10 Mar 2026 00:08:34 -0700 Subject: [PATCH 05/12] send eoi after tlb shootdown ipi --- drivers/apic/ipi.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/drivers/apic/ipi.c b/drivers/apic/ipi.c index aecb4f7..1b18e54 100644 --- a/drivers/apic/ipi.c +++ b/drivers/apic/ipi.c @@ -148,6 +148,8 @@ void apic_tlb_shootdown_dispatch(void) { cpu_invlpg(tlb_shootdown_addr); tlb_shootdown_barrier[proc_data_get()->arb_id] = 0; + + apic_write_reg(APIC_REG_EOI, APIC_EOI); } void apic_register_barrier(uint8_t apic_id) { From 2b45de525e978f7c807d0b25a7be311d115fb02e Mon Sep 17 00:00:00 2001 From: Ebrahim Aleem Date: Wed, 11 Mar 2026 13:20:32 -0700 Subject: [PATCH 06/12] read directory entries from all blocks --- drivers/ext2/ext2.c | 227 ++++++++++++++++++++++++++++++++++++--- kernel/core/fs.c | 181 ++++++++++++++++++++++--------- kernel/core/mm.c | 25 +++-- kernel/include/core/fs.h | 11 +- 4 files changed, 371 insertions(+), 73 deletions(-) diff --git a/drivers/ext2/ext2.c b/drivers/ext2/ext2.c index 6690d59..3cc3453 100644 --- a/drivers/ext2/ext2.c +++ b/drivers/ext2/ext2.c @@ -33,6 +33,16 @@ #define SUPERBLOCK_LBA 2 #define SUPERBLOCK_SECTORS 2 +#define DIRECT_BLOCKS 12 +#define INDIR_1 12 +#define INDIR_2 13 +#define INDIR_3 14 + +#define BLOCK_OK 0 +#define BLOCK_RETRY 1 +#define BLOCK_LAST 2 +#define BLOCK_ERROR 3 + #define EXT2_SUPER_MAGIC 0xEF53 #define EXT2_ROOT_INO 2 @@ -164,10 +174,27 @@ struct ext2_dir_track_t { struct ext2_inode_handle_t* handle; struct ext2_inode_t dir; uint64_t off; + uint64_t block; }; static uint8_t label_rootfs[16] = {'r', 'o', 'o', 't', 'f', 's', 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; +static void* read_block(uint64_t block, struct ext2_t* ext2) { + const uint64_t block_size = 1024u << ext2->superblock->s_log_block_size; + + void* buffer = kmalloc(block_size); + + const uint64_t lba = ext2->start_lba + block * block_size / SECTOR_SIZE; + + if (disk_read(ext2->disk, buffer, lba, (uint16_t)(block_size / SECTOR_SIZE)) != DISK_OK) { + logging_log_error("Failed to read"); + kfree(buffer); + return 0; + } + + return buffer; +} + static uint8_t get_inode(const struct ext2_inode_handle_t* inode_handle, struct ext2_inode_t* inode) { const struct ext2_superblock_t* superblock = inode_handle->ext2->superblock; const struct ext2_bg_desc_t* bgdt = inode_handle->ext2->bgdt; @@ -180,16 +207,11 @@ static uint8_t get_inode(const struct ext2_inode_handle_t* inode_handle, struct const uint64_t inode_off = lcl_inode_off % block_size; const uint64_t inode_table_block = bgdt[block_group].bg_inode_table + lcl_inode_blk; - void* buffer = kmalloc(block_size); + void* buffer = read_block(inode_table_block, inode_handle->ext2); - if (disk_read( - inode_handle->ext2->disk, - buffer, - inode_handle->ext2->start_lba + inode_table_block * block_size / SECTOR_SIZE, - (uint16_t)(block_size / SECTOR_SIZE)) != DISK_OK) { + if (!buffer) { logging_log_error("Failed to read inode %lu", inode_handle->inode_index); kfree(buffer); - return 1; } *inode = *(struct ext2_inode_t*)((uint64_t)buffer + inode_off); @@ -197,6 +219,159 @@ static uint8_t get_inode(const struct ext2_inode_handle_t* inode_handle, struct return 0; } +static uint8_t get_block_index_dir(struct ext2_dir_track_t* dt, uint64_t* index) { + uint64_t block = dt->block; + struct ext2_inode_t* inode = &dt->dir; + struct ext2_t* ext2 = dt->handle->ext2; + + + if (block < DIRECT_BLOCKS) { + *index = inode->i_block[block]; + + if (!*index) { + dt->block += 1; + return BLOCK_RETRY; + } + + return BLOCK_OK; + } + + block -= DIRECT_BLOCKS; + + const uint64_t block_size = 1024u << ext2->superblock->s_log_block_size; + const uint64_t indir1 = block_size / sizeof(uint32_t); + + uint32_t* buffer; + + if (block < indir1) { + *index = inode->i_block[INDIR_1]; + + if (!*index) { + dt->block += indir1; + return BLOCK_RETRY; + } + + buffer = read_block(*index, ext2); + + if (!buffer) { + return BLOCK_ERROR; + } + + *index = buffer[block]; + kfree(buffer); + + if (!*index) { + dt->block += 1; + return BLOCK_RETRY; + } + + return BLOCK_OK; + } + + block -= indir1; + + const uint64_t indir2 = indir1 * indir1; + + + if (block < indir2) { + *index = inode->i_block[INDIR_2]; + + if (!*index) { + dt->block += indir2; + return BLOCK_RETRY; + } + + buffer = read_block(*index, ext2); + + if (!buffer) { + return BLOCK_ERROR; + } + + *index = buffer[block / indir1]; + kfree(buffer); + + if (!*index) { + dt->block += indir1; + return BLOCK_RETRY; + } + + buffer = read_block(*index, ext2); + + if (!buffer) { + return BLOCK_ERROR; + } + + *index = buffer[block % indir1]; + kfree(buffer); + + if (!*index) { + dt->block += 1; + return BLOCK_RETRY; + } + + return BLOCK_OK; + } + + block -= indir2; + + const uint64_t indir3 = indir2 * indir1; + + if (block < indir3) { + *index = inode->i_block[INDIR_3]; + + if (!*index) { + dt->block += indir3; + return BLOCK_RETRY; + } + + buffer = read_block(*index, ext2); + + if (!buffer) { + return BLOCK_ERROR; + } + + *index = buffer[block / indir2]; + kfree(buffer); + + if (!*index) { + dt->block += indir2; + return BLOCK_RETRY; + } + + buffer = read_block(*index, ext2); + + if (!buffer) { + return BLOCK_ERROR; + } + + *index = buffer[(block % indir2) / indir1]; + kfree(buffer); + + if (!*index) { + dt->block += indir1; + return BLOCK_RETRY; + } + + buffer = read_block(*index, ext2); + + if (!buffer) { + return BLOCK_ERROR; + } + + *index = buffer[block % indir1]; + kfree(buffer); + + if (!*index) { + dt->block += 1; + return BLOCK_RETRY; + } + + return BLOCK_OK; + } + + return BLOCK_LAST; +} + static enum fs_status_t ext2_stat(struct fs_file_handle_t* file, struct fs_info_t* info) { struct ext2_inode_t inode; @@ -230,7 +405,7 @@ static struct fs_dirls_handle_t* ext2_dirst(struct fs_file_handle_t* handle) { dir_track->handle = (struct ext2_inode_handle_t*)handle; dir_track->dir = inode; dir_track->off = 0; - //TODO: support reading from other blocks as well + dir_track->block = 0; return (struct fs_dirls_handle_t*)dir_track; } @@ -242,15 +417,34 @@ static enum fs_status_t ext2_dirls(struct fs_dirls_handle_t** handle, struct fs_ const uint64_t block_size = 1024u << superblock->s_log_block_size; if (dt->off >= block_size) { + dt->block++; + dt->off = 0; + } + + uint64_t block_index; + uint8_t res = get_block_index_dir(dt, &block_index); + + if (res == BLOCK_RETRY) { + file->valid = 0; + dt->off = 0; + return FS_STATUS_OK; + } + + if (res == BLOCK_LAST) { + file->valid = 0; return FS_STATUS_EOF; } - const uint64_t lba = dt->handle->ext2->start_lba + dt->dir.i_block[0] * block_size / SECTOR_SIZE; + if (res == BLOCK_ERROR) { + file->valid = 0; + return FS_STATUS_ERROR; + } - void* buffer = kmalloc(block_size); + void* buffer = read_block(block_index, dt->handle->ext2); - if (disk_read(dt->handle->ext2->disk, buffer, lba, (uint16_t)(block_size / SECTOR_SIZE)) != DISK_OK) { + if (!buffer) { logging_log_error("Failed to read"); + return FS_STATUS_ERROR; } struct ext2_ll_dir_entry_t* entry = @@ -282,6 +476,14 @@ static void ext2_diren(struct fs_dirls_handle_t* handle) { kfree(handle); } +static struct fs_file_handle_t* ext2_create( + struct fs_file_handle_t* handle, + enum fs_file_type_t type, + const char* name, + uint8_t name_len) { + return 0; +} + uint8_t ext2_attempt_init(struct disk_t* disk, uint64_t start_lba, uint64_t end_lba) { struct ext2_superblock_t* superblock = kmalloc(sizeof(struct ext2_superblock_t)); struct ext2_inode_handle_t* root_handle; @@ -335,7 +537,8 @@ uint8_t ext2_attempt_init(struct disk_t* disk, uint64_t start_lba, uint64_t end_ ext2_stat, ext2_dirst, ext2_dirls, - ext2_diren + ext2_diren, + ext2_create ) != FS_STATUS_OK) { logging_log_error("Failed to mount rootfs"); panic(PANIC_STATE); diff --git a/kernel/core/fs.c b/kernel/core/fs.c index 9e4a643..b5c488c 100644 --- a/kernel/core/fs.c +++ b/kernel/core/fs.c @@ -35,6 +35,7 @@ struct fs_mount_t { fs_dirst_t dirst; fs_dirls_t dirls; fs_diren_t diren; + fs_create_t create; }; struct fs_node_t { @@ -59,6 +60,10 @@ struct fs_node_t { struct fs_file_t { struct fs_node_t* node; struct fs_info_t info; + union { + uint64_t off; + struct fs_node_t* dir; + } seek; }; enum node_res_t { @@ -102,12 +107,27 @@ static void vfs_diren(struct fs_dirls_handle_t* handle) { (void)handle; } +static struct fs_file_handle_t* vfs_create( + struct fs_file_handle_t* handle, + enum fs_file_type_t type, + const char* name, + uint8_t name_len) { + (void)handle; + (void)type; + (void)name; + (void)name_len; + + logging_log_error("Attempted to create virtual file %s (%u)", name, type); + return 0; +} + static struct fs_mount_t vfs_mount = { .parent = &vfs_mount, .stat = vfs_stat, .dirst = vfs_dirst, .dirls = vfs_dirls, - .diren = vfs_diren + .diren = vfs_diren, + .create = vfs_create, }; static uint8_t vfs_lock; @@ -129,6 +149,36 @@ void fs_init(void) { vfs_root.info.type = FS_TYPE_DIR; } +static inline struct fs_node_t* init_node( + struct fs_node_t* node, + struct fs_file_handle_t* handle, + const char* name, + uint8_t name_len) { + enum fs_status_t status; + struct fs_info_t info; + + if ((status = node->mount->stat(handle, &info)) != FS_STATUS_OK) { + return 0; + } + + struct fs_node_t* sub = kmalloc(sizeof(struct fs_node_t)); + + sub->accesses = 0; + sub->co = 0; + sub->handle = handle; + sub->mount = node->mount; + sub->name_len = name_len; + sub->name = kmalloc(name_len + 1); + kmemcpy(sub->name, name, name_len); + sub->name[name_len] = 0; + sub->parent = node; + sub->status = 0; + sub->sub = 0; + sub->info = info; + + return sub; +} + static inline enum fs_status_t assert_consistent(struct fs_node_t* node, uint8_t clear) { if (node->status & VFS_STATUS_CONSISTENT) { return FS_STATUS_OK; @@ -137,13 +187,9 @@ static inline enum fs_status_t assert_consistent(struct fs_node_t* node, uint8_t if (node->sub && clear) { logging_log_error("Detected corrupt vfs state. Inconsistent non-leaf node"); panic(PANIC_STATE); - } - struct fs_info_t info; - enum fs_status_t status; - + } struct fs_ls_info_t file; - struct fs_node_t* temp; struct fs_dirls_handle_t* handle = node->mount->dirst(node->handle); if (!handle) { @@ -154,27 +200,15 @@ static inline enum fs_status_t assert_consistent(struct fs_node_t* node, uint8_t if (!file.valid) { continue; } - - if ((status = node->mount->stat(file.handle, &info)) != FS_STATUS_OK) { + + struct fs_node_t* temp = init_node(node, file.handle, file.name, file.name_len); + if (!temp) { node->mount->diren(handle); - return status; + return FS_STATUS_ERROR; } - temp = node->sub; - node->sub = kmalloc(sizeof(struct fs_node_t)); - - node->sub->accesses = 0; - node->sub->co = temp; - node->sub->handle = file.handle; - node->sub->mount = node->mount; - node->sub->name_len = file.name_len; - node->sub->name = kmalloc(file.name_len + 1); - kmemcpy(node->sub->name, file.name, file.name_len); - node->sub->name[file.name_len] = 0; - node->sub->parent = node; - node->sub->status = 0; - node->sub->sub = 0; - node->sub->info = info; + temp->co = node->sub; + node->sub = temp; } node->mount->diren(handle); @@ -269,38 +303,14 @@ static void cleanup_path(struct fs_node_t* root, const char* path) { (void)path; } -struct fs_file_t* fs_open(const char* path) { - struct fs_node_t* node = resolve_path(&vfs_root, simplify_path(path)); - - if (!node) { - return 0; - } - - struct fs_file_t* file = kmalloc(sizeof(struct fs_file_t)); - file->node = node; - return file; -} - -void fs_close(struct fs_file_t* file) { - lock_acquire(&vfs_lock); - cleanup_path(&vfs_root, simplify_path(file->node->name)); - lock_release(&vfs_lock); - - kfree(file); -} - -enum fs_status_t fs_stat(struct fs_file_t* file, struct fs_info_t* info) { - *info = file->node->info; - return FS_STATUS_OK; -} - extern enum fs_status_t fs_mount( struct fs_file_handle_t* root, const char* path, fs_stat_t stat, fs_dirst_t dirst, fs_dirls_t dirls, - fs_diren_t diren) { + fs_diren_t diren, + fs_create_t create) { lock_acquire(&vfs_lock); @@ -318,6 +328,7 @@ extern enum fs_status_t fs_mount( mount->dirst = dirst; mount->dirls = dirls; mount->diren = diren; + mount->create = create; node->mount = mount; node->handle = root; @@ -343,6 +354,76 @@ extern enum fs_status_t fs_mount( return FS_STATUS_OK; } +struct fs_file_t* fs_open(const char* path) { + lock_acquire(&vfs_lock); + struct fs_node_t* node = resolve_path(&vfs_root, simplify_path(path)); + lock_release(&vfs_lock); + + if (!node) { + return 0; + } + + struct fs_file_t* file = kmalloc(sizeof(struct fs_file_t)); + file->node = node; + file->seek.off = 0; + return file; +} + +void fs_close(struct fs_file_t* file) { + lock_acquire(&vfs_lock); + cleanup_path(&vfs_root, simplify_path(file->node->name)); + lock_release(&vfs_lock); + + kfree(file); +} + +enum fs_status_t fs_stat(struct fs_file_t* file, struct fs_info_t* info) { + *info = file->node->info; + return FS_STATUS_OK; +} + +enum fs_status_t fs_list(struct fs_file_t* file, char* buffer) { + + if (!file->seek.dir) { + lock_acquire(&vfs_lock); + file->seek.dir = file->node->sub; + lock_release(&vfs_lock); + } + + if (!file->seek.dir) { + return FS_STATUS_EOF; + } + + kmemcpy(buffer, file->seek.dir->name, file->seek.dir->name_len); + buffer[file->seek.dir->name_len] = 0; + + lock_acquire(&vfs_lock); + file->seek.dir = file->seek.dir->co; + lock_release(&vfs_lock); + + return FS_STATUS_OK; +} + +enum fs_status_t fs_create(struct fs_file_t* file, enum fs_file_type_t type, const char* name) { + uint8_t name_len; + for (name_len = 0; name[name_len]; name_len++); //TODO: use strlen + + lock_acquire(&vfs_lock); + struct fs_file_handle_t* handle = file->node->mount->create(file->node->handle, type, name, name_len); + + if (!handle) { + lock_release(&vfs_lock); + return FS_STATUS_ERROR; + } + + struct fs_node_t* node = init_node(file->node, handle, name, name_len); + node->co = file->node->sub; + file->node->sub = node; + + lock_release(&vfs_lock); + return FS_STATUS_OK; +} + #ifdef DEBUG static void fs_log_tree(struct fs_node_t* node, char* prefix, size_t prefix_len) { diff --git a/kernel/core/mm.c b/kernel/core/mm.c index 2a77341..2fdbb97 100644 --- a/kernel/core/mm.c +++ b/kernel/core/mm.c @@ -80,19 +80,24 @@ static void free_node(struct mm_tree_node_t* node) { } static struct mm_tree_node_t* find_base_node(uint64_t base, struct mm_tree_node_t* root, struct mm_tree_node_t* parent) { - if (!root) { - return parent; - } + while (1) { + if (!root) { + return parent; + } - if (WITHIN_NODE(base, root->base, root->limit)) { - return root; - } + if (WITHIN_NODE(base, root->base, root->limit)) { + return root; + } - if (base < root->base) { - return find_base_node(base, root->less, root); - } + parent = root; - return find_base_node(base, root->more, root); + if (base < root->base) { + root = root->less; + } + else { + root = root->more; + } + } } static void attach_node(struct mm_tree_node_t* root, struct mm_tree_node_t* node) { diff --git a/kernel/include/core/fs.h b/kernel/include/core/fs.h index 3009bf2..aa70566 100644 --- a/kernel/include/core/fs.h +++ b/kernel/include/core/fs.h @@ -58,6 +58,12 @@ typedef struct fs_dirls_handle_t* (*fs_dirst_t)(struct fs_file_handle_t* handle) typedef enum fs_status_t (*fs_dirls_t)(struct fs_dirls_handle_t** handle, struct fs_ls_info_t* file); typedef void (*fs_diren_t)(struct fs_dirls_handle_t* handle); +typedef struct fs_file_handle_t* (*fs_create_t)( + struct fs_file_handle_t* handle, + enum fs_file_type_t type, + const char* name, + uint8_t name_len); + extern void fs_init(void); extern enum fs_status_t fs_mount( @@ -66,11 +72,14 @@ extern enum fs_status_t fs_mount( fs_stat_t stat, fs_dirst_t dirst, fs_dirls_t dirls, - fs_diren_t diren); + fs_diren_t diren, + fs_create_t create); extern struct fs_file_t* fs_open(const char* path); extern void fs_close(struct fs_file_t* file); extern enum fs_status_t fs_stat(struct fs_file_t* file, struct fs_info_t* info); +extern enum fs_status_t fs_list(struct fs_file_t* file, char* buffer); +extern enum fs_status_t fs_create(struct fs_file_t* file, enum fs_file_type_t type, const char* name); #ifdef DEBUG extern void fs_log_vfs_tree(void); From a2ccb0f4fefa68b101c6b6c1ee1a59dce2f7d4e0 Mon Sep 17 00:00:00 2001 From: Ebrahim Aleem Date: Mon, 6 Apr 2026 22:02:15 -0700 Subject: [PATCH 07/12] stack guard pages and vfs wip --- Makefile | 4 +- boot/multiboot2/boot.S | 11 + boot/multiboot2/init.c | 13 + drivers/apic/apic_init.c | 45 ++- drivers/ext2/ext2.c | 19 +- kernel/core/alloc.c | 4 + kernel/core/ap.S | 1 + kernel/core/cpu_instr.S | 5 + kernel/core/fs.c | 543 +++++++++++++++++--------------- kernel/core/idt.c | 2 +- kernel/core/kentry.c | 10 +- kernel/core/mm.c | 7 + kernel/core/paging.c | 8 + kernel/core/panic.c | 3 + kernel/core/process.c | 65 +++- kernel/core/scheduler.c | 3 +- kernel/include/core/cpu_instr.h | 2 + kernel/include/core/fs.h | 51 ++- kernel/include/core/kentry.h | 2 - kernel/include/core/paging.h | 2 + kernel/include/core/process.h | 16 +- kernel/include/lib/kstrcmp.h | 23 ++ kernel/include/lib/kstrcpy.h | 26 ++ kernel/include/lib/kstrlen.h | 25 ++ kernel/lib/kstrcmp.c | 27 ++ kernel/lib/kstrcpy.c | 39 +++ kernel/lib/kstrlen.c | 28 ++ test/lib/test.c | 50 +++ 28 files changed, 715 insertions(+), 319 deletions(-) create mode 100644 kernel/include/lib/kstrcmp.h create mode 100644 kernel/include/lib/kstrcpy.h create mode 100644 kernel/include/lib/kstrlen.h create mode 100644 kernel/lib/kstrcmp.c create mode 100644 kernel/lib/kstrcpy.c create mode 100644 kernel/lib/kstrlen.c diff --git a/Makefile b/Makefile index 15af1a7..3445f3e 100644 --- a/Makefile +++ b/Makefile @@ -43,7 +43,7 @@ export BUILD_DRIVERS_HPET = 1 export BUILD_DRIVERS_AHCI = 1 export BUILD_DRIVERS_GPT = 1 -export BUILD_DRIVERS_EXT2 = 1 +#export BUILD_DRIVERS_EXT2 = 1 # End of options @@ -100,7 +100,7 @@ test-all: $(TEST_CANIDATES) .PHONY: $(TEST_CANIDATES) $(TEST_CANIDATES): test-%: $(OBJ_DIR)/test_% - ./$< + -./$< .PHONY: $(SUBDIRS) $(SUBDIRS): diff --git a/boot/multiboot2/boot.S b/boot/multiboot2/boot.S index 31f0fb1..a69fec4 100644 --- a/boot/multiboot2/boot.S +++ b/boot/multiboot2/boot.S @@ -231,6 +231,10 @@ ktransfer: pushq $0 pushq $0 call multiboot2_init + movq init_stack_vaddr, %rsp + addq $0x5000, %rsp + pushq $0 + pushq $0 jmp kentry .section .data.boot @@ -330,3 +334,10 @@ stack: .rept STACK_SIZE .byte 0 .endr + + /* pointer to guarded stack */ +.globl init_stack_vaddr + init_stack_vaddr: .quad 0 + +.globl init_stack_paddr + init_stack_paddr: .quad 0 diff --git a/boot/multiboot2/init.c b/boot/multiboot2/init.c index b9fae84..85a5849 100644 --- a/boot/multiboot2/init.c +++ b/boot/multiboot2/init.c @@ -21,6 +21,7 @@ #include #include +#include #include #include #include @@ -104,6 +105,9 @@ extern volatile struct gdt_t gdt[GDT_NUM_ENTRIES]; static volatile struct mb2_tag_t* memmap_tag; +extern uint64_t init_stack_paddr; +extern uint64_t init_stack_vaddr; + static void first_segment(uint64_t* handle) { *handle = 0; } @@ -202,6 +206,15 @@ void multiboot2_init(struct mb2_info_t* info) { i = (i + 7) & ~MOD8_MASK; } + init_stack_paddr = mm_alloc_p(PAGE_SIZE_4K * 4); + init_stack_vaddr = mm_alloc_v(PAGE_SIZE_4K * 5); + + paging_map(init_stack_vaddr + PAGE_SIZE_4K * 1, init_stack_paddr + PAGE_SIZE_4K * 1, PAGE_PRESENT | PAGE_RW, PAGE_4K); + paging_map(init_stack_vaddr + PAGE_SIZE_4K * 2, init_stack_paddr + PAGE_SIZE_4K * 2, PAGE_PRESENT | PAGE_RW, PAGE_4K); + paging_map(init_stack_vaddr + PAGE_SIZE_4K * 3, init_stack_paddr + PAGE_SIZE_4K * 3, PAGE_PRESENT | PAGE_RW, PAGE_4K); + paging_map(init_stack_vaddr + PAGE_SIZE_4K * 4, init_stack_paddr + PAGE_SIZE_4K * 4, PAGE_PRESENT | PAGE_RW, PAGE_4K); + paging_install_guard(init_stack_vaddr); + boot_context.gdt = &gdt; return; } diff --git a/drivers/apic/apic_init.c b/drivers/apic/apic_init.c index c31106b..bb9b33b 100644 --- a/drivers/apic/apic_init.c +++ b/drivers/apic/apic_init.c @@ -96,7 +96,8 @@ extern uint8_t gdt; extern uint8_t gdt_end; extern uint8_t kernel_pml4; -uint64_t* init_stacks; +uint64_t* init_stacks_paddr; +uint64_t* init_stacks_vaddr; volatile struct gdt_t(** ap_gdts)[GDT_NUM_ENTRIES]; volatile struct gdt_ptr_64_t** ap_gdt_ptr_64; uint8_t* ap_init_locks; @@ -121,7 +122,8 @@ void apic_init(void) { apic_init_ap(); // init stacks - init_stacks = kmalloc(sizeof(uint64_t*) * num_apic); + init_stacks_vaddr = kmalloc(sizeof(uint64_t) * num_apic); + init_stacks_paddr = kmalloc(sizeof(uint64_t) * num_apic); proc_data_ptr = kmalloc(sizeof(struct proc_data_t*) * num_apic); proc_data_ptr[0] = &bsp_proc_data; @@ -132,7 +134,42 @@ void apic_init(void) { for (--num_apic; num_apic; num_apic--) { proc_data_ptr[num_apic] = kmalloc(sizeof(struct proc_data_t)); - init_stacks[num_apic] = (uint64_t)kmalloc(INIT_STACK_SIZE) + INIT_STACK_SIZE; + init_stacks_vaddr[num_apic] = mm_alloc_v(PAGE_SIZE_4K * 5); + + if (!init_stacks_vaddr[num_apic]) { + logging_log_error("Failed to allocate stack"); + panic(PANIC_NO_MEM); + } + + init_stacks_paddr[num_apic] = mm_alloc_p(PAGE_SIZE_4K * 4); + + if (!init_stacks_paddr[num_apic]) { + logging_log_error("Failed to allocate stack"); + mm_free_v(init_stacks_vaddr[num_apic], PAGE_SIZE_4K * 5); + panic(PANIC_NO_MEM); + } + + paging_map( + init_stacks_vaddr[num_apic] + PAGE_SIZE_4K * 1, + init_stacks_paddr[num_apic] + PAGE_SIZE_4K * 1, + PAGE_PRESENT | PAGE_RW, + PAGE_4K); + paging_map( + init_stacks_vaddr[num_apic] + PAGE_SIZE_4K * 2, + init_stacks_paddr[num_apic] + PAGE_SIZE_4K * 2, + PAGE_PRESENT | PAGE_RW, + PAGE_4K); + paging_map( + init_stacks_vaddr[num_apic] + PAGE_SIZE_4K * 3, + init_stacks_paddr[num_apic] + PAGE_SIZE_4K * 3, + PAGE_PRESENT | PAGE_RW, + PAGE_4K); + paging_map( + init_stacks_vaddr[num_apic] + PAGE_SIZE_4K * 4, + init_stacks_paddr[num_apic] + PAGE_SIZE_4K * 4, + PAGE_PRESENT | PAGE_RW, + PAGE_4K); + paging_install_guard(init_stacks_vaddr[num_apic]); ap_gdts[num_apic] = kmalloc(sizeof(struct gdt_t[GDT_NUM_ENTRIES])); ap_gdt_ptr_64[num_apic] = kmalloc(sizeof(struct gdt_ptr_64_t)); @@ -315,7 +352,7 @@ void apic_start_ap(void) { (uint16_t)((uint64_t)&gdt_end - (uint64_t)&gdt - 1); // gdt64 ptr *(volatile uint64_t*)paging_ident(AP_ARB_BASE + 0xa) = (uint64_t)&gdt; *(volatile uint32_t*)paging_ident(AP_ARB_BASE + 0x12) = (uint32_t)(uint64_t)&kernel_pml4; - *(volatile uint64_t*)paging_ident(AP_ARB_BASE + 0x16) = (uint64_t)init_stacks; + *(volatile uint64_t*)paging_ident(AP_ARB_BASE + 0x16) = (uint64_t)init_stacks_vaddr; uint64_t handle; struct acpi_madt_ics_local_apic_t* local_apic; diff --git a/drivers/ext2/ext2.c b/drivers/ext2/ext2.c index 3cc3453..c8aff47 100644 --- a/drivers/ext2/ext2.c +++ b/drivers/ext2/ext2.c @@ -450,6 +450,8 @@ static enum fs_status_t ext2_dirls(struct fs_dirls_handle_t** handle, struct fs_ struct ext2_ll_dir_entry_t* entry = (struct ext2_ll_dir_entry_t*)((uint64_t)buffer + dt->off); + logging_log_info("directory entry %x, %x, %x", entry->inode, entry->name_len, entry->rec_len); + if (entry->inode != 0) { if (entry->name[0] == '.' && (entry->name_len == 1 || (entry->name_len == 2 && entry->name[1] == '.'))) { file->valid = 0; @@ -476,14 +478,6 @@ static void ext2_diren(struct fs_dirls_handle_t* handle) { kfree(handle); } -static struct fs_file_handle_t* ext2_create( - struct fs_file_handle_t* handle, - enum fs_file_type_t type, - const char* name, - uint8_t name_len) { - return 0; -} - uint8_t ext2_attempt_init(struct disk_t* disk, uint64_t start_lba, uint64_t end_lba) { struct ext2_superblock_t* superblock = kmalloc(sizeof(struct ext2_superblock_t)); struct ext2_inode_handle_t* root_handle; @@ -534,11 +528,10 @@ uint8_t ext2_attempt_init(struct disk_t* disk, uint64_t start_lba, uint64_t end_ if (!kmemcmp(label_rootfs, superblock->s_volume_name, sizeof(superblock->s_volume_name))) { if (fs_mount((struct fs_file_handle_t*)root_handle, "/", + ext2_open, + ext2_close, ext2_stat, - ext2_dirst, - ext2_dirls, - ext2_diren, - ext2_create + ext2_read_dir, ) != FS_STATUS_OK) { logging_log_error("Failed to mount rootfs"); panic(PANIC_STATE); @@ -561,8 +554,6 @@ uint8_t ext2_attempt_init(struct disk_t* disk, uint64_t start_lba, uint64_t end_ fs_close(root_file); } - fs_log_vfs_tree(); - //TODO: mount other volumes return 1; diff --git a/kernel/core/alloc.c b/kernel/core/alloc.c index eb155ea..b413663 100644 --- a/kernel/core/alloc.c +++ b/kernel/core/alloc.c @@ -25,6 +25,7 @@ #include #include #include +#include #define HEADER_SIZE_MASK 0xFFFFFFFFFFFFFFF8uLL #define HEADER_USED 0x1uLL @@ -151,6 +152,9 @@ void kfree(void* ptr) { struct alloc_header_t* header = (struct alloc_header_t*)((uint64_t)ptr - sizeof(struct alloc_header_t)); if (!(header->header & HEADER_USED)) { logging_log_warning("Double free @ 0x%lx", ptr); +#ifdef DEBUG + cpu_trap(); +#endif /* DEBUG */ return; } diff --git a/kernel/core/ap.S b/kernel/core/ap.S index b1b8ea5..981e8eb 100644 --- a/kernel/core/ap.S +++ b/kernel/core/ap.S @@ -111,6 +111,7 @@ movb %bl, %dil movq AP_STACKS, %rax movq (%rax,%rdi,8), %rsp +addq $0x5000, %rsp // switch to correct gdt movq ap_gdt_ptr_64, %rax diff --git a/kernel/core/cpu_instr.S b/kernel/core/cpu_instr.S index 9c178a6..f789d1a 100644 --- a/kernel/core/cpu_instr.S +++ b/kernel/core/cpu_instr.S @@ -56,3 +56,8 @@ cpu_halt_loop: cli hlt jmp cpu_halt_loop + +.globl cpu_trap +cpu_trap: +// setting a breakpoint here will catch traps +ret diff --git a/kernel/core/fs.c b/kernel/core/fs.c index b5c488c..44a1042 100644 --- a/kernel/core/fs.c +++ b/kernel/core/fs.c @@ -25,17 +25,154 @@ #include #include +#include +#include +#include +/* +struct vfs_mount_t { + fs_stat_t stat; + fs_opendir_t opendir; + fs_closedir_t closedir; +}; + +struct vfs_node_t { + struct vfs_node_t* co; + struct vfs_node_t* sub; + + const char* name; + struct vfs_mount_t* mount; +}; + +static struct vfs_node_t vfs_root; +static struct vfs_mount_t vfs_mount; +static uint8_t vfs_lock; + +static inline const char* simplify_path(const char* path) { + while ( + *path == '/' || + (*path == '.' && (*(path+1) == '/' || !*(path+1)))) { + path++; + } + + return path; +} + +static inline const char* path_next(const char* path, uint8_t* len) { + *len = 0; + + while (*path && *path != '/') { + path++; + (*len)++; + } + + return simplify_path(path); +} + +static struct vfs_node_t* resolve_sub_path(struct vfs_node_t* root, const char* path) { + struct vfs_node_t* walk, * node; + const char* next = path; + uint8_t len; + + path = path_next(path, &len); + + for (walk = root->sub; walk; walk = walk->co) { + if (len == kstrlen(walk->name) && kmemcmp(walk->name, next, len) == 0) { + if (*next) { + return resolve_sub_path(walk, path); + } + + return walk; + } + } + + struct fs_file_open_handle_t* file = root->mount->opendir(root->handle); + + if (!file) { + return 0; + } + + char* buffer = kmalloc(256); + struct fs_file_handle_t* handle; + while (root->mount->read_dir(file, &handle, buffer) == FS_STATUS_OK) { + if (kstrcmp(buffer, next) == 0) { + walk = init_node(root, handle, buffer); + if (!walk) { + kfree(buffer); + return 0; + } + + walk->co = root->sub; + root->sub = walk; + + root->mount->close(file); + + if (*next) { + node = resolve_sub_path(walk, path); + if (node) { + walk->accesses++; + return node; + } + return 0; + } + + walk->accesses++; + return walk; + } + } + + + root->mount->close(file); + kfree(buffer); + return 0; +} + +static struct fs_node_t* resolve_absolute_path(const char* path) { + path = simplify_path(path); + + if (kstrcmp(path, "") == 0) { + return &vfs_root; + } + + return resolve_sub_path(&vfs_root, path); +} + +void fs_init(void) { + vfs_root.co = 0; + vfs_root.sub = 0; + vfs_root.name = ""; + vfs_root.mount = 0; + + lock_init(&vfs_lock); +} + +void fs_mount( + const char* path, + fs_stat_t stat, + fs_opendir_t opendir, + fs_closedir_t closedir) { +} + + + +*/ + + + + + + -#define VFS_STATUS_CONSISTENT 0x1 -#define VFS_STATUS_MOUNTED 0x2 + +/* old implementation */ + +#define VFS_STATUS_MOUNTED 0x1 struct fs_mount_t { struct fs_mount_t* parent; + fs_open_t open; + fs_close_t close; fs_stat_t stat; - fs_dirst_t dirst; - fs_dirls_t dirls; - fs_diren_t diren; - fs_create_t create; + fs_read_dir_t read_dir; }; struct fs_node_t { @@ -49,176 +186,117 @@ struct fs_node_t { uint64_t accesses; - char* name; + const char* name; struct fs_info_t info; - uint8_t name_len; uint8_t status; }; -struct fs_file_t { - struct fs_node_t* node; - struct fs_info_t info; - union { - uint64_t off; - struct fs_node_t* dir; - } seek; +struct vfs_file_open_handle_t { + struct fs_node_t* walk; }; -enum node_res_t { - NODE_RES_TRUE, - NODE_RES_FALSE, - NODE_RES_LAST, - NODE_RES_PARENT, -}; +static struct fs_file_open_handle_t* vfs_open(struct fs_file_handle_t* handle) { + struct fs_node_t* node = (struct fs_node_t*)handle; + struct vfs_file_open_handle_t* open; -static enum fs_status_t vfs_stat(struct fs_file_handle_t* handle, struct fs_info_t* info) { - (void)handle; + open = kmalloc(sizeof(struct vfs_file_open_handle_t)); + open->walk = node->sub; + return (struct fs_file_open_handle_t*)open; +} + +static void vfs_close(struct fs_file_open_handle_t* handle) { + kfree(handle); +} +static enum fs_status_t vfs_stat(struct fs_file_open_handle_t* handle, struct fs_info_t* info) { + (void)handle; info->size = 0; info->type = FS_TYPE_DIR; return FS_STATUS_OK; } -static struct fs_dirls_handle_t* vfs_dirst(struct fs_file_handle_t* handle) { - struct fs_node_t* node = (struct fs_node_t*)handle; - return (struct fs_dirls_handle_t*)node->sub; -} - -static enum fs_status_t vfs_dirls(struct fs_dirls_handle_t** handle, struct fs_ls_info_t* file) { - if (!handle) { +static enum fs_status_t vfs_read_dir(struct fs_file_open_handle_t* handle, struct fs_file_handle_t** file, char* name) { + struct vfs_file_open_handle_t* open = (struct vfs_file_open_handle_t*)handle; + if (!open->walk) { return FS_STATUS_EOF; } - struct fs_node_t* walk = (struct fs_node_t*)*handle; - - file->handle = (struct fs_file_handle_t*)walk; - kmemcpy(file->name, walk->name, walk->name_len); - file->name_len = walk->name_len; - - *handle = (struct fs_dirls_handle_t*)walk->co; + *file = open->walk->handle; + kstrcpy(name, open->walk->name); + open->walk = open->walk->co; return FS_STATUS_OK; } -static void vfs_diren(struct fs_dirls_handle_t* handle) { - (void)handle; -} - -static struct fs_file_handle_t* vfs_create( - struct fs_file_handle_t* handle, - enum fs_file_type_t type, - const char* name, - uint8_t name_len) { - (void)handle; - (void)type; - (void)name; - (void)name_len; - - logging_log_error("Attempted to create virtual file %s (%u)", name, type); - return 0; -} - static struct fs_mount_t vfs_mount = { .parent = &vfs_mount, + .open = vfs_open, + .close = vfs_close, .stat = vfs_stat, - .dirst = vfs_dirst, - .dirls = vfs_dirls, - .diren = vfs_diren, - .create = vfs_create, + .read_dir = vfs_read_dir }; -static uint8_t vfs_lock; static struct fs_node_t vfs_root; +static uint8_t vfs_lock; + void fs_init(void) { lock_init(&vfs_lock); - vfs_root.sub = 0; + vfs_root.handle = (struct fs_file_handle_t*)&vfs_root; vfs_root.co = 0; + vfs_root.sub = 0; vfs_root.parent = &vfs_root; vfs_root.mount = &vfs_mount; - vfs_root.name = (char*)""; - vfs_root.status = VFS_STATUS_CONSISTENT; - vfs_root.name_len = 0; - vfs_root.handle = (struct fs_file_handle_t*)&vfs_root; + vfs_root.name = ""; + vfs_root.status = 0; vfs_root.accesses = 1; vfs_root.info.size = 0; vfs_root.info.type = FS_TYPE_DIR; } static inline struct fs_node_t* init_node( - struct fs_node_t* node, + struct fs_node_t* parent, struct fs_file_handle_t* handle, - const char* name, - uint8_t name_len) { + const char* name) { + + struct fs_node_t* node; enum fs_status_t status; struct fs_info_t info; - if ((status = node->mount->stat(handle, &info)) != FS_STATUS_OK) { - return 0; - } + struct fs_file_open_handle_t* open = parent->mount->open(handle); - struct fs_node_t* sub = kmalloc(sizeof(struct fs_node_t)); - - sub->accesses = 0; - sub->co = 0; - sub->handle = handle; - sub->mount = node->mount; - sub->name_len = name_len; - sub->name = kmalloc(name_len + 1); - kmemcpy(sub->name, name, name_len); - sub->name[name_len] = 0; - sub->parent = node; - sub->status = 0; - sub->sub = 0; - sub->info = info; - - return sub; -} - -static inline enum fs_status_t assert_consistent(struct fs_node_t* node, uint8_t clear) { - if (node->status & VFS_STATUS_CONSISTENT) { - return FS_STATUS_OK; + if (!open) { + return 0; } - if (node->sub && clear) { - logging_log_error("Detected corrupt vfs state. Inconsistent non-leaf node"); - panic(PANIC_STATE); - } - - struct fs_ls_info_t file; - struct fs_dirls_handle_t* handle = node->mount->dirst(node->handle); + status = parent->mount->stat(open, &info); + parent->mount->close(open); - if (!handle) { - return FS_STATUS_ERROR; + if (status != FS_STATUS_OK) { + return 0; } - while (node->mount->dirls(&handle, &file) == FS_STATUS_OK) { - if (!file.valid) { - continue; - } - - struct fs_node_t* temp = init_node(node, file.handle, file.name, file.name_len); - if (!temp) { - node->mount->diren(handle); - return FS_STATUS_ERROR; - } - temp->co = node->sub; - node->sub = temp; - } - - node->mount->diren(handle); + node = kmalloc(sizeof(struct fs_node_t)); - node->status |= VFS_STATUS_CONSISTENT; + node->handle = handle; + node->co = 0; + node->sub = 0; + node->parent = parent; + node->mount = parent->mount; + node->name = name; + node->status = 0; + node->accesses = 0; + node->info = info; - return FS_STATUS_OK; + return node; } -static inline const char* simplify_path(const char* path) { +static const inline char* simplify_path(const char* path) { while ( *path == '/' || (*path == '.' && (*(path+1) == '/' || !*(path+1)))) { @@ -228,73 +306,89 @@ static inline const char* simplify_path(const char* path) { return path; } -static inline const char* check_path(struct fs_node_t* node, const char* path, enum node_res_t* res) { - uint8_t i = 0; - const char* start; +static inline const char* path_next(const char* path, uint8_t* len) { + *len = 0; - for (start = path; *path && *path != '/'; path++) { - i++; + while (*path && *path != '/') { + path++; + (*len)++; } - - path = simplify_path(path); - - *res = NODE_RES_FALSE; - if (i == node->name_len && !kmemcmp(node->name, start, i)) { - if (!*path) { - *res = NODE_RES_LAST; - } - else { - *res = NODE_RES_TRUE; - } - } + return simplify_path(path); +} - if (i == 2 && !kmemcmp("..", start, i)) { - *res = NODE_RES_PARENT; - } +static struct fs_node_t* resolve_sub_path(struct fs_node_t* root, const char* path) { + struct fs_node_t* walk, * node; + const char* next = path; + uint8_t len; - return path; -} + path = path_next(path, &len); -static struct fs_node_t* resolve_path(struct fs_node_t* root, const char* path) { - enum node_res_t res; - struct fs_node_t* node, * walk; + for (walk = root->sub; walk; walk = walk->co) { + if (len == kstrlen(walk->name) && kmemcmp(walk->name, next, len) == 0) { + if (*next) { + node = resolve_sub_path(walk, path); + if (node) { + walk->accesses++; + return node; + } + return 0; + } - path = check_path(root, path, &res); + walk->accesses++; + return walk; + } + } - switch (res) { - case NODE_RES_LAST: - root->accesses++; - return root; + struct fs_file_open_handle_t* file = root->mount->open(root->handle); - case NODE_RES_PARENT: - node = resolve_path(root->parent, path); - if (node) { - root->parent->accesses--; - } - return node; + if (!file) { + return 0; + } - case NODE_RES_TRUE: - if (root->info.type != FS_TYPE_DIR) { + char* buffer = kmalloc(256); + struct fs_file_handle_t* handle; + while (root->mount->read_dir(file, &handle, buffer) == FS_STATUS_OK) { + if (kstrcmp(buffer, next) == 0) { + walk = init_node(root, handle, buffer); + if (!walk) { + kfree(buffer); return 0; } - if (assert_consistent(root, 1) != FS_STATUS_OK) { - return 0; - } + walk->co = root->sub; + root->sub = walk; - for (walk = root->sub; walk; walk = walk->co) { - node = resolve_path(walk, path); + root->mount->close(file); + + if (*next) { + node = resolve_sub_path(walk, path); if (node) { - root->accesses++; + walk->accesses++; return node; } + return 0; } - __attribute__((fallthrough)); - case NODE_RES_FALSE: - default: - return 0; + + walk->accesses++; + return walk; + } } + + + root->mount->close(file); + kfree(buffer); + return 0; +} + +static struct fs_node_t* resolve_absolute_path(const char* path) { + path = simplify_path(path); + + if (kstrcmp(path, "") == 0) { + return &vfs_root; + } + + return resolve_sub_path(&vfs_root, path); } static void cleanup_path(struct fs_node_t* root, const char* path) { @@ -306,17 +400,17 @@ static void cleanup_path(struct fs_node_t* root, const char* path) { extern enum fs_status_t fs_mount( struct fs_file_handle_t* root, const char* path, + fs_open_t open, + fs_close_t close, fs_stat_t stat, - fs_dirst_t dirst, - fs_dirls_t dirls, - fs_diren_t diren, - fs_create_t create) { + fs_read_dir_t read_dir) { lock_acquire(&vfs_lock); - struct fs_node_t* node = resolve_path(&vfs_root, path); + struct fs_node_t* node = resolve_absolute_path(path); if (node->status & VFS_STATUS_MOUNTED) { + lock_release(&vfs_lock); return FS_STATUS_BUSY; } @@ -324,11 +418,11 @@ extern enum fs_status_t fs_mount( revert = *node; struct fs_mount_t* mount = kmalloc(sizeof(struct fs_mount_t)); mount->parent = node->mount; + + mount->open = open; + mount->close = close; mount->stat = stat; - mount->dirst = dirst; - mount->dirls = dirls; - mount->diren = diren; - mount->create = create; + mount->read_dir = read_dir; node->mount = mount; node->handle = root; @@ -339,122 +433,49 @@ extern enum fs_status_t fs_mount( if (status != FS_STATUS_OK) { kfree(mount); *node = revert; + lock_release(&vfs_lock); return status; } node->info = info; - if ((status = assert_consistent(node, 0)) != FS_STATUS_OK) { - kfree(mount); - *node = revert; - return status; - } - lock_release(&vfs_lock); return FS_STATUS_OK; } struct fs_file_t* fs_open(const char* path) { lock_acquire(&vfs_lock); - struct fs_node_t* node = resolve_path(&vfs_root, simplify_path(path)); + struct fs_node_t* node = resolve_absolute_path(path); lock_release(&vfs_lock); if (!node) { return 0; } - struct fs_file_t* file = kmalloc(sizeof(struct fs_file_t)); - file->node = node; - file->seek.off = 0; - return file; + return (struct fs_file_t*)node; } void fs_close(struct fs_file_t* file) { + struct fs_node_t* node = (struct fs_node_t*)file; + lock_acquire(&vfs_lock); - cleanup_path(&vfs_root, simplify_path(file->node->name)); + cleanup_path(&vfs_root, simplify_path(node->name)); lock_release(&vfs_lock); - - kfree(file); } enum fs_status_t fs_stat(struct fs_file_t* file, struct fs_info_t* info) { - *info = file->node->info; - return FS_STATUS_OK; -} - -enum fs_status_t fs_list(struct fs_file_t* file, char* buffer) { - - if (!file->seek.dir) { - lock_acquire(&vfs_lock); - file->seek.dir = file->node->sub; - lock_release(&vfs_lock); - } - - if (!file->seek.dir) { - return FS_STATUS_EOF; - } - - kmemcpy(buffer, file->seek.dir->name, file->seek.dir->name_len); - buffer[file->seek.dir->name_len] = 0; - - lock_acquire(&vfs_lock); - file->seek.dir = file->seek.dir->co; - lock_release(&vfs_lock); + struct fs_node_t* node = (struct fs_node_t*)file; + *info = node->info; return FS_STATUS_OK; } -enum fs_status_t fs_create(struct fs_file_t* file, enum fs_file_type_t type, const char* name) { - uint8_t name_len; - for (name_len = 0; name[name_len]; name_len++); //TODO: use strlen +enum fs_status_t fs_read_dir(struct fs_file_t* file, char* buffer) { + struct fs_node_t* node = (struct fs_node_t*)file; lock_acquire(&vfs_lock); - struct fs_file_handle_t* handle = file->node->mount->create(file->node->handle, type, name, name_len); - - if (!handle) { - lock_release(&vfs_lock); - return FS_STATUS_ERROR; - } - - struct fs_node_t* node = init_node(file->node, handle, name, name_len); - node->co = file->node->sub; - file->node->sub = node; - + enum fs_status_t sts = node->mount->read_dir(node->handle, buffer, ""); lock_release(&vfs_lock); - return FS_STATUS_OK; -} - -#ifdef DEBUG - -static void fs_log_tree(struct fs_node_t* node, char* prefix, size_t prefix_len) { - logging_log_debug("vfs tree: %s%256s (%u/0x%lx)", prefix, node->name, node->info.type, node->info.size); - - if (node->info.type != FS_TYPE_DIR) { - return; - } - - if (assert_consistent(node, 1) != FS_STATUS_OK) { - logging_log_error("Failed to log vfs tree"); - return; - } - - char* new_prefix = kmalloc(prefix_len + 2); - kmemcpy(new_prefix+2, prefix, prefix_len); - new_prefix[0] = new_prefix[1] = ' '; - for (struct fs_node_t* walk = node->sub; walk; walk = walk->co) { - fs_log_tree(walk, new_prefix, prefix_len + 2); - } - - kfree(new_prefix); + return sts; } - -void fs_log_vfs_tree(void) { - lock_acquire(&vfs_lock); - - fs_log_tree(&vfs_root, (char*)"", 1); - - lock_release(&vfs_lock); -} - -#endif /* DEBUG */ diff --git a/kernel/core/idt.c b/kernel/core/idt.c index 92ef1fe..d0187e6 100644 --- a/kernel/core/idt.c +++ b/kernel/core/idt.c @@ -50,7 +50,7 @@ void idt_init(void) { idt_install(0x00, (uint64_t)isr_00, GDT_CODE_SEL, 0, IDT_GATE_TRP, 0); idt_install(0x01, (uint64_t)isr_01, GDT_CODE_SEL, 0, IDT_GATE_TRP, 0); idt_install(0x02, (uint64_t)isr_02, GDT_CODE_SEL, 0, IDT_GATE_TRP, 0); - idt_install(0x03, (uint64_t)isr_03, GDT_CODE_SEL, 0, IDT_GATE_TRP, 0); + //idt_install(0x03, (uint64_t)isr_03, GDT_CODE_SEL, 0, IDT_GATE_TRP, 0); idt_install(0x04, (uint64_t)isr_04, GDT_CODE_SEL, 0, IDT_GATE_TRP, 0); idt_install(0x05, (uint64_t)isr_05, GDT_CODE_SEL, 0, IDT_GATE_TRP, 0); idt_install(0x06, (uint64_t)isr_06, GDT_CODE_SEL, 0, IDT_GATE_TRP, 0); diff --git a/kernel/core/kentry.c b/kernel/core/kentry.c index 5ba3d72..c821d03 100644 --- a/kernel/core/kentry.c +++ b/kernel/core/kentry.c @@ -55,6 +55,12 @@ extern uint8_t ap_bootstrap_end; extern volatile struct gdt_t(** ap_gdts)[GDT_NUM_ENTRIES]; extern uint8_t* ap_init_locks; +extern uint64_t init_stack_vaddr; +extern uint64_t init_stack_paddr; + +extern uint64_t* init_stacks_paddr; +extern uint64_t* init_stacks_vaddr; + void kentry(void) { logging_log_debug("Kernel Entry"); @@ -66,7 +72,7 @@ void kentry(void) { logging_log_debug("TSS and IDT init"); tss_init((void*)paging_ident((uint64_t)boot_context.gdt)); - process_init(0); + process_init(init_stack_vaddr, init_stack_paddr); idt_init(); scheduler_init(); logging_log_debug("TSS and IDT init done"); @@ -127,7 +133,7 @@ void kapentry(uint64_t arb_id) { logging_log_debug("AP TSS and IDT init"); tss_init(ap_gdts[proc_data_get()->arb_id]); - process_init_ap(init_stacks[arb_id] - INIT_STACK_SIZE); + process_init_ap(init_stacks_vaddr[arb_id], init_stacks_paddr[arb_id]); idt_init_ap(); logging_log_debug("AP TSS and IDT init done"); diff --git a/kernel/core/mm.c b/kernel/core/mm.c index 2fdbb97..278c4a9 100644 --- a/kernel/core/mm.c +++ b/kernel/core/mm.c @@ -24,6 +24,7 @@ #include #include #include +#include #include @@ -184,9 +185,15 @@ static void mm_free(uint64_t base, uint64_t size, struct mm_tree_node_t* root, u if (WITHIN_NODE(base, node->base, node->limit)) { if (root == p_tree) { logging_log_warning("Double free @ 0x%lx on p_tree", base); +#ifdef DEBUG + cpu_trap(); +#endif /* DEBUG */ } else { logging_log_warning("Double free @ 0x%lx on v_tree", base); +#ifdef DEBUG + cpu_trap(); +#endif /* DEBUG */ } } else if (base < node->base) { diff --git a/kernel/core/paging.c b/kernel/core/paging.c index c8b281c..9b7981b 100644 --- a/kernel/core/paging.c +++ b/kernel/core/paging.c @@ -148,3 +148,11 @@ void paging_unmap(uint64_t vaddr, enum page_size_t page_size) { uint64_t paging_ident(uint64_t paddr) { return paddr + IDENT_BASE; } + +void paging_install_guard(uint64_t vaddr) { + //TODO, and install ISR +} + +void paging_remove_guard(uint64_t vaddr) { + //TODO +} diff --git a/kernel/core/panic.c b/kernel/core/panic.c index 51c7274..f6c1faf 100644 --- a/kernel/core/panic.c +++ b/kernel/core/panic.c @@ -37,5 +37,8 @@ void panic(enum panic_code_t code) { logging_log_error("Panic 0x%lX %s", (uint64_t)code, panic_names[code] ? panic_names[code] : panic_names[PANIC_UNK]); +#ifdef DEBUG + cpu_trap(); +#endif /* DEBUG */ process_kill_current(); } diff --git a/kernel/core/process.c b/kernel/core/process.c index 1445b92..570d32f 100644 --- a/kernel/core/process.c +++ b/kernel/core/process.c @@ -26,12 +26,16 @@ #include #include #include +#include +#include #include #define INIT_RFLG 0x200 #define INIT_STACK_SIZE 0x4000 +// change manual paging map when adjusting stack size + static uint64_t next_pid; static uint8_t lock_proc; @@ -40,10 +44,10 @@ __attribute__((noreturn)) static void function_setup(process_function_t func, vo process_kill_current(); } -void process_init(uint64_t init_rsp) { +void process_init(uint64_t init_rsp_vaddr, uint64_t init_rsp_paddr) { next_pid = 1; lock_init(&lock_proc); - process_init_ap(init_rsp); + process_init_ap(init_rsp_vaddr, init_rsp_paddr); } static uint64_t assign_pid(void) { @@ -57,17 +61,45 @@ uint64_t process_get_pid(void) { return proc_data_get()->current_process->pid; } -void process_init_ap(uint64_t init_rsp) { +void process_init_ap(uint64_t init_rsp_vaddr, uint64_t init_rsp_paddr) { struct pcb_t* pcb = kmalloc(sizeof(struct pcb_t)); - pcb->init_rsp = init_rsp; - pcb->init_k_rsp = 0; + pcb->init_rsp_vaddr = init_rsp_vaddr; + pcb->init_rsp_paddr = init_rsp_paddr; + pcb->init_k_rsp_vaddr = + pcb->init_k_rsp_paddr = 0; pcb->sched_cntr = SCHED_SKIP; proc_data_get()->current_process = pcb; proc_data_get()->current_process->pid = assign_pid(); } struct pcb_t* process_from_vaddr(uint64_t vaddr) { - struct pcb_t* pcb = kmalloc(sizeof(struct pcb_t)); + struct pcb_t* pcb; + uint64_t stack_vaddr; + uint64_t stack_paddr; + + stack_vaddr = mm_alloc_v(INIT_STACK_SIZE + PAGE_SIZE_4K); // extra guard page + if (!stack_vaddr) { + logging_log_error("Failed to allocate stack"); + panic(PANIC_NO_MEM); + } + + stack_paddr = mm_alloc_p(INIT_STACK_SIZE); + if (!stack_paddr) { + mm_free_v(stack_vaddr, INIT_STACK_SIZE + PAGE_SIZE_4K); + logging_log_error("Failed to allocate stack"); + panic(PANIC_NO_MEM); + } + + _Static_assert(INIT_STACK_SIZE == 4 * PAGE_SIZE_4K, "stack size must be page size multiple of four"); + // add for increased stack size + paging_map(stack_vaddr + 1 * PAGE_SIZE_4K, stack_paddr + 0 * PAGE_SIZE_4K, PAGE_PRESENT | PAGE_RW, PAGE_4K); + paging_map(stack_vaddr + 2 * PAGE_SIZE_4K, stack_paddr + 1 * PAGE_SIZE_4K, PAGE_PRESENT | PAGE_RW, PAGE_4K); + paging_map(stack_vaddr + 3 * PAGE_SIZE_4K, stack_paddr + 2 * PAGE_SIZE_4K, PAGE_PRESENT | PAGE_RW, PAGE_4K); + paging_map(stack_vaddr + 4 * PAGE_SIZE_4K, stack_paddr + 3 * PAGE_SIZE_4K, PAGE_PRESENT | PAGE_RW, PAGE_4K); + // leave last page unmapped as guard + paging_install_guard(stack_vaddr); + + pcb = kmalloc(sizeof(struct pcb_t)); pcb->rax = pcb->rbx = @@ -85,10 +117,12 @@ struct pcb_t* process_from_vaddr(uint64_t vaddr) { pcb->r14 = pcb->r15 = 0; - pcb->rsp = - pcb->init_rsp = (uint64_t)kmalloc(INIT_STACK_SIZE); - pcb->init_k_rsp = 0; - pcb->rsp += INIT_STACK_SIZE; + pcb->rsp = stack_vaddr + PAGE_SIZE_4K * 5; + pcb->init_rsp_vaddr = stack_vaddr; + pcb->init_rsp_paddr = stack_paddr; + + pcb->init_k_rsp_vaddr = + pcb->init_k_rsp_paddr = 0; pcb->k_rsp_lo = 0; pcb->k_rsp_hi = 0; @@ -125,7 +159,16 @@ void process_kill_current(void) { } void process_discard(struct pcb_t* pcb) { - kfree((void*)pcb->init_rsp); + _Static_assert(INIT_STACK_SIZE == 4 * PAGE_SIZE_4K, "stack size must be page size multiple of four"); + paging_unmap(pcb->init_rsp_vaddr + 1 * PAGE_SIZE_4K, PAGE_4K); + paging_unmap(pcb->init_rsp_vaddr + 2 * PAGE_SIZE_4K, PAGE_4K); + paging_unmap(pcb->init_rsp_vaddr + 3 * PAGE_SIZE_4K, PAGE_4K); + paging_unmap(pcb->init_rsp_vaddr + 4 * PAGE_SIZE_4K, PAGE_4K); + paging_remove_guard(pcb->init_rsp_vaddr); + + mm_free_v(pcb->init_rsp_vaddr, INIT_STACK_SIZE + PAGE_SIZE_4K); + mm_free_p(pcb->init_rsp_paddr, INIT_STACK_SIZE); + kfree(pcb); } diff --git a/kernel/core/scheduler.c b/kernel/core/scheduler.c index be58fd8..7bd8dfe 100644 --- a/kernel/core/scheduler.c +++ b/kernel/core/scheduler.c @@ -58,8 +58,7 @@ void scheduler_run(void) { process_resume(current_pcb); break; case SCHED_KILL: - kfree((void*)current_pcb->init_rsp); - kfree((void*)current_pcb->init_k_rsp); + process_discard(current_pcb); break; default: scheduler_schedule(current_pcb); diff --git a/kernel/include/core/cpu_instr.h b/kernel/include/core/cpu_instr.h index c832800..1bfa65a 100644 --- a/kernel/include/core/cpu_instr.h +++ b/kernel/include/core/cpu_instr.h @@ -36,4 +36,6 @@ extern void cpu_wait_loop(void) __attribute__((noreturn)); extern void cpu_halt_loop(void) __attribute__((noreturn)); +extern void cpu_trap(void); + #endif /* KERNEL_CORE_CPU_INSTR_H */ diff --git a/kernel/include/core/fs.h b/kernel/include/core/fs.h index aa70566..1e80c57 100644 --- a/kernel/include/core/fs.h +++ b/kernel/include/core/fs.h @@ -20,6 +20,33 @@ #include #include +/* +struct fs_dir_handle_t; + +enum fs_status_t { + FS_STATUS_OK, + FS_STATUS_ERROR +}; + +struct fs_stat_buf_t { +}; + +typedef enum fs_status_t (*fs_stat_t)(const char* path, struct fs_stat_buf_t* stat_buf); +typedef struct fs_dir_handle_t* (*fs_opendir_t)(const char* path); +typedef void (*fs_closedir_t)(struct fs_dir_handle_t* handle); +typedef enum fs_status_t (*fs_readdir_t)(struct fs_dir_handle_t* handle, const char** name); + +extern void fs_init(void); + +extern void fs_mount( + const char* path, + fs_stat_t stat, + fs_opendir_t opendir, + fs_closedir_t closedir, + fs_readdir_t readdir); +*/ + +/* old interface */ enum fs_file_type_t { FS_TYPE_FILE, @@ -52,11 +79,12 @@ struct fs_dirls_handle_t; extern void fs_init(void); -typedef enum fs_status_t (*fs_stat_t)(struct fs_file_handle_t* handle, struct fs_info_t* info); -typedef struct fs_dirls_handle_t* (*fs_dirst_t)(struct fs_file_handle_t* handle); -typedef enum fs_status_t (*fs_dirls_t)(struct fs_dirls_handle_t** handle, struct fs_ls_info_t* file); -typedef void (*fs_diren_t)(struct fs_dirls_handle_t* handle); +typedef struct fs_file_open_handle_t* (*fs_open_t)(struct fs_file_handle_t* handle); +typedef void (*fs_close_t)(struct fs_file_open_handle_t* handle); + +typedef enum fs_status_t (*fs_stat_t)(struct fs_file_open_handle_t* handle, struct fs_info_t* info); +typedef enum fs_status_t (*fs_read_dir_t)(struct fs_file_open_handle_t* handle, struct fs_file_handle_t** file, char* name); typedef struct fs_file_handle_t* (*fs_create_t)( struct fs_file_handle_t* handle, @@ -69,20 +97,15 @@ extern void fs_init(void); extern enum fs_status_t fs_mount( struct fs_file_handle_t* root, const char* path, + fs_open_t open, + fs_close_t close, fs_stat_t stat, - fs_dirst_t dirst, - fs_dirls_t dirls, - fs_diren_t diren, - fs_create_t create); + fs_read_dir_t read_dir); extern struct fs_file_t* fs_open(const char* path); extern void fs_close(struct fs_file_t* file); -extern enum fs_status_t fs_stat(struct fs_file_t* file, struct fs_info_t* info); -extern enum fs_status_t fs_list(struct fs_file_t* file, char* buffer); -extern enum fs_status_t fs_create(struct fs_file_t* file, enum fs_file_type_t type, const char* name); -#ifdef DEBUG -extern void fs_log_vfs_tree(void); -#endif /* DEBUG */ +extern enum fs_status_t fs_stat(struct fs_file_t* file, struct fs_info_t* info); +extern enum fs_status_t fs_read_dir(struct fs_file_t* file, char* buffer); #endif /* KERNEL_CORE_FS_H */ diff --git a/kernel/include/core/kentry.h b/kernel/include/core/kentry.h index c8b8c29..0f6f1c1 100644 --- a/kernel/include/core/kentry.h +++ b/kernel/include/core/kentry.h @@ -25,8 +25,6 @@ #include -#define INIT_STACK_SIZE 0x4000 - #ifdef GRAPHICSBASE #include #endif /* GRAPHICSBASE */ diff --git a/kernel/include/core/paging.h b/kernel/include/core/paging.h index 82319a7..3bd7fe8 100644 --- a/kernel/include/core/paging.h +++ b/kernel/include/core/paging.h @@ -47,5 +47,7 @@ extern uint64_t paging_map(uint64_t vaddr, uint64_t paddr, uint16_t flg, enum pa extern void paging_unmap(uint64_t vaddr, enum page_size_t page_size); extern uint64_t paging_ident(uint64_t paddr); +extern void paging_install_guard(uint64_t vaddr); +extern void paging_remove_guard(uint64_t vaddr); #endif /* KERNEL_CORE_PAGING_H */ diff --git a/kernel/include/core/process.h b/kernel/include/core/process.h index da49c6b..ee2a369 100644 --- a/kernel/include/core/process.h +++ b/kernel/include/core/process.h @@ -51,16 +51,20 @@ struct pcb_t { uint64_t pid; uint32_t k_rsp_lo; uint32_t k_rsp_hi; - uint64_t init_rsp; - uint64_t init_k_rsp; + uint64_t init_rsp_vaddr; + uint64_t init_rsp_paddr; + uint64_t init_k_rsp_vaddr; + uint64_t init_k_rsp_paddr; + + struct pcb_t* next; + enum { SCHED_READY, SCHED_KILL, SCHED_SKIP } sched_cntr; - struct pcb_t* next; -}; +} __attribute__((packed)); struct preempt_frame_t { uint64_t rbp; @@ -90,9 +94,9 @@ typedef void (*process_function_t)(void* cntx); extern uint64_t process_get_pid(void); -extern void process_init(uint64_t init_rsp); +extern void process_init(uint64_t init_rsp_vaddr, uint64_t init_rsp_paddr); -extern void process_init_ap(uint64_t init_rsp); +extern void process_init_ap(uint64_t init_rsp_vaddr, uint64_t init_rsp_paddr); extern struct pcb_t* process_from_vaddr(uint64_t vaddr); diff --git a/kernel/include/lib/kstrcmp.h b/kernel/include/lib/kstrcmp.h new file mode 100644 index 0000000..03d008f --- /dev/null +++ b/kernel/include/lib/kstrcmp.h @@ -0,0 +1,23 @@ +/* kstrcmp.h - kernel string compare interface */ +/* Copyright (C) 2026 Ebrahim Aleem +* +* This program is free software: you can redistribute it and/or modify +* it under the terms of the GNU General Public License as published by +* the Free Software Foundation, either version 3 of the License, or +* (at your option) any later version. +* +* This program is distributed in the hope that it will be useful, +* but WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +* GNU General Public License for more details. +* +* You should have received a copy of the GNU General Public License +* along with this program. If not, see +*/ + +#ifndef KERNEL_LIB_KSTRCMP_H +#define KERNEL_LIB_KSTRCMP_H + +extern int kstrcmp(const char* s1, const char* s2); + +#endif /* KERNEL_LIB_KSTRCMP_H */ diff --git a/kernel/include/lib/kstrcpy.h b/kernel/include/lib/kstrcpy.h new file mode 100644 index 0000000..b591a4c --- /dev/null +++ b/kernel/include/lib/kstrcpy.h @@ -0,0 +1,26 @@ +/* kstrcpy.h - kernel string copy interface */ +/* Copyright (C) 2026 Ebrahim Aleem +* +* This program is free software: you can redistribute it and/or modify +* it under the terms of the GNU General Public License as published by +* the Free Software Foundation, either version 3 of the License, or +* (at your option) any later version. +* +* This program is distributed in the hope that it will be useful, +* but WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +* GNU General Public License for more details. +* +* You should have received a copy of the GNU General Public License +* along with this program. If not, see +*/ + +#ifndef KERNEL_LIB_KSTRCPY_H +#define KERNEL_LIB_KSTRCPY_H + +extern char* kstrcpy(char* dest, const char* src); + +extern char* kstrcpy_no_null(char* dest, const char* src); + +#endif /* KERNEL_LIB_KSTRCPY_H */ + diff --git a/kernel/include/lib/kstrlen.h b/kernel/include/lib/kstrlen.h new file mode 100644 index 0000000..45a3485 --- /dev/null +++ b/kernel/include/lib/kstrlen.h @@ -0,0 +1,25 @@ +/* kstrlen.h - kernel strlen interface */ +/* Copyright (C) 2026 Ebrahim Aleem +* +* This program is free software: you can redistribute it and/or modify +* it under the terms of the GNU General Public License as published by +* the Free Software Foundation, either version 3 of the License, or +* (at your option) any later version. +* +* This program is distributed in the hope that it will be useful, +* but WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +* GNU General Public License for more details. +* +* You should have received a copy of the GNU General Public License +* along with this program. If not, see +*/ + +#ifndef KERNEL_LIB_KSTRLEN_H +#define KERNEL_LIB_KSTRLEN_H + +#include + +extern size_t kstrlen(const char* s); + +#endif /* KERNEL_LIB_KSTRLEN_H */ diff --git a/kernel/lib/kstrcmp.c b/kernel/lib/kstrcmp.c new file mode 100644 index 0000000..e5b04d4 --- /dev/null +++ b/kernel/lib/kstrcmp.c @@ -0,0 +1,27 @@ +/* kstrcmp.c - kernel string compare implementation */ +/* Copyright (C) 2026 Ebrahim Aleem +* +* This program is free software: you can redistribute it and/or modify +* it under the terms of the GNU General Public License as published by +* the Free Software Foundation, either version 3 of the License, or +* (at your option) any later version. +* +* This program is distributed in the hope that it will be useful, +* but WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +* GNU General Public License for more details. +* +* You should have received a copy of the GNU General Public License +* along with this program. If not, see +*/ + +#include + +int kstrcmp(const char* s1, const char* s2) { + while (*s1 && *s2 && *s1 == *s2) { + s1++; + s2++; + } + + return (int)(*s1 - *s2); +} diff --git a/kernel/lib/kstrcpy.c b/kernel/lib/kstrcpy.c new file mode 100644 index 0000000..a24e571 --- /dev/null +++ b/kernel/lib/kstrcpy.c @@ -0,0 +1,39 @@ +/* kstrcpy.c - kernel string copy implementation */ +/* Copyright (C) 2026 Ebrahim Aleem +* +* This program is free software: you can redistribute it and/or modify +* it under the terms of the GNU General Public License as published by +* the Free Software Foundation, either version 3 of the License, or +* (at your option) any later version. +* +* This program is distributed in the hope that it will be useful, +* but WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +* GNU General Public License for more details. +* +* You should have received a copy of the GNU General Public License +* along with this program. If not, see +*/ + +#include + +char* kstrcpy(char* dest, const char* src) { + while (*src) { + *dest = *src; + src++; + dest++; + } + + *dest = 0; + return dest + 1; +} + +char* kstrcpy_no_null(char* dest, const char* src) { + while (*src) { + *dest = *src; + src++; + dest++; + } + + return dest; +} diff --git a/kernel/lib/kstrlen.c b/kernel/lib/kstrlen.c new file mode 100644 index 0000000..4140dab --- /dev/null +++ b/kernel/lib/kstrlen.c @@ -0,0 +1,28 @@ +/* kstrlen.c - kernel strlen implementation */ +/* Copyright (C) 2026 Ebrahim Aleem +* +* This program is free software: you can redistribute it and/or modify +* it under the terms of the GNU General Public License as published by +* the Free Software Foundation, either version 3 of the License, or +* (at your option) any later version. +* +* This program is distributed in the hope that it will be useful, +* but WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +* GNU General Public License for more details. +* +* You should have received a copy of the GNU General Public License +* along with this program. If not, see +*/ + +#include + +#include + +size_t kstrlen(const char* s) { + size_t size = 0; + for (; *s; s++) size++; + + return size; +} + diff --git a/test/lib/test.c b/test/lib/test.c index 88ae2ca..d180e56 100644 --- a/test/lib/test.c +++ b/test/lib/test.c @@ -18,12 +18,16 @@ #include #include #include +#include #include #include #include #include +#include +#include +#include #include #define MEM_TEST_SIZE 256 @@ -67,6 +71,52 @@ TEST("kmemcpy") { free(copy); } +TEST("kstrlen") { + ASSERT_TRUE(kstrlen("") == 0, "fails empty string"); + ASSERT_TRUE(kstrlen("1") == 1, "fails 1 string"); + ASSERT_TRUE(kstrlen("12") == 2, "fails 12 string"); + ASSERT_TRUE(kstrlen("\t\n\r\0") == 3, "fails control character string"); +} + +TEST("kstrcpy") { + char* original = malloc(MEM_TEST_SIZE); + char* copy = malloc(MEM_TEST_SIZE); + + for (uint64_t i = 0; i < MEM_TEST_SIZE - 1; i += (i % 7) + 1) { + original[i] = (char)(i ^ (i * i)) | 1; + } + + kstrcpy(copy, original); + ASSERT_TRUE(!strcmp(original, copy), "string comparison fails"); + + free(original); + free(copy); +} + +TEST("kstrcpy_no_null") { + char* original = malloc(MEM_TEST_SIZE); + char* copy = malloc(MEM_TEST_SIZE); + + for (uint64_t i = 0; i < MEM_TEST_SIZE - 1; i += (i % 7) + 1) { + original[i] = (char)(i ^ (i * i)) | 1; + } + copy[MEM_TEST_SIZE - 1] = 0xAA; + + kstrcpy_no_null(copy, original); + ASSERT_TRUE(!memcmp(original, copy, strlen(original)), "string comparison fails"); + ASSERT_TRUE(copy[MEM_TEST_SIZE - 1] == (char)0xAA, "overwritten ending byte"); + + free(original); + free(copy); +} + +TEST("kstrcmp") { + ASSERT_TRUE(kstrcmp("", "") == 0, "kernel memcmp fails zero size"); + ASSERT_TRUE(kstrcmp(" a", " b") < 0, "kernel strcmp flips sign"); + ASSERT_TRUE(kstrcmp(" 4", " 2") > 0, "kernel strcmp flips sign"); + ASSERT_TRUE(kstrcmp(" a\0b", " a\0c") == 0, "kernel strcmp reads too many bytes"); +} + TEST("hash_byte_sum") { ASSERT_TRUE(hash_byte_sum((uint8_t*)0xdeadbeef, 0) == 0, "fails invalid ptr"); ASSERT_TRUE(hash_byte_sum((uint8_t*)"\0\1\2\3\0\0\1\2", 8) == 9, "fails basic sum"); From 6780ae6feae86c0830d8df35500f6136c119c3a8 Mon Sep 17 00:00:00 2001 From: Ebrahim Aleem Date: Tue, 7 Apr 2026 10:41:28 -0700 Subject: [PATCH 08/12] stack guard page handler --- boot/multiboot2/init.c | 8 +++--- drivers/apic/apic_init.c | 8 +++--- kernel/core/cpu_instr.S | 5 ++++ kernel/core/exception_dispatch.c | 14 +++++++++ kernel/core/idt.c | 4 +-- kernel/core/paging.c | 49 ++++++++++++++++++++++++++++++-- kernel/core/panic.c | 3 +- kernel/core/tss.c | 5 ++++ kernel/include/core/cpu_instr.h | 2 ++ kernel/include/core/paging.h | 1 + kernel/include/core/tss.h | 1 + 11 files changed, 87 insertions(+), 13 deletions(-) diff --git a/boot/multiboot2/init.c b/boot/multiboot2/init.c index 85a5849..fc1f7b6 100644 --- a/boot/multiboot2/init.c +++ b/boot/multiboot2/init.c @@ -209,10 +209,10 @@ void multiboot2_init(struct mb2_info_t* info) { init_stack_paddr = mm_alloc_p(PAGE_SIZE_4K * 4); init_stack_vaddr = mm_alloc_v(PAGE_SIZE_4K * 5); - paging_map(init_stack_vaddr + PAGE_SIZE_4K * 1, init_stack_paddr + PAGE_SIZE_4K * 1, PAGE_PRESENT | PAGE_RW, PAGE_4K); - paging_map(init_stack_vaddr + PAGE_SIZE_4K * 2, init_stack_paddr + PAGE_SIZE_4K * 2, PAGE_PRESENT | PAGE_RW, PAGE_4K); - paging_map(init_stack_vaddr + PAGE_SIZE_4K * 3, init_stack_paddr + PAGE_SIZE_4K * 3, PAGE_PRESENT | PAGE_RW, PAGE_4K); - paging_map(init_stack_vaddr + PAGE_SIZE_4K * 4, init_stack_paddr + PAGE_SIZE_4K * 4, PAGE_PRESENT | PAGE_RW, PAGE_4K); + paging_map(init_stack_vaddr + PAGE_SIZE_4K * 1, init_stack_paddr + PAGE_SIZE_4K * 0, PAGE_PRESENT | PAGE_RW, PAGE_4K); + paging_map(init_stack_vaddr + PAGE_SIZE_4K * 2, init_stack_paddr + PAGE_SIZE_4K * 1, PAGE_PRESENT | PAGE_RW, PAGE_4K); + paging_map(init_stack_vaddr + PAGE_SIZE_4K * 3, init_stack_paddr + PAGE_SIZE_4K * 2, PAGE_PRESENT | PAGE_RW, PAGE_4K); + paging_map(init_stack_vaddr + PAGE_SIZE_4K * 4, init_stack_paddr + PAGE_SIZE_4K * 3, PAGE_PRESENT | PAGE_RW, PAGE_4K); paging_install_guard(init_stack_vaddr); boot_context.gdt = &gdt; diff --git a/drivers/apic/apic_init.c b/drivers/apic/apic_init.c index bb9b33b..386c90d 100644 --- a/drivers/apic/apic_init.c +++ b/drivers/apic/apic_init.c @@ -151,22 +151,22 @@ void apic_init(void) { paging_map( init_stacks_vaddr[num_apic] + PAGE_SIZE_4K * 1, - init_stacks_paddr[num_apic] + PAGE_SIZE_4K * 1, + init_stacks_paddr[num_apic] + PAGE_SIZE_4K * 0, PAGE_PRESENT | PAGE_RW, PAGE_4K); paging_map( init_stacks_vaddr[num_apic] + PAGE_SIZE_4K * 2, - init_stacks_paddr[num_apic] + PAGE_SIZE_4K * 2, + init_stacks_paddr[num_apic] + PAGE_SIZE_4K * 1, PAGE_PRESENT | PAGE_RW, PAGE_4K); paging_map( init_stacks_vaddr[num_apic] + PAGE_SIZE_4K * 3, - init_stacks_paddr[num_apic] + PAGE_SIZE_4K * 3, + init_stacks_paddr[num_apic] + PAGE_SIZE_4K * 2, PAGE_PRESENT | PAGE_RW, PAGE_4K); paging_map( init_stacks_vaddr[num_apic] + PAGE_SIZE_4K * 4, - init_stacks_paddr[num_apic] + PAGE_SIZE_4K * 4, + init_stacks_paddr[num_apic] + PAGE_SIZE_4K * 3, PAGE_PRESENT | PAGE_RW, PAGE_4K); paging_install_guard(init_stacks_vaddr[num_apic]); diff --git a/kernel/core/cpu_instr.S b/kernel/core/cpu_instr.S index f789d1a..bf6619d 100644 --- a/kernel/core/cpu_instr.S +++ b/kernel/core/cpu_instr.S @@ -61,3 +61,8 @@ jmp cpu_halt_loop cpu_trap: // setting a breakpoint here will catch traps ret + +.globl read_cr2 +read_cr2: +movq %cr2, %rax +ret diff --git a/kernel/core/exception_dispatch.c b/kernel/core/exception_dispatch.c index 9b66fab..e6f6d9d 100644 --- a/kernel/core/exception_dispatch.c +++ b/kernel/core/exception_dispatch.c @@ -20,6 +20,10 @@ #include #include #include +#include +#include + +#define VECTOR_PF 0xE void exception_dispatch(struct exception_context_t* context) { //TODO: remove reduntant rsp push @@ -36,5 +40,15 @@ void exception_dispatch(struct exception_context_t* context) { context->r12, context->r13, context->r14, context->r15, context->rflags, context->cs, context->ss, context->rip); + switch (context->vector) { + case VECTOR_PF: + if (paging_check_guard(read_cr2())) { + logging_log_error("Stack Overflow"); + } + break; + default: + break; + } + panic(PANIC_STATE); } diff --git a/kernel/core/idt.c b/kernel/core/idt.c index d0187e6..d504a89 100644 --- a/kernel/core/idt.c +++ b/kernel/core/idt.c @@ -50,7 +50,7 @@ void idt_init(void) { idt_install(0x00, (uint64_t)isr_00, GDT_CODE_SEL, 0, IDT_GATE_TRP, 0); idt_install(0x01, (uint64_t)isr_01, GDT_CODE_SEL, 0, IDT_GATE_TRP, 0); idt_install(0x02, (uint64_t)isr_02, GDT_CODE_SEL, 0, IDT_GATE_TRP, 0); - //idt_install(0x03, (uint64_t)isr_03, GDT_CODE_SEL, 0, IDT_GATE_TRP, 0); + idt_install(0x03, (uint64_t)isr_03, GDT_CODE_SEL, 0, IDT_GATE_TRP, 0); idt_install(0x04, (uint64_t)isr_04, GDT_CODE_SEL, 0, IDT_GATE_TRP, 0); idt_install(0x05, (uint64_t)isr_05, GDT_CODE_SEL, 0, IDT_GATE_TRP, 0); idt_install(0x06, (uint64_t)isr_06, GDT_CODE_SEL, 0, IDT_GATE_TRP, 0); @@ -61,7 +61,7 @@ void idt_init(void) { idt_install(0x0b, (uint64_t)isr_0b, GDT_CODE_SEL, 0, IDT_GATE_TRP, 0); idt_install(0x0c, (uint64_t)isr_0c, GDT_CODE_SEL, 0, IDT_GATE_TRP, 0); idt_install(0x0d, (uint64_t)isr_0d, GDT_CODE_SEL, 0, IDT_GATE_TRP, 0); - idt_install(0x0e, (uint64_t)isr_0e, GDT_CODE_SEL, 0, IDT_GATE_TRP, 0); + idt_install(0x0e, (uint64_t)isr_0e, GDT_CODE_SEL, IST_PF, IDT_GATE_TRP, 0); idt_install(0x10, (uint64_t)isr_10, GDT_CODE_SEL, 0, IDT_GATE_TRP, 0); idt_install(0x11, (uint64_t)isr_11, GDT_CODE_SEL, 0, IDT_GATE_TRP, 0); idt_install(0x12, (uint64_t)isr_12, GDT_CODE_SEL, IST_ABORT, IDT_GATE_INT, 0); diff --git a/kernel/core/paging.c b/kernel/core/paging.c index 9b7981b..9ed6aaa 100644 --- a/kernel/core/paging.c +++ b/kernel/core/paging.c @@ -44,6 +44,13 @@ extern uint64_t kernel_pml4[512]; static uint8_t paging_lock; +struct addr_list_t { + struct addr_list_t* next; + uint64_t addr; +}; + +static struct addr_list_t* stack_guard_list; + static enum page_size_t page_walk(uint64_t vaddr, uint64_t** access) { uint64_t entry; *access = (uint64_t*)paging_ident((uint64_t)&kernel_pml4[0]); @@ -83,6 +90,8 @@ static enum page_size_t page_walk(uint64_t vaddr, uint64_t** access) { void paging_init(void) { lock_init(&paging_lock); + + stack_guard_list = 0; } uint64_t paging_map(uint64_t vaddr, uint64_t paddr, uint16_t flg, enum page_size_t page_size) { @@ -150,9 +159,45 @@ uint64_t paging_ident(uint64_t paddr) { } void paging_install_guard(uint64_t vaddr) { - //TODO, and install ISR + struct addr_list_t* guard = kmalloc(sizeof(struct addr_list_t)); + guard->addr = vaddr & PAGE_ADDR_MASK; + + lock_acquire(&paging_lock); + guard->next = stack_guard_list; + stack_guard_list = guard; + lock_release(&paging_lock); } void paging_remove_guard(uint64_t vaddr) { - //TODO + struct addr_list_t* i, ** prev = &stack_guard_list; + + lock_acquire(&paging_lock); + for (i = stack_guard_list; i; i = i->next) { + if (i->addr == vaddr) { + *prev = i->next; + kfree(i); + break; + } + + prev = &i->next; + } + + lock_release(&paging_lock); +} + +uint8_t paging_check_guard(uint64_t vaddr) { + struct addr_list_t* i; + uint64_t addr = vaddr & PAGE_ADDR_MASK; + uint8_t ret = 0; + + lock_acquire(&paging_lock); + for (i = stack_guard_list; i; i = i->next) { + if (i->addr == addr) { + ret = 1; + break; + } + } + lock_release(&paging_lock); + + return ret; } diff --git a/kernel/core/panic.c b/kernel/core/panic.c index f6c1faf..6fa34a5 100644 --- a/kernel/core/panic.c +++ b/kernel/core/panic.c @@ -40,5 +40,6 @@ void panic(enum panic_code_t code) { #ifdef DEBUG cpu_trap(); #endif /* DEBUG */ - process_kill_current(); + + cpu_halt_loop(); } diff --git a/kernel/core/tss.c b/kernel/core/tss.c index 800550d..fdc1408 100644 --- a/kernel/core/tss.c +++ b/kernel/core/tss.c @@ -29,6 +29,7 @@ #define IST_ABORT_SIZE 0x1000 #define IST_SCHED_SIZE 0x1000 +#define IST_PF_SIZE 0x1000 #define IST_LO_MASK 0xFFFFFFFF #define IST_HI_SHFT 32 @@ -48,6 +49,10 @@ void tss_init(volatile struct gdt_t(* gdt)[GDT_NUM_ENTRIES]) { tss->ist2_lo = ist2 & IST_LO_MASK; tss->ist2_hi = (uint32_t)(ist2 >> IST_HI_SHFT); + const uint64_t ist3 = (uint64_t)kmalloc(IST_SCHED_SIZE) + IST_SCHED_SIZE; + tss->ist3_lo = ist3 & IST_LO_MASK; + tss->ist3_hi = (uint32_t)(ist3 >> IST_HI_SHFT); + logging_log_debug("New TSS @ 0x%lX - 0x%lX 0x%lX (ist1) 0x%lX (ist2)", (uint64_t)tss, ist1, ist2); diff --git a/kernel/include/core/cpu_instr.h b/kernel/include/core/cpu_instr.h index 1bfa65a..0ac5366 100644 --- a/kernel/include/core/cpu_instr.h +++ b/kernel/include/core/cpu_instr.h @@ -38,4 +38,6 @@ extern void cpu_halt_loop(void) __attribute__((noreturn)); extern void cpu_trap(void); +extern uint64_t read_cr2(void); + #endif /* KERNEL_CORE_CPU_INSTR_H */ diff --git a/kernel/include/core/paging.h b/kernel/include/core/paging.h index 3bd7fe8..a1e2122 100644 --- a/kernel/include/core/paging.h +++ b/kernel/include/core/paging.h @@ -49,5 +49,6 @@ extern uint64_t paging_ident(uint64_t paddr); extern void paging_install_guard(uint64_t vaddr); extern void paging_remove_guard(uint64_t vaddr); +extern uint8_t paging_check_guard(uint64_t vaddr); #endif /* KERNEL_CORE_PAGING_H */ diff --git a/kernel/include/core/tss.h b/kernel/include/core/tss.h index f201afd..9913cf9 100644 --- a/kernel/include/core/tss.h +++ b/kernel/include/core/tss.h @@ -22,6 +22,7 @@ #define IST_ABORT 1 #define IST_SCHED 2 +#define IST_PF 3 struct tss_t { uint32_t resv0; From 9808eac1e7de6dba3b920b5f1aefd3addadc116f Mon Sep 17 00:00:00 2001 From: Ebrahim Aleem Date: Tue, 7 Apr 2026 14:20:10 -0700 Subject: [PATCH 09/12] stat root dir --- Makefile | 2 +- drivers/ext2/ext2.c | 155 +++--------- kernel/core/exception_dispatch.c | 81 +++++- kernel/core/fs.c | 419 ++++--------------------------- kernel/include/core/fs.h | 100 ++------ 5 files changed, 179 insertions(+), 578 deletions(-) diff --git a/Makefile b/Makefile index 3445f3e..3337156 100644 --- a/Makefile +++ b/Makefile @@ -43,7 +43,7 @@ export BUILD_DRIVERS_HPET = 1 export BUILD_DRIVERS_AHCI = 1 export BUILD_DRIVERS_GPT = 1 -#export BUILD_DRIVERS_EXT2 = 1 +export BUILD_DRIVERS_EXT2 = 1 # End of options diff --git a/drivers/ext2/ext2.c b/drivers/ext2/ext2.c index c8aff47..d16a460 100644 --- a/drivers/ext2/ext2.c +++ b/drivers/ext2/ext2.c @@ -186,6 +186,10 @@ static void* read_block(uint64_t block, struct ext2_t* ext2) { const uint64_t lba = ext2->start_lba + block * block_size / SECTOR_SIZE; + if (lba > ext2->end_lba) { + logging_log_error("Attempt to read beyond ext2 end lba (0x%x > 0x%x)", lba, ext2->end_lba); + } + if (disk_read(ext2->disk, buffer, lba, (uint16_t)(block_size / SECTOR_SIZE)) != DISK_OK) { logging_log_error("Failed to read"); kfree(buffer); @@ -372,115 +376,35 @@ static uint8_t get_block_index_dir(struct ext2_dir_track_t* dt, uint64_t* index) return BLOCK_LAST; } -static enum fs_status_t ext2_stat(struct fs_file_handle_t* file, struct fs_info_t* info) { +static enum file_status_t ext2_stat(struct mount_cntx_t* cntx, const char* path, struct file_info_t* info) { + struct ext2_inode_handle_t inode_handle; struct ext2_inode_t inode; - - if (get_inode((struct ext2_inode_handle_t*)file, &inode)) { - return FS_STATUS_ERROR; - } - info->size = (uint32_t)inode.i_size | ((uint64_t)inode.i_dir_acl << 32); + inode_handle.ext2 = (struct ext2_t*)cntx; + inode_handle.inode_index = 2; + (void)path; + + if (get_inode(&inode_handle, &inode)) { + return FILE_ERROR; + } if (inode.i_mode & EXT2_S_IFREG) { - info->type = FS_TYPE_FILE; + info->type = FILE_TYPE_REG; } else if (inode.i_mode & EXT2_S_IFDIR) { - info->type = FS_TYPE_DIR; + info->type = FILE_TYPE_DIR; } else { - return FS_STATUS_ERROR; - } - - return FS_STATUS_OK; -} - -static struct fs_dirls_handle_t* ext2_dirst(struct fs_file_handle_t* handle) { - struct ext2_inode_t inode; - - if (get_inode((struct ext2_inode_handle_t*)handle, &inode)) { - return 0; - } - - struct ext2_dir_track_t* dir_track = kmalloc(sizeof(struct ext2_dir_track_t)); - dir_track->handle = (struct ext2_inode_handle_t*)handle; - dir_track->dir = inode; - dir_track->off = 0; - dir_track->block = 0; - return (struct fs_dirls_handle_t*)dir_track; -} - -static enum fs_status_t ext2_dirls(struct fs_dirls_handle_t** handle, struct fs_ls_info_t* file) { - struct ext2_dir_track_t* dt = (struct ext2_dir_track_t*)*handle; - - const struct ext2_superblock_t* superblock = dt->handle->ext2->superblock; - - const uint64_t block_size = 1024u << superblock->s_log_block_size; - - if (dt->off >= block_size) { - dt->block++; - dt->off = 0; - } - - uint64_t block_index; - uint8_t res = get_block_index_dir(dt, &block_index); - - if (res == BLOCK_RETRY) { - file->valid = 0; - dt->off = 0; - return FS_STATUS_OK; - } - - if (res == BLOCK_LAST) { - file->valid = 0; - return FS_STATUS_EOF; - } - - if (res == BLOCK_ERROR) { - file->valid = 0; - return FS_STATUS_ERROR; - } - - void* buffer = read_block(block_index, dt->handle->ext2); - - if (!buffer) { - logging_log_error("Failed to read"); - return FS_STATUS_ERROR; + return FILE_NO_SUPPORT; } - struct ext2_ll_dir_entry_t* entry = - (struct ext2_ll_dir_entry_t*)((uint64_t)buffer + dt->off); - - logging_log_info("directory entry %x, %x, %x", entry->inode, entry->name_len, entry->rec_len); + info->size = inode.i_size; - if (entry->inode != 0) { - if (entry->name[0] == '.' && (entry->name_len == 1 || (entry->name_len == 2 && entry->name[1] == '.'))) { - file->valid = 0; - } - - else { - kmemcpy(file->name, entry->name, entry->name_len); - file->name_len = entry->name_len; - struct ext2_inode_handle_t* hndl = kmalloc(sizeof(struct ext2_inode_handle_t)); - hndl->ext2 = dt->handle->ext2; - hndl->inode_index = entry->inode; - file->handle = (struct fs_file_handle_t*)hndl; - file->valid = 1; - } - } - - dt->off += entry->rec_len; - - kfree(buffer); - return FS_STATUS_OK; -} - -static void ext2_diren(struct fs_dirls_handle_t* handle) { - kfree(handle); + return FILE_OK; } uint8_t ext2_attempt_init(struct disk_t* disk, uint64_t start_lba, uint64_t end_lba) { struct ext2_superblock_t* superblock = kmalloc(sizeof(struct ext2_superblock_t)); - struct ext2_inode_handle_t* root_handle; struct ext2_bg_desc_t* bgdt; uint64_t bgdt_size, adj, bgdt_start_lba; @@ -513,45 +437,34 @@ uint8_t ext2_attempt_init(struct disk_t* disk, uint64_t start_lba, uint64_t end_ logging_log_info("Found ext2 filesystem %16.16s", superblock->s_volume_name); - root_handle = kmalloc(sizeof(struct ext2_inode_handle_t)); - root_handle->ext2 = kmalloc(sizeof(struct ext2_t)); - root_handle->ext2->start_lba = start_lba; - root_handle->ext2->end_lba = end_lba; - root_handle->ext2->superblock = superblock; - root_handle->ext2->bgdt = bgdt; - root_handle->ext2->disk = disk; - root_handle->inode_index = EXT2_ROOT_INO; + struct ext2_t* ext2 = kmalloc(sizeof(struct ext2_t)); + ext2->start_lba = start_lba; + ext2->end_lba = end_lba; + ext2->superblock = superblock; + ext2->bgdt = bgdt; + ext2->disk = disk; logging_log_debug("ext2 blocks: 0x%x x 0x%x (0x%lX)", 1024u << superblock->s_log_block_size, superblock->s_blocks_count, (uint64_t)(1024u << superblock->s_log_block_size) * (uint64_t)superblock->s_blocks_count); if (!kmemcmp(label_rootfs, superblock->s_volume_name, sizeof(superblock->s_volume_name))) { - if (fs_mount((struct fs_file_handle_t*)root_handle, "/", - ext2_open, - ext2_close, - ext2_stat, - ext2_read_dir, - ) != FS_STATUS_OK) { + if (fs_mount( + "/", + (struct mount_cntx_t*)ext2, + ext2_stat + ) != FILE_OK) { logging_log_error("Failed to mount rootfs"); panic(PANIC_STATE); } - struct fs_file_t* root_file = fs_open("/."); - if (!root_file) { - logging_log_error("Failed to open root directory"); - panic(PANIC_STATE); + struct file_info_t stat_buf; + enum file_status_t sts; + if ((sts = fs_stat("/.", &stat_buf)) != FILE_OK) { + logging_log_error("Failed to stat root directory %u", sts); } - struct fs_info_t root_file_info; - if (fs_stat(root_file, &root_file_info) != FS_STATUS_OK) { - logging_log_error("Failed to stat root directory"); - panic(PANIC_STATE); - } - - logging_log_debug("Root directory (0x%lx) (%u)", root_file_info.size, root_file_info.type); - - fs_close(root_file); + logging_log_debug("Root directory %u (%u)", stat_buf.size, stat_buf.type); } //TODO: mount other volumes diff --git a/kernel/core/exception_dispatch.c b/kernel/core/exception_dispatch.c index e6f6d9d..f8e368f 100644 --- a/kernel/core/exception_dispatch.c +++ b/kernel/core/exception_dispatch.c @@ -23,12 +23,87 @@ #include #include -#define VECTOR_PF 0xE +#define VECTOR_DE 0x00 +#define VECTOR_DB 0x01 +#define VECTOR_NMI 0x02 +#define VECTOR_BP 0x03 +#define VECTOR_OF 0x04 +#define VECTOR_BR 0x05 +#define VECTOR_UD 0x06 +#define VECTOR_NM 0x07 +#define VECTOR_DF 0x08 +#define VECTOR_TS 0x0A +#define VECTOR_NP 0x0B +#define VECTOR_SS 0x0C +#define VECTOR_GP 0x0D +#define VECTOR_PF 0x0E +#define VECTOR_MF 0x10 +#define VECTOR_AC 0x11 +#define VECTOR_MC 0x12 +#define VECTOR_XM 0x13 +#define VECTOR_VE 0x14 +#define VECTOR_CP 0x15 +#define VECTOR_HV 0x1C +#define VECTOR_VC 0x1D +#define VECTOR_SX 0x1E + +static inline const char* get_exception_name(uint64_t vector) { + switch (vector) { + case VECTOR_DE: + return "#DE"; + case VECTOR_DB: + return "#DB"; + case VECTOR_NMI: + return "NMI"; + case VECTOR_BP: + return "#BP"; + case VECTOR_OF: + return "#OF"; + case VECTOR_BR: + return "#BR"; + case VECTOR_UD: + return "#UD"; + case VECTOR_NM: + return "#NM"; + case VECTOR_DF: + return "#DF"; + case VECTOR_TS: + return "#TS"; + case VECTOR_NP: + return "#NP"; + case VECTOR_SS: + return "#SS"; + case VECTOR_GP: + return "#GP"; + case VECTOR_PF: + return "#PF"; + case VECTOR_MF: + return "#MF"; + case VECTOR_AC: + return "#AC"; + case VECTOR_MC: + return "#MC"; + case VECTOR_XM: + return "#XM"; + case VECTOR_VE: + return "#VE"; + case VECTOR_CP: + return "#CP"; + case VECTOR_HV: + return "#HV"; + case VECTOR_VC: + return "#VC"; + case VECTOR_SX: + return "#SX"; + default: + return ""; + } +} void exception_dispatch(struct exception_context_t* context) { //TODO: remove reduntant rsp push - logging_log_error("Unrecoverable exception 0x%lX (0x%lX) @ 0x%lX", - context->vector, context->code, context->rip); + logging_log_error("Unrecoverable exception 0x%lX %s (0x%lX) @ 0x%lX", + context->vector, get_exception_name(context->vector), context->code, context->rip); logging_log_debug("Register Dump:\r\nrax 0x%lX\r\nrbx 0x%lX\r\nrcx 0x%lX\r\nrdx 0x%lX\ \r\nrsi 0x%lX\r\nrdi 0x%lX\r\nrbp 0x%lX\r\nrsp 0x%lX\r\nr8 0x%lX\r\nr9 0x%lX\r\nr10 0x%lX\ diff --git a/kernel/core/fs.c b/kernel/core/fs.c index 44a1042..5c425f2 100644 --- a/kernel/core/fs.c +++ b/kernel/core/fs.c @@ -28,24 +28,24 @@ #include #include #include -/* + +static uint8_t fs_lock; + struct vfs_mount_t { + struct mount_cntx_t* cntx; fs_stat_t stat; - fs_opendir_t opendir; - fs_closedir_t closedir; }; -struct vfs_node_t { - struct vfs_node_t* co; - struct vfs_node_t* sub; +struct vfs_tree_node_t { + struct vfs_tree_node_t* co; + struct vfs_tree_node_t* sub; const char* name; + struct vfs_mount_t* mount; }; -static struct vfs_node_t vfs_root; -static struct vfs_mount_t vfs_mount; -static uint8_t vfs_lock; +static struct vfs_tree_node_t vfs_root; static inline const char* simplify_path(const char* path) { while ( @@ -68,8 +68,9 @@ static inline const char* path_next(const char* path, uint8_t* len) { return simplify_path(path); } -static struct vfs_node_t* resolve_sub_path(struct vfs_node_t* root, const char* path) { - struct vfs_node_t* walk, * node; +static struct vfs_mount_t* find_mountpoint_sub(struct vfs_tree_node_t* root, const char* path) { + struct vfs_tree_node_t* walk; + struct vfs_mount_t* sub_mount = 0; const char* next = path; uint8_t len; @@ -78,404 +79,70 @@ static struct vfs_node_t* resolve_sub_path(struct vfs_node_t* root, const char* for (walk = root->sub; walk; walk = walk->co) { if (len == kstrlen(walk->name) && kmemcmp(walk->name, next, len) == 0) { if (*next) { - return resolve_sub_path(walk, path); + sub_mount = find_mountpoint_sub(walk, path); } - return walk; + break; } } - struct fs_file_open_handle_t* file = root->mount->opendir(root->handle); - - if (!file) { - return 0; + if (sub_mount) { + return sub_mount; } - char* buffer = kmalloc(256); - struct fs_file_handle_t* handle; - while (root->mount->read_dir(file, &handle, buffer) == FS_STATUS_OK) { - if (kstrcmp(buffer, next) == 0) { - walk = init_node(root, handle, buffer); - if (!walk) { - kfree(buffer); - return 0; - } - - walk->co = root->sub; - root->sub = walk; - - root->mount->close(file); - - if (*next) { - node = resolve_sub_path(walk, path); - if (node) { - walk->accesses++; - return node; - } - return 0; - } - - walk->accesses++; - return walk; - } - } - - - root->mount->close(file); - kfree(buffer); - return 0; + return walk->mount; } -static struct fs_node_t* resolve_absolute_path(const char* path) { +static struct vfs_mount_t* find_mountpoint(const char* path) { path = simplify_path(path); if (kstrcmp(path, "") == 0) { - return &vfs_root; - } - - return resolve_sub_path(&vfs_root, path); -} - -void fs_init(void) { - vfs_root.co = 0; - vfs_root.sub = 0; - vfs_root.name = ""; - vfs_root.mount = 0; - - lock_init(&vfs_lock); -} - -void fs_mount( - const char* path, - fs_stat_t stat, - fs_opendir_t opendir, - fs_closedir_t closedir) { -} - - - -*/ - - - - - - - - -/* old implementation */ - -#define VFS_STATUS_MOUNTED 0x1 - -struct fs_mount_t { - struct fs_mount_t* parent; - fs_open_t open; - fs_close_t close; - fs_stat_t stat; - fs_read_dir_t read_dir; -}; - -struct fs_node_t { - struct fs_node_t* parent; - struct fs_node_t* sub; - struct fs_node_t* co; - - struct fs_mount_t* mount; - - struct fs_file_handle_t* handle; - - uint64_t accesses; - - const char* name; - - struct fs_info_t info; - - uint8_t status; -}; - -struct vfs_file_open_handle_t { - struct fs_node_t* walk; -}; - -static struct fs_file_open_handle_t* vfs_open(struct fs_file_handle_t* handle) { - struct fs_node_t* node = (struct fs_node_t*)handle; - struct vfs_file_open_handle_t* open; - - open = kmalloc(sizeof(struct vfs_file_open_handle_t)); - open->walk = node->sub; - return (struct fs_file_open_handle_t*)open; -} - -static void vfs_close(struct fs_file_open_handle_t* handle) { - kfree(handle); -} - -static enum fs_status_t vfs_stat(struct fs_file_open_handle_t* handle, struct fs_info_t* info) { - (void)handle; - info->size = 0; - info->type = FS_TYPE_DIR; - - return FS_STATUS_OK; -} - -static enum fs_status_t vfs_read_dir(struct fs_file_open_handle_t* handle, struct fs_file_handle_t** file, char* name) { - struct vfs_file_open_handle_t* open = (struct vfs_file_open_handle_t*)handle; - if (!open->walk) { - return FS_STATUS_EOF; + return vfs_root.mount; } - *file = open->walk->handle; - kstrcpy(name, open->walk->name); - - open->walk = open->walk->co; - return FS_STATUS_OK; + return find_mountpoint_sub(&vfs_root, path); } -static struct fs_mount_t vfs_mount = { - .parent = &vfs_mount, - .open = vfs_open, - .close = vfs_close, - .stat = vfs_stat, - .read_dir = vfs_read_dir -}; - -static struct fs_node_t vfs_root; - -static uint8_t vfs_lock; - void fs_init(void) { - lock_init(&vfs_lock); + lock_init(&fs_lock); - vfs_root.handle = (struct fs_file_handle_t*)&vfs_root; vfs_root.co = 0; vfs_root.sub = 0; - vfs_root.parent = &vfs_root; - vfs_root.mount = &vfs_mount; vfs_root.name = ""; - vfs_root.status = 0; - vfs_root.accesses = 1; - vfs_root.info.size = 0; - vfs_root.info.type = FS_TYPE_DIR; -} - -static inline struct fs_node_t* init_node( - struct fs_node_t* parent, - struct fs_file_handle_t* handle, - const char* name) { - - struct fs_node_t* node; - enum fs_status_t status; - struct fs_info_t info; - - struct fs_file_open_handle_t* open = parent->mount->open(handle); - - if (!open) { - return 0; - } - - status = parent->mount->stat(open, &info); - parent->mount->close(open); - - if (status != FS_STATUS_OK) { - return 0; - } - - - node = kmalloc(sizeof(struct fs_node_t)); - - node->handle = handle; - node->co = 0; - node->sub = 0; - node->parent = parent; - node->mount = parent->mount; - node->name = name; - node->status = 0; - node->accesses = 0; - node->info = info; - - return node; -} - -static const inline char* simplify_path(const char* path) { - while ( - *path == '/' || - (*path == '.' && (*(path+1) == '/' || !*(path+1)))) { - path++; - } - - return path; -} - -static inline const char* path_next(const char* path, uint8_t* len) { - *len = 0; - - while (*path && *path != '/') { - path++; - (*len)++; - } - - return simplify_path(path); + vfs_root.mount = 0; } -static struct fs_node_t* resolve_sub_path(struct fs_node_t* root, const char* path) { - struct fs_node_t* walk, * node; - const char* next = path; - uint8_t len; +enum file_status_t fs_mount( + const char* mountpoint, + struct mount_cntx_t* cntx, + fs_stat_t stat + ) { - path = path_next(path, &len); + if (kstrcmp(mountpoint, "") && !vfs_root.mount) { + vfs_root.mount = kmalloc(sizeof(struct vfs_mount_t)); - for (walk = root->sub; walk; walk = walk->co) { - if (len == kstrlen(walk->name) && kmemcmp(walk->name, next, len) == 0) { - if (*next) { - node = resolve_sub_path(walk, path); - if (node) { - walk->accesses++; - return node; - } - return 0; - } - - walk->accesses++; - return walk; + if (!vfs_root.mount) { + logging_log_error("Failed to mount root"); + return FILE_ERROR; } - } - struct fs_file_open_handle_t* file = root->mount->open(root->handle); + vfs_root.mount->cntx = cntx; + vfs_root.mount->stat = stat; - if (!file) { - return 0; + return FILE_OK; } - char* buffer = kmalloc(256); - struct fs_file_handle_t* handle; - while (root->mount->read_dir(file, &handle, buffer) == FS_STATUS_OK) { - if (kstrcmp(buffer, next) == 0) { - walk = init_node(root, handle, buffer); - if (!walk) { - kfree(buffer); - return 0; - } - - walk->co = root->sub; - root->sub = walk; - - root->mount->close(file); - - if (*next) { - node = resolve_sub_path(walk, path); - if (node) { - walk->accesses++; - return node; - } - return 0; - } - - walk->accesses++; - return walk; - } - } - - - root->mount->close(file); - kfree(buffer); - return 0; + //TODO: support non root mount + logging_log_error("Can only mount root"); + return FILE_ERROR; } -static struct fs_node_t* resolve_absolute_path(const char* path) { - path = simplify_path(path); +enum file_status_t fs_stat(const char* name, struct file_info_t* info) { + struct vfs_mount_t* mount = find_mountpoint(name); - if (kstrcmp(path, "") == 0) { - return &vfs_root; + if (!mount) { + return FILE_DNE; } - return resolve_sub_path(&vfs_root, path); -} - -static void cleanup_path(struct fs_node_t* root, const char* path) { - //TODO: cleanup vfs tree - (void)root; - (void)path; -} - -extern enum fs_status_t fs_mount( - struct fs_file_handle_t* root, - const char* path, - fs_open_t open, - fs_close_t close, - fs_stat_t stat, - fs_read_dir_t read_dir) { - - lock_acquire(&vfs_lock); - - struct fs_node_t* node = resolve_absolute_path(path); - - if (node->status & VFS_STATUS_MOUNTED) { - lock_release(&vfs_lock); - return FS_STATUS_BUSY; - } - - struct fs_node_t revert; - revert = *node; - struct fs_mount_t* mount = kmalloc(sizeof(struct fs_mount_t)); - mount->parent = node->mount; - - mount->open = open; - mount->close = close; - mount->stat = stat; - mount->read_dir = read_dir; - - node->mount = mount; - node->handle = root; - node->status = VFS_STATUS_MOUNTED; - - struct fs_info_t info; - enum fs_status_t status = node->mount->stat(node->handle, &info); - if (status != FS_STATUS_OK) { - kfree(mount); - *node = revert; - lock_release(&vfs_lock); - return status; - } - - node->info = info; - - lock_release(&vfs_lock); - return FS_STATUS_OK; -} - -struct fs_file_t* fs_open(const char* path) { - lock_acquire(&vfs_lock); - struct fs_node_t* node = resolve_absolute_path(path); - lock_release(&vfs_lock); - - if (!node) { - return 0; - } - - return (struct fs_file_t*)node; -} - -void fs_close(struct fs_file_t* file) { - struct fs_node_t* node = (struct fs_node_t*)file; - - lock_acquire(&vfs_lock); - cleanup_path(&vfs_root, simplify_path(node->name)); - lock_release(&vfs_lock); -} - -enum fs_status_t fs_stat(struct fs_file_t* file, struct fs_info_t* info) { - struct fs_node_t* node = (struct fs_node_t*)file; - *info = node->info; - - return FS_STATUS_OK; -} - -enum fs_status_t fs_read_dir(struct fs_file_t* file, char* buffer) { - struct fs_node_t* node = (struct fs_node_t*)file; - - lock_acquire(&vfs_lock); - enum fs_status_t sts = node->mount->read_dir(node->handle, buffer, ""); - lock_release(&vfs_lock); - - return sts; + return mount->stat(mount->cntx, name, info); } diff --git a/kernel/include/core/fs.h b/kernel/include/core/fs.h index 1e80c57..f0e8425 100644 --- a/kernel/include/core/fs.h +++ b/kernel/include/core/fs.h @@ -20,92 +20,38 @@ #include #include -/* -struct fs_dir_handle_t; -enum fs_status_t { - FS_STATUS_OK, - FS_STATUS_ERROR -}; - -struct fs_stat_buf_t { -}; - -typedef enum fs_status_t (*fs_stat_t)(const char* path, struct fs_stat_buf_t* stat_buf); -typedef struct fs_dir_handle_t* (*fs_opendir_t)(const char* path); -typedef void (*fs_closedir_t)(struct fs_dir_handle_t* handle); -typedef enum fs_status_t (*fs_readdir_t)(struct fs_dir_handle_t* handle, const char** name); - -extern void fs_init(void); +struct mount_cntx_t; -extern void fs_mount( - const char* path, - fs_stat_t stat, - fs_opendir_t opendir, - fs_closedir_t closedir, - fs_readdir_t readdir); -*/ - -/* old interface */ - -enum fs_file_type_t { - FS_TYPE_FILE, - FS_TYPE_DIR -}; +struct file_handle_t; +struct dir_handle_t; -enum fs_status_t { - FS_STATUS_OK, - FS_STATUS_ERROR, - FS_STATUS_EOF, - FS_STATUS_FILE_NOT_FOUND, - FS_STATUS_BUSY +enum file_status_t { + FILE_OK, + FILE_ERROR, + FILE_DNE, + FILE_BUSY, + FILE_NO_SUPPORT }; -struct fs_info_t { - enum fs_file_type_t type; - size_t size; +struct file_info_t { + enum { + FILE_TYPE_REG, + FILE_TYPE_DIR + } type; + uint64_t size; }; -struct fs_ls_info_t { - struct fs_file_handle_t* handle; - char name[256]; - uint8_t name_len; - uint8_t valid; -}; - -struct fs_file_t; -struct fs_file_handle_t; -struct fs_dirls_handle_t; - -extern void fs_init(void); - - -typedef struct fs_file_open_handle_t* (*fs_open_t)(struct fs_file_handle_t* handle); -typedef void (*fs_close_t)(struct fs_file_open_handle_t* handle); - -typedef enum fs_status_t (*fs_stat_t)(struct fs_file_open_handle_t* handle, struct fs_info_t* info); -typedef enum fs_status_t (*fs_read_dir_t)(struct fs_file_open_handle_t* handle, struct fs_file_handle_t** file, char* name); - -typedef struct fs_file_handle_t* (*fs_create_t)( - struct fs_file_handle_t* handle, - enum fs_file_type_t type, - const char* name, - uint8_t name_len); - -extern void fs_init(void); +typedef enum file_status_t (*fs_stat_t)(struct mount_cntx_t* cntx, const char*, struct file_info_t*); -extern enum fs_status_t fs_mount( - struct fs_file_handle_t* root, - const char* path, - fs_open_t open, - fs_close_t close, - fs_stat_t stat, - fs_read_dir_t read_dir); +enum file_status_t fs_stat(const char* name, struct file_info_t* info); -extern struct fs_file_t* fs_open(const char* path); -extern void fs_close(struct fs_file_t* file); +void fs_init(void); -extern enum fs_status_t fs_stat(struct fs_file_t* file, struct fs_info_t* info); -extern enum fs_status_t fs_read_dir(struct fs_file_t* file, char* buffer); +enum file_status_t fs_mount( + const char* mountpoint, + struct mount_cntx_t* cntx, + fs_stat_t stat + ); #endif /* KERNEL_CORE_FS_H */ From b51851220d2b2d4fb1540b13896c68b4c1a87d01 Mon Sep 17 00:00:00 2001 From: Ebrahim Aleem Date: Fri, 10 Apr 2026 17:56:30 -0700 Subject: [PATCH 10/12] ext2 stat on any file --- drivers/apic/apic_init.c | 4 +- drivers/ext2/ext2.c | 138 ++++++++++++++-- drivers/include/acpica/platform/acmodulos.h | 4 +- drivers/ioapic/routing.c | 2 +- drivers/pic_8259/pic.c | 4 +- kernel/core/cpu_instr.S | 9 +- kernel/core/exception_dispatch.c | 2 +- kernel/core/fs.c | 172 ++++++++++++++------ kernel/core/idt.c | 2 +- kernel/core/paging.c | 112 ++++++------- kernel/core/process.c | 2 - kernel/core/scheduler.c | 7 + kernel/include/core/cpu_instr.h | 4 +- kernel/include/core/fs.h | 16 +- 14 files changed, 348 insertions(+), 130 deletions(-) diff --git a/drivers/apic/apic_init.c b/drivers/apic/apic_init.c index 386c90d..d337450 100644 --- a/drivers/apic/apic_init.c +++ b/drivers/apic/apic_init.c @@ -114,8 +114,8 @@ void apic_init(void) { error_vector = idt_get_vector(); // install idts - idt_install(timer_vector, (uint64_t)apic_isr_timer, GDT_CODE_SEL, IST_SCHED, IDT_GATE_INT, 0); - idt_install(error_vector, (uint64_t)apic_isr_error, GDT_CODE_SEL, 0, IDT_GATE_INT, 0); + idt_install(timer_vector, (uint64_t)apic_isr_timer, GDT_CODE_SEL, IST_SCHED, IDT_GATE_TRP, 0); + idt_install(error_vector, (uint64_t)apic_isr_error, GDT_CODE_SEL, 0, IDT_GATE_TRP, 0); apic_init_shootdowns(num_apic); diff --git a/drivers/ext2/ext2.c b/drivers/ext2/ext2.c index d16a460..f39d174 100644 --- a/drivers/ext2/ext2.c +++ b/drivers/ext2/ext2.c @@ -43,6 +43,8 @@ #define BLOCK_LAST 2 #define BLOCK_ERROR 3 +#define EXT2_FT_DIR 2 + #define EXT2_SUPER_MAGIC 0xEF53 #define EXT2_ROOT_INO 2 @@ -172,7 +174,7 @@ struct ext2_inode_handle_t { struct ext2_dir_track_t { struct ext2_inode_handle_t* handle; - struct ext2_inode_t dir; + struct ext2_inode_t* dir; uint64_t off; uint64_t block; }; @@ -216,6 +218,7 @@ static uint8_t get_inode(const struct ext2_inode_handle_t* inode_handle, struct if (!buffer) { logging_log_error("Failed to read inode %lu", inode_handle->inode_index); kfree(buffer); + return 1; } *inode = *(struct ext2_inode_t*)((uint64_t)buffer + inode_off); @@ -225,7 +228,7 @@ static uint8_t get_inode(const struct ext2_inode_handle_t* inode_handle, struct static uint8_t get_block_index_dir(struct ext2_dir_track_t* dt, uint64_t* index) { uint64_t block = dt->block; - struct ext2_inode_t* inode = &dt->dir; + struct ext2_inode_t* inode = dt->dir; struct ext2_t* ext2 = dt->handle->ext2; @@ -376,15 +379,120 @@ static uint8_t get_block_index_dir(struct ext2_dir_track_t* dt, uint64_t* index) return BLOCK_LAST; } -static enum file_status_t ext2_stat(struct mount_cntx_t* cntx, const char* path, struct file_info_t* info) { - struct ext2_inode_handle_t inode_handle; +static inline size_t path_entry_len(char* path) { + size_t len = 0; + + for (; *path && *path != '/'; path++) { + len++; + } + + return len; +} + + +static struct file_handle_t* ext2_open(struct mount_cntx_t* cntx, char* path) { struct ext2_inode_t inode; + size_t path_len; + struct ext2_dir_track_t track; + uint64_t block_index; + uint8_t cntrl = 0; + + + track.handle = kmalloc(sizeof(struct ext2_inode_handle_t)); - inode_handle.ext2 = (struct ext2_t*)cntx; - inode_handle.inode_index = 2; - (void)path; + if (!track.handle) { + return 0; + } + + track.handle->ext2 = (struct ext2_t*)cntx; + track.handle->inode_index = EXT2_ROOT_INO; + + const struct ext2_superblock_t* superblock = track.handle->ext2->superblock; + const uint64_t block_size = 1024u << superblock->s_log_block_size; + void* buffer; + + while (*path && cntrl != 2) { + path_len = path_entry_len(path); + + if (get_inode(track.handle, &inode)) { + return 0; + } - if (get_inode(&inode_handle, &inode)) { + track.dir = &inode; + track.block = 0; + track.off = 0; + + cntrl = 1; + while (cntrl == 1) { + if (track.off >= block_size) { + track.block++; + track.off = 0; + } + + switch (get_block_index_dir(&track, &block_index)) { + case BLOCK_OK: + buffer = read_block(block_index, track.handle->ext2); + if (!buffer) { + kfree(track.handle); + return 0; + } + + struct ext2_ll_dir_entry_t* entry = (struct ext2_ll_dir_entry_t*)((uint64_t)buffer + track.off); + + if (entry->inode != 0) { + if (entry->name_len == path_len && !kmemcmp(entry->name, path, path_len)) { + path += path_len; + + // handle non EOS + if (*path == '/') { + path++; + } + + track.handle->inode_index = entry->inode; + + if (*path && entry->file_type != EXT2_FT_DIR) { + cntrl = 2; // file not found + } + else { + cntrl = 0; + } + + break; + } + } + + track.off += entry->rec_len; + __attribute__((fallthrough)); + case BLOCK_RETRY: + continue; + case BLOCK_LAST: + cntrl = 2; // file not found + break; + case BLOCK_ERROR: + default: + kfree(track.handle); + return 0; + } + } + } + + if (*path || cntrl == 2) { + kfree(track.handle); // file not found + return 0; + } + + return (struct file_handle_t*)track.handle; +} + +static void ext2_close(struct file_handle_t* handle) { + kfree(handle); +} + +static enum file_status_t ext2_stat(struct file_handle_t* handle, struct file_info_t* info) { + struct ext2_inode_t inode; + struct ext2_inode_handle_t* inode_handle = (struct ext2_inode_handle_t*)handle; + + if (!inode_handle || get_inode(inode_handle, &inode)) { return FILE_ERROR; } @@ -452,6 +560,8 @@ uint8_t ext2_attempt_init(struct disk_t* disk, uint64_t start_lba, uint64_t end_ if (fs_mount( "/", (struct mount_cntx_t*)ext2, + ext2_open, + ext2_close, ext2_stat ) != FILE_OK) { logging_log_error("Failed to mount rootfs"); @@ -460,11 +570,19 @@ uint8_t ext2_attempt_init(struct disk_t* disk, uint64_t start_lba, uint64_t end_ struct file_info_t stat_buf; enum file_status_t sts; - if ((sts = fs_stat("/.", &stat_buf)) != FILE_OK) { - logging_log_error("Failed to stat root directory %u", sts); + + struct fs_handle_t* root_handle = fs_open("/"); + if (!root_handle) { + logging_log_error("Failed to open root directory"); + } + + if ((sts = fs_stat(root_handle, &stat_buf)) != FILE_OK) { + logging_log_error("Failed to stat root directory %u", (uint32_t)sts); } logging_log_debug("Root directory %u (%u)", stat_buf.size, stat_buf.type); + + fs_close(root_handle); } //TODO: mount other volumes diff --git a/drivers/include/acpica/platform/acmodulos.h b/drivers/include/acpica/platform/acmodulos.h index dad0fd3..3902e70 100644 --- a/drivers/include/acpica/platform/acmodulos.h +++ b/drivers/include/acpica/platform/acmodulos.h @@ -172,6 +172,8 @@ #include #include +#include + #ifdef ACPI_USE_STANDARD_HEADERS #undef ACPI_USE_STANDARD_HEADERS #endif /* ACPI_USE_STANDARD_HEADERS */ @@ -210,7 +212,7 @@ static uint8_t _stub(void) { return 0; } -#define ACPI_FLUSH_CPU_CACHE() _stub() //TODO cpu_instr tlb invl +#define ACPI_FLUSH_CPU_CACHE() cpu_wbinvd(); #define ACPI_ACQUIRE_GLOBAL_LOCK(facsPtr, acc) acc = _stub() //TODO: sync #define ACPI_RELEASE_GLOBAL_LOCK(facsPtr, pen) pen = _stub() diff --git a/drivers/ioapic/routing.c b/drivers/ioapic/routing.c index a38aa0c..e48eac4 100644 --- a/drivers/ioapic/routing.c +++ b/drivers/ioapic/routing.c @@ -138,7 +138,7 @@ void ioapic_routing_init(uint64_t num_gsi) { logging_log_info("Found SCI on GSI 0x%lX", sci_gsi); const uint8_t sci_v = idt_get_vector(); - idt_install(sci_v, (uint64_t)sci_isr, GDT_CODE_SEL, 0, IDT_GATE_INT, 0); + idt_install(sci_v, (uint64_t)sci_isr, GDT_CODE_SEL, 0, IDT_GATE_TRP, 0); ioapic_conf_gsi(sci_gsi, sci_v, IOAPIC_REDIR_TRG_LVL | IOAPIC_REDIR_POL_LO, bsp_apic_id); } diff --git a/drivers/pic_8259/pic.c b/drivers/pic_8259/pic.c index 9972e34..81d983f 100644 --- a/drivers/pic_8259/pic.c +++ b/drivers/pic_8259/pic.c @@ -63,8 +63,8 @@ void pic_disab(void) { outb(PIC2_DATA, ICW4_8086); io_wait(); - idt_install(PIC1_IRQ_BASE + PIC_SPURIOUS, (uint64_t)pic_spurious_master, GDT_CODE_SEL, 0, IDT_GATE_INT, 0); - idt_install(PIC2_IRQ_BASE + PIC_SPURIOUS, (uint64_t)pic_spurious_slave, GDT_CODE_SEL, 0, IDT_GATE_INT, 0); + idt_install(PIC1_IRQ_BASE + PIC_SPURIOUS, (uint64_t)pic_spurious_master, GDT_CODE_SEL, 0, IDT_GATE_TRP, 0); + idt_install(PIC2_IRQ_BASE + PIC_SPURIOUS, (uint64_t)pic_spurious_slave, GDT_CODE_SEL, 0, IDT_GATE_TRP, 0); // mask outb(PIC1_DATA, 0xff); diff --git a/kernel/core/cpu_instr.S b/kernel/core/cpu_instr.S index bf6619d..4f2c763 100644 --- a/kernel/core/cpu_instr.S +++ b/kernel/core/cpu_instr.S @@ -62,7 +62,12 @@ cpu_trap: // setting a breakpoint here will catch traps ret -.globl read_cr2 -read_cr2: +.globl cpu_read_cr2 +cpu_read_cr2: movq %cr2, %rax ret + +.globl cpu_wbinvd +cpu_wbinvd: +wbinvd +ret diff --git a/kernel/core/exception_dispatch.c b/kernel/core/exception_dispatch.c index f8e368f..c7bde50 100644 --- a/kernel/core/exception_dispatch.c +++ b/kernel/core/exception_dispatch.c @@ -117,7 +117,7 @@ void exception_dispatch(struct exception_context_t* context) { switch (context->vector) { case VECTOR_PF: - if (paging_check_guard(read_cr2())) { + if (paging_check_guard(cpu_read_cr2())) { logging_log_error("Stack Overflow"); } break; diff --git a/kernel/core/fs.c b/kernel/core/fs.c index 5c425f2..fb24377 100644 --- a/kernel/core/fs.c +++ b/kernel/core/fs.c @@ -33,9 +33,17 @@ static uint8_t fs_lock; struct vfs_mount_t { struct mount_cntx_t* cntx; + + fs_open_t open; + fs_close_t close; fs_stat_t stat; }; +struct fs_handle_t { + struct vfs_mount_t* mount; + struct file_handle_t* handle; +}; + struct vfs_tree_node_t { struct vfs_tree_node_t* co; struct vfs_tree_node_t* sub; @@ -47,17 +55,7 @@ struct vfs_tree_node_t { static struct vfs_tree_node_t vfs_root; -static inline const char* simplify_path(const char* path) { - while ( - *path == '/' || - (*path == '.' && (*(path+1) == '/' || !*(path+1)))) { - path++; - } - - return path; -} - -static inline const char* path_next(const char* path, uint8_t* len) { +static inline char* path_next(char* path, size_t* len) { *len = 0; while (*path && *path != '/') { @@ -65,42 +63,11 @@ static inline const char* path_next(const char* path, uint8_t* len) { (*len)++; } - return simplify_path(path); -} - -static struct vfs_mount_t* find_mountpoint_sub(struct vfs_tree_node_t* root, const char* path) { - struct vfs_tree_node_t* walk; - struct vfs_mount_t* sub_mount = 0; - const char* next = path; - uint8_t len; - - path = path_next(path, &len); - - for (walk = root->sub; walk; walk = walk->co) { - if (len == kstrlen(walk->name) && kmemcmp(walk->name, next, len) == 0) { - if (*next) { - sub_mount = find_mountpoint_sub(walk, path); - } - - break; - } - } - - if (sub_mount) { - return sub_mount; + if (*path) { + return path + 1; } - return walk->mount; -} - -static struct vfs_mount_t* find_mountpoint(const char* path) { - path = simplify_path(path); - - if (kstrcmp(path, "") == 0) { - return vfs_root.mount; - } - - return find_mountpoint_sub(&vfs_root, path); + return path; } void fs_init(void) { @@ -115,6 +82,8 @@ void fs_init(void) { enum file_status_t fs_mount( const char* mountpoint, struct mount_cntx_t* cntx, + fs_open_t open, + fs_close_t close, fs_stat_t stat ) { @@ -127,6 +96,8 @@ enum file_status_t fs_mount( } vfs_root.mount->cntx = cntx; + vfs_root.mount->open = open; + vfs_root.mount->close = close; vfs_root.mount->stat = stat; return FILE_OK; @@ -137,12 +108,115 @@ enum file_status_t fs_mount( return FILE_ERROR; } -enum file_status_t fs_stat(const char* name, struct file_info_t* info) { - struct vfs_mount_t* mount = find_mountpoint(name); +struct fs_handle_t* fs_open(const char* path) { + struct vfs_tree_node_t* node = &vfs_root, * walk = 0; + size_t len = kstrlen(path); + char* clean_path = kmalloc(len + 1); + char* mount_path = (char*)""; + struct vfs_mount_t* mount = 0; + + + uint64_t num_chars = 0; + uint64_t skip = 0; + uint8_t dot_only = 1; + + const char* path_read = path + len; + char* path_write = clean_path + len; + + for (; path_read >= path; --path_read) { + switch (*path_read) { + case '/': // absolute paths must start with / + if (dot_only && num_chars == 1) { + path_write += num_chars; + } + else if (dot_only && num_chars == 2) { + skip++; + path_write += num_chars; + } + else if (num_chars > 0) { + if (skip) { + path_write += num_chars; + skip--; + } + else { + *path_write = '/'; + path_write--; + } + } + + num_chars = 0; + dot_only = 1; + break; + default: + dot_only = 0; + __attribute__((fallthrough)); + case '.': + num_chars++; + __attribute__((fallthrough)); + case 0: + *path_write = *path_read; + path_write--; + break; + } + } + + path_write++; // one to rewind write pointer + + if (*path_write == '/') { + path_write++; // one to skip / + } + + + lock_acquire(&fs_lock); + + do { + if (node->mount) { + mount_path = path_write; + mount = node->mount; + } + + path_read = path_write; + path_write = path_next(path_write, &len); + + for (walk = node->sub; walk; walk = walk->co) { + if (kstrlen(node->name) == len && kmemcmp(node->name, path_read, len) == 0) { + node = walk; + break; + } + } + + } while (walk && node != walk); + + lock_release(&fs_lock); if (!mount) { - return FILE_DNE; + kfree(clean_path); + return 0; } - return mount->stat(mount->cntx, name, info); + struct file_handle_t* handle = mount->open(mount->cntx, mount_path); + + kfree(clean_path); + + struct fs_handle_t* fs_handle = kmalloc(sizeof(struct fs_handle_t)); + fs_handle->handle = handle; + fs_handle->mount = mount; + return fs_handle; +} + +void fs_close(struct fs_handle_t* handle) { + lock_acquire(&fs_lock); + + handle->mount->close(handle->handle); + lock_release(&fs_lock); + + kfree(handle); +} + +enum file_status_t fs_stat(struct fs_handle_t* handle, struct file_info_t* info) { + lock_acquire(&fs_lock); + + enum file_status_t ret = handle->mount->stat(handle->handle, info); + lock_release(&fs_lock); + return ret; } diff --git a/kernel/core/idt.c b/kernel/core/idt.c index d504a89..8785133 100644 --- a/kernel/core/idt.c +++ b/kernel/core/idt.c @@ -61,7 +61,7 @@ void idt_init(void) { idt_install(0x0b, (uint64_t)isr_0b, GDT_CODE_SEL, 0, IDT_GATE_TRP, 0); idt_install(0x0c, (uint64_t)isr_0c, GDT_CODE_SEL, 0, IDT_GATE_TRP, 0); idt_install(0x0d, (uint64_t)isr_0d, GDT_CODE_SEL, 0, IDT_GATE_TRP, 0); - idt_install(0x0e, (uint64_t)isr_0e, GDT_CODE_SEL, IST_PF, IDT_GATE_TRP, 0); + idt_install(0x0e, (uint64_t)isr_0e, GDT_CODE_SEL, IST_PF, IDT_GATE_INT, 0); idt_install(0x10, (uint64_t)isr_10, GDT_CODE_SEL, 0, IDT_GATE_TRP, 0); idt_install(0x11, (uint64_t)isr_11, GDT_CODE_SEL, 0, IDT_GATE_TRP, 0); idt_install(0x12, (uint64_t)isr_12, GDT_CODE_SEL, IST_ABORT, IDT_GATE_INT, 0); diff --git a/kernel/core/paging.c b/kernel/core/paging.c index 9ed6aaa..cfac405 100644 --- a/kernel/core/paging.c +++ b/kernel/core/paging.c @@ -40,17 +40,12 @@ #define GET_PDPT_INDEX(addr) ((addr & 0x7FC0000000) >> 30) #define GET_PML4_INDEX(addr) ((addr & 0xFF8000000000) >> 39) +#define AVL_GUARD 0x800 + extern uint64_t kernel_pml4[512]; static uint8_t paging_lock; -struct addr_list_t { - struct addr_list_t* next; - uint64_t addr; -}; - -static struct addr_list_t* stack_guard_list; - static enum page_size_t page_walk(uint64_t vaddr, uint64_t** access) { uint64_t entry; *access = (uint64_t*)paging_ident((uint64_t)&kernel_pml4[0]); @@ -88,28 +83,7 @@ static enum page_size_t page_walk(uint64_t vaddr, uint64_t** access) { return PAGE_4K; } -void paging_init(void) { - lock_init(&paging_lock); - - stack_guard_list = 0; -} - -uint64_t paging_map(uint64_t vaddr, uint64_t paddr, uint16_t flg, enum page_size_t page_size) { - uint64_t* access; - enum page_size_t lvl = page_walk(vaddr, &access); - - if (lvl < page_size) { - logging_log_error("Cannot override page of finer granularity from 0x%lx-0x%lx (%u) to 0x%lx-0x%lx (%u)", - vaddr, *access - IDENT_BASE, (uint32_t)lvl, vaddr, paddr | flg, (uint32_t)page_size); - return *access - IDENT_BASE; - } - - if (*access & PAGE_PRESENT) { - logging_log_error("Cannot override page from 0x%lx-0x%lx (%u) to 0x%lx-0x%lx (%u)", - vaddr, *access, (uint32_t)lvl, vaddr, paddr | flg, (uint32_t)page_size); - return *access; - } - +static uint64_t* increase_granularity(uint64_t vaddr, uint64_t* access, enum page_size_t lvl, enum page_size_t page_size) { for (; lvl > page_size; lvl--) { *access = mm_alloc_p(0x1000); if (!access) { @@ -132,6 +106,34 @@ uint64_t paging_map(uint64_t vaddr, uint64_t paddr, uint16_t flg, enum page_size } } + return access; +} + +void paging_init(void) { + lock_init(&paging_lock); +} + +uint64_t paging_map(uint64_t vaddr, uint64_t paddr, uint16_t flg, enum page_size_t page_size) { + uint64_t* access; + enum page_size_t lvl = page_walk(vaddr, &access); + + if (lvl < page_size) { + logging_log_error("Cannot override page of finer granularity from 0x%lx-0x%lx (%u) to 0x%lx-0x%lx (%u)", + vaddr, *access - IDENT_BASE, (uint32_t)lvl, vaddr, paddr | flg, (uint32_t)page_size); + return *access - IDENT_BASE; + } + + if (*access & PAGE_PRESENT) { + logging_log_error("Cannot override page from 0x%lx-0x%lx (%u) to 0x%lx-0x%lx (%u)", + vaddr, *access, (uint32_t)lvl, vaddr, paddr | flg, (uint32_t)page_size); + return *access; + } + + access = increase_granularity(vaddr, access, lvl, page_size); + if (!access) { + return 0; + } + if (page_size != PAGE_4K) { flg |= PAGE_PS; } @@ -159,45 +161,45 @@ uint64_t paging_ident(uint64_t paddr) { } void paging_install_guard(uint64_t vaddr) { - struct addr_list_t* guard = kmalloc(sizeof(struct addr_list_t)); - guard->addr = vaddr & PAGE_ADDR_MASK; - + uint64_t* access; lock_acquire(&paging_lock); - guard->next = stack_guard_list; - stack_guard_list = guard; + enum page_size_t lvl = page_walk(vaddr, &access); + + if (*access & PAGE_PRESENT) { + logging_log_error("Cannot install page guard over mapped page"); + panic(PANIC_STATE); + } + + access = increase_granularity(vaddr, access, lvl, PAGE_4K); + if (!access) { + logging_log_error("Failed to install page guard"); + panic(PANIC_STATE); + } + + *access |= AVL_GUARD; lock_release(&paging_lock); } void paging_remove_guard(uint64_t vaddr) { - struct addr_list_t* i, ** prev = &stack_guard_list; - + uint64_t* access; lock_acquire(&paging_lock); - for (i = stack_guard_list; i; i = i->next) { - if (i->addr == vaddr) { - *prev = i->next; - kfree(i); - break; - } + enum page_size_t lvl = page_walk(vaddr, &access); - prev = &i->next; - } + if (lvl != PAGE_4K || !(*access & AVL_GUARD)) { + logging_log_error("Attempted to remove guard from ungaurded page @ 0x%x", vaddr); + } + *access = 0; lock_release(&paging_lock); } uint8_t paging_check_guard(uint64_t vaddr) { - struct addr_list_t* i; - uint64_t addr = vaddr & PAGE_ADDR_MASK; - uint8_t ret = 0; - + uint64_t* access, access_value; lock_acquire(&paging_lock); - for (i = stack_guard_list; i; i = i->next) { - if (i->addr == addr) { - ret = 1; - break; - } - } + enum page_size_t lvl = page_walk(vaddr, &access); + + access_value = *access; lock_release(&paging_lock); - return ret; + return lvl == PAGE_4K && (access_value & AVL_GUARD); } diff --git a/kernel/core/process.c b/kernel/core/process.c index 570d32f..e9414be 100644 --- a/kernel/core/process.c +++ b/kernel/core/process.c @@ -195,7 +195,5 @@ void process_preempt_entry(struct preempt_frame_t* context) { pcb->rflags = context->rflags; pcb->ss = context->ss; - apic_write_reg(APIC_REG_EOI, APIC_EOI); - scheduler_run(); } diff --git a/kernel/core/scheduler.c b/kernel/core/scheduler.c index 7bd8dfe..e0da3d8 100644 --- a/kernel/core/scheduler.c +++ b/kernel/core/scheduler.c @@ -25,6 +25,8 @@ #include #include +#include + static uint8_t lock_sched; static volatile struct pcb_t* active_queue; static volatile struct pcb_t* active_queue_tail; @@ -55,6 +57,8 @@ void scheduler_run(void) { struct pcb_t* current_pcb = pd->current_process; switch (current_pcb->sched_cntr) { case SCHED_SKIP: + cpu_cli(); + apic_write_reg(APIC_REG_EOI, APIC_EOI); process_resume(current_pcb); break; case SCHED_KILL: @@ -84,5 +88,8 @@ void scheduler_run(void) { pd->tss->rsp0_lo = run->k_rsp_lo; pd->tss->rsp0_hi = run->k_rsp_hi; pd->current_process = run; + + cpu_cli(); + apic_write_reg(APIC_REG_EOI, APIC_EOI); process_resume(run); } diff --git a/kernel/include/core/cpu_instr.h b/kernel/include/core/cpu_instr.h index 0ac5366..46de151 100644 --- a/kernel/include/core/cpu_instr.h +++ b/kernel/include/core/cpu_instr.h @@ -38,6 +38,8 @@ extern void cpu_halt_loop(void) __attribute__((noreturn)); extern void cpu_trap(void); -extern uint64_t read_cr2(void); +extern uint64_t cpu_read_cr2(void); + +extern void cpu_wbinvd(void); #endif /* KERNEL_CORE_CPU_INSTR_H */ diff --git a/kernel/include/core/fs.h b/kernel/include/core/fs.h index f0e8425..7dc959c 100644 --- a/kernel/include/core/fs.h +++ b/kernel/include/core/fs.h @@ -24,7 +24,8 @@ struct mount_cntx_t; struct file_handle_t; -struct dir_handle_t; + +struct fs_handle_t; enum file_status_t { FILE_OK, @@ -42,16 +43,25 @@ struct file_info_t { uint64_t size; }; -typedef enum file_status_t (*fs_stat_t)(struct mount_cntx_t* cntx, const char*, struct file_info_t*); -enum file_status_t fs_stat(const char* name, struct file_info_t* info); +typedef struct file_handle_t* (*fs_open_t)(struct mount_cntx_t*, char*); +typedef void (*fs_close_t)(struct file_handle_t*); + +typedef enum file_status_t (*fs_stat_t)(struct file_handle_t*, struct file_info_t*); void fs_init(void); enum file_status_t fs_mount( const char* mountpoint, struct mount_cntx_t* cntx, + fs_open_t open, + fs_close_t close, fs_stat_t stat ); +struct fs_handle_t* fs_open(const char* path); +void fs_close(struct fs_handle_t* handle); + +enum file_status_t fs_stat(struct fs_handle_t* handle, struct file_info_t* info); + #endif /* KERNEL_CORE_FS_H */ From 28fb4f21cd0a6da1c8b2c23ce60d124a77c8a86e Mon Sep 17 00:00:00 2001 From: Ebrahim Aleem Date: Fri, 10 Apr 2026 22:16:19 -0700 Subject: [PATCH 11/12] ext2 file reading --- drivers/ext2/ext2.c | 149 +++++++++++++++++++++++++++++++++------ kernel/core/fs.c | 15 +++- kernel/include/core/fs.h | 13 ++-- 3 files changed, 150 insertions(+), 27 deletions(-) diff --git a/drivers/ext2/ext2.c b/drivers/ext2/ext2.c index f39d174..0fd7252 100644 --- a/drivers/ext2/ext2.c +++ b/drivers/ext2/ext2.c @@ -29,6 +29,7 @@ #include #include +#include #define SUPERBLOCK_LBA 2 #define SUPERBLOCK_SECTORS 2 @@ -170,11 +171,13 @@ struct ext2_t { struct ext2_inode_handle_t { struct ext2_t* ext2; uint64_t inode_index; + uint64_t seek; + uint64_t seek_block; }; -struct ext2_dir_track_t { +struct ext2_block_track_t { struct ext2_inode_handle_t* handle; - struct ext2_inode_t* dir; + struct ext2_inode_t* inode; uint64_t off; uint64_t block; }; @@ -226,17 +229,17 @@ static uint8_t get_inode(const struct ext2_inode_handle_t* inode_handle, struct return 0; } -static uint8_t get_block_index_dir(struct ext2_dir_track_t* dt, uint64_t* index) { - uint64_t block = dt->block; - struct ext2_inode_t* inode = dt->dir; - struct ext2_t* ext2 = dt->handle->ext2; +static uint8_t get_block_index(struct ext2_block_track_t* bt, uint64_t* index) { + uint64_t block = bt->block; + struct ext2_inode_t* inode = bt->inode; + struct ext2_t* ext2 = bt->handle->ext2; if (block < DIRECT_BLOCKS) { *index = inode->i_block[block]; if (!*index) { - dt->block += 1; + bt->block += 1; return BLOCK_RETRY; } @@ -254,7 +257,7 @@ static uint8_t get_block_index_dir(struct ext2_dir_track_t* dt, uint64_t* index) *index = inode->i_block[INDIR_1]; if (!*index) { - dt->block += indir1; + bt->block += indir1; return BLOCK_RETRY; } @@ -268,7 +271,7 @@ static uint8_t get_block_index_dir(struct ext2_dir_track_t* dt, uint64_t* index) kfree(buffer); if (!*index) { - dt->block += 1; + bt->block += 1; return BLOCK_RETRY; } @@ -284,7 +287,7 @@ static uint8_t get_block_index_dir(struct ext2_dir_track_t* dt, uint64_t* index) *index = inode->i_block[INDIR_2]; if (!*index) { - dt->block += indir2; + bt->block += indir2; return BLOCK_RETRY; } @@ -298,7 +301,7 @@ static uint8_t get_block_index_dir(struct ext2_dir_track_t* dt, uint64_t* index) kfree(buffer); if (!*index) { - dt->block += indir1; + bt->block += indir1; return BLOCK_RETRY; } @@ -312,7 +315,7 @@ static uint8_t get_block_index_dir(struct ext2_dir_track_t* dt, uint64_t* index) kfree(buffer); if (!*index) { - dt->block += 1; + bt->block += 1; return BLOCK_RETRY; } @@ -327,7 +330,7 @@ static uint8_t get_block_index_dir(struct ext2_dir_track_t* dt, uint64_t* index) *index = inode->i_block[INDIR_3]; if (!*index) { - dt->block += indir3; + bt->block += indir3; return BLOCK_RETRY; } @@ -341,7 +344,7 @@ static uint8_t get_block_index_dir(struct ext2_dir_track_t* dt, uint64_t* index) kfree(buffer); if (!*index) { - dt->block += indir2; + bt->block += indir2; return BLOCK_RETRY; } @@ -355,7 +358,7 @@ static uint8_t get_block_index_dir(struct ext2_dir_track_t* dt, uint64_t* index) kfree(buffer); if (!*index) { - dt->block += indir1; + bt->block += indir1; return BLOCK_RETRY; } @@ -369,7 +372,7 @@ static uint8_t get_block_index_dir(struct ext2_dir_track_t* dt, uint64_t* index) kfree(buffer); if (!*index) { - dt->block += 1; + bt->block += 1; return BLOCK_RETRY; } @@ -393,7 +396,7 @@ static inline size_t path_entry_len(char* path) { static struct file_handle_t* ext2_open(struct mount_cntx_t* cntx, char* path) { struct ext2_inode_t inode; size_t path_len; - struct ext2_dir_track_t track; + struct ext2_block_track_t track; uint64_t block_index; uint8_t cntrl = 0; @@ -406,9 +409,12 @@ static struct file_handle_t* ext2_open(struct mount_cntx_t* cntx, char* path) { track.handle->ext2 = (struct ext2_t*)cntx; track.handle->inode_index = EXT2_ROOT_INO; + track.handle->seek = 0; + track.handle->seek_block = 0; const struct ext2_superblock_t* superblock = track.handle->ext2->superblock; const uint64_t block_size = 1024u << superblock->s_log_block_size; + const uint64_t size = (uint64_t)inode.i_size | ((uint64_t)inode.i_dir_acl << 32); void* buffer; while (*path && cntrl != 2) { @@ -418,18 +424,23 @@ static struct file_handle_t* ext2_open(struct mount_cntx_t* cntx, char* path) { return 0; } - track.dir = &inode; + track.inode = &inode; track.block = 0; track.off = 0; cntrl = 1; while (cntrl == 1) { + if (track.block * block_size > size) { + cntrl = 2; + break; + } + if (track.off >= block_size) { track.block++; track.off = 0; } - switch (get_block_index_dir(&track, &block_index)) { + switch (get_block_index(&track, &block_index)) { case BLOCK_OK: buffer = read_block(block_index, track.handle->ext2); if (!buffer) { @@ -457,11 +468,13 @@ static struct file_handle_t* ext2_open(struct mount_cntx_t* cntx, char* path) { cntrl = 0; } + kfree(buffer); break; } } track.off += entry->rec_len; + kfree(buffer); __attribute__((fallthrough)); case BLOCK_RETRY: continue; @@ -506,11 +519,84 @@ static enum file_status_t ext2_stat(struct file_handle_t* handle, struct file_in return FILE_NO_SUPPORT; } - info->size = inode.i_size; + info->size = (uint64_t)inode.i_size | ((uint64_t)inode.i_dir_acl << 32); return FILE_OK; } +static size_t ext2_read(struct file_handle_t* handle, void* buffer, size_t count) { + struct ext2_inode_t inode; + struct ext2_inode_handle_t* inode_handle = (struct ext2_inode_handle_t*)handle; + struct ext2_block_track_t track; + uint8_t* block_buffer = 0; + + if (!inode_handle || get_inode(inode_handle, &inode)) { + return 0; + } + + const uint64_t size = (uint64_t)inode.i_size | ((uint64_t)inode.i_dir_acl << 32); + const struct ext2_superblock_t* superblock = inode_handle->ext2->superblock; + const uint64_t block_size = 1024u << superblock->s_log_block_size; + + size_t read = 0; + uint64_t index; + uint64_t write_seek = 0; + size_t write_len; + + while (count) { + track.block = inode_handle->seek_block; + track.inode = &inode; + track.handle = inode_handle; + + if (track.block * block_size > size) { + break; + } + + write_len = block_size; // default full block + + if (count < block_size) { + // read partial, only requested + write_len = count; + } + + if (write_len + inode_handle->seek > block_size) { + // read partial, not past block + write_len = block_size - inode_handle->seek; + } + + switch (get_block_index(&track, &index)) { + case BLOCK_OK: + block_buffer = read_block(index, inode_handle->ext2); + + if (!block_buffer) { + return read; + } + + kmemcpy((uint8_t*)buffer + write_seek, block_buffer + inode_handle->seek, write_len); + + kfree(block_buffer); + break; + case BLOCK_RETRY: + kmemset((uint8_t*)buffer + write_seek, 0, write_len); + break; + default: + return read; + } + + write_seek += write_len; + inode_handle->seek += write_len; + count -= write_len; + read += write_len; + + if (inode_handle->seek == block_size) { + inode_handle->seek = 0; + inode_handle->seek_block++; + } + } + + return read; +} + uint8_t ext2_attempt_init(struct disk_t* disk, uint64_t start_lba, uint64_t end_lba) { struct ext2_superblock_t* superblock = kmalloc(sizeof(struct ext2_superblock_t)); struct ext2_bg_desc_t* bgdt; @@ -562,7 +648,8 @@ uint8_t ext2_attempt_init(struct disk_t* disk, uint64_t start_lba, uint64_t end_ (struct mount_cntx_t*)ext2, ext2_open, ext2_close, - ext2_stat + ext2_stat, + ext2_read ) != FILE_OK) { logging_log_error("Failed to mount rootfs"); panic(PANIC_STATE); @@ -582,7 +669,27 @@ uint8_t ext2_attempt_init(struct disk_t* disk, uint64_t start_lba, uint64_t end_ logging_log_debug("Root directory %u (%u)", stat_buf.size, stat_buf.type); + struct fs_handle_t* gpl_handle = fs_open("/usr/share/doc/ModulOS/LICENSES/GPLV3"); + if (!gpl_handle) { + logging_log_error("Failed to open GPL license"); + } + + if ((sts = fs_stat(gpl_handle, &stat_buf)) != FILE_OK) { + logging_log_error("Failed to stat GPL license %u", (uint32_t)sts); + } + + char* GPL = kmalloc(stat_buf.size + 1); + + if (stat_buf.size != fs_read(gpl_handle, GPL, stat_buf.size)) { + logging_log_error("Failed to read GPL license"); + } + + GPL[stat_buf.size] = 0; + + logging_log_debug("Read License\n%s", GPL); + fs_close(root_handle); + fs_close(gpl_handle); } //TODO: mount other volumes diff --git a/kernel/core/fs.c b/kernel/core/fs.c index fb24377..dbbdddc 100644 --- a/kernel/core/fs.c +++ b/kernel/core/fs.c @@ -37,6 +37,7 @@ struct vfs_mount_t { fs_open_t open; fs_close_t close; fs_stat_t stat; + fs_read_t read; }; struct fs_handle_t { @@ -84,7 +85,8 @@ enum file_status_t fs_mount( struct mount_cntx_t* cntx, fs_open_t open, fs_close_t close, - fs_stat_t stat + fs_stat_t stat, + fs_read_t read ) { if (kstrcmp(mountpoint, "") && !vfs_root.mount) { @@ -99,6 +101,7 @@ enum file_status_t fs_mount( vfs_root.mount->open = open; vfs_root.mount->close = close; vfs_root.mount->stat = stat; + vfs_root.mount->read = read; return FILE_OK; } @@ -220,3 +223,13 @@ enum file_status_t fs_stat(struct fs_handle_t* handle, struct file_info_t* info) lock_release(&fs_lock); return ret; } + +size_t fs_read(struct fs_handle_t* handle, void* buffer, size_t count) { + size_t ret; + + lock_acquire(&fs_lock); + ret = handle->mount->read(handle->handle, buffer, count); + lock_release(&fs_lock); + + return ret; +} diff --git a/kernel/include/core/fs.h b/kernel/include/core/fs.h index 7dc959c..7f05c67 100644 --- a/kernel/include/core/fs.h +++ b/kernel/include/core/fs.h @@ -1,4 +1,4 @@ -/* fs.c - kernel file system layer interface */ +/* fs.h - kernel file system layer interface */ /* Copyright (C) 2026 Ebrahim Aleem * * This program is free software: you can redistribute it and/or modify @@ -48,6 +48,7 @@ typedef struct file_handle_t* (*fs_open_t)(struct mount_cntx_t*, char*); typedef void (*fs_close_t)(struct file_handle_t*); typedef enum file_status_t (*fs_stat_t)(struct file_handle_t*, struct file_info_t*); +typedef size_t (*fs_read_t)(struct file_handle_t*, void*, size_t); void fs_init(void); @@ -56,12 +57,14 @@ enum file_status_t fs_mount( struct mount_cntx_t* cntx, fs_open_t open, fs_close_t close, - fs_stat_t stat + fs_stat_t stat, + fs_read_t read ); -struct fs_handle_t* fs_open(const char* path); -void fs_close(struct fs_handle_t* handle); +extern struct fs_handle_t* fs_open(const char* path); +extern void fs_close(struct fs_handle_t* handle); -enum file_status_t fs_stat(struct fs_handle_t* handle, struct file_info_t* info); +extern enum file_status_t fs_stat(struct fs_handle_t* handle, struct file_info_t* info); +extern size_t fs_read(struct fs_handle_t* handle, void* buffer, size_t count); #endif /* KERNEL_CORE_FS_H */ From d22b8b83fcbf0433b45cf3805e53dbb57fb4ed14 Mon Sep 17 00:00:00 2001 From: Ebrahim Aleem Date: Sat, 11 Apr 2026 11:53:33 -0700 Subject: [PATCH 12/12] removed ext2 read test --- Makefile | 2 +- drivers/ext2/ext2.c | 20 -------------------- 2 files changed, 1 insertion(+), 21 deletions(-) diff --git a/Makefile b/Makefile index 3337156..8336179 100644 --- a/Makefile +++ b/Makefile @@ -17,7 +17,7 @@ # Debug options -export DEBUG = 1 +#export DEBUG = 1 export DEBUG_LOGGING = 1 export SUPPRESS_ACPICA_BUILD_OUTPUT = 1 diff --git a/drivers/ext2/ext2.c b/drivers/ext2/ext2.c index 0fd7252..bc8e6b9 100644 --- a/drivers/ext2/ext2.c +++ b/drivers/ext2/ext2.c @@ -669,27 +669,7 @@ uint8_t ext2_attempt_init(struct disk_t* disk, uint64_t start_lba, uint64_t end_ logging_log_debug("Root directory %u (%u)", stat_buf.size, stat_buf.type); - struct fs_handle_t* gpl_handle = fs_open("/usr/share/doc/ModulOS/LICENSES/GPLV3"); - if (!gpl_handle) { - logging_log_error("Failed to open GPL license"); - } - - if ((sts = fs_stat(gpl_handle, &stat_buf)) != FILE_OK) { - logging_log_error("Failed to stat GPL license %u", (uint32_t)sts); - } - - char* GPL = kmalloc(stat_buf.size + 1); - - if (stat_buf.size != fs_read(gpl_handle, GPL, stat_buf.size)) { - logging_log_error("Failed to read GPL license"); - } - - GPL[stat_buf.size] = 0; - - logging_log_debug("Read License\n%s", GPL); - fs_close(root_handle); - fs_close(gpl_handle); } //TODO: mount other volumes