:: commit 9476b3dfaa35a77329686c6e1e10690c6e1a1855

mintsuki <mintsuki@protonmail.com> — 2024-05-07 17:53

parents: 1b6779303b

disk: BIOS: Use DPTE to determine removable media and BDA disk count to skip broken entries

diff --git a/common/drivers/disk.s2.c b/common/drivers/disk.s2.c
index 6678f7f8..2097fc0b 100644
--- a/common/drivers/disk.s2.c
+++ b/common/drivers/disk.s2.c
@@ -23,6 +23,21 @@
 
 #define MAX_VOLUMES 64
 
+struct dpte {
+    uint16_t io_port;
+    uint16_t control_port;
+    uint8_t head_reg_upper;
+    uint8_t bios_vendor_specific;
+    uint8_t irq_info;
+    uint8_t block_count_multiple;
+    uint8_t dma_info;
+    uint8_t pio_info;
+    uint16_t flags;
+    uint16_t reserved;
+    uint8_t revision;
+    uint8_t checksum;
+} __attribute__((packed));
+
 struct bios_drive_params {
     uint16_t buf_size;
     uint16_t info_flags;
@@ -31,7 +46,8 @@ struct bios_drive_params {
     uint32_t sects;
     uint64_t lba_count;
     uint16_t bytes_per_sect;
-    uint32_t edd;
+    uint16_t dpte_off;
+    uint16_t dpte_seg;
 } __attribute__((packed));
 
 struct dap {
@@ -127,39 +143,6 @@ int disk_read_sectors(struct volume *volume, void *buf, uint64_t block, size_t c
     return DISK_SUCCESS;
 }
 
-static int disk_write_sectors(struct volume *volume, void *buf, uint64_t block, size_t count) {
-    struct dap dap = {0};
-
-    if (count * volume->sector_size > XFER_BUF_SIZE)
-        panic(false, "XFER");
-
-    if (xfer_buf == NULL)
-        xfer_buf = conv_mem_alloc(XFER_BUF_SIZE);
-
-    dap.size    = 16;
-    dap.count   = count;
-    dap.segment = rm_seg(xfer_buf);
-    dap.offset  = rm_off(xfer_buf);
-    dap.lba     = block;
-
-    struct rm_regs r = {0};
-    r.eax = 0x4301;
-    r.edx = volume->drive;
-    r.esi = (uint32_t)rm_off(&dap);
-    r.ds  = rm_seg(&dap);
-
-    if (buf != NULL)
-        memcpy(xfer_buf, buf, count * volume->sector_size);
-
-    rm_int(0x13, &r, &r);
-
-    if (r.eflags & EFLAGS_CF) {
-        return DISK_FAILURE;
-    }
-
-    return DISK_SUCCESS;
-}
-
 static bool detect_sector_size(struct volume *volume) {
     struct dap dap = {0};
 
@@ -228,9 +211,12 @@ static bool detect_sector_size(struct volume *volume) {
 void disk_create_index(void) {
     volume_index = ext_mem_alloc(sizeof(struct volume) * MAX_VOLUMES);
 
+    // Disk count (only non-removable) at 0040:0075
+    uint8_t *bda_disk_count = (void *)rm_desegment(0x0040, 0x0075);
+
     int optical_indices = 1, hdd_indices = 1;
 
-    for (uint8_t drive = 0x80; drive < 0xf0; drive++) {
+    for (uint8_t drive = 0x80; drive != 0 /* overflow */; drive++) {
         struct rm_regs r = {0};
         struct bios_drive_params drive_params;
 
@@ -247,6 +233,23 @@ void disk_create_index(void) {
             continue;
         }
 
+        bool is_removable = drive_params.info_flags & (1 << 2);
+
+        struct dpte *dpte = NULL;
+        if (drive_params.buf_size >= 0x1e
+         && (drive_params.dpte_seg != 0x0000 || drive_params.dpte_off != 0x0000)
+         && (drive_params.dpte_seg != 0xffff || drive_params.dpte_off != 0xffff)) {
+            dpte = (void *)rm_desegment(drive_params.dpte_seg, drive_params.dpte_off);
+            if ((dpte->control_port & 0xff00) != 0xa000) {
+                // Check for removable (5) or ATAPI (6)
+                is_removable = is_removable && ((dpte->flags & (1 << 5)) || (dpte->flags & (1 << 6)));
+            }
+        }
+
+        if (!is_removable && hdd_indices > *bda_disk_count) {
+            continue;
+        }
+
         struct volume *block = ext_mem_alloc(sizeof(struct volume));
 
         block->drive = drive;
@@ -263,7 +266,7 @@ void disk_create_index(void) {
             continue;
         }
 
-        block->is_optical = disk_write_sectors(block, xfer_buf, 0, 1) != DISK_SUCCESS;
+        block->is_optical = is_removable;
 
         if (block->is_optical) {
             block->index = optical_indices++;
tab: 248 wrap: offon