[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