diff --git a/CONFIG.md b/CONFIG.md index cce17965..44bed234 100644 --- a/CONFIG.md +++ b/CONFIG.md @@ -119,9 +119,10 @@ Editor control options. * `KASLR` - For relocatable kernels, if set to `no`, disable kernel address space layout randomisation. KASLR is enabled by default. * 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. + * `DRIVE` - The 1-based drive to chainload, if omitted, assume boot drive. + * `PARTITION` - The 1-based partition to chainload, if omitted, or set to 0, chainload drive (MBR). + * `MBR_ID` - Optional. If passed, use an MBR ID (32-bit hex value) to identify the drive containing the volume to chainload. Overrides `DRIVE`, if present, but does *not* override `PARTITION`. + * `GPT_UUID` or `GPT_GUID` - Optional. If passed, use the GPT GUID to identify the drive containing the volume to chainload. Overrides `DRIVE` and `MBR_ID`, if present, but does *not* override `PARTITION`. * Chainload protocol on UEFI: * `IMAGE_PATH` - URI of the EFI application to chainload. diff --git a/common/protos/chainload.c b/common/protos/chainload.c index cf6d4cd0..eee0f681 100644 --- a/common/protos/chainload.c +++ b/common/protos/chainload.c @@ -102,6 +102,42 @@ noreturn void chainload(char *config) { struct volume *p = volume_get_by_coord(false, drive, part); + char *gpt_guid_s = config_get_value(config, 0, "GPT_GUID"); + if (gpt_guid_s == NULL) { + gpt_guid_s = config_get_value(config, 0, "GPT_UUID"); + } + if (gpt_guid_s != NULL) { + struct guid guid; + if (!string_to_guid_be(&guid, gpt_guid_s)) { + panic(true, "chainload: Malformed GUID"); + } + + p = volume_get_by_guid(&guid); + if (p == NULL) { + if (!string_to_guid_mixed(&guid, gpt_guid_s)) { + panic(true, "chainload: Malformed GUID"); + } + + p = volume_get_by_guid(&guid); + } + + if (p == NULL) { + panic(true, "chainload: No matching GPT drive for GPT_GUID found"); + } + + if (p->partition != 0) { + panic(true, "chainload: GPT_GUID is that of a partition, not a drive"); + } + + p = volume_get_by_coord(false, p->index, part); + + if (p == NULL) { + panic(true, "chainload: Partition specified is not valid"); + } + + goto load; + } + 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); @@ -118,6 +154,11 @@ noreturn void chainload(char *config) { if (mbr_id_1 == mbr_id) { p = volume_get_by_coord(false, p->index, part); + + if (p == NULL) { + panic(true, "chainload: Partition specified is not valid"); + } + goto load; } }