title: Most UEFI protocols are reported as "unsupported"
body: <p>I'm writing an EFI executable on a SoC device (Up Board) to help us automate BIOS updates and PXE boots for installating our software on numerous devices.</p>
  
  <p>The problem I have is that seemingly most of the protocols in the specification are "unsupported" on this platform, even basic file system tasks. The only one I've successfully used is the LOADED_IMAGE_PROTOCOL. I'm using gnu-efi to compile the code, basing my code to this example <a href="https://mjg59.dreamwidth.org/18773.html" rel="nofollow noreferrer">https://mjg59.dreamwidth.org/18773.html</a>. Is there something I'm doing wrong, or is this simply the firmware absolutely not implementing any of the protocols?</p>
  
  <p>The American Megatrends utility "AfuEfix64.efi" is capable of retrieving BIOS information, and the SoC BIOS updates are done using an Intel's EFI executable. Both are closed source, unfortunately. My initial idea would have been to write a script that parses the output from these executables, but I don't think the EFI shell has much features for this type of tasks, so I moved on to writing an EFI executable to perform this.</p>
  
  <p>Minimal code showing this:</p>
  
  <pre><code>#include &lt;efi.h&gt;
  #include &lt;efilib.h&gt;
  #include &lt;x86_64/efibind.h&gt;
  
  // gnu-efi does not currently define firmware management
  // https://raw.githubusercontent.com/tianocore/edk2/master/MdePkg/Include/Protocol/FirmwareManagement.h
  #include "efifirmware.h"
  
  // gnu-efi does not currently define this
  #define EFI_LOAD_FILE2_PROTOCOL_GUID \
  { 0x4006c0c1, 0xfcb3, 0x403e, \
  { 0x99, 0x6d, 0x4a, 0x6c, 0x87, 0x24, 0xe0, 0x6d }}
  typedef EFI_LOAD_FILE_PROTOCOL EFI_LOAD_FILE2_PROTOCOL;
  
  void tryProtocol(EFI_GUID proto_guid, void** out, const CHAR16* name,
      EFI_HANDLE imageHandle, EFI_SYSTEM_TABLE* systemTable) {
  
      EFI_STATUS status;
      status = uefi_call_wrapper(systemTable-&gt;BootServices-&gt;HandleProtocol, 3,
          imageHandle, &amp;proto_guid, out);
  
      if (EFI_ERROR(status)) {
          Print(L"HandleProtocol error for %s: %r\n", name, status);
      } else {
          Print(L"Protocol %s is supported\n", name);
      }
  }
  
  void tryProtocols(EFI_HANDLE imgh, EFI_SYSTEM_TABLE* syst) {
      EFI_LOADED_IMAGE* loaded_image = NULL;
      EFI_GUID guid_imgprot = LOADED_IMAGE_PROTOCOL;
      tryProtocol(guid_imgprot, (void**)&amp;loaded_image,
          L"LOADED_IMAGE_PROTOCOL", imgh, syst);
  
      Print(L"Image base: %lx\n", loaded_image-&gt;ImageBase);
      Print(L"Image size: %lx\n", loaded_image-&gt;ImageSize);
      Print(L"Image file: %s\n", DevicePathToStr(loaded_image-&gt;FilePath));
  
      EFI_FIRMWARE_MANAGEMENT_PROTOCOL* fw_manage = NULL;
      EFI_GUID guid_fwman_prot = EFI_FIRMWARE_MANAGEMENT_PROTOCOL_GUID;
      tryProtocol(guid_fwman_prot, (void**)&amp;fw_manage,
          L"FIRMWARE_MANAGEMENT_PROTOCOL", imgh, syst);
  
      EFI_LOAD_FILE_PROTOCOL* load_file = NULL;
      EFI_GUID guid_loadf_prot = EFI_LOAD_FILE_PROTOCOL_GUID;
      tryProtocol(guid_loadf_prot, (void**)&amp;load_file,
          L"LOAD_FILE_PROTOCOL", imgh, syst);
  
      EFI_LOAD_FILE2_PROTOCOL* load_file2 = NULL;
      EFI_GUID guid_loadf2_prot = EFI_LOAD_FILE2_PROTOCOL_GUID;
      tryProtocol(guid_loadf2_prot, (void**)&amp;load_file2,
          L"LOAD_FILE2_PROTOCOL", imgh, syst);
  
      EFI_SIMPLE_FILE_SYSTEM_PROTOCOL* simple_fs = NULL;
      EFI_GUID guid_simple_fs_prot = EFI_SIMPLE_FILE_SYSTEM_PROTOCOL_GUID;
      tryProtocol(guid_simple_fs_prot, (void**)&amp;simple_fs,
          L"SIMPLE_FILE_SYSTEM_PROTOCOL", imgh, syst);
  
      EFI_DISK_IO_PROTOCOL* disk = NULL;
      EFI_GUID guid_disk_io_prot = EFI_DISK_IO_PROTOCOL_GUID;
      tryProtocol(guid_disk_io_prot, (void**)&amp;disk,
          L"DISK_IO_PROTOCOL", imgh, syst);
  
      EFI_BLOCK_IO_PROTOCOL* block = NULL;
      EFI_GUID guid_block_io_prot = EFI_BLOCK_IO_PROTOCOL_GUID;
      tryProtocol(guid_block_io_prot, (void**)&amp;block,
          L"BLOCK_IO_PROTOCOL", imgh, syst);
  }
  
  EFI_STATUS
  EFIAPI
  efi_main (EFI_HANDLE imageHandle, EFI_SYSTEM_TABLE* systemTable) {
      InitializeLib(imageHandle, systemTable);
      Print(L"Image loaded\n");
  
      tryProtocols(imageHandle, systemTable);
  
      return EFI_SUCCESS;
  }
  </code></pre>
  
  <p>Here's the output for running it:</p>
  
  <pre><code>EFI Shell version 2.40 [5.11]
  Current running mode 1.1.2
  Device mapping table
    fs0  :HardDisk - Alias hd6b blk0
          PciRoot(0x0)/Pci(0x10,0x0)/Ctrl(0x0)/HD(1,GPT,2DCDDADD-8F3A-4A77-94A9-010A8C700BB8,0x800,0x100000)
    fs1  :Removable HardDisk - Alias hd9g0a0b blk1
          PciRoot(0x0)/Pci(0x14,0x0)/USB(0x6,0x0)/USB(0x0,0x0)/HD(1,MBR,0x528E6A1F,0x800,0x1CDE800)
    blk0 :HardDisk - Alias hd6b fs0
          PciRoot(0x0)/Pci(0x10,0x0)/Ctrl(0x0)/HD(1,GPT,2DCDDADD-8F3A-4A77-94A9-010A8C700BB8,0x800,0x100000)
    blk1 :Removable HardDisk - Alias hd9g0a0b fs1
          PciRoot(0x0)/Pci(0x14,0x0)/USB(0x6,0x0)/USB(0x0,0x0)/HD(1,MBR,0x528E6A1F,0x800,0x1CDE800)
    blk2 :HardDisk - Alias (null)
          PciRoot(0x0)/Pci(0x10,0x0)/Ctrl(0x0)/HD(2,GPT,8AC0F94E-3CA2-4C03-BE00-3A69721CC391,0x100800,0x1C1F7DF)
    blk3 :BlockDevice - Alias (null)
          PciRoot(0x0)/Pci(0x10,0x0)/Ctrl(0x0)
    blk4 :BlockDevice - Alias (null)
          PciRoot(0x0)/Pci(0x10,0x0)/Ctrl(0x1)
    blk5 :BlockDevice - Alias (null)
          PciRoot(0x0)/Pci(0x10,0x0)/Ctrl(0x2)
    blk6 :Removable BlockDevice - Alias (null)
          PciRoot(0x0)/Pci(0x14,0x0)/USB(0x6,0x0)/USB(0x0,0x0)
  
  Press ESC in 4 seconds to skip startup.nsh, any other key to continue.
  
  fs1:\&gt; tryprotocols.efi
  Image loaded
  Protocol LOADED_IMAGE_PROTOCOL is supported
  Image base: 55BA6000
  Image size: F000
  Image file: \/tryprotocols.efi
  HandleProtocol error for FIRMWARE_MANAGEMENT_PROTOCOL: Unsupported
  HandleProtocol error for LOAD_FILE_PROTOCOL: Unsupported
  HandleProtocol error for LOAD_FILE2_PROTOCOL: Unsupported
  HandleProtocol error for SIMPLE_FILE_SYSTEM_PROTOCOL: Unsupported
  HandleProtocol error for DISK_IO_PROTOCOL: Unsupported
  HandleProtocol error for BLOCK_IO_PROTOCOL: Unsupported
  
  fs1:\&gt;
  </code></pre>
  
  <p>And here's the Makefile I use to compile it:</p>
  
  <pre><code>ARCH=x86_64
  OBJS=tryprotocols.o
  TARGET=tryprotocols.efi
  TARGET_SO=$(TARGET:.efi=.so)
  GNUEFIDIR=/home/gekko/gnu-efi-3.0.8
  EFIINC=$(GNUEFIDIR)/inc
  EFIINCS=-I$(EFIINC) -I$(EFIINC)/$(ARCH) -I$(EFIINC)/protocol
  LIB=$(GNUEFIDIR)/$(ARCH)/lib
  EFILIB=$(GNUEFIDIR)/gnuefi
  EFI_CRT_OBJS=$(GNUEFIDIR)/$(ARCH)/gnuefi/crt0-efi-$(ARCH).o
  EFI_LDS=$(EFILIB)/elf_$(ARCH)_efi.lds
  
  CFLAGS=$(EFIINCS) -fno-stack-protector -fpic \
      -fshort-wchar -mno-red-zone -Wall
  
  ifeq ($(ARCH),x86_64)
      CFLAGS += -DEFI_FUNCTION_WRAPPER
  endif
  
  LDFLAGS=-nostdlib -znocombreloc -T $(EFI_LDS) -shared \
      -Bsymbolic -L $(EFILIB) -L $(LIB) $(EFI_CRT_OBJS)
  
  all: $(TARGET)
  
  $(TARGET_SO): $(OBJS)
      ld $(LDFLAGS) $(OBJS) -o $@ -lefi -lgnuefi
  
  %.efi: %.so
      objcopy -j .text -j .sdata -j .data -j .dynamic \
      -j .dynsym  -j .rel -j .rela -j .reloc \
      --target=efi-app-$(ARCH) $^ $@
  
  clean:
      rm -f *.o
      rm -f $(TARGET)
      rm -f $(TARGET_SO)
  </code></pre>
  
  <p>EDIT: Modified version that properly uses LocateProtocol() to find the protocols, and uses them to open and close a file.</p>
  
  <pre><code>#include &lt;efi.h&gt;
  #include &lt;efilib.h&gt;
  #include &lt;x86_64/efibind.h&gt;
  
  BOOLEAN tryProtocol(EFI_GUID proto_guid, void** out, const CHAR16* name,
      EFI_HANDLE imageHandle, EFI_SYSTEM_TABLE* systemTable) {
  
      *out = NULL;
      EFI_STATUS status;
      EFI_HANDLE interface = NULL;
  
      status = uefi_call_wrapper(systemTable-&gt;BootServices-&gt;LocateProtocol, 3,
          &amp;proto_guid, NULL, &amp;interface);
  
      if (EFI_ERROR(status)) {
          Print(L"LocateProtocol error for %s: %r\n", name, status);
          return FALSE;
      }
  
      Print(L"Locate protocol address: %s, %x\n", name, interface);
      *out = interface;
  
      return TRUE;
  }
  EFI_STATUS
  EFIAPI
  efi_main (EFI_HANDLE imageHandle, EFI_SYSTEM_TABLE* systemTable) {
      InitializeLib(imageHandle, systemTable);
      Print(L"Image loaded\n");
  
      EFI_LOADED_IMAGE* loaded_image = NULL;
      EFI_GUID guid_imgprot = LOADED_IMAGE_PROTOCOL;
  
      if (tryProtocol(guid_imgprot, (void**)&amp;loaded_image,
          L"LOADED_IMAGE_PROTOCOL", imageHandle, systemTable) != TRUE) {
          Print(L"Missing required protocol. Aborting\n");
          return EFI_SUCCESS;
      }
  
      Print(L"Image base: %lx\n", loaded_image-&gt;ImageBase);
      Print(L"Image size: %lx\n", loaded_image-&gt;ImageSize);
      Print(L"Image file: %s\n", DevicePathToStr(loaded_image-&gt;FilePath));
  
      EFI_SIMPLE_FILE_SYSTEM_PROTOCOL* simple_fs = NULL;
      EFI_GUID guid_simple_fs_prot = EFI_SIMPLE_FILE_SYSTEM_PROTOCOL_GUID;
  
      if (tryProtocol(guid_simple_fs_prot, (void**)&amp;simple_fs,
          L"EFI_SIMPLE_FILE_SYSTEM_PROTOCOL", imageHandle, systemTable) != TRUE) {
          Print(L"Missing required protocol. Aborting\n");
          return EFI_SUCCESS;
      }
  
      EFI_FILE_PROTOCOL* vol_proto = NULL;
      EFI_STATUS status;
  
      Print(L"dereffing\n");
      Print(L"address of OpenVolume: %x\n", simple_fs-&gt;OpenVolume);
  
      status = uefi_call_wrapper(simple_fs-&gt;OpenVolume, 2, simple_fs, &amp;vol_proto);
  
      if (EFI_ERROR(status)) {
          Print(L"Error opening volume: %r\n", status);
          return EFI_SUCCESS;
      }
  
      Print(L"SIMPLE_FILE_SYSTEM volume opened\n");
  
      EFI_FILE_PROTOCOL* f;
      CHAR16 fname[10] = L"foo.txt\0";
      UINT64 openmode = EFI_FILE_MODE_READ;
      UINT64 attr = 0;
      status = uefi_call_wrapper(vol_proto-&gt;Open, 5, vol_proto, &amp;f, fname, openmode, attr);
  
      if (EFI_ERROR(status)) {
          Print(L"Error opening file: %r\n", status);
          return EFI_SUCCESS;
      }
  
      Print(L"opened file %s\n", fname);
  
      // Spec says can only return EFI_SUCCESS
      status = uefi_call_wrapper(vol_proto-&gt;Close, 1, f);
  
      Print(L"Closed file\n");
  
      return EFI_SUCCESS;
  }
  </code></pre>