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);
/* 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);
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)
* 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
__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; }
/* 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" };
/* 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;
}
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;
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++;
}
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);
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);
/* ---- 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) {
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;
}
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);
/* 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);
}
* 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;
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;
}
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) {
#include "process.h"
#include "spinlock.h"
#include "uaccess.h"
+#include "kernel/init.h"
#include "blockdev.h"
#include "console.h"
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;
}
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;
}
/* ======== PARTITION LAYER TESTS ======== */
-static block_device_t g_test_bdev1 = {"hda", 512, 1024*1024, 0};
TEST(part_register_basic) {
partition_registry_reset();
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");
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);