[U-Boot] x86: EFI: boot fails at exit_boot_services - Was: Stuck trying to build a non-qemu EFI payload

Hi Bin, Simon,
On 18 August 2015 at 15:47, Stoppa, Igor igor.stoppa@intel.com wrote:
Hi, I have verified that I can reproduce a working build of U-Boot as x86-64bit EFI payload for Qemu: I can boot it, interact with various filesystems of both real and emulated disks, etc.
Now I would like to build and boot it for a real board, still as EFI payload.
The docs/README.efi file states:
U-Boot is packaged up and loaded in its entirety by EFI. Once started, U-Boot changes to 32-bit mode (currently) and takes over the machine. You can use devices, boot a kernel, etc.
My test device is a a D4250WYK NUC with a 4th generation Core i5 Haswell processor. I tried booting it with an USB stick that I prepared and tested with qemu. The build is based on the qemu-x86_defconfig, plus the EFI settings needed for generating a 64 bit payload.
On qemu I can reach the U-Boot shell and run commands, however on the NUC it stops at the message "U-Boot EFI Payload", which is printed by the stub.
I've added traces to my setup and somewhat narrowed down the place where it gets stuck.
It happens much earlier than I thought: I was expecting it would get stuck during the handover from the stub to the real U-Boot, after the jump_to_uboot call, instead it never reaches that point.
On the NUC I get a system hang at the first
ret = boot->exit_boot_services(image, key);
in efi_main. I traced it with some putc().
My assumption was that, even if the payload is configured for QEmu, rather than for the real board I am using, the loading should be successful anyway, because it relies on the EFI API.
Is my assumption in correct?
I noticed something (unrelated?) regarding exit_boot_services: There's a comment in the efi_stub.c file, stating:
/* * Unfortunately it happens that we cannot exit boot services * the first time. But the second time it work. I don't know * why but this seems to be a repeatable problem. To get * around it, just try again. */
But, with Qemu, "exit_boot_services" always work at the first attempt: the execution never enters the braces containing that comment.

Hi again,
On 20 August 2015 at 12:44, Stoppa, Igor igor.stoppa@intel.com wrote:
It happens much earlier than I thought: I was expecting it would get stuck during the handover from the stub to the real U-Boot, after the jump_to_uboot call, instead it never reaches that point.
Now I am able to reach the jump_to_uboot call
On the NUC I get a system hang at the first
ret = boot->exit_boot_services(image, key);
I reach this point by commenting out: * the call to exit_boot_services * the brace following the if (ret) test associated to exit_boot_services * the enabling of the debug UART (because the qemu build is probably not compatible with my board)
I have found a workaround to the problem I was describing in my first mail, however the issue is not solved cleanly, because I'm not exiting EFI Boot Services.
This might problem might by due to differences in the EFI firmware between what runs on the NUC and Tianocore, which I use in Qemu.
I can create a bug report, if there is any bug tracker. From the website I couldn't find any.

Hi Igor,
On 20 August 2015 at 08:25, Stoppa, Igor igor.stoppa@intel.com wrote:
Hi again,
On 20 August 2015 at 12:44, Stoppa, Igor igor.stoppa@intel.com wrote:
It happens much earlier than I thought: I was expecting it would get stuck during the handover from the stub to the real U-Boot, after the jump_to_uboot call, instead it never reaches that point.
Now I am able to reach the jump_to_uboot call
On the NUC I get a system hang at the first
ret = boot->exit_boot_services(image, key);
I reach this point by commenting out:
- the call to exit_boot_services
- the brace following the if (ret) test associated to exit_boot_services
- the enabling of the debug UART (because the qemu build is probably
not compatible with my board)
I have found a workaround to the problem I was describing in my first mail, however the issue is not solved cleanly, because I'm not exiting EFI Boot Services.
This might problem might by due to differences in the EFI firmware between what runs on the NUC and Tianocore, which I use in Qemu.
I can create a bug report, if there is any bug tracker. From the website I couldn't find any.
Bugs are normally reported on the mailing list, as you have.
Note that once you call exit_boot_services you will not be able to use the console. Be careful here - the board may appear to hang but actually it is broken by you trying to output to the console.
See this code which switches to the legacy UART and allows you to use printch() etc. which should show you what is going on.
use_uart = true;
As to the root cause I am not sure. What do you think? The code is very simple so I'm not sure what could be different in your setup.
Regards, Simon

Hi Simon, thanks for helping, please find my reply below.
On 21 August 2015 at 23:51, Simon Glass sjg@chromium.org wrote:
Note that once you call exit_boot_services you will not be able to use the console. Be careful here - the board may appear to hang but actually it is broken by you trying to output to the console.
Yes, I had realised it, but it seemed - on qemu - that it would still work to call "putc", after the code:
map.version = version; map.desc_size = desc_size; add_entry_addr(priv, EFIET_MEMORY_MAP, &map, sizeof(map), desc, size); add_entry_addr(priv, EFIET_END, NULL, 0, 0, 0);
But maybe I was just "lucky" and it worked even if it was not supposed to. For example, maybe it was using memory pages that had already been freed.
However, after your reply, I re-cloned the x86 branch, just to be sure I would be starting from a clean slate, and re-did the configuration from scratch, without adding any traces.
The result is that stub reaches the call "jump_to_uboot", so it seems that there are no problems there.
The issues are to be found in the payload (as expected, since I'm using the qemu defconfig).
Trying the QEMU image on my Haswell test device, I see it rebooting.
Since I do not have means to obtain a serial console (please see footer note), I resorted to using a "while(1);" to identify the point where the reboot happens, by turning the reboot into a hang.
The location where the reboot is triggered is in:
common/board_f.c: board_init_f_mem @ 1048: memset(gd_ptr, '\0', sizeof(*gd));
I do not know the value of the pointer, but it seems that it is incorrect and writing to this address causes a reset.
I wonder if this is because I'm still using the device tree for the machine emulated by QEMU and if I should build one for my specific Haswell NUC.
Btw, the EFI bios offers the option of printing the EFI device tree. Is it the same used by U-Boot, so that I could use this information to create the Device Tree file?

Hi Igor,
On 25 August 2015 at 07:18, Stoppa, Igor igor.stoppa@intel.com wrote:
Hi Simon, thanks for helping, please find my reply below.
On 21 August 2015 at 23:51, Simon Glass sjg@chromium.org wrote:
Note that once you call exit_boot_services you will not be able to use the console. Be careful here - the board may appear to hang but actually it is broken by you trying to output to the console.
Yes, I had realised it, but it seemed - on qemu - that it would still work to call "putc", after the code:
map.version = version; map.desc_size = desc_size; add_entry_addr(priv, EFIET_MEMORY_MAP, &map, sizeof(map), desc, size); add_entry_addr(priv, EFIET_END, NULL, 0, 0, 0);
But maybe I was just "lucky" and it worked even if it was not supposed to. For example, maybe it was using memory pages that had already been freed.
However, after your reply, I re-cloned the x86 branch, just to be sure I would be starting from a clean slate, and re-did the configuration from scratch, without adding any traces.
The result is that stub reaches the call "jump_to_uboot", so it seems that there are no problems there.
The issues are to be found in the payload (as expected, since I'm using the qemu defconfig).
Trying the QEMU image on my Haswell test device, I see it rebooting.
Since I do not have means to obtain a serial console (please see footer note), I resorted to using a "while(1);" to identify the point where the reboot happens, by turning the reboot into a hang.
The location where the reboot is triggered is in:
common/board_f.c: board_init_f_mem @ 1048: memset(gd_ptr, '\0', sizeof(*gd));
I do not know the value of the pointer, but it seems that it is incorrect and writing to this address causes a reset.
You might be able to output it with printhex8() if not too early.
This is supposed to be in cache-as-RAM space. See start.S where it calls that function. The FSP returns that value so I'm not sure what could be wrong.
I wonder if this is because I'm still using the device tree for the machine emulated by QEMU and if I should build one for my specific Haswell NUC.
Btw, the EFI bios offers the option of printing the EFI device tree. Is it the same used by U-Boot, so that I could use this information to create the Device Tree file?
I don't think the device tree matters. Also we use the open firmware device tree (as Linux) - I thought EFI had its own thing?
-- thanks, igor
Regards, Simon
participants (2)
-
Simon Glass
-
Stoppa, Igor