diff options
| -rw-r--r-- | .gitignore | 3 | ||||
| -rw-r--r-- | GNUmakefile | 2 | ||||
| -rw-r--r-- | kernel/GNUmakefile | 2 | ||||
| -rw-r--r-- | kernel/src/drivers/disk.cpp | 74 | ||||
| -rw-r--r-- | kernel/src/drivers/disk.hpp | 7 | ||||
| -rw-r--r-- | kernel/src/drivers/ext2.cpp | 679 | ||||
| -rw-r--r-- | kernel/src/drivers/ext2.hpp | 74 | ||||
| -rw-r--r-- | kernel/src/drivers/gpt.hpp | 28 | ||||
| -rw-r--r-- | kernel/src/generic/vfs.cpp | 134 | ||||
| -rw-r--r-- | kernel/src/generic/vfs.hpp | 173 | ||||
| -rw-r--r-- | kernel/src/klibc/string.cpp | 106 | ||||
| -rw-r--r-- | kernel/src/klibc/string.hpp | 6 | ||||
| -rw-r--r-- | kernel/src/utils/math.hpp | 3 | ||||
| -rw-r--r-- | limine.conf | 2 |
14 files changed, 1256 insertions, 37 deletions
@@ -3,4 +3,5 @@ *.iso *.hdd disk.img -disk_gpt.img
\ No newline at end of file +disk_gpt.img +*.img
\ No newline at end of file diff --git a/GNUmakefile b/GNUmakefile index e777f1f..276807d 100644 --- a/GNUmakefile +++ b/GNUmakefile @@ -5,7 +5,7 @@ ARCH := x86_64 # Default user QEMU flags. These are appended to the QEMU command calls. -QEMUFLAGS := -m 256M -d int -no-reboot -serial stdio +QEMUFLAGS := -m 256M -d int -serial stdio override IMAGE_NAME := orange-$(ARCH) diff --git a/kernel/GNUmakefile b/kernel/GNUmakefile index 538a975..055b8c2 100644 --- a/kernel/GNUmakefile +++ b/kernel/GNUmakefile @@ -46,7 +46,7 @@ ifeq ($(TOOLCHAIN),llvm) endif # User controllable C flags. -CFLAGS := -g -O3 -pipe -Werror -Wall +CFLAGS := -g -O3 -ffast-math -pipe -Werror -Wall -fomit-frame-pointer -funroll-loops -fno-exceptions -mllvm -force-vector-width=64 -mllvm -inline-threshold=1000 # User controllable C++ flags. We default to same as C flags. CXXFLAGS := $(CFLAGS) diff --git a/kernel/src/drivers/disk.cpp b/kernel/src/drivers/disk.cpp index 78477dd..36742f2 100644 --- a/kernel/src/drivers/disk.cpp +++ b/kernel/src/drivers/disk.cpp @@ -8,6 +8,13 @@ #include <drivers/gpt.hpp> #include <drivers/ext2.hpp> +std::uint8_t linux_fs_signature[16] = { + 0xAF, 0x3D, 0xC6, 0x0F, + 0x83, 0x84, + 0x72, 0x47, + 0x8E, 0x79, 0x3D, 0x69, 0xD8, 0x47, 0x7D, 0xE4 +}; + const char* disk_type_to_str(partition_style disk_type) { switch(disk_type) { case partition_style::err: @@ -66,13 +73,34 @@ const char* mbr_to_str(std::uint8_t type) { return "unknown"; } +bool disk_try_linux(disk* new_disk) { + bytes_to_block_res b = bytes_to_blocks(1024, 1024, new_disk->lba_size); + + char* buffer = (char*)(pmm::freelist::alloc_4k() + etc::hhdm()); + new_disk->read(new_disk->arg, buffer, b.lba, b.size_in_blocks); + ext2_superblock *sb = (ext2_superblock*)((std::uint64_t)buffer + b.offset); + + if (sb->s_magic == EXT2_MAGIC) { +#ifdef MBR_ORANGE_TRACE + klibc::printf("Disk: Detected ext2\r\n"); +#endif + drivers::ext2::init(new_disk, 0); + pmm::freelist::free((std::uint64_t)buffer - etc::hhdm()); + return true; + } else { + pmm::freelist::free((std::uint64_t)buffer - etc::hhdm()); + return false; + } + return false; +} + void disk_do_mbr_linux(disk* new_disk, std::uint64_t start_lba) { bytes_to_block_res b = bytes_to_blocks(1024, 1024, new_disk->lba_size); char* buffer = (char*)(pmm::freelist::alloc_4k() + etc::hhdm()); new_disk->read(new_disk->arg, buffer, start_lba + b.lba, b.size_in_blocks); - ext2_superblock *sb = (ext2_superblock*)buffer; + ext2_superblock *sb = (ext2_superblock*)((std::uint64_t)buffer + b.offset); if (sb->s_magic == EXT2_MAGIC) { #ifdef MBR_ORANGE_TRACE @@ -103,6 +131,43 @@ void disk_do_mbr(disk* new_disk) { pmm::freelist::free((std::uint64_t)buffer - etc::hhdm()); } +void print_gpt_guid(uint8_t *g) { + + klibc::printf("%02X%02X%02X%02X-%02X%02X-%02X%02X-%02X%02X-%02X%02X%02X%02X%02X%02X\r\n", + g[3], g[2], g[1], g[0], + g[5], g[4], + g[7], g[6], + g[8], g[9], + g[10], g[11], g[12], + g[13], g[14], g[15]); +} + +void disk_do_gpt(disk* new_disk) { + char* buffer = (char*)(pmm::freelist::alloc_4k() + etc::hhdm()); + new_disk->read(new_disk->arg, (char*)buffer, 1, 1); + gpt_lba1 lba1 = {}; + klibc::memcpy(&lba1, buffer, sizeof(gpt_lba1)); + new_disk->read(new_disk->arg, (char*)buffer, lba1.partition_lba, 1); + + gpt_partition_entry* part_table = (gpt_partition_entry*)buffer; + for(std::size_t i = 0;i < lba1.count_partitions; i++) { + gpt_partition_entry entry = part_table[i]; + if(klibc::memcmp(entry.guid, (uint8_t[16]){0}, 16) == 0) continue; +#ifdef MBR_ORANGE_TRACE + klibc::printf("gpt: detected fs with start_lba %lli with type ",entry.start_lba); + print_gpt_guid(entry.guid); +#endif + if(klibc::memcmp(entry.guid, linux_fs_signature, 16) == 0) { +#ifdef MBR_ORANGE_TRACE + klibc::printf("gpt: detected linux fs\r\n"); +#endif + disk_do_mbr_linux(new_disk, entry.start_lba); + } + } + + pmm::freelist::free((std::uint64_t)buffer - etc::hhdm()); +} + void drivers::init_disk(disk* new_disk) { if(disk_selftest(new_disk) == false) return; @@ -115,8 +180,13 @@ void drivers::init_disk(disk* new_disk) { case partition_style::mbr: disk_do_mbr(new_disk); break; + case partition_style::gpt: + disk_do_gpt(new_disk); + break; default: - assert(0,"unsupported disk\r\n"); + bool status = disk_try_linux(new_disk); + if(status == false) + assert(0,"unsupported disk\r\n"); break; } }
\ No newline at end of file diff --git a/kernel/src/drivers/disk.hpp b/kernel/src/drivers/disk.hpp index d1ac4b5..1186952 100644 --- a/kernel/src/drivers/disk.hpp +++ b/kernel/src/drivers/disk.hpp @@ -1,6 +1,7 @@ #pragma once #include <cstdint> #include <klibc/stdio.hpp> +#include <utils/align.hpp> enum class partition_style : std::uint8_t { err = 0, @@ -20,12 +21,14 @@ struct disk { struct bytes_to_block_res { std::uint64_t lba; std::uint64_t size_in_blocks; + std::uint64_t offset; }; inline static bytes_to_block_res bytes_to_blocks(std::uint64_t start, std::uint64_t size, std::uint64_t lba_size) { bytes_to_block_res result; - result.lba = start / lba_size; - result.size_in_blocks = (size / lba_size) == 0 ? 1 : (size / lba_size); + result.lba = ALIGNDOWN(start,lba_size) / lba_size; + result.size_in_blocks = (ALIGNUP(size,lba_size) / lba_size) == 0 ? 1 : (ALIGNUP(size,lba_size) / lba_size); + result.offset = start - ALIGNDOWN(start, lba_size); return result; } diff --git a/kernel/src/drivers/ext2.cpp b/kernel/src/drivers/ext2.cpp index f153e7a..34fdf32 100644 --- a/kernel/src/drivers/ext2.cpp +++ b/kernel/src/drivers/ext2.cpp @@ -5,43 +5,684 @@ #include <generic/hhdm.hpp> #include <utils/assert.hpp> #include <klibc/stdio.hpp> +#include <utils/math.hpp> +#include <klibc/string.hpp> +#include <utils/errno.hpp> #include <cstdint> -ext2_inode ext2_get_inode(ext2_partition* partition, std::uint64_t inode_num) { +inline static std::uint64_t inode_to_block_group(ext2_superblock* sb, std::uint64_t inode) { + return (inode - 1) / sb->s_inodes_per_group; +} - char* buffer = (char*)(pmm::freelist::alloc_4k() + etc::hhdm()); +inline static std::uint64_t inode_size(ext2_superblock* sb) { + return sb->revision >= 1 ? sb->inode_size : 128; +} - ext2_superblock* sb = partition->sb; - std::uint32_t group = (inode_num - 1) / sb->s_inodes_per_group; - std::uint32_t index = (inode_num - 1) % sb->s_inodes_per_group; +inline static std::uint64_t inode_to_index(ext2_superblock* sb, std::uint64_t inode) { + return div_remain(inode - 1, sb->s_inodes_per_group); +} - std::uint32_t bgdt_block = (sb->s_log_block_size == 0) ? 2 : 1; +inline static std::uint64_t inode_to_block(ext2_superblock* sb, std::uint64_t inode) { + std::uint64_t index = inode_to_index(sb, inode); + return (index * inode_size(sb)) / (1024 << sb->s_log_block_size); +} + +inline static std::uint64_t ext2_blocks_count(ext2_superblock* sb) { + if(sb->s_feature_incompat & EXT4_FEATURE_INCOMPAT_64BIT) { + return sb->s_blocks_count | ((std::uint64_t)sb->s_blocks_count_hi << 32); + } else + return sb->s_blocks_count; + return 0; +} + + +inline static bool ext2_test_bit(std::uint8_t* bitmap, std::uint32_t bit) { + return bitmap[bit / 8] & (1 << (bit % 8)); +} + +inline static void ext2_set_bit(std::uint8_t* bitmap, std::uint32_t bit) { + bitmap[bit / 8] |= (1 << (bit % 8)); +} + +inline static void ext2_clear_bit(std::uint8_t* bitmap, std::uint32_t bit) { + bitmap[bit / 8] &= ~(1 << (bit % 8)); +} + +ext2_inode ext2_get_inode(ext2_partition* partition, std::uint64_t inode_num, std::int32_t* status = nullptr) { + ext2_superblock* sb = partition->sb; std::uint32_t block_size = 1024 << sb->s_log_block_size; + + std::uint64_t group = inode_to_block_group(sb, inode_num); + + char* bgdt = (char*)(pmm::freelist::alloc_4k() + etc::hhdm()); + + bytes_to_block_res res; + + ext2_group_desc* gd = (ext2_group_desc*)((std::uint64_t)partition->cached_group + group * sizeof(ext2_group_desc)); + uint32_t inode_table_block = gd->bg_inode_table; + + uint32_t inode_byte_offset = inode_to_index(sb, inode_num) * inode_size(sb); + + uint32_t final_inode_block = gd->bg_inode_table + (inode_byte_offset / block_size); + uint32_t final_offset_in_block = div_remain(inode_byte_offset, block_size); + + res = bytes_to_blocks(final_inode_block * block_size, block_size, partition->target_disk->lba_size); + partition->target_disk->read(partition->target_disk->arg, bgdt, res.lba + partition->lba_start, res.size_in_blocks); + + ext2_inode actual_inode = {}; + klibc::memcpy(&actual_inode, bgdt + res.offset + final_offset_in_block, sizeof(ext2_inode)); + +#ifdef EXT2_ORANGE_TRACE + klibc::printf("ext2: inode_size %lli inode_to_block_group %lli inode_to_block %lli index %lli inode %lli inode per group %lli bgdt start %lli block size %lli block offset %lli block internal offset %lli inode_table_block %lli byte offset %lli inode block %lli offset inode in block %lli\r\n",inode_size(sb), inode_to_block_group(partition->sb,inode_num),inode_to_block(sb, inode_num), inode_to_index(sb, inode_num), inode_num, sb->s_inodes_per_group,bgdt_start_block, block_size, 0, 0, inode_table_block, inode_byte_offset, final_inode_block, final_offset_in_block); +#else + (void)inode_to_block; + (void)inode_table_block; +#endif + + pmm::freelist::free((std::uint64_t)bgdt - etc::hhdm()); + + if(status != nullptr) + *status = 0; + + return actual_inode; +} + +uint32_t read_indirect_ptr(ext2_partition* partition, std::uint64_t table_block, std::uint64_t index) { + if (table_block == 0) return 0; + std::uint32_t* buffer = (std::uint32_t*)(pmm::freelist::alloc_4k() + etc::hhdm()); + std::uint64_t saved_index = 0; + std::uint64_t block_size = 1024 << partition->sb->s_log_block_size; + bytes_to_block_res b = bytes_to_blocks(table_block * block_size, block_size / 4, partition->target_disk->lba_size); + partition->target_disk->read(partition->target_disk->arg, (char*)buffer, b.lba + partition->lba_start, b.size_in_blocks); + std::uint32_t* table = (std::uint32_t*)((std::uint64_t)buffer + b.offset); + saved_index = table[index]; + pmm::freelist::free((std::uint64_t)buffer - etc::hhdm()); + return saved_index; +} + +std::uint64_t get_extent_address(uint16_t hi, uint32_t lo) { + return (static_cast<uint64_t>(hi) << 32) | lo; +} + +void ext2_read_block(ext2_partition* partition, std::uint64_t block, char* buffer) { + bytes_to_block_res b = bytes_to_blocks(block * (1024 << partition->sb->s_log_block_size), 1024 << partition->sb->s_log_block_size, partition->target_disk->lba_size); + assert(b.offset == 0, "uhhhhh r :("); + partition->target_disk->read(partition->target_disk->arg, buffer, b.lba + partition->lba_start, b.size_in_blocks); +} + +void ext2_memcpy_block(ext2_partition* part, std::uint64_t block, void* buffer, std::size_t c) { + ext2_read_block(part, block, part->temp_buffer2); + klibc::memcpy(buffer, part->temp_buffer2, c); +} + +void ext2_write_block(ext2_partition* partition, std::uint64_t block, char* buffer) { + bytes_to_block_res b = bytes_to_blocks(block * (1024 << partition->sb->s_log_block_size), 1024 << partition->sb->s_log_block_size, partition->target_disk->lba_size); + assert(b.offset == 0, "uhhhhh w :("); + partition->target_disk->write(partition->target_disk->arg, buffer + b.offset, b.lba + partition->lba_start, b.size_in_blocks); +} + +std::uint64_t ext4_get_phys_block_extents(ext2_partition* part, ext4_extent_header* header, std::uint32_t logical_block) { + + assert(header->eh_magic == 0xF30A, "uhh :(("); + if (header->eh_magic != 0xF30A) return 0; + + if (header->eh_depth > 0) { + ext4_extent_idx* idx = (ext4_extent_idx*)((std::uint8_t*)header + sizeof(ext4_extent_header)); + int target_idx = -1; + + for (int i = 0; i < header->eh_entries; i++) { + if (logical_block >= idx[i].ei_block) { + target_idx = i; + } else { + break; + } + } + + if (target_idx == -1) return 0; + + std::uint64_t next_node_phys = get_extent_address(idx[target_idx].ei_leaf_hi, idx[target_idx].ei_leaf_lo); + + std::uint32_t block_size = 1024 << part->sb->s_log_block_size; + char* local_buf = new char[block_size]; + ext2_memcpy_block(part, next_node_phys, local_buf, block_size); + + std::uint64_t res = ext4_get_phys_block_extents(part, (ext4_extent_header*)local_buf, logical_block); + delete[] local_buf; + return res; + } else { + ext4_extent* ext = (ext4_extent*)((std::uint8_t*)header + sizeof(ext4_extent_header)); + + for (int i = 0; i < header->eh_entries; i++) { + std::uint32_t start_lblock = ext[i].ee_block; + std::uint32_t len = ext[i].ee_len; + if (len > 32768) len -= 32768; + + if (logical_block >= start_lblock && logical_block < start_lblock + len) { + std::uint64_t phys_start = get_extent_address(ext[i].ee_start_hi, ext[i].ee_start_lo); + return phys_start + (logical_block - start_lblock); + } + } + } + + return 0; +} + + +std::uint64_t get_phys_block(ext2_partition* partition, ext2_inode *node, std::uint32_t logical_block) { + + if(partition->sb->s_feature_incompat & EXT4_FEATURE_INCOMPAT_EXTENTS) { + return ext4_get_phys_block_extents(partition, (ext4_extent_header*)node->i_block, logical_block); + } + + std::uint32_t block_size = 1024 << partition->sb->s_log_block_size; + std::uint64_t ptrs_per_block = block_size / 4; + + if (logical_block < 12) { + return node->i_block[logical_block]; + } + logical_block -= 12; + + if (logical_block < ptrs_per_block) { + return read_indirect_ptr(partition, node->i_block[12], logical_block); + } + logical_block -= ptrs_per_block; + + std::uint64_t doubly_limit = ptrs_per_block * ptrs_per_block; + if (logical_block < doubly_limit) { + std::uint64_t a = logical_block / ptrs_per_block; + std::uint64_t b = logical_block % ptrs_per_block; + + std::uint64_t first_level_ptr = read_indirect_ptr(partition, node->i_block[13], a); + return read_indirect_ptr(partition, first_level_ptr, b); + } + logical_block -= doubly_limit; + + std::uint64_t triply_limit = ptrs_per_block * ptrs_per_block * ptrs_per_block; + if (logical_block < triply_limit) { + std::uint64_t a = logical_block / (ptrs_per_block * ptrs_per_block); + std::uint64_t remaining = logical_block % (ptrs_per_block * ptrs_per_block); + std::uint64_t b = remaining / ptrs_per_block; + std::uint64_t c = remaining % ptrs_per_block; + + std::uint64_t L1_ptr = read_indirect_ptr(partition, node->i_block[14], a); + std::uint64_t L2_ptr = read_indirect_ptr(partition, L1_ptr, b); + return read_indirect_ptr(partition, L2_ptr, c); + } - bytes_to_block_res result = bytes_to_blocks(block_size * bgdt_block, block_size, partition->target_disk->lba_size); - partition->target_disk->read(partition->target_disk->arg, buffer, result.lba, result.size_in_blocks); + return 0; +} + + +std::uint64_t ext2_find_child(ext2_partition* part, ext2_inode* dir_inode, const char* name) { + std::uint32_t block_size = 1024 << part->sb->s_log_block_size; + char* block_buffer = (char*)(pmm::freelist::alloc_4k() + etc::hhdm()); - struct ext2_group_desc *gd = (struct ext2_group_desc *)((std::uint64_t)buffer + group); + std::uint64_t num_blocks = dir_inode->i_size / block_size; + for (std::uint64_t i = 0; i < num_blocks; i++) { + std::uint64_t phys_block = get_phys_block(part, dir_inode, i); + if (phys_block == 0) continue; - uint32_t inode_size = 128; - uint32_t byte_offset = index * inode_size; - uint32_t block_in_table = gd->bg_inode_table + (byte_offset / block_size); - uint32_t internal_offset = byte_offset % block_size; + ext2_read_block(part, phys_block, block_buffer); - result = bytes_to_blocks(block_size * block_in_table, block_size, partition->target_disk->lba_size); + ext2_dir_entry* entry = (ext2_dir_entry*)block_buffer; + std::uint64_t offset = 0; - char* inode_buffer = (char*)(pmm::freelist::alloc_4k() + etc::hhdm()); - partition->target_disk->read(partition->target_disk->arg, inode_buffer, result.lba, result.size_in_blocks); + while (offset < block_size && entry->inode != 0) { + if (klibc::strlen(name) == entry->name_len && + klibc::memcmp(name, entry->name, entry->name_len) == 0) { + + std::uint64_t found_inode = entry->inode; + pmm::freelist::free((std::uint64_t)block_buffer - etc::hhdm()); + return found_inode; + } - pmm::freelist::free((std::uint64_t)buffer - etc::hhdm()); - return *(struct ext2_inode*)((std::uint64_t)inode_buffer + internal_offset); + offset += entry->rec_len; + entry = (ext2_dir_entry*)(block_buffer + offset); + } + } + + pmm::freelist::free((std::uint64_t)block_buffer - etc::hhdm()); + return 0; +} + +std::int32_t ext2_lookup(ext2_partition* part, const char* path, ext2_inode* out, std::uint64_t* inode_out) { + uint32_t current_inode_num = 2; + ext2_inode current_inode = ext2_get_inode(part, 2); + + char path_copy[1024]; + klibc::memcpy(path_copy, path, klibc::strlen(path)); + + char* saveptr; + char* token = klibc::strtok(&saveptr, path_copy, "/"); + +#ifdef EXT2_ORANGE_TRACE + klibc::printf("ext2: trying to lookup %s\r\n",path); +#endif + + while (token != nullptr) { + if ((current_inode.i_mode & 0xF000) != 0x4000) { + return -ENOTDIR; + } + + current_inode_num = ext2_find_child(part, ¤t_inode, token); + if (current_inode_num == 0) { + return -ENOENT; + } + + current_inode = ext2_get_inode(part, current_inode_num); + token = klibc::strtok(&saveptr, nullptr, "/"); + } + + +#ifdef EXT2_ORANGE_TRACE + klibc::printf("ext2: return inode %lli (%s)\r\n", current_inode_num, path); +#endif + + *inode_out = current_inode_num; + *out = current_inode; + return 0; +} + +std::int64_t ext2_alloc_blocks(ext2_partition* part, uint32_t count, uint64_t* out) { + uint64_t blocks_per_group = part->sb->s_blocks_per_group; + uint64_t total_groups = (ext2_blocks_count(part->sb) + blocks_per_group - 1) / blocks_per_group; + + uint8_t* bitmap = (uint8_t*)(pmm::freelist::alloc_4k() + etc::hhdm()); + uint64_t allocated_so_far = 0; + + for (uint32_t g = 0; g < total_groups; g++) { + ext2_group_desc* gd = &((ext2_group_desc*)part->cached_group)[g]; + if (gd->bg_free_blocks_count < count) continue; + + ext2_read_block(part, gd->bg_block_bitmap, (char*)bitmap); + + for (uint32_t i = 0; i <= blocks_per_group - count; i++) { + bool found = true; + for (uint32_t j = 0; j < count; j++) { + if (ext2_test_bit(bitmap, i + j)) { + found = false; + break; + } + } + + if (found) { + for (uint32_t j = 0; j < count; j++) { + ext2_set_bit(bitmap, i + j); + out[j] = (uint64_t)g * blocks_per_group + i + j + part->sb->s_first_data_block; + } + ext2_write_block(part, gd->bg_block_bitmap, (char*)bitmap); + gd->bg_free_blocks_count -= count; + pmm::freelist::free((uint64_t)bitmap - etc::hhdm()); + return 0; + } + } + } + + for (uint32_t g = 0; g < total_groups && allocated_so_far < count; g++) { + ext2_group_desc* gd = &((ext2_group_desc*)part->cached_group)[g]; + if (gd->bg_free_blocks_count == 0) continue; + + ext2_read_block(part, gd->bg_block_bitmap, (char*)bitmap); + bool changed = false; + + for (uint32_t i = 0; i < blocks_per_group && allocated_so_far < count; i++) { + if (!ext2_test_bit(bitmap, i)) { + ext2_set_bit(bitmap, i); + out[allocated_so_far++] = (uint64_t)g * blocks_per_group + i + part->sb->s_first_data_block; + gd->bg_free_blocks_count--; + changed = true; + } + } + if (changed) ext2_write_block(part, gd->bg_block_bitmap, (char*)bitmap); + } + + pmm::freelist::free((uint64_t)bitmap - etc::hhdm()); + return (allocated_so_far == count) ? 0 : -ENOSPC; +} + +void ext2_free_blocks(ext2_partition* part, uint32_t count, uint64_t* blocks) { + uint32_t blocks_per_group = part->sb->s_blocks_per_group; + uint8_t* bitmap = (uint8_t*)(pmm::freelist::alloc_4k() + etc::hhdm()); + + for (uint32_t i = 0; i < count; i++) { + uint64_t abs_block = blocks[i] - part->sb->s_first_data_block; + uint32_t group = abs_block / blocks_per_group; + uint32_t index = abs_block % blocks_per_group; + + ext2_group_desc* gd = &((ext2_group_desc*)part->cached_group)[group]; + + ext2_read_block(part, gd->bg_block_bitmap, (char*)bitmap); + if (ext2_test_bit(bitmap, index)) { + ext2_clear_bit(bitmap, index); + gd->bg_free_blocks_count++; + ext2_write_block(part, gd->bg_block_bitmap, (char*)bitmap); + } + } + pmm::freelist::free((uint64_t)bitmap - etc::hhdm()); +} + +signed long ext2_read(file_descriptor* file, void* buffer, signed long count) { + if (count <= 0) return 0; + + file->vnode.fs->lock.lock(); + + std::int32_t status = 0; + ext2_partition* part = (ext2_partition*)(file->vnode.fs->fs_specific.partition); + ext2_inode inode = ext2_get_inode(part, file->fs_specific.ino, &status); + + if (status != 0) { + file->vnode.fs->lock.unlock(); + return status; + } + + if (file->offset >= inode.i_size) { + file->vnode.fs->lock.unlock(); + return 0; + } + + if (file->offset + count > inode.i_size) { + count = inode.i_size - file->offset; + } + + std::uint32_t block_size = 1024 << part->sb->s_log_block_size; + char* temp_block = (char*)(pmm::freelist::alloc_4k() + etc::hhdm()); + + signed long total_read = 0; + char* out_ptr = (char*)buffer; + + while (total_read < count) { + std::uint64_t logical_block = (file->offset + total_read) / block_size; + std::uint64_t block_offset = (file->offset + total_read) % block_size; + + std::uint64_t phys_block = get_phys_block(part, &inode, logical_block); + + if (phys_block == 0) { + klibc::memset(temp_block, 0, block_size); + } else { + ext2_read_block(part, phys_block, temp_block); + } + + std::uint32_t to_copy = block_size - block_offset; + if (to_copy > (std::uint32_t)(count - total_read)) { + to_copy = count - total_read; + } + + klibc::memcpy(out_ptr + total_read, temp_block + block_offset, to_copy); + + total_read += to_copy; + } + + file->offset += total_read; + + pmm::freelist::free((std::uint64_t)temp_block - etc::hhdm()); + file->vnode.fs->lock.unlock(); + + return total_read; +} + +uint32_t set_indirect_ptr(ext2_partition* part, uint32_t table_block, uint32_t index, uint32_t new_val) { + uint32_t* buffer = (uint32_t*)(pmm::freelist::alloc_4k() + etc::hhdm()); + ext2_read_block(part, table_block, (char*)buffer); + buffer[index] = new_val; + ext2_write_block(part, table_block, (char*)buffer); + pmm::freelist::free((uint64_t)buffer - etc::hhdm()); + return new_val; +} + +uint64_t get_or_alloc_phys_block(ext2_partition* part, ext2_inode* node, uint32_t logical_block, bool* dirty) { + uint32_t block_size = 1024 << part->sb->s_log_block_size; + uint32_t ptrs_per_block = block_size / 4; + + auto alloc_one = [&]() { + uint64_t b = 0; + ext2_alloc_blocks(part, 1, &b); + char* zero = (char*)(pmm::freelist::alloc_4k() + etc::hhdm()); + klibc::memset(zero, 0, block_size); + ext2_write_block(part, b, zero); + pmm::freelist::free((uint64_t)zero - etc::hhdm()); + *dirty = true; + return (uint32_t)b; + }; + + if (logical_block < 12) { + if (!node->i_block[logical_block]) node->i_block[logical_block] = alloc_one(); + return node->i_block[logical_block]; + } + logical_block -= 12; + + if (logical_block < ptrs_per_block) { + if (!node->i_block[12]) node->i_block[12] = alloc_one(); + uint32_t phys = read_indirect_ptr(part, node->i_block[12], logical_block); + if (!phys) phys = set_indirect_ptr(part, node->i_block[12], logical_block, alloc_one()); + return phys; + } + logical_block -= ptrs_per_block; + + uint64_t doubly_limit = ptrs_per_block * ptrs_per_block; + if (logical_block < doubly_limit) { + if (!node->i_block[13]) node->i_block[13] = alloc_one(); + uint32_t a = logical_block / ptrs_per_block; + uint32_t b = logical_block % ptrs_per_block; + + uint32_t L1 = read_indirect_ptr(part, node->i_block[13], a); + if (!L1) L1 = set_indirect_ptr(part, node->i_block[13], a, alloc_one()); + + uint32_t phys = read_indirect_ptr(part, L1, b); + if (!phys) phys = set_indirect_ptr(part, L1, b, alloc_one()); + return phys; + } + logical_block -= doubly_limit; + + if (!node->i_block[14]) node->i_block[14] = alloc_one(); + uint32_t a = logical_block / (ptrs_per_block * ptrs_per_block); + uint32_t rem = logical_block % (ptrs_per_block * ptrs_per_block); + uint32_t b = rem / ptrs_per_block; + uint32_t c = rem % ptrs_per_block; + + uint32_t L1 = read_indirect_ptr(part, node->i_block[14], a); + if (!L1) L1 = set_indirect_ptr(part, node->i_block[14], a, alloc_one()); + uint32_t L2 = read_indirect_ptr(part, L1, b); + if (!L2) L2 = set_indirect_ptr(part, L1, b, alloc_one()); + uint32_t phys = read_indirect_ptr(part, L2, c); + if (!phys) phys = set_indirect_ptr(part, L2, c, alloc_one()); + + return phys; +} + +void ext2_write_inode(ext2_partition* part, uint64_t ino, ext2_inode* inode) { + ext2_superblock* sb = part->sb; + uint32_t block_size = 1024 << sb->s_log_block_size; + uint32_t group = inode_to_block_group(sb, ino); + ext2_group_desc* gd = (ext2_group_desc*)((uint64_t)part->cached_group + group * sizeof(ext2_group_desc)); + + uint32_t inode_off = inode_to_index(sb, ino) * inode_size(sb); + uint32_t block = gd->bg_inode_table + (inode_off / block_size); + uint32_t off_in_block = inode_off % block_size; + + char* buf = (char*)(pmm::freelist::alloc_4k() + etc::hhdm()); + ext2_read_block(part, block, buf); + klibc::memcpy(buf + off_in_block, inode, sizeof(ext2_inode)); + ext2_write_block(part, block, buf); + pmm::freelist::free((uint64_t)buf - etc::hhdm()); +} + +signed long ext2_write(file_descriptor* file, void* buffer, signed long count) { + if (count <= 0) return 0; + file->vnode.fs->lock.lock(); + + ext2_partition* part = (ext2_partition*)(file->vnode.fs->fs_specific.partition); + ext2_inode inode = ext2_get_inode(part, file->fs_specific.ino, nullptr); + uint32_t block_size = 1024 << part->sb->s_log_block_size; + char* temp_block = (char*)(pmm::freelist::alloc_4k() + etc::hhdm()); + + signed long total_written = 0; + const char* in_ptr = (const char*)buffer; + bool inode_dirty = false; + + while (total_written < count) { + uint64_t logical_block = (file->offset) / block_size; + uint64_t block_offset = (file->offset) % block_size; + uint32_t to_write = block_size - block_offset; + if (to_write > (uint32_t)(count - total_written)) to_write = count - total_written; + + uint64_t phys_block = get_or_alloc_phys_block(part, &inode, logical_block, &inode_dirty); + + if (to_write < block_size) { + ext2_read_block(part, phys_block, temp_block); + } + + klibc::memcpy(temp_block + block_offset, in_ptr + total_written, to_write); + ext2_write_block(part, phys_block, temp_block); + + file->offset += to_write; + total_written += to_write; + + if (file->offset > inode.i_size) { + inode.i_size = file->offset; + inode_dirty = true; + } + } + + if (inode_dirty) { + ext2_write_inode(part, file->fs_specific.ino, &inode); + } + + pmm::freelist::free((uint64_t)temp_block - etc::hhdm()); + file->vnode.fs->lock.unlock(); + return total_written; +} + +std::uint32_t ext2_open(filesystem* fs, void* file_desc, char* path) { + fs->lock.lock(); + ext2_inode res; + std::uint64_t inode_num = 0; + std::uint32_t status = ext2_lookup((ext2_partition*)(fs->fs_specific.partition), path, &res, &inode_num); + if(status != 0) { fs->lock.unlock(); + return status; } + file_descriptor* fd = (file_descriptor*)file_desc; + fd->fs_specific.ino = inode_num; + fd->vnode.fs = fs; + fd->vnode.read = ext2_read; + fd->vnode.write = ext2_write; + fs->lock.unlock(); + return 0; +} + +std::int32_t ext2_stat(file_descriptor* file, stat* out) { + std::int32_t status = 0; + ext2_partition* part = (ext2_partition*)(file->vnode.fs->fs_specific.partition); + ext2_inode inode = ext2_get_inode(part, file->fs_specific.ino, &status); + + if (status != 0) { + file->vnode.fs->lock.unlock(); + return status; + } + + out->st_atim.tv_nsec = 0; + out->st_atim.tv_sec = inode.i_atime; + out->st_ctim.tv_nsec = 0; + out->st_ctim.tv_sec = inode.i_ctime; + out->st_mtim.tv_nsec = 0; + out->st_mtim.tv_sec = inode.i_mtime; + out->st_blksize = 1024 << part->sb->s_log_block_size; + out->st_blocks = ALIGNUP(inode.i_size, out->st_blksize) / out->st_blksize; + out->st_size = inode.i_size; + out->st_uid = inode.i_uid; + out->st_gid = inode.i_gid; + out->st_dev = 0; + out->st_rdev = 0; // should be filled by vfs + out->st_nlink = inode.i_links_count; + out->st_mode = inode.i_mode; + + return 0; +} + +void ext2_load_group_descriptors(ext2_partition* part) { + uint32_t block_size = 1024 << part->sb->s_log_block_size; + + uint32_t bgdt_block = (block_size == 1024) ? 2 : 1; + + uint32_t blocks_per_group = part->sb->s_blocks_per_group; + uint32_t groups_count = (ext2_blocks_count(part->sb) + blocks_per_group - 1) / blocks_per_group; + + uint32_t table_size_bytes = groups_count * sizeof(ext2_group_desc); + uint32_t table_size_blocks = (table_size_bytes + block_size - 1) / block_size; + + for (uint32_t i = 0; i < table_size_blocks; i++) { + ext2_read_block(part, bgdt_block + i, (char*)((uint64_t)part->cached_group + (i * block_size))); + } +} + +static inline int isprint(int c) { + return (c >= 0x20 && c <= 0x7E); +} + + +static inline void print_buffer(const unsigned char *buffer, std::size_t size) { + + for (std::size_t i = 0; i < size; i++) { + + if(buffer[i] == '\0') + continue; + + if (isprint(buffer[i])) { + klibc::printf("%c ", buffer[i]); + } else { + klibc::printf("0x%02X ", buffer[i]); + } + } + klibc::printf("\r\n"); } void drivers::ext2::init(disk* target_disk, std::uint64_t lba_start) { bytes_to_block_res b = bytes_to_blocks(1024, 1024, target_disk->lba_size); char* buffer = (char*)(pmm::freelist::alloc_4k() + etc::hhdm()); target_disk->read(target_disk->arg, buffer, lba_start + b.lba, b.size_in_blocks); - ext2_superblock *sb = (ext2_superblock*)buffer; + ext2_superblock *sb = (ext2_superblock*)((std::uint64_t)buffer + b.offset); assert(sb->s_magic == EXT2_MAGIC,"its not ext2 partition !"); + + if((1024 << sb->s_log_block_size) > PAGE_SIZE) { + klibc::printf("ext2: partition block size is bigger than page_size ! (todo mb) \r\n"); + return; + } + + if(sb->revision >= 1) { + klibc::printf("ext2: detected features %s %s %s\r\n",(sb->s_feature_ro_compat & EXT2_FEATURE_RO_COMPAT_LARGE_FILE) ? "EXT2_FEATURE_RO_COMPAT_LARGE_FILE" : "", (sb->s_feature_incompat & EXT4_FEATURE_INCOMPAT_64BIT) ? "EXT4_FEATURE_INCOMPAT_64BIT" : "", (sb->s_feature_incompat & EXT4_FEATURE_INCOMPAT_EXTENTS) ? "EXT4_FEATURE_INCOMPAT_EXTENTS" : ""); + } + + uint32_t groups_count = (ext2_blocks_count(sb) + sb->s_blocks_per_group - 1); + + ext2_partition* part = new ext2_partition; + part->buffer = (char*)(pmm::freelist::alloc_4k() + etc::hhdm()); + part->lba_start = lba_start; + part->lock.unlock(); + part->sb = sb; + part->target_disk = target_disk; + part->cached_group = (void*)(pmm::buddy::alloc(groups_count * sizeof(ext2_group_desc)).phys + etc::hhdm()); + + ext2_load_group_descriptors(part); + + ext2_inode root = ext2_get_inode(part, 2); + klibc::printf("inode 2 size %lli links count %lli mode 0x%p block_size %lli\r\n",root.i_size, root.i_links_count, root.i_mode, 1024 << part->sb->s_log_block_size); + klibc::printf("logic blocks for root first block = %lli, second block = %lli\r\n", get_phys_block(part, &root, 0),get_phys_block(part, &root, 1)); + (void)print_buffer; + + char* buffer2 = (char*)(pmm::freelist::alloc_4k() + etc::hhdm()); + ext2_read_block(part, get_phys_block(part, &root, 0), buffer2); + klibc::printf("dumping first root block\r\n"); + print_buffer((const unsigned char*)buffer2, 1024 << part->sb->s_log_block_size); + + const char* file_test = "/test1/meow"; + ext2_inode res = {}; + std::uint64_t in = 0; + std::int32_t status = ext2_lookup(part, file_test, &res, &in); + + klibc::memset(buffer2, 0, PAGE_SIZE); + klibc::printf("reading file %s, status %d, size %lli\r\n", file_test, status, res.i_size); + ext2_read_block(part, get_phys_block(part, &res, 0), buffer2); + klibc::printf("%s\r\n", buffer2); + + klibc::printf("group count %lli (size %lli)\r\n",groups_count,groups_count * sizeof(ext2_group_desc)); + }
\ No newline at end of file diff --git a/kernel/src/drivers/ext2.hpp b/kernel/src/drivers/ext2.hpp index bfede39..4fdcd3c 100644 --- a/kernel/src/drivers/ext2.hpp +++ b/kernel/src/drivers/ext2.hpp @@ -3,6 +3,14 @@ #include <drivers/disk.hpp> #include <generic/lock/mutex.hpp> +//#define EXT2_ORANGE_TRACE + +#define EXT4_FEATURE_INCOMPAT_64BIT 0x0080 +#define EXT2_FEATURE_RO_COMPAT_LARGE_FILE 0x0002 +#define EXT4_FEATURE_INCOMPAT_EXTENTS 0x0040 + +#include <stdint.h> + struct ext2_superblock { uint32_t s_inodes_count; uint32_t s_blocks_count; @@ -23,7 +31,47 @@ struct ext2_superblock { 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 revision; + uint16_t s_def_resuid; + uint16_t s_def_resgid; + + uint32_t s_first_ino; + uint16_t 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]; + char s_volume_name[16]; + char s_last_mounted[64]; + uint32_t s_algo_bitmap; + + uint8_t s_prealloc_blocks; + uint8_t s_prealloc_dir_blocks; + uint16_t s_reserved_gdt_blocks; + + uint8_t s_journal_uuid[16]; + uint32_t s_journal_inum; + uint32_t s_journal_dev; + uint32_t s_last_orphan; + + uint32_t s_hash_seed[4]; + uint8_t s_def_hash_version; + uint8_t s_jnl_backup_type; + uint16_t s_desc_size; + uint32_t s_default_mount_opts; + uint32_t s_first_meta_bg; + uint32_t s_mkfs_time; + uint32_t s_jnl_blocks[17]; + + uint32_t s_blocks_count_hi; + uint32_t s_r_blocks_count_hi; + uint32_t s_free_blocks_count_hi; +} __attribute__((packed)); + struct ext2_group_desc { uint32_t bg_block_bitmap; @@ -68,11 +116,35 @@ struct ext2_dir_entry { struct ext2_partition { std::uint64_t lba_start; ext2_superblock* sb; + void* cached_group; locks::mutex lock; disk* target_disk; + char* temp_buffer2; char* buffer; }; +struct ext4_extent_header { + uint16_t eh_magic; + uint16_t eh_entries; + uint16_t eh_max; + uint16_t eh_depth; + uint32_t eh_generation; +}; + +struct ext4_extent { + uint32_t ee_block; + uint16_t ee_len; + uint16_t ee_start_hi; + uint32_t ee_start_lo; +}; + +struct ext4_extent_idx { + uint32_t ei_block; + uint32_t ei_leaf_lo; + uint16_t ei_leaf_hi; + uint16_t ei_unused; +}; + #define EXT2_MAGIC 0xEF53 namespace drivers { diff --git a/kernel/src/drivers/gpt.hpp b/kernel/src/drivers/gpt.hpp index 9f43b54..109ede6 100644 --- a/kernel/src/drivers/gpt.hpp +++ b/kernel/src/drivers/gpt.hpp @@ -1,4 +1,32 @@ #pragma once #include <cstdint> +struct __attribute__((packed)) gpt_lba1 { + std::uint8_t signature[8]; + std::uint32_t revision; + std::uint32_t size; + std::uint32_t crc32; + std::uint32_t reserved; + std::uint64_t current_lba; + std::uint64_t other_lba; + std::uint64_t first_usable; + std::uint64_t last_usable; + std::uint8_t guid[16]; + std::uint64_t partition_lba; + std::uint32_t count_partitions; + std::uint32_t size_of_partition; +}; + +struct __attribute__((packed)) gpt_partition_entry { + std::uint8_t guid[16]; + std::uint8_t unique_guid[16]; + std::uint64_t start_lba; + std::uint64_t end_lba; + std::uint64_t attributes; + std::uint8_t name[72]; +}; + +static_assert(sizeof(gpt_partition_entry) == (0x38 + 72)); +static_assert(sizeof(gpt_lba1) == 0x58); + #define GPT_SIGNATURE "EFI PART"
\ No newline at end of file diff --git a/kernel/src/generic/vfs.cpp b/kernel/src/generic/vfs.cpp index d34ae0c..75c3ed8 100644 --- a/kernel/src/generic/vfs.cpp +++ b/kernel/src/generic/vfs.cpp @@ -1,6 +1,140 @@ #include <cstdint> #include <generic/vfs.hpp> #include <drivers/disk.hpp> +#include <klibc/string.hpp> +#include <utils/errno.hpp> +#include <klibc/stdio.hpp> +#include <generic/lock/mutex.hpp> + +// /bin/path -> /usr/bin/path +void __vfs_symlink_resolve_no_at_symlink_follow(char* path, char* out) { + char *next = nullptr; + char buffer[4096]; + + int e = vfs::readlink(path,buffer,4096); + + if(e == ENOSYS) + klibc::memcpy(out,path,klibc::strlen(path) + 1); + + if(e == EINVAL) + klibc::memcpy(out,path,klibc::strlen(path) + 1); + else if(e == 0) { + + klibc::memcpy(out,path,klibc::strlen(path) + 1); + } else if(e == ENOENT) { + klibc::memcpy(out,path,klibc::strlen(path) + 1); + // maybe it wants directory symlink ? + char path0[4096]; + klibc::memcpy(path0,path,klibc::strlen(path) + 1); + + char result[4096]; + + int c = 0; + + char* token = klibc::strtok(&next, path0, "/"); + + /* Start building path from null and trying to find symlink */ + while(token) { + + result[c] = '/'; + c++; + + std::uint64_t mm = 0; + mm = klibc::strlen(token); + klibc::memcpy((char*)((std::uint64_t)result + c),token,mm); + c += mm; + result[c] = '\0'; + + e = vfs::readlink(result,buffer,4096); + if(e == 0) { + char buffer2[4096]; + vfs::resolve_path(buffer,result,buffer2,0); + c = klibc::strlen(buffer2); + buffer2[c++] = '/'; + klibc::memcpy(buffer2 + c, path + klibc::strlen(result) + 1, klibc::strlen(path) - klibc::strlen(result)); + __vfs_symlink_resolve_no_at_symlink_follow(buffer2,out); + return; + } else if(e == ENOENT) { + klibc::memcpy(out,path,klibc::strlen(path) + 1); + } + + token = klibc::strtok(&next,0,"/"); + } + klibc::memcpy(out,path,klibc::strlen(path) + 1); + } +} + +void __vfs_symlink_resolve(char* path, char* out, int level) { + + char *next = nullptr; + + char buffer[4096]; + + if(level == 25) { + // hell no :skull: + klibc::memcpy(out,path,klibc::strlen(path) + 1); + return; + } + + int e = vfs::readlink(path,buffer,4096); + + if(e == ENOSYS) + klibc::memcpy(out,path,klibc::strlen(path) + 1); + + if(e == EINVAL) + klibc::memcpy(out,path,klibc::strlen(path) + 1); + else if(e == 0) { + + char result[4096]; + vfs::resolve_path(buffer,path,result,0); + __vfs_symlink_resolve(result,out, level + 1); + } else if(e == ENOENT) { + klibc::memcpy(out,path,klibc::strlen(path) + 1); + // maybe it wants directory symlink ? + char path0[4096]; + klibc::memcpy(path0,path,klibc::strlen(path) + 1); + + char result[4096]; + + int c = 0; + + char* token = klibc::strtok(&next, path0, "/"); + + /* Start building path from null and trying to find symlink */ + while(token) { + + result[c] = '/'; + c++; + + std::uint64_t mm = 0; + mm = klibc::strlen(token); + klibc:: memcpy((char*)((std::uint64_t)result + c),token,mm); + c += mm; + result[c] = '\0'; + + e = vfs::readlink(result,buffer,4096); + if(e == 0) { + char buffer2[4096]; + vfs::resolve_path(buffer,result,buffer2,0); + c = klibc::strlen(buffer2); + buffer2[c++] = '/'; + klibc::memcpy(buffer2 + c, path + klibc::strlen(result) + 1, klibc::strlen(path) - klibc::strlen(result)); + __vfs_symlink_resolve(buffer2,out, level + 1); + return; + } else if(e == ENOENT) { + klibc::memcpy(out,path,klibc::strlen(path) + 1); + return; + } else { + klibc::memcpy(out,path,klibc::strlen(path) + 1); + return; + } + + token = klibc::strtok(&next,0,"/"); + } + klibc::memcpy(out,path,klibc::strlen(path) + 1); + } +} + void vfs::init() { diff --git a/kernel/src/generic/vfs.hpp b/kernel/src/generic/vfs.hpp index 8736d42..d6fac32 100644 --- a/kernel/src/generic/vfs.hpp +++ b/kernel/src/generic/vfs.hpp @@ -37,7 +37,11 @@ struct stat { struct filesystem { locks::mutex lock; - std::uint32_t (*open)(void* file_desc, char* path); + union { + std::uint64_t partition; + } fs_specific; + + std::uint32_t (*open)(filesystem* fs, void* file_desc, char* path); char path[2048]; }; @@ -45,30 +49,181 @@ struct filesystem { struct file_descriptor { file_descriptor_type type; + + std::size_t offset; std::uint32_t flags; - union fs_specific { + union { std::uint64_t ino; std::uint64_t tmpfs_pointer; - }; + } fs_specific; - struct vnode { + struct { disk* target_disk; filesystem* fs; signed long (*read)(file_descriptor* file, void* buffer, signed long count); signed long (*write)(file_descriptor* file, void* buffer, signed long count); - signed long (*stat)(file_descriptor* file, stat* out); + std::int32_t (*stat)(file_descriptor* file, stat* out); void (*close)(file_descriptor* file); - }; + } vnode; }; namespace vfs { void init(); - void open(file_descriptor* fd, char* path, bool follow_symlinks ); - void create(char* path, std::uint32_t mode); // mode contains type too + std::int32_t open(file_descriptor* fd, char* path, bool follow_symlinks); + std::int32_t create(char* path, std::uint32_t mode); // mode contains type too + std::int32_t readlink(char* path, char* out, std::uint32_t out_len); } -// fs should setup this during open +// took from old kernel +namespace vfs { + static inline std::uint64_t resolve_count(char* str,std::uint64_t sptr,char delim) { + char* current = str; + std::uint16_t att = 0; + std::uint64_t ptr = sptr; + while(current[ptr] != delim) { + if(att > 1024) + return 0; + att++; + + if(ptr != 0) { + ptr--; + } + } + return ptr; + } + + + static inline int normalize_path(const char* src, char* dest, std::uint64_t dest_size) { + if (!src ||!dest || dest_size < 2) return -1; + std::uint64_t j = 0; + int prev_slash = 0; + for (std::uint64_t i = 0; src[i] && j < dest_size - 1; i++) { + if (src[i] == '/') { + if (!prev_slash) { + dest[j++] = '/'; + prev_slash = 1; + } + } else { + dest[j++] = src[i]; + prev_slash = 0; + } + } + + if (j > 1 && dest[j-1] == '/') j--; + if (j >= dest_size) { + dest[0] = '\0'; + return -1; + } + dest[j] = '\0'; + return 0; + } + + /* I'll use path resolver from my old kernel */ + static inline void resolve_path(const char* inter0,const char* base, char *result, char spec) { + char* next = 0; + char buffer2_in_stack[2048]; + char inter[2048]; + char* buffer = 0; + char* final_buffer = (char*)buffer2_in_stack; + std::uint64_t ptr = klibc::strlen((char*)base); + char is_first = 1; + char is_full = 0; + + klibc::memcpy(inter,inter0,klibc::strlen(inter0) + 1); + + if(klibc::strlen((char*)inter) == 1 && inter[0] == '.') { + klibc::memcpy(result,base,klibc::strlen((char*)base) + 1); + if(result[0] == '\0') { + result[0] = '/'; + result[1] = '\0'; + } + return; + } + + if(!klibc::strcmp(inter,"/")) { + klibc::memcpy(result,inter,klibc::strlen((char*)inter) + 1); + if(result[0] == '\0') { + result[0] = '/'; + result[1] = '\0'; + } + return; + } + + if(inter[0] == '/') { + ptr = 0; + is_full = 1; + } else { + klibc::memcpy(final_buffer,base,klibc::strlen((char*)base) + 1); + } + + if(spec) + is_first = 0; + + if(!klibc::strcmp(base,"/")) + is_first = 0; + + buffer = klibc::strtok(&next,(char*)inter,"/"); + while(buffer) { + + if(is_first && !is_full) { + std::uint64_t mm = resolve_count(final_buffer,ptr,'/'); + + if(ptr < mm) { + final_buffer[0] = '/'; + final_buffer[1] = '\0'; + ptr = 1; + continue; + } + + ptr = mm; + final_buffer[ptr] = '\0'; + is_first = 0; + } + + if(!klibc::strcmp(buffer,"..")) { + std::uint64_t mm = resolve_count(final_buffer,ptr,'/'); + + if(!klibc::strcmp(final_buffer,"/\0")) { + buffer = klibc::strtok(&next,0,"/"); + continue; + } + + + if(ptr < mm) { + final_buffer[0] = '/'; + final_buffer[1] = '\0'; + ptr = 1; + continue; + } + + ptr = mm; + final_buffer[ptr] = '\0'; + + + + } else if(klibc::strcmp(buffer,"./") && klibc::strcmp(buffer,".")) { + + final_buffer[ptr] = '/'; + ptr++; + + std::uint64_t mm = 0; + mm = klibc::strlen(buffer); + klibc::memcpy((char*)((std::uint64_t)final_buffer + ptr),buffer,mm); + ptr += mm; + final_buffer[ptr] = '\0'; + } + + buffer = klibc::strtok(&next,0,"/"); + } + normalize_path(final_buffer,result,2048); + + if(result[0] == '\0') { + result[0] = '/'; + result[1] = '\0'; + } + } +}
\ No newline at end of file diff --git a/kernel/src/klibc/string.cpp b/kernel/src/klibc/string.cpp index e4ead45..4663a1d 100644 --- a/kernel/src/klibc/string.cpp +++ b/kernel/src/klibc/string.cpp @@ -76,4 +76,110 @@ int klibc::strlen(const char *str) { len++; } return len; +} + +char* klibc::strchr(const char *s, int c) { + while (*s) { + if (*s == (char)c) return (char *)s; + s++; + } + return nullptr; +} + +char* klibc::strtok(char **next,char *str, const char *delim) { + if (str) *next = str; + if (!*next) return nullptr; + + char *start = *next; + while (*start && strchr(delim, *start)) { + start++; + } + if (!*start) { + *next = nullptr; + return nullptr; + } + + char *end = start; + while (*end && !strchr(delim, *end)) { + end++; + } + + if (*end) { + *end = '\0'; + *next = end + 1; + } else { + *next = nullptr; + } + + return start; +} + +char* klibc::strrchr(const char* str, int ch) { + char* last_occurrence = 0; + + while (*str) { + if (*str == ch) { + last_occurrence = (char*)str; + } + str++; + } + + return last_occurrence; +} + +char* klibc::strcat(char* dest, const char* src) { + + char* ptr = dest; + while(*ptr != '\0') { + ptr++; + } + + while(*src != '\0') { + *ptr = *src; + ptr++; + src++; + } + + *ptr = '\0'; + + return dest; +} + +int klibc::strncmp(const char *s1, const char *s2, std::size_t n) { + std::size_t i = 0; + while (i < n && s1[i] && (s1[i] == s2[i])) { + i++; + } + if (i == n) return 0; + return (unsigned char)s1[i] - (unsigned char)s2[i]; +} + +// tbh i dont remember from what i took this +int klibc::strcmp(const char *s1, const char *s2) { + const unsigned long *w1 = (const unsigned long *)s1; + const unsigned long *w2 = (const unsigned long *)s2; + const unsigned long himagic = 0x8080808080808080UL; + const unsigned long lomagic = 0x0101010101010101UL; + + while (1) { + unsigned long word1 = *w1++; + unsigned long word2 = *w2++; + + unsigned long diff = word1 ^ word2; + unsigned long zeros = (word1 - lomagic) & ~word1 & himagic; + + if (diff != 0 || zeros != 0) { + const char *c1 = (const char *)(w1 - 1); + const char *c2 = (const char *)(w2 - 1); + + do { + unsigned char ch1 = *c1++; + unsigned char ch2 = *c2++; + if (ch1 != ch2) return ch1 - ch2; + if (ch1 == 0) break; + } while (1); + + return 0; + } + } }
\ No newline at end of file diff --git a/kernel/src/klibc/string.hpp b/kernel/src/klibc/string.hpp index c900862..5652d21 100644 --- a/kernel/src/klibc/string.hpp +++ b/kernel/src/klibc/string.hpp @@ -7,4 +7,10 @@ namespace klibc { void* memset(void *s, int c, std::size_t n); void* memmove(void *dest, const void *src, std::size_t n); int memcmp(const void *s1, const void *s2, std::size_t n); + char* strtok(char **next,char *str, const char *delim); + char* strchr(const char *s, int c); + char* strrchr(const char* str, int ch); + char* strcat(char* dest, const char* src); + int strncmp(const char *s1, const char *s2, std::size_t n); + int strcmp(const char *s1, const char *s2); };
\ No newline at end of file diff --git a/kernel/src/utils/math.hpp b/kernel/src/utils/math.hpp new file mode 100644 index 0000000..4d8f581 --- /dev/null +++ b/kernel/src/utils/math.hpp @@ -0,0 +1,3 @@ +#pragma once +#define is_power_of_two(n) ((n) > 0 && ((n) & ((n) - 1)) == 0) +#define div_remain(value, full) (value % full)
\ No newline at end of file diff --git a/limine.conf b/limine.conf index 2d4e09d..4fc44ff 100644 --- a/limine.conf +++ b/limine.conf @@ -1,5 +1,5 @@ # Timeout in seconds that Limine will use before automatically booting. -timeout: 3 +timeout: 2 # The entry name that will be displayed in the boot menu. /Orange |
