:: commit 34ddbe6f147b8e1acebc5f2ea507fa7f36ffa091

mintsuki <mintsuki@protonmail.com> — 2020-12-26 19:02

parents: 0daaa565f3

part: Add support for MBR extended and logical partitions

diff --git a/CONFIG.md b/CONFIG.md
index 9d257a2e..b8ebca0b 100644
--- a/CONFIG.md
+++ b/CONFIG.md
@@ -100,8 +100,8 @@ resource://root/path
 The format for `root` changes depending on the resource used.
 
 A resource can be one of the following:
-* `boot` - The `root` is the 1-based decimal value representing the partition on the boot drive. If omitted, the partition containing the configuration file on the boot drive is used. For example: `boot://2/...` will use partition 2 of the boot drive and `boot:///...` will use the partition containing the config file on the boot drive.
-* `bios` - The `root` takes the form of `drive:partition`; for example: `bios://3:1/...` would use BIOS drive 3, partition 1. Partitions and BIOS drives are both 1-based. Omitting the drive is possible; for example: `bios://:2/...`. Omitting the drive makes Limine use the boot drive.
+* `boot` - The `root` is the 1-based decimal value representing the partition on the boot drive (values of 5+ for MBR logical partitions). If omitted, the partition containing the configuration file on the boot drive is used. For example: `boot://2/...` will use partition 2 of the boot drive and `boot:///...` will use the partition containing the config file on the boot drive.
+* `bios` - The `root` takes the form of `drive:partition`; for example: `bios://3:1/...` would use BIOS drive 3, partition 1. Partitions and BIOS drives are both 1-based (partition values of 5+ for MBR logical partitions). Omitting the drive is possible; for example: `bios://:2/...`. Omitting the drive makes Limine use the boot drive.
 * `guid` - The `root` takes the form of a GUID/UUID, such as `guid://736b5698-5ae1-4dff-be2c-ef8f44a61c52/...`. The GUID is that of either a filesystem, when available, or a GPT partition GUID, when using GPT, in a unified namespace.
 * `uuid` - Alias of `guid`.
 * `tftp` - The `root` is the IP address of the tftp server to load the file from. If the root is left empty (`tftp:///...`) the file will be loaded from the server Limine booted from. This resource is only available when booting off PXE.
diff --git a/limine-pxe.bin b/limine-pxe.bin
index e888346a..038b2693 100644
Binary files a/limine-pxe.bin and b/limine-pxe.bin differ
diff --git a/limine.bin b/limine.bin
index ef07be3c..2b3f7454 100644
Binary files a/limine.bin and b/limine.bin differ
diff --git a/stage2.map b/stage2.map
index 2fca87cc..99f8fa9e 100644
Binary files a/stage2.map and b/stage2.map differ
diff --git a/stage2/lib/part.c b/stage2/lib/part.c
index edb68b2d..1796ceb5 100644
--- a/stage2/lib/part.c
+++ b/stage2/lib/part.c
@@ -103,6 +103,55 @@ struct mbr_entry {
 	uint32_t sect_count;
 } __attribute__((packed));
 
+static int mbr_get_logical_part(struct part *ret, struct part *extended_part,
+                                int drive, int partition) {
+    struct mbr_entry entry;
+
+    size_t ebr_sector = 0;
+
+    for (int i = 0; i < partition; i++) {
+        size_t entry_offset = ebr_sector * extended_part->sector_size + 0x1ce;
+
+        int r;
+        r = part_read(extended_part, &entry, entry_offset, sizeof(struct mbr_entry));
+        if (r)
+            return r;
+
+        if (entry.type != 0x0f && entry.type != 0x05)
+            return END_OF_TABLE;
+
+        ebr_sector = entry.first_sect;
+    }
+
+    size_t entry_offset = ebr_sector * extended_part->sector_size + 0x1be;
+
+    int r;
+    r = part_read(extended_part, &entry, entry_offset, sizeof(struct mbr_entry));
+    if (r)
+        return r;
+
+    if (entry.type == 0)
+        return NO_PARTITION;
+
+    ret->drive       = drive;
+    ret->partition   = partition + 4;
+    ret->sector_size = disk_get_sector_size(drive);
+    ret->first_sect  = extended_part->first_sect + ebr_sector + entry.first_sect;
+    ret->sect_count  = entry.sect_count;
+
+    struct guid guid;
+    if (!fs_get_guid(&guid, ret)) {
+        ret->guid_valid = false;
+    } else {
+        ret->guid_valid = true;
+        ret->guid = guid;
+    }
+
+    ret->part_guid_valid = false;
+
+    return 0;
+}
+
 static int mbr_get_part(struct part *ret, int drive, int partition) {
     // Check if actually valid mbr
     uint16_t hint;
@@ -110,13 +159,33 @@ static int mbr_get_part(struct part *ret, int drive, int partition) {
     if (hint && hint != 0x5a5a)
         return INVALID_TABLE;
 
-    if (partition > 3)
-        return END_OF_TABLE;
+    struct mbr_entry entry;
 
-    uint32_t disk_signature;
-    disk_read(drive, &disk_signature, 440, sizeof(uint32_t));
+    if (partition > 3) {
+        for (int i = 0; i < 4; i++) {
+            size_t entry_offset = 0x1be + sizeof(struct mbr_entry) * i;
+
+            int r = disk_read(drive, &entry, entry_offset, sizeof(struct mbr_entry));
+            if (r)
+                return r;
+
+            if (entry.type != 0x0f)
+                continue;
+
+            struct part extended_part;
+
+            extended_part.drive       = drive;
+            extended_part.partition   = i;
+            extended_part.sector_size = disk_get_sector_size(drive);
+            extended_part.first_sect  = entry.first_sect;
+            extended_part.sect_count  = entry.sect_count;
+
+            return mbr_get_logical_part(ret, &extended_part, drive, partition - 4);
+        }
+
+        return END_OF_TABLE;
+    }
 
-    struct mbr_entry entry;
     size_t entry_offset = 0x1be + sizeof(struct mbr_entry) * partition;
 
     int r = disk_read(drive, &entry, entry_offset, sizeof(struct mbr_entry));
tab: 248 wrap: offon