Files
system76-edk2/ArmPlatformPkg/ArmJunoPkg/Drivers/ArmJunoDxe/ArmJunoDxe.c
Ronald Cron c1fee786c1 ArmPlatformPkg/ArmJunoDxe: Add PCI GBE MAC address to Juno R1 boot options
On Juno R1, the MAC address assigned to the PCI Gigabyte Ethernet device
as to be passed to the Linux Kernel.

The MAC address is passed to the Linux Kernel by means of the boot argument
"sky2.mac_address".

This patch adds this boot argument to the lists of boot arguments of the
two Juno R1 default boot options.

Contributed-under: TianoCore Contribution Agreement 1.0
Signed-off-by: Ronald Cron <ronald.cron@arm.com>
Reviewed-by: Olivier Martin <olivier.martin@arm.com>




git-svn-id: https://svn.code.sf.net/p/edk2/code/trunk/edk2@17095 6f19259b-4bc3-4df7-8a09-765794883524
2015-04-01 14:46:52 +00:00

433 lines
14 KiB
C

/** @file
*
* Copyright (c) 2013-2015, ARM 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 "ArmJunoDxeInternal.h"
#include <ArmPlatform.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>
#include <Library/IoLib.h>
#include <Library/PrintLib.h>
//
// Size in number of characters of the Linux boot argument
// passing the MAC address to be used by the PCI GigaByte
// Ethernet device : " sky2.mac_address=0x11,0x22,0x33,0x44,0x55,0x66"
//
#define SKY2_MAC_ADDRESS_BOOTARG_LEN 47
//
// Hardware platform identifiers
//
typedef enum {
UNKNOWN,
JUNO_R0,
JUNO_R1
} JUNO_REVISION;
//
// Function prototypes
//
STATIC EFI_STATUS SetJunoR1DefaultBootEntries (
VOID
);
// 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 (
IN EFI_HANDLE ImageHandle,
IN EFI_SYSTEM_TABLE *SystemTable
)
{
EFI_STATUS Status;
EFI_PHYSICAL_ADDRESS HypBase;
CHAR16 *TextDevicePath;
UINTN TextDevicePathSize;
VOID *Buffer;
UINT32 Midr;
UINT32 CpuType;
UINT32 CpuRev;
JUNO_REVISION JunoRevision;
JunoRevision = UNKNOWN;
Status = PciEmulationEntryPoint ();
if (EFI_ERROR (Status)) {
return Status;
}
//
// If a hypervisor has been declared then we need to make sure its region is protected at runtime
//
// Note: This code is only a workaround for our dummy hypervisor (ArmPkg/Extra/AArch64ToAArch32Shim/)
// that does not set up (yet) the stage 2 translation table to hide its own memory to EL1.
//
if (FixedPcdGet32 (PcdHypFvSize) != 0) {
// Ensure the hypervisor region is strictly contained into a EFI_PAGE_SIZE-aligned region.
// The memory must be a multiple of EFI_PAGE_SIZE to ensure we do not reserve more memory than the hypervisor itself.
// A UEFI Runtime region size granularity cannot be smaller than EFI_PAGE_SIZE. If the hypervisor size is not rounded
// to this size then there is a risk some non-runtime memory could be visible to the OS view.
if (((FixedPcdGet32 (PcdHypFvSize) & EFI_PAGE_MASK) == 0) && ((FixedPcdGet32 (PcdHypFvBaseAddress) & EFI_PAGE_MASK) == 0)) {
// The memory needs to be declared because the DXE core marked it as reserved and removed it from the memory space
// as it contains the Firmware.
Status = gDS->AddMemorySpace (
EfiGcdMemoryTypeSystemMemory,
FixedPcdGet32 (PcdHypFvBaseAddress), FixedPcdGet32 (PcdHypFvSize),
EFI_MEMORY_WB | EFI_MEMORY_RUNTIME
);
if (!EFI_ERROR (Status)) {
// We allocate the memory to ensure it is marked as runtime memory
HypBase = FixedPcdGet32 (PcdHypFvBaseAddress);
Status = gBS->AllocatePages (AllocateAddress, EfiRuntimeServicesCode,
EFI_SIZE_TO_PAGES (FixedPcdGet32 (PcdHypFvSize)), &HypBase);
}
} else {
// The hypervisor must be contained into a EFI_PAGE_SIZE-aligned region and its size must also be aligned
// on a EFI_PAGE_SIZE boundary (ie: 4KB).
Status = EFI_UNSUPPORTED;
ASSERT_EFI_ERROR (Status);
}
if (EFI_ERROR (Status)) {
return Status;
}
}
// Install dynamic Shell command to run baremetal binaries.
Status = ShellDynCmdRunAxfInstall (ImageHandle);
if (EFI_ERROR (Status)) {
DEBUG ((EFI_D_ERROR, "ArmJunoDxe: Failed to install ShellDynCmdRunAxf\n"));
}
//
// We detect whether we are running on a Juno r0 or Juno r1 board at
// 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;
switch (CpuType) {
case ARM_CPU_TYPE_A53:
if (CpuRev == ARM_CPU_REV (0, 0)) {
JunoRevision = JUNO_R0;
} else if (CpuRev == ARM_CPU_REV (0, 3)) {
JunoRevision = JUNO_R1;
}
break;
case ARM_CPU_TYPE_A57:
if (CpuRev == ARM_CPU_REV (0, 0)) {
JunoRevision = JUNO_R0;
} else if (CpuRev == ARM_CPU_REV (1, 1)) {
JunoRevision = JUNO_R1;
}
}
//
// Set the R1 two boot options if not already done.
//
if (JunoRevision == JUNO_R1) {
Status = SetJunoR1DefaultBootEntries ();
if (EFI_ERROR (Status)) {
return Status;
}
}
//
// Set up the device path to the FDT.
//
switch (JunoRevision) {
case JUNO_R0:
TextDevicePath = (CHAR16*)FixedPcdGetPtr (PcdJunoR0FdtDevicePath);
break;
case JUNO_R1:
TextDevicePath = (CHAR16*)FixedPcdGetPtr (PcdJunoR1A57x2FdtDevicePath);
break;
default:
TextDevicePath = NULL;
}
if (TextDevicePath != NULL) {
TextDevicePathSize = StrSize (TextDevicePath);
Buffer = PcdSetPtr (PcdFdtDevicePaths, &TextDevicePathSize, TextDevicePath);
Status = (Buffer != NULL) ? EFI_SUCCESS : EFI_BUFFER_TOO_SMALL;
} else {
Status = EFI_NOT_FOUND;
}
if (EFI_ERROR (Status)) {
DEBUG (
(EFI_D_ERROR,
"ArmJunoDxe: Setting of FDT device path in PcdFdtDevicePaths failed - %r\n", Status)
);
return Status;
}
// Try to install the ACPI Tables
Status = LocateAndInstallAcpiFromFv (&mJunoAcpiTableFile);
return Status;
}
/**
* If no boot entry is currently defined, define the two default boot entries
* for Juno R1.
*
* @return EFI_SUCCESS Some boot entries were already defined or
* the default boot entries were set successfully.
* @return EFI_OUT_OF_RESOURCES A memory allocation failed.
* @return EFI_DEVICE_ERROR An UEFI variable could not be saved due to a hardware failure.
* @return EFI_WRITE_PROTECTED An UEFI variable is read-only.
* @return EFI_SECURITY_VIOLATION An UEFI variable could not be written.
*/
STATIC
EFI_STATUS
SetJunoR1DefaultBootEntries (
VOID
)
{
EFI_STATUS Status;
CONST CHAR16* ExtraBootArgument = L" dtb=juno-r1-ca57x2_ca53x4.dtb";
UINTN Size;
EFI_DEVICE_PATH_FROM_TEXT_PROTOCOL *EfiDevicePathFromTextProtocol;
EFI_DEVICE_PATH* BootDevicePath;
UINT32 SysPciGbeL;
UINT32 SysPciGbeH;
CHAR16* DefaultBootArgument;
CHAR16* DefaultBootArgument1;
UINTN DefaultBootArgument1Size;
CHAR16* DefaultBootArgument2;
UINTN DefaultBootArgument2Size;
UINT16 BootOrder[2];
BootDevicePath = NULL;
DefaultBootArgument1 = NULL;
DefaultBootArgument2 = NULL;
//
// 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) {
return Status;
}
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)
);
if (BootDevicePath == NULL) {
return EFI_UNSUPPORTED;
}
DefaultBootArgument = (CHAR16*)PcdGetPtr (PcdDefaultBootArgument);
DefaultBootArgument1Size = StrSize (DefaultBootArgument) +
(SKY2_MAC_ADDRESS_BOOTARG_LEN * sizeof (CHAR16));
DefaultBootArgument2Size = DefaultBootArgument1Size + StrSize (ExtraBootArgument);
Status = EFI_OUT_OF_RESOURCES;
DefaultBootArgument1 = AllocatePool (DefaultBootArgument1Size);
if (DefaultBootArgument1 == NULL) {
goto Error;
}
DefaultBootArgument2 = AllocatePool (DefaultBootArgument2Size);
if (DefaultBootArgument2 == NULL) {
goto Error;
}
SysPciGbeL = MmioRead32 (ARM_JUNO_SYS_PCIGBE_L);
SysPciGbeH = MmioRead32 (ARM_JUNO_SYS_PCIGBE_H);
UnicodeSPrint (
DefaultBootArgument1,
DefaultBootArgument1Size,
L"%s sky2.mac_address=0x%02x,0x%02x,0x%02x,0x%02x,0x%02x,0x%02x",
DefaultBootArgument,
(SysPciGbeH >> 8 ) & 0xFF, (SysPciGbeH ) & 0xFF,
(SysPciGbeL >> 24) & 0xFF, (SysPciGbeL >> 16) & 0xFF,
(SysPciGbeL >> 8 ) & 0xFF, (SysPciGbeL ) & 0xFF
);
CopyMem (DefaultBootArgument2, DefaultBootArgument1, DefaultBootArgument1Size);
CopyMem (
(UINT8*)DefaultBootArgument2 + DefaultBootArgument1Size - 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*)DefaultBootArgument1, DefaultBootArgument1Size
);
if (EFI_ERROR (Status)) {
ASSERT (TRUE);
goto Error;
}
//
// Create Boot0002 environment variable
//
Status = BootOptionCreate (
L"Boot0002", LOAD_OPTION_ACTIVE | LOAD_OPTION_CATEGORY_BOOT,
L"Linux with A57x2_A53x4", BootDevicePath,
(UINT8*)DefaultBootArgument2, DefaultBootArgument2Size
);
if (EFI_ERROR (Status)) {
ASSERT (TRUE);
goto Error;
}
//
// 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
);
Error:
if (BootDevicePath != NULL) {
FreePool (BootDevicePath);
}
if (DefaultBootArgument1 != NULL) {
FreePool (DefaultBootArgument1);
}
if (DefaultBootArgument2 != NULL) {
FreePool (DefaultBootArgument2);
}
if (EFI_ERROR (Status)) {
DEBUG ((
EFI_D_ERROR,
"ArmJunoDxe - The setting of the default boot entries failed - %r\n",
Status
));
}
return Status;
}