chainload: Implement MBR_ID config option. Closes #190
diff --git a/CONFIG.md b/CONFIG.md
index 7e67af72..d348bf4d 100644
--- a/CONFIG.md
+++ b/CONFIG.md
@@ -127,6 +127,7 @@ Editor control options.
* Chainload protocol on BIOS:
* `DRIVE` - The 1-based BIOS drive to chainload, if omitted, assume boot drive.
* `PARTITION` - The 1-based BIOS partition to chainload, if omitted, chainload drive (MBR).
+ * `MBR_ID` - Optional. If passed, use an MBR ID (32-bit hex value) to identify the volume to chainload.
* Chainload protocol on UEFI:
* `IMAGE_PATH` - URI of the EFI application to chainload.
diff --git a/common/lib/part.h b/common/lib/part.h
index 9de453f5..e092a17b 100644
--- a/common/lib/part.h
+++ b/common/lib/part.h
@@ -55,6 +55,7 @@ struct volume {
};
void list_volumes(void);
+bool is_valid_mbr(struct volume *volume);
extern struct volume **volume_index;
extern size_t volume_index_i;
diff --git a/common/lib/part.s2.c b/common/lib/part.s2.c
index e8befe83..eadd53e9 100644
--- a/common/lib/part.s2.c
+++ b/common/lib/part.s2.c
@@ -244,7 +244,7 @@ struct mbr_entry {
uint32_t sect_count;
} __attribute__((packed));
-static bool is_valid_mbr(struct volume *volume) {
+bool is_valid_mbr(struct volume *volume) {
// Check if actually valid mbr
uint16_t hint = 0;
volume_read(volume, &hint, 218, sizeof(uint16_t));
diff --git a/common/protos/chainload.c b/common/protos/chainload.c
index 93a4610b..354d3376 100644
--- a/common/protos/chainload.c
+++ b/common/protos/chainload.c
@@ -99,6 +99,29 @@ void chainload(char *config) {
struct volume *p = volume_get_by_coord(false, drive, part);
+ char *mbr_id_s = config_get_value(config, 0, "MBR_ID");
+ if (mbr_id_s != NULL) {
+ uint32_t mbr_id = strtoui(mbr_id_s, NULL, 16);
+
+ for (size_t i = 0; i < volume_index_i; i++) {
+ p = volume_index[i];
+
+ if (!is_valid_mbr(p)) {
+ continue;
+ }
+
+ uint32_t mbr_id_1;
+ volume_read(p, &mbr_id_1, 0x1b8, sizeof(uint32_t));
+
+ if (mbr_id_1 == mbr_id) {
+ goto load;
+ }
+ }
+
+ panic(true, "chainload: No matching MBR ID found");
+ }
+
+load:
bios_chainload_volume(p);
panic(true, "chainload: Volume is not bootable");
