]> git.proxmox.com Git - mirror_edk2.git/blobdiff - ArmPkg/Drivers/CpuDxe/Exception.c
ArmPkg: Fix Ecc error 5005 in CpuDxe
[mirror_edk2.git] / ArmPkg / Drivers / CpuDxe / Exception.c
index 21a4c035a9a00968052174bb87622f469ff7d984..503c882a3ff20aae24de747d360eb4432689781e 100644 (file)
 /** @file\r
 \r
   Copyright (c) 2008 - 2009, Apple Inc. All rights reserved.<BR>\r
-  \r
-  This program and the accompanying materials\r
-  are licensed and made available under the terms and conditions of the BSD License\r
-  which accompanies this distribution.  The full text of the license may be found at\r
-  http://opensource.org/licenses/bsd-license.php\r
+  Portions Copyright (c) 2011 - 2021, Arm Limited. All rights reserved.<BR>\r
 \r
-  THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,\r
-  WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
+  SPDX-License-Identifier: BSD-2-Clause-Patent\r
 \r
 **/\r
 \r
-#include "CpuDxe.h" \r
-\r
-//FIXME: Will not compile on non-ARMv7 builds\r
-#include <Chipset/ArmV7.h>\r
-\r
-VOID\r
-ExceptionHandlersStart (\r
-  VOID\r
-  );\r
-\r
-VOID\r
-ExceptionHandlersEnd (\r
-  VOID\r
-  );\r
-\r
-VOID\r
-CommonExceptionEntry (\r
-  VOID\r
-  );\r
-\r
-VOID\r
-AsmCommonExceptionEntry (\r
-  VOID\r
-  );\r
-\r
-\r
-EFI_EXCEPTION_CALLBACK  gExceptionHandlers[MAX_ARM_EXCEPTION + 1];\r
-EFI_EXCEPTION_CALLBACK  gDebuggerExceptionHandlers[MAX_ARM_EXCEPTION + 1];\r
-\r
-\r
-\r
-/**\r
-  This function registers and enables the handler specified by InterruptHandler for a processor \r
-  interrupt or exception type specified by InterruptType. If InterruptHandler is NULL, then the \r
-  handler for the processor interrupt or exception type specified by InterruptType is uninstalled. \r
-  The installed handler is called once for each processor interrupt or exception.\r
-\r
-  @param  InterruptType    A pointer to the processor's current interrupt state. Set to TRUE if interrupts\r
-                           are enabled and FALSE if interrupts are disabled.\r
-  @param  InterruptHandler A pointer to a function of type EFI_CPU_INTERRUPT_HANDLER that is called\r
-                           when a processor interrupt occurs. If this parameter is NULL, then the handler\r
-                           will be uninstalled.\r
-\r
-  @retval EFI_SUCCESS           The handler for the processor interrupt was successfully installed or uninstalled.\r
-  @retval EFI_ALREADY_STARTED   InterruptHandler is not NULL, and a handler for InterruptType was\r
-                                previously installed.\r
-  @retval EFI_INVALID_PARAMETER InterruptHandler is NULL, and a handler for InterruptType was not\r
-                                previously installed.\r
-  @retval EFI_UNSUPPORTED       The interrupt specified by InterruptType is not supported.\r
-\r
-**/\r
-EFI_STATUS\r
-RegisterInterruptHandler (\r
-  IN EFI_EXCEPTION_TYPE             InterruptType,\r
-  IN EFI_CPU_INTERRUPT_HANDLER      InterruptHandler\r
-  )\r
-{\r
-  if (InterruptType > MAX_ARM_EXCEPTION) {\r
-    return EFI_UNSUPPORTED;\r
-  }\r
-\r
-  if ((InterruptHandler != NULL) && (gExceptionHandlers[InterruptType] != NULL)) {\r
-    return EFI_ALREADY_STARTED;\r
-  }\r
-\r
-  gExceptionHandlers[InterruptType] = InterruptHandler;\r
-\r
-  return EFI_SUCCESS;\r
-}\r
-\r
-\r
-\r
-\r
-VOID\r
-EFIAPI\r
-CommonCExceptionHandler (\r
-  IN     EFI_EXCEPTION_TYPE           ExceptionType,\r
-  IN OUT EFI_SYSTEM_CONTEXT           SystemContext\r
-  )\r
-{\r
-\r
-  if (ExceptionType <= MAX_ARM_EXCEPTION) {\r
-    if (gExceptionHandlers[ExceptionType]) {\r
-      gExceptionHandlers[ExceptionType] (ExceptionType, SystemContext);\r
-      return;\r
-    }\r
-  } else {\r
-    DEBUG ((EFI_D_ERROR, "Unknown exception type %d from %08x\n", ExceptionType, SystemContext.SystemContextArm->PC));\r
-    ASSERT (FALSE);\r
-  }\r
-  \r
-  if (ExceptionType == EXCEPT_ARM_SOFTWARE_INTERRUPT) {\r
-    //\r
-    // ARM JTAG debuggers some times use this vector, so it is not an error to get one\r
-    //\r
-    return;\r
-  }\r
-\r
-  DefaultExceptionHandler (ExceptionType, SystemContext);\r
-}\r
-\r
-\r
+#include "CpuDxe.h"\r
+#include <Library/CpuExceptionHandlerLib.h>\r
+#include <Guid/VectorHandoffTable.h>\r
 \r
 EFI_STATUS\r
 InitializeExceptions (\r
   IN EFI_CPU_ARCH_PROTOCOL    *Cpu\r
   )\r
 {\r
-  EFI_STATUS           Status;\r
-  UINTN                Offset;\r
-  UINTN                Length;\r
-  UINTN                Index;\r
-  BOOLEAN              IrqEnabled;\r
-  BOOLEAN              FiqEnabled;\r
-  EFI_PHYSICAL_ADDRESS Base;\r
-  UINT32               *VectorBase;\r
+  EFI_STATUS                      Status;\r
+  EFI_VECTOR_HANDOFF_INFO         *VectorInfoList;\r
+  EFI_VECTOR_HANDOFF_INFO         *VectorInfo;\r
+  BOOLEAN                         IrqEnabled;\r
+  BOOLEAN                         FiqEnabled;\r
+\r
+  VectorInfo = (EFI_VECTOR_HANDOFF_INFO *)NULL;\r
+  Status = EfiGetSystemConfigurationTable(&gEfiVectorHandoffTableGuid, (VOID **)&VectorInfoList);\r
+  if (Status == EFI_SUCCESS && VectorInfoList != NULL) {\r
+    VectorInfo = VectorInfoList;\r
+  }\r
+\r
+  // initialize the CpuExceptionHandlerLib so we take over the exception vector table from the DXE Core\r
+  InitializeCpuExceptionHandlers(VectorInfo);\r
 \r
   Status = EFI_SUCCESS;\r
+\r
   //\r
   // Disable interrupts\r
   //\r
@@ -137,79 +40,61 @@ InitializeExceptions (
   Cpu->DisableInterrupt (Cpu);\r
 \r
   //\r
-  // EFI does not use the FIQ, but a debugger might so we must disable \r
-  // as we take over the exception vectors. \r
+  // EFI does not use the FIQ, but a debugger might so we must disable\r
+  // as we take over the exception vectors.\r
   //\r
   FiqEnabled = ArmGetFiqState ();\r
   ArmDisableFiq ();\r
 \r
-  if (FeaturePcdGet(PcdRelocateVectorTable) == TRUE) {\r
-      //\r
-      // Copy an implementation of the ARM exception vectors to PcdCpuVectorBaseAddress.\r
-      //\r
-      Length = (UINTN)ExceptionHandlersEnd - (UINTN)ExceptionHandlersStart;\r
-    \r
-      //\r
-      // Reserve space for the exception handlers\r
-      //\r
-      Base = (EFI_PHYSICAL_ADDRESS)PcdGet32 (PcdCpuVectorBaseAddress);\r
-      VectorBase = (UINT32 *)(UINTN)Base;\r
-      Status = gBS->AllocatePages (AllocateAddress, EfiBootServicesCode, EFI_SIZE_TO_PAGES (Length), &Base);\r
-      // If the request was for memory that's not in the memory map (which is often the case for 0x00000000\r
-      // on embedded systems, for example, we don't want to hang up.  So we'll check here for a status of \r
-      // EFI_NOT_FOUND, and continue in that case.\r
-      if (EFI_ERROR(Status) && (Status != EFI_NOT_FOUND)) {\r
-        ASSERT_EFI_ERROR (Status);\r
-      }\r
-    \r
-      // Save existing vector table, in case debugger is already hooked in\r
-      CopyMem ((VOID *)gDebuggerExceptionHandlers, (VOID *)VectorBase, sizeof (gDebuggerExceptionHandlers));\r
-    \r
-      // Copy our assembly code into the page that contains the exception vectors. \r
-      CopyMem ((VOID *)VectorBase, (VOID *)ExceptionHandlersStart, Length);\r
-    \r
-      //\r
-      // Patch in the common Assembly exception handler\r
-      //\r
-      Offset = (UINTN)CommonExceptionEntry - (UINTN)ExceptionHandlersStart;\r
-      *(UINTN *) ((UINT8 *)(UINTN)PcdGet32 (PcdCpuVectorBaseAddress) + Offset) = (UINTN)AsmCommonExceptionEntry;\r
-    \r
-      //\r
-      // Initialize the C entry points for interrupts\r
-      //\r
-      for (Index = 0; Index <= MAX_ARM_EXCEPTION; Index++) {\r
-        if ((gDebuggerExceptionHandlers[Index] == 0) || (gDebuggerExceptionHandlers[Index] == (VOID *)(UINTN)0xEAFFFFFE)) {\r
-          // Exception handler contains branch to vector location (jmp $) so no handler\r
-          // NOTE: This code assumes vectors are ARM and not Thumb code\r
-          Status = RegisterInterruptHandler (Index, NULL);\r
-          ASSERT_EFI_ERROR (Status);\r
-        } else {\r
-          // If the debugger has alread hooked put its vector back\r
-          VectorBase[Index] = (UINT32)(UINTN)gDebuggerExceptionHandlers[Index];\r
-        }\r
-      }\r
-    \r
-      // Flush Caches since we updated executable stuff\r
-      InvalidateInstructionCacheRange ((VOID *)PcdGet32(PcdCpuVectorBaseAddress), Length);\r
-\r
-      //Note: On ARM processor with the Security Extension, the Vector Table can be located anywhere in the memory.\r
-      //      The Vector Base Address Register defines the location\r
-      ArmWriteVBar(PcdGet32(PcdCpuVectorBaseAddress));\r
-  } else {\r
-    // We do not copy the Exception Table at PcdGet32(PcdCpuVectorBaseAddress). We just set Vector Base Address to point into CpuDxe code.\r
-    ArmWriteVBar((UINT32)ExceptionHandlersStart);\r
-  }\r
-\r
   if (FiqEnabled) {\r
     ArmEnableFiq ();\r
   }\r
 \r
   if (IrqEnabled) {\r
-    // \r
+    //\r
     // Restore interrupt state\r
     //\r
     Status = Cpu->EnableInterrupt (Cpu);\r
   }\r
 \r
+  //\r
+  // On a DEBUG build, unmask SErrors so they are delivered right away rather\r
+  // than when the OS unmasks them. This gives us a better chance of figuring\r
+  // out the cause.\r
+  //\r
+  DEBUG_CODE (\r
+    ArmEnableAsynchronousAbort ();\r
+  );\r
+\r
   return Status;\r
 }\r
+\r
+/**\r
+This function registers and enables the handler specified by InterruptHandler for a processor\r
+interrupt or exception type specified by InterruptType. If InterruptHandler is NULL, then the\r
+handler for the processor interrupt or exception type specified by InterruptType is uninstalled.\r
+The installed handler is called once for each processor interrupt or exception.\r
+\r
+@param  InterruptType    A pointer to the processor's current interrupt state. Set to TRUE if interrupts\r
+are enabled and FALSE if interrupts are disabled.\r
+@param  InterruptHandler A pointer to a function of type EFI_CPU_INTERRUPT_HANDLER that is called\r
+when a processor interrupt occurs. If this parameter is NULL, then the handler\r
+will be uninstalled.\r
+\r
+@retval EFI_SUCCESS           The handler for the processor interrupt was successfully installed or uninstalled.\r
+@retval EFI_ALREADY_STARTED   InterruptHandler is not NULL, and a handler for InterruptType was\r
+previously installed.\r
+@retval EFI_INVALID_PARAMETER InterruptHandler is NULL, and a handler for InterruptType was not\r
+previously installed.\r
+@retval EFI_UNSUPPORTED       The interrupt specified by InterruptType is not supported.\r
+\r
+**/\r
+EFI_STATUS\r
+RegisterInterruptHandler(\r
+  IN EFI_EXCEPTION_TYPE             InterruptType,\r
+  IN EFI_CPU_INTERRUPT_HANDLER      InterruptHandler\r
+  )\r
+{\r
+  // pass down to CpuExceptionHandlerLib\r
+  return (EFI_STATUS)RegisterCpuInterruptHandler(InterruptType, InterruptHandler);\r
+}\r