:: commit deac1d7fd106e940fdb41ead006428b4f7163325

mintsuki <mintsuki@protonmail.com> — 2021-03-04 08:15

parents: 7be0b35f6f

Misc stuff

diff --git a/stage23/drivers/disk.h b/stage23/drivers/disk.h
index 4df24a71..7df6b71a 100644
--- a/stage23/drivers/disk.h
+++ b/stage23/drivers/disk.h
@@ -10,11 +10,11 @@
 
 #include <efi.h>
 
-bool disk_volume_from_efi_handle(struct volume *ret, EFI_HANDLE *efi_handle);
+struct volume *disk_volume_from_efi_handle(EFI_HANDLE *efi_handle);
 
 #endif
 
-size_t disk_create_index(struct volume **ret);
+void disk_create_index(void);
 bool disk_read_sectors(struct volume *volume, void *buf, uint64_t block, size_t count);
 
 #endif
diff --git a/stage23/drivers/disk.s2.c b/stage23/drivers/disk.s2.c
index b67b7bf1..7e347d7d 100644
--- a/stage23/drivers/disk.s2.c
+++ b/stage23/drivers/disk.s2.c
@@ -80,9 +80,8 @@ bool disk_read_sectors(struct volume *volume, void *buf, uint64_t block, size_t
     return true;
 }
 
-size_t disk_create_index(struct volume **ret) {
-    struct volume *volume_index;
-    size_t volume_count = 0, volume_index_i = 0;
+void disk_create_index(void) {
+    size_t volume_count = 0;
 
     for (uint8_t drive = 0x80; drive; drive++) {
         struct rm_regs r = {0};
@@ -104,8 +103,6 @@ size_t disk_create_index(struct volume **ret) {
         print(" ... %X total %u-byte sectors\n",
               drive_params.lba_count, drive_params.bytes_per_sect);
 
-        volume_count++;
-
         struct volume block = {0};
 
         block.drive = drive;
@@ -120,6 +117,8 @@ size_t disk_create_index(struct volume **ret) {
             continue;
         }
 
+        volume_count++;
+
         for (int part = 0; ; part++) {
             struct volume p = {0};
             int ret = part_get(&p, &block, part);
@@ -151,7 +150,7 @@ size_t disk_create_index(struct volume **ret) {
         if (r.eflags & EFLAGS_CF)
             continue;
 
-        struct volume *block = &volume_index[volume_index_i++];
+        struct volume *block = ext_mem_alloc(sizeof(struct volume));
 
         block->drive = drive;
         block->partition = -1;
@@ -165,13 +164,15 @@ size_t disk_create_index(struct volume **ret) {
             continue;
         }
 
+        volume_index[volume_index_i++] = block;
+
         if (gpt_get_guid(&block->guid, block)) {
             block->guid_valid = true;
         }
 
         for (int part = 0; ; part++) {
-            struct volume p = {0};
-            int ret = part_get(&p, block, part);
+            struct volume *p = ext_mem_alloc(sizeof(struct volume));
+            int ret = part_get(p, block, part);
 
             if (ret == END_OF_TABLE || ret == INVALID_TABLE)
                 break;
@@ -181,17 +182,14 @@ size_t disk_create_index(struct volume **ret) {
             volume_index[volume_index_i++] = p;
         }
     }
-
-    *ret = volume_index;
-    return volume_count;
 }
 
 #endif
 
 #if defined (uefi)
 
-bool disk_volume_from_efi_handle(struct volume *ret, EFI_HANDLE *efi_handle) {
-    bool ok = false;
+struct volume *disk_volume_from_efi_handle(EFI_HANDLE *efi_handle) {
+    struct volume *ret = NULL;
 
     EFI_GUID disk_io_guid = DISK_IO_PROTOCOL;
     EFI_GUID block_io_guid = BLOCK_IO_PROTOCOL;
@@ -217,20 +215,19 @@ bool disk_volume_from_efi_handle(struct volume *ret, EFI_HANDLE *efi_handle) {
         EFI_DISK_IO *cur_disk_io = NULL;
         EFI_BLOCK_IO *cur_block_io = NULL;
 
-        uefi_call_wrapper(gBS->HandleProtocol, 3, volume_index[i].drive,
+        uefi_call_wrapper(gBS->HandleProtocol, 3, volume_index[i]->efi_handle,
                           &disk_io_guid, &cur_disk_io);
-        uefi_call_wrapper(gBS->HandleProtocol, 3, volume_index[i].drive,
+        uefi_call_wrapper(gBS->HandleProtocol, 3, volume_index[i]->efi_handle,
                           &block_io_guid, &cur_block_io);
 
         uefi_call_wrapper(cur_disk_io->ReadDisk, 5, cur_disk_io,
                           cur_block_io->Media->MediaId,
                           0 +
-                          volume_index[i].first_sect * volume_index[i].sector_size,
+                          volume_index[i]->first_sect * volume_index[i]->sector_size,
                           sizeof(uint64_t), &compare);
 
         if (compare == signature) {
-            *ret = volume_index[i];
-            ok = true;
+            ret = volume_index[i];
             break;
         }
     }
@@ -238,7 +235,7 @@ bool disk_volume_from_efi_handle(struct volume *ret, EFI_HANDLE *efi_handle) {
     uefi_call_wrapper(disk_io->WriteDisk, 5, disk_io, block_io->Media->MediaId, 0,
                       sizeof(uint64_t), &orig);
 
-    return ok;
+    return ret;
 }
 
 bool disk_read_sectors(struct volume *volume, void *buf, uint64_t block, size_t count) {
@@ -247,7 +244,7 @@ bool disk_read_sectors(struct volume *volume, void *buf, uint64_t block, size_t
     EFI_GUID block_io_guid = BLOCK_IO_PROTOCOL;
     EFI_BLOCK_IO *block_io = NULL;
 
-    status = uefi_call_wrapper(gBS->HandleProtocol, 3, volume->drive,
+    status = uefi_call_wrapper(gBS->HandleProtocol, 3, volume->efi_handle,
                                &block_io_guid, &block_io);
 
     status = uefi_call_wrapper(block_io->ReadBlocks, 5, block_io,
@@ -261,11 +258,9 @@ bool disk_read_sectors(struct volume *volume, void *buf, uint64_t block, size_t
     return true;
 }
 
-size_t disk_create_index(struct volume **ret) {
+void disk_create_index(void) {
     EFI_STATUS status;
 
-    struct volume *volume_index = NULL;
-    size_t volume_index_i = 0;
     size_t volume_count = 0;
 
     EFI_GUID block_io_guid = BLOCK_IO_PROTOCOL;
@@ -296,14 +291,14 @@ size_t disk_create_index(struct volume **ret) {
 
         volume_count++;
 
-        block.drive = handles[i];
+        block.efi_handle = handles[i];
         block.sector_size = block_io->Media->BlockSize;
         block.first_sect = 0;
         block.sect_count = block_io->Media->LastBlock + 1;
 
         for (int part = 0; ; part++) {
-            struct volume p = {0};
-            int ret = part_get(&p, &block, part);
+            struct volume trash = {0};
+            int ret = part_get(&trash, &block, part);
 
             if (ret == END_OF_TABLE || ret == INVALID_TABLE)
                 break;
@@ -316,6 +311,8 @@ size_t disk_create_index(struct volume **ret) {
 
     volume_index = ext_mem_alloc(sizeof(struct volume) * volume_count);
 
+    size_t drives_counter = 0x80;
+
     for (size_t i = 0; i < handles_size / sizeof(EFI_HANDLE); i++) {
         EFI_BLOCK_IO *drive = NULL;
 
@@ -328,17 +325,20 @@ size_t disk_create_index(struct volume **ret) {
         if (drive->Media->LogicalPartition)
             continue;
 
-        struct volume *block = &volume_index[volume_index_i++];
+        struct volume *block = ext_mem_alloc(sizeof(struct volume));
 
-        block->drive = handles[i];
+        block->drive = drives_counter++;
+        block->efi_handle = handles[i];
         block->partition = -1;
         block->sector_size = drive->Media->BlockSize;
         block->first_sect = 0;
         block->sect_count = drive->Media->LastBlock + 1;
 
+        volume_index[volume_index_i++] = block;
+
         for (int part = 0; ; part++) {
-            struct volume p = {0};
-            int ret = part_get(&p, block, part);
+            struct volume *p = ext_mem_alloc(sizeof(struct volume));
+            int ret = part_get(p, block, part);
 
             if (ret == END_OF_TABLE || ret == INVALID_TABLE)
                 break;
@@ -348,9 +348,6 @@ size_t disk_create_index(struct volume **ret) {
             volume_index[volume_index_i++] = p;
         }
     }
-
-    *ret = volume_index;
-    return volume_count;
 }
 
 #endif
diff --git a/stage23/entry.s2.c b/stage23/entry.s2.c
index 6fba5037..12136efb 100644
--- a/stage23/entry.s2.c
+++ b/stage23/entry.s2.c
@@ -19,11 +19,12 @@
 #include <menu.h>
 #include <pxe/pxe.h>
 #include <pxe/tftp.h>
+#include <drivers/disk.h>
 
 extern uint64_t stage3_build_id;
 
-drive_t boot_drive;
-int     boot_partition = -1;
+int boot_drive;
+int boot_partition = -1;
 
 bool booted_from_pxe = false;
 bool booted_from_cd = false;
@@ -79,29 +80,18 @@ void entry(uint8_t _boot_drive, int boot_from) {
     init_e820();
     init_memmap();
 
-    volume_create_index();
-
-    switch (boot_from) {
-        case BOOT_FROM_HDD:
-        case BOOT_FROM_CD: {
-            struct volume boot_volume = {0};
-            volume_get_by_coord(&boot_volume, boot_drive, -1);
-            struct volume part = boot_volume;
-            for (int i = 0; ; i++) {
-                if (stage3_init(&part)) {
-                    print("Stage 3 found and loaded.\n");
-                    break;
-                }
-                int ret = part_get(&part, &boot_volume, i);
-                switch (ret) {
-                    case INVALID_TABLE:
-                    case END_OF_TABLE:
-                        panic("Stage 3 not found.");
-                }
-            }
+    disk_create_index();
+
+    struct volume *boot_volume = volume_get_by_coord(boot_drive, -1);
+
+    volume_iterate_parts(boot_volume,
+        if (stage3_init(_PART)) {
             break;
         }
-    }
+    );
+
+    if (!stage3_loaded)
+        panic("Failed to load stage 3.\n");
 
     __attribute__((noreturn))
     void (*stage3)(int boot_from) = (void *)stage3_addr;
diff --git a/stage23/entry.s3.c b/stage23/entry.s3.c
index 5fe6ec70..eab5371f 100644
--- a/stage23/entry.s3.c
+++ b/stage23/entry.s3.c
@@ -31,7 +31,7 @@ EFI_STATUS EFIAPI efi_main(EFI_HANDLE ImageHandle, EFI_SYSTEM_TABLE *SystemTable
 
     print("Limine " LIMINE_VERSION "\n\n", print);
 
-    volume_create_index();
+    disk_create_index();
 
     EFI_GUID loaded_img_prot_guid = EFI_LOADED_IMAGE_PROTOCOL_GUID;
     EFI_LOADED_IMAGE_PROTOCOL *loaded_image = NULL;
@@ -39,23 +39,54 @@ EFI_STATUS EFIAPI efi_main(EFI_HANDLE ImageHandle, EFI_SYSTEM_TABLE *SystemTable
     uefi_call_wrapper(gBS->HandleProtocol, 3, ImageHandle, &loaded_img_prot_guid,
                       &loaded_image);
 
-    struct volume boot_volume = {0};
-    if (!disk_volume_from_efi_handle(&boot_volume, loaded_image->DeviceHandle)) {
+    struct volume *boot_volume = disk_volume_from_efi_handle(loaded_image->DeviceHandle);
+    if (boot_volume == NULL) {
         panic("Can't determine boot disk");
     }
 
-    if (!volume_iterate_parts(boot_volume,
-        if (!init_config_disk(&_PART_)) {
+    if (boot_volume->backing_dev != NULL) {
+        boot_volume = boot_volume->backing_dev;
+
+        int part_cnt = 0;
+        for (size_t i = 0; ; i++) {
+            if (part_cnt > boot_volume->max_partition)
+                break;
+
+            struct volume *volume = volume_get_by_coord(boot_volume->drive, i);
+            if (volume == NULL)
+                continue;
+
+            part_cnt++;
+
+            if (!init_config_disk(volume)) {
+                print("Config file found and loaded.\n");
+                boot_partition = i;
+                boot_drive = boot_volume->drive;
+                goto config_loaded;
+            }
+        }
+
+        panic("Config file not found.");
+    } else {
+        struct volume *volume = volume_get_by_coord(boot_volume->drive, -1);
+        if (volume == NULL)
+            panic("Config file not found.");
+
+        if (!init_config_disk(volume)) {
             print("Config file found and loaded.\n");
-            boot_partition = _PARTNUM_;
-            break;
+            boot_partition = -1;
+            boot_drive = boot_volume->drive;
+            goto config_loaded;
         }
-    )) {
+
         panic("Config file not found.");
     }
 
-    for (;;);
-    //stage3_common();
+config_loaded:
+    print("Boot drive: %x\n", boot_drive);
+    print("Boot partition: %d\n", boot_partition);
+
+    stage3_common();
 }
 #endif
 
@@ -66,33 +97,20 @@ uint64_t stage3_build_id = BUILD_ID;
 __attribute__((noreturn))
 __attribute__((section(".stage3_entry")))
 void stage3_entry(int boot_from) {
+    (void)boot_from;
+
     mtrr_save();
 
-    switch (boot_from) {
-        case BOOT_FROM_HDD:
-        case BOOT_FROM_CD: {
-            struct volume boot_volume = {0};
-            volume_get_by_coord(&boot_volume, boot_drive, -1);
-
-            if (!volume_iterate_parts(boot_volume,
-                if (!init_config_disk(&_PART_)) {
-                    print("Config file found and loaded.\n");
-                    boot_partition = _PARTNUM_;
-                    break;
-                }
-            )) {
-                panic("Config file not found.");
-            }
-            break;
-        case BOOT_FROM_PXE:
-            pxe_init();
-            if (init_config_pxe()) {
-                panic("Failed to load config file");
-            }
-            print("Config loaded via PXE\n");
+    struct volume *boot_volume = volume_get_by_coord(boot_drive, -1);
+
+    volume_iterate_parts(boot_volume,
+        if (!init_config_disk(_PART)) {
+            print("Config file found and loaded.\n");
+            boot_partition = _PARTNO;
+            boot_drive = _PART->drive;
             break;
         }
-    }
+    );
 
     stage3_common();
 }
diff --git a/stage23/fs/echfs.h b/stage23/fs/echfs.h
index 92f221c9..38a684eb 100644
--- a/stage23/fs/echfs.h
+++ b/stage23/fs/echfs.h
@@ -21,7 +21,7 @@ struct echfs_dir_entry {
 } __attribute__((packed));
 
 struct echfs_file_handle {
-    struct volume part;
+    struct volume *part;
     uint64_t block_size;
     uint64_t block_count;
     uint64_t dir_length;
diff --git a/stage23/fs/echfs.s2.c b/stage23/fs/echfs.s2.c
index 4e1428b6..5c2cfeef 100644
--- a/stage23/fs/echfs.s2.c
+++ b/stage23/fs/echfs.s2.c
@@ -23,7 +23,7 @@ struct echfs_identity_table {
 #define DIR_TYPE     1
 
 static bool read_block(struct echfs_file_handle *file, void *buf, uint64_t block, uint64_t offset, uint64_t count) {
-    return volume_read(&file->part, buf, (file->alloc_map[block] * file->block_size) + offset, count);
+    return volume_read(file->part, buf, (file->alloc_map[block] * file->block_size) + offset, count);
 }
 
 int echfs_read(struct echfs_file_handle *file, void *buf, uint64_t loc, uint64_t count) {
@@ -69,10 +69,10 @@ bool echfs_get_guid(struct guid *guid, struct volume *part) {
 int echfs_open(struct echfs_file_handle *ret, struct volume *part, const char *path) {
     const char *fullpath = path;
 
-    ret->part = *part;
+    ret->part = part;
 
     struct echfs_identity_table id_table;
-    volume_read(&ret->part, &id_table, 0, sizeof(struct echfs_identity_table));
+    volume_read(ret->part, &id_table, 0, sizeof(struct echfs_identity_table));
 
     if (strncmp(id_table.signature, "_ECH_FS_", 8)) {
         print("echfs: signature invalid\n");
@@ -105,7 +105,7 @@ next:;
     }
 
     for (uint64_t i = 0; i < ret->dir_length; i += sizeof(struct echfs_dir_entry)) {
-        volume_read(&ret->part, &ret->dir_entry, i + ret->dir_offset, sizeof(struct echfs_dir_entry));
+        volume_read(ret->part, &ret->dir_entry, i + ret->dir_offset, sizeof(struct echfs_dir_entry));
 
         if (!ret->dir_entry.parent_id) {
             break;
@@ -135,7 +135,7 @@ found:;
     ret->alloc_map[0] = ret->dir_entry.payload;
     for (uint64_t i = 1; i < file_block_count; i++) {
         // Read the next block.
-        volume_read(&ret->part,
+        volume_read(ret->part,
             &ret->alloc_map[i],
             ret->alloc_table_offset + ret->alloc_map[i-1] * sizeof(uint64_t),
             sizeof(uint64_t));
diff --git a/stage23/fs/ext2.h b/stage23/fs/ext2.h
index 540c55cc..e9541a09 100644
--- a/stage23/fs/ext2.h
+++ b/stage23/fs/ext2.h
@@ -113,7 +113,7 @@ struct ext2_inode {
 } __attribute__((packed));
 
 struct ext2_file_handle {
-    struct volume part;
+    struct volume *part;
     struct ext2_superblock sb;
     int size;
     struct ext2_inode root_inode;
diff --git a/stage23/fs/ext2.s2.c b/stage23/fs/ext2.s2.c
index a809aaf4..7f429a74 100644
--- a/stage23/fs/ext2.s2.c
+++ b/stage23/fs/ext2.s2.c
@@ -138,7 +138,7 @@ static bool ext2_get_inode(struct ext2_inode *ret,
         struct ext2_bgd target_descriptor;
         const uint64_t bgd_offset = bgd_start_offset + (sizeof(struct ext2_bgd) * ino_blk_grp);
 
-        volume_read(&fd->part, &target_descriptor, bgd_offset, sizeof(struct ext2_bgd));
+        volume_read(fd->part, &target_descriptor, bgd_offset, sizeof(struct ext2_bgd));
 
         ino_offset = ((target_descriptor.bg_inode_table) * block_size) +
                                     (ino_size * ino_tbl_idx);
@@ -146,13 +146,13 @@ static bool ext2_get_inode(struct ext2_inode *ret,
         struct ext4_bgd target_descriptor;
         const uint64_t bgd_offset = bgd_start_offset + (sizeof(struct ext4_bgd) * ino_blk_grp);
 
-        volume_read(&fd->part, &target_descriptor, bgd_offset, sizeof(struct ext4_bgd));
+        volume_read(fd->part, &target_descriptor, bgd_offset, sizeof(struct ext4_bgd));
 
         ino_offset = ((target_descriptor.bg_inode_table | (bit64 ? ((uint64_t)target_descriptor.inode_id_hi << 32) : 0)) * block_size) +
                                     (ino_size * ino_tbl_idx);
     }
 
-    volume_read(&fd->part, ret, ino_offset, sizeof(struct ext2_inode));
+    volume_read(fd->part, ret, ino_offset, sizeof(struct ext2_inode));
 
     return true;
 }
@@ -184,7 +184,7 @@ static uint32_t *create_alloc_map(struct ext2_file_handle *fd,
                 }
                 uint32_t indirect_block;
                 volume_read(
-                    &fd->part, &indirect_block,
+                    fd->part, &indirect_block,
                     inode->i_blocks[13] * fd->block_size + index * sizeof(uint32_t),
                     sizeof(uint32_t)
                 );
@@ -192,7 +192,7 @@ static uint32_t *create_alloc_map(struct ext2_file_handle *fd,
                     if (i + j >= inode->i_blocks_count)
                         return alloc_map;
                     volume_read(
-                        &fd->part, &alloc_map[i + j],
+                        fd->part, &alloc_map[i + j],
                         indirect_block * fd->block_size + j * sizeof(uint32_t),
                         sizeof(uint32_t)
                     );
@@ -201,7 +201,7 @@ static uint32_t *create_alloc_map(struct ext2_file_handle *fd,
             } else {
                 // Single indirect block
                 volume_read(
-                    &fd->part, &alloc_map[i],
+                    fd->part, &alloc_map[i],
                     inode->i_blocks[12] * fd->block_size + block * sizeof(uint32_t),
                     sizeof(uint32_t)
                 );
@@ -289,9 +289,9 @@ next:
 }
 
 int ext2_open(struct ext2_file_handle *ret, struct volume *part, const char *path) {
-    ret->part = *part;
+    ret->part = part;
 
-    volume_read(&ret->part, &ret->sb, 1024, sizeof(struct ext2_superblock));
+    volume_read(ret->part, &ret->sb, 1024, sizeof(struct ext2_superblock));
 
     struct ext2_superblock *sb = &ret->sb;
 
@@ -380,7 +380,7 @@ static int inode_read(void *buf, uint64_t loc, uint64_t count,
             struct ext4_extent *ext;
             int i;
 
-            leaf = ext4_find_leaf((struct ext4_extent_header*)inode->i_blocks, block, fd->block_size, &fd->part);
+            leaf = ext4_find_leaf((struct ext4_extent_header*)inode->i_blocks, block, fd->block_size, fd->part);
 
             if (!leaf)
                 panic("invalid extent");
@@ -407,7 +407,7 @@ static int inode_read(void *buf, uint64_t loc, uint64_t count,
             block_index = alloc_map[block];
         }
 
-        volume_read(&fd->part, buf + progress, (block_index * fd->block_size) + offset, chunk);
+        volume_read(fd->part, buf + progress, (block_index * fd->block_size) + offset, chunk);
 
         progress += chunk;
     }
diff --git a/stage23/fs/fat32.h b/stage23/fs/fat32.h
index abd56adb..55f401ec 100644
--- a/stage23/fs/fat32.h
+++ b/stage23/fs/fat32.h
@@ -5,7 +5,7 @@
 #include <lib/part.h>
 
 struct fat32_context {
-    struct volume part;
+    struct volume *part;
     uint8_t sectors_per_cluster;
     uint16_t reserved_sectors;
     uint8_t number_of_fats;
diff --git a/stage23/fs/fat32.s2.c b/stage23/fs/fat32.s2.c
index 0433486a..06ffe1d2 100644
--- a/stage23/fs/fat32.s2.c
+++ b/stage23/fs/fat32.s2.c
@@ -68,10 +68,10 @@ struct fat32_lfn_entry {
 } __attribute__((packed));
 
 static int fat32_init_context(struct fat32_context* context, struct volume *part) {
-    context->part  = *part;
+    context->part = part;
 
     struct fat32_bpb bpb;
-    volume_read(&context->part, &bpb, 0, sizeof(struct fat32_bpb));
+    volume_read(context->part, &bpb, 0, sizeof(struct fat32_bpb));
 
     if (bpb.signature != FAT32_VALID_SIGNATURE_1 && bpb.signature != FAT32_VALID_SIGNATURE_2) {
         return 1;
@@ -98,7 +98,7 @@ static int fat32_read_cluster_from_map(struct fat32_context* context, uint32_t c
     const uint32_t offset = cluster % (FAT32_SECTOR_SIZE / 4);
 
     uint32_t clusters[FAT32_SECTOR_SIZE / sizeof(uint32_t)];
-    volume_read(&context->part, &clusters[0], (context->fat_start_lba + sector) * FAT32_SECTOR_SIZE, sizeof(clusters));
+    volume_read(context->part, &clusters[0], (context->fat_start_lba + sector) * FAT32_SECTOR_SIZE, sizeof(clusters));
 
     *out = clusters[offset] & 0x0FFFFFFF;
     return 0;
@@ -139,7 +139,7 @@ static bool read_cluster_chain(struct fat32_context *context,
             chunk = block_size - offset;
 
         uint64_t base = (context->data_start_lba + (cluster_chain[block] - 2)) * block_size;
-        volume_read(&context->part, buf + progress, base + offset, chunk);
+        volume_read(context->part, buf + progress, base + offset, chunk);
 
         progress += chunk;
     }
diff --git a/stage23/fs/iso9660.h b/stage23/fs/iso9660.h
index 02c5552a..2819f325 100644
--- a/stage23/fs/iso9660.h
+++ b/stage23/fs/iso9660.h
@@ -7,7 +7,7 @@
 #define ISO9660_SECTOR_SIZE (2 << 10)
 
 struct iso9660_context {
-    struct volume vol;
+    struct volume *vol;
     void* root;
     uint32_t root_size;
 };
diff --git a/stage23/fs/iso9660.s2.c b/stage23/fs/iso9660.s2.c
index c949d310..6c4086fd 100644
--- a/stage23/fs/iso9660.s2.c
+++ b/stage23/fs/iso9660.s2.c
@@ -108,14 +108,14 @@ static void iso9660_cache_root(struct volume *vol,
 static struct iso9660_context *iso9660_get_context(struct volume *vol) {
     struct iso9660_contexts_node *current = contexts;
     while (current) {
-        if (current->context.vol.drive == vol->drive)
+        if (current->context.vol == vol)
             return &current->context;
         current = current->next;
     }
 
     // The context is not cached at this point
     struct iso9660_contexts_node *node = ext_mem_alloc(sizeof(struct iso9660_contexts_node));
-    node->context.vol = *vol;
+    node->context.vol = vol;
     iso9660_cache_root(vol, &node->context.root, &node->context.root_size);
 
     node->next = contexts;
@@ -211,6 +211,6 @@ int iso9660_open(struct iso9660_file_handle *ret, struct volume *vol, const char
 }
 
 int iso9660_read(struct iso9660_file_handle *file, void *buf, uint64_t loc, uint64_t count) {
-    volume_read(&file->context->vol, buf, file->LBA * ISO9660_SECTOR_SIZE + loc, count);
+    volume_read(file->context->vol, buf, file->LBA * ISO9660_SECTOR_SIZE + loc, count);
     return 0;
 }
diff --git a/stage23/lib/blib.h b/stage23/lib/blib.h
index cedff14c..9501947a 100644
--- a/stage23/lib/blib.h
+++ b/stage23/lib/blib.h
@@ -16,8 +16,8 @@ extern EFI_BOOT_SERVICES *gBS;
 extern EFI_RUNTIME_SERVICES *gRT;
 #endif
 
-extern drive_t boot_drive;
-extern int     boot_partition;
+extern int boot_drive;
+extern int boot_partition;
 
 extern bool booted_from_pxe;
 extern bool booted_from_cd;
diff --git a/stage23/lib/part.h b/stage23/lib/part.h
index 2abaa6bd..38c26be8 100644
--- a/stage23/lib/part.h
+++ b/stage23/lib/part.h
@@ -13,57 +13,62 @@
 #define INVALID_TABLE (-2)
 #define END_OF_TABLE  (-3)
 
-#if defined (bios)
-typedef int drive_t;
-#elif defined (uefi)
-typedef EFI_HANDLE drive_t;
+struct volume {
+#if defined (uefi)
+    EFI_HANDLE efi_handle;
 #endif
 
-struct volume {
-    drive_t drive;
+    int drive;
     int partition;
     int sector_size;
+    struct volume *backing_dev;
+
+    int max_partition;
+
     int cache_status;
     uint8_t *cache;
     uint64_t cached_block;
+
     uint64_t first_sect;
     uint64_t sect_count;
+
     bool guid_valid;
     struct guid guid;
     bool part_guid_valid;
     struct guid part_guid;
 };
 
-extern struct volume *volume_index;
+extern struct volume **volume_index;
 extern size_t volume_index_i;
 
-void volume_create_index(void);
-
 bool gpt_get_guid(struct guid *guid, struct volume *volume);
 
 int part_get(struct volume *part, struct volume *volume, int partition);
-bool volume_get_by_guid(struct volume *part, struct guid *guid);
-bool volume_get_by_coord(struct volume *part, drive_t drive, int partition);
+
+struct volume *volume_get_by_guid(struct guid *guid);
+struct volume *volume_get_by_coord(int drive, int partition);
 
 bool volume_read(struct volume *part, void *buffer, uint64_t loc, uint64_t count);
 
 #define volume_iterate_parts(_VOLUME_, _BODY_) ({   \
-    bool _OK_ = true;                               \
-    struct volume _PART_ = _VOLUME_;                \
-    for (int i = 0; ; i++) {                        \
-        int _PARTNUM_ = i - 1;                      \
-        _BODY_ ;                                    \
-        switch (part_get(&_PART_, &_VOLUME_, i)) {  \
-            case INVALID_TABLE:                     \
-            case END_OF_TABLE:                      \
-                _OK_ = false;                       \
-                break;                              \
-            default:                                \
-                continue;                           \
-        }                                           \
-        break;                                      \
-    }                                               \
-    _OK_;                                           \
+    struct volume *_VOLUME = _VOLUME_;   \
+    while (_VOLUME->backing_dev != NULL) { \
+        _VOLUME = _VOLUME->backing_dev; \
+    } \
+ \
+    int _PART_CNT = -1; \
+    for (size_t _PARTNO = -1; ; _PARTNO++) { \
+        if (_PART_CNT > _VOLUME->max_partition) \
+            break; \
+ \
+        struct volume *_PART = volume_get_by_coord(_VOLUME->drive, _PARTNO); \
+        if (_PART == NULL) \
+            continue; \
+ \
+        _PART_CNT++; \
+ \
+        _BODY_ \
+    } \
 })
 
 #endif
diff --git a/stage23/lib/part.s2.c b/stage23/lib/part.s2.c
index 9450fc9c..7d918f0a 100644
--- a/stage23/lib/part.s2.c
+++ b/stage23/lib/part.s2.c
@@ -147,11 +147,15 @@ static int gpt_get_part(struct volume *ret, struct volume *volume, int partition
     if (!memcmp(&entry.unique_partition_guid, &empty_guid, sizeof(struct guid)))
         return NO_PARTITION;
 
+#if defined (uefi)
+    ret->efi_handle  = volume->efi_handle;
+#endif
     ret->drive       = volume->drive;
     ret->partition   = partition;
     ret->sector_size = sector_size;
     ret->first_sect  = entry.starting_lba;
     ret->sect_count  = (entry.ending_lba - entry.starting_lba) + 1;
+    ret->backing_dev = volume;
 
     struct guid guid;
     if (!fs_get_guid(&guid, ret)) {
@@ -200,11 +204,15 @@ static int mbr_get_logical_part(struct volume *ret, struct volume *extended_part
     if (entry.type == 0)
         return NO_PARTITION;
 
+#if defined (uefi)
+    ret->efi_handle  = extended_part->efi_handle;
+#endif
     ret->drive       = extended_part->drive;
     ret->partition   = partition + 4;
     ret->sector_size = extended_part->sector_size;
     ret->first_sect  = extended_part->first_sect + ebr_sector + entry.first_sect;
     ret->sect_count  = entry.sect_count;
+    ret->backing_dev = extended_part->backing_dev;
 
     struct guid guid;
     if (!fs_get_guid(&guid, ret)) {
@@ -239,11 +247,15 @@ static int mbr_get_part(struct volume *ret, struct volume *volume, int partition
 
             struct volume extended_part = {0};
 
+#if defined (uefi)
+            extended_part.efi_handle  = volume->efi_handle;
+#endif
             extended_part.drive       = volume->drive;
             extended_part.partition   = i;
             extended_part.sector_size = volume->sector_size;
             extended_part.first_sect  = entry.first_sect;
             extended_part.sect_count  = entry.sect_count;
+            extended_part.backing_dev = volume;
 
             return mbr_get_logical_part(ret, &extended_part, partition - 4);
         }
@@ -258,11 +270,15 @@ static int mbr_get_part(struct volume *ret, struct volume *volume, int partition
     if (entry.type == 0)
         return NO_PARTITION;
 
+#if defined (uefi)
+    ret->efi_handle  = volume->efi_handle;
+#endif
     ret->drive       = volume->drive;
     ret->partition   = partition;
     ret->sector_size = volume->sector_size;
     ret->first_sect  = entry.first_sect;
     ret->sect_count  = entry.sect_count;
+    ret->backing_dev = volume;
 
     struct guid guid;
     if (!fs_get_guid(&guid, ret)) {
@@ -291,41 +307,31 @@ int part_get(struct volume *part, struct volume *volume, int partition) {
     return INVALID_TABLE;
 }
 
-struct volume *volume_index = NULL;
+struct volume **volume_index = NULL;
 size_t volume_index_i = 0;
 
-void volume_create_index(void) {
-    volume_index_i = disk_create_index(&volume_index);
-}
-
-bool volume_get_by_guid(struct volume *part, struct guid *guid) {
-    size_t i;
-    for (i = 0; i < volume_index_i; i++) {
-        if (volume_index[i].guid_valid
-         && memcmp(&volume_index[i].guid, guid, 16) == 0) {
-            goto found;
+struct volume *volume_get_by_guid(struct guid *guid) {
+    for (size_t i = 0; i < volume_index_i; i++) {
+        if (volume_index[i]->guid_valid
+         && memcmp(&volume_index[i]->guid, guid, 16) == 0) {
+            return volume_index[i];
         }
-        if (volume_index[i].part_guid_valid
-         && memcmp(&volume_index[i].part_guid, guid, 16) == 0) {
-            goto found;
+        if (volume_index[i]->part_guid_valid
+         && memcmp(&volume_index[i]->part_guid, guid, 16) == 0) {
+            return volume_index[i];
         }
     }
-    return false;
-found:
-    *part = volume_index[i];
-    return true;
+
+    return NULL;
 }
 
-bool volume_get_by_coord(struct volume *part, drive_t drive, int partition) {
-    size_t i;
-    for (i = 0; i < volume_index_i; i++) {
-        if (volume_index[i].drive == drive
-         && volume_index[i].partition == partition) {
-            goto found;
+struct volume *volume_get_by_coord(int drive, int partition) {
+    for (size_t i = 0; i < volume_index_i; i++) {
+        if (volume_index[i]->drive == drive
+         && volume_index[i]->partition == partition) {
+            return volume_index[i];
         }
     }
-    return false;
-found:
-    *part = volume_index[i];
-    return true;
+
+    return NULL;
 }
diff --git a/stage23/lib/uri.c b/stage23/lib/uri.c
index 705de6dd..78c0cf96 100644
--- a/stage23/lib/uri.c
+++ b/stage23/lib/uri.c
@@ -95,14 +95,14 @@ static bool parse_bios_partition(char *loc, uint8_t *drive, uint8_t *partition)
 static bool uri_bios_dispatch(struct file_handle *fd, char *loc, char *path) {
     uint8_t drive, partition;
 
-    struct volume volume = {0};
     if (!parse_bios_partition(loc, &drive, &partition))
         return false;
 
-    if (!volume_get_by_coord(&volume, drive, partition))
+    struct volume *volume = volume_get_by_coord(drive, partition);
+    if (volume == NULL)
         return false;
 
-    if (fopen(fd, &volume, path))
+    if (fopen(fd, volume, path))
         return false;
 
     return true;
@@ -114,16 +114,17 @@ static bool uri_guid_dispatch(struct file_handle *fd, char *guid_str, char *path
     if (!string_to_guid_be(&guid, guid_str))
         return false;
 
-    struct volume part = {0};
-    if (!volume_get_by_guid(&part, &guid)) {
+    struct volume *volume = volume_get_by_guid(&guid);
+    if (volume == NULL) {
         if (!string_to_guid_mixed(&guid, guid_str))
             return false;
 
-        if (!volume_get_by_guid(&part, &guid))
+        volume = volume_get_by_guid(&guid);
+        if (volume == NULL)
             return false;
     }
 
-    if (fopen(fd, &part, path))
+    if (fopen(fd, volume, path))
         return false;
 
     return true;
@@ -174,11 +175,11 @@ static bool uri_boot_dispatch(struct file_handle *fd, char *s_part, char *path)
         panic("Boot partition information is unavailable.");
     }
 
-    struct volume part = {0};
-    if (!volume_get_by_coord(&part, boot_drive, partition))
+    struct volume *volume = volume_get_by_coord(boot_drive, partition);
+    if (volume == NULL)
         return false;
 
-    if (fopen(fd, &part, path))
+    if (fopen(fd, volume, path))
         return false;
 
     return true;
diff --git a/stage23/protos/chainload.c b/stage23/protos/chainload.c
index e6e2f172..f407e35d 100644
--- a/stage23/protos/chainload.c
+++ b/stage23/protos/chainload.c
@@ -77,10 +77,9 @@ void chainload(char *config) {
 
     term_deinit();
 
-    struct volume p = {0};
-    volume_get_by_coord(&p, drive, part);
+    struct volume *p = volume_get_by_coord(drive, part);
 
-    volume_read(&p, (void *)0x7c00, 0, 512);
+    volume_read(p, (void *)0x7c00, 0, 512);
 
     mtrr_restore();
 
tab: 248 wrap: offon