]> git.proxmox.com Git - mirror_edk2.git/blobdiff - BaseTools/Source/C/GenFv/GenFvInternalLib.c
GenFv: Arm: support images entered in Thumb mode
[mirror_edk2.git] / BaseTools / Source / C / GenFv / GenFvInternalLib.c
index 6e296b8ad6b2f7132954db8cf49dd9e625e96f13..d650a527a5af1eac220c70fdb28dd3833927e2c5 100644 (file)
@@ -34,9 +34,27 @@ SPDX-License-Identifier: BSD-2-Clause-Patent
 #include "FvLib.h"\r
 #include "PeCoffLib.h"\r
 \r
-#define ARMT_UNCONDITIONAL_JUMP_INSTRUCTION       0xEB000000\r
 #define ARM64_UNCONDITIONAL_JUMP_INSTRUCTION      0x14000000\r
 \r
+/*\r
+ * Arm instruction to jump to Fv entry instruction in Arm or Thumb mode.\r
+ * From ARM Arch Ref Manual versions b/c/d, section A8.8.25 BL, BLX (immediate)\r
+ * BLX (encoding A2) branches to offset in Thumb instruction set mode.\r
+ * BL (encoding A1) branches to offset in Arm instruction set mode.\r
+ */\r
+#define ARM_JUMP_OFFSET_MAX        0xffffff\r
+#define ARM_JUMP_TO_ARM(Offset)    (0xeb000000 | ((Offset - 8) >> 2))\r
+\r
+#define _ARM_JUMP_TO_THUMB(Imm32)  (0xfa000000 | \\r
+                                    (((Imm32) & (1 << 1)) << (24 - 1)) | \\r
+                                    (((Imm32) >> 2) & 0x7fffff))\r
+#define ARM_JUMP_TO_THUMB(Offset)  _ARM_JUMP_TO_THUMB((Offset) - 8)\r
+\r
+/*\r
+ * Arm instruction to return from exception (MOVS PC, LR)\r
+ */\r
+#define ARM_RETURN_FROM_EXCEPTION  0xE1B0F07E\r
+\r
 BOOLEAN mArm = FALSE;\r
 BOOLEAN mRiscV = FALSE;\r
 STATIC UINT32   MaxFfsAlignment = 0;\r
@@ -2203,23 +2221,25 @@ Returns:
     // if we found an SEC core entry point then generate a branch instruction\r
     // to it and populate a debugger SWI entry as well\r
     if (UpdateVectorSec) {\r
+      UINT32                    EntryOffset;\r
 \r
       VerboseMsg("UpdateArmResetVectorIfNeeded updating ARM SEC vector");\r
 \r
-      // B SecEntryPoint - signed_immed_24 part +/-32MB offset\r
-      // on ARM, the PC is always 8 ahead, so we're not really jumping from the base address, but from base address + 8\r
-      ResetVector[0] = (INT32)(SecCoreEntryAddress - FvInfo->BaseAddress - 8) >> 2;\r
+      EntryOffset = (INT32)(SecCoreEntryAddress - FvInfo->BaseAddress);\r
 \r
-      if (ResetVector[0] > 0x00FFFFFF) {\r
-        Error(NULL, 0, 3000, "Invalid", "SEC Entry point must be within 32MB of the start of the FV");\r
+      if (EntryOffset > ARM_JUMP_OFFSET_MAX) {\r
+          Error(NULL, 0, 3000, "Invalid", "SEC Entry point offset above 1MB of the start of the FV");\r
         return EFI_ABORTED;\r
       }\r
 \r
-      // Add opcode for an unconditional branch with no link. i.e.: " B SecEntryPoint"\r
-      ResetVector[0] |= ARMT_UNCONDITIONAL_JUMP_INSTRUCTION;\r
+      if ((SecCoreEntryAddress & 1) != 0) {\r
+        ResetVector[0] = ARM_JUMP_TO_THUMB(EntryOffset);\r
+      } else {\r
+        ResetVector[0] = ARM_JUMP_TO_ARM(EntryOffset);\r
+      }\r
 \r
       // SWI handler movs   pc,lr. Just in case a debugger uses SWI\r
-      ResetVector[2] = 0xE1B0F07E;\r
+      ResetVector[2] = ARM_RETURN_FROM_EXCEPTION;\r
 \r
       // Place holder to support a common interrupt handler from ROM.\r
       // Currently not supported. For this to be used the reset vector would not be in this FV\r