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.

(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".)

(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()?

(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.

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.

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

Reply via email to