From a8213b88e92416f3f6c84935e4766862a6f316db Mon Sep 17 00:00:00 2001 From: d0p1 Date: Thu, 25 Jul 2024 08:46:56 +0000 Subject: [PATCH] feat(mkfs.stpd): make filesystem bootable (WIP) --- configure.ac | 4 ++ libstpdfs/Makefile.am | 2 +- tools/Makefile.am | 11 ++- tools/mkfs/boot.asm | 164 ++++++++++++++++++++++++++++++++++++++++++ tools/mkfs/main.c | 18 ++++- 5 files changed, 195 insertions(+), 4 deletions(-) create mode 100644 tools/mkfs/boot.asm diff --git a/configure.ac b/configure.ac index e9bb9ea..20fc2ed 100644 --- a/configure.ac +++ b/configure.ac @@ -13,6 +13,10 @@ AM_PROG_AR AC_PROG_INSTALL AC_PROG_RANLIB AM_PROG_CC_C_O +AC_CHECK_PROG([NASM], [nasm], [nasm]) +AS_IF([test -z "$NASM"], [ + AC_MSG_ERROR([nasm is required]) +]) AC_CONFIG_HEADERS([config.h]) diff --git a/libstpdfs/Makefile.am b/libstpdfs/Makefile.am index 3557c22..5a423d0 100644 --- a/libstpdfs/Makefile.am +++ b/libstpdfs/Makefile.am @@ -1,2 +1,2 @@ noinst_LIBRARIES = libstpdfs.a -liblzp_a_SOURCES = super.c bio.c inode.c file.c dir.c \ No newline at end of file +libstpdfs_a_SOURCES = super.c bio.c inode.c file.c dir.c \ No newline at end of file diff --git a/tools/Makefile.am b/tools/Makefile.am index 86a5a32..98feb4c 100644 --- a/tools/Makefile.am +++ b/tools/Makefile.am @@ -4,7 +4,16 @@ LDADD = ../lib/libstpdfs.a bin_PROGRAMS = mkfs.stpd tools.stpd mkfs_stpd_SOURCES = mkfs/main.c +mkfs_stpd_LDADD = ../lib/libstpdfs.a mkfs/bootsector.o tools_stpd_SOURCES = tools/main.c -man_MANS = mkfs/mkfs.stpd.8 tools/tools.stpd.8 \ No newline at end of file +mkfs/boot.o: mkfs/boot.asm + $(NASM) -fbin -o $@ $< + +mkfs/bootsector.o: mkfs/boot.o + ld -r -b binary -o $@ $< + +man_MANS = mkfs/mkfs.stpd.8 tools/tools.stpd.8 + +CLEANFILES = mkfs/boot.o mkfs/bootsector.o \ No newline at end of file diff --git a/tools/mkfs/boot.asm b/tools/mkfs/boot.asm new file mode 100644 index 0000000..f9ffa2e --- /dev/null +++ b/tools/mkfs/boot.asm @@ -0,0 +1,164 @@ + [BITS 16] + [ORG 0x7c00] + + LOADER_BASE equ 0x1000 + DISK_BUFFER equ 0x8000 + STPDFS_MAGIC equ 0x44505453 + INODE_SIZE equ 34 + INODE_ALLOCATED equ (1<<15) + CR equ 0xD + LF equ 0xA + + struc inode + .mode: resb 1 + .nlink: resb 1 + .uid: resb 1 + .gid: resb 1 + .flags: resb 1 + .size: resd 1 + .zones: resd 10 + .actime: resq 1 + .modtime: resq 1 + endstruc + + jmp start + nop + +bpb: + db 0, 0, 0 +.oem_id: db "STUPIDFS" +.sector_size: dw 512 +.sects_per_cluster: db 0 +.reserved_sects: dw 0 +.fat_count: db 0 +.root_dir_entries: dw 0 +.sector_count: dw 0 +.media_type: db 0 +.sects_per_fat: dw 0 +.sects_per_track: dw 18 +.head_count: dw 2 +.hidden_sects: dd 0 +.sector_count_big: dd 0 +.drive_num: db 0 +.reserved: db 0 +.signature: db 0 +.volume_id: dd 0 +.volume_label: db "STPD.MKFS " +.filesystem_type: times 8 db 0 + +start: + cli + cld + jmp 0x0:.canonicalize_cs + +.canonicalize_cs: + xor ax, ax + mov ds, ax + mov ss, ax + mov es, ax + mov sp, 0x7c00 + + mov [bpb.drive_num], dl + + ; ensure lba mode is supported + mov ah, 0x41 + mov bx, 0x55AA + int 0x13 + jc .err_lba + + ; reset disk +.reset_disk: + mov dl, [bpb.drive_num] + xor ah, ah + int 0x13 + jc .reset_disk + + ; read superblock + mov ax, DISK_BUFFER/10 + mov es, ax + + ; load two sector in memory + ; superblock and first inodes + mov eax, 1 + mov cx, 2 + xor bx, bx + call disk_read_sectors + + mov dword eax, [DISK_BUFFER] + cmp eax, STPDFS_MAGIC + jne .err_magic + + ; inode 0 bad + ; inode 1 root dir + ; inode 2 is loader, let's keep things easy + mov ax, word [DISK_BUFFER + 34 * 2 + inode.flags] + and ax, INODE_ALLOCATED + jz .err_no_loader + + mov dword eax, [DISK_BUFFER + 34 * 2 + inode.size] ; size + mov dword [uFsize], eax + + mov eax, DISK_BUFFER + 34 * 2 + 14 ; first zone + + mov ax, LOADER_BASE/10 + mov es, ax + + jmp 0x0:LOADER_BASE + +.err_no_loader: + mov si, szErrorNoLoader + call bios_print + jmp .end +.err_magic: + mov si, szErrorNoLoader + call bios_print + jmp .end +.err_lba: + mov si, szErrorLBA + call bios_print +.end: + hlt + jmp $ + +bios_print: + lodsb + or al, al + jz .end + mov ah, 0x0E + int 0x10 + jmp bios_print +.end: + ret + +szMsgHello: db "Hello world", CR, LF, 0 +szErrorNoLoader: db "Loader not found", CR, LF, 0 +szErrorBadMagic: db "Invalid magic number", CR, LF, 0 +szErrorLBA: db "LBA not supported", CR, LF, 0 +uFsize: dd 0 + +disk_read_sectors: + mov word [disk_packet.sectors], cx + mov word [disk_packet.segment], es + mov word [disk_packet.offset], bx + mov dword [disk_packet.lba], eax + mov si, [disk_packet] + mov dl, [bpb.drive_num] + mov ah, 0x42 + int 0x13 + ret + +disk_packet: + db 0x10 + db 0 +.sectors: + dw 0 +.segment: + dw 0 +.offset: + dw 0 +.lba: + dd 0 + dd 0 + + times 510-($-$$) db 0 + dw 0xAA55 \ No newline at end of file diff --git a/tools/mkfs/main.c b/tools/mkfs/main.c index 70af679..cf5c54d 100644 --- a/tools/mkfs/main.c +++ b/tools/mkfs/main.c @@ -23,12 +23,17 @@ static const char *prg_name; static int inodes = -1; static const char *device; static int blocks = -1; +static int bootable = 0; static struct stpdfs_sb super; +extern const char _binary_mkfs_boot_o_start[]; +extern const char _binary_mkfs_boot_o_end[]; + #ifdef HAVE_STRUCT_OPTION static struct option long_options[] = { {"help", no_argument, 0, 'h'}, {"version", no_argument, 0, 'V'}, + {"boot", no_argument, 0, 'b'}, {"inodes", required_argument, 0, 'i'}, {0, 0, 0, 0} }; @@ -45,6 +50,7 @@ usage(int retval) { printf("Usage: %s [options] /dev/name [blocks]\n\n", prg_name); printf("Options:\n"); + printf(" -b, --boot make filesystem bootable\n"); printf(" -i, --inode number of inodes for the filesystem\n"); printf(" -h, --help display this help\n"); printf(" -V, --version display version\n\n"); @@ -168,6 +174,11 @@ mkfs() super.state = STPDFS_CLEANLY_UNMOUNTED; stpdfs_write(fd, 1, &super, sizeof(struct stpdfs_sb)); + if (bootable) + { + stpdfs_write(fd, 0, (void *)_binary_mkfs_boot_o_start, STPDFS_BLOCK_SIZE); + } + /* we finished \o/ */ printf("StupidFS: %u blocks (%u Inodes)\n", super.fsize, super.isize); @@ -189,9 +200,9 @@ main(int argc, char **argv) #endif /* HAVE_LIBGEN_H */ #if defined(HAVE_GETOPT_LONG) && defined(HAVE_STRUCT_OPTION) - while ((c = getopt_long(argc, argv, "hVi:", long_options, &idx)) != EOF) + while ((c = getopt_long(argc, argv, "hVbi:", long_options, &idx)) != EOF) #else - while ((c = getopt(argc, argv, "hVi:")) != EOF) + while ((c = getopt(argc, argv, "hVbi:")) != EOF) #endif /* HAVE_GETOPT_LONG && HAVE_STRUCT_OPTION */ { switch (c) @@ -202,6 +213,9 @@ main(int argc, char **argv) case 'V': version(); break; + case 'b': + bootable = 1; + break; case 'i': inodes = atoi(optarg); break;