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));
