From d366c94ac895e889970078dc55b2edb5ad5b32ea Mon Sep 17 00:00:00 2001 From: Rafal Kupiec Date: Sat, 27 Sep 2025 17:25:51 +0200 Subject: [PATCH] Import disk image manipulation tool --- build.sh | 2 +- tools/diskimg.c | 186 ++++++++++++++++++++++++++++++++++++++++++++++++ tools/xtchain.h | 22 ++++-- 3 files changed, 204 insertions(+), 6 deletions(-) create mode 100644 tools/diskimg.c diff --git a/build.sh b/build.sh index b4454e9..0e43cd4 100755 --- a/build.sh +++ b/build.sh @@ -408,7 +408,7 @@ xtchain_build() echo ">>> Building XTchain tools ..." mkdir -p ${BINDIR}/bin mkdir -p ${BINDIR}/lib/xtchain - for EXEC in bin2c exetool xtcspecc; do + for EXEC in bin2c diskimg exetool xtcspecc; do if [ ! -e ${BINDIR}/bin/${EXEC} ]; then ${CCOMPILER} ${WRKDIR}/tools/${EXEC}.c -o ${BINDIR}/bin/${EXEC} fi diff --git a/tools/diskimg.c b/tools/diskimg.c new file mode 100644 index 0000000..a6b4161 --- /dev/null +++ b/tools/diskimg.c @@ -0,0 +1,186 @@ +/** + * PROJECT: XTchain + * LICENSE: See COPYING.md in the top level directory + * FILE: tools/diskimg.c + * DESCRIPTION: Disk Image manipulation tool + * DEVELOPERS: Rafal Kupiec + */ + +#include "xtchain.h" + + +/* Loads a sector from a file */ +int LoadSector(const char *FileName, uint8_t *Buffer) +{ + FILE *File; + long Size; + + /* Open the file in binary mode */ + File= fopen(FileName, "rb"); + if(!File) + { + /* Failed to open file */ + perror("Failed to open sector file"); + return -1; + } + + /* Check the file size */ + fseek(File, 0, SEEK_END); + Size = ftell(File); + fseek(File, 0, SEEK_SET); + if(Size != SECTOR_SIZE) + { + /* File is not exactly 512 bytes */ + fprintf(stderr, "Error: file '%s' must be exactly 512 bytes.\n", FileName); + fclose(File); + return -1; + } + + /* Read sector to buffer */ + if(fread(Buffer, 1, SECTOR_SIZE, File) != SECTOR_SIZE) + { + /* Failed to read sector */ + perror("Failed to read sector from file"); + fclose(File); + return -1; + } + + /* Close the file */ + fclose(File); + return 0; +} + +/* Main function */ +int main(int argc, char **argv) +{ + FILE *File; + long DiskSizeBytes = 0; + long DiskSizeMB = 0; + MBR_PARTITION Partition = {0}; + char Zero[SECTOR_SIZE] = {0}; + uint8_t Mbr[SECTOR_SIZE] = {0}; + uint8_t Vbr[SECTOR_SIZE]; + const char *FileName = NULL; + const char *MbrFile = NULL; + const char *VbrFile = NULL; + + /* Parse command line arguments */ + for(int i = 1; i < argc; i++) + { + if(strcmp(argv[i], "-s") == 0 && i + 1 < argc) + { + /* Disk size */ + DiskSizeMB = atol(argv[++i]); + } + else if(strcmp(argv[i], "-o") == 0 && i + 1 < argc) + { + /* Output file */ + FileName = argv[++i]; + } + else if(strcmp(argv[i], "-m") == 0 && i + 1 < argc) + { + /* MBR file */ + MbrFile = argv[++i]; + } + else if(strcmp(argv[i], "-v") == 0 && i + 1 < argc) + { + /* VBR file */ + VbrFile = argv[++i]; + } + else + { + /* Unknown argument */ + fprintf(stderr, "Unknown argument: %s\n", argv[i]); + return 1; + } + } + + /* Check for required arguments */ + if(DiskSizeMB <= 0 || FileName == NULL) + { + /* Missing required arguments, print usage */ + fprintf(stderr, "Usage: %s -s -o [-m ] [-v ]\n", argv[0]); + return 1; + } + + /* Calculate disk size in bytes */ + DiskSizeBytes = DiskSizeMB * 1024 * 1024; + + /* Open the output file in binary mode */ + File = fopen(FileName, "wb"); + if(!File) { + /* Failed to open file */ + perror("Failed to open disk image file"); + return 1; + } + + /* Write zeros to the disk image file */ + for(long i = 0; i < DiskSizeBytes / SECTOR_SIZE; i++) + { + if(fwrite(Zero, 1, SECTOR_SIZE, File) != SECTOR_SIZE) + { + /* Failed to write to disk image file */ + perror("Failed to write to disk image file"); + fclose(File); + return 1; + } + } + + /* Load MBR if provided */ + if(MbrFile) + { + if(LoadSector(MbrFile, Mbr) != 0) + { + /* Failed to load MBR from file */ + perror("Failed to load MBR from file"); + fclose(File); + return 1; + } + } + + /* Setup MBR partition as W95 FAT32 */ + Partition.BootFlag = 0x80; + Partition.Type = 0x0B; + Partition.StartLBA = 2048; + Partition.Size = (DiskSizeBytes / SECTOR_SIZE) - 2048; + + /* Write MBR */ + memcpy(&Mbr[446], &Partition, sizeof(MBR_PARTITION)); + Mbr[510] = 0x55; + Mbr[511] = 0xAA; + + /* Write the MBR to the beginning of the disk image */ + fseek(File, 0, SEEK_SET); + if(fwrite(Mbr, 1, SECTOR_SIZE, File) != SECTOR_SIZE) + { + perror("Failed to write MBR to disk image"); + fclose(File); + return 1; + } + + /* Write VBR to the start of the partition, if provided */ + if(VbrFile) + { + if (LoadSector(VbrFile, Vbr) != 0) { + fclose(File); + return 1; + } + /* Seek to the start of the partition and write VBR */ + fseek(File, Partition.StartLBA * SECTOR_SIZE, SEEK_SET); + if(fwrite(Vbr, 1, SECTOR_SIZE, File) != SECTOR_SIZE) + { + /* Failed to write VBR to disk image */ + perror("Failed to write VBR to disk image"); + fclose(File); + return 1; + } + } + + fclose(File); + printf("Successfully created disk image '%s' (%ld MB) with one bootable W95 FAT32 partition%s%s.\n", + FileName, + DiskSizeMB, + MbrFile ? " with MBR from file" : "", + VbrFile ? " and VBR from file" : ""); + return 0; +} diff --git a/tools/xtchain.h b/tools/xtchain.h index 5aa9822..4266fbd 100644 --- a/tools/xtchain.h +++ b/tools/xtchain.h @@ -9,10 +9,22 @@ #include #include +#include #include #include -#define _T(x) x + +#define SECTOR_SIZE 512 +#define _T(x) x + +typedef struct MBR_PARTITION { + uint8_t BootFlag; // 0x80 = bootable, 0x00 = non-boot + uint8_t StartCHS [3]; // CHS address + uint8_t Type; // Partition type + uint8_t EndCHS[3]; // CHS address + uint32_t StartLBA; // Start sector + uint32_t Size; // Sectors count +} MBR_PARTITION, *PMBR_PARTITION; static inline @@ -52,17 +64,17 @@ split_argv(const char *argv0, char **exe_ptr) { const char *sep = _tcsrchrs(argv0, '/', '\\'); + const char *basename_ptr_const = argv0; char *dir = strdup(_T("")); - const char *basename = argv0; if(sep) { dir = strdup(argv0); dir[sep + 1 - argv0] = '\0'; - basename = sep + 1; + basename_ptr_const = sep + 1; } - basename = strdup(basename); + char *basename = strdup(basename_ptr_const); char *period = strchr(basename, '.'); if(period) @@ -72,7 +84,7 @@ split_argv(const char *argv0, char *target = strdup(basename); char *dash = strrchr(target, '-'); - const char *exe = basename; + char *exe = basename; if(dash) {