From 9a54c41ad07ec00316bb8fcdeba51c215446d454 Mon Sep 17 00:00:00 2001 From: Aleksa Vuckovic Date: Mon, 22 Aug 2022 15:12:25 +0200 Subject: ext2 as multiboot2 module --- Makefile | 33 ++++-- kernel/Makefile | 2 + kernel/include/disc.h | 21 ++++ kernel/include/ext2.h | 144 ++++++++++++++++++++++++++ kernel/include/heap.h | 4 +- kernel/include/multiboot2.h | 13 ++- kernel/src/boot/multiboot2.c | 18 +++- kernel/src/devices/disc.c | 32 ++++++ kernel/src/fs/ext2.c | 237 +++++++++++++++++++++++++++++++++++++++++++ kernel/src/grub.cfg | 2 +- kernel/src/libk/list.c | 1 + kernel/src/main.c | 14 +++ 12 files changed, 510 insertions(+), 11 deletions(-) create mode 100644 kernel/include/disc.h create mode 100644 kernel/include/ext2.h create mode 100644 kernel/src/devices/disc.c create mode 100644 kernel/src/fs/ext2.c diff --git a/Makefile b/Makefile index af294e8..4f5c382 100644 --- a/Makefile +++ b/Makefile @@ -12,7 +12,7 @@ W += -Wwrite-strings -Wmissing-prototypes -Wmissing-declarations W += -Wredundant-decls -Wnested-externs -Winline -Wno-long-long -Wconversion W += -Wstrict-prototypes WNO := -Wno-error=unused-parameter -Wno-error=unused-variable -WNO += -Wno-error=infinite-recursion +WNO += -Wno-error=unused-but-set-variable -Wno-error=infinite-recursion CFLAGS = $(W) $(WNO) -fno-omit-frame-pointer -mcmodel=large CFLAGS += -mgeneral-regs-only # disables SIMD instructions @@ -27,19 +27,26 @@ K = kernel all: kernel.iso +FORCE: + $K/kernel.bin: FORCE @$(MAKE) -C $(@D) -FORCE: -kernel.iso: $K/kernel.bin $K/src/grub.cfg Makefile +isodir: $(info [all] $@) @mkdir -p isodir/boot/grub - @cp $K/kernel.bin isodir/boot/kernel.bin @cp $K/src/grub.cfg isodir/boot/grub/grub.cfg - @grub-mkrescue -o kernel.iso isodir 2> /dev/null + @mkdir -p isodir/modules + @dd if=/dev/zero of=isodir/modules/ext2.img bs=4M count=2 > /dev/null 2>&1 + @mkfs.ext2 isodir/modules/ext2.img > /dev/null 2>&1 +kernel.iso: $K/kernel.bin $K/src/grub.cfg Makefile isodir FORCE + $(info [all] $@) + @cp $K/kernel.bin isodir/boot/kernel.bin + @grub-mkrescue -o kernel.iso isodir > /dev/null 2>&1 -.PHONY: all build qemu bochs clean + +.PHONY: all build qemu bochs mount umount clean QEMU = qemu-system-x86_64 BOCHS = bochs -q @@ -50,8 +57,22 @@ qemu: kernel.iso bochs: kernel.iso $(BOCHS) -qf .bochsrc +mount: isodir +ifeq ("$(wildcard /mnt/ext2/lost+found/)","") + $(info [all] $@) + @doas mount isodir/modules/ext2.img /mnt/ext2 -o loop + @doas chown -R aleksa:aleksa /mnt/ext2 +endif + +umount: +ifneq ("$(wildcard /mnt/ext2/lost+found/)","") + $(info [all] $@) + @doas umount /mnt/ext2 +endif + clean: @find -name "*.o" -exec rm {} \; @find -name "*.d" -exec rm {} \; @rm -f kernel.iso $K/kernel.bin xbochs.log bx_enh_dbg.ini @rm -rf isodir + @$(MAKE) umount diff --git a/kernel/Makefile b/kernel/Makefile index 03138fa..af14226 100644 --- a/kernel/Makefile +++ b/kernel/Makefile @@ -10,7 +10,9 @@ OBJS = \ src/cpu/irq.o \ src/cpu/irq_stub.o \ src/cpu/pic.o \ + src/devices/disc.o \ src/devices/keyboard.o \ + src/fs/ext2.o \ src/libk/list.o \ src/libk/math.o \ src/libk/stdio.o \ diff --git a/kernel/include/disc.h b/kernel/include/disc.h new file mode 100644 index 0000000..7b4fd0b --- /dev/null +++ b/kernel/include/disc.h @@ -0,0 +1,21 @@ +#ifndef DISC_H +#define DISC_H + +#include + +#include + +#define SECTOR_SIZE 512 + +struct disc_sector_t { + uint8_t data[SECTOR_SIZE]; +}; +typedef struct disc_sector_t disc_sector_t; + +extern disc_sector_t* disc; + +void disc_init(void); +void read_sector(size_t sector_num, disc_sector_t* disc_sector); +void write_sector(size_t sector_num, disc_sector_t* disc_sector); + +#endif diff --git a/kernel/include/ext2.h b/kernel/include/ext2.h new file mode 100644 index 0000000..1760fef --- /dev/null +++ b/kernel/include/ext2.h @@ -0,0 +1,144 @@ +#ifndef EXT2_H +#define EXT2_H + +#include + +#include + +struct ext2_superblock_t { +// base fields + uint32_t inodes_count; + uint32_t blocks_count; + uint32_t superuser_blocks; + uint32_t free_blocks; + uint32_t free_inodes; + uint32_t superblock_block; + uint32_t block_size; + uint32_t fragment_size; + uint32_t blocks_per_group; + uint32_t fragments_per_group; + uint32_t inodes_per_group; + uint32_t last_mount_time; + uint32_t last_write_time; + uint16_t mounts_since_fcsk; + uint16_t mounts_before_fcsk; + uint16_t signature; + uint16_t state; + uint16_t on_error; + uint16_t version_minor; + uint32_t last_time_fcsk; + uint32_t interval_fcsk; + uint32_t os_id; + uint32_t version_major; + uint16_t superuser_id; + uint16_t supergroup_id; +// extended fields + uint32_t first_inode; + uint16_t inode_size; + uint16_t superblock_group; + uint32_t optional_features; + uint32_t required_features; + uint32_t ro_features; + uint8_t id[16]; + uint8_t volume_name[16]; + uint8_t path_name[64]; + uint32_t compression; + uint8_t blocks_for_files; + uint8_t blocks_for_dirs; + uint16_t unused; + uint8_t journal_id[16]; + uint32_t journal_inode; + uint32_t journal_device; + uint32_t orphan_inode_head; + // unused +}; +typedef struct ext2_superblock_t ext2_superblock_t; + +struct ext2_bg_desc_t { + uint32_t block_bitmap; + uint32_t inode_bitmap; + uint32_t inode_block_address; + uint16_t free_blocks; + uint16_t free_inodes; + uint16_t dir_count; +}; +typedef struct ext2_bg_desc_t ext2_bg_desc_t; + +struct ext2_inode_t { + uint16_t type_perms; + uint16_t user_id; + uint32_t size_lower; + uint32_t last_accessed; + uint32_t creation_time; + uint32_t last_modified; + uint32_t deletion_time; + uint16_t group_id; + uint16_t hard_links_count; + uint32_t sectors_used; + uint32_t flags; + uint8_t os_specific1[4]; + uint32_t dbp[12]; + uint32_t sibp; + uint32_t dibp; + uint32_t tibp; + uint32_t gen_number; + uint32_t eab; + uint32_t size_upper; + uint32_t fragment_address; + uint8_t os_specific2[12]; +}; +typedef struct ext2_inode_t ext2_inode_t; + +// inode type +#define TYPE_FIFO 0x1000 +#define TYPE_CHAR_DEV 0x2000 +#define TYPE_DIR 0x4000 +#define TYPE_BLOCK DEV 0x6000 +#define TYPE_FILE 0x8000 +#define TYPE_SYMLINK 0xA000 +#define TYPE_SOCKET 0xC000 + +// inode permission +#define PERM_OE 0x001 +#define PERM_OR 0x002 +#define PERM_OW 0x004 +#define PERM_GE 0x008 +#define PERM_GR 0x010 +#define PERM_GW 0x020 +#define PERM_UE 0x040 +#define PERM_UR 0x080 +#define PERM_UW 0x100 +#define PERM_STICKY 0x200 +#define PERM_GID 0x400 +#define PERM_UID 0x800 + +struct ext2_dentry_t { + uint32_t inode; + uint16_t size; + uint8_t name_length_lower; + uint8_t type; + char* name; +}; +typedef struct ext2_dentry_t ext2_dentry_t; + +extern ext2_superblock_t* ext2_superblock; + +// size of structs +#define BG_DESC_SIZE 32 +#define BLOCK_SIZE (uint32_t)(1024 << ext2_superblock->block_size) +#define INODE_SIZE (ext2_superblock->inode_size) +#define INODES_PER_BLOCK (BLOCK_SIZE / INODE_SIZE) + + +void read_block(uint32_t block_num, void* block_ptr); +void read_superblock(ext2_superblock_t* ext2_superblock); +void read_bg_desc(uint32_t bg_desc, ext2_bg_desc_t* ext2_bg_desc); +void read_inode(uint32_t starting_block_num, uint32_t inode_index, ext2_inode_t* ext2_inode); +list_t* directory_to_entries(uint32_t inode); +char* files_to_buffer(uint32_t inode); +list_t* path_to_list(const char* path); +uint32_t path_to_inode(const char* path); +void ls(uint32_t inode); +void print(uint32_t inode); + +#endif diff --git a/kernel/include/heap.h b/kernel/include/heap.h index 88a9ad0..62d3b6f 100644 --- a/kernel/include/heap.h +++ b/kernel/include/heap.h @@ -3,8 +3,8 @@ #include -#define HEAP_VMEM_ADDR 0xc0400000 -#define HEAP_PMEM_ADDR 0x00400000 +#define HEAP_VMEM_ADDR 0xc1000000 +#define HEAP_PMEM_ADDR 0x01000000 #define HEAP_SIZE 0x01000000 #define HEAP_BLOCK_SIZE 0x00000010 diff --git a/kernel/include/multiboot2.h b/kernel/include/multiboot2.h index 6d4a86f..994dbc5 100644 --- a/kernel/include/multiboot2.h +++ b/kernel/include/multiboot2.h @@ -37,6 +37,15 @@ struct mb2_tag_mmap_entry { }; typedef struct mb2_tag_mmap_entry mb2_tag_mmap_entry; +struct mb2_tag_module { + uint32_t type; + uint32_t size; + uint32_t mod_start; + uint32_t mod_end; + char* name; +}; +typedef struct mb2_tag_module mb2_tag_module; + // multiboot2 magic check #define MB2_MAGIC 0x36D76289 @@ -45,16 +54,18 @@ typedef struct mb2_tag_mmap_entry mb2_tag_mmap_entry; #define MB2_TAG_END 0 #define MB2_TAG_CMDLINE 1 #define MB2_TAG_BOOTLOADER 2 -#define MB2_TAG_MODULES 3 +#define MB2_TAG_MODULE 3 #define MB2_TAG_MEM 4 #define MB2_TAG_BIOS 5 #define MB2_TAG_MMAP 6 #define MB2_TAG_VBE 7 #define MB2_TAG_FB 8 +extern mb2_tag_module* ext2_module; void read_mb2(mb2_tag_header* multiboot_bootinfo, uint32_t multiboot_magic); void init_fb(mb2_tag_fb* tag_fb); void init_mmap(mb2_tag_mmap* tag_mmap); +void init_module(mb2_tag_module* tag_module); #endif diff --git a/kernel/src/boot/multiboot2.c b/kernel/src/boot/multiboot2.c index d0b0667..1bb9aac 100644 --- a/kernel/src/boot/multiboot2.c +++ b/kernel/src/boot/multiboot2.c @@ -13,6 +13,8 @@ /* https://www.gnu.org/software/grub/manual/multiboot2/html_node/Boot-information-format.html */ +mb2_tag_module* ext2_module; + void init_fb(mb2_tag_fb* tag_fb) { main_fb.addr = tag_fb->framebuffer_addr; @@ -42,7 +44,8 @@ void init_mmap(mb2_tag_mmap* tag_mmap) for (list_t* tmp = mmap; tmp != NULL; tmp = tmp->next) { mb2_tag_mmap_entry* mmap_entry; mmap_entry = tmp->data; - printf("base_addr: 0x%x, length: 0x%x, type: %d\n", mmap_entry->base_addr, mmap_entry->length, mmap_entry->type); +// printf("base_addr: 0x%x, length: 0x%x, type: %d\n", mmap_entry->base_addr, mmap_entry->length, mmap_entry->type); + mmap_entry = mmap_entry; } // free data @@ -54,6 +57,15 @@ void init_mmap(mb2_tag_mmap* tag_mmap) free_list(&mmap); } +void init_module(mb2_tag_module* tag_module) +{ + // name is utf-8 encoded string! + uint32_t name_size = tag_module->size - sizeof(tag_module) + sizeof(char*); + tag_module->name = (char*)kalloc(name_size); + memcpy(tag_module->name, tag_module + tag_module->size - name_size, name_size); + kfree(tag_module->name); +} + void read_mb2(mb2_tag_header* multiboot_bootinfo, uint32_t multiboot_magic) { if (multiboot_magic != MB2_MAGIC) { @@ -77,6 +89,9 @@ void read_mb2(mb2_tag_header* multiboot_bootinfo, uint32_t multiboot_magic) case MB2_TAG_MMAP: tag_mmap = (mb2_tag_mmap*)tag_header; break; + case MB2_TAG_MODULE: + ext2_module = (mb2_tag_module*)tag_header; + break; default: break; } @@ -87,4 +102,5 @@ void read_mb2(mb2_tag_header* multiboot_bootinfo, uint32_t multiboot_magic) init_fb(tag_fb); init_mmap(tag_mmap); + init_module(ext2_module); } diff --git a/kernel/src/devices/disc.c b/kernel/src/devices/disc.c new file mode 100644 index 0000000..8d34473 --- /dev/null +++ b/kernel/src/devices/disc.c @@ -0,0 +1,32 @@ +#include +#include +#include +#include +#include + +#define KERNEL_VMA 0xc0000000 + +disc_sector_t* disc; + +void disc_init() +{ + disc = (disc_sector_t*)(uint64_t)ext2_module->mod_start; + if (disc == NULL) { + printf("Error opening disc\n"); + } + + uint32_t disc_size = ext2_module->mod_end - ext2_module->mod_start; + for (size_t i = 0; i < upper_div(disc_size, PAGE_SIZE) + 1; i++) { + map_addr((uint64_t)((char*)disc + i * PAGE_SIZE), (uint64_t)((char*)disc + i * PAGE_SIZE), FLAG_PRESENT | FLAG_WRITABLE | FLAG_HUGE); + } +} + +void read_sector(size_t sector_num, disc_sector_t* disc_sector) +{ + memcpy(disc_sector, disc + sector_num, SECTOR_SIZE); +} + +void write_sector(size_t sector_num, disc_sector_t* disc_sector) +{ + memcpy(disc + sector_num, disc_sector, SECTOR_SIZE); +} diff --git a/kernel/src/fs/ext2.c b/kernel/src/fs/ext2.c new file mode 100644 index 0000000..11f26fc --- /dev/null +++ b/kernel/src/fs/ext2.c @@ -0,0 +1,237 @@ +#include +#include +#include +#include +#include +#include + +ext2_superblock_t* ext2_superblock; + +void read_block(uint32_t block_num, void* block_ptr) +{ + uint32_t sectors_per_block = BLOCK_SIZE / SECTOR_SIZE; + + for (size_t i = 0; i < sectors_per_block; i++) { + read_sector(block_num * sectors_per_block + i, (disc_sector_t*)block_ptr + i); + } +} + +void read_superblock(ext2_superblock_t* superblock) +{ + char block[1024]; + read_sector(2, (disc_sector_t*)block); + read_sector(3, (disc_sector_t*)block + 1); + memcpy(superblock, block, sizeof(ext2_superblock_t)); +} + +void read_bg_desc(uint32_t bg_desc, ext2_bg_desc_t* ext2_bg_desc) +{ + uint32_t starting_block_num = BLOCK_SIZE == 1024 ? 2 : 1; + uint32_t bg_descs_per_block = BLOCK_SIZE / BG_DESC_SIZE; + uint32_t block_num = starting_block_num + bg_desc / bg_descs_per_block; + uint32_t block_index = bg_desc % bg_descs_per_block; + + char block[BLOCK_SIZE]; + read_block(block_num, block); + memcpy(ext2_bg_desc, (char*)block + BG_DESC_SIZE * block_index, sizeof(ext2_bg_desc_t)); +} + +void read_inode(uint32_t starting_block_num, uint32_t inode_index, ext2_inode_t* ext2_inode) +{ + uint32_t block_num = starting_block_num + inode_index / INODES_PER_BLOCK; + uint32_t block_index = inode_index % INODES_PER_BLOCK; + + char block[BLOCK_SIZE]; + read_block(block_num, block); + memcpy(ext2_inode, (char*)block + block_index * INODE_SIZE, sizeof(ext2_inode_t)); +} + +list_t* directory_to_entries(uint32_t inode) +{ + list_t* list = NULL; + + uint32_t bg_desc = (inode - 1) / ext2_superblock->inodes_per_group; + uint32_t inode_index = (inode - 1) % ext2_superblock->inodes_per_group; + + // block group descriptor + ext2_bg_desc_t* ext2_bg_desc; + ext2_bg_desc = (ext2_bg_desc_t*)kalloc(sizeof(ext2_bg_desc_t)); + read_bg_desc(bg_desc, ext2_bg_desc); + + // inode table + ext2_inode_t* ext2_inode; + ext2_inode = (ext2_inode_t*)kalloc(sizeof(ext2_inode_t)); + read_inode(ext2_bg_desc->inode_block_address, inode_index, ext2_inode); + + // if it is not directory + if (!(ext2_inode->type_perms & TYPE_DIR)) + return list; + + // read inode contents + for (size_t i = 0; i < 12; i++) { + if (ext2_inode->dbp[i] == 0) + break; + + // get block + char block[BLOCK_SIZE]; + read_block(ext2_inode->dbp[i], block); + + // parse block + for (size_t block_offset = 0; block_offset < BLOCK_SIZE;) { + // get dentry header + ext2_dentry_t* ext2_dentry; + ext2_dentry = (ext2_dentry_t*)kalloc(sizeof(ext2_dentry_t)); + memcpy(ext2_dentry, (char*)block + block_offset, sizeof(ext2_dentry_t) - sizeof(char*)); + + // get dentry name + ext2_dentry->name = (char*)kalloc(ext2_dentry->name_length_lower); + memcpy(ext2_dentry->name, (char*)block + block_offset + sizeof(ext2_dentry_t) - sizeof(char*), ext2_dentry->name_length_lower); + + if (inode == 0) { + kfree(ext2_dentry->name); + kfree(ext2_dentry); + break; + } + + // put dentry in list + add_to_list_head(&list, ext2_dentry); + + // offset + block_offset += ext2_dentry->size; + } + } + + + kfree(ext2_bg_desc); + kfree(ext2_inode); + + return list; +} + +char* files_to_buffer(uint32_t inode) +{ + uint32_t bg_desc = (inode - 1) / ext2_superblock->inodes_per_group; + uint32_t inode_index = (inode - 1) % ext2_superblock->inodes_per_group; + + // block group descriptor + ext2_bg_desc_t* ext2_bg_desc; + ext2_bg_desc = (ext2_bg_desc_t*)kalloc(sizeof(ext2_bg_desc_t)); + read_bg_desc(bg_desc, ext2_bg_desc); + + // inode table + ext2_inode_t* ext2_inode; + ext2_inode = (ext2_inode_t*)kalloc(sizeof(ext2_inode_t)); + read_inode(ext2_bg_desc->inode_block_address, inode_index, ext2_inode); + + char* data; + + uint32_t size = ext2_inode->size_lower; + data = (char*)kalloc(size); + + uint32_t block_num = upper_div(size, BLOCK_SIZE); + for (size_t i = 0; i < min(block_num, 12); i++) { + char block[BLOCK_SIZE]; + read_block(ext2_inode->dbp[i], block); + memcpy(data + i * BLOCK_SIZE, block, size >= (i + 1) * BLOCK_SIZE ? BLOCK_SIZE : size % BLOCK_SIZE); + } + + return data; +} + +list_t* path_to_list(const char* path) +{ + size_t i, j; + list_t* divided_path = NULL; + + size_t n = strlen(path); + for (i = 0, j = 0; i <= n; i++) { + if (i == n || path[i] == '/') { + // add data before slash + if (i != j) { + char* ptr = (char*)kalloc(sizeof(char) * (uint32_t)(i - j + 1)); + memcpy(ptr, path + j, i - j); + ptr[i - j] = '\0'; + add_to_list_tail(÷d_path, ptr); + } + // add slash + if (i != n) { + char* ptr = (char*)kalloc(sizeof(char) * 2); + ptr[0] = '/'; + ptr[1] = '\0'; + add_to_list_tail(÷d_path, ptr); + j = i + 1; + } + } + } + + return divided_path; +} + +// only supports absolute path for now +uint32_t path_to_inode(const char* path) +{ + uint32_t inode = 0; + list_t* divided_path = path_to_list(path); + + list_t* curr_dir = divided_path; + + // first entry is / + curr_dir = curr_dir->next; + inode = 2; + + while (curr_dir != NULL) { + // list of dentry + list_t* list = directory_to_entries(inode); + + // check if inode is actually a dir + if (list == NULL) { + printf("not a directory\n"); + return 0; + } + + // iterate through all direntries + uint8_t ind = 1; + for (list_t* curr_list = list; curr_list != NULL; curr_list = curr_list->next) { + ext2_dentry_t* ext2_dentry; + ext2_dentry = curr_list->data; + + if (!memcmp(curr_dir->data, ext2_dentry->name)) { + ind = 0; + inode = ext2_dentry->inode; + break; + } + } + + // if dir not found error + if (ind) { + printf("file/dir not found\n"); + return 0; + } + + // next dir + curr_dir = curr_dir->next; + if (curr_dir != NULL) + curr_dir = curr_dir->next; + } + + return inode; +} + +void ls(uint32_t inode) +{ + list_t* dir = directory_to_entries(inode); + + printf("ls dir with inode %d:\n", inode); + for (list_t* tmp = dir; tmp != NULL; tmp = tmp->next) { + ext2_dentry_t* ext2_dentry; + ext2_dentry = tmp->data; + printf("inode: %d, name: %s\n", ext2_dentry->inode, ext2_dentry->name); + } +} + +void print(uint32_t inode) +{ + printf("contents of inode %d:\n", inode); + char *p = files_to_buffer(inode); + printf("%s", p); +} diff --git a/kernel/src/grub.cfg b/kernel/src/grub.cfg index 05a13f7..89d3ddf 100644 --- a/kernel/src/grub.cfg +++ b/kernel/src/grub.cfg @@ -4,5 +4,5 @@ set default=0 insmod efi_gop menuentry "mykernel64" { multiboot2 /boot/kernel.bin - boot + module2 /modules/ext2.img ext2 } diff --git a/kernel/src/libk/list.c b/kernel/src/libk/list.c index 5f75845..be2e4e5 100644 --- a/kernel/src/libk/list.c +++ b/kernel/src/libk/list.c @@ -14,6 +14,7 @@ void add_to_list_tail(list_t** ptr, void* data) { list_t* node = (list_t*)kalloc(sizeof(list_t)); node->data = data; + node->next = NULL; if (*ptr == NULL) { *ptr = node; diff --git a/kernel/src/main.c b/kernel/src/main.c index a3303e4..ce307e2 100644 --- a/kernel/src/main.c +++ b/kernel/src/main.c @@ -9,6 +9,8 @@ #include #include #include +#include +#include int kernel_main(mb2_tag_header* multiboot_bootinfo, uint32_t multiboot_magic); int kernel_main(mb2_tag_header* multiboot_bootinfo, uint32_t multiboot_magic) @@ -18,6 +20,18 @@ int kernel_main(mb2_tag_header* multiboot_bootinfo, uint32_t multiboot_magic) init_heap(); read_mb2(multiboot_bootinfo, multiboot_magic); + // init disc + disc_init(); + + // read superblock + ext2_superblock = (ext2_superblock_t*)kalloc(sizeof(ext2_superblock_t)); + read_superblock(ext2_superblock); + + ls(path_to_inode("/")); + + // free superblock + kfree(ext2_superblock); + for(;;) { __asm__ volatile ("hlt;"); } -- cgit v1.2.3