From: Christian Storm <[email protected]>

Refactor the watchdog probing in terms of
(1) renaming scan_devices() to probe_watchdogs(), and
(2) replacing the static upper-bounded PCI device enumeration
    with a dynamic one based on EFI's LocateHandleBuffer().

Signed-off-by: Christian Storm <[email protected]>
---
 main.c | 105 +++++++++++++++++++++++++++++----------------------------
 1 file changed, 54 insertions(+), 51 deletions(-)

diff --git a/main.c b/main.c
index 0bec838..b11c5fb 100644
--- a/main.c
+++ b/main.c
@@ -27,72 +27,75 @@ extern const unsigned long init_array_start[];
 extern const unsigned long init_array_end[];
 extern CHAR16 *boot_medium_path;
 
-static EFI_STATUS probe_watchdog(EFI_LOADED_IMAGE *loaded_image,
-                                EFI_PCI_IO *pci_io, UINT16 pci_vendor_id,
-                                UINT16 pci_device_id, UINTN timeout)
-{
-       const unsigned long *entry;
-
-       for (entry = init_array_start; entry < init_array_end; entry++) {
-               EFI_STATUS (*probe)(EFI_PCI_IO *, UINT16, UINT16, UINTN);
-
-               probe = loaded_image->ImageBase + *entry;
-               if (probe(pci_io, pci_vendor_id, pci_device_id, timeout) ==
-                   EFI_SUCCESS) {
-                       return EFI_SUCCESS;
-               }
-       }
+#define PCI_GET_VENDOR_ID(id) id
+#define PCI_GET_PRODUCT_ID(id) id >> 16
 
-       return EFI_UNSUPPORTED;
-}
-
-static EFI_STATUS scan_devices(EFI_LOADED_IMAGE *loaded_image, UINTN timeout)
+static EFI_STATUS probe_watchdogs(EFI_LOADED_IMAGE *loaded_image, UINTN 
timeout)
 {
-       EFI_HANDLE devices[1000];
-       UINTN count, size = sizeof(devices);
-       EFI_PCI_IO *pci_io;
-       EFI_STATUS status;
-       UINT32 value;
-
-       status = uefi_call_wrapper(BS->LocateHandle, 5, ByProtocol,
-                                  &PciIoProtocol, NULL, &size, devices);
-       if (EFI_ERROR(status)) {
-               return status;
+       if (init_array_end - init_array_start == 0) {
+               WARNING(L"No watchdog drivers registered.\n");
+               return EFI_NOT_FOUND;
        }
 
-       count = size / sizeof(EFI_HANDLE);
-       if (count == 0) {
-               return probe_watchdog(loaded_image, NULL, 0, 0, timeout);
+       UINTN handle_count = 0;
+       EFI_HANDLE *handle_buffer = NULL;
+       EFI_STATUS status = uefi_call_wrapper(BS->LocateHandleBuffer, 5,
+                                             ByProtocol, &PciIoProtocol, NULL,
+                                             &handle_count, &handle_buffer);
+       if (EFI_ERROR(status) || (handle_count == 0)) {
+               WARNING(L"No PCI I/O Protocol handles found.\n");
+               if (handle_buffer) {
+                       FreePool(handle_buffer);
+               }
+               return EFI_UNSUPPORTED;
        }
 
-       do {
-               EFI_HANDLE device = devices[count - 1];
-
-               count--;
-
-               status = uefi_call_wrapper(BS->OpenProtocol, 6, device,
-                                          &PciIoProtocol, (VOID **)&pci_io,
-                                          this_image, NULL,
-                                          EFI_OPEN_PROTOCOL_GET_PROTOCOL);
+       EFI_PCI_IO_PROTOCOL *pci_io;
+       UINT32 value;
+       for (UINTN index = 0; index < handle_count; index++) {
+               status = uefi_call_wrapper(BS->OpenProtocol, 6,
+                   handle_buffer[index], &PciIoProtocol,
+                   (VOID **)&pci_io, this_image, NULL,
+                   EFI_OPEN_PROTOCOL_BY_HANDLE_PROTOCOL);
                if (EFI_ERROR(status)) {
-                       error_exit(L"Cannot open PciIoProtocol while probing 
watchdogs",
-                                  status);
+                       ERROR(L"Cannot not open PciIoProtocol: %r\n", status);
+                       FreePool(handle_buffer);
+                       return status;
                }
 
                status = uefi_call_wrapper(pci_io->Pci.Read, 5, pci_io,
                                           EfiPciIoWidthUint32, PCI_VENDOR_ID,
                                           1, &value);
                if (EFI_ERROR(status)) {
-                       error_exit(L"Cannot read from PCI device while probing 
watchdogs",
-                                  status);
+                       WARNING(
+                           L"Cannot not read from PCI device, skipping: %r\n",
+                           status);
+                       (VOID) uefi_call_wrapper(
+                           BS->CloseProtocol, 4, handle_buffer[index],
+                           &PciIoProtocol, this_image, NULL);
+                       continue;
                }
 
-               status = probe_watchdog(loaded_image, pci_io, (UINT16)value,
-                                       value >> 16, timeout);
+               EFI_STATUS (*probe)(EFI_PCI_IO *, UINT16, UINT16, UINTN);
+               for (const unsigned long *entry = init_array_start;
+                    entry < init_array_end; entry++) {
+                       probe = loaded_image->ImageBase + *entry;
+                       if ((status = probe(pci_io, PCI_GET_VENDOR_ID(value),
+                                           PCI_GET_PRODUCT_ID(value),
+                                           timeout)) == EFI_SUCCESS) {
+                               break;
+                       }
+               }
+
+               (VOID) uefi_call_wrapper(BS->CloseProtocol, 4,
+                                        handle_buffer[index], &PciIoProtocol,
+                                        this_image, NULL);
 
-               uefi_call_wrapper(BS->CloseProtocol, 4, device, &PciIoProtocol,
-                                 this_image, NULL);
-       } while (status != EFI_SUCCESS && count > 0);
+               if (status == EFI_SUCCESS) {
+                       break;
+               }
+       }
+       FreePool(handle_buffer);
 
        return status;
 }
@@ -168,7 +171,7 @@ EFI_STATUS efi_main(EFI_HANDLE image_handle, 
EFI_SYSTEM_TABLE *system_table)
        if (bg_loader_params.timeout == 0) {
                WARNING(L"Watchdog is disabled.\n");
        } else {
-               status = scan_devices(loaded_image, bg_loader_params.timeout);
+               status = probe_watchdogs(loaded_image, 
bg_loader_params.timeout);
                if (EFI_ERROR(status)) {
                        error_exit(L"Cannot probe watchdog", status);
                }
-- 
2.33.0

-- 
You received this message because you are subscribed to the Google Groups "EFI 
Boot Guard" group.
To unsubscribe from this group and stop receiving emails from it, send an email 
to [email protected].
To view this discussion on the web visit 
https://groups.google.com/d/msgid/efibootguard-dev/20210824140714.368156-1-christian.storm%40siemens.com.

Reply via email to