[edk2] EmbeddedPkg: add driver to set graphical/serial console preference

Message ID 20171020133337.23372-1-ard.biesheuvel@linaro.org
State New
Headers show
Series
  • [edk2] EmbeddedPkg: add driver to set graphical/serial console preference
Related show

Commit Message

Ard Biesheuvel Oct. 20, 2017, 1:33 p.m.
Linux on ARM/arm64 will infer from the presence of a /chosen/stdout-path
DT property or of a SPCR ACPI table that the primary console is the serial
port, even if a graphical console is available as well.

So let's introduce a driver that allows the user to set a preference
between graphical and serial if both are available. If the preference
is set to 'Graphical', and any GOP protocol instances have been installed
by the time the ReadyToBoot event is signalled, remove the DT property
and the table entirely.

Contributed-under: TianoCore Contribution Agreement 1.1
Signed-off-by: Ard Biesheuvel <ard.biesheuvel@linaro.org>

---
 EmbeddedPkg/Drivers/ConsolePrefDxe/ConsolePrefDxe.c   | 284 ++++++++++++++++++++
 EmbeddedPkg/Drivers/ConsolePrefDxe/ConsolePrefDxe.h   |  31 +++
 EmbeddedPkg/Drivers/ConsolePrefDxe/ConsolePrefDxe.inf |  62 +++++
 EmbeddedPkg/Drivers/ConsolePrefDxe/ConsolePrefHii.uni |  27 ++
 EmbeddedPkg/Drivers/ConsolePrefDxe/ConsolePrefHii.vfr |  51 ++++
 5 files changed, 455 insertions(+)

-- 
2.11.0

_______________________________________________
edk2-devel mailing list
edk2-devel@lists.01.org
https://lists.01.org/mailman/listinfo/edk2-devel

Comments

Ard Biesheuvel Oct. 20, 2017, 1:40 p.m. | #1
On 20 October 2017 at 14:33, Ard Biesheuvel <ard.biesheuvel@linaro.org> wrote:
> Linux on ARM/arm64 will infer from the presence of a /chosen/stdout-path

> DT property or of a SPCR ACPI table that the primary console is the serial

> port, even if a graphical console is available as well.

>

> So let's introduce a driver that allows the user to set a preference

> between graphical and serial if both are available. If the preference

> is set to 'Graphical', and any GOP protocol instances have been installed

> by the time the ReadyToBoot event is signalled, remove the DT property

> and the table entirely.

>

> Contributed-under: TianoCore Contribution Agreement 1.1

> Signed-off-by: Ard Biesheuvel <ard.biesheuvel@linaro.org>

> ---

>  EmbeddedPkg/Drivers/ConsolePrefDxe/ConsolePrefDxe.c   | 284 ++++++++++++++++++++

>  EmbeddedPkg/Drivers/ConsolePrefDxe/ConsolePrefDxe.h   |  31 +++

>  EmbeddedPkg/Drivers/ConsolePrefDxe/ConsolePrefDxe.inf |  62 +++++

>  EmbeddedPkg/Drivers/ConsolePrefDxe/ConsolePrefHii.uni |  27 ++

>  EmbeddedPkg/Drivers/ConsolePrefDxe/ConsolePrefHii.vfr |  51 ++++


Two [trivial] hunks missing here, apologies. They are pasted below

>  5 files changed, 455 insertions(+)

>

> diff --git a/EmbeddedPkg/Drivers/ConsolePrefDxe/ConsolePrefDxe.c b/EmbeddedPkg/Drivers/ConsolePrefDxe/ConsolePrefDxe.c

> new file mode 100644

> index 000000000000..cabe4f652cf5

> --- /dev/null

> +++ b/EmbeddedPkg/Drivers/ConsolePrefDxe/ConsolePrefDxe.c

> @@ -0,0 +1,284 @@

> +/** @file

> +*

> +*  Copyright (c) 2017, Linaro, Ltd. 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 <IndustryStandard/Acpi.h>

> +#include <libfdt.h>

> +#include <Library/BaseLib.h>

> +#include <Library/DebugLib.h>

> +#include <Library/DevicePathLib.h>

> +#include <Library/HiiLib.h>

> +#include <Library/UefiBootServicesTableLib.h>

> +#include <Library/UefiBootServicesTableLib.h>

> +#include <Library/UefiDriverEntryPoint.h>

> +#include <Library/UefiLib.h>

> +#include <Library/UefiRuntimeServicesTableLib.h>

> +

> +#include <Protocol/AcpiTable.h>

> +#include <Protocol/AcpiSystemDescriptionTable.h>

> +

> +#include "ConsolePrefDxe.h"

> +

> +#define SPCR_SIG    EFI_ACPI_2_0_SERIAL_PORT_CONSOLE_REDIRECTION_TABLE_SIGNATURE

> +

> +extern  UINT8                     ConsolePrefHiiBin[];

> +extern  UINT8                     ConsolePrefDxeStrings[];

> +

> +typedef struct {

> +  VENDOR_DEVICE_PATH              VendorDevicePath;

> +  EFI_DEVICE_PATH_PROTOCOL        End;

> +} HII_VENDOR_DEVICE_PATH;

> +

> +STATIC HII_VENDOR_DEVICE_PATH     mConsolePrefDxeVendorDevicePath = {

> +  {

> +    {

> +      HARDWARE_DEVICE_PATH,

> +      HW_VENDOR_DP,

> +      {

> +        (UINT8) (sizeof (VENDOR_DEVICE_PATH)),

> +        (UINT8) ((sizeof (VENDOR_DEVICE_PATH)) >> 8)

> +      }

> +    },

> +    CONSOLE_PREF_FORMSET_GUID

> +  },

> +  {

> +    END_DEVICE_PATH_TYPE,

> +    END_ENTIRE_DEVICE_PATH_SUBTYPE,

> +    {

> +      (UINT8) (END_DEVICE_PATH_LENGTH),

> +      (UINT8) ((END_DEVICE_PATH_LENGTH) >> 8)

> +    }

> +  }

> +};

> +

> +STATIC EFI_EVENT                  mReadyToBootEvent;

> +STATIC UINTN                      mSpcrTableKey;

> +

> +STATIC

> +EFI_STATUS

> +InstallHiiPages (

> +  VOID

> +  )

> +{

> +  EFI_STATUS                      Status;

> +  EFI_HII_HANDLE                  HiiHandle;

> +  EFI_HANDLE                      DriverHandle;

> +

> +  DriverHandle = NULL;

> +  Status = gBS->InstallMultipleProtocolInterfaces (&DriverHandle,

> +                  &gEfiDevicePathProtocolGuid,

> +                  &mConsolePrefDxeVendorDevicePath,

> +                  NULL);

> +  if (EFI_ERROR (Status)) {

> +    return Status;

> +  }

> +

> +  HiiHandle = HiiAddPackages (&gConsolePrefFormSetGuid,

> +                              DriverHandle,

> +                              ConsolePrefDxeStrings,

> +                              ConsolePrefHiiBin,

> +                              NULL);

> +

> +  if (HiiHandle == NULL) {

> +    gBS->UninstallMultipleProtocolInterfaces (DriverHandle,

> +                  &gEfiDevicePathProtocolGuid,

> +                  &mConsolePrefDxeVendorDevicePath,

> +                  NULL);

> +    return EFI_OUT_OF_RESOURCES;

> +  }

> +  return EFI_SUCCESS;

> +}

> +

> +STATIC

> +VOID

> +RemoveDtStdoutPath (

> +  VOID

> +)

> +{

> +  VOID        *Dtb;

> +  INT32       Node;

> +  INT32       Error;

> +  EFI_STATUS  Status;

> +

> +  Status = EfiGetSystemConfigurationTable (&gFdtTableGuid, &Dtb);

> +  if (EFI_ERROR (Status)) {

> +    DEBUG ((DEBUG_INFO, "%a: could not retrieve DT blob - %r\n", __FUNCTION__,

> +      Status));

> +  }

> +

> +  Node = fdt_path_offset (Dtb, "/chosen");

> +  if (Node < 0) {

> +    return;

> +  }

> +

> +  Error = fdt_delprop (Dtb, Node, "stdout-path");

> +  if (Error) {

> +    DEBUG ((DEBUG_INFO, "%a: Failed to delete 'stdout-path' property: %a\n",

> +      __FUNCTION__, fdt_strerror (Error)));

> +  }

> +}

> +

> +STATIC

> +VOID

> +OnReadyToBoot (

> +  IN EFI_EVENT  Event,

> +  IN VOID       *Context

> +  )

> +{

> +  CONSOLE_PREF_VARSTORE_DATA      ConsolePref;

> +  UINTN                           BufferSize;

> +  EFI_STATUS                      Status;

> +  VOID                            *Gop;

> +  EFI_ACPI_TABLE_PROTOCOL         *AcpiTable;

> +

> +  BufferSize = sizeof (ConsolePref);

> +  Status = gRT->GetVariable (CONSOLE_PREF_VARIABLE_NAME,

> +                  &gConsolePrefFormSetGuid, NULL, &BufferSize, &ConsolePref);

> +  if (EFI_ERROR (Status)) {

> +    DEBUG ((DEBUG_ERROR,

> +      "%a: variable '%s' could not be read - bailing!\n", __FUNCTION__,

> +      CONSOLE_PREF_VARIABLE_NAME));

> +    return;

> +  }

> +

> +  if (ConsolePref.Console == CONSOLE_PREF_SERIAL) {

> +    DEBUG ((DEBUG_INFO,

> +      "%a: serial console preferred - doing nothing\n", __FUNCTION__));

> +    return;

> +  }

> +

> +  //

> +  // Check if any GOP instances exist: if so, disable stdout-path and SPCR

> +  //

> +  Status = gBS->LocateProtocol (&gEfiGraphicsOutputProtocolGuid, NULL, &Gop);

> +  if (EFI_ERROR (Status)) {

> +    DEBUG ((DEBUG_INFO,

> +      "%a: no GOP instances found - doing nothing (%r)\n", __FUNCTION__,

> +      Status));

> +    return;

> +  }

> +

> +  RemoveDtStdoutPath ();

> +

> +  if (mSpcrTableKey != 0) {

> +    Status = gBS->LocateProtocol (&gEfiAcpiTableProtocolGuid, NULL,

> +                    (VOID **)&AcpiTable);

> +    ASSERT_EFI_ERROR (Status);

> +

> +    Status = AcpiTable->UninstallAcpiTable (AcpiTable, mSpcrTableKey);

> +    if (EFI_ERROR (Status)) {

> +      DEBUG ((DEBUG_WARN, "%a: failed to uninstall SPCR table - %r\n",

> +        __FUNCTION__, Status));

> +    }

> +  }

> +}

> +

> +STATIC

> +EFI_STATUS

> +OnInstallAcpiTable (

> +  IN EFI_ACPI_SDT_HEADER    *Table,

> +  IN EFI_ACPI_TABLE_VERSION Version,

> +  IN UINTN                  TableKey

> +  )

> +{

> +  if (Table->Signature == SPCR_SIG) {

> +    mSpcrTableKey = TableKey;

> +  }

> +  return EFI_SUCCESS;

> +}

> +

> +/**

> +  The entry point for ConsolePrefDxe driver.

> +

> +  @param[in] ImageHandle     The image handle of the driver.

> +  @param[in] SystemTable     The system table.

> +

> +  @retval EFI_ALREADY_STARTED     The driver already exists in system.

> +  @retval EFI_OUT_OF_RESOURCES    Fail to execute entry point due to lack of

> +                                  resources.

> +  @retval EFI_SUCCES              All the related protocols are installed on

> +                                  the driver.

> +

> +**/

> +EFI_STATUS

> +EFIAPI

> +ConsolePrefDxeEntryPoint (

> +  IN EFI_HANDLE                   ImageHandle,

> +  IN EFI_SYSTEM_TABLE             *SystemTable

> +  )

> +{

> +  EFI_STATUS                      Status;

> +  CONSOLE_PREF_VARSTORE_DATA      ConsolePref;

> +  UINTN                           BufferSize;

> +  EFI_ACPI_SDT_PROTOCOL           *Sdt;

> +

> +  //

> +  // Get the current console preference from the ConsolePref variable.

> +  //

> +  BufferSize = sizeof (ConsolePref);

> +  Status = gRT->GetVariable (CONSOLE_PREF_VARIABLE_NAME,

> +                  &gConsolePrefFormSetGuid, NULL, &BufferSize, &ConsolePref);

> +  if (EFI_ERROR (Status)) {

> +    DEBUG ((DEBUG_INFO,

> +      "%a: no console preference found, defaulting to graphical\n",

> +      __FUNCTION__));

> +    ConsolePref.Console = CONSOLE_PREF_GRAPHICAL;

> +  }

> +

> +  if (!EFI_ERROR (Status) &&

> +      ConsolePref.Console != CONSOLE_PREF_GRAPHICAL &&

> +      ConsolePref.Console != CONSOLE_PREF_SERIAL) {

> +    DEBUG ((DEBUG_WARN, "%a: invalid value for %s, defaulting to graphical\n",

> +      __FUNCTION__, CONSOLE_PREF_VARIABLE_NAME));

> +    ConsolePref.Console = CONSOLE_PREF_GRAPHICAL;

> +    Status = EFI_INVALID_PARAMETER; // trigger setvar below

> +  }

> +

> +  //

> +  // Write the newly selected default value back to the variable store.

> +  //

> +  if (EFI_ERROR (Status)) {

> +    ZeroMem (&ConsolePref.Reserved, sizeof (ConsolePref.Reserved));

> +    Status = gRT->SetVariable (CONSOLE_PREF_VARIABLE_NAME,

> +                    &gConsolePrefFormSetGuid,

> +                    EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_BOOTSERVICE_ACCESS,

> +                    sizeof (ConsolePref), &ConsolePref);

> +

> +    if (EFI_ERROR (Status)) {

> +      DEBUG ((DEBUG_ERROR, "%a: gRT->SetVariable () failed - %r\n",

> +        __FUNCTION__, Status));

> +      return Status;

> +    }

> +  }

> +

> +  Status = gBS->LocateProtocol (&gEfiAcpiSdtProtocolGuid, NULL, (VOID **)&Sdt);

> +  if (!EFI_ERROR (Status)) {

> +    //

> +    // If we have the SDT protocol, use it to register a ACPI table

> +    // installation notification callback so we can record the table

> +    // key of the SPCR table.

> +    //

> +    Status = Sdt->RegisterNotify (TRUE, OnInstallAcpiTable);

> +    if (EFI_ERROR (Status)) {

> +      DEBUG ((DEBUG_WARN, "%a: Sdt->RegisterNotify () failed - %r\n",

> +        __FUNCTION__, Status));

> +    }

> +  }

> +

> +  Status = gBS->CreateEventEx (EVT_NOTIFY_SIGNAL, TPL_CALLBACK,

> +                  OnReadyToBoot, NULL, &gEfiEventReadyToBootGuid,

> +                  &mReadyToBootEvent);

> +  ASSERT_EFI_ERROR (Status);

> +

> +  return InstallHiiPages ();

> +}

> diff --git a/EmbeddedPkg/Drivers/ConsolePrefDxe/ConsolePrefDxe.h b/EmbeddedPkg/Drivers/ConsolePrefDxe/ConsolePrefDxe.h

> new file mode 100644

> index 000000000000..7ec420f89013

> --- /dev/null

> +++ b/EmbeddedPkg/Drivers/ConsolePrefDxe/ConsolePrefDxe.h

> @@ -0,0 +1,31 @@

> +/** @file

> +*

> +*  Copyright (c) 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.

> +*

> +**/

> +

> +#ifndef __CONSOLE_PREF_DXE_H__

> +#define __CONSOLE_PREF_DXE_H__

> +

> +#include <Guid/HiiPlatformSetupFormset.h>

> +#include <Guid/ConsolePrefFormSet.h>

> +

> +#define CONSOLE_PREF_GRAPHICAL      0x0

> +#define CONSOLE_PREF_SERIAL         0x1

> +

> +#define CONSOLE_PREF_VARIABLE_NAME  L"ConsolePref"

> +

> +typedef struct {

> +  UINT8         Console;

> +  UINT8         Reserved[3];

> +} CONSOLE_PREF_VARSTORE_DATA;

> +

> +#endif

> diff --git a/EmbeddedPkg/Drivers/ConsolePrefDxe/ConsolePrefDxe.inf b/EmbeddedPkg/Drivers/ConsolePrefDxe/ConsolePrefDxe.inf

> new file mode 100644

> index 000000000000..d8b412b9200a

> --- /dev/null

> +++ b/EmbeddedPkg/Drivers/ConsolePrefDxe/ConsolePrefDxe.inf

> @@ -0,0 +1,62 @@

> +## @file

> +#

> +#  Copyright (c) 2017, Linaro, Ltd. All rights reserved.<BR>

> +#

> +#  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                 = ConsolePrefDxe

> +  FILE_GUID                 = bbe2668c-0efc-46fb-9137-4f2da8f419f3

> +  MODULE_TYPE               = DXE_DRIVER

> +  VERSION_STRING            = 1.0

> +  ENTRY_POINT               = ConsolePrefDxeEntryPoint

> +

> +#

> +# The following information is for reference only and not required by the build tools.

> +#

> +#  VALID_ARCHITECTURES      = IA32 X64 ARM AARCH64

> +#

> +

> +[Sources]

> +  ConsolePrefDxe.c

> +  ConsolePrefHii.vfr

> +  ConsolePrefHii.uni

> +

> +[Packages]

> +  EmbeddedPkg/EmbeddedPkg.dec

> +  MdePkg/MdePkg.dec

> +  MdeModulePkg/MdeModulePkg.dec

> +

> +[LibraryClasses]

> +  BaseLib

> +  DebugLib

> +  FdtLib

> +  HiiLib

> +  UefiBootServicesTableLib

> +  UefiDriverEntryPoint

> +  UefiLib

> +  UefiRuntimeServicesTableLib

> +

> +[Guids]

> +  gConsolePrefFormSetGuid

> +  gFdtTableGuid

> +  gEfiEventReadyToBootGuid

> +

> +[Protocols]

> +  gEfiAcpiTableProtocolGuid

> +  gEfiAcpiSdtProtocolGuid

> +  gEfiGraphicsOutputProtocolGuid

> +

> +[Depex]

> +  gEfiVariableArchProtocolGuid        AND

> +  gEfiVariableWriteArchProtocolGuid

> diff --git a/EmbeddedPkg/Drivers/ConsolePrefDxe/ConsolePrefHii.uni b/EmbeddedPkg/Drivers/ConsolePrefDxe/ConsolePrefHii.uni

> new file mode 100644

> index 000000000000..0442adf77163

> --- /dev/null

> +++ b/EmbeddedPkg/Drivers/ConsolePrefDxe/ConsolePrefHii.uni

> @@ -0,0 +1,27 @@

> +/** @file

> +*

> +*  Copyright (c) 2017, Linaro, Ltd. 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.

> +*

> +**/

> +

> +#langdef en-US  "English"

> +

> +#string STR_FORM_SET_TITLE             #language en-US "Console Preference Selection"

> +#string STR_FORM_SET_TITLE_HELP        #language en-US "Press <Enter> to choose between graphical and serial console."

> +

> +#string STR_MAIN_FORM_TITLE            #language en-US "Console Preference Selection"

> +#string STR_NULL_STRING                #language en-US ""

> +

> +#string STR_CONSOLE_PREF_SELECT_PROMPT #language en-US "Preferred console"

> +#string STR_CONSOLE_PREF_SELECT_HELP   #language en-US "Select the preferred console if both graphical and serial are available."

> +

> +#string STR_CONSOLE_PREF_GRAPHICAL     #language en-US "Graphical"

> +#string STR_CONSOLE_PREF_SERIAL        #language en-US "Serial"

> diff --git a/EmbeddedPkg/Drivers/ConsolePrefDxe/ConsolePrefHii.vfr b/EmbeddedPkg/Drivers/ConsolePrefDxe/ConsolePrefHii.vfr

> new file mode 100644

> index 000000000000..fdfba5cf4cb3

> --- /dev/null

> +++ b/EmbeddedPkg/Drivers/ConsolePrefDxe/ConsolePrefHii.vfr

> @@ -0,0 +1,51 @@

> +/** @file

> +*

> +*  Copyright (c) 2017, Linaro, Ltd. 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 "ConsolePrefDxe.h"

> +

> +//

> +// EFI Variable attributes

> +//

> +#define EFI_VARIABLE_NON_VOLATILE       0x00000001

> +#define EFI_VARIABLE_BOOTSERVICE_ACCESS 0x00000002

> +#define EFI_VARIABLE_RUNTIME_ACCESS     0x00000004

> +#define EFI_VARIABLE_READ_ONLY          0x00000008

> +

> +formset

> +  guid      = CONSOLE_PREF_FORMSET_GUID,

> +  title     = STRING_TOKEN(STR_FORM_SET_TITLE),

> +  help      = STRING_TOKEN(STR_FORM_SET_TITLE_HELP),

> +  classguid = EFI_HII_PLATFORM_SETUP_FORMSET_GUID,

> +

> +  efivarstore CONSOLE_PREF_VARSTORE_DATA,

> +    attribute = EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_NON_VOLATILE,  // EFI variable attributes

> +    name  = ConsolePref,

> +    guid  = CONSOLE_PREF_FORMSET_GUID;

> +

> +  form formid = 0x1000,

> +    title  = STRING_TOKEN(STR_MAIN_FORM_TITLE);

> +

> +    oneof varid = ConsolePref.Console,

> +        prompt      = STRING_TOKEN(STR_CONSOLE_PREF_SELECT_PROMPT),

> +        help        = STRING_TOKEN(STR_CONSOLE_PREF_SELECT_HELP),

> +        flags       = NUMERIC_SIZE_1 | INTERACTIVE,

> +        option text = STRING_TOKEN(STR_CONSOLE_PREF_GRAPHICAL), value = CONSOLE_PREF_GRAPHICAL, flags = DEFAULT;

> +        option text = STRING_TOKEN(STR_CONSOLE_PREF_SERIAL), value = CONSOLE_PREF_SERIAL, flags = 0;

> +    endoneof;

> +

> +    subtitle text = STRING_TOKEN(STR_NULL_STRING);

> +

> +  endform;

> +

> +endformset;

> --

> 2.11.0

>



diff --git a/EmbeddedPkg/EmbeddedPkg.dec b/EmbeddedPkg/EmbeddedPkg.dec
index 151b1d503dee..52482af13aeb 100644
--- a/EmbeddedPkg/EmbeddedPkg.dec
+++ b/EmbeddedPkg/EmbeddedPkg.dec
@@ -67,6 +67,9 @@ [Guids.common]
   # File GUID for default DTB image embedded in the firmware volume
   gDtPlatformDefaultDtbFileGuid = { 0x25462cda, 0x221f, 0x47df, {
0xac, 0x1d, 0x25, 0x9c, 0xfa, 0xa4, 0xe3, 0x26 } }

+  # HII form set GUID for ConsolePrefDxe driver
+  gConsolePrefFormSetGuid = { 0x2d2358b4, 0xe96c, 0x484d, { 0xb2,
0xdd, 0x7c, 0x2e, 0xdf, 0xc7, 0xd5, 0x6f } }
+
 [Protocols.common]
   gHardwareInterruptProtocolGuid =  { 0x2890B3EA, 0x053D, 0x1643, {
0xAD, 0x0C, 0xD6, 0x48, 0x08, 0xDA, 0x3F, 0xF1 } }
   gHardwareInterrupt2ProtocolGuid = { 0x32898322, 0x2da1, 0x474a, {
0xba, 0xaa, 0xf3, 0xf7, 0xcf, 0x56, 0x94, 0x70 } }
diff --git a/EmbeddedPkg/Include/Guid/ConsolePrefFormSet.h
b/EmbeddedPkg/Include/Guid/ConsolePrefFormSet.h
new file mode 100644
index 000000000000..2c2e1a154871
--- /dev/null
+++ b/EmbeddedPkg/Include/Guid/ConsolePrefFormSet.h
@@ -0,0 +1,23 @@
+/** @file
+*
+*  Copyright (c) 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.
+*
+**/
+
+#ifndef __CONSOLE_PREF_FORMSET_H__
+#define __CONSOLE_PREF_FORMSET_H__
+
+#define CONSOLE_PREF_FORMSET_GUID  \
+  { 0x2d2358b4, 0xe96c, 0x484d, { 0xb2, 0xdd, 0x7c, 0x2e, 0xdf, 0xc7,
0xd5, 0x6f } }
+
+extern EFI_GUID gConsolePrefFormSetGuid;
+
+#endif
_______________________________________________
edk2-devel mailing list
edk2-devel@lists.01.org
https://lists.01.org/mailman/listinfo/edk2-devel
Leif Lindholm Oct. 20, 2017, 1:50 p.m. | #2
On Fri, Oct 20, 2017 at 02:33:37PM +0100, Ard Biesheuvel wrote:
> Linux on ARM/arm64 will infer from the presence of a /chosen/stdout-path

> DT property or of a SPCR ACPI table that the primary console is the serial

> port, even if a graphical console is available as well.

> 

> So let's introduce a driver that allows the user to set a preference

> between graphical and serial if both are available. If the preference

> is set to 'Graphical', and any GOP protocol instances have been installed

> by the time the ReadyToBoot event is signalled, remove the DT property

> and the table entirely.

> 

> Contributed-under: TianoCore Contribution Agreement 1.1

> Signed-off-by: Ard Biesheuvel <ard.biesheuvel@linaro.org>

> ---

>  EmbeddedPkg/Drivers/ConsolePrefDxe/ConsolePrefDxe.c   | 284 ++++++++++++++++++++

>  EmbeddedPkg/Drivers/ConsolePrefDxe/ConsolePrefDxe.h   |  31 +++

>  EmbeddedPkg/Drivers/ConsolePrefDxe/ConsolePrefDxe.inf |  62 +++++

>  EmbeddedPkg/Drivers/ConsolePrefDxe/ConsolePrefHii.uni |  27 ++

>  EmbeddedPkg/Drivers/ConsolePrefDxe/ConsolePrefHii.vfr |  51 ++++

>  5 files changed, 455 insertions(+)

> 

> diff --git a/EmbeddedPkg/Drivers/ConsolePrefDxe/ConsolePrefDxe.c b/EmbeddedPkg/Drivers/ConsolePrefDxe/ConsolePrefDxe.c

> new file mode 100644

> index 000000000000..cabe4f652cf5

> --- /dev/null

> +++ b/EmbeddedPkg/Drivers/ConsolePrefDxe/ConsolePrefDxe.c

> @@ -0,0 +1,284 @@

> +/** @file

> +*

> +*  Copyright (c) 2017, Linaro, Ltd. 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 <IndustryStandard/Acpi.h>

> +#include <libfdt.h>

> +#include <Library/BaseLib.h>

> +#include <Library/DebugLib.h>

> +#include <Library/DevicePathLib.h>

> +#include <Library/HiiLib.h>

> +#include <Library/UefiBootServicesTableLib.h>

> +#include <Library/UefiBootServicesTableLib.h>

> +#include <Library/UefiDriverEntryPoint.h>

> +#include <Library/UefiLib.h>

> +#include <Library/UefiRuntimeServicesTableLib.h>

> +

> +#include <Protocol/AcpiTable.h>

> +#include <Protocol/AcpiSystemDescriptionTable.h>

> +

> +#include "ConsolePrefDxe.h"

> +

> +#define SPCR_SIG    EFI_ACPI_2_0_SERIAL_PORT_CONSOLE_REDIRECTION_TABLE_SIGNATURE

> +

> +extern  UINT8                     ConsolePrefHiiBin[];

> +extern  UINT8                     ConsolePrefDxeStrings[];

> +

> +typedef struct {

> +  VENDOR_DEVICE_PATH              VendorDevicePath;

> +  EFI_DEVICE_PATH_PROTOCOL        End;

> +} HII_VENDOR_DEVICE_PATH;

> +

> +STATIC HII_VENDOR_DEVICE_PATH     mConsolePrefDxeVendorDevicePath = {

> +  {

> +    {

> +      HARDWARE_DEVICE_PATH,

> +      HW_VENDOR_DP,

> +      {

> +        (UINT8) (sizeof (VENDOR_DEVICE_PATH)),

> +        (UINT8) ((sizeof (VENDOR_DEVICE_PATH)) >> 8)

> +      }

> +    },

> +    CONSOLE_PREF_FORMSET_GUID

> +  },

> +  {

> +    END_DEVICE_PATH_TYPE,

> +    END_ENTIRE_DEVICE_PATH_SUBTYPE,

> +    {

> +      (UINT8) (END_DEVICE_PATH_LENGTH),

> +      (UINT8) ((END_DEVICE_PATH_LENGTH) >> 8)

> +    }

> +  }

> +};

> +

> +STATIC EFI_EVENT                  mReadyToBootEvent;

> +STATIC UINTN                      mSpcrTableKey;

> +

> +STATIC

> +EFI_STATUS

> +InstallHiiPages (

> +  VOID

> +  )

> +{

> +  EFI_STATUS                      Status;

> +  EFI_HII_HANDLE                  HiiHandle;

> +  EFI_HANDLE                      DriverHandle;

> +

> +  DriverHandle = NULL;

> +  Status = gBS->InstallMultipleProtocolInterfaces (&DriverHandle,

> +                  &gEfiDevicePathProtocolGuid,

> +                  &mConsolePrefDxeVendorDevicePath,

> +                  NULL);

> +  if (EFI_ERROR (Status)) {

> +    return Status;

> +  }

> +

> +  HiiHandle = HiiAddPackages (&gConsolePrefFormSetGuid,

> +                              DriverHandle,

> +                              ConsolePrefDxeStrings,

> +                              ConsolePrefHiiBin,

> +                              NULL);

> +

> +  if (HiiHandle == NULL) {

> +    gBS->UninstallMultipleProtocolInterfaces (DriverHandle,

> +                  &gEfiDevicePathProtocolGuid,

> +                  &mConsolePrefDxeVendorDevicePath,

> +                  NULL);


Something funky going on with indentation here.

If you address that:
Reviewed-by: Leif Lindholm <leif.lindholm@linaro.org>


Thanks for putting this together.

/
    Leif

> +    return EFI_OUT_OF_RESOURCES;

> +  }

> +  return EFI_SUCCESS;

> +}

> +

> +STATIC

> +VOID

> +RemoveDtStdoutPath (

> +  VOID

> +)

> +{

> +  VOID        *Dtb;

> +  INT32       Node;

> +  INT32       Error;

> +  EFI_STATUS  Status;

> +

> +  Status = EfiGetSystemConfigurationTable (&gFdtTableGuid, &Dtb);

> +  if (EFI_ERROR (Status)) {

> +    DEBUG ((DEBUG_INFO, "%a: could not retrieve DT blob - %r\n", __FUNCTION__,

> +      Status));

> +  }

> +

> +  Node = fdt_path_offset (Dtb, "/chosen");

> +  if (Node < 0) {

> +    return;

> +  }

> +

> +  Error = fdt_delprop (Dtb, Node, "stdout-path");

> +  if (Error) {

> +    DEBUG ((DEBUG_INFO, "%a: Failed to delete 'stdout-path' property: %a\n",

> +      __FUNCTION__, fdt_strerror (Error)));

> +  }

> +}

> +

> +STATIC

> +VOID

> +OnReadyToBoot (

> +  IN EFI_EVENT  Event,

> +  IN VOID       *Context

> +  )

> +{

> +  CONSOLE_PREF_VARSTORE_DATA      ConsolePref;

> +  UINTN                           BufferSize;

> +  EFI_STATUS                      Status;

> +  VOID                            *Gop;

> +  EFI_ACPI_TABLE_PROTOCOL         *AcpiTable;

> +

> +  BufferSize = sizeof (ConsolePref);

> +  Status = gRT->GetVariable (CONSOLE_PREF_VARIABLE_NAME,

> +                  &gConsolePrefFormSetGuid, NULL, &BufferSize, &ConsolePref);

> +  if (EFI_ERROR (Status)) {

> +    DEBUG ((DEBUG_ERROR,

> +      "%a: variable '%s' could not be read - bailing!\n", __FUNCTION__,

> +      CONSOLE_PREF_VARIABLE_NAME));

> +    return;

> +  }

> +

> +  if (ConsolePref.Console == CONSOLE_PREF_SERIAL) {

> +    DEBUG ((DEBUG_INFO,

> +      "%a: serial console preferred - doing nothing\n", __FUNCTION__));

> +    return;

> +  }

> +

> +  //

> +  // Check if any GOP instances exist: if so, disable stdout-path and SPCR

> +  //

> +  Status = gBS->LocateProtocol (&gEfiGraphicsOutputProtocolGuid, NULL, &Gop);

> +  if (EFI_ERROR (Status)) {

> +    DEBUG ((DEBUG_INFO,

> +      "%a: no GOP instances found - doing nothing (%r)\n", __FUNCTION__,

> +      Status));

> +    return;

> +  }

> +

> +  RemoveDtStdoutPath ();

> +

> +  if (mSpcrTableKey != 0) {

> +    Status = gBS->LocateProtocol (&gEfiAcpiTableProtocolGuid, NULL,

> +                    (VOID **)&AcpiTable);

> +    ASSERT_EFI_ERROR (Status);

> +

> +    Status = AcpiTable->UninstallAcpiTable (AcpiTable, mSpcrTableKey);

> +    if (EFI_ERROR (Status)) {

> +      DEBUG ((DEBUG_WARN, "%a: failed to uninstall SPCR table - %r\n",

> +        __FUNCTION__, Status));

> +    }

> +  }

> +}

> +

> +STATIC

> +EFI_STATUS

> +OnInstallAcpiTable (

> +  IN EFI_ACPI_SDT_HEADER    *Table,

> +  IN EFI_ACPI_TABLE_VERSION Version,

> +  IN UINTN                  TableKey

> +  )

> +{

> +  if (Table->Signature == SPCR_SIG) {

> +    mSpcrTableKey = TableKey;

> +  }

> +  return EFI_SUCCESS;

> +}

> +

> +/**

> +  The entry point for ConsolePrefDxe driver.

> +

> +  @param[in] ImageHandle     The image handle of the driver.

> +  @param[in] SystemTable     The system table.

> +

> +  @retval EFI_ALREADY_STARTED     The driver already exists in system.

> +  @retval EFI_OUT_OF_RESOURCES    Fail to execute entry point due to lack of

> +                                  resources.

> +  @retval EFI_SUCCES              All the related protocols are installed on

> +                                  the driver.

> +

> +**/

> +EFI_STATUS

> +EFIAPI

> +ConsolePrefDxeEntryPoint (

> +  IN EFI_HANDLE                   ImageHandle,

> +  IN EFI_SYSTEM_TABLE             *SystemTable

> +  )

> +{

> +  EFI_STATUS                      Status;

> +  CONSOLE_PREF_VARSTORE_DATA      ConsolePref;

> +  UINTN                           BufferSize;

> +  EFI_ACPI_SDT_PROTOCOL           *Sdt;

> +

> +  //

> +  // Get the current console preference from the ConsolePref variable.

> +  //

> +  BufferSize = sizeof (ConsolePref);

> +  Status = gRT->GetVariable (CONSOLE_PREF_VARIABLE_NAME,

> +                  &gConsolePrefFormSetGuid, NULL, &BufferSize, &ConsolePref);

> +  if (EFI_ERROR (Status)) {

> +    DEBUG ((DEBUG_INFO,

> +      "%a: no console preference found, defaulting to graphical\n",

> +      __FUNCTION__));

> +    ConsolePref.Console = CONSOLE_PREF_GRAPHICAL;

> +  }

> +

> +  if (!EFI_ERROR (Status) &&

> +      ConsolePref.Console != CONSOLE_PREF_GRAPHICAL &&

> +      ConsolePref.Console != CONSOLE_PREF_SERIAL) {

> +    DEBUG ((DEBUG_WARN, "%a: invalid value for %s, defaulting to graphical\n",

> +      __FUNCTION__, CONSOLE_PREF_VARIABLE_NAME));

> +    ConsolePref.Console = CONSOLE_PREF_GRAPHICAL;

> +    Status = EFI_INVALID_PARAMETER; // trigger setvar below

> +  }

> +

> +  //

> +  // Write the newly selected default value back to the variable store.

> +  //

> +  if (EFI_ERROR (Status)) {

> +    ZeroMem (&ConsolePref.Reserved, sizeof (ConsolePref.Reserved));

> +    Status = gRT->SetVariable (CONSOLE_PREF_VARIABLE_NAME,

> +                    &gConsolePrefFormSetGuid,

> +                    EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_BOOTSERVICE_ACCESS,

> +                    sizeof (ConsolePref), &ConsolePref);

> +

> +    if (EFI_ERROR (Status)) {

> +      DEBUG ((DEBUG_ERROR, "%a: gRT->SetVariable () failed - %r\n",

> +        __FUNCTION__, Status));

> +      return Status;

> +    }

> +  }

> +

> +  Status = gBS->LocateProtocol (&gEfiAcpiSdtProtocolGuid, NULL, (VOID **)&Sdt);

> +  if (!EFI_ERROR (Status)) {

> +    //

> +    // If we have the SDT protocol, use it to register a ACPI table

> +    // installation notification callback so we can record the table

> +    // key of the SPCR table.

> +    //

> +    Status = Sdt->RegisterNotify (TRUE, OnInstallAcpiTable);

> +    if (EFI_ERROR (Status)) {

> +      DEBUG ((DEBUG_WARN, "%a: Sdt->RegisterNotify () failed - %r\n",

> +        __FUNCTION__, Status));

> +    }

> +  }

> +

> +  Status = gBS->CreateEventEx (EVT_NOTIFY_SIGNAL, TPL_CALLBACK,

> +                  OnReadyToBoot, NULL, &gEfiEventReadyToBootGuid,

> +                  &mReadyToBootEvent);

> +  ASSERT_EFI_ERROR (Status);

> +

> +  return InstallHiiPages ();

> +}

> diff --git a/EmbeddedPkg/Drivers/ConsolePrefDxe/ConsolePrefDxe.h b/EmbeddedPkg/Drivers/ConsolePrefDxe/ConsolePrefDxe.h

> new file mode 100644

> index 000000000000..7ec420f89013

> --- /dev/null

> +++ b/EmbeddedPkg/Drivers/ConsolePrefDxe/ConsolePrefDxe.h

> @@ -0,0 +1,31 @@

> +/** @file

> +*

> +*  Copyright (c) 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.

> +*

> +**/

> +

> +#ifndef __CONSOLE_PREF_DXE_H__

> +#define __CONSOLE_PREF_DXE_H__

> +

> +#include <Guid/HiiPlatformSetupFormset.h>

> +#include <Guid/ConsolePrefFormSet.h>

> +

> +#define CONSOLE_PREF_GRAPHICAL      0x0

> +#define CONSOLE_PREF_SERIAL         0x1

> +

> +#define CONSOLE_PREF_VARIABLE_NAME  L"ConsolePref"

> +

> +typedef struct {

> +  UINT8         Console;

> +  UINT8         Reserved[3];

> +} CONSOLE_PREF_VARSTORE_DATA;

> +

> +#endif

> diff --git a/EmbeddedPkg/Drivers/ConsolePrefDxe/ConsolePrefDxe.inf b/EmbeddedPkg/Drivers/ConsolePrefDxe/ConsolePrefDxe.inf

> new file mode 100644

> index 000000000000..d8b412b9200a

> --- /dev/null

> +++ b/EmbeddedPkg/Drivers/ConsolePrefDxe/ConsolePrefDxe.inf

> @@ -0,0 +1,62 @@

> +## @file

> +#

> +#  Copyright (c) 2017, Linaro, Ltd. All rights reserved.<BR>

> +#

> +#  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                 = ConsolePrefDxe

> +  FILE_GUID                 = bbe2668c-0efc-46fb-9137-4f2da8f419f3

> +  MODULE_TYPE               = DXE_DRIVER

> +  VERSION_STRING            = 1.0

> +  ENTRY_POINT               = ConsolePrefDxeEntryPoint

> +

> +#

> +# The following information is for reference only and not required by the build tools.

> +#

> +#  VALID_ARCHITECTURES      = IA32 X64 ARM AARCH64

> +#

> +

> +[Sources]

> +  ConsolePrefDxe.c

> +  ConsolePrefHii.vfr

> +  ConsolePrefHii.uni

> +

> +[Packages]

> +  EmbeddedPkg/EmbeddedPkg.dec

> +  MdePkg/MdePkg.dec

> +  MdeModulePkg/MdeModulePkg.dec

> +

> +[LibraryClasses]

> +  BaseLib

> +  DebugLib

> +  FdtLib

> +  HiiLib

> +  UefiBootServicesTableLib

> +  UefiDriverEntryPoint

> +  UefiLib

> +  UefiRuntimeServicesTableLib

> +

> +[Guids]

> +  gConsolePrefFormSetGuid

> +  gFdtTableGuid

> +  gEfiEventReadyToBootGuid

> +

> +[Protocols]

> +  gEfiAcpiTableProtocolGuid

> +  gEfiAcpiSdtProtocolGuid

> +  gEfiGraphicsOutputProtocolGuid

> +

> +[Depex]

> +  gEfiVariableArchProtocolGuid        AND

> +  gEfiVariableWriteArchProtocolGuid

> diff --git a/EmbeddedPkg/Drivers/ConsolePrefDxe/ConsolePrefHii.uni b/EmbeddedPkg/Drivers/ConsolePrefDxe/ConsolePrefHii.uni

> new file mode 100644

> index 000000000000..0442adf77163

> --- /dev/null

> +++ b/EmbeddedPkg/Drivers/ConsolePrefDxe/ConsolePrefHii.uni

> @@ -0,0 +1,27 @@

> +/** @file

> +*

> +*  Copyright (c) 2017, Linaro, Ltd. 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.

> +*

> +**/

> +

> +#langdef en-US  "English"

> +

> +#string STR_FORM_SET_TITLE             #language en-US "Console Preference Selection"

> +#string STR_FORM_SET_TITLE_HELP        #language en-US "Press <Enter> to choose between graphical and serial console."

> +

> +#string STR_MAIN_FORM_TITLE            #language en-US "Console Preference Selection"

> +#string STR_NULL_STRING                #language en-US ""

> +

> +#string STR_CONSOLE_PREF_SELECT_PROMPT #language en-US "Preferred console"

> +#string STR_CONSOLE_PREF_SELECT_HELP   #language en-US "Select the preferred console if both graphical and serial are available."

> +

> +#string STR_CONSOLE_PREF_GRAPHICAL     #language en-US "Graphical"

> +#string STR_CONSOLE_PREF_SERIAL        #language en-US "Serial"

> diff --git a/EmbeddedPkg/Drivers/ConsolePrefDxe/ConsolePrefHii.vfr b/EmbeddedPkg/Drivers/ConsolePrefDxe/ConsolePrefHii.vfr

> new file mode 100644

> index 000000000000..fdfba5cf4cb3

> --- /dev/null

> +++ b/EmbeddedPkg/Drivers/ConsolePrefDxe/ConsolePrefHii.vfr

> @@ -0,0 +1,51 @@

> +/** @file

> +*

> +*  Copyright (c) 2017, Linaro, Ltd. 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 "ConsolePrefDxe.h"

> +

> +//

> +// EFI Variable attributes

> +//

> +#define EFI_VARIABLE_NON_VOLATILE       0x00000001

> +#define EFI_VARIABLE_BOOTSERVICE_ACCESS 0x00000002

> +#define EFI_VARIABLE_RUNTIME_ACCESS     0x00000004

> +#define EFI_VARIABLE_READ_ONLY          0x00000008

> +

> +formset

> +  guid      = CONSOLE_PREF_FORMSET_GUID,

> +  title     = STRING_TOKEN(STR_FORM_SET_TITLE),

> +  help      = STRING_TOKEN(STR_FORM_SET_TITLE_HELP),

> +  classguid = EFI_HII_PLATFORM_SETUP_FORMSET_GUID,

> +

> +  efivarstore CONSOLE_PREF_VARSTORE_DATA,

> +    attribute = EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_NON_VOLATILE,  // EFI variable attributes

> +    name  = ConsolePref,

> +    guid  = CONSOLE_PREF_FORMSET_GUID;

> +

> +  form formid = 0x1000,

> +    title  = STRING_TOKEN(STR_MAIN_FORM_TITLE);

> +

> +    oneof varid = ConsolePref.Console,

> +        prompt      = STRING_TOKEN(STR_CONSOLE_PREF_SELECT_PROMPT),

> +        help        = STRING_TOKEN(STR_CONSOLE_PREF_SELECT_HELP),

> +        flags       = NUMERIC_SIZE_1 | INTERACTIVE,

> +        option text = STRING_TOKEN(STR_CONSOLE_PREF_GRAPHICAL), value = CONSOLE_PREF_GRAPHICAL, flags = DEFAULT;

> +        option text = STRING_TOKEN(STR_CONSOLE_PREF_SERIAL), value = CONSOLE_PREF_SERIAL, flags = 0;

> +    endoneof;

> +

> +    subtitle text = STRING_TOKEN(STR_NULL_STRING);

> +

> +  endform;

> +

> +endformset;

> -- 

> 2.11.0

> 

_______________________________________________
edk2-devel mailing list
edk2-devel@lists.01.org
https://lists.01.org/mailman/listinfo/edk2-devel
Ard Biesheuvel Oct. 20, 2017, 2:11 p.m. | #3
On 20 October 2017 at 14:50, Leif Lindholm <leif.lindholm@linaro.org> wrote:
> On Fri, Oct 20, 2017 at 02:33:37PM +0100, Ard Biesheuvel wrote:

>> Linux on ARM/arm64 will infer from the presence of a /chosen/stdout-path

>> DT property or of a SPCR ACPI table that the primary console is the serial

>> port, even if a graphical console is available as well.

>>

>> So let's introduce a driver that allows the user to set a preference

>> between graphical and serial if both are available. If the preference

>> is set to 'Graphical', and any GOP protocol instances have been installed

>> by the time the ReadyToBoot event is signalled, remove the DT property

>> and the table entirely.

>>

>> Contributed-under: TianoCore Contribution Agreement 1.1

>> Signed-off-by: Ard Biesheuvel <ard.biesheuvel@linaro.org>

>> ---

>>  EmbeddedPkg/Drivers/ConsolePrefDxe/ConsolePrefDxe.c   | 284 ++++++++++++++++++++

>>  EmbeddedPkg/Drivers/ConsolePrefDxe/ConsolePrefDxe.h   |  31 +++

>>  EmbeddedPkg/Drivers/ConsolePrefDxe/ConsolePrefDxe.inf |  62 +++++

>>  EmbeddedPkg/Drivers/ConsolePrefDxe/ConsolePrefHii.uni |  27 ++

>>  EmbeddedPkg/Drivers/ConsolePrefDxe/ConsolePrefHii.vfr |  51 ++++

>>  5 files changed, 455 insertions(+)

>>

>> diff --git a/EmbeddedPkg/Drivers/ConsolePrefDxe/ConsolePrefDxe.c b/EmbeddedPkg/Drivers/ConsolePrefDxe/ConsolePrefDxe.c

>> new file mode 100644

>> index 000000000000..cabe4f652cf5

>> --- /dev/null

>> +++ b/EmbeddedPkg/Drivers/ConsolePrefDxe/ConsolePrefDxe.c

>> @@ -0,0 +1,284 @@

>> +/** @file

>> +*

>> +*  Copyright (c) 2017, Linaro, Ltd. 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 <IndustryStandard/Acpi.h>

>> +#include <libfdt.h>

>> +#include <Library/BaseLib.h>

>> +#include <Library/DebugLib.h>

>> +#include <Library/DevicePathLib.h>

>> +#include <Library/HiiLib.h>

>> +#include <Library/UefiBootServicesTableLib.h>

>> +#include <Library/UefiBootServicesTableLib.h>

>> +#include <Library/UefiDriverEntryPoint.h>

>> +#include <Library/UefiLib.h>

>> +#include <Library/UefiRuntimeServicesTableLib.h>

>> +

>> +#include <Protocol/AcpiTable.h>

>> +#include <Protocol/AcpiSystemDescriptionTable.h>

>> +

>> +#include "ConsolePrefDxe.h"

>> +

>> +#define SPCR_SIG    EFI_ACPI_2_0_SERIAL_PORT_CONSOLE_REDIRECTION_TABLE_SIGNATURE

>> +

>> +extern  UINT8                     ConsolePrefHiiBin[];

>> +extern  UINT8                     ConsolePrefDxeStrings[];

>> +

>> +typedef struct {

>> +  VENDOR_DEVICE_PATH              VendorDevicePath;

>> +  EFI_DEVICE_PATH_PROTOCOL        End;

>> +} HII_VENDOR_DEVICE_PATH;

>> +

>> +STATIC HII_VENDOR_DEVICE_PATH     mConsolePrefDxeVendorDevicePath = {

>> +  {

>> +    {

>> +      HARDWARE_DEVICE_PATH,

>> +      HW_VENDOR_DP,

>> +      {

>> +        (UINT8) (sizeof (VENDOR_DEVICE_PATH)),

>> +        (UINT8) ((sizeof (VENDOR_DEVICE_PATH)) >> 8)

>> +      }

>> +    },

>> +    CONSOLE_PREF_FORMSET_GUID

>> +  },

>> +  {

>> +    END_DEVICE_PATH_TYPE,

>> +    END_ENTIRE_DEVICE_PATH_SUBTYPE,

>> +    {

>> +      (UINT8) (END_DEVICE_PATH_LENGTH),

>> +      (UINT8) ((END_DEVICE_PATH_LENGTH) >> 8)

>> +    }

>> +  }

>> +};

>> +

>> +STATIC EFI_EVENT                  mReadyToBootEvent;

>> +STATIC UINTN                      mSpcrTableKey;

>> +

>> +STATIC

>> +EFI_STATUS

>> +InstallHiiPages (

>> +  VOID

>> +  )

>> +{

>> +  EFI_STATUS                      Status;

>> +  EFI_HII_HANDLE                  HiiHandle;

>> +  EFI_HANDLE                      DriverHandle;

>> +

>> +  DriverHandle = NULL;

>> +  Status = gBS->InstallMultipleProtocolInterfaces (&DriverHandle,

>> +                  &gEfiDevicePathProtocolGuid,

>> +                  &mConsolePrefDxeVendorDevicePath,

>> +                  NULL);

>> +  if (EFI_ERROR (Status)) {

>> +    return Status;

>> +  }

>> +

>> +  HiiHandle = HiiAddPackages (&gConsolePrefFormSetGuid,

>> +                              DriverHandle,

>> +                              ConsolePrefDxeStrings,

>> +                              ConsolePrefHiiBin,

>> +                              NULL);

>> +

>> +  if (HiiHandle == NULL) {

>> +    gBS->UninstallMultipleProtocolInterfaces (DriverHandle,

>> +                  &gEfiDevicePathProtocolGuid,

>> +                  &mConsolePrefDxeVendorDevicePath,

>> +                  NULL);

>

> Something funky going on with indentation here.

>

> If you address that:

> Reviewed-by: Leif Lindholm <leif.lindholm@linaro.org>

>

> Thanks for putting this together.

>


Thanks. But it seems the SPCR handling is not robust yet: it worked
with ArmVirtQemu, but not with a baremetal platform, due to dispatch
order issues etc.
_______________________________________________
edk2-devel mailing list
edk2-devel@lists.01.org
https://lists.01.org/mailman/listinfo/edk2-devel

Patch

diff --git a/EmbeddedPkg/Drivers/ConsolePrefDxe/ConsolePrefDxe.c b/EmbeddedPkg/Drivers/ConsolePrefDxe/ConsolePrefDxe.c
new file mode 100644
index 000000000000..cabe4f652cf5
--- /dev/null
+++ b/EmbeddedPkg/Drivers/ConsolePrefDxe/ConsolePrefDxe.c
@@ -0,0 +1,284 @@ 
+/** @file
+*
+*  Copyright (c) 2017, Linaro, Ltd. 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 <IndustryStandard/Acpi.h>
+#include <libfdt.h>
+#include <Library/BaseLib.h>
+#include <Library/DebugLib.h>
+#include <Library/DevicePathLib.h>
+#include <Library/HiiLib.h>
+#include <Library/UefiBootServicesTableLib.h>
+#include <Library/UefiBootServicesTableLib.h>
+#include <Library/UefiDriverEntryPoint.h>
+#include <Library/UefiLib.h>
+#include <Library/UefiRuntimeServicesTableLib.h>
+
+#include <Protocol/AcpiTable.h>
+#include <Protocol/AcpiSystemDescriptionTable.h>
+
+#include "ConsolePrefDxe.h"
+
+#define SPCR_SIG    EFI_ACPI_2_0_SERIAL_PORT_CONSOLE_REDIRECTION_TABLE_SIGNATURE
+
+extern  UINT8                     ConsolePrefHiiBin[];
+extern  UINT8                     ConsolePrefDxeStrings[];
+
+typedef struct {
+  VENDOR_DEVICE_PATH              VendorDevicePath;
+  EFI_DEVICE_PATH_PROTOCOL        End;
+} HII_VENDOR_DEVICE_PATH;
+
+STATIC HII_VENDOR_DEVICE_PATH     mConsolePrefDxeVendorDevicePath = {
+  {
+    {
+      HARDWARE_DEVICE_PATH,
+      HW_VENDOR_DP,
+      {
+        (UINT8) (sizeof (VENDOR_DEVICE_PATH)),
+        (UINT8) ((sizeof (VENDOR_DEVICE_PATH)) >> 8)
+      }
+    },
+    CONSOLE_PREF_FORMSET_GUID
+  },
+  {
+    END_DEVICE_PATH_TYPE,
+    END_ENTIRE_DEVICE_PATH_SUBTYPE,
+    {
+      (UINT8) (END_DEVICE_PATH_LENGTH),
+      (UINT8) ((END_DEVICE_PATH_LENGTH) >> 8)
+    }
+  }
+};
+
+STATIC EFI_EVENT                  mReadyToBootEvent;
+STATIC UINTN                      mSpcrTableKey;
+
+STATIC
+EFI_STATUS
+InstallHiiPages (
+  VOID
+  )
+{
+  EFI_STATUS                      Status;
+  EFI_HII_HANDLE                  HiiHandle;
+  EFI_HANDLE                      DriverHandle;
+
+  DriverHandle = NULL;
+  Status = gBS->InstallMultipleProtocolInterfaces (&DriverHandle,
+                  &gEfiDevicePathProtocolGuid,
+                  &mConsolePrefDxeVendorDevicePath,
+                  NULL);
+  if (EFI_ERROR (Status)) {
+    return Status;
+  }
+
+  HiiHandle = HiiAddPackages (&gConsolePrefFormSetGuid,
+                              DriverHandle,
+                              ConsolePrefDxeStrings,
+                              ConsolePrefHiiBin,
+                              NULL);
+
+  if (HiiHandle == NULL) {
+    gBS->UninstallMultipleProtocolInterfaces (DriverHandle,
+                  &gEfiDevicePathProtocolGuid,
+                  &mConsolePrefDxeVendorDevicePath,
+                  NULL);
+    return EFI_OUT_OF_RESOURCES;
+  }
+  return EFI_SUCCESS;
+}
+
+STATIC
+VOID
+RemoveDtStdoutPath (
+  VOID
+)
+{
+  VOID        *Dtb;
+  INT32       Node;
+  INT32       Error;
+  EFI_STATUS  Status;
+
+  Status = EfiGetSystemConfigurationTable (&gFdtTableGuid, &Dtb);
+  if (EFI_ERROR (Status)) {
+    DEBUG ((DEBUG_INFO, "%a: could not retrieve DT blob - %r\n", __FUNCTION__,
+      Status));
+  }
+
+  Node = fdt_path_offset (Dtb, "/chosen");
+  if (Node < 0) {
+    return;
+  }
+
+  Error = fdt_delprop (Dtb, Node, "stdout-path");
+  if (Error) {
+    DEBUG ((DEBUG_INFO, "%a: Failed to delete 'stdout-path' property: %a\n",
+      __FUNCTION__, fdt_strerror (Error)));
+  }
+}
+
+STATIC
+VOID
+OnReadyToBoot (
+  IN EFI_EVENT  Event,
+  IN VOID       *Context
+  )
+{
+  CONSOLE_PREF_VARSTORE_DATA      ConsolePref;
+  UINTN                           BufferSize;
+  EFI_STATUS                      Status;
+  VOID                            *Gop;
+  EFI_ACPI_TABLE_PROTOCOL         *AcpiTable;
+
+  BufferSize = sizeof (ConsolePref);
+  Status = gRT->GetVariable (CONSOLE_PREF_VARIABLE_NAME,
+                  &gConsolePrefFormSetGuid, NULL, &BufferSize, &ConsolePref);
+  if (EFI_ERROR (Status)) {
+    DEBUG ((DEBUG_ERROR,
+      "%a: variable '%s' could not be read - bailing!\n", __FUNCTION__,
+      CONSOLE_PREF_VARIABLE_NAME));
+    return;
+  }
+
+  if (ConsolePref.Console == CONSOLE_PREF_SERIAL) {
+    DEBUG ((DEBUG_INFO,
+      "%a: serial console preferred - doing nothing\n", __FUNCTION__));
+    return;
+  }
+
+  //
+  // Check if any GOP instances exist: if so, disable stdout-path and SPCR
+  //
+  Status = gBS->LocateProtocol (&gEfiGraphicsOutputProtocolGuid, NULL, &Gop);
+  if (EFI_ERROR (Status)) {
+    DEBUG ((DEBUG_INFO,
+      "%a: no GOP instances found - doing nothing (%r)\n", __FUNCTION__,
+      Status));
+    return;
+  }
+
+  RemoveDtStdoutPath ();
+
+  if (mSpcrTableKey != 0) {
+    Status = gBS->LocateProtocol (&gEfiAcpiTableProtocolGuid, NULL,
+                    (VOID **)&AcpiTable);
+    ASSERT_EFI_ERROR (Status);
+
+    Status = AcpiTable->UninstallAcpiTable (AcpiTable, mSpcrTableKey);
+    if (EFI_ERROR (Status)) {
+      DEBUG ((DEBUG_WARN, "%a: failed to uninstall SPCR table - %r\n",
+        __FUNCTION__, Status));
+    }
+  }
+}
+
+STATIC
+EFI_STATUS
+OnInstallAcpiTable (
+  IN EFI_ACPI_SDT_HEADER    *Table,
+  IN EFI_ACPI_TABLE_VERSION Version,
+  IN UINTN                  TableKey
+  )
+{
+  if (Table->Signature == SPCR_SIG) {
+    mSpcrTableKey = TableKey;
+  }
+  return EFI_SUCCESS;
+}
+
+/**
+  The entry point for ConsolePrefDxe driver.
+
+  @param[in] ImageHandle     The image handle of the driver.
+  @param[in] SystemTable     The system table.
+
+  @retval EFI_ALREADY_STARTED     The driver already exists in system.
+  @retval EFI_OUT_OF_RESOURCES    Fail to execute entry point due to lack of
+                                  resources.
+  @retval EFI_SUCCES              All the related protocols are installed on
+                                  the driver.
+
+**/
+EFI_STATUS
+EFIAPI
+ConsolePrefDxeEntryPoint (
+  IN EFI_HANDLE                   ImageHandle,
+  IN EFI_SYSTEM_TABLE             *SystemTable
+  )
+{
+  EFI_STATUS                      Status;
+  CONSOLE_PREF_VARSTORE_DATA      ConsolePref;
+  UINTN                           BufferSize;
+  EFI_ACPI_SDT_PROTOCOL           *Sdt;
+
+  //
+  // Get the current console preference from the ConsolePref variable.
+  //
+  BufferSize = sizeof (ConsolePref);
+  Status = gRT->GetVariable (CONSOLE_PREF_VARIABLE_NAME,
+                  &gConsolePrefFormSetGuid, NULL, &BufferSize, &ConsolePref);
+  if (EFI_ERROR (Status)) {
+    DEBUG ((DEBUG_INFO,
+      "%a: no console preference found, defaulting to graphical\n",
+      __FUNCTION__));
+    ConsolePref.Console = CONSOLE_PREF_GRAPHICAL;
+  }
+
+  if (!EFI_ERROR (Status) &&
+      ConsolePref.Console != CONSOLE_PREF_GRAPHICAL &&
+      ConsolePref.Console != CONSOLE_PREF_SERIAL) {
+    DEBUG ((DEBUG_WARN, "%a: invalid value for %s, defaulting to graphical\n",
+      __FUNCTION__, CONSOLE_PREF_VARIABLE_NAME));
+    ConsolePref.Console = CONSOLE_PREF_GRAPHICAL;
+    Status = EFI_INVALID_PARAMETER; // trigger setvar below
+  }
+
+  //
+  // Write the newly selected default value back to the variable store.
+  //
+  if (EFI_ERROR (Status)) {
+    ZeroMem (&ConsolePref.Reserved, sizeof (ConsolePref.Reserved));
+    Status = gRT->SetVariable (CONSOLE_PREF_VARIABLE_NAME,
+                    &gConsolePrefFormSetGuid,
+                    EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_BOOTSERVICE_ACCESS,
+                    sizeof (ConsolePref), &ConsolePref);
+
+    if (EFI_ERROR (Status)) {
+      DEBUG ((DEBUG_ERROR, "%a: gRT->SetVariable () failed - %r\n",
+        __FUNCTION__, Status));
+      return Status;
+    }
+  }
+
+  Status = gBS->LocateProtocol (&gEfiAcpiSdtProtocolGuid, NULL, (VOID **)&Sdt);
+  if (!EFI_ERROR (Status)) {
+    //
+    // If we have the SDT protocol, use it to register a ACPI table
+    // installation notification callback so we can record the table
+    // key of the SPCR table.
+    //
+    Status = Sdt->RegisterNotify (TRUE, OnInstallAcpiTable);
+    if (EFI_ERROR (Status)) {
+      DEBUG ((DEBUG_WARN, "%a: Sdt->RegisterNotify () failed - %r\n",
+        __FUNCTION__, Status));
+    }
+  }
+
+  Status = gBS->CreateEventEx (EVT_NOTIFY_SIGNAL, TPL_CALLBACK,
+                  OnReadyToBoot, NULL, &gEfiEventReadyToBootGuid,
+                  &mReadyToBootEvent);
+  ASSERT_EFI_ERROR (Status);
+
+  return InstallHiiPages ();
+}
diff --git a/EmbeddedPkg/Drivers/ConsolePrefDxe/ConsolePrefDxe.h b/EmbeddedPkg/Drivers/ConsolePrefDxe/ConsolePrefDxe.h
new file mode 100644
index 000000000000..7ec420f89013
--- /dev/null
+++ b/EmbeddedPkg/Drivers/ConsolePrefDxe/ConsolePrefDxe.h
@@ -0,0 +1,31 @@ 
+/** @file
+*
+*  Copyright (c) 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.
+*
+**/
+
+#ifndef __CONSOLE_PREF_DXE_H__
+#define __CONSOLE_PREF_DXE_H__
+
+#include <Guid/HiiPlatformSetupFormset.h>
+#include <Guid/ConsolePrefFormSet.h>
+
+#define CONSOLE_PREF_GRAPHICAL      0x0
+#define CONSOLE_PREF_SERIAL         0x1
+
+#define CONSOLE_PREF_VARIABLE_NAME  L"ConsolePref"
+
+typedef struct {
+  UINT8         Console;
+  UINT8         Reserved[3];
+} CONSOLE_PREF_VARSTORE_DATA;
+
+#endif
diff --git a/EmbeddedPkg/Drivers/ConsolePrefDxe/ConsolePrefDxe.inf b/EmbeddedPkg/Drivers/ConsolePrefDxe/ConsolePrefDxe.inf
new file mode 100644
index 000000000000..d8b412b9200a
--- /dev/null
+++ b/EmbeddedPkg/Drivers/ConsolePrefDxe/ConsolePrefDxe.inf
@@ -0,0 +1,62 @@ 
+## @file
+#
+#  Copyright (c) 2017, Linaro, Ltd. All rights reserved.<BR>
+#
+#  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                 = ConsolePrefDxe
+  FILE_GUID                 = bbe2668c-0efc-46fb-9137-4f2da8f419f3
+  MODULE_TYPE               = DXE_DRIVER
+  VERSION_STRING            = 1.0
+  ENTRY_POINT               = ConsolePrefDxeEntryPoint
+
+#
+# The following information is for reference only and not required by the build tools.
+#
+#  VALID_ARCHITECTURES      = IA32 X64 ARM AARCH64
+#
+
+[Sources]
+  ConsolePrefDxe.c
+  ConsolePrefHii.vfr
+  ConsolePrefHii.uni
+
+[Packages]
+  EmbeddedPkg/EmbeddedPkg.dec
+  MdePkg/MdePkg.dec
+  MdeModulePkg/MdeModulePkg.dec
+
+[LibraryClasses]
+  BaseLib
+  DebugLib
+  FdtLib
+  HiiLib
+  UefiBootServicesTableLib
+  UefiDriverEntryPoint
+  UefiLib
+  UefiRuntimeServicesTableLib
+
+[Guids]
+  gConsolePrefFormSetGuid
+  gFdtTableGuid
+  gEfiEventReadyToBootGuid
+
+[Protocols]
+  gEfiAcpiTableProtocolGuid
+  gEfiAcpiSdtProtocolGuid
+  gEfiGraphicsOutputProtocolGuid
+
+[Depex]
+  gEfiVariableArchProtocolGuid        AND
+  gEfiVariableWriteArchProtocolGuid
diff --git a/EmbeddedPkg/Drivers/ConsolePrefDxe/ConsolePrefHii.uni b/EmbeddedPkg/Drivers/ConsolePrefDxe/ConsolePrefHii.uni
new file mode 100644
index 000000000000..0442adf77163
--- /dev/null
+++ b/EmbeddedPkg/Drivers/ConsolePrefDxe/ConsolePrefHii.uni
@@ -0,0 +1,27 @@ 
+/** @file
+*
+*  Copyright (c) 2017, Linaro, Ltd. 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.
+*
+**/
+
+#langdef en-US  "English"
+
+#string STR_FORM_SET_TITLE             #language en-US "Console Preference Selection"
+#string STR_FORM_SET_TITLE_HELP        #language en-US "Press <Enter> to choose between graphical and serial console."
+
+#string STR_MAIN_FORM_TITLE            #language en-US "Console Preference Selection"
+#string STR_NULL_STRING                #language en-US ""
+
+#string STR_CONSOLE_PREF_SELECT_PROMPT #language en-US "Preferred console"
+#string STR_CONSOLE_PREF_SELECT_HELP   #language en-US "Select the preferred console if both graphical and serial are available."
+
+#string STR_CONSOLE_PREF_GRAPHICAL     #language en-US "Graphical"
+#string STR_CONSOLE_PREF_SERIAL        #language en-US "Serial"
diff --git a/EmbeddedPkg/Drivers/ConsolePrefDxe/ConsolePrefHii.vfr b/EmbeddedPkg/Drivers/ConsolePrefDxe/ConsolePrefHii.vfr
new file mode 100644
index 000000000000..fdfba5cf4cb3
--- /dev/null
+++ b/EmbeddedPkg/Drivers/ConsolePrefDxe/ConsolePrefHii.vfr
@@ -0,0 +1,51 @@ 
+/** @file
+*
+*  Copyright (c) 2017, Linaro, Ltd. 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 "ConsolePrefDxe.h"
+
+//
+// EFI Variable attributes
+//
+#define EFI_VARIABLE_NON_VOLATILE       0x00000001
+#define EFI_VARIABLE_BOOTSERVICE_ACCESS 0x00000002
+#define EFI_VARIABLE_RUNTIME_ACCESS     0x00000004
+#define EFI_VARIABLE_READ_ONLY          0x00000008
+
+formset
+  guid      = CONSOLE_PREF_FORMSET_GUID,
+  title     = STRING_TOKEN(STR_FORM_SET_TITLE),
+  help      = STRING_TOKEN(STR_FORM_SET_TITLE_HELP),
+  classguid = EFI_HII_PLATFORM_SETUP_FORMSET_GUID,
+
+  efivarstore CONSOLE_PREF_VARSTORE_DATA,
+    attribute = EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_NON_VOLATILE,  // EFI variable attributes
+    name  = ConsolePref,
+    guid  = CONSOLE_PREF_FORMSET_GUID;
+
+  form formid = 0x1000,
+    title  = STRING_TOKEN(STR_MAIN_FORM_TITLE);
+
+    oneof varid = ConsolePref.Console,
+        prompt      = STRING_TOKEN(STR_CONSOLE_PREF_SELECT_PROMPT),
+        help        = STRING_TOKEN(STR_CONSOLE_PREF_SELECT_HELP),
+        flags       = NUMERIC_SIZE_1 | INTERACTIVE,
+        option text = STRING_TOKEN(STR_CONSOLE_PREF_GRAPHICAL), value = CONSOLE_PREF_GRAPHICAL, flags = DEFAULT;
+        option text = STRING_TOKEN(STR_CONSOLE_PREF_SERIAL), value = CONSOLE_PREF_SERIAL, flags = 0;
+    endoneof;
+
+    subtitle text = STRING_TOKEN(STR_NULL_STRING);
+
+  endform;
+
+endformset;