summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorOlivier Martin <olivier.martin@arm.com>2015-02-26 11:04:52 +0000
committeroliviermartin <oliviermartin@Edk2>2015-02-26 11:04:52 +0000
commit6d60dfea870182cfed9bfe612316619786afb848 (patch)
tree9069475a65c4a96d11ca4be7f2853004e0b58488
parent1ccc0fd73ffe0c69f6c281ca03637576d4004170 (diff)
downloadedk2-6d60dfea870182cfed9bfe612316619786afb848.zip
edk2-6d60dfea870182cfed9bfe612316619786afb848.tar.gz
edk2-6d60dfea870182cfed9bfe612316619786afb848.tar.bz2
ArmPlatformPkg/ArmJunoPkg: Create two default boot entries on first boot on Juno R1
Juno R1 can run in two configurations: - A57x2 - A57x2-A53x4 The Device Tree tell Linux which configuration has been selected. Contributed-under: TianoCore Contribution Agreement 1.0 Signed-off-by: Olivier Martin <olivier.martin@arm.com> git-svn-id: https://svn.code.sf.net/p/edk2/code/trunk/edk2@16942 6f19259b-4bc3-4df7-8a09-765794883524
-rw-r--r--ArmPlatformPkg/ArmJunoPkg/Drivers/ArmJunoDxe/ArmJunoDxe.c161
-rw-r--r--ArmPlatformPkg/ArmJunoPkg/Drivers/ArmJunoDxe/ArmJunoDxe.inf6
2 files changed, 163 insertions, 4 deletions
diff --git a/ArmPlatformPkg/ArmJunoPkg/Drivers/ArmJunoDxe/ArmJunoDxe.c b/ArmPlatformPkg/ArmJunoPkg/Drivers/ArmJunoDxe/ArmJunoDxe.c
index 4b91f1e..e94047a 100644
--- a/ArmPlatformPkg/ArmJunoPkg/Drivers/ArmJunoDxe/ArmJunoDxe.c
+++ b/ArmPlatformPkg/ArmJunoPkg/Drivers/ArmJunoDxe/ArmJunoDxe.c
@@ -13,12 +13,90 @@
**/
#include "ArmJunoDxeInternal.h"
+
+#include <Protocol/DevicePathFromText.h>
+
+#include <Guid/GlobalVariable.h>
+
#include <Library/ArmShellCmdLib.h>
#include <Library/AcpiLib.h>
+#include <Library/BaseMemoryLib.h>
+#include <Library/DevicePathLib.h>
+#include <Library/MemoryAllocationLib.h>
+#include <Library/UefiRuntimeServicesTableLib.h>
// This GUID must match the FILE_GUID in ArmPlatformPkg/ArmJunoPkg/AcpiTables/AcpiTables.inf
STATIC CONST EFI_GUID mJunoAcpiTableFile = { 0xa1dd808e, 0x1e95, 0x4399, { 0xab, 0xc0, 0x65, 0x3c, 0x82, 0xe8, 0x53, 0x0c } };
+/**
+ * Build and Set UEFI Variable Boot####
+ *
+ * @param BootVariableName Name of the UEFI Variable
+ * @param Attributes 'Attributes' for the Boot#### variable as per UEFI spec
+ * @param BootDescription Description of the Boot#### variable
+ * @param DevicePath EFI Device Path of the EFI Application to boot
+ * @param OptionalData Parameters to pass to the EFI application
+ * @param OptionalDataSize Size of the parameters to pass to the EFI application
+ *
+ * @return EFI_OUT_OF_RESOURCES A memory allocation failed
+ * @return Return value of RT.SetVariable
+ */
+STATIC
+EFI_STATUS
+BootOptionCreate (
+ IN CHAR16 BootVariableName[9],
+ IN UINT32 Attributes,
+ IN CHAR16* BootDescription,
+ IN EFI_DEVICE_PATH_PROTOCOL* DevicePath,
+ IN UINT8* OptionalData,
+ IN UINTN OptionalDataSize
+ )
+{
+ UINTN VariableSize;
+ UINT8 *Variable;
+ UINT8 *VariablePtr;
+ UINTN FilePathListLength;
+ UINTN BootDescriptionSize;
+
+ FilePathListLength = GetDevicePathSize (DevicePath);
+ BootDescriptionSize = StrSize (BootDescription);
+
+ // Each Boot#### variable is built as follow:
+ // UINT32 Attributes
+ // UINT16 FilePathListLength
+ // CHAR16* Description
+ // EFI_DEVICE_PATH_PROTOCOL FilePathList[]
+ // UINT8 OptionalData[]
+ VariableSize = sizeof (UINT32) + sizeof (UINT16) +
+ BootDescriptionSize + FilePathListLength + OptionalDataSize;
+ Variable = AllocateZeroPool (VariableSize);
+ if (Variable == NULL) {
+ return EFI_OUT_OF_RESOURCES;
+ }
+
+ // 'Attributes' field
+ *(UINT32*)Variable = Attributes;
+ // 'FilePathListLength' field
+ VariablePtr = Variable + sizeof (UINT32);
+ *(UINT16*)VariablePtr = FilePathListLength;
+ // 'Description' field
+ VariablePtr += sizeof (UINT16);
+ CopyMem (VariablePtr, BootDescription, BootDescriptionSize);
+ // 'FilePathList' field
+ VariablePtr += BootDescriptionSize;
+ CopyMem (VariablePtr, DevicePath, FilePathListLength);
+ // 'OptionalData' field
+ VariablePtr += FilePathListLength;
+ CopyMem (VariablePtr, OptionalData, OptionalDataSize);
+
+ return gRT->SetVariable (
+ BootVariableName,
+ &gEfiGlobalVariableGuid,
+ EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS,
+ VariableSize, Variable
+ );
+}
+
EFI_STATUS
EFIAPI
ArmJunoEntryPoint (
@@ -34,6 +112,7 @@ ArmJunoEntryPoint (
UINT32 Midr;
UINT32 CpuType;
UINT32 CpuRev;
+ BOOLEAN IsJunoR1;
Status = PciEmulationEntryPoint ();
if (EFI_ERROR (Status)) {
@@ -89,10 +168,11 @@ ArmJunoEntryPoint (
// runtime by checking the value of the MIDR register.
//
- Midr = ArmReadMidr ();
- CpuType = (Midr >> ARM_CPU_TYPE_SHIFT) & ARM_CPU_TYPE_MASK;
- CpuRev = Midr & ARM_CPU_REV_MASK;
+ Midr = ArmReadMidr ();
+ CpuType = (Midr >> ARM_CPU_TYPE_SHIFT) & ARM_CPU_TYPE_MASK;
+ CpuRev = Midr & ARM_CPU_REV_MASK;
TextDevicePath = NULL;
+ IsJunoR1 = FALSE;
switch (CpuType) {
case ARM_CPU_TYPE_A53:
@@ -100,6 +180,7 @@ ArmJunoEntryPoint (
TextDevicePath = (CHAR16*)FixedPcdGetPtr (PcdJunoR0FdtDevicePath);
} else if (CpuRev == ARM_CPU_REV (0, 3)) {
TextDevicePath = (CHAR16*)FixedPcdGetPtr (PcdJunoR1A57x2FdtDevicePath);
+ IsJunoR1 = TRUE;
}
break;
@@ -108,6 +189,7 @@ ArmJunoEntryPoint (
TextDevicePath = (CHAR16*)FixedPcdGetPtr (PcdJunoR0FdtDevicePath);
} else if (CpuRev == ARM_CPU_REV (1, 1)) {
TextDevicePath = (CHAR16*)FixedPcdGetPtr (PcdJunoR1A57x2FdtDevicePath);
+ IsJunoR1 = TRUE;
}
}
@@ -130,5 +212,78 @@ ArmJunoEntryPoint (
// Try to install the ACPI Tables
Status = LocateAndInstallAcpiFromFv (&mJunoAcpiTableFile);
+ //
+ // If Juno R1 and it is the first boot then default boot entries will be created
+ //
+ if (IsJunoR1) {
+ CONST CHAR16* ExtraBootArgument = L" dtb=juno-r1-ca57x2_ca53x4.dtb";
+ UINTN Size;
+ EFI_DEVICE_PATH_FROM_TEXT_PROTOCOL* EfiDevicePathFromTextProtocol;
+ EFI_DEVICE_PATH* BootDevicePath;
+ CHAR16* DefaultBootArgument;
+ UINTN DefaultBootArgumentSize;
+ CHAR16* DefaultBootArgument2;
+ UINTN DefaultBootArgument2Size;
+ UINT16 BootOrder[2];
+
+ // Because the driver has a dependency on gEfiVariable(Write)ArchProtocolGuid (see [Depex]
+ // section of the INF file), we know we can safely access the UEFI Variable at that stage.
+ Size = 0;
+ Status = gRT->GetVariable (L"BootOrder", &gEfiGlobalVariableGuid, NULL, &Size, NULL);
+ if (Status == EFI_NOT_FOUND) {
+ Status = gBS->LocateProtocol (&gEfiDevicePathFromTextProtocolGuid, NULL, (VOID **)&EfiDevicePathFromTextProtocol);
+ if (EFI_ERROR (Status)) {
+ // You must provide an implementation of DevicePathFromTextProtocol in your firmware (eg: DevicePathDxe)
+ DEBUG ((EFI_D_ERROR, "Error: Require DevicePathFromTextProtocol\n"));
+ return Status;
+ }
+ // We use the same default kernel
+ BootDevicePath = EfiDevicePathFromTextProtocol->ConvertTextToDevicePath ((CHAR16*)PcdGetPtr (PcdDefaultBootDevicePath));
+
+ // Create the entry if the Default values are correct
+ if (BootDevicePath != NULL) {
+ DefaultBootArgument = (CHAR16*)PcdGetPtr (PcdDefaultBootArgument);
+ DefaultBootArgumentSize = StrSize (DefaultBootArgument);
+ DefaultBootArgument2Size = DefaultBootArgumentSize + StrSize (ExtraBootArgument);
+
+ DefaultBootArgument2 = AllocatePool (DefaultBootArgument2Size);
+ if (DefaultBootArgument2 == NULL) {
+ FreePool (BootDevicePath);
+ return EFI_OUT_OF_RESOURCES;
+ }
+ CopyMem (DefaultBootArgument2, DefaultBootArgument, DefaultBootArgumentSize);
+ CopyMem ((UINT8*)DefaultBootArgument2 + (StrLen (DefaultBootArgument2) * sizeof (CHAR16)), ExtraBootArgument, StrSize (ExtraBootArgument));
+
+ // Create Boot0001 environment variable
+ Status = BootOptionCreate (L"Boot0001", LOAD_OPTION_ACTIVE | LOAD_OPTION_CATEGORY_BOOT,
+ L"Linux with A57x2", BootDevicePath,
+ (UINT8*)DefaultBootArgument, DefaultBootArgumentSize);
+ ASSERT_EFI_ERROR (Status);
+
+ // Create Boot0002 environment variable
+ Status = BootOptionCreate (L"Boot0002", LOAD_OPTION_ACTIVE | LOAD_OPTION_CATEGORY_BOOT,
+ L"Linux with A57x2_A53x4", BootDevicePath,
+ (UINT8*)DefaultBootArgument2, DefaultBootArgument2Size);
+ ASSERT_EFI_ERROR (Status);
+
+ // Add the new Boot Index to the list
+ BootOrder[0] = 1; // Boot0001
+ BootOrder[1] = 2; // Boot0002
+ Status = gRT->SetVariable (
+ L"BootOrder",
+ &gEfiGlobalVariableGuid,
+ EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS,
+ sizeof (BootOrder),
+ BootOrder
+ );
+
+ FreePool (BootDevicePath);
+ FreePool (DefaultBootArgument2);
+ } else {
+ Status = EFI_UNSUPPORTED;
+ }
+ }
+ }
+
return Status;
}
diff --git a/ArmPlatformPkg/ArmJunoPkg/Drivers/ArmJunoDxe/ArmJunoDxe.inf b/ArmPlatformPkg/ArmJunoPkg/Drivers/ArmJunoDxe/ArmJunoDxe.inf
index 370edcb..ea1738b 100644
--- a/ArmPlatformPkg/ArmJunoPkg/Drivers/ArmJunoDxe/ArmJunoDxe.inf
+++ b/ArmPlatformPkg/ArmJunoPkg/Drivers/ArmJunoDxe/ArmJunoDxe.inf
@@ -73,8 +73,12 @@
gArmJunoTokenSpaceGuid.PcdJunoR1A57x2FdtDevicePath
gArmJunoTokenSpaceGuid.PcdJunoR1A57x2A53x4FdtDevicePath
+ gArmPlatformTokenSpaceGuid.PcdDefaultBootDevicePath
+ gArmPlatformTokenSpaceGuid.PcdDefaultBootArgument
+
[Pcd]
gEmbeddedTokenSpaceGuid.PcdFdtDevicePaths
[Depex]
- TRUE
+ # We depend on these protocols to create the default boot entries
+ gEfiVariableArchProtocolGuid AND gEfiVariableWriteArchProtocolGuid