Page 1 of 1
gnu-efi undefined reference to WaitForSingleEvent
Posted: Fri Jul 17, 2020 4:18 am
by Rhodez
Hi, I need some help.
I have followed this
https://wiki.osdev.org/UEFI_Bare_Bones and I have the hello world example
running in both QEMU and on hardware form a USB, so that is very good.
I would like to extend the example, as suggested, with the WaitForKey.
If I have understood correct the code should look somthing like this:
Code: Select all
/* Now wait until a key becomes available. This is a simple
polling implementation. You could try and use the WaitForKey
event instead if you like */
/* while(Status = ST->ConIn->ReadKeyStroke(ST->ConIn, &Key) == EFI_NOT_READY); */
while (Key.UnicodeChar != 'q')
{
WaitForSingleEvent(ST->ConIn->WaitForKey, 0);
ST->ConIn->ReadKeyStroke(ST->ConIn, &Key);
ST->ConOut->OutputString(ST->ConOut, &Key.UnicodeChar );
}
But when I try to compile I get an undefined reference to `WaitForSingleEvent'
Code: Select all
/usr/lib/gcc/x86_64-w64-mingw32/10.1.0/../../../../x86_64-w64-mingw32/bin/ld: hello.o:hello.c:(.text+0xca): undefined reference to `WaitForSingleEvent'
collect2: error: ld returned 1 exit status
It is my first time cross compiling, so maybe it is just a small thing that I'm not aware of.
Anyone who can help?
Re: gnu-efi undefined reference to WaitForSingleEvent
Posted: Fri Jul 17, 2020 4:38 am
by iansjack
What command are you using to link the files?
Re: gnu-efi undefined reference to WaitForSingleEvent
Posted: Fri Jul 17, 2020 4:43 am
by bzt
Hi,
Rhodez wrote:It is my first time cross compiling, so maybe it is just a small thing that I'm not aware of.
Anyone who can help?
Your problem is not cross-compilation related. As the error message says, there's no such function "WaitForSingleEvent". Either you implement it yourself, or you rewrite your code to use
BS->WaitForEvent with one event in parameter.
Cheers,
bzt
Re: gnu-efi undefined reference to WaitForSingleEvent
Posted: Fri Jul 17, 2020 5:13 am
by Rhodez
iansjack wrote:What command are you using to link the files?
Just like the wiki says.
Code: Select all
x86_64-w64-mingw32-gcc -nostdlib -Wl,-dll -shared -Wl,--subsystem,10 -e efi_main -o BOOTX64.EFI hello.o data.o -lgcc
@bzt:
This was it! At least it compiles now, but it seems that no events occur.
I have both tried my own example here, but also the one from the link.
From the link example it only writes the first "wait" but then it just freezes.
Do you have any more suggestions here?
Re: gnu-efi undefined reference to WaitForSingleEvent
Posted: Fri Jul 17, 2020 5:40 am
by bzt
Rhodez wrote:@bzt:
This was it! At least it compiles now, but it seems that no events occur.
I have both tried my own example here, but also the one from the link.
From the link example it only writes the first "wait" but then it just freezes.
Do you have any more suggestions here?
Set up a timer to implement timeout maybe? Then you'd have to wait for two events, one for WaitForKey, and one for TimerEvent (not entirely sure about this, but it seems all examples on the net do this).
My other suggestion would be that you need to somehow "acknowledge" the event, my guess would be to read the keystroke before you enter the WaitForEvent cycle again. But you probably have tried this already.
I'd recommend to take a look at some FOSS UEFI boot manager, I'm pretty sure you can find a working example somewhere. Such as elilo, rEFInd, etc. Last resort GRUB (it's code is terrible, hard to read compared to the others, but has the answer for sure).
Cheers,
bzt
Re: gnu-efi undefined reference to WaitForSingleEvent
Posted: Fri Jul 17, 2020 7:08 am
by Rhodez
I have basically copy/pasted the example from the link, which I assume should work, but at least it does not on my machine.
I will try to examine more source code and see if I can figure it out.
But thanks for the BS->xxx tip, I hadn't figured out how to access the EFI_BOOT_SERVICES until that.
By chance, do you know the difference of using BS->xxx and gBS->xxx as he does in the example.
Both things works for me.
Cheers
Re: gnu-efi undefined reference to WaitForSingleEvent
Posted: Fri Jul 17, 2020 8:52 am
by bzt
Rhodez wrote:By chance, do you know the difference of using BS->xxx and gBS->xxx as he does in the example.
Different examples use different variable names, that's all. Both should be a pointer to the EFI Boot Time Services table. Most SDKs and libs set these up for you, but you could use your own pointer and read the address yourself from EFI_SYSTEM_TABLE*. I believe the "g" prefix most likely supposed to refer to "global" variable. To keep compatibility, it is not uncommon for EFI libs to set both. Here's the relevant code from
gnu-efi's InitializeLib, and here's the
EDK2 counterpart. As you can see, both initialized with SystemTable->BootServices.
For example,
elilo is using the gnu-efi library that sets up BS, while
shim prefers gBS and gRT (primarily uses EDK2, but also gnu-efi too for some reason).
Cheers,
bzt
Re: gnu-efi undefined reference to WaitForSingleEvent
Posted: Fri Jul 17, 2020 10:36 am
by Rhodez
Nice, thanks for the valuable information.
My initial understanding is much better now.
I will look at some more source code, and hopefully figure out what I need to do to get the WaitForEvent to work.
Re: gnu-efi undefined reference to WaitForSingleEvent
Posted: Fri Jul 17, 2020 1:13 pm
by Rhodez
Of course it was a stupid mistake.
I had not set BS to be ST->BootServices so it has been an invalid pointer during my tests.
I have attached a complete example of an UEFI application which just waits and writes keystrokes and exits on ESC.
Code: Select all
#include <efi.h>
#include <efilib.h>
EFI_STATUS
efi_main(EFI_HANDLE image, EFI_SYSTEM_TABLE *systemTable)
{
ST = systemTable;
BS = ST->BootServices;
UINTN index;
EFI_INPUT_KEY Key;
EFI_EVENT event = ST->ConIn->WaitForKey;
SIMPLE_INPUT_INTERFACE* conIn = ST->ConIn;
SIMPLE_TEXT_OUTPUT_INTERFACE* conOut = ST->ConOut;
conOut->OutputString(conOut, L"Hello UEFI");
while(Key.ScanCode != SCAN_ESC)
{
BS->WaitForEvent(1, &event, &index);
ST->ConIn->ReadKeyStroke(conIn, &Key);
ST->ConOut->OutputString(conOut, &Key.UnicodeChar );
}
return EFI_SUCCESS;
}