On 22 October 2017 at 15:40, Leif Lindholm <[email protected]> wrote:
> On Sat, Oct 21, 2017 at 02:10:49PM +0100, Ard Biesheuvel wrote:
>> To make it easier for power users to provision a 'desktop' system [as
>> opposed to a VM or server] from scratch, introduce a driver that adds
>> boot options to the boot menu that can launch network installers over
>> HTTP straight off the Internet.
>>
>> Currently, this only supports the 'mini.iso' style netboot installers
>> that Debian/Ubuntu provide: larger images that need to be mounted by
>> the installer when running under the Linux kernel are only supported
>> on ACPI systems with support for the NFIT table, and this was enabled
>> only recently (Linux v4.14) for arm64. For DT boot, there is currently
>> no way at all to expose ramdisks created by UEFI as block devices in
>> Linux.
>
> This is good stuff.
>
>> Contributed-under: TianoCore Contribution Agreement 1.1
>> Signed-off-by: Ard Biesheuvel <[email protected]>
>> ---
>>
>> Posted as an RFC because:
>> a) Where does this belong? Surely not in ArmPkg but I had to put it somewhere
>
> Not ArmPkg. EmbeddedPkg would also be wrong.
>
> It feels to me like it shares a common thread with the ACPI/DT
> switcher and the console preference widget.
>

... which should live where? the ACPI/DT switcher currently lives in
EmbeddedPkg, and actually, the serial console widget actually does
have an 'embedded' nature, so it would not seem out of place there.
But that is assuming you think EmbeddedPkg has a reason to exist in
the first place, and be something other than 'stuff that the Intel
guys don't want to touch'

>> b) Currently, the way the options are created results in them taking priority
>>    if no real boot options were set (i.e., for GRUB).
>> c) Is there a use case for downloading 300-500 MB installers off the Internet
>>    for a one shot installation? Or should we just stick to the mini.iso 
>> flavors.
>> d) Did I miss any distros we may care about?
>
> I think answers to all three of the above questions can end up being
> somewhat platform-specific. But I also think figuring out how that may
> best be implementented can wait.
>

I solved b) by using the LOAD_OPTION_CATEGORY_APP flag: that way, it
does appear in the 'Boot Manager' menu, but it is not launched
automatically.

> I could see a case here for a new package of UI tweaks and utilities.
> It would also not be unreasonable to add items like this under
> MdeModulePkg/{Application|Library}.
>

How about ValueAddPkg? :-)

>
>>  ArmPkg/Drivers/OsInstallerMenuDxe/OsInstallerMenuDxe.c   | 228 
>> ++++++++++++++++++++
>>  ArmPkg/Drivers/OsInstallerMenuDxe/OsInstallerMenuDxe.inf |  42 ++++
>>  2 files changed, 270 insertions(+)
>>
>> diff --git a/ArmPkg/Drivers/OsInstallerMenuDxe/OsInstallerMenuDxe.c 
>> b/ArmPkg/Drivers/OsInstallerMenuDxe/OsInstallerMenuDxe.c
>> new file mode 100644
>> index 000000000000..7c5934935924
>> --- /dev/null
>> +++ b/ArmPkg/Drivers/OsInstallerMenuDxe/OsInstallerMenuDxe.c
>> @@ -0,0 +1,228 @@
>> +/** @file
>> + *
>> + *  Copyright (c) 2016-2017, Linaro Limited. All rights reserved.
>> + *
>> + *  This program and the accompanying materials are licensed and made 
>> available
>> + *  under the terms and conditions of the BSD License which accompanies this
>> + *  distribution.  The full text of the license may be found at
>> + *  http://opensource.org/licenses/bsd-license.php
>> + *
>> + *  THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
>> + *  WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR 
>> IMPLIED.
>> + */
>> +
>> +#include <Uefi.h>
>> +#include <Library/BaseLib.h>
>> +#include <Library/BaseMemoryLib.h>
>> +#include <Library/DebugLib.h>
>> +#include <Library/DevicePathLib.h>
>> +#include <Library/MemoryAllocationLib.h>
>> +#include <Library/UefiBootManagerLib.h>
>> +#include <Library/UefiBootServicesTableLib.h>
>> +#include <Library/UefiLib.h>
>> +#include <Protocol/SimpleNetwork.h>
>> +
>> +typedef struct {
>> +  CONST CHAR16  *Name;
>> +  CONST CHAR8   *Uri;
>> +} OS_INSTALLER_IMAGE;
>> +
>> +STATIC CONST OS_INSTALLER_IMAGE mOsInstallers[] = {
>> +  { L"Install Debian Stretch over HTTP",
>> +    
>> "http://ftp.us.debian.org/debian/dists/stretch/main/installer-arm64/current/images/netboot/mini.iso";
>>  },
>> +
>> +  { L"Install Ubuntu 17.10 (Artful) over HTTP",
>> +    
>> "http://ports.ubuntu.com/ubuntu-ports/dists/artful/main/installer-arm64/current/images/netboot/mini.iso";
>>  },
>> +
>> +//
>> +// The links below refer to 300-500 MB netboot images that need to be 
>> exposed to
>> +// the OS via a ramdisk after the OS loader boots the installer from it.
>> +// Currently, this requires ACPI/NFIT support, which was only enabled for 
>> arm64
>> +// in Linux in version v4.14. For DT boot, there is currently no solution 
>> for
>> +// this.
>> +//
>> +//  { L"Install openSUSE Tumbleweed over HTTP",
>> +//    
>> "http://download.opensuse.org/ports/aarch64/factory/iso/openSUSE-Tumbleweed-NET-aarch64-Current.iso";
>>  },
>> +//
>> +//  { L"Install Fedora Server 26 over HTTP",
>> +//    
>> "http://download.fedoraproject.org/pub/fedora-secondary/releases/26/Server/aarch64/iso/Fedora-Server-netinst-aarch64-26-1.5.iso";
>>  },
>> +//
>> +//  { L"Install Centos 7 over HTTP",
>> +//    
>> "http://mirror.centos.org/altarch/7/isos/aarch64/CentOS-7-aarch64-NetInstall.iso";
>>  }
>> +//
>> +};
>> +
>> +STATIC EFI_EVENT                  mRegisterProtocolEvent;
>> +STATIC VOID                       *mRegistration;
>> +
>> +STATIC
>> +EFI_STATUS
>> +CreateOsInstallerBootOptions (
>> +  IN  EFI_HANDLE    Handle
>> +  )
>> +{
>> +  EFI_DEVICE_PATH_PROTOCOL        *ParentDevicePath;
>> +  EFI_DEVICE_PATH_PROTOCOL        *TmpDevicePath;
>> +  EFI_DEVICE_PATH_PROTOCOL        *NewDevicePath;
>> +  EFI_STATUS                      Status;
>> +  UINTN                           Idx;
>> +  EFI_DEV_PATH                    *Node;
>> +  UINTN                           Length;
>> +  EFI_BOOT_MANAGER_LOAD_OPTION    NewOption;
>> +  EFI_BOOT_MANAGER_LOAD_OPTION    *BootOptions;
>> +  UINTN                           BootOptionCount;
>> +  INTN                            OptionIndex;
>> +
>> +  BootOptions = EfiBootManagerGetLoadOptions (&BootOptionCount,
>> +                  LoadOptionTypeBoot);
>> +  ASSERT (BootOptions != NULL);
>> +
>> +  Status = gBS->HandleProtocol (Handle, &gEfiDevicePathProtocolGuid,
>> +                  (VOID **)&ParentDevicePath);
>> +  if (EFI_ERROR (Status)) {
>> +    DEBUG ((DEBUG_WARN, "%a: gBS->HandleProtocol returned %r\n",
>> +      __FUNCTION__, Status));
>> +    return Status;
>> +  }
>> +
>> +  for (Idx = 0; Idx < ARRAY_SIZE (mOsInstallers); Idx++) {
>> +    Node = AllocateZeroPool (sizeof (IPv4_DEVICE_PATH));
>> +    if (Node == NULL) {
>> +      Status = EFI_OUT_OF_RESOURCES;
>> +      goto FreeBootOptions;
>> +    }
>> +    Node->Ipv4.Header.Type    = MESSAGING_DEVICE_PATH;
>> +    Node->Ipv4.Header.SubType = MSG_IPv4_DP;
>> +    SetDevicePathNodeLength (Node, sizeof (IPv4_DEVICE_PATH));
>> +
>> +    TmpDevicePath = AppendDevicePathNode (ParentDevicePath,
>> +                      (EFI_DEVICE_PATH_PROTOCOL*) Node);
>> +    FreePool (Node);
>> +    if (TmpDevicePath == NULL) {
>> +      Status = EFI_OUT_OF_RESOURCES;
>> +      goto FreeBootOptions;
>> +    }
>> +
>> +    //
>> +    // Update the URI node with the input boot file URI.
>> +    //
>> +    Length = sizeof (EFI_DEVICE_PATH_PROTOCOL) +
>> +             AsciiStrSize (mOsInstallers[Idx].Uri);
>> +    Node = AllocatePool (Length);
>> +    if (Node == NULL) {
>> +      Status = EFI_OUT_OF_RESOURCES;
>> +      FreePool (TmpDevicePath);
>> +      goto FreeBootOptions;
>> +    }
>> +    Node->DevPath.Type    = MESSAGING_DEVICE_PATH;
>> +    Node->DevPath.SubType = MSG_URI_DP;
>> +    SetDevicePathNodeLength (Node, Length);
>> +    CopyMem ((UINT8*) Node + sizeof (EFI_DEVICE_PATH_PROTOCOL),
>> +      mOsInstallers[Idx].Uri, AsciiStrSize (mOsInstallers[Idx].Uri));
>> +    NewDevicePath = AppendDevicePathNode (TmpDevicePath,
>> +                      (EFI_DEVICE_PATH_PROTOCOL*) Node);
>> +    FreePool (Node);
>> +    FreePool (TmpDevicePath);
>> +    if (NewDevicePath == NULL) {
>> +      Status = EFI_OUT_OF_RESOURCES;
>> +      goto FreeBootOptions;
>> +    }
>> +
>> +    //
>> +    // Create a new load option.
>> +    //
>> +    Status = EfiBootManagerInitializeLoadOption (&NewOption,
>> +               LoadOptionNumberUnassigned, LoadOptionTypeBoot,
>> +               LOAD_OPTION_ACTIVE, (CHAR16 *)mOsInstallers[Idx].Name,
>> +               NewDevicePath, NULL, 0);
>> +    ASSERT_EFI_ERROR (Status);
>> +
>> +    OptionIndex = EfiBootManagerFindLoadOption (&NewOption, BootOptions,
>> +                    BootOptionCount);
>> +    if (OptionIndex == -1) {
>> +      //
>> +      // Add the new load option if it did not exist already
>> +      //
>> +      EfiBootManagerAddLoadOptionVariable (&NewOption, (UINTN) -1);
>> +    }
>> +    EfiBootManagerFreeLoadOption (&NewOption);
>> +    FreePool (NewDevicePath);
>> +  }
>> +
>> +FreeBootOptions:
>> +
>> +  EfiBootManagerFreeLoadOptions (BootOptions, BootOptionCount);
>> +  return Status;
>> +}
>> +
>> +STATIC
>> +BOOLEAN
>> +MediaDisconnected (
>> +  IN  EFI_HANDLE    Handle
>> +  )
>> +{
>> +  EFI_SIMPLE_NETWORK_PROTOCOL   *Snp;
>> +  EFI_STATUS                    Status;
>> +
>> +  Status = gBS->HandleProtocol (Handle, &gEfiSimpleNetworkProtocolGuid,
>> +                  (VOID **)&Snp);
>> +  if (EFI_ERROR (Status) || !Snp->Mode->MediaPresentSupported) {
>> +    return FALSE;
>> +  }
>> +
>> +  Snp->GetStatus (Snp, NULL, NULL);
>> +
>> +  return !Snp->Mode->MediaPresent;
>> +}
>> +
>> +STATIC
>> +VOID
>> +OnRegisterProtocol (
>> +  IN EFI_EVENT  Event,
>> +  IN VOID       *Context
>> +  )
>> +{
>> +  EFI_STATUS                      Status;
>> +  UINTN                           HandleCount;
>> +  EFI_HANDLE                      *HandleBuffer;
>> +  UINTN                           Idx;
>> +
>> +  Status = gBS->LocateHandleBuffer (ByRegisterNotify,
>> +                  &gEfiHttpServiceBindingProtocolGuid, mRegistration,
>> +                  &HandleCount, &HandleBuffer);
>> +  if (EFI_ERROR (Status)) {
>> +    return;
>> +  }
>> +
>> +  for (Idx = 0; Idx < HandleCount; Idx++) {
>> +    if (MediaDisconnected (HandleBuffer[Idx])) {
>> +      continue;
>> +    }
>> +
>> +    CreateOsInstallerBootOptions (HandleBuffer[Idx]);
>> +
>> +    //
>> +    // Create the options only a single time - we take care to only install
>> +    // them for a network interface that has a link, and we should try not 
>> to
>> +    // confuse the user by having 10 identical options when the system has 
>> 10
>> +    // network interfaces.
>> +    //
>> +    gBS->CloseEvent (Event);
>> +    break;
>> +  }
>> +  FreePool (HandleBuffer);
>> +}
>> +
>> +EFI_STATUS
>> +EFIAPI
>> +OsInstallerMenuDxeEntryPoint (
>> +  IN EFI_HANDLE        ImageHandle,
>> +  IN EFI_SYSTEM_TABLE  *SystemTable
>> +  )
>> +{
>> +  mRegisterProtocolEvent = EfiCreateProtocolNotifyEvent (
>> +                             &gEfiHttpServiceBindingProtocolGuid, 
>> TPL_CALLBACK,
>> +                             OnRegisterProtocol, NULL, &mRegistration);
>> +
>> +  return EFI_SUCCESS;
>> +}
>> diff --git a/ArmPkg/Drivers/OsInstallerMenuDxe/OsInstallerMenuDxe.inf 
>> b/ArmPkg/Drivers/OsInstallerMenuDxe/OsInstallerMenuDxe.inf
>> new file mode 100644
>> index 000000000000..9bc5a81a78a1
>> --- /dev/null
>> +++ b/ArmPkg/Drivers/OsInstallerMenuDxe/OsInstallerMenuDxe.inf
>> @@ -0,0 +1,42 @@
>> +#
>> +#  Copyright (c) 2016-2017, Linaro Limited. All rights reserved.
>> +#
>> +#  This program and the accompanying materials are licensed and made 
>> available
>> +#  under the terms and conditions of the BSD License which accompanies this
>> +#  distribution.  The full text of the license may be found at
>> +#  http://opensource.org/licenses/bsd-license.php
>> +#
>> +#  THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
>> +#  WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR 
>> IMPLIED.
>> +#
>> +
>> +[Defines]
>> +  INF_VERSION           = 0x00010019
>> +  BASE_NAME             = OsInstallerMenuDxe
>> +  FILE_GUID             = 4def5019-3233-4925-98ef-db5c60b2aec4
>> +  MODULE_TYPE           = UEFI_DRIVER
>> +  VERSION_STRING        = 0.1
>> +  ENTRY_POINT           = OsInstallerMenuDxeEntryPoint
>> +
>> +[Sources]
>> +  OsInstallerMenuDxe.c
>> +
>> +[Packages]
>> +  MdePkg/MdePkg.dec
>> +  MdeModulePkg/MdeModulePkg.dec
>> +
>> +[LibraryClasses]
>> +  BaseLib
>> +  BaseMemoryLib
>> +  DebugLib
>> +  DevicePathLib
>> +  MemoryAllocationLib
>> +  UefiBootManagerLib
>> +  UefiBootServicesTableLib
>> +  UefiDriverEntryPoint
>> +  UefiLib
>> +
>> +[Protocols]
>> +  gEfiHttpServiceBindingProtocolGuid
>> +  gEfiDevicePathProtocolGuid
>> +  gEfiSimpleNetworkProtocolGuid
>> --
>> 2.11.0
>>
_______________________________________________
edk2-devel mailing list
[email protected]
https://lists.01.org/mailman/listinfo/edk2-devel

Reply via email to