]> Projects (at) Tadryanom (dot) Me - AdrOS.git/commitdiff
mount: resolve partitions in boot and mount paths
authorTulio A M Mendes <[email protected]>
Sat, 6 Jun 2026 18:05:02 +0000 (15:05 -0300)
committerTulio A M Mendes <[email protected]>
Sat, 6 Jun 2026 18:05:02 +0000 (15:05 -0300)
include/ata_pio.h
include/blockdev.h
include/kernel/init.h
src/drivers/ata_pio.c
src/hal/x86/ata_pio.c
src/kernel/blockdev.c
src/kernel/init.c
src/kernel/kconsole.c
src/kernel/syscall.c
tests/test_utils.c

index 63dbeffc2575c7aa9c8bc4bfee71959cf815921d..fbb555053804a8c4b0ec25dad47e9a3500e126a9 100644 (file)
@@ -36,6 +36,7 @@ int ata_pio_read28(int drive, uint32_t lba, uint8_t* buf512);
 int ata_pio_write28(int drive, uint32_t lba, const uint8_t* buf512);
 
 uint32_t ata_pio_sector_size(void);
+uint32_t ata_pio_sector_count(int drive);
 
 /* Map device name ("hda".."hdd") to drive ID. Returns -1 if invalid. */
 int ata_name_to_drive(const char* name);
index edf38f5e98c3d01a2ee9597ae1cfdd0c29e94103..c5e9189c7a1a943bdd6ea2afd19888a32b969fe7 100644 (file)
@@ -46,6 +46,9 @@ block_device_t* blockdev_find(const char* name);
 /* Look up a block device by drive_id. Returns pointer or NULL. */
 block_device_t* blockdev_by_id(int drive_id);
 
+int blockdev_count(void);
+block_device_t* blockdev_get(int index);
+
 /* Increment block device refcount (called when filesystem mounts). */
 void blockdev_claim(block_device_t* dev);
 
index bbc1bcaaca79459db62cb47f30f883ff53053fe3..98bbff13a779150909b6f7b181a7484091ac3334 100644 (file)
@@ -16,6 +16,8 @@
 
 int init_start(const struct boot_info* bi);
 
+int init_resolve_mount_device(const char* device, struct block_device** bdev, uint32_t* lba);
+
 /* Mount a filesystem on the given block device at the given mountpoint.
  * fstype: "fat", "ext2"
  * bdev: block device (from blockdev_find or blockdev_by_id)
@@ -23,6 +25,6 @@ int init_start(const struct boot_info* bi);
  * mountpoint: e.g. "/disk", "/fat", "/ext2"
  * flags: mount flags (MS_RDONLY, etc.) — stored in VFS mount table
  * Returns 0 on success, negative errno on failure. */
-int init_mount_fs(const char* fstype, struct block_device* bdev, uint32_t lba, const char* mountpoint, unsigned long flags);
+int init_mount_fs(const char* fstype, struct block_device* bdev, uint32_t lba, const char* mountpoint, unsigned long flags, const char* source_name);
 
 #endif
index 97b5842ffa04b317f2a051199c41d339910fa6d6..ebbade6f85981029f9e1ea3810795ea973c13f4b 100644 (file)
@@ -14,6 +14,9 @@
 __attribute__((weak))
 uint32_t ata_pio_sector_size(void) { return 512; }
 
+__attribute__((weak))
+uint32_t ata_pio_sector_count(int drive) { (void)drive; return 0; }
+
 __attribute__((weak))
 int ata_pio_init(void) { return -ENOSYS; }
 
index 2d4ab22a8ff7f9c7e2c9759d5ffdcb3ddffdb2a4..ddede5ee9dc25fbbd838ead740a132b3d0a3e421 100644 (file)
@@ -46,6 +46,7 @@ static const uint8_t  ch_irq_vec[ATA_NUM_CHANNELS]    = { 46, 47 };
 
 /* Drive presence flags */
 static int drive_present[ATA_MAX_DRIVES];
+static uint32_t drive_sector_count[ATA_MAX_DRIVES];
 static int ata_pio_inited = 0;
 
 static const char* drive_names[ATA_MAX_DRIVES] = { "hda", "hdb", "hdc", "hdd" };
@@ -129,11 +130,20 @@ static int ata_probe_drive(int channel, int slave) {
     /* Wait for DRQ */
     if (ata_wait_drq(io) < 0) return 0;
 
-    /* Read and discard 256 words of identify data */
+    uint16_t identify[256];
     for (int i = 0; i < 256; i++) {
-        (void)inw((uint16_t)(io + ATA_REG_DATA));
+        identify[i] = inw((uint16_t)(io + ATA_REG_DATA));
     }
 
+    uint32_t sectors = ((uint32_t)identify[61] << 16) | identify[60];
+    if (sectors == 0) {
+        sectors = ((uint32_t)identify[103] << 16) | identify[102];
+        if (sectors == 0) {
+            sectors = ((uint32_t)identify[101] << 16) | identify[100];
+        }
+    }
+    drive_sector_count[channel * 2 + slave] = sectors;
+
     return 1;
 }
 
@@ -143,6 +153,11 @@ uint32_t ata_pio_sector_size(void) {
     return 512;
 }
 
+uint32_t ata_pio_sector_count(int drive) {
+    if (drive < 0 || drive >= ATA_MAX_DRIVES) return 0;
+    return drive_sector_count[drive];
+}
+
 int ata_pio_init(void) {
     if (ata_pio_inited) return 0;
 
@@ -158,12 +173,15 @@ int ata_pio_init(void) {
         if (st == 0xFF) {
             drive_present[ch * 2]     = 0;
             drive_present[ch * 2 + 1] = 0;
+            drive_sector_count[ch * 2] = 0;
+            drive_sector_count[ch * 2 + 1] = 0;
             continue;
         }
 
         for (int sl = 0; sl < 2; sl++) {
             int id = ch * 2 + sl;
             drive_present[id] = ata_probe_drive(ch, sl);
+            if (!drive_present[id]) drive_sector_count[id] = 0;
             if (drive_present[id]) found++;
         }
 
index 5eae1a51b4fcde373d80ed95e893ccdfb837dc40..c3561ce4cf4de95ccfcb8bad9f050676538ca7f6 100644 (file)
@@ -75,6 +75,23 @@ block_device_t* blockdev_by_id(int drive_id) {
     return result;
 }
 
+int blockdev_count(void) {
+    uintptr_t flags = spin_lock_irqsave(&g_blockdev_lock);
+    int count = g_blockdev_count;
+    spin_unlock_irqrestore(&g_blockdev_lock, flags);
+    return count;
+}
+
+block_device_t* blockdev_get(int index) {
+    uintptr_t flags = spin_lock_irqsave(&g_blockdev_lock);
+    block_device_t* result = NULL;
+    if (index >= 0 && index < g_blockdev_count) {
+        result = &g_blockdevs[index];
+    }
+    spin_unlock_irqrestore(&g_blockdev_lock, flags);
+    return result;
+}
+
 void blockdev_claim(block_device_t* dev) {
     if (!dev) return;
     uintptr_t flags = spin_lock_irqsave(&g_blockdev_lock);
@@ -113,7 +130,7 @@ void blockdev_register_ata(void) {
         memset(&bd, 0, sizeof(bd));
         strncpy(bd.name, names[i], sizeof(bd.name) - 1);
         bd.sector_size = 512;
-        bd.sector_count = 0; /* unknown */
+        bd.sector_count = ata_pio_sector_count(i);
         bd.drive_id = i;
         bd.ops = &ata_bd_ops;
         blockdev_register(&bd);
index 3c0fe7d32ebe822beecbecf2e3700220089c4c4f..f2140ad936de337320dc859a1915190f1f6e08bf 100644 (file)
 
 /* ---- Mount helper: used by fstab parser and kconsole 'mount' command ---- */
 
-int init_mount_fs(const char* fstype, block_device_t* bdev, uint32_t lba, const char* mountpoint, unsigned long flags) {
+static void init_build_mount_source_name(const char* source_name, block_device_t* bdev, char* out, size_t out_size) {
+    if (!out || out_size == 0) return;
+
+    if (source_name && source_name[0] != '\0') {
+        if (strncmp(source_name, "/dev/", 5) == 0) {
+            strncpy(out, source_name, out_size - 1);
+            out[out_size - 1] = '\0';
+            return;
+        }
+
+        strcpy(out, "/dev/");
+        char* dp = out + 5;
+        const char* sp = source_name;
+        while (*sp && (size_t)(dp - out) < out_size - 1)
+            *dp++ = *sp++;
+        *dp = '\0';
+        return;
+    }
+
+    if (!bdev) {
+        strncpy(out, "none", out_size - 1);
+        out[out_size - 1] = '\0';
+        return;
+    }
+
+    strcpy(out, "/dev/");
+    char* dp = out + 5;
+    const char* sp = bdev->name;
+    while (*sp && (size_t)(dp - out) < out_size - 1)
+        *dp++ = *sp++;
+    *dp = '\0';
+}
+
+int init_resolve_mount_device(const char* device, block_device_t** bdev, uint32_t* lba) {
+    if (!device || !bdev || !lba) return -EINVAL;
+
+    const char* devname = device;
+    if (strncmp(devname, "/dev/", 5) == 0) devname += 5;
+
+    block_device_t* resolved_bdev = blockdev_find(devname);
+    if (resolved_bdev) {
+        *bdev = resolved_bdev;
+        *lba = 0;
+        return 0;
+    }
+
+    partition_t* part = partition_find(devname);
+    if (!part || !part->parent) return -ENODEV;
+
+    *bdev = part->parent;
+    *lba = part->start_lba;
+    return 0;
+}
+
+int init_mount_fs(const char* fstype, block_device_t* bdev, uint32_t lba, const char* mountpoint, unsigned long flags, const char* source_name) {
     /* Validate mountpoint exists and is a directory */
     fs_node_t* mp_node = vfs_lookup(mountpoint);
     if (!mp_node) {
@@ -62,10 +116,13 @@ int init_mount_fs(const char* fstype, block_device_t* bdev, uint32_t lba, const
         return -EINVAL;
     }
 
+    char devname[32];
+    init_build_mount_source_name(source_name, bdev, devname, sizeof(devname));
+
     vfs_mount_result_t mres = fst->mount(bdev, lba);
     if (!mres.root) {
         kprintf("[MOUNT] Failed to mount %s on %s at %s\n",
-                fstype, bdev ? bdev->name : "?",
+                fstype, devname,
                 mountpoint);
         return -ENODEV;
     }
@@ -80,18 +137,6 @@ int init_mount_fs(const char* fstype, block_device_t* bdev, uint32_t lba, const
         blockdev_claim(bdev);
     }
 
-    /* Build device name for mount table metadata */
-    char devname[32] = "none";
-    if (bdev) {
-        strcpy(devname, "/dev/");
-        /* Append device name after /dev/ */
-        char* dp = devname + 5;
-        const char* dname = bdev->name;
-        while (*dname && (dp - devname) < (int)sizeof(devname) - 2)
-            *dp++ = *dname++;
-        *dp = '\0';
-    }
-
     int rc = vfs_mount_full(mountpoint, mres.root, fstype, devname, flags, bdev, mres.sb);
     if (rc < 0) {
         kprintf("[MOUNT] Failed to register mount at %s (err=%d)\n", mountpoint, rc);
@@ -293,10 +338,8 @@ int init_start(const struct boot_info* bi) {
 
     /* Initialize partition subsystem and scan for partitions */
     partition_init_lock();
-    for (int i = 0; i < ATA_MAX_DRIVES; i++) {
-        if (!ata_pio_drive_present(i)) continue;
-        const char* names[ATA_MAX_DRIVES] = { "hda", "hdb", "hdc", "hdd" };
-        block_device_t* bdev = blockdev_find(names[i]);
+    for (int i = 0; i < blockdev_count(); i++) {
+        block_device_t* bdev = blockdev_get(i);
         if (bdev) {
             partition_scan_mbr(bdev);
         }
@@ -312,16 +355,14 @@ int init_start(const struct boot_info* bi) {
      * has disk access.  /etc/fstab parsing is now done by /sbin/init. */
     const char* root_dev = cmdline_get("root");
     if (root_dev) {
-        const char* devname = root_dev;
-        if (strncmp(root_dev, "/dev/", 5) == 0)
-            devname = root_dev + 5;
-        block_device_t* bdev = blockdev_find(devname);
-        if (bdev) {
+        block_device_t* bdev = NULL;
+        uint32_t lba = 0;
+        if (init_resolve_mount_device(root_dev, &bdev, &lba) == 0) {
             /* Auto-detect: try ext2, then fat (non-destructive probes). */
             static const char* fstypes[] = { "ext2", "fat", NULL };
             int mounted = 0;
             for (int i = 0; fstypes[i]; i++) {
-                if (init_mount_fs(fstypes[i], bdev, 0, "/disk", 0) == 0) {
+                if (init_mount_fs(fstypes[i], bdev, lba, "/disk", 0, root_dev) == 0) {
                     kprintf("[INIT] root=%s mounted as %s on /disk\n",
                             root_dev, fstypes[i]);
                     mounted = 1;
@@ -339,7 +380,7 @@ int init_start(const struct boot_info* bi) {
         if (bdev) {
             static const char* fstypes[] = { "ext2", "fat", NULL };
             for (int i = 0; fstypes[i]; i++) {
-                if (init_mount_fs(fstypes[i], bdev, 0, "/disk", 0) == 0) {
+                if (init_mount_fs(fstypes[i], bdev, 0, "/disk", 0, "/dev/hda") == 0) {
                     kprintf("[INIT] /dev/hda auto-mounted as %s on /disk\n", fstypes[i]);
                     break;
                 }
index 01af235707ecf17f8da16a5180f4a284a1893bf8..336b0b786910c48ea411e84bbd6fbc287b996249 100644 (file)
@@ -362,18 +362,14 @@ static void kconsole_mount(const char* args) {
         return;
     }
 
-    /* Resolve device to block device */
-    const char* devname = device;
-    if (strncmp(device, "/dev/", 5) == 0) {
-        devname = device + 5;
-    }
-    block_device_t* bdev = blockdev_find(devname);
-    if (!bdev) {
+    block_device_t* bdev = NULL;
+    uint32_t lba = 0;
+    if (init_resolve_mount_device(device, &bdev, &lba) < 0) {
         kprintf("mount: unknown device: %s\n", device);
         return;
     }
 
-    (void)init_mount_fs(fstype, bdev, 0, mountpoint, 0);
+    (void)init_mount_fs(fstype, bdev, lba, mountpoint, 0, device);
 }
 
 static void kconsole_exec(const char* cmd) {
index 9c6e74e81a1389f4cb2f67f1a8437dc81bddac83..fb98c29f28c2be43570573bb115563fcbe4813f6 100644 (file)
@@ -13,6 +13,7 @@
 #include "process.h"
 #include "spinlock.h"
 #include "uaccess.h"
+#include "kernel/init.h"
 #include "blockdev.h"
 
 #include "console.h"
@@ -5290,15 +5291,14 @@ static void extended_syscall_dispatch(struct registers* regs, uint32_t syscall_n
             return;
         }
 
-        /* Disk-based: parse /dev/hdX -> block device */
-        const char* devname = kdev;
-        if (strncmp(devname, "/dev/", 5) == 0) devname += 5;
-        extern block_device_t* blockdev_find(const char* name);
-        block_device_t* bdev = blockdev_find(devname);
-        if (!bdev) { sc_ret(regs) = (uint32_t)-ENODEV; return; }
+        block_device_t* bdev = NULL;
+        uint32_t lba = 0;
+        if (init_resolve_mount_device(kdev, &bdev, &lba) < 0) {
+            sc_ret(regs) = (uint32_t)-ENODEV;
+            return;
+        }
 
-        extern int init_mount_fs(const char* fstype, const block_device_t* bdev, uint32_t lba, const char* mountpoint, unsigned long flags);
-        int rc = init_mount_fs(ktype, bdev, 0, kmp, mount_flags);
+        int rc = init_mount_fs(ktype, bdev, lba, kmp, mount_flags, kdev);
         sc_ret(regs) = (uint32_t)(rc < 0 ? rc : 0);
         return;
     }
index ea3163e98ae77e18c328f09c7d9649930b2d2614..5332f866c74de3849bfa5fec0280b135706a7fb4 100644 (file)
@@ -88,6 +88,37 @@ partition_t* partition_find_by_device(block_device_t* parent, uint8_t partition_
     return NULL;
 }
 
+static block_device_t g_test_bdev1 = {"hda", 512, 1024*1024, 0};
+static block_device_t g_test_bdev2 = {"vda", 512, 2048*1024, 1};
+
+static block_device_t* blockdev_find(const char* name) {
+    if (!name) return NULL;
+    if (strcmp(name, g_test_bdev1.name) == 0) return &g_test_bdev1;
+    if (strcmp(name, g_test_bdev2.name) == 0) return &g_test_bdev2;
+    return NULL;
+}
+
+static int init_resolve_mount_device_test(const char* device, block_device_t** bdev, uint32_t* lba) {
+    if (!device || !bdev || !lba) return -1;
+
+    const char* devname = device;
+    if (strncmp(devname, "/dev/", 5) == 0) devname += 5;
+
+    block_device_t* resolved_bdev = blockdev_find(devname);
+    if (resolved_bdev) {
+        *bdev = resolved_bdev;
+        *lba = 0;
+        return 0;
+    }
+
+    partition_t* part = partition_find(devname);
+    if (!part || !part->parent) return -1;
+
+    *bdev = part->parent;
+    *lba = part->start_lba;
+    return 0;
+}
+
 /* ---- Minimal test framework ---- */
 static int g_tests_run = 0;
 static int g_tests_passed = 0;
@@ -800,7 +831,6 @@ TEST(elf_null) {
 }
 
 /* ======== PARTITION LAYER TESTS ======== */
-static block_device_t g_test_bdev1 = {"hda", 512, 1024*1024, 0};
 
 TEST(part_register_basic) {
     partition_registry_reset();
@@ -917,6 +947,48 @@ TEST(part_claim_release) {
     ASSERT_EQ(found->refcount, 0);
 }
 
+TEST(resolve_mount_device_blockdev) {
+    partition_registry_reset();
+    block_device_t* bdev = NULL;
+    uint32_t lba = 123;
+    ASSERT_EQ(init_resolve_mount_device_test("hda", &bdev, &lba), 0);
+    ASSERT_EQ(bdev, &g_test_bdev1);
+    ASSERT_EQ(lba, 0);
+}
+
+TEST(resolve_mount_device_blockdev_devpath) {
+    partition_registry_reset();
+    block_device_t* bdev = NULL;
+    uint32_t lba = 123;
+    ASSERT_EQ(init_resolve_mount_device_test("/dev/vda", &bdev, &lba), 0);
+    ASSERT_EQ(bdev, &g_test_bdev2);
+    ASSERT_EQ(lba, 0);
+}
+
+TEST(resolve_mount_device_partition) {
+    partition_registry_reset();
+    partition_t part;
+    memset(&part, 0, sizeof(part));
+    part.parent = &g_test_bdev1;
+    part.start_lba = 2048;
+    part.partition_number = 1;
+    strcpy(part.name, "hda1");
+    partition_register(&part);
+
+    block_device_t* bdev = NULL;
+    uint32_t lba = 0;
+    ASSERT_EQ(init_resolve_mount_device_test("/dev/hda1", &bdev, &lba), 0);
+    ASSERT_EQ(bdev, &g_test_bdev1);
+    ASSERT_EQ(lba, 2048);
+}
+
+TEST(resolve_mount_device_unknown) {
+    partition_registry_reset();
+    block_device_t* bdev = NULL;
+    uint32_t lba = 0;
+    ASSERT_EQ(init_resolve_mount_device_test("/dev/doesnotexist", &bdev, &lba), -1);
+}
+
 /* ======== MAIN ======== */
 int main(void) {
     printf("\n=========================================\n");
@@ -1017,6 +1089,10 @@ int main(void) {
     RUN(part_find_by_device);
     RUN(part_find_by_device_not_found);
     RUN(part_claim_release);
+    RUN(resolve_mount_device_blockdev);
+    RUN(resolve_mount_device_blockdev_devpath);
+    RUN(resolve_mount_device_partition);
+    RUN(resolve_mount_device_unknown);
 
     printf("\n  %d/%d passed, %d failed\n", g_tests_passed, g_tests_run, g_tests_failed);