From 03f0ec6f88cc14cd6df4ed58f03b6e7d33f554c6 Mon Sep 17 00:00:00 2001 From: Rick Rongen Date: Wed, 6 Oct 2021 21:45:15 +0200 Subject: [PATCH] feat: Vfs and Ext2 support. Code style/attribute improvements Added VFS and Ext2 support. Optimized attributes of methods to improve code highlighting. Printf attribute, malloc attribute, etc. --- include/myke/mem/malloc.h | 2 +- include/myke/vfs/blockdev.h | 15 +- include/myke/vfs/lfs/ext2.h | 223 +++++++++++++++++ include/myke/vfs/vfs-driver.h | 36 +++ include/myke/vfs/vfs.h | 70 ++++++ include/stdio.h | 8 +- include/string.h | 14 +- include/sys/stat.h | 50 ++++ include/time.h | 6 + kernel/command.c | 72 +++++- kernel/libc/kprintf.c | 12 +- kernel/libc/string.c | 24 +- kernel/mem/malloc.c | 2 +- kernel/vfs/blockdev.c | 86 +++---- kernel/vfs/lfs/ext2.c | 438 ++++++++++++++++++++++++++++++++++ kernel/vfs/lfs/fat.c | 19 +- kernel/vfs/lfs/ustar.c | 11 +- kernel/vfs/part/mbr.c | 13 +- kernel/vfs/vfs.c | 186 +++++++++++++++ linker.ld | 16 +- rootfs/.gitignore | 3 + rootfs/mkrootfs.sh | 52 ++++ rootfs/mount_rootfs.sh | 39 +++ rootfs/umount_rootfsh.sh | 15 ++ 24 files changed, 1322 insertions(+), 90 deletions(-) create mode 100644 include/myke/vfs/lfs/ext2.h create mode 100644 include/myke/vfs/vfs-driver.h create mode 100644 include/myke/vfs/vfs.h create mode 100644 include/sys/stat.h create mode 100644 kernel/vfs/lfs/ext2.c create mode 100644 kernel/vfs/vfs.c create mode 100644 rootfs/.gitignore create mode 100755 rootfs/mkrootfs.sh create mode 100755 rootfs/mount_rootfs.sh create mode 100755 rootfs/umount_rootfsh.sh diff --git a/include/myke/mem/malloc.h b/include/myke/mem/malloc.h index 743ed5f..617146d 100644 --- a/include/myke/mem/malloc.h +++ b/include/myke/mem/malloc.h @@ -7,7 +7,7 @@ // retrieved from https://github.com/blanham/liballoc #include -void *malloc(size_t); +void __attribute__((assume_aligned (16), alloc_size (1), malloc)) *malloc(size_t); void *realloc(void *, size_t); diff --git a/include/myke/vfs/blockdev.h b/include/myke/vfs/blockdev.h index b6d44bc..2917f82 100644 --- a/include/myke/vfs/blockdev.h +++ b/include/myke/vfs/blockdev.h @@ -9,6 +9,8 @@ #include #include +#define BLOCK_DEV_LBA_SIZE 512 + #define BLOCK_DEV_ACCESS_OK 0 #define BLOCK_DEV_ACCESS_ERR 1 @@ -27,21 +29,21 @@ typedef struct block_device block_device_t; -typedef uint8_t (*block_device_driver_check_device)(const block_device_t *device, uint8_t *first_sector); +typedef uint8_t (*block_device_driver_check_device)(block_device_t *device); -typedef uint8_t (*block_device_driver_free)(const block_device_t *device); +typedef uint8_t (*block_device_driver_free)(block_device_t *device); typedef uint8_t (*block_device_access)(const block_device_t *device, uint8_t direction, uint32_t lba, uint8_t sectors, void *target); -struct block_dev_driver { +typedef struct block_dev_driver { char name[16]; struct { uint8_t partitioning: 1; } flags; block_device_driver_check_device check_device; block_device_driver_free free_device; -} __attribute__((__aligned__(STRUCT_ALIGNMENT))); +} __attribute__((__aligned__(STRUCT_ALIGNMENT))) block_dev_driver_t; #define BLOCK_DEV_DRIVER(order) GENERIC_DRIVER(block_dev_driver, order) @@ -59,6 +61,7 @@ struct block_device { block_device_access access; struct block_dev_driver *driver; void *device_info; // pointer to driver defined structure + void *driver_info; // pointer to driver defined structure // todo device info }; @@ -66,8 +69,8 @@ uint8_t block_dev_register(block_device_t *device); void block_dev_free(block_device_t *device); +void *block_dev_mount(const char *device, const char *driver_name); + void block_dev_print_info(); -bool block_dev_mount(char *identifier, char *driver); - #endif //NEW_KERNEL_BLOCKDEV_H diff --git a/include/myke/vfs/lfs/ext2.h b/include/myke/vfs/lfs/ext2.h new file mode 100644 index 0000000..8f10574 --- /dev/null +++ b/include/myke/vfs/lfs/ext2.h @@ -0,0 +1,223 @@ +// +// Created by rick on 18-09-21. +// + +#ifndef NEW_KERNEL_EXT2_H +#define NEW_KERNEL_EXT2_H + +#include +#include + +#define EXT2_SIGNATURE 0xEF53 + +#define EXT2_SB_ADDR 1024 +#define EXT2_SB_SIZE 1024 +#define EXT2_BGD_START_ADDR (EXT2_SB_ADDR + EXT2_SB_SIZE) + +#define EXT2_DEFAULT_RESERVED_INODES 11 +#define EXT2_DEFAULT_INODE_SIZE 128 + +#define EXT2_ROOT_INODE 2 + +typedef struct ext2_sb { + uint32_t total_inodes; + uint32_t total_blocks; + uint32_t num_reserved_su; + uint32_t unallocated_blocks; + uint32_t unallocated_inodes; + uint32_t no_blocks_with_sb; + uint32_t block_size; + uint32_t fragment_size; + uint32_t no_blocks_per_group; + uint32_t no_fragments_per_group; + uint32_t no_inodes_per_group; + uint32_t last_mounted; + uint32_t last_written; + uint16_t no_mounted_since_fschk; + uint16_t max_no_mounted_since_fschk; + uint16_t ext2_signature; + uint16_t fs_state; + uint16_t error_action; + uint16_t minor_version; + uint32_t last_fschk; + uint32_t interval_fschk; + uint32_t os_id; + uint32_t major_version; + uint16_t uid_reserved; + uint16_t gid_reserved; + + // below extended fields + uint32_t first_nor_reserved_inode; + uint16_t size_inode; + uint16_t owner_bg; + uint32_t features_optional; + uint32_t features_required; + uint32_t features_ro; + uint8_t fs_id[16]; + char fs_name[16]; + char last_mounted_path[64]; + uint32_t compression_alg; + uint8_t preallocate_files; + uint8_t preallocate_dirs; + uint16_t: 16; // unused + uint8_t journal_id[16]; + uint32_t journal_inode; + uint32_t journal_device; + uint32_t head_of_orphan_inode_list; +} att_packed ext2_sb_t; + +enum { + EXT2_FS_STATE_CLEAN = 1, + EXT2_FS_STATE_ERROR = 2, +}; + +enum { + EXT2_ERROR_ACTION_IGNORE = 1, + EXT2_ERROR_ACTION_REMOUNT_RO = 2, + EXT2_ERROR_ACTION_PANIC = 3, +}; + +enum { + EXT2_OS_ID_LINUX = 0, + EXT2_OS_ID_GNU_HURD = 1, + EXT2_OS_ID_MASIX = 2, + EXT2_OS_ID_FREE_BSD = 3, + EXT2_OS_ID_LITES = 4, +}; + +enum { + EXT2_FEATURE_OPTIONAL_PREALLOCATE = 0x01, + EXT2_FEATURE_OPTIONAL_AFS_SERVER_INODE = 0x02, + EXT2_FEATURE_OPTIONAL_HAS_JOURNAL = 0x04, + EXT2_FEATURE_OPTIONAL_EXTENDED_ATTRIBUTES = 0x08, + EXT2_FEATURE_OPTIONAL_CAN_RESIZE = 0x10, + EXT2_FEATURE_OPTIONAL_DIR_HASH_INDEX = 0x20, +}; +#define EXT2_FEAT_OPT_SUPPORTED ( \ + 0 \ + ) + +enum { + EXT2_FEATURE_REQUIRED_COMPRESSION = 0x01, + EXT2_FEATURE_REQUIRED_DIR_HAS_TYPE = 0x02, + EXT2_FEATURE_REQUIRED_JOURNAL_REPLAY_REQUIRED = 0x04, + EXT2_FEATURE_REQUIRED_HAS_JOURNAL_DEVICE = 0x08, +}; + +#define EXT2_FEAT_REQ_SUPPORTED ( \ + EXT2_FEATURE_REQUIRED_DIR_HAS_TYPE | \ + 0 \ + ) + +enum { + EXT2_FEATURE_RO_SPARSE_SUPERBLOCKS_AND_GROUPS_DESCRIPTOR = 0x01, + EXT2_FEATURE_RO_64BIT_SIZE = 0x02, + EXT2_FEATURE_RO_DIR_BTREE = 0X04 +}; + +#define EXT2_FEAT_RO_64BIT_SIZE (SIZE_MAX > UINT32_MAX) +#define EXT2_FEAT_RO_SUPPORTED ( \ + (EXT2_FEAT_RO_64BIT_SIZE ? EXT2_FEATURE_RO_64BIT_SIZE : 0) | \ + 0 \ + ) + +typedef struct ext2_bg_descriptor { + uint32_t block_usage_bm; + uint32_t inode_usage_bm; + uint32_t start_block_inode; + uint16_t no_unallocated_blocks; + uint16_t no_unallocated_inodes; + uint16_t no_dirs; + uint8_t unused[14]; +} ext2_bg_descriptor_t; + +typedef struct ext2_inode { + union { + uint16_t type_permission; + struct { + uint8_t permission_o: 3; + uint8_t permission_g: 3; + uint8_t permission_u: 3; + bool permission_sticky: 1; + bool permission_setgid: 1; + bool permission_setuid: 1; + uint8_t type: 4; + } att_packed; + }; + uint16_t uid; + uint32_t size_l; + uint32_t last_access; + uint32_t created; + uint32_t last_mod; + uint32_t deleted; + uint16_t gid; + uint16_t no_hard_links; + uint32_t no_sectors; + uint32_t flags; + uint32_t os_val1; + uint32_t dbp[12]; // fist 12 direct block pointers + uint32_t sibp; + uint32_t dibp; + uint32_t tibp; + uint32_t generation; + uint32_t extended_attr; + union { + uint32_t size_h; + uint32_t dir_acl; + }; + uint32_t fragment_addr; + uint8_t os_val2[12]; +} att_packed ext2_inode_t; + +enum { + EXT2_INODE_FLAG_SECURE_DELETE = 0x00000001, + EXT2_INODE_FLAG_KEEP_COPY_ON_DELETE = 0x00000002, + EXT2_INODE_FLAG_FILE_COMPRESSION = 0x00000004, + EXT2_INODE_FLAG_SYNC_UPDATE = 0x00000008, + EXT2_INODE_FLAG_IMMUTABLE = 0x00000010, + EXT2_INODE_FLAG_APPEND_ONLY = 0x00000020, + EXT2_INODE_FLAG_NO_DUMP = 0x00000040, + EXT2_INODE_FLAG_LAST_ACCESS_IGNORE = 0x00000080, + EXT2_INODE_FLAG_HASH_INDEXED_DIR = 0x00010000, + EXT2_INODE_FLAG_AFS_DIRECTORY = 0x00020000, + EXT2_INODE_FLAG_JOURNAL_FILE_DATA = 0x00040000, +}; + +typedef struct ext2_dir_entry { + uint32_t inode; + uint16_t ent_size; + uint8_t name_size; + uint8_t type_or_name_size_h; + char name; +} ext2_dir_entry_t; + +enum { + EXT2_INODE_TYPE_FIFO = 0x1, + EXT2_INODE_TYPE_CHAR_DEV = 0x2, + EXT2_INODE_TYPE_DIR = 0x4, + EXT2_INODE_TYPE_BLOCK_DEV = 0x6, + EXT2_INODE_TYPE_FILE = 0x8, + EXT2_INODE_TYPE_SYM_LINK = 0xA, + EXT2_INODE_TYPE_UNIX_SOCK = 0xC, +}; + +enum { + EXT2_DIR_TYPE_UNKNOWN = 0, + EXT2_DIR_TYPE_FILE = 1, + EXT2_DIR_TYPE_DIR = 2, + EXT2_DIR_TYPE_CHAR_DEV = 3, + EXT2_DIR_TYPE_BLOCK_DEV = 4, + EXT2_DIR_TYPE_FIFO = 5, + EXT2_DIR_TYPE_SOCKET = 6, + EXT2_DIR_TYPE_SOFT_LINK = 7, +}; + +typedef struct ext2_mount_info { + ext2_sb_t sb; + uint32_t no_block_groups; + uint64_t block_size; + uint64_t fragment_size; + void *block_dev; +} ext2_mount_info_t; + +#endif //NEW_KERNEL_EXT2_H diff --git a/include/myke/vfs/vfs-driver.h b/include/myke/vfs/vfs-driver.h new file mode 100644 index 0000000..ffeb59a --- /dev/null +++ b/include/myke/vfs/vfs-driver.h @@ -0,0 +1,36 @@ +// +// Created by rick on 19-09-21. +// + +#ifndef NEW_KERNEL_VFS_DRIVER_H +#define NEW_KERNEL_VFS_DRIVER_H + +#include +#include + +typedef struct vfs_driver { + char name[16]; + struct { + } flags; + + // api + int (*vfs_mount)(vfs_mount_t *mount); + + int (*open)(vfs_mount_t *mount, vfs_fd_t *dir, const char *path, int mode, vfs_fd_t *out); + + int (*close)(vfs_mount_t *mount, vfs_fd_t *fd); + + int (*fstat)(vfs_mount_t *mount, vfs_fd_t *fd, stat_t *target, int flags); + + int (*fread)(vfs_mount_t *mount, vfs_fd_t *fd, void *target, size_t size); + + int (*dgetent)(vfs_mount_t *mount, vfs_fd_t *fd, void *target, size_t size); + +} __attribute__((__aligned__(STRUCT_ALIGNMENT))) vfs_driver_t; + +void vfs_mk_dirent_record(vfs_dirent_t *ent, uint32_t inode, uint32_t cur_offset, uint8_t type, char *name, + size_t name_length); + +#define VFS_DRIVER(order) GENERIC_DRIVER(vfs_driver, order) + +#endif //NEW_KERNEL_VFS_DRIVER_H diff --git a/include/myke/vfs/vfs.h b/include/myke/vfs/vfs.h new file mode 100644 index 0000000..a87f3c1 --- /dev/null +++ b/include/myke/vfs/vfs.h @@ -0,0 +1,70 @@ +// +// Created by rick on 19-09-21. +// + +#ifndef NEW_KERNEL_VFS_H +#define NEW_KERNEL_VFS_H + +#include +#include + +#define VFS_MOUNT_OK 0 +#define VFS_MOUNT_ERROR 1 + +#define VFS_OPEN_ERROR 1 +#define VFS_OPEN_OK 0 + +#define VFS_CLOSE_OK 1 + +#define VFS_READ_ERROR (-1) + +#define VFS_DGETENTS_ERR 1 + +struct vfs_mount; + +typedef struct vfs_mount { + struct { + } flags; + const char *prefix; + const char *device; + void *driver; // vfs_mount_driver_t + void *global_driver_data; + struct vfs_mount *next; +} vfs_mount_t; + +typedef struct vfs_fd { + struct { + } flags; + vfs_mount_t *mount; + void *driver_data; +} vfs_fd_t; + +#define VFS_DIRENT_BASE_SIZE (4 + 4 + 2 + 1) +#define VFS_DIRENT_SIZE(name_length) ((VFS_DIRENT_BASE_SIZE + (name_length) + 1 + 15) & (~0xF)) +#define VFS_DIRENT_MAX_SIZE (VFS_DIRENT_BASE_SIZE + 256 + 1) + +typedef struct vfs_dirent { + uint32_t inode; + uint32_t offset_next; + uint16_t reclen; + uint8_t type; + char name[]; +} vfs_dirent_t; + +int vfs_mount(const char *path, const char *device, const char *driver); + +// https://man7.org/linux/man-pages/man2/open.2.html +vfs_fd_t *vfs_open(const char *path, int flags, int mode); + +void vfs_close(vfs_fd_t *fd); + +// https://man7.org/linux/man-pages/man2/stat.2.html +int vfs_fstat(vfs_fd_t *fd, stat_t *target, int flags); + +// https://man7.org/linux/man-pages/man2/read.2.html +int vfs_read(vfs_fd_t *fd, void *target, size_t size); + +// inspiration https://man7.org/linux/man-pages/man2/getdents.2.html +int vfs_getdents(vfs_fd_t *fd, void *target, int count); + +#endif //NEW_KERNEL_VFS_H diff --git a/include/stdio.h b/include/stdio.h index 1a24f9f..8f2b59d 100644 --- a/include/stdio.h +++ b/include/stdio.h @@ -24,7 +24,7 @@ void fflush(FILE *); FILE *fopen(const char *, const char *); -void fprintf(FILE *, const char *, ...); +void __attribute__((format (printf, 2, 3))) fprintf(FILE *, const char *, ...); size_t fread(void *, size_t, size_t, FILE *); @@ -38,11 +38,11 @@ void setbuf(FILE *, char *); int vfprintf(FILE *, const char *, va_list); -int vprintf(const char* fmt, va_list args); +int vprintf(const char *fmt, va_list args); -int printf(const char *fmt, ...); +int __attribute__((format (printf, 1, 2))) printf(const char *fmt, ...); -int sprintf(char *target, const char *fmt, ...); +int __attribute__((format (printf, 2, 3))) sprintf(char *target, const char *fmt, ...); #endif //NEW_KERNEL_STDIO_H diff --git a/include/string.h b/include/string.h index 97e3e56..0335373 100644 --- a/include/string.h +++ b/include/string.h @@ -7,9 +7,9 @@ #include -void* memcpy(void *dst, const void *src, size_t amount); +void *memcpy(void *dst, const void *src, size_t amount); -void* memset(void *dst, int data, size_t amount); +void *memset(void *dst, int data, size_t amount); void *memmove(void *dst, const void *src, size_t amount); @@ -19,19 +19,19 @@ void *strncpy(char *dst, const char *src, size_t n); size_t strlen(const char *str); -const char *strchr(const char *s, char c); +char *strchr(const char *s, char c); -const char *strrchr(const char *s, char c); +char *strrchr(const char *s, char c); int memcmp(const void *s1, const void *s2, size_t n); int strcmp(const char *s1, const char *s2); -int strncmp(const char *s1, const char *s2, int n); +int strncmp(const char *s1, const char *s2, size_t n); -char* strdup(const char* s); +char *strdup(const char *s); -char* strndup(const char* s, size_t n); +char *strndup(const char *s, size_t n); char *strcat(char *dest, const char *src); diff --git a/include/sys/stat.h b/include/sys/stat.h new file mode 100644 index 0000000..fed3816 --- /dev/null +++ b/include/sys/stat.h @@ -0,0 +1,50 @@ +// +// Created by rick on 06-10-21. +// + +#ifndef NEW_KERNEL_STAT_H +#define NEW_KERNEL_STAT_H + +#include + +// https://man7.org/linux/man-pages/man2/stat.2.html + +typedef uint32_t dev_t; +typedef uint32_t ino_t; +typedef uint32_t mode_t; +typedef uint32_t nlink_t; +typedef uint32_t uid_t; +typedef uint32_t gid_t; +typedef size_t off_t; +typedef size_t blksize_t; +typedef uint32_t blkcnt_t; + + +struct stat { + dev_t st_dev; /* ID of device containing file */ + ino_t st_ino; /* Inode number */ + mode_t st_mode; /* File type and mode */ + nlink_t st_nlink; /* Number of hard links */ + uid_t st_uid; /* User ID of owner */ + gid_t st_gid; /* Group ID of owner */ + dev_t st_rdev; /* Device ID (if special file) */ + off_t st_size; /* Total size, in bytes */ + blksize_t st_blksize; /* Block size for filesystem I/O */ + blkcnt_t st_blocks; /* Number of 512B blocks allocated */ + + /* Since Linux 2.6, the kernel supports nanosecond + precision for the following timestamp fields. + For the details before Linux 2.6, see NOTES. */ + + struct timespec st_atim; /* Time of last access */ + struct timespec st_mtim; /* Time of last modification */ + struct timespec st_ctim; /* Time of last status change */ + +#define st_atime st_atim.tv_sec /* Backward compatibility */ +#define st_mtime st_mtim.tv_sec +#define st_ctime st_ctim.tv_sec +}; + +typedef struct stat stat_t; + +#endif //NEW_KERNEL_STAT_H diff --git a/include/time.h b/include/time.h index 259e8fe..c823a63 100644 --- a/include/time.h +++ b/include/time.h @@ -5,4 +5,10 @@ #ifndef NEW_KERNEL_TIME_H #define NEW_KERNEL_TIME_H +typedef uint32_t time_t; + +struct timespec { + time_t tv_sec; + long tv_nsec; +}; #endif //NEW_KERNEL_TIME_H diff --git a/kernel/command.c b/kernel/command.c index 77fe350..ca68db6 100644 --- a/kernel/command.c +++ b/kernel/command.c @@ -19,6 +19,7 @@ #include #include #include +#include #ifdef ENABLE_SELF_TEST @@ -54,6 +55,12 @@ void shutdown(const char *args); void ps(const char *args); +void mount(const char *args); + +void ls(const char *args); + +void cat(const char *args); + #ifdef ENABLE_SELF_TEST void explode(const char *args); @@ -75,6 +82,9 @@ cmd_handler cmd_handlers[] = { {"ide", ide}, {"shutdown", shutdown}, {"ps", ps}, + {"mount", mount}, + {"ls", ls}, + {"cat", cat}, #ifdef ENABLE_SELF_TEST {"slingurl", slingurl}, {"kill-self", kill_self}, @@ -185,17 +195,74 @@ void ide(const char *arg) { } } +void mount(const char *arg) { + vfs_mount("/", "ide0p0", "ext2"); +} + +void ls(const char *arg) { + vfs_fd_t *fd = vfs_open("/", 0, 0); + if (fd == NULL) { + printf("could not open /\n"); + return; + } + void *data = malloc(1024); + if (data == NULL) { + printf("malloc fail\n"); + vfs_close(fd); + return; + } + uint32_t num = 0; + while ((num = vfs_getdents(fd, data, 1024)) > 0) { + vfs_dirent_t *ent = data; + while (true) { + printf("%s\n", ent->name); + if (ent->offset_next >= 1024) { + break; + } + ent = &data[ent->offset_next]; + } + } + free(data); + vfs_close(fd); +} + +void cat(const char *arg) { + vfs_fd_t *fd = vfs_open("/sda1", 0, 0); + vfs_close(fd); + fd = vfs_open("/test.txt", 0, 0); + if (fd == NULL) { + printf("could not open /test.txt\n"); + return; + } + char *data = malloc(1024); + if (data == NULL) { + printf("no mem\n"); + vfs_close(fd); + return; + } + int read = vfs_read(fd, data, 1024); + if (read < 0) { + printf("Failed to read\n"); + } else if (read == 0) { + printf("emtpy file\n"); + } else { + printf("first 10 chars %10s\n", data); + } + free(data); + vfs_close(fd); +} + void store_bootloader_info(multiboot_info_t *multiboot_info) { // get bootloader and cmdline if (multiboot_info->flags & MULTIBOOT_INFO_CMDLINE) { - int cmdline_length = strlen((const char *) multiboot_info->cmdline); + size_t cmdline_length = strlen((const char *) multiboot_info->cmdline); if (cmdline_length > CMDLINE_MAX_LENGTH) { k_panics("cmdline to long!\n"); } memcpy(cmdline, (char *) multiboot_info->cmdline, cmdline_length); } if (multiboot_info->flags & MULTIBOOT_INFO_BOOT_LOADER_NAME) { - int bootloader_length = strlen((const char *) multiboot_info->boot_loader_name); + size_t bootloader_length = strlen((const char *) multiboot_info->boot_loader_name); if (bootloader_length > BOOTLOADER_NAME_MAX_LENGTH) { k_panics("bootloader name to long!\n"); } @@ -226,6 +293,7 @@ void att_noreturn main_loop(void *data) { } #ifdef K_SHELL + void main_loop_start() { task_spawn(main_loop, NULL, "main"); } diff --git a/kernel/libc/kprintf.c b/kernel/libc/kprintf.c index 5642648..8422679 100644 --- a/kernel/libc/kprintf.c +++ b/kernel/libc/kprintf.c @@ -68,6 +68,11 @@ uint32_t vasprintf(char *buf, const char *fmt, va_list args) { ++i; } } + int l = 0; + while (fmt[i] == 'l') { + l++; + i++; + } switch (fmt[i]) { case 's': { // string uint32_t j = 0; @@ -87,7 +92,12 @@ uint32_t vasprintf(char *buf, const char *fmt, va_list args) { case 'x': case 'p': case 'X': // todo capitalize - print_int((uint32_t) va_arg(args, uint32_t), field_width, buf, &ptr, 16); + if (l == 0 || l == 1) { + print_int((uint32_t) va_arg(args, uint32_t), field_width, buf, &ptr, 16); + } else if (l == 2) { + print_int((uint64_t) va_arg(args, uint64_t), field_width, buf, &ptr, 16); + } + // todo error break; case 'i': case 'd': diff --git a/kernel/libc/string.c b/kernel/libc/string.c index b058401..29bb3cb 100644 --- a/kernel/libc/string.c +++ b/kernel/libc/string.c @@ -22,7 +22,7 @@ void *memset(void *dst, int data, size_t amount) { } void *memmove(void *dst, const void *src, size_t amount) { - void* tmp = malloc(amount); + void *tmp = malloc(amount); if (tmp == NULL) { return NULL; } @@ -48,16 +48,19 @@ size_t strlen(const char *str) { } int strcmp(const char *s1, const char *s2) { - int len1 = strlen(s1); - int len2 = strlen(s2); + size_t len1 = strlen(s1); + size_t len2 = strlen(s2); return strncmp(s1, s2, MAX(len1, len2)); } -const char *strchr(const char *s, char c) { - int index = 0; +char *strchr(const char *s, char c) { + size_t index = 0; while (1) { if (s[index] == c) { +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Wincompatible-pointer-types-discards-qualifiers" return &s[index]; +#pragma clang diagnostic pop } if (s[index] == 0) { return NULL; @@ -66,11 +69,14 @@ const char *strchr(const char *s, char c) { } } -const char *strrchr(const char *s, char c) { - int index = strlen(s); +char *strrchr(const char *s, char c) { + size_t index = strlen(s); while (1) { if (s[index] == c) { +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Wincompatible-pointer-types-discards-qualifiers" return &s[index]; +#pragma clang diagnostic pop } if (index == 0) { return NULL; @@ -90,8 +96,8 @@ int memcmp(const void *s1, const void *s2, size_t n) { return 0; } -int strncmp(const char *s1, const char *s2, int n) { - for (int i = 0; i < n; ++i) { +int strncmp(const char *s1, const char *s2, size_t n) { + for (size_t i = 0; i < n; ++i) { if (s1[i] == 0 && s2[i] == 0) { return 0; } diff --git a/kernel/mem/malloc.c b/kernel/mem/malloc.c index 0fd0daf..9eb02f5 100644 --- a/kernel/mem/malloc.c +++ b/kernel/mem/malloc.c @@ -282,7 +282,7 @@ static struct liballoc_major *allocate_new_page(unsigned int size) { } -void *malloc(size_t req_size) { +void __attribute__((assume_aligned (16), alloc_size (1), malloc)) *malloc(size_t req_size) { int startedBet = 0; unsigned long long bestSize = 0; void *p = NULL; diff --git a/kernel/vfs/blockdev.c b/kernel/vfs/blockdev.c index 01a9582..9b60087 100644 --- a/kernel/vfs/blockdev.c +++ b/kernel/vfs/blockdev.c @@ -4,7 +4,6 @@ #include #include -#include #include #include @@ -26,6 +25,25 @@ extern struct block_dev_driver __stop_block_dev_driver[]; semaphore_t *block_semaphore; bool blockdev_task_running = false; +block_device_t *block_dev_get_by_id(const char *name) { + for (int i = 0; i < last_block_dev; ++i) { + if (block_devices[i].flags.present + && strcmp(block_devices[i].identifier, name) == 0) { + return &block_devices[i]; + } + } + return NULL; +} + +block_dev_driver_t *block_dev_driver_by_name(const char *name) { + for (size_t i = 0; i < NUM_DRIVERS; ++i) { + if (strcmp(DRIVER(i)->name, name) == 0) { + return DRIVER(i); + } + } + return NULL; +} + uint8_t block_dev_register(block_device_t *device) { if (last_block_dev >= MAX_BLOCK_DEVS - 1) { return BLOCK_DEV_REGISTER_FULL; @@ -39,6 +57,25 @@ uint8_t block_dev_register(block_device_t *device) { return BLOCK_DEV_REGISTER_OK; } +void *block_dev_mount(const char *device, const char *driver_name) { + if (device == NULL || driver_name == NULL || strlen(device) == 0 || strlen(driver_name) == 0) { + return NULL; // invalid input + } + block_device_t *dev = block_dev_get_by_id(device); + if (dev == NULL) { + return NULL; + } + block_dev_driver_t *driver = block_dev_driver_by_name(driver_name); + if (driver == NULL) { + return NULL; + } + if (driver->check_device(dev) == BLOCK_DEV_DRIVER_CHECK_OK) { + dev->driver = driver; + return dev->driver_info; + } + return NULL; +} + void block_dev_free(block_device_t *device) { //todo k_panics("block dev free not supported"); @@ -52,53 +89,10 @@ int block_dev_num_not_scanned() { return not_scanned; } -bool block_dev_mount(char *identifier, char *driver_name) { - bool result = true; - block_device_t *device = NULL; - for (int i = 0; i < last_block_dev; ++i) { - if (strncmp(block_devices[i].identifier, identifier, 16) == 0) { - device = &block_devices[i]; - } - } - if (identifier == NULL) { - result = false; - goto _end; - } - struct block_dev_driver *driver = NULL; - for (size_t j = 0; j < NUM_DRIVERS; ++j) { - if (strncmp(DRIVER(j)->name, driver_name, 16) == 0) { - driver = DRIVER(j); - } - } - if (driver == NULL) { - result = false; - goto _end; - } - uint8_t *lba0 = malloc(device->block_size); - uint8_t read_result = device->access(device, BLOCK_DEV_DIRECTION_READ, 0, 1, lba0); - if (read_result != BLOCK_DEV_ACCESS_OK) { - result = false; - goto _access_fail; - } - if (driver->check_device(device, lba0) != BLOCK_DEV_DRIVER_CHECK_OK) { - result = false; - } - _access_fail: - free(lba0); - _end: - return result; -} - void block_dev_scan() { int c_last_block_dev = last_block_dev; for (int i = 0; i < c_last_block_dev; ++i) { if (block_devices[i].flags.scanned || !block_devices[i].flags.present) continue; - uint8_t *lba0 = malloc(block_devices[i].block_size); - uint8_t read_result = block_devices[i].access(&block_devices[i], BLOCK_DEV_DIRECTION_READ, 0, 1, lba0); - if (read_result != BLOCK_DEV_ACCESS_OK) { - block_devices[i].flags.unreadable = 1; - goto _block_dev_scan_free; - } for (size_t j = 0; j < NUM_DRIVERS; ++j) { // only partitioning drivers are automatically assigned if (!DRIVER(i)->flags.partitioning) { @@ -110,15 +104,13 @@ void block_dev_scan() { } // let the driver test the disk - uint8_t driver_result = DRIVER(j)->check_device(&block_devices[i], lba0); + uint8_t driver_result = DRIVER(j)->check_device(&block_devices[i]); if (driver_result == BLOCK_DEV_DRIVER_CHECK_OK) { block_devices[i].driver = DRIVER(j); block_devices[i].flags.driver_installed = 1; break; } } - _block_dev_scan_free: - free(lba0); block_devices[i].flags.scanned = 1; } } diff --git a/kernel/vfs/lfs/ext2.c b/kernel/vfs/lfs/ext2.c new file mode 100644 index 0000000..f07e68a --- /dev/null +++ b/kernel/vfs/lfs/ext2.c @@ -0,0 +1,438 @@ +// +// Created by rick on 19-09-21. +// + +#include +#include +#include + +#include +#include +#include +#include +#include + +// https://wiki.osdev.org/Ext2 + +#define EXT2_DRIVER_NAME "ext2" +#define MI(mount) ((ext2_mount_info_t *)(mount)->global_driver_data) +#define FDI(fd) ((ext2_fd_info_t *)(fd)->driver_data) +#define DIV_ROUND_UP(a, b) (((a) + ((b) - 1)) / (b)) + +typedef struct ext2_dgetents_state { + uint32_t bp; + void *current_data; + void *current_data_pos; + void *current_data_end; + uint32_t cur; + bool at_end_of_block; +} ext2_dgetents_state_t; + +typedef struct ext2_fd_info { + uint32_t inode_nr; + ext2_inode_t *inode; + size_t seek_position; + ext2_dgetents_state_t *dgetents_state; + size_t size; + bool dgetents_done; +} ext2_fd_info_t; + +#define EXT2_READ_OK 0 +#define EXT2_READ_ENOMEM 1 +#define EXT2_READ_IOERR 2 +#define EXT2_READ_EOF 3 + +int ext2_read_blocks(vfs_mount_t *mount, uint32_t block, uint32_t num, void *target) { + uint32_t lba = (block * MI(mount)->block_size) / BLOCK_DEV_LBA_SIZE; + uint32_t num_lba = DIV_ROUND_UP(num * MI(mount)->block_size, BLOCK_DEV_LBA_SIZE); + void *buffer = malloc(num_lba * BLOCK_DEV_LBA_SIZE); + if (buffer == NULL) { + return EXT2_READ_ENOMEM; + } + + if (((block_device_t *) MI(mount)->block_dev)->access( + (block_device_t *) MI(mount)->block_dev, + BLOCK_DEV_DIRECTION_READ, lba, num_lba, buffer) + != BLOCK_DEV_ACCESS_OK) { + free(buffer); + return EXT2_READ_IOERR; // todo + } + memcpy(target, buffer, MI(mount)->block_size); + free(buffer); + return EXT2_READ_OK; +} + +ext2_bg_descriptor_t *ext2_get_bg_descriptor(vfs_mount_t *mount, uint32_t idx) { + uint32_t bg_per_block = MI(mount)->block_size / sizeof(ext2_bg_descriptor_t); + uint32_t block = idx / bg_per_block; + if (MI(mount)->block_size != 1024) { + k_panics("only 1024 supported for now"); + } + block += 2; + ext2_bg_descriptor_t *blocks = malloc(MI(mount)->block_size); + if (blocks == NULL) { + return NULL; + } + if (ext2_read_blocks(mount, block, 1, blocks) != EXT2_READ_OK) { + free(blocks); + return NULL; + } + ext2_bg_descriptor_t *res = malloc(sizeof(ext2_bg_descriptor_t)); + if (res == NULL) { + free(blocks); + return NULL; + } + uint32_t block_index = idx % bg_per_block; + memcpy(res, &blocks[block_index], sizeof(ext2_bg_descriptor_t)); + free(blocks); + return res; +} + +ext2_bg_descriptor_t *ext2_get_bg_descriptor_for_inode(vfs_mount_t *mount, uint32_t inode) { + uint32_t group_idx = (inode - 1) / MI(mount)->sb.no_inodes_per_group; + if (group_idx > MI(mount)->no_block_groups) { + return NULL; // todo report + } + ext2_bg_descriptor_t *result = ext2_get_bg_descriptor(mount, group_idx); + if (result == NULL) { + return NULL; + } + return result; +} + +ext2_inode_t *ext2_get_inode(vfs_mount_t *mount, uint32_t inode) { + if (inode > MI(mount)->sb.total_inodes) { + return NULL; // todo report + } + ext2_bg_descriptor_t *descriptor = ext2_get_bg_descriptor_for_inode(mount, inode); + if (descriptor == NULL) { + return NULL; + } + + uint8_t *inodes_in_group = malloc(MI(mount)->block_size); + if (inodes_in_group == NULL) { + free(descriptor); + return NULL; + } + + uint32_t inode_index = (inode - 1) % MI(mount)->sb.no_inodes_per_group; + uint32_t block = (inode_index * MI(mount)->sb.size_inode) / MI(mount)->block_size; + uint32_t inode_offset = (inode_index * MI(mount)->sb.size_inode) % MI(mount)->block_size; + + // todo check bitmap? + if (ext2_read_blocks(mount, descriptor->start_block_inode + block, 1, inodes_in_group) != EXT2_READ_OK) { + free(descriptor); + return NULL; + } + free(descriptor); + + ext2_inode_t *node = malloc(sizeof(ext2_inode_t)); + memcpy(node, &inodes_in_group[inode_offset], sizeof(ext2_inode_t)); + + free(inodes_in_group); + return node; +} + +int ext2_get_block_from_inode(vfs_mount_t *mount, vfs_fd_t *fd, void *target, uint32_t block_idx) { + if (block_idx < 12) { + uint32_t bp = FDI(fd)->inode->dbp[block_idx]; + if (bp == 0) { + return EXT2_READ_EOF; + } + return ext2_read_blocks(mount, bp, 1, target); + } else { + k_panics("Not implemented"); + } +} + +#define EXT2_DGETENT_CONT 1 +#define EXT2_DGETENT_FULL 2 +#define EXT2_DGETENT_END 3 +#define EXT2_DGETENT_ERR 4 + +int ext2_dgetent_next(vfs_mount_t *mount, vfs_fd_t *fd, ext2_dgetents_state_t *state, void *target, size_t offset, + size_t max_size) { + if (state->bp == UINT32_MAX) { + // new + state->current_data = malloc(MI(mount)->block_size); + state->current_data_pos = state->current_data; + state->current_data_end = state->current_data + MI(mount)->block_size; + state->bp = 0; + state->at_end_of_block = false; + int result = ext2_get_block_from_inode(mount, fd, state->current_data, state->bp); + if (result != EXT2_READ_OK) { + return result == EXT2_READ_EOF ? EXT2_DGETENT_END : EXT2_DGETENT_ERR; + } + } + if (state->at_end_of_block == true) { + state->bp += 1; + int result = ext2_get_block_from_inode(mount, fd, state->current_data, state->bp); + state->current_data_pos = state->current_data; + if (result != EXT2_READ_OK) { + return result == EXT2_READ_EOF ? EXT2_DGETENT_END : EXT2_DGETENT_ERR; + } + } + ext2_dir_entry_t *ent = state->current_data_pos; + if (VFS_DIRENT_SIZE(ent->name_size) > max_size) { + return EXT2_DGETENT_FULL; + } + vfs_mk_dirent_record(&target[offset], ent->inode, offset, 0, &ent->name, ent->name_size); + state->current_data_pos += ent->ent_size; + if (state->current_data_pos >= state->current_data_end) { + state->at_end_of_block = true; + } + return EXT2_DGETENT_CONT; +} + +int ext2_vfs_mount(vfs_mount_t *mount) { + ext2_mount_info_t *mount_info = block_dev_mount(mount->device, EXT2_DRIVER_NAME); + if (mount_info == NULL) { + return VFS_MOUNT_ERROR; + } + mount->global_driver_data = mount_info; + return VFS_MOUNT_OK; +} + +ext2_fd_info_t *ext2_get_inode_info(vfs_mount_t *mount, uint32_t inode) { + ext2_inode_t *node = ext2_get_inode(mount, inode); + if (node == NULL) { + return NULL; + } + ext2_fd_info_t *driver_data = malloc(sizeof(ext2_fd_info_t)); + if (driver_data == NULL) { + return NULL; + } + size_t size = node->size_l; + if (MI(mount)->sb.features_optional & EXT2_FEATURE_RO_64BIT_SIZE && node->type == EXT2_INODE_TYPE_FILE) { +#if EXT2_FEAT_RO_64BIT_SIZE + size += node->size_h << 32; +#else + if (node->size_h != 0) { + printf("WARN: file to large"); + free(driver_data); + return NULL; + } +#endif + } + driver_data->inode_nr = inode; + driver_data->inode = node; + driver_data->size = size; + driver_data->seek_position = 0; + driver_data->dgetents_state = NULL; + driver_data->dgetents_done = false; + return driver_data; +} + +vfs_dirent_t *ext2_get_dirent_for_filename(vfs_mount_t *mount, vfs_fd_t *dir, const char *path) { + size_t name_length = strlen(path); + vfs_dirent_t *ent = malloc(VFS_DIRENT_MAX_SIZE); + if (ent == NULL) { + return NULL; + } + ext2_dgetents_state_t *state = malloc(sizeof(ext2_dgetents_state_t)); + if (state == NULL) { + return NULL; + } + memset(state, 0, sizeof(ext2_dgetents_state_t)); + state->bp = UINT32_MAX; + bool found = false; + // todo hash algorithm + while (true) { + const int result = ext2_dgetent_next(mount, dir, state, ent, 0, VFS_DIRENT_MAX_SIZE); + if (result == EXT2_DGETENT_FULL || result == EXT2_DGETENT_ERR) { + break; // whut + } + if (result == EXT2_DGETENT_END) { + // not found + break; // not found + } + if (name_length != strlen(ent->name)) { + continue; + } + if (strncmp(path, ent->name, name_length) != 0) { + // not same name + continue; + } + found = true; + break; + } + free(state); + if (!found) { + free(ent); + return NULL; + } + return ent; +} + +int ext2_vfs_open(vfs_mount_t *mount, vfs_fd_t *dir, const char *path, int mode, vfs_fd_t *out) { + if (dir == NULL && path == NULL) { + ext2_fd_info_t *driver_data = ext2_get_inode_info(mount, EXT2_ROOT_INODE); + if (driver_data == NULL) { + return VFS_OPEN_ERROR; + } + out->driver_data = driver_data; + return VFS_OPEN_OK; + } + vfs_dirent_t *dirent = ext2_get_dirent_for_filename(mount, dir, path); + int open_result = VFS_OPEN_ERROR; + if (dirent != NULL) { + ext2_fd_info_t *driver_data = ext2_get_inode_info(mount, dirent->inode); + if (driver_data != NULL) { + out->driver_data = driver_data; + open_result = VFS_OPEN_OK; + } + } + free(dirent); + return open_result; +} + +int ext2_vfs_close(vfs_mount_t *mount, vfs_fd_t *fd) { + if (FDI(fd)->dgetents_state != NULL) { + free(FDI(fd)->dgetents_state); + } + free(fd); + return VFS_CLOSE_OK; +} + +int ext2_vfs_fstat(vfs_mount_t *mount, vfs_fd_t *fd, stat_t *target, int flags) { + target->st_dev = 0; // todo + target->st_ino = FDI(fd)->inode_nr; + target->st_mode = FDI(fd)->inode->type; + target->st_nlink = FDI(fd)->inode->no_hard_links; + target->st_uid = FDI(fd)->inode->uid; + target->st_gid = FDI(fd)->inode->gid; + target->st_size = FDI(fd)->size; + target->st_blksize = MI(mount)->block_size; + target->st_blocks = FDI(fd)->size / 512; // todo correct? + target->st_atim.tv_sec = FDI(fd)->inode->last_access; + target->st_mtim.tv_sec = FDI(fd)->inode->last_mod; + target->st_ctim.tv_sec = FDI(fd)->inode->created; + + if (FDI(fd)->inode->type == EXT2_INODE_TYPE_BLOCK_DEV || FDI(fd)->inode->type == EXT2_INODE_TYPE_CHAR_DEV) { + target->st_rdev = FDI(fd)->inode->dbp[0]; + } + return 0; +} + +int ext2_vfs_fread(vfs_mount_t *mount, vfs_fd_t *fd, void *target, size_t size) { + size_t target_pos = 0; + + void *buffer = malloc(MI(mount)->block_size); + if (buffer == NULL) { + return VFS_READ_ERROR; + } + while (true) { + uint32_t block = FDI(fd)->seek_position / MI(mount)->block_size; + uint32_t bytes_read_in_block = FDI(fd)->seek_position % MI(mount)->block_size; + uint32_t bytes_left_in_block = MI(mount)->block_size - bytes_read_in_block; + size_t toread = MIN(MIN(bytes_left_in_block, size - target_pos), FDI(fd)->size - target_pos); + + if (ext2_get_block_from_inode(mount, fd, buffer, block) != EXT2_READ_OK) { + free(buffer); + return VFS_READ_ERROR; + } + + memcpy(&target[target_pos], &buffer[block], toread); + target_pos += toread; + FDI(fd)->seek_position += toread; + if (target_pos == size || FDI(fd)->seek_position >= FDI(fd)->size) { + break; + } + } + free(buffer); + return target_pos; +} + +int ext2_vfs_dgetent(vfs_mount_t *mount, vfs_fd_t *fd, void *target, size_t size) { + if (FDI(fd)->dgetents_done == true) { + return 0; + } + size_t offset = 0; + size_t prev_offset = 0; + if (FDI(fd)->dgetents_state == NULL) { + FDI(fd)->dgetents_state = malloc(sizeof(ext2_dgetents_state_t)); + FDI(fd)->dgetents_state->bp = UINT32_MAX; + FDI(fd)->dgetents_state->cur = 0; + } + + while (true) { + int result = ext2_dgetent_next(mount, fd, FDI(fd)->dgetents_state, target, offset, size - offset); + if (result != EXT2_DGETENT_CONT) { + if (result == EXT2_DGETENT_END) { + if (FDI(fd)->dgetents_state->current_data != NULL) { + free(FDI(fd)->dgetents_state->current_data); + FDI(fd)->dgetents_state->current_data = NULL; + } + free(FDI(fd)->dgetents_state); + FDI(fd)->dgetents_state = NULL; + FDI(fd)->dgetents_done = true; + } + if (result == EXT2_DGETENT_FULL || result == EXT2_DGETENT_END) { + ((vfs_dirent_t *) &target[prev_offset])->offset_next = size; + } + break; + } + size_t reclen = ((vfs_dirent_t *) &target[offset])->reclen; + prev_offset = offset; + offset += reclen; + } + return offset; +} + +uint32_t ext2_get_no_bg(ext2_sb_t *sb) { + uint32_t no_bg_by_blocks = DIV_ROUND_UP(sb->total_blocks, sb->no_blocks_per_group); + uint32_t no_bg_by_inodes = DIV_ROUND_UP(sb->total_inodes, sb->no_inodes_per_group); + if (no_bg_by_blocks != no_bg_by_inodes) { + k_panics("No no match"); + } + return no_bg_by_inodes; +} + +uint8_t ext2_check_device(block_device_t *device) { + ext2_sb_t *sb = malloc(EXT2_SB_SIZE); + if (device->access(device, + BLOCK_DEV_DIRECTION_READ, + EXT2_SB_ADDR / BLOCK_DEV_LBA_SIZE, + EXT2_SB_SIZE / BLOCK_DEV_LBA_SIZE, + sb) != BLOCK_DEV_ACCESS_OK) { + free(sb); + return BLOCK_DEV_DRIVER_CHECK_NO_MATCH; + } + if (sb->ext2_signature != EXT2_SIGNATURE) { + printf("Missing signature\n"); + return BLOCK_DEV_DRIVER_CHECK_NO_MATCH; + } + printf("Ext2 features:\n\tRequired: %lx\n\tOptional: %lx\n\tRo: %lx\n", sb->features_required, + sb->features_optional, sb->features_ro); + if (sb->features_required ^ EXT2_FEAT_REQ_SUPPORTED) { + printf("Filesystem uses features not supported by implementation, %lx\n", sb->features_required); + free(sb); + return BLOCK_DEV_DRIVER_CHECK_NO_MATCH; + } + printf("ext2 valid\n"); + ext2_mount_info_t *mount_info = malloc(sizeof(ext2_mount_info_t)); + memcpy(&mount_info->sb, sb, sizeof(ext2_sb_t)); + mount_info->no_block_groups = ext2_get_no_bg(sb); + mount_info->block_size = 1024 << sb->block_size; + mount_info->fragment_size = 1024 << sb->fragment_size; + mount_info->block_dev = device; + device->driver_info = mount_info; + free(sb); + return BLOCK_DEV_DRIVER_CHECK_OK; +} + +BLOCK_DEV_DRIVER(300) = { + .name = EXT2_DRIVER_NAME, + .check_device = ext2_check_device, + .free_device = NULL, +}; + +VFS_DRIVER(300) = { + .name = EXT2_DRIVER_NAME, + .vfs_mount = ext2_vfs_mount, + .open = ext2_vfs_open, + .close = ext2_vfs_close, + .fstat = ext2_vfs_fstat, + .fread = ext2_vfs_fread, + .dgetent = ext2_vfs_dgetent, +}; diff --git a/kernel/vfs/lfs/fat.c b/kernel/vfs/lfs/fat.c index 8ec0306..1375477 100644 --- a/kernel/vfs/lfs/fat.c +++ b/kernel/vfs/lfs/fat.c @@ -107,9 +107,26 @@ void print_chars(char *chars, int amount) { } } -uint8_t att_used fat_check_device(const block_device_t *device, uint8_t *first_sector) { +uint8_t att_used fat_check_device(const block_device_t *device) { + uint8_t *first_sector = malloc(512); + if (first_sector == NULL) { + printf("No mem\n"); + return BLOCK_DEV_DRIVER_CHECK_NO_MATCH; + } + uint8_t result = device->access(device, BLOCK_DEV_DIRECTION_READ, 0, 1, first_sector); + if (result != BLOCK_DEV_ACCESS_OK) { + printf("Could not access device\n"); + free(first_sector); + return BLOCK_DEV_DRIVER_CHECK_NO_MATCH; + } + if (first_sector[510] != 0x55 || first_sector[511] != 0xAA) { + printf("No boot signature\n"); + free(first_sector); + return BLOCK_DEV_DRIVER_CHECK_NO_MATCH; + } fat_bpb bpb; memcpy((uint8_t *) &bpb, first_sector, sizeof(fat_bpb)); + free(first_sector); if (bpb.bpb.sectors_per_fat == 0 || bpb.bpb.sectors_per_cluster == 0) { printf("Definitely not FAT\n"); return BLOCK_DEV_DRIVER_CHECK_NO_MATCH; diff --git a/kernel/vfs/lfs/ustar.c b/kernel/vfs/lfs/ustar.c index 282e3fd..0d6df0d 100644 --- a/kernel/vfs/lfs/ustar.c +++ b/kernel/vfs/lfs/ustar.c @@ -75,15 +75,20 @@ ustar_sector *ustar_next(ustar_sector *current) { return ustar_sector_valid(next) ? next : NULL; } -uint8_t ustar_check_device(const block_device_t *device, uint8_t *first_sector) { - ustar_sector *sector = (ustar_sector *) first_sector; +uint8_t ustar_check_device(const block_device_t *device) { + ustar_sector *sector = malloc(512); // todo fix leak + if (device->access(device, BLOCK_DEV_DIRECTION_READ, 0, 1, sector) != BLOCK_DEV_ACCESS_OK) { + free(sector); + return BLOCK_DEV_DRIVER_CHECK_NO_MATCH; + } if (!ustar_sector_valid(sector)) { + free(sector); return BLOCK_DEV_DRIVER_CHECK_NO_MATCH; } ustar_fs *fs = malloc(sizeof(ustar_fs)); fs->first_inode = malloc(sizeof(ustar_inode)); - memcpy(&fs->first_inode->sector, first_sector, sizeof(ustar_sector)); + memcpy(&fs->first_inode->sector, sector, sizeof(ustar_sector)); fs->first_inode->lba = 0; fs->device = device; diff --git a/kernel/vfs/part/mbr.c b/kernel/vfs/part/mbr.c index 805927e..e00c257 100644 --- a/kernel/vfs/part/mbr.c +++ b/kernel/vfs/part/mbr.c @@ -33,12 +33,11 @@ typedef struct { } att_packed mbr_table; typedef struct { - const block_device_t *device; + block_device_t *device; uint32_t start_lba; } mbr_block_driver_info; -uint8_t -mbr_block_dev_access(const block_device_t *device, uint8_t direction, uint32_t lba, uint8_t sectors, void *target) { +uint8_t mbr_block_dev_access(block_device_t *device, uint8_t direction, uint32_t lba, uint8_t sectors, void *target) { if (!device->flags.present || lba > device->num_lba) { return BLOCK_DEV_ACCESS_ERR; } @@ -52,9 +51,15 @@ mbr_block_dev_access(const block_device_t *device, uint8_t direction, uint32_t l return info->device->access(info->device, direction, actual_lba, sectors, target); } -uint8_t att_used mbr_check_device(const block_device_t *device, uint8_t *first_sector) { +uint8_t mbr_check_device(block_device_t *device) { + uint8_t *first_sector = malloc(512); + if (device->access(device, BLOCK_DEV_DIRECTION_READ, 0, 1, first_sector) != BLOCK_DEV_ACCESS_OK) { + free(first_sector); + return BLOCK_DEV_DRIVER_CHECK_NO_MATCH; + } mbr_table table; memcpy((uint8_t *) &table, first_sector + (device->block_size - sizeof(mbr_table)), sizeof(mbr_table)); + free(first_sector); if (table.signature[0] != 0x55 && table.signature[1] != 0xAA) { // AA 55 but in little endian return BLOCK_DEV_DRIVER_CHECK_NO_MATCH; } diff --git a/kernel/vfs/vfs.c b/kernel/vfs/vfs.c new file mode 100644 index 0000000..5a49da4 --- /dev/null +++ b/kernel/vfs/vfs.c @@ -0,0 +1,186 @@ +// +// Created by rick on 12-08-21. +// + +#include +#include +#include + +#include +#include +#include +#include +#include + +vfs_mount_t *first_mount = NULL; +mutex_t *mount_lock = NULL; + +extern vfs_driver_t __start_vfs_driver[]; +extern vfs_driver_t __stop_vfs_driver[]; +#define NUM_DRIVERS ((size_t)(__stop_vfs_driver - __start_vfs_driver)) +#define DRIVER(i) ((__start_vfs_driver) + (i)) + +vfs_driver_t *vfs_get_driver_by_name(const char *name) { + for (size_t i = 0; i < NUM_DRIVERS; ++i) { + if (strcmp(DRIVER(i)->name, name) == 0) { + return DRIVER(i); + } + } + return NULL; +} + +void vfs_register_mount(vfs_mount_t *mount) { + mutex_acquire(mount_lock); + if (first_mount == NULL) { + first_mount = mount; + } else { + vfs_mount_t *last_mount = first_mount; + while (last_mount->next != NULL) last_mount = last_mount->next; + last_mount->next = mount; + } + mutex_release(mount_lock); +} + +vfs_mount_t *vfs_get_mount_for_path(const char *path) { + if (first_mount == NULL) { + return NULL; + } + mutex_acquire(mount_lock); + size_t max_length = strlen(path); + vfs_mount_t *longest_match = NULL; + size_t match_length = 0; + vfs_mount_t *last_mount = NULL; + do { + if (last_mount == NULL) { + last_mount = first_mount; + } else if ((last_mount = last_mount->next) == NULL) { + break; + } + size_t mount_length = strlen(last_mount->prefix); + if (mount_length > max_length || mount_length < match_length) { + continue; + } + if (strncmp(last_mount->prefix, path, strlen(last_mount->prefix)) == 0) { + longest_match = last_mount; + match_length = mount_length; + } + } while (true); + mutex_release(mount_lock); + return longest_match; +} + +int vfs_mount(const char *path, const char *device, const char *driver) { + vfs_driver_t *driver_impl = vfs_get_driver_by_name(driver); + if (driver_impl == NULL) { + return VFS_MOUNT_ERROR; + } + vfs_mount_t *mount = malloc(sizeof(vfs_mount_t)); + mount->driver = driver_impl; + mount->device = device; + mount->prefix = path; + int result = driver_impl->vfs_mount(mount); + if (result != VFS_MOUNT_OK) { + free(mount); + return result; + } + vfs_register_mount(mount); + return VFS_MOUNT_OK; +} + +vfs_fd_t *vfs_open_intermediate(vfs_mount_t *mount, const char *path, int flags, int mode) { + vfs_fd_t *intermediate_dir = malloc(sizeof(vfs_fd_t)); + vfs_fd_t *out = malloc(sizeof(vfs_fd_t)); + out->mount = mount; + intermediate_dir->mount = mount; + char *full_path = strdup(path); + char *current_path = full_path; + while (strlen(current_path) > 0) { + if (current_path[0] == '/') { + // root + if (((vfs_driver_t *) mount->driver)->open(mount, NULL, NULL, flags, out) != VFS_OPEN_OK) { + free(out); + free(intermediate_dir); + free(full_path); + return NULL; + } + current_path = ¤t_path[1]; + } else { + char *next_dir = strchr(current_path, '/'); + if (next_dir != NULL) { + next_dir[0] = 0; + } + if (((vfs_driver_t *) mount->driver)->open(mount, intermediate_dir, current_path, flags, out) != + VFS_OPEN_OK) { + ((vfs_driver_t *) mount->driver)->close(mount, intermediate_dir); + free(out); + free(intermediate_dir); + free(full_path); + return NULL; + } + if (next_dir == NULL) { + current_path = ¤t_path[strlen(current_path)]; + } else { + current_path = &next_dir[1]; + } + if (((vfs_driver_t *) mount->driver)->close(mount, intermediate_dir) != VFS_CLOSE_OK) { + free(out); + free(intermediate_dir); + free(full_path); + return NULL; + } + } + memcpy(intermediate_dir, out, sizeof(vfs_fd_t)); + } + free(full_path); + free(intermediate_dir); + return out; +} + +// https://man7.org/linux/man-pages/man2/open.2.html +vfs_fd_t *vfs_open(const char *path, int flags, int mode) { + vfs_mount_t *mount = vfs_get_mount_for_path(path); + if (mount == NULL) { + return NULL; + } + return vfs_open_intermediate(mount, &path[strlen(mount->prefix) - 1], flags, mode); +} + +void vfs_close(vfs_fd_t *fd) { + ((vfs_driver_t *) (fd->mount->driver))->close(fd->mount, fd); + free(fd); +} + +// https://man7.org/linux/man-pages/man2/stat.2.html +int vfs_fstat(vfs_fd_t *dirfd, stat_t *target, int flags) { + return ((vfs_driver_t *) (dirfd->mount->driver))->fstat(dirfd->mount, dirfd, target, flags); +} + +// https://man7.org/linux/man-pages/man2/read.2.html +int vfs_read(vfs_fd_t *fd, void *target, size_t size) { + return ((vfs_driver_t *) (fd->mount->driver))->fread(fd->mount, fd, target, size); +} + +// inspiration https://man7.org/linux/man-pages/man2/getdents.2.html +int vfs_getdents(vfs_fd_t *fd, void *target, int count) { + return ((vfs_driver_t *) fd->mount->driver)->dgetent(fd->mount, fd, target, count); +} + +void vfs_mk_dirent_record(vfs_dirent_t *ent, uint32_t inode, uint32_t cur_offset, uint8_t type, char *name, + size_t name_length) { + ent->inode = inode; + strncpy(ent->name, name, name_length); + ent->name[name_length] = 0; + ent->type = type; + ent->reclen = VFS_DIRENT_SIZE(name_length); + ent->offset_next = cur_offset + ent->reclen; +} + +void vfs_init() { + mount_lock = mutex_create(); +} + +INIT_FUNCTION(100) = { + .name = "vfs-task", + .stage = INIT_STAGE_PRE_TASKING, + .init = vfs_init, +}; diff --git a/linker.ld b/linker.ld index 386ea79..796290e 100644 --- a/linker.ld +++ b/linker.ld @@ -30,18 +30,26 @@ SECTIONS .data BLOCK(4K) : ALIGN(4K) { *(.data) - . = ALIGN(16); - __start_init = .; - *(SORT(.init.*)) - __stop_init = .; + . = ALIGN(16); __start_pci_driver = .; *(SORT(.pci_driver.*)) __stop_pci_driver = .; + . = ALIGN(16); __start_block_dev_driver = .; *(SORT(.block_dev_driver.*)) __stop_block_dev_driver = .; + + . = ALIGN(16); + __start_vfs_driver = .; + *(SORT(.vfs_driver.*)) + __stop_vfs_driver = .; + + . = ALIGN(16); + __start_init = .; + *(SORT(.init.*)) + __stop_init = .; } /* Read-write data (uninitialized) and stack */ diff --git a/rootfs/.gitignore b/rootfs/.gitignore new file mode 100644 index 0000000..642862d --- /dev/null +++ b/rootfs/.gitignore @@ -0,0 +1,3 @@ +mnt/* +!mnt +rootfs.img \ No newline at end of file diff --git a/rootfs/mkrootfs.sh b/rootfs/mkrootfs.sh new file mode 100755 index 0000000..247c3fd --- /dev/null +++ b/rootfs/mkrootfs.sh @@ -0,0 +1,52 @@ +#!/bin/bash + +IMG_FILE=rootfs.img +IMG_SIZE=100 # MB + +function log() { + echo "$*" +} + +function yes_or_no() { + while true; do + read -p "$* [y/n]: " yn + case $yn in + [Yy]*) return 0 ;; + [Nn]*) + echo "Aborted" + return 1 + ;; + esac + done +} + +function setup_lb() { + sudo losetup -fP --show ${IMG_FILE} +} + +if [ ! -d mnt ]; then + mkdir mnt +fi + +if [ -f "${IMG_FILE}" ]; then + log "${IMG_FILE} already exists" + if ! yes_or_no "Continue?"; then + exit 1 + fi +fi + +# build img +dd if=/dev/zero of=${IMG_FILE} bs=1M count=${IMG_SIZE} + +parted -s ${IMG_FILE} mktable msdos +parted -s ${IMG_FILE} mkpart primary ext2 0 100% + +LB_DEV="$(setup_lb)" + +if [ -z "${LB_DEV}" ]; then + log "Failed to setup loobback" + exit 1 +fi + +sudo mkfs.ext2 -L rootfs "${LB_DEV}p1" +sudo mount "${LB_DEV}p1" mnt diff --git a/rootfs/mount_rootfs.sh b/rootfs/mount_rootfs.sh new file mode 100755 index 0000000..0086fe9 --- /dev/null +++ b/rootfs/mount_rootfs.sh @@ -0,0 +1,39 @@ +#!/bin/bash + +IMG_FILE=rootfs.img +IMG_SIZE=100 # MB + +function log() { + echo "$*" +} + +function yes_or_no() { + while true; do + read -p "$* [y/n]: " yn + case $yn in + [Yy]*) return 0 ;; + [Nn]*) + echo "Aborted" + return 1 + ;; + esac + done +} + +function setup_lb() { + sudo losetup -fP --show ${IMG_FILE} +} + +if [ ! -f "${IMG_FILE}" ]; then + log "${IMG_FILE} doesn't exist" + exit 1 +fi + +LB_DEV="$(setup_lb)" + +if [ -z "${LB_DEV}" ]; then + log "Failed to setup loobback" + exit 1 +fi + +sudo mount "${LB_DEV}p1" mnt diff --git a/rootfs/umount_rootfsh.sh b/rootfs/umount_rootfsh.sh new file mode 100755 index 0000000..8b59907 --- /dev/null +++ b/rootfs/umount_rootfsh.sh @@ -0,0 +1,15 @@ +#!/bin/bash + +function log() { + echo "$*" +} + +LB_DEV=$(findmnt -n -o SOURCE mnt) + +if [ -z "${LB_DEV}" ]; then + log "Not mounted" + exit 1 +fi + +sudo umount mnt +sudo losetup -d "${LB_DEV%p1}"