All checks were successful
Build documentation / build-and-deploy (push) Successful in 4m33s
233 lines
8.0 KiB
C
233 lines
8.0 KiB
C
#include <devices.h>
|
|
#include <fs_types.h>
|
|
#include <in_input.h>
|
|
#include <libfat.h>
|
|
#include <mprintf.h>
|
|
#include <process_self.h>
|
|
#include <status.h>
|
|
#include <str_status.h>
|
|
#include <strconv.h>
|
|
#include <string.h>
|
|
#include <system.h>
|
|
#include <tcursor.h>
|
|
#include <tscreen.h>
|
|
|
|
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 start_part_dos (void) {
|
|
char dev_name[64];
|
|
memset (dev_name, 0, sizeof (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;
|
|
|
|
in_stream_read_line ("Device name: ", dev_name, sizeof (dev_name));
|
|
|
|
#define prompt_partition(N) \
|
|
char p##N##_start_lba_str[12], p##N##_sector_cout_str[12]; \
|
|
uint32_t p##N##_start_lba, p##N##_sector_count; \
|
|
mprintf ("\nConfigure parition %d:\n", N); \
|
|
in_stream_read_line ("Start LBA: ", p##N##_start_lba_str, sizeof (p##N##_start_lba_str)); \
|
|
in_stream_read_line ("Sector count: ", p##N##_sector_cout_str, sizeof (p##N##_sector_cout_str)); \
|
|
p##N##_start_lba = str_to_uint32 (p##N##_start_lba_str); \
|
|
p##N##_sector_count = str_to_uint32 (p##N##_sector_cout_str);
|
|
|
|
prompt_partition (0);
|
|
prompt_partition (1);
|
|
prompt_partition (2);
|
|
prompt_partition (3);
|
|
|
|
mbr.ptes[0].start_lba = p0_start_lba;
|
|
mbr.ptes[0].sector_count = p0_sector_count;
|
|
lba_to_chs (p0_start_lba, mbr.ptes[0].chs_start_addr);
|
|
lba_to_chs (p0_start_lba + p0_sector_count - 1, mbr.ptes[0].chs_last_sect_addr);
|
|
|
|
mbr.ptes[1].start_lba = p1_start_lba;
|
|
mbr.ptes[1].sector_count = p1_sector_count;
|
|
lba_to_chs (p1_start_lba, mbr.ptes[1].chs_start_addr);
|
|
lba_to_chs (p1_start_lba + p1_sector_count - 1, mbr.ptes[1].chs_last_sect_addr);
|
|
|
|
mbr.ptes[2].start_lba = p2_start_lba;
|
|
mbr.ptes[2].sector_count = p2_sector_count;
|
|
lba_to_chs (p2_start_lba, mbr.ptes[2].chs_start_addr);
|
|
lba_to_chs (p2_start_lba + p2_sector_count - 1, mbr.ptes[2].chs_last_sect_addr);
|
|
|
|
mbr.ptes[3].start_lba = p3_start_lba;
|
|
mbr.ptes[3].sector_count = p3_sector_count;
|
|
lba_to_chs (p3_start_lba, mbr.ptes[3].chs_start_addr);
|
|
lba_to_chs (p3_start_lba + p3_sector_count - 1, mbr.ptes[3].chs_last_sect_addr);
|
|
|
|
mbr.valid_sign[0] = 0x55;
|
|
mbr.valid_sign[1] = 0xAA;
|
|
|
|
/* clang-format off */
|
|
mprintf ("\n\n-------------------------------------------------------\n");
|
|
mprintf ("Current configuration (%s):\n", dev_name);
|
|
mprintf ("Partition 0: start LBA = %u, sector count = %zu\n",mbr.ptes[0].start_lba, mbr.ptes[0].sector_count);
|
|
mprintf ("Partition 1: start LBA = %u, sector count = %zu\n",mbr.ptes[1].start_lba, mbr.ptes[1].sector_count);
|
|
mprintf ("Partition 2: start LBA = %u, sector count = %zu\n",mbr.ptes[2].start_lba, mbr.ptes[2].sector_count);
|
|
mprintf ("Partition 3: start LBA = %u, sector count = %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, sector count = %zu\n",mbr.ptes[0].start_lba, mbr.ptes[0].sector_count);
|
|
mprintf ("Partition 1: start LBA = %u, sector count = %zu\n",mbr.ptes[1].start_lba, mbr.ptes[1].sector_count);
|
|
mprintf ("Partition 2: start LBA = %u, sector count = %zu\n",mbr.ptes[2].start_lba, mbr.ptes[2].sector_count);
|
|
mprintf ("Partition 3: start LBA = %u, sector count = %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);
|
|
}
|
|
|
|
void app_main (void) {
|
|
libprocess_self_init ();
|
|
|
|
char commandbuf[32];
|
|
memset (commandbuf, 0, sizeof (commandbuf));
|
|
char devnamebuf[64];
|
|
memset (devnamebuf, 0, sizeof (devnamebuf));
|
|
|
|
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) {
|
|
start_part_dos ();
|
|
} 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 {
|
|
mprintf ("ERROR C=%s. Unknown command\n", commandbuf);
|
|
}
|
|
}
|