Merge "QcomModulePkg: Implement Scm Mode switch protocol"
diff --git a/QcomModulePkg/Include/Library/UpdateDeviceTree.h b/QcomModulePkg/Include/Library/UpdateDeviceTree.h
index dbe4cba..a6d8262 100644
--- a/QcomModulePkg/Include/Library/UpdateDeviceTree.h
+++ b/QcomModulePkg/Include/Library/UpdateDeviceTree.h
@@ -44,6 +44,7 @@
#define MSMCOBALT_PGOOD_FUSE 0x78013C
#define MSMCOBALT_PGOOD_SUBBIN_FUSE 0x780324
+#define DTB_OFFSET_LOCATION_IN_ARCH32_KERNEL_HDR 0x2C
#define PARTIAL_GOOD_GOLD_DISABLE 0x1
diff --git a/QcomModulePkg/Library/BootLib/BootLib.inf b/QcomModulePkg/Library/BootLib/BootLib.inf
index 1feca8e..34ceaab 100644
--- a/QcomModulePkg/Library/BootLib/BootLib.inf
+++ b/QcomModulePkg/Library/BootLib/BootLib.inf
@@ -130,6 +130,7 @@
gQcomChargerExProtocolGuid
gEfiLimitsProtocolGuid
gEfiQcomVerifiedBootProtocolGuid
+ gQcomScmModeSwithProtocolGuid
[FixedPcd]
gArmTokenSpaceGuid.PcdSystemMemoryBase
@@ -140,6 +141,7 @@
gQcomTokenSpaceGuid.RamdiskEndAddress
gQcomTokenSpaceGuid.EnablePartialGoods
gQcomTokenSpaceGuid.EnableDisplayMenu
+ gQcomTokenSpaceGuid.KernelLoadAddress32
[Depex]
TRUE
diff --git a/QcomModulePkg/Library/BootLib/BootLinux.c b/QcomModulePkg/Library/BootLib/BootLinux.c
index e97733f..77a5087 100644
--- a/QcomModulePkg/Library/BootLib/BootLinux.c
+++ b/QcomModulePkg/Library/BootLib/BootLinux.c
@@ -32,11 +32,33 @@
#include <Library/VerifiedBootMenu.h>
#include <Library/DrawUI.h>
+#include <Protocol/EFIScmModeSwitch.h>
#include "BootLinux.h"
#include "BootStats.h"
+#include "BootImage.h"
+#include "UpdateDeviceTree.h"
STATIC BOOLEAN VerifiedBootEnbled();
+STATIC QCOM_SCM_MODE_SWITCH_PROTOCOL *pQcomScmModeSwitchProtocol = NULL;
+
+STATIC EFI_STATUS SwitchTo32bitModeBooting(UINT64 KernelLoadAddr, UINT64 DeviceTreeLoadAddr) {
+ EFI_STATUS Status;
+ EFI_HLOS_BOOT_ARGS HlosBootArgs;
+
+ SetMem((VOID*)&HlosBootArgs, sizeof(HlosBootArgs), 0);
+ HlosBootArgs.el1_x2 = DeviceTreeLoadAddr;
+ /* Write 0 into el1_x4 to switch to 32bit mode */
+ HlosBootArgs.el1_x4 = 0;
+ HlosBootArgs.el1_elr = KernelLoadAddr;
+ Status = pQcomScmModeSwitchProtocol->SwitchTo32bitMode(HlosBootArgs);
+ if (EFI_ERROR(Status)) {
+ DEBUG((EFI_D_ERROR, "ERROR: Failed to switch to 32 bit mode.Status= %r\n",Status));
+ return Status;
+ }
+ /*Return Unsupported if the execution ever reaches here*/
+ return EFI_NOT_STARTED;
+}
EFI_STATUS BootLinux (VOID *ImageBuffer, UINT32 ImageSize, DeviceInfo *DevInfo, CHAR8 *pname, BOOLEAN Recovery)
{
@@ -49,6 +71,7 @@
STATIC UINT32 KernelSizeActual;
STATIC UINT32 RamdiskSizeActual;
STATIC UINT32 SecondSizeActual;
+ struct kernel64_hdr* Kptr = NULL;
/*Boot Image header information variables*/
STATIC UINT32 KernelSize;
@@ -71,6 +94,7 @@
QCOM_VERIFIEDBOOT_PROTOCOL *VbIntf;
device_info_vb_t DevInfo_vb;
STATIC CHAR8 StrPartition[MAX_PNAME_LENGTH];
+ BOOLEAN BootingWith32BitKernel = FALSE;
if (VerifiedBootEnbled())
{
@@ -168,6 +192,22 @@
}
DEBUG((EFI_D_INFO, "Decompressing kernel image done: %u ms\n", GetTimerCountms()));
+ Kptr = KernelLoadAddr;
+ } else {
+ if (CHECK_ADD64(ImageBuffer, PageSize)) {
+ DEBUG((EFI_D_ERROR, "Integer Overflow: in Kernel header fields addition\n"));
+ return EFI_BAD_BUFFER_SIZE;
+ }
+ Kptr = ImageBuffer + PageSize;
+ }
+ if (Kptr->magic_64 != KERNEL64_HDR_MAGIC) {
+ BootingWith32BitKernel = TRUE;
+ KernelLoadAddr = (EFI_PHYSICAL_ADDRESS)(BaseMemory | PcdGet32(KernelLoadAddress32));
+ if (CHECK_ADD64((VOID*)Kptr, DTB_OFFSET_LOCATION_IN_ARCH32_KERNEL_HDR)) {
+ DEBUG((EFI_D_ERROR, "Integer Overflow: in DTB offset addition\n"));
+ return EFI_BAD_BUFFER_SIZE;
+ }
+ CopyMem((VOID*)&DtbOffset, ((VOID*)Kptr + DTB_OFFSET_LOCATION_IN_ARCH32_KERNEL_HDR), sizeof(DtbOffset));
}
/*Finds out the location of device tree image and ramdisk image within the boot image
@@ -228,6 +268,18 @@
}
CopyMem (RamdiskLoadAddr, ImageBuffer + RamdiskOffset, RamdiskSize);
+ if (BootingWith32BitKernel) {
+ if (CHECK_ADD64(KernelLoadAddr, KernelSizeActual)) {
+ DEBUG((EFI_D_ERROR, "Integer Overflow: while Kernel image copy\n"));
+ return EFI_BAD_BUFFER_SIZE;
+ }
+ if (KernelLoadAddr + KernelSizeActual > DeviceTreeLoadAddr) {
+ DEBUG((EFI_D_ERROR, "Kernel size is over the limit\n"));
+ return EFI_INVALID_PARAMETER;
+ }
+ CopyMem(KernelLoadAddr, ImageBuffer + PageSize, KernelSizeActual);
+ }
+
if (FixedPcdGetBool(EnablePartialGoods))
{
Status = UpdatePartialGoodsNode((VOID*)DeviceTreeLoadAddr);
@@ -247,11 +299,18 @@
return Status;
}
}
- DEBUG((EFI_D_INFO, "\nShutting Down UEFI Boot Services: %u ms\n\n", GetTimerCountms()));
/* Free the boot logo blt buffer before starting kernel */
FreeBootLogoBltBuffer();
+ if (BootingWith32BitKernel) {
+ Status = gBS->LocateProtocol(&gQcomScmModeSwithProtocolGuid, NULL, (VOID**)&pQcomScmModeSwitchProtocol);
+ if(EFI_ERROR(Status)) {
+ DEBUG((EFI_D_ERROR,"ERROR: Unable to Locate Protocol handle for ScmModeSwicthProtocol Status=%r\n", Status));
+ return Status;
+ }
+ }
+ DEBUG((EFI_D_INFO, "\nShutting Down UEFI Boot Services: %u ms\n", GetTimerCountms()));
/*Shut down UEFI boot services*/
Status = ShutdownUefiBootServices ();
if(EFI_ERROR(Status)) {
@@ -270,6 +329,11 @@
//
// Start the Linux Kernel
//
+ if (BootingWith32BitKernel) {
+ Status = SwitchTo32bitModeBooting((UINT64)KernelLoadAddr, (UINT64)DeviceTreeLoadAddr);
+ return Status;
+ }
+
LinuxKernel = (LINUX_KERNEL)(UINTN)KernelLoadAddr;
LinuxKernel ((UINTN)DeviceTreeLoadAddr, 0, 0, 0);
diff --git a/QcomModulePkg/QcomModulePkg.dec b/QcomModulePkg/QcomModulePkg.dec
index e44838f..f6d921b 100644
--- a/QcomModulePkg/QcomModulePkg.dec
+++ b/QcomModulePkg/QcomModulePkg.dec
@@ -107,6 +107,8 @@
gEfiLimitsProtocolGuid = { 0x79d6c879, 0x725e, 0x489e, { 0xa0, 0xa9, 0x27, 0xef, 0xa5, 0xdf, 0xcb, 0x35 } }
# VerifiedBoot Protocol
gEfiQcomVerifiedBootProtocolGuid = { 0x8e5eff91, 0x21b6, 0x47d3, { 0xaf, 0x2b, 0xc1, 0x5a, 0x1, 0xe0, 0x20, 0xec } }
+ # Scm mode switch Protocol
+ gQcomScmModeSwithProtocolGuid = { 0xf57f73ed, 0x0afc, 0x4723, { 0x93, 0x74, 0x2c, 0xeb, 0xc0, 0x19, 0x8e, 0xf9 } }
[PcdsFixedAtBuild.common]
# LinuxLoaderCommon
@@ -116,3 +118,4 @@
gQcomTokenSpaceGuid.RamdiskEndAddress|0x05800000|UINT32|0x00015003
gQcomTokenSpaceGuid.EnablePartialGoods|TRUE|BOOLEAN|0x00015004
gQcomTokenSpaceGuid.EnableDisplayMenu|TRUE|BOOLEAN|0x00015005
+ gQcomTokenSpaceGuid.KernelLoadAddress32|0x00008000|UINT32|0x00015006