0

I'm trying to use the EFI simple network protocol:

http://wiki.phoenix.com/wiki/index.php/EFI_SIMPLE_NETWORK_PROTOCOL

to wait for an incoming ethernet packet. However, using QEMU, the WaitForPacket event never triggers even with incoming packets, and on real hardware the event always triggers immediately without any packets arriving. I can see my sample packets "on the wire" with tcpdump so I'm fairly confident I am supplying packets to it. Here is my code (boiled down to just this test case):

#include <efi.h>
#include <efilib.h>

EFI_HANDLE getNetHandle();

EFI_STATUS
EFIAPI
efi_main (EFI_HANDLE ImageHandle, EFI_SYSTEM_TABLE *SystemTable)
{
  InitializeLib(ImageHandle, SystemTable);

  EFI_GUID snpguid = EFI_SIMPLE_NETWORK_PROTOCOL;
  EFI_HANDLE netHandle = getNetHandle();
  EFI_STATUS status;
  EFI_SIMPLE_NETWORK* net_if_struct;

  status = uefi_call_wrapper(BS->HandleProtocol, 3,
                             netHandle, &snpguid, &net_if_struct);
  Print(L"Main: HandleProtocol status: %r\n", status);

  Print(L"Main: WaitForPacket event: %x\n", net_if_struct->WaitForPacket);

  EFI_EVENT waitEvents[1];
  waitEvents[0] = net_if_struct->WaitForPacket;
  UINTN eventTriggered;
  status = uefi_call_wrapper(BS->WaitForEvent, 3,
                            1, waitEvents, &eventTriggered);
  Print(L"Main: WaitForEvent status: %r, event triggered: %d\n", status, eventTriggered);

  return EFI_SUCCESS;
}

EFI_HANDLE getNetHandle()
{
  UINTN numHandles = 0;
  EFI_HANDLE* handles = NULL;
  EFI_GUID SimpleNetworkGUID = EFI_SIMPLE_NETWORK_PROTOCOL;
  EFI_STATUS status = uefi_call_wrapper(BS->LocateHandleBuffer, 5,
                             ByProtocol, &SimpleNetworkGUID, NULL, &numHandles, &handles);

  if (status != EFI_SUCCESS)
    Print(L"getNetHandle: Failed to LocateHandleBuffer (%d)\n", status);
  else
    Print(L"getNetHandle: LocateHandleBuffer OK (%d handles)\n", numHandles);

  EFI_HANDLE toReturn = NULL;
  if (numHandles == 1)
  {
    toReturn = handles[0];
  }

  FreePool(handles);
  return toReturn;
}

Things I've tried / proof / clues I have:

When this runs the WaitForPacket event print line prints a non-null value so I am assuming the EFI system has created an event and left it ready in the EFI_SIMPLE_NETWORK struct.

I have tried assuming the other way that I need to create an event and put it in the struct, and then use that event to wait on, but it didn't make any difference.

I have other code which can send and receive packets (just about), so I think my understanding of the network handle and interface struct is reasonable, and my EFI hardware and QEMU is capable of network communication.

The documentation on how to use WaitForPacket is non-existent, to a point where it feels like this should be one of those things that just works. Documentation I have found is at the Phoenix wiki (linked above) and the 2899 page UEFI spec document version 2.7.

Despite my best Googling I can't find any examples of WaitForPacket being used in a GNU-EFI application.

I've tried starting and initialising the network hardware which seems necessary with QEMU but not with real hardware. I've also tried setting the hardware to promiscuous mode using ReceiveFilters() and broadcasting at it, but that made no difference either.

Any ideas??

  • Just fishing for more clues - does `WaitForEvent` return `EFI_SUCCESS` on the hardware? – PhilMasteG Jun 18 '18 at 17:28
  • @PhilMasterG Hi, WaitForEvent on the H/W returns immediately with EFI_SUCCESS. You would think this means there's a packet to receive but a Receive call immediately following returns EFI_NOT_READY. Just for kicks I checked the which-event-triggered UINTN return from WaitForEvent by waiting for two events - keyboard first, network second and the event triggered index return changed to 1 from 0. – Horatio Gerblatim Jun 19 '18 at 12:33
  • Can you check whether you have anything sensible in `net_if_struct->WaitForPacket` on hardware vs. QEMU? – unixsmurf Jun 21 '18 at 16:03
  • @unixsmurf This line: `Print(L"Main: WaitForPacket event: %x\n", net_if_struct->WaitForPacket);` results in `Main: WaitForPacket event: 6FD4098` on QEMU, exactly the same over several runs and QEMU restarts. On the H/W, it is nearly always `Main: WaitForPacket event: D1ADCA18` but once I saw the value D1ADDC18. It's just a void* so I don't know what more investigation I can do. Right after the print line I have some packet send code and I can see the packets with tcpdump so the net_if_struct is definitely valid. – Horatio Gerblatim Jun 22 '18 at 13:33
  • @HoratioGerblatim the reason I asked is I saw some examples of drivers not initialising the WaitForPacket event. However, EFI_EVENT is typedeffed to VOID *, and both of those look like nice 64-bit aligned pointers. – unixsmurf Jun 22 '18 at 14:49
  • @unixsmurf Ah yeah, well thanks for looking at it – Horatio Gerblatim Jun 22 '18 at 15:29

0 Answers0