[ipxe-devel] [PATCH] [efi] make load file protocol optional
Laszlo Ersek
lersek at redhat.com
Thu Feb 12 14:41:32 UTC 2015
On 02/12/15 11:55, Michael Brown wrote:
> On 11/02/15 15:52, Gerd Hoffmann wrote:
>> The load file implementation added by commit
>> c7c3d839fc9120aee28de9aabe452dc85ad91502 doesn't support loading
>> arbitrary files from the tftp server, so efi applications trying
>> to do exactly that fail to boot:
>
> Which part of the EDK2 codebase supports loading arbitrary files via
> EFI_LOAD_FILE_PROTOCOL? I can find only two (almost identical)
> implementations of the protocol within EDK2:
>
> - NetworkPkg/UefiPxeBcDxe/PxeBcImpl.c : ignores the FilePath parameter
> and fails unless BootPolicy is true
>
> - MdeModulePkg/Universal/Network/UefiPxeBcDxe/PxeBcImpl.c : ignores
> the FilePath parameter and fails unless BootPolicy is true
>
> both of which match the behaviour used by iPXE.
>
> I'm happy to make iPXE's behaviour "correct", but I need some
> reference for what "correct" behaviour is supposed to be. Where is
> the code which implements your desired behaviour?
1.1 When the iPXE oprom is not loaded (or is deconfigured) for QEMU's
virtio-net NIC, then the SIMPLE_NETWORK_PROTOCOL interface is
provided by OVMF's builtin driver. This driver is dispatched from a
firmware volume that comes from the OVMF flash contents.
VirtioNetDriverBindingStart() [OvmfPkg/VirtioNetDxe/DriverBinding.c]
installs SIMPLE_NETWORK_PROTOCOL and EFI_DEVICE_PATH_PROTOCOL
interfaces on the child handle.
1.2 The rest of the protocol stack is provided by edk2 drivers. In
particular, PxeBcDriverBindingStart() in
"MdeModulePkg/Universal/Network/UefiPxeBcDxe/PxeBcDriver.c" installs
interfaces on the same handle for the following protocols:
- EFI_PXE_BASE_CODE_PROTOCOL,
- EFI_LOAD_FILE_PROTOCOL.
Note both LoadFile and PXEBaseCode in the following:
> Shell> dh -d -v -p SimpleNetwork
> 9E: UnknownDevice LoadFile PXEBaseCode TCPv4ServiceBinding
> MTFTPv4ServiceBinding DHCPv4ServiceBinding UDPv4ServiceBinding
> IPv4ServiceBinding IPv4Config ARPServiceBinding UnknownDevice
> ManagedNetworkServiceBinding EfiVlanConfigProtocolGuid DevicePath
> PciRoot(0x0)/Pci(0x3,0x0)/MAC(52540036A382,0x1) SimpleNetwork
> Controller Name : Virtio Network Device
> Device Path : PciRoot(0x0)/Pci(0x3,0x0)/MAC(52540036A382,0x1)
> Controller Type : BUS
> Configuration : NO
> Diagnostics : NO
> Managed by :
> Drv[6D] : MNP Network Service Driver
> Drv[6E] : VLAN Configuration Driver
> Drv[71] : IP4 CONFIG Network Service Driver
> Parent Controllers :
> Parent[8A] : Virtio Network Device
> Child Controllers :
> Child[A0] : MNP (MAC=52-54-00-36-A3-82, ProtocolType=0x806, VlanId=0)
> Child[A1] : MNP (Not started)
> Child[A3] : MNP (MAC=52-54-00-36-A3-82, ProtocolType=0x800, VlanId=0)
> Child[9F] : PciRoot(0x0)/Pci(0x3,0x0)/MAC(52540036A382,0x1)/VenHw(D79DF6B0-EF44-43BD-9797-43E93BCF5FA8)
> Child[A2] : PciRoot(0x0)/Pci(0x3,0x0)/MAC(52540036A382,0x1)/VenHw(D8944553-C4DD-41F4-9B30-E1397CFB267B)
1.3 Intel BDS looks for EFI_LOAD_FILE_PROTOCOL interfaces (see
"IntelFrameworkModulePkg/Universal/BdsDxe/BootMaint/BootOption.c").
It doesn't care about EFI_PXE_BASE_CODE_PROTOCOL.
1.4 The single member of EFI_LOAD_FILE_PROTOCOL is implemented with
EfiPxeLoadFile()
[MdeModulePkg/Universal/Network/UefiPxeBcDxe/PxeBcImpl.c]. That
function reuses EFI_PXE_BASE_CODE_PROTOCOL (which is provided by the
same driver) internally.
1.5 After shim.efi is loaded (using EFI_LOAD_FILE_PROTOCOL, which
internally relies on EFI_PXE_BASE_CODE_PROTOCOL), shim.efi tries to
load further files, like grub<ARCH>.efi. For that it uses
EFI_PXE_BASE_CODE_PROTOCOL directly.
Please see findNetboot() and FetchNetbootimage() in "netboot.c".
(Requiring EFI_PXE_BASE_CODE_PROTOCOL is not unique to shim, see
another boot loader here:
<http://thread.gmane.org/gmane.comp.bios.tianocore.devel/12021>.)
1.6 FetchNetbootimage() calls EFI_PXE_BASE_CODE_PROTOCOL.Mtftp(), which
is implemented in EfiPxeBcMtftp()
[MdeModulePkg/Universal/Network/UefiPxeBcDxe/PxeBcImpl.c]. The
Filename parameter is considered.
2.1 When the iPXE oprom is loaded, then it takes priority.
efi_snp_probe() in iPXE's "src/interface/efi/efi_snp.c" installs
the following protocols:
- EFI_SIMPLE_NETWORK_PROTOCOL
- EFI_DEVICE_PATH_PROTOCOL
- EFI_NII_PROTOCOL
- EFI_NII31_PROTOCOL
- EFI_COMPONENT_NAME2_PROTOCOL
- EFI_LOAD_FILE_PROTOCOL
This will prevent the builtin virtio-net driver from binding the
device in at least two places: first, because the iPXE driver keeps
open the PciIo interface with BY_DRIVER, and second (which is
probably not even reached due to the first), because duplicate
protocol interfaces cannot be installed on the same handle (SNP,
device path). Okay.
2.2 The rest of the stack is provided by edk2 drivers. Except,
PxeBcDriverBindingStart() in
"MdeModulePkg/Universal/Network/UefiPxeBcDxe/PxeBcDriver.c" will
*not* bind the controller handle, because EFI_LOAD_FILE_PROTOCOL,
which PxeBcDriverBindingStart() wants to install, is already present
on the handle (from step 2.1), and duplicate protocol interfaces are
not allowed on the same handle.
As a result, EFI_PXE_BASE_CODE_PROTOCOL will not be installed either
by this driver. Note the presence of LoadFile in the following
(provided by iPXE), but the absence of PXEBaseCode:
> Shell> dh -d -v -p SimpleNetwork
> 9F: UnknownDevice TCPv4ServiceBinding MTFTPv4ServiceBinding
> DHCPv4ServiceBinding UDPv4ServiceBinding IPv4ServiceBinding IPv4Config
> ARPServiceBinding UnknownDevice ManagedNetworkServiceBinding
> EfiVlanConfigProtocolGuid HIIConfigAccess LoadFile ComponentName2
> NetworkInterfaceIdentifier31 NetworkInterfaceIdentifier DevicePath
> PciRoot(0x0)/Pci(0x3,0x0)/MAC(525400938342,0x1) SimpleNetwork
> Controller Name : iPXE net0 (52:54:00:93:83:42)
> Device Path : PciRoot(0x0)/Pci(0x3,0x0)/MAC(525400938342,0x1)
> Controller Type : BUS
> Configuration : NO
> Diagnostics : NO
> Managed by :
> Drv[6D] : MNP Network Service Driver
> Drv[6E] : VLAN Configuration Driver
> Drv[71] : IP4 CONFIG Network Service Driver
> Parent Controllers :
> Parent[89] : PciRoot(0x0)/Pci(0x3,0x0)
> Child Controllers :
> Child[A1] : MNP (MAC=52-54-00-93-83-42, ProtocolType=0x806, VlanId=0)
> Child[A2] : MNP (Not started)
> Child[A4] : MNP (MAC=52-54-00-93-83-42, ProtocolType=0x800, VlanId=0)
> Child[A0] : PciRoot(0x0)/Pci(0x3,0x0)/MAC(525400938342,0x1)/VenHw(D79DF6B0-EF44-43BD-9797-43E93BCF5FA8)
> Child[A3] : PciRoot(0x0)/Pci(0x3,0x0)/MAC(525400938342,0x1)/VenHw(D8944553-C4DD-41F4-9B30-E1397CFB267B)
2.3 Intel BDS works identically (see 1.3); it only cares about
EFI_LOAD_FILE_PROTOCOL.
2.4 The single member of EFI_LOAD_FILE_PROTOCOL is implemented with
efi_snp_load_file() [src/interface/efi/efi_snp.c]. That function
calls the main ipxe() function. It loads shim.efi from the network.
2.5 After shim.efi is loaded (with the main ipxe() function), shim.efi
tries to load further files, like grub<ARCH>.efi. For that it looks
up EFI_PXE_BASE_CODE_PROTOCOL, which fails, because step 2.2 has
been prevented by step 2.1.
This issue might be fixable in several ways:
(a) Rework edk2 to provide EFI_PXE_BASE_CODE_PROTOCOL independently of
EFI_LOAD_FILE_PROTOCOL.
(b) Or, implement EFI_PXE_BASE_CODE_PROTOCOL in iPXE, and install it
alongside EFI_LOAD_FILE_PROTOCOL, in efi_snp_probe().
(c) Or, drop EFI_LOAD_FILE_PROTOCOL from step 2.1 (dependent on build
time configuration).
(d) Or, modify shim.efi, and possibly the other boot loader mentioned in
step 1.5, to use EFI_LOAD_FILE_PROTOCOL. This would also require all
relevant EFI_LOAD_FILE_PROTOCOL implementations to adhere to the
FilePath parameter.
Option (c) is by far the least intrusive, and the proposed patch does
that. With the patch applied, we get:
> Shell> dh -d -v -p SimpleNetwork
> 9F: UnknownDevice LoadFile PXEBaseCode TCPv4ServiceBinding
> MTFTPv4ServiceBinding DHCPv4ServiceBinding UDPv4ServiceBinding
> IPv4ServiceBinding IPv4Config ARPServiceBinding UnknownDevice
> ManagedNetworkServiceBinding EfiVlanConfigProtocolGuid HIIConfigAccess
> ComponentName2 NetworkInterfaceIdentifier31 NetworkInterfaceIdentifier
> DevicePath PciRoot(0x0)/Pci(0x3,0x0)/MAC(525400938342,0x1)
> SimpleNetwork
> Controller Name : iPXE net0 (52:54:00:93:83:42)
> Device Path : PciRoot(0x0)/Pci(0x3,0x0)/MAC(525400938342,0x1)
> Controller Type : BUS
> Configuration : NO
> Diagnostics : NO
> Managed by :
> Drv[6D] : MNP Network Service Driver
> Drv[6E] : VLAN Configuration Driver
> Drv[71] : IP4 CONFIG Network Service Driver
> Parent Controllers :
> Parent[89] : PciRoot(0x0)/Pci(0x3,0x0)
> Child Controllers :
> Child[A1] : MNP (MAC=52-54-00-93-83-42, ProtocolType=0x806, VlanId=0)
> Child[A2] : MNP (Not started)
> Child[A4] : MNP (MAC=52-54-00-93-83-42, ProtocolType=0x800, VlanId=0)
> Child[A0] : PciRoot(0x0)/Pci(0x3,0x0)/MAC(525400938342,0x1)/VenHw(D79DF6B0-EF44-43BD-9797-43E93BCF5FA8)
> Child[A3] : PciRoot(0x0)/Pci(0x3,0x0)/MAC(525400938342,0x1)/VenHw(D8944553-C4DD-41F4-9B30-E1397CFB267B)
Both LoadFile and PXEBaseCode are present.
Thanks
Laszlo
More information about the ipxe-devel
mailing list