Hi Andrew, On 5 February 2016 at 18:39, Andrew Fish <[email protected]> wrote: > >> On Feb 5, 2016, at 10:36 AM, Ryan Harkin <[email protected]> wrote: >> >> Hi Laszlo, >> >> On 5 February 2016 at 17:19, Laszlo Ersek <[email protected]> wrote: >>> On 02/05/16 17:35, Ryan Harkin wrote: >>>> Hello all, >>>> >>>> I'm having a problem that is platform specific, but perhaps more of a >>>> generic problem. >>>> >>>> When ARM's Juno board boots, not all devices are connected. The first >>>> boot creates the boot variables and sets their order, meaning that we >>>> get the following list on the first attempt: >>>> >>>> EFI Misc Device >>>> EFI Misc Device 1 >>>> EFI Internal Shell >>>> >>>> Intel BDS then attempts to boot from one of the devices and ends up in >>>> Shell. After exiting Shell, the Intel BDS console GUI comes up. >>>> Selecting the Boot Manager option shows more devices being connected >>>> and the list becomes longer: >>>> >>>> EFI Misc Device >>>> EFI Misc Device 1 >>>> EFI Internal Shell >>>> EFI Hard Drive >>>> EFI Network >>>> >>>> Subsequent boots will never attempt to boot from Hard Drive or Network >>>> because Shell will always succeed. That is not good. >>>> >>>> Leif has a patch in his working tree that solves this problem [1] by >>>> making the platform call BdsLibConnectAll() at init time. So now, the >>>> first time boot order looks sane: >>>> >>>> EFI Misc Device >>>> EFI Misc Device 1 >>>> EFI Hard Drive >>>> EFI Network >>>> EFI Internal Shell >>>> >>>> However, then the board is booting, the "EFI Network" fails to boot >>>> the first time and so the board drops back to Shell again: >>>> >>>> Warning: LAN9118 Driver in stopped state >>>> Link timeout in auto-negotiation. >>>> Lan9118: Auto Negociation not supported. >>>> EhcExecTransfer: transfer failed with 2 >>>> EhcControlTransfer: error - Device Error, transfer - 2 >>>> Buffer: EFI Hard Drive >>>> Booting EFI Misc Device >>>> Booting EFI Misc Device 1 >>>> Booting EFI Hard Drive >>>> Booting EFI Network >>>> Warning: LAN9118 Driver not initialized >>>> Link timeout in auto-negotiation. >>>> Lan9118: Auto Negociation not supported. >>>> Booting EFI Internal Shell >>>> >>>> Exiting Shell drops the user back to the Intel BDS UI. Selecting >>>> "Continue" then succeeds in booting from the EFI Network: >>>> >>>> Booting EFI Misc Device >>>> Booting EFI Misc Device 1 >>>> Booting EFI Hard Drive >>>> Booting EFI Network >>>> ..MnpFreeTxBuf: Duplicated recycle report from SNP. >>>> MnpFreeTxBuf: Duplicated recycle report from SNP. >>>> [snip repeated SNP errors] >>>> >>>> If I duplicate the call to BdsLibConnectAll() [2], then boot works as >>>> expected. On first boot, the boot order is created correctly and EFI >>>> Network pulls down a file and boots it. >>>> >>>> I'm assuming that the 2nd call is connecting things that didn't >>>> connect the first time. And from that, I suspect/guess that perhaps >>>> they didn't connect due to either ordering or timing. >>>> >>>> Is there a recommended way to set the order things are connected? Is >>>> it even possible to specify dependencies or order? And if so, how do >>>> we work out what the order should be? >>> >>> I cannot give a coherent answer, just a few thoughts. >>> >>> (1) I think BdsLibConnectAll() actually succeeds for the first time as >>> well. All devices are enumerated, all drivers are connected, aren't >>> they? The boot order is a separate question. >>> >> >> Yes, you're right, they are all connected because they all appear in >> the boot list. >> >> >>> (2) The network, the NIC, or the NIC driver are more probable suspects. >>> If I see right, you always have a misc / misc1 / hd / network sequence >>> of attempts, it's just that on the first few occasions, the network >>> fails. ("Link timeout in auto-negotiation".) >>> >> >> Correct. >> >> >>> (3) I think repeated BdsLibConnectAll() calls may only give more time to >>> the NIC to bring itself into working shape. What if you keep only one >>> BdsLibConnectAll(), and replace the second BdsLibConnectAll() with a >>> sizeable gBS->Stall()? >>> >> >> Eureka! I replace the 2nd BdsLibConnectAll() with >> "gBS->Stall(500000);" (0.5 seconds) and this works every time also. >> >> So time to negociate (sic) would seem like the culprit. I suppose a >> 2nd BdsLibConnectAll() buys the NIC some time. >> >> I'm left wondering if the "Boot EFI Network" option should actually be >> waiting for negotiation, however. I'm sure it's common on first boot >> that the network needs a little time to negotiate. I'll look into >> that. Perhaps there is a setting or an override to tell it to be >> patient? >> > > This is either a bug in the driver, or a bug in the config of the PXE server. >
I doubt it's a bug in the server: negotiation here refers to the the NIC training on the network, so the server isn't involved at this stage. But a bug in the driver is a distinct possibility. Thanks, Ryan. > Thanks, > > Andrew Fish > >> >>> (4) What the boot order should be can be influenced by the platform BDS >>> lib, in the PlatformBdsPolicyBehavior() function. >>> >>> Namely, the BdsEntry() function in >>> "MdeModulePkg/Universal/Variable/RuntimeDxe/Variable.c" initializes the >>> "BootOptionList" variable to an empty list. Then it calls >>> PlatformBdsPolicyBehavior(), which takes "BootOptionList" as an >>> input/output parameter -- if it wishes, it can populate it. >>> >>> In ArmVirtPkg and in OvmfPkg, we perform the following steps in >>> PlatformBdsPolicyBehavior(): >>> >>> (a) connect the console(s) >>> >>> (b) BdsLibConnectAll() >>> >>> (c) BdsLibEnumerateAllBootOption (BootOptionList) -- this relies on the >>> presence of all devices, from the previous step. This function (in >>> "IntelFrameworkModulePkg/Library/GenericBdsLib/BdsBoot.c") has extensive >>> documentation in its leading comment. >>> >>> It will enumerate everything sensible (modifying BootOrder as well I >>> think), and output a BootOptionList that contains all the possible boot >>> options, in a sane order. Sanity means, if I remember correctly, that >>> all options that existed previously and were referenced by BootOrder, >>> retain their positions at the front of the list, and any new >>> auto-detected boot options are tacked to the end. >>> >>> (d) SetBootOrderFromQemu (BootOptionList) -- this is the really platform >>> specific part for massaging the boot order. We read through >>> BootOptionList -- we don't modify it --, do various calculations, and >>> then rewrite the BootOrder variable. Importantly, all Boot#### variables >>> that become *unreferenced* by BootOrder as a result of this, must be >>> deleted (otherwise they constitute a leak). Again, BootOptionList is not >>> modified. >>> >>> (e) BdsLibBuildOptionFromVar (BootOptionList, L"BootOrder") -- it >>> rebuilds BootOptionList from the new BootOrder contents. (We are again >>> in PlatformBdsPolicyBehavior(), where BootOptionList counts as >>> input/output.) >>> >>> On a physical platform, I think you just go with (b) and (c), and then >>> let the user customize the boot order. Next time you boot, (c) will >>> respect that. >>> >> >> Excellent answer, thanks. It looks like (c) is exactly the thing I'm >> looking for. For example, make HDD boot before USB. That sort of >> thing. >> >> I'm quite happy that once the default boot order has been set that it >> stays that way unless the user changes it. I don't (think I) want to >> customise the boot order after the initial boot. >> >> >>> There are further possibilities; there is a "boot mode" HOB with which >>> your low-level platform code can control your BDS policy, in order to >>> speed up things. See BdsLibGetBootMode() and the macros in >>> "MdePkg/Include/Pi/PiBootMode.h". Those macros are documented in one of >>> the PI spec volumes. >>> >>> For example, I think BOOT_ASSUMING_NO_CONFIGURATION_CHANGES is meant to >>> be very fast (no need to connect all devices to all drivers), but such a >>> HOB must be produced by your own PEI phase somehow -- you must know for >>> example that the chassis was never opened while the machine was off. >>> >>> FWIW, OVMF only uses BOOT_WITH_FULL_CONFIGURATION, and >>> BOOT_ON_S3_RESUME, and these two are differentiated in OVMF's PEI phase >>> by reading a CMOS register. >>> >>> Anyway, I think what you need is: >>> - call BdsLibConnectAll() exactly once >>> - give that NIC more time (?) >>> - if you'd like to regenerate all possible boot options *at the end* of >>> BootOrder that the user may have deleted (or have become available by >>> installing new hardware), call BdsLibEnumerateAllBootOption() too. >>> >> >> Yes, that sounds about right. I have concerns about the negotiation >> timing, but the boot order hacking sounds like what I'm looking for. >> >> Thanks again, >> Ryan. >> >> >>> Laszlo >>> >>>> >>>> Regards, >>>> Ryan. >>>> >>>> [1] >>>> https://git.linaro.org/uefi/linaro-edk2.git/commitdiff/bfbd0ef1a182e1baa120f66ad2c6838ef48ff48c >>>> [2] >>>> https://git.linaro.org/landing-teams/working/arm/edk2.git/commitdiff/25320ba4e447a843daaf7c603ec87afae3c2a120 >>>> >>> >> _______________________________________________ >> edk2-devel mailing list >> [email protected] >> https://lists.01.org/mailman/listinfo/edk2-devel > _______________________________________________ edk2-devel mailing list [email protected] https://lists.01.org/mailman/listinfo/edk2-devel

