]> git.ipfire.org Git - thirdparty/systemd.git/commitdiff
sd-boot: Move xbootldr code into its own file
authorJan Janssen <medhefgo@web.de>
Mon, 27 Sep 2021 08:02:50 +0000 (10:02 +0200)
committerLennart Poettering <lennart@poettering.net>
Tue, 12 Oct 2021 07:53:48 +0000 (09:53 +0200)
src/boot/efi/boot.c
src/boot/efi/meson.build
src/boot/efi/xbootldr.c [new file with mode: 0644]
src/boot/efi/xbootldr.h [new file with mode: 0644]

index 30e9516dd7be69f9069d408f443a6d7e78e5dbc0..e073217f31a65ca973b32cf7d265d08d1e054902 100644 (file)
@@ -17,6 +17,7 @@
 #include "secure-boot.h"
 #include "shim.h"
 #include "util.h"
+#include "xbootldr.h"
 
 #ifndef EFI_OS_INDICATIONS_BOOT_TO_FW_UI
 #define EFI_OS_INDICATIONS_BOOT_TO_FW_UI 0x0000000000000001ULL
@@ -2098,208 +2099,19 @@ static VOID config_entry_add_linux(
         }
 }
 
-#define XBOOTLDR_GUID \
-        &(const EFI_GUID) { 0xbc13c2ff, 0x59e6, 0x4262, { 0xa3, 0x52, 0xb2, 0x75, 0xfd, 0x6f, 0x71, 0x72 } }
-
-static EFI_DEVICE_PATH *path_parent(EFI_DEVICE_PATH *path, EFI_DEVICE_PATH *node) {
-        EFI_DEVICE_PATH *parent;
-        UINTN len;
-
-        assert(path);
-        assert(node);
-
-        len = (UINT8*) NextDevicePathNode(node) - (UINT8*) path;
-        parent = (EFI_DEVICE_PATH*) AllocatePool(len + sizeof(EFI_DEVICE_PATH));
-        CopyMem(parent, path, len);
-        CopyMem((UINT8*) parent + len, EndDevicePath, sizeof(EFI_DEVICE_PATH));
-
-        return parent;
-}
-
 static VOID config_load_xbootldr(
                 Config *config,
                 EFI_HANDLE *device) {
 
-        EFI_DEVICE_PATH *partition_path, *disk_path, *copy;
-        UINT32 found_partition_number = UINT32_MAX;
-        UINT64 found_partition_start = UINT64_MAX;
-        UINT64 found_partition_size = UINT64_MAX;
-        UINT8 found_partition_signature[16] = {};
         EFI_HANDLE new_device;
         EFI_FILE *root_dir;
-        EFI_STATUS r;
+        EFI_STATUS err;
 
         assert(config);
         assert(device);
 
-        partition_path = DevicePathFromHandle(device);
-        if (!partition_path)
-                return;
-
-        for (EFI_DEVICE_PATH *node = partition_path; !IsDevicePathEnd(node); node = NextDevicePathNode(node)) {
-                EFI_HANDLE disk_handle;
-                EFI_BLOCK_IO *block_io;
-                EFI_DEVICE_PATH *p;
-
-                /* First, Let's look for the SCSI/SATA/USB/… device path node, i.e. one above the media
-                 * devices */
-                if (DevicePathType(node) != MESSAGING_DEVICE_PATH)
-                        continue;
-
-                /* Determine the device path one level up */
-                disk_path = path_parent(partition_path, node);
-                p = disk_path;
-                r = uefi_call_wrapper(BS->LocateDevicePath, 3, &BlockIoProtocol, &p, &disk_handle);
-                if (EFI_ERROR(r))
-                        continue;
-
-                r = uefi_call_wrapper(BS->HandleProtocol, 3, disk_handle, &BlockIoProtocol, (VOID **)&block_io);
-                if (EFI_ERROR(r))
-                        continue;
-
-                /* Filter out some block devices early. (We only care about block devices that aren't
-                 * partitions themselves — we look for GPT partition tables to parse after all —, and only
-                 * those which contain a medium and have at least 2 blocks.) */
-                if (block_io->Media->LogicalPartition ||
-                    !block_io->Media->MediaPresent ||
-                    block_io->Media->LastBlock <= 1)
-                        continue;
-
-                /* Try both copies of the GPT header, in case one is corrupted */
-                for (UINTN nr = 0; nr < 2; nr++) {
-                        _cleanup_freepool_ EFI_PARTITION_ENTRY* entries = NULL;
-                        union {
-                                EFI_PARTITION_TABLE_HEADER gpt_header;
-                                uint8_t space[((sizeof(EFI_PARTITION_TABLE_HEADER) + 511) / 512) * 512];
-                        } gpt_header_buffer;
-                        EFI_PARTITION_TABLE_HEADER *h = &gpt_header_buffer.gpt_header;
-                        UINT64 where;
-                        UINTN sz;
-                        UINT32 crc32, crc32_saved;
-
-                        if (nr == 0)
-                                /* Read the first copy at LBA 1 */
-                                where = 1;
-                        else
-                                /* Read the second copy at the very last LBA of this block device */
-                                where = block_io->Media->LastBlock;
-
-                        /* Read the GPT header */
-                        r = uefi_call_wrapper(block_io->ReadBlocks, 5,
-                                              block_io,
-                                              block_io->Media->MediaId,
-                                              where,
-                                              sizeof(gpt_header_buffer), &gpt_header_buffer);
-                        if (EFI_ERROR(r))
-                                continue;
-
-                        /* Some superficial validation of the GPT header */
-                        if(CompareMem(&h->Header.Signature, "EFI PART", sizeof(h->Header.Signature) != 0))
-                                continue;
-
-                        if (h->Header.HeaderSize < 92 ||
-                            h->Header.HeaderSize > 512)
-                                continue;
-
-                        if (h->Header.Revision != 0x00010000U)
-                                continue;
-
-                        /* Calculate CRC check */
-                        crc32_saved = h->Header.CRC32;
-                        h->Header.CRC32 = 0;
-                        r = BS->CalculateCrc32(&gpt_header_buffer, h->Header.HeaderSize, &crc32);
-                        h->Header.CRC32 = crc32_saved;
-                        if (EFI_ERROR(r) || crc32 != crc32_saved)
-                                continue;
-
-                        if (h->MyLBA != where)
-                                continue;
-
-                        if (h->SizeOfPartitionEntry < sizeof(EFI_PARTITION_ENTRY))
-                                continue;
-
-                        if (h->NumberOfPartitionEntries <= 0 ||
-                            h->NumberOfPartitionEntries > 1024)
-                                continue;
-
-                        if (h->SizeOfPartitionEntry > UINTN_MAX / h->NumberOfPartitionEntries) /* overflow check */
-                                continue;
-
-                        /* Now load the GPT entry table */
-                        sz = ALIGN_TO((UINTN) h->SizeOfPartitionEntry * (UINTN) h->NumberOfPartitionEntries, 512);
-                        entries = AllocatePool(sz);
-
-                        r = uefi_call_wrapper(block_io->ReadBlocks, 5,
-                                              block_io,
-                                              block_io->Media->MediaId,
-                                              h->PartitionEntryLBA,
-                                              sz, entries);
-                        if (EFI_ERROR(r))
-                                continue;
-
-                        /* Calculate CRC of entries array, too */
-                        r = BS->CalculateCrc32(&entries, sz, &crc32);
-                        if (EFI_ERROR(r) || crc32 != h->PartitionEntryArrayCRC32)
-                                continue;
-
-                        for (UINTN i = 0; i < h->NumberOfPartitionEntries; i++) {
-                                EFI_PARTITION_ENTRY *entry;
-
-                                entry = (EFI_PARTITION_ENTRY*) ((UINT8*) entries + h->SizeOfPartitionEntry * i);
-
-                                if (CompareMem(&entry->PartitionTypeGUID, XBOOTLDR_GUID, 16) == 0) {
-                                        UINT64 end;
-
-                                        /* Let's use memcpy(), in case the structs are not aligned (they really should be though) */
-                                        CopyMem(&found_partition_start, &entry->StartingLBA, sizeof(found_partition_start));
-                                        CopyMem(&end, &entry->EndingLBA, sizeof(end));
-
-                                        if (end < found_partition_start) /* Bogus? */
-                                                continue;
-
-                                        found_partition_size = end - found_partition_start + 1;
-                                        CopyMem(found_partition_signature, &entry->UniquePartitionGUID, sizeof(found_partition_signature));
-
-                                        found_partition_number = i + 1;
-                                        goto found;
-                                }
-                        }
-
-                        break; /* This GPT was fully valid, but we didn't find what we are looking for. This
-                                * means there's no reason to check the second copy of the GPT header */
-                }
-        }
-
-        return; /* Not found */
-
-found:
-        copy = DuplicateDevicePath(partition_path);
-
-        /* Patch in the data we found */
-        for (EFI_DEVICE_PATH *node = copy; !IsDevicePathEnd(node); node = NextDevicePathNode(node)) {
-                HARDDRIVE_DEVICE_PATH *hd;
-
-                if (DevicePathType(node) != MEDIA_DEVICE_PATH)
-                        continue;
-
-                if (DevicePathSubType(node) != MEDIA_HARDDRIVE_DP)
-                        continue;
-
-                hd = (HARDDRIVE_DEVICE_PATH*) node;
-                hd->PartitionNumber = found_partition_number;
-                hd->PartitionStart = found_partition_start;
-                hd->PartitionSize = found_partition_size;
-                CopyMem(hd->Signature, found_partition_signature, sizeof(hd->Signature));
-                hd->MBRType = MBR_TYPE_EFI_PARTITION_TABLE_HEADER;
-                hd->SignatureType = SIGNATURE_TYPE_GUID;
-        }
-
-        r = uefi_call_wrapper(BS->LocateDevicePath, 3, &BlockIoProtocol, &copy, &new_device);
-        if (EFI_ERROR(r))
-                return;
-
-        root_dir = LibOpenRoot(new_device);
-        if (!root_dir)
+        err = xbootldr_open(device, &new_device, &root_dir);
+        if (EFI_ERROR(err))
                 return;
 
         config_entry_add_linux(config, new_device, root_dir);
index f1374a964a70f8569c4f7a48db16fe37cb6f17b2..cf3d3e60798be5ed8e0102aee66ec1cfe70e9a6d 100644 (file)
@@ -15,6 +15,7 @@ efi_headers = files('''
         shim.h
         splash.h
         util.h
+        xbootldr.h
 '''.split())
 
 common_sources = '''
@@ -34,6 +35,7 @@ systemd_boot_sources = '''
         drivers.c
         random-seed.c
         shim.c
+        xbootldr.c
 '''.split()
 
 stub_sources = '''
diff --git a/src/boot/efi/xbootldr.c b/src/boot/efi/xbootldr.c
new file mode 100644 (file)
index 0000000..5ae2053
--- /dev/null
@@ -0,0 +1,212 @@
+/* SPDX-License-Identifier: LGPL-2.1-or-later */
+
+#include <efi.h>
+#include <efigpt.h>
+#include <efilib.h>
+
+#include "util.h"
+#include "xbootldr.h"
+
+static EFI_DEVICE_PATH *path_parent(EFI_DEVICE_PATH *path, EFI_DEVICE_PATH *node) {
+        EFI_DEVICE_PATH *parent;
+        UINTN len;
+
+        assert(path);
+        assert(node);
+
+        len = (UINT8*) NextDevicePathNode(node) - (UINT8*) path;
+        parent = (EFI_DEVICE_PATH*) AllocatePool(len + sizeof(EFI_DEVICE_PATH));
+        CopyMem(parent, path, len);
+        CopyMem((UINT8*) parent + len, EndDevicePath, sizeof(EFI_DEVICE_PATH));
+
+        return parent;
+}
+
+EFI_STATUS xbootldr_open(EFI_HANDLE *device, EFI_HANDLE *ret_device, EFI_FILE **ret_root_dir) {
+        EFI_DEVICE_PATH *partition_path, *disk_path, *copy;
+        UINT32 found_partition_number = UINT32_MAX;
+        UINT64 found_partition_start = UINT64_MAX;
+        UINT64 found_partition_size = UINT64_MAX;
+        UINT8 found_partition_signature[16] = {};
+        EFI_HANDLE new_device;
+        EFI_FILE *root_dir;
+        EFI_STATUS r;
+
+        assert(device);
+        assert(ret_device);
+        assert(ret_root_dir);
+
+        partition_path = DevicePathFromHandle(device);
+        if (!partition_path)
+                return EFI_NOT_FOUND;
+
+        for (EFI_DEVICE_PATH *node = partition_path; !IsDevicePathEnd(node); node = NextDevicePathNode(node)) {
+                EFI_HANDLE disk_handle;
+                EFI_BLOCK_IO *block_io;
+                EFI_DEVICE_PATH *p;
+
+                /* First, Let's look for the SCSI/SATA/USB/… device path node, i.e. one above the media
+                 * devices */
+                if (DevicePathType(node) != MESSAGING_DEVICE_PATH)
+                        continue;
+
+                /* Determine the device path one level up */
+                disk_path = path_parent(partition_path, node);
+                p = disk_path;
+                r = uefi_call_wrapper(BS->LocateDevicePath, 3, &BlockIoProtocol, &p, &disk_handle);
+                if (EFI_ERROR(r))
+                        continue;
+
+                r = uefi_call_wrapper(BS->HandleProtocol, 3, disk_handle, &BlockIoProtocol, (VOID **)&block_io);
+                if (EFI_ERROR(r))
+                        continue;
+
+                /* Filter out some block devices early. (We only care about block devices that aren't
+                 * partitions themselves — we look for GPT partition tables to parse after all —, and only
+                 * those which contain a medium and have at least 2 blocks.) */
+                if (block_io->Media->LogicalPartition ||
+                    !block_io->Media->MediaPresent ||
+                    block_io->Media->LastBlock <= 1)
+                        continue;
+
+                /* Try both copies of the GPT header, in case one is corrupted */
+                for (UINTN nr = 0; nr < 2; nr++) {
+                        _cleanup_freepool_ EFI_PARTITION_ENTRY* entries = NULL;
+                        union {
+                                EFI_PARTITION_TABLE_HEADER gpt_header;
+                                uint8_t space[((sizeof(EFI_PARTITION_TABLE_HEADER) + 511) / 512) * 512];
+                        } gpt_header_buffer;
+                        EFI_PARTITION_TABLE_HEADER *h = &gpt_header_buffer.gpt_header;
+                        UINT64 where;
+                        UINTN sz;
+                        UINT32 crc32, crc32_saved;
+
+                        if (nr == 0)
+                                /* Read the first copy at LBA 1 */
+                                where = 1;
+                        else
+                                /* Read the second copy at the very last LBA of this block device */
+                                where = block_io->Media->LastBlock;
+
+                        /* Read the GPT header */
+                        r = uefi_call_wrapper(block_io->ReadBlocks, 5,
+                                              block_io,
+                                              block_io->Media->MediaId,
+                                              where,
+                                              sizeof(gpt_header_buffer), &gpt_header_buffer);
+                        if (EFI_ERROR(r))
+                                continue;
+
+                        /* Some superficial validation of the GPT header */
+                        if(CompareMem(&h->Header.Signature, "EFI PART", sizeof(h->Header.Signature) != 0))
+                                continue;
+
+                        if (h->Header.HeaderSize < 92 ||
+                            h->Header.HeaderSize > 512)
+                                continue;
+
+                        if (h->Header.Revision != 0x00010000U)
+                                continue;
+
+                        /* Calculate CRC check */
+                        crc32_saved = h->Header.CRC32;
+                        h->Header.CRC32 = 0;
+                        r = BS->CalculateCrc32(&gpt_header_buffer, h->Header.HeaderSize, &crc32);
+                        h->Header.CRC32 = crc32_saved;
+                        if (EFI_ERROR(r) || crc32 != crc32_saved)
+                                continue;
+
+                        if (h->MyLBA != where)
+                                continue;
+
+                        if (h->SizeOfPartitionEntry < sizeof(EFI_PARTITION_ENTRY))
+                                continue;
+
+                        if (h->NumberOfPartitionEntries <= 0 ||
+                            h->NumberOfPartitionEntries > 1024)
+                                continue;
+
+                        if (h->SizeOfPartitionEntry > UINTN_MAX / h->NumberOfPartitionEntries) /* overflow check */
+                                continue;
+
+                        /* Now load the GPT entry table */
+                        sz = ALIGN_TO((UINTN) h->SizeOfPartitionEntry * (UINTN) h->NumberOfPartitionEntries, 512);
+                        entries = AllocatePool(sz);
+
+                        r = uefi_call_wrapper(block_io->ReadBlocks, 5,
+                                              block_io,
+                                              block_io->Media->MediaId,
+                                              h->PartitionEntryLBA,
+                                              sz, entries);
+                        if (EFI_ERROR(r))
+                                continue;
+
+                        /* Calculate CRC of entries array, too */
+                        r = BS->CalculateCrc32(&entries, sz, &crc32);
+                        if (EFI_ERROR(r) || crc32 != h->PartitionEntryArrayCRC32)
+                                continue;
+
+                        for (UINTN i = 0; i < h->NumberOfPartitionEntries; i++) {
+                                EFI_PARTITION_ENTRY *entry;
+
+                                entry = (EFI_PARTITION_ENTRY*) ((UINT8*) entries + h->SizeOfPartitionEntry * i);
+
+                                if (CompareMem(&entry->PartitionTypeGUID, XBOOTLDR_GUID, 16) == 0) {
+                                        UINT64 end;
+
+                                        /* Let's use memcpy(), in case the structs are not aligned (they really should be though) */
+                                        CopyMem(&found_partition_start, &entry->StartingLBA, sizeof(found_partition_start));
+                                        CopyMem(&end, &entry->EndingLBA, sizeof(end));
+
+                                        if (end < found_partition_start) /* Bogus? */
+                                                continue;
+
+                                        found_partition_size = end - found_partition_start + 1;
+                                        CopyMem(found_partition_signature, &entry->UniquePartitionGUID, sizeof(found_partition_signature));
+
+                                        found_partition_number = i + 1;
+                                        goto found;
+                                }
+                        }
+
+                        break; /* This GPT was fully valid, but we didn't find what we are looking for. This
+                                * means there's no reason to check the second copy of the GPT header */
+                }
+        }
+
+        return EFI_NOT_FOUND;
+
+found:
+        copy = DuplicateDevicePath(partition_path);
+
+        /* Patch in the data we found */
+        for (EFI_DEVICE_PATH *node = copy; !IsDevicePathEnd(node); node = NextDevicePathNode(node)) {
+                HARDDRIVE_DEVICE_PATH *hd;
+
+                if (DevicePathType(node) != MEDIA_DEVICE_PATH)
+                        continue;
+
+                if (DevicePathSubType(node) != MEDIA_HARDDRIVE_DP)
+                        continue;
+
+                hd = (HARDDRIVE_DEVICE_PATH*) node;
+                hd->PartitionNumber = found_partition_number;
+                hd->PartitionStart = found_partition_start;
+                hd->PartitionSize = found_partition_size;
+                CopyMem(hd->Signature, found_partition_signature, sizeof(hd->Signature));
+                hd->MBRType = MBR_TYPE_EFI_PARTITION_TABLE_HEADER;
+                hd->SignatureType = SIGNATURE_TYPE_GUID;
+        }
+
+        r = uefi_call_wrapper(BS->LocateDevicePath, 3, &BlockIoProtocol, &copy, &new_device);
+        if (EFI_ERROR(r))
+                return r;
+
+        root_dir = LibOpenRoot(new_device);
+        if (!root_dir)
+                return EFI_DEVICE_ERROR;
+
+        *ret_device = new_device;
+        *ret_root_dir = root_dir;
+        return EFI_SUCCESS;
+}
diff --git a/src/boot/efi/xbootldr.h b/src/boot/efi/xbootldr.h
new file mode 100644 (file)
index 0000000..4cb370a
--- /dev/null
@@ -0,0 +1,8 @@
+/* SPDX-License-Identifier: LGPL-2.1-or-later */
+
+#include <efi.h>
+
+#define XBOOTLDR_GUID \
+        &(const EFI_GUID) { 0xbc13c2ff, 0x59e6, 0x4262, { 0xa3, 0x52, 0xb2, 0x75, 0xfd, 0x6f, 0x71, 0x72 } }
+
+EFI_STATUS xbootldr_open(EFI_HANDLE *device, EFI_HANDLE *ret_device, EFI_FILE **ret_root_dir);