#include "limine-bios-hdd.h" #include #include #include #include #include #include #include #include #include #include #include #include #include #include struct dos_pte { uint8_t drive_attrs; uint8_t chs_start_addr[3]; uint8_t part_type; uint8_t chs_last_sect_addr[3]; uint32_t start_lba; uint32_t sector_count; } __attribute__ ((packed)); struct dos_mbr { uint8_t boot_code[440]; uint8_t signature[4]; uint8_t resv[2]; struct dos_pte ptes[4]; uint8_t valid_sign[2]; } __attribute__ ((packed)); static void lba_to_chs (uint32_t lba, uint8_t chs[3]) { uint32_t sectors_per_track = 63; uint32_t heads = 255; uint32_t cylinder = lba / (heads * sectors_per_track); uint32_t head = (lba / sectors_per_track) % heads; uint32_t sector = (lba % sectors_per_track) + 1; if (cylinder > 1023) { chs[0] = 254; chs[1] = 0xFF; chs[2] = 0xFF; } else { chs[0] = (uint8_t)head; chs[1] = (uint8_t)((sector & 0x3F) | ((cylinder >> 2) & 0xC0)); chs[2] = (uint8_t)(cylinder & 0xFF); } } static void ask_and_setup_dos_partition (struct dos_pte* pte, int part_num) { char part_start_lba_str[12], part_sector_count_str[12]; uint32_t part_start_lba, part_sector_count; char part_isboot_str[4]; bool part_isboot; mprintf ("\nConfigure parition %d:\n", part_num); in_stream_read_line ("Start LBA: ", part_start_lba_str, sizeof (part_start_lba_str)); in_stream_read_line ("Sector count: ", part_sector_count_str, sizeof (part_sector_count_str)); in_stream_read_line ("Mark as bootable? [yes/no]: ", part_isboot_str, sizeof (part_isboot_str)); part_start_lba = str_to_uint32 (part_start_lba_str); part_sector_count = str_to_uint32 (part_sector_count_str); part_isboot = (strcmp (part_isboot_str, "yes") == 0); pte->start_lba = part_start_lba; pte->sector_count = part_sector_count; lba_to_chs (part_start_lba, pte->chs_start_addr); lba_to_chs (part_start_lba + (part_sector_count > 1 ? part_sector_count : 1) - 1, pte->chs_last_sect_addr); pte->part_type = 0x0C; if (part_isboot) pte->drive_attrs |= (1 << 7); } static void start_part_dos (const char* dev_name) { struct dos_mbr mbr; memset (&mbr, 0, sizeof (mbr)); char confirm_buf[4]; memset (confirm_buf, 0, sizeof (confirm_buf)); bool ok = false, write = false; ask_and_setup_dos_partition (&mbr.ptes[0], 0); ask_and_setup_dos_partition (&mbr.ptes[1], 1); ask_and_setup_dos_partition (&mbr.ptes[2], 2); ask_and_setup_dos_partition (&mbr.ptes[3], 3); struct dos_mbr* limine_mbr = (struct dos_mbr*)&binary_limine_hdd_bin_data[0]; memcpy (mbr.boot_code, limine_mbr->boot_code, sizeof (mbr.boot_code)); memcpy (mbr.signature, limine_mbr->signature, sizeof (mbr.signature)); memcpy (mbr.valid_sign, limine_mbr->valid_sign, sizeof (mbr.valid_sign)); /* clang-format off */ mprintf ("\n\n-------------------------------------------------------\n"); mprintf ("Current configuration (%s):\n", dev_name); mprintf ("Partition 0: start LBA=%u, sectors=%zu\n",mbr.ptes[0].start_lba, mbr.ptes[0].sector_count); mprintf ("Partition 1: start LBA=%u, sectors=%zu\n",mbr.ptes[1].start_lba, mbr.ptes[1].sector_count); mprintf ("Partition 2: start LBA=%u, sectors=%zu\n",mbr.ptes[2].start_lba, mbr.ptes[2].sector_count); mprintf ("Partition 3: start LBA=%u, sectors=%zu\n",mbr.ptes[3].start_lba, mbr.ptes[3].sector_count); /* clang-format on */ in_stream_read_line ("\nDoes this look plausible? [yes/no]: ", confirm_buf, sizeof (confirm_buf)); if (strcmp (confirm_buf, "yes") == 0) { in_stream_read_line ("\nWrite to device? There's no going back! [yes/no]: ", confirm_buf, sizeof (confirm_buf)); ok = true; if (strcmp (confirm_buf, "yes") == 0) { write = true; } else { mprintf ("OK. Canceling\n"); } } else { mprintf ("OK. Canceling\n"); } if (ok && write) { size_t sector = 0; size_t sector_count = 1; int r = device_do (dev_name, XDRV_WRITE, §or, §or_count, &mbr, NULL); mprintf ("Finished writing. Result: %s (%d)\n", str_status[r < 0 ? -r : r], r); } } static void list_part_dos (const char* dev_name) { struct dos_mbr mbr; memset (&mbr, 0, sizeof (mbr)); size_t sector = 0; size_t sector_count = 1; int r = device_do (dev_name, XDRV_READ, §or, §or_count, &mbr, NULL); mprintf ("Finished reading. Result: %s (%d)\n", str_status[r < 0 ? -r : r], r); if (!(mbr.valid_sign[0] == 0x55 && mbr.valid_sign[1] == 0xAA)) { mprintf ("ERROR invalid Master Boot Record!\n"); return; } /* clang-format off */ mprintf ("\n\n-------------------------------------------------------\n"); mprintf ("Summary (%s):\n", dev_name); mprintf ("Partition 0: start LBA=%u, sectors=%zu\n",mbr.ptes[0].start_lba, mbr.ptes[0].sector_count); mprintf ("Partition 1: start LBA=%u, sectors=%zu\n",mbr.ptes[1].start_lba, mbr.ptes[1].sector_count); mprintf ("Partition 2: start LBA=%u, sectors=%zu\n",mbr.ptes[2].start_lba, mbr.ptes[2].sector_count); mprintf ("Partition 3: start LBA=%u, sectors=%zu\n",mbr.ptes[3].start_lba, mbr.ptes[3].sector_count); /* clang-format on */ } static const char* spinner = "-\\|/"; static size_t spinner_state = 0; static size_t sectors_done = 0; static void format_update (size_t sector, size_t sector_count) { (void)sector; char spinner_char = spinner[(spinner_state++) % (sizeof (spinner) - 1)]; mprintf (ANSIQ_CUR_SET_COL (0) ANSIQ_SCR_CLR2LEND "%c %zu", spinner_char, sectors_done); sectors_done += sector_count; } static void format_fat32 (const char* dev_name) { mprintf ("Formatting device %s!\n", dev_name); struct fatfs_ctx ctx; memset (&ctx, 0, sizeof (ctx)); ctx.update_cb = &format_update; int r = fat_format_drive (&ctx, dev_name, FS_FAT32); mprintf ("\nFormatting done: %s (%d)\n", str_status[r < 0 ? -r : r], r); } static void format_fat16 (const char* dev_name) { mprintf ("Formatting device %s!\n", dev_name); struct fatfs_ctx ctx; memset (&ctx, 0, sizeof (ctx)); ctx.update_cb = &format_update; int r = fat_format_drive (&ctx, dev_name, FS_FAT16); mprintf ("\nFormatting done: %s (%d)\n", str_status[r < 0 ? -r : r], r); } static void install_limine_stage2 (const char* dev_name) { int r; struct dos_mbr mbr; memset (&mbr, 0, sizeof (mbr)); size_t stage2_size = sizeof (binary_limine_hdd_bin_data) - 512; size_t stage2_sectors = (stage2_size + 511) / 512; size_t mbr_lba = 0, mbr_sector_count = 1; uint64_t stage2_lba = 1; uint8_t* stage2_data = (uint8_t*)((uintptr_t)&binary_limine_hdd_bin_data[0] + 512); size_t sector = 0; size_t sector_count = 1; r = device_do (dev_name, XDRV_READ, §or, §or_count, &mbr, NULL); if (r < 0) { mprintf ("ERROR could not read MBR\n"); return; } size_t stage2_end = stage2_lba + stage2_sectors; for (size_t i = 0; i < 4; i++) { if (mbr.ptes[i].sector_count == 0) continue; if (mbr.ptes[i].start_lba < stage2_end) { mprintf ("ERROR partition overlaps with Limine stage 2 area!\n"); return; } } uint64_t stage2_loc = stage2_lba * 512; memcpy ((uint8_t*)&mbr + 0x1A4, &stage2_loc, sizeof (stage2_loc)); r = device_do (dev_name, XDRV_WRITE, &mbr_lba, &mbr_sector_count, (void*)&mbr, NULL); if (r < 0) { mprintf ("ERROR could not write patched MBR\n"); return; } r = device_do (dev_name, XDRV_WRITE, &stage2_lba, &stage2_sectors, (void*)stage2_data, NULL); mprintf ("Finished writing Limine Stage 2. Result: %s (%d)\n", str_status[r < 0 ? -r : r], r); } void app_main (void) { char commandbuf[32]; memset (commandbuf, 0, sizeof (commandbuf)); char devnamebuf[64]; memset (devnamebuf, 0, sizeof (devnamebuf)); if (env_get (process_get_pgid (), "help", (void*)commandbuf, sizeof (commandbuf)) == ST_OK) { mprintf ("sdutil -C command -dev device_key\n"); mprintf ("commands: part_dos, list_part_dos, format_fat32, format_fat16\n"); mprintf (" install_limine_stage2, partition_rescan\n"); return; } if (env_get (process_get_pgid (), "C", (void*)commandbuf, sizeof (commandbuf)) != ST_OK) { mprintf ("ERROR C=???. No command provided\n"); return; } if (strcmp (commandbuf, "part_dos") == 0) { if (env_get (process_get_pgid (), "dev", (void*)devnamebuf, sizeof (devnamebuf)) != ST_OK) { mprintf ("ERROR dev=???. No device name provided for part_dos\n"); return; } start_part_dos (devnamebuf); } else if (strcmp (commandbuf, "list_part_dos") == 0) { if (env_get (process_get_pgid (), "dev", (void*)devnamebuf, sizeof (devnamebuf)) != ST_OK) { mprintf ("ERROR dev=???. No device name provided for list_part_dos\n"); return; } list_part_dos (devnamebuf); } else if (strcmp (commandbuf, "format_fat32") == 0) { if (env_get (process_get_pgid (), "dev", (void*)devnamebuf, sizeof (devnamebuf)) != ST_OK) { mprintf ("ERROR dev=???. No device name provided for format_fat32\n"); return; } format_fat32 (devnamebuf); } else if (strcmp (commandbuf, "format_fat16") == 0) { if (env_get (process_get_pgid (), "dev", (void*)devnamebuf, sizeof (devnamebuf)) != ST_OK) { mprintf ("ERROR dev=???. No device name provided for format_fat16\n"); return; } format_fat16 (devnamebuf); } else if (strcmp (commandbuf, "install_limine_stage2") == 0) { if (env_get (process_get_pgid (), "dev", (void*)devnamebuf, sizeof (devnamebuf)) != ST_OK) { mprintf ("ERROR dev=???. No device name provided for install_limine_stage2\n"); return; } install_limine_stage2 (devnamebuf); } else if (strcmp (commandbuf, "partition_rescan") == 0) { if (env_get (process_get_pgid (), "dev", (void*)devnamebuf, sizeof (devnamebuf)) != ST_OK) { mprintf ("ERROR dev=???. No device name provided for partition_rescan\n"); return; } mprintf ("WARNING Make sure all filesystems were unmounted from this device.\n"); mprintf ("Otherwise a rescan may result in broken filesystems and crashes!\n"); device_do (devnamebuf, XDRV_PARTITION_RESCAN, NULL, NULL, NULL, NULL); } else { mprintf ("ERROR C=%s. Unknown command\n", commandbuf); } }