summaryrefslogtreecommitdiff
path: root/ArmPkg/Drivers/CpuDxe
diff options
context:
space:
mode:
authorAJFISH <AJFISH@6f19259b-4bc3-4df7-8a09-765794883524>2009-12-06 01:57:05 +0000
committerAJFISH <AJFISH@6f19259b-4bc3-4df7-8a09-765794883524>2009-12-06 01:57:05 +0000
commit2ef2b01e07c02db339f34004445734a2dbdd80e1 (patch)
tree19532a6be8d8bdb0aef04bd00c1efb582f6dc841 /ArmPkg/Drivers/CpuDxe
parentf7753a96ba1653ddd31b01c198a352f6332ac404 (diff)
downloadedk2-platforms-2ef2b01e07c02db339f34004445734a2dbdd80e1.tar.xz
Adding support for BeagleBoard.
ArmPkg - Supoprt for ARM specific things that can change as the architecture changes. Plus semihosting JTAG drivers. EmbeddedPkg - Generic support for an embeddded platform. Including a light weight command line shell. BeagleBoardPkg - Platform specifics for BeagleBoard. SD Card works, but USB has issues. Looks like a bug in the open source USB stack (Our internal stack works fine). git-svn-id: https://edk2.svn.sourceforge.net/svnroot/edk2/trunk/edk2@9518 6f19259b-4bc3-4df7-8a09-765794883524
Diffstat (limited to 'ArmPkg/Drivers/CpuDxe')
-rw-r--r--ArmPkg/Drivers/CpuDxe/CpuDxe.c154
-rw-r--r--ArmPkg/Drivers/CpuDxe/CpuDxe.h91
-rw-r--r--ArmPkg/Drivers/CpuDxe/CpuDxe.inf56
-rw-r--r--ArmPkg/Drivers/CpuDxe/DebugSupport.c247
-rw-r--r--ArmPkg/Drivers/CpuDxe/Exception.c238
-rwxr-xr-xArmPkg/Drivers/CpuDxe/ExceptionSupport.S152
-rwxr-xr-xArmPkg/Drivers/CpuDxe/ExceptionSupport.asm152
7 files changed, 1090 insertions, 0 deletions
diff --git a/ArmPkg/Drivers/CpuDxe/CpuDxe.c b/ArmPkg/Drivers/CpuDxe/CpuDxe.c
new file mode 100644
index 0000000000..c57dac2f74
--- /dev/null
+++ b/ArmPkg/Drivers/CpuDxe/CpuDxe.c
@@ -0,0 +1,154 @@
+/** @file
+
+ Copyright (c) 2008-2009, Apple Inc. All rights reserved.
+
+ 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 "CpuDxe.h"
+
+EFI_STATUS
+EFIAPI
+CpuFlushCpuDataCache (
+ IN EFI_CPU_ARCH_PROTOCOL *This,
+ IN EFI_PHYSICAL_ADDRESS Start,
+ IN UINT64 Length,
+ IN EFI_CPU_FLUSH_TYPE FlushType
+ )
+{
+ switch (FlushType) {
+ case EfiCpuFlushTypeWriteBack:
+ WriteBackDataCacheRange((VOID *)(UINTN)Start, (UINTN)Length);
+ break;
+ case EfiCpuFlushTypeInvalidate:
+ InvalidateDataCacheRange((VOID *)(UINTN)Start, (UINTN)Length);
+ break;
+ case EfiCpuFlushTypeWriteBackInvalidate:
+ WriteBackInvalidateDataCacheRange((VOID *)(UINTN)Start, (UINTN)Length);
+ break;
+ default:
+ return EFI_INVALID_PARAMETER;
+ }
+
+ return EFI_SUCCESS;
+}
+
+EFI_STATUS
+EFIAPI
+CpuEnableInterrupt (
+ IN EFI_CPU_ARCH_PROTOCOL *This
+ )
+{
+ if (ArmProcessorMode() != ARM_PROCESSOR_MODE_IRQ) {
+ ArmEnableInterrupts();
+ }
+ return EFI_SUCCESS;
+}
+
+
+EFI_STATUS
+EFIAPI
+CpuDisableInterrupt (
+ IN EFI_CPU_ARCH_PROTOCOL *This
+ )
+{
+ if (ArmProcessorMode() != ARM_PROCESSOR_MODE_IRQ) {
+ ArmDisableInterrupts();
+ }
+ return EFI_SUCCESS;
+}
+
+EFI_STATUS
+EFIAPI
+CpuGetInterruptState (
+ IN EFI_CPU_ARCH_PROTOCOL *This,
+ OUT BOOLEAN *State
+ )
+{
+ if (State == NULL) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ *State = ArmGetInterruptState();
+ return EFI_SUCCESS;
+}
+
+EFI_STATUS
+EFIAPI
+CpuInit (
+ IN EFI_CPU_ARCH_PROTOCOL *This,
+ IN EFI_CPU_INIT_TYPE InitType
+ )
+{
+ return EFI_UNSUPPORTED;
+}
+
+EFI_STATUS
+EFIAPI
+CpuRegisterInterruptHandler (
+ IN EFI_CPU_ARCH_PROTOCOL *This,
+ IN EFI_EXCEPTION_TYPE InterruptType,
+ IN EFI_CPU_INTERRUPT_HANDLER InterruptHandler
+ )
+{
+ return RegisterInterruptHandler(InterruptType, InterruptHandler);
+}
+
+EFI_STATUS
+EFIAPI
+CpuGetTimerValue (
+ IN EFI_CPU_ARCH_PROTOCOL *This,
+ IN UINT32 TimerIndex,
+ OUT UINT64 *TimerValue,
+ OUT UINT64 *TimerPeriod OPTIONAL
+ )
+{
+ return EFI_UNSUPPORTED;
+}
+
+EFI_STATUS
+EFIAPI
+CpuSetMemoryAttributes (
+ IN EFI_CPU_ARCH_PROTOCOL *This,
+ IN EFI_PHYSICAL_ADDRESS BaseAddress,
+ IN UINT64 Length,
+ IN UINT64 Attributes
+ )
+{
+ return EFI_UNSUPPORTED;
+}
+
+//
+// Globals used to initialize the protocol
+//
+EFI_HANDLE mCpuHandle = NULL;
+EFI_CPU_ARCH_PROTOCOL mCpu = {
+ CpuFlushCpuDataCache,
+ CpuEnableInterrupt,
+ CpuDisableInterrupt,
+ CpuGetInterruptState,
+ CpuInit,
+ CpuRegisterInterruptHandler,
+ CpuGetTimerValue,
+ CpuSetMemoryAttributes,
+ 0, // NumberOfTimers
+ 4, // DmaBufferAlignment
+};
+
+EFI_STATUS
+CpuDxeInitialize (
+ IN EFI_HANDLE ImageHandle,
+ IN EFI_SYSTEM_TABLE *SystemTable
+ )
+{
+ InitializeExceptions(&mCpu);
+ return gBS->InstallMultipleProtocolInterfaces(&mCpuHandle, &gEfiCpuArchProtocolGuid, &mCpu, NULL);
+}
+
diff --git a/ArmPkg/Drivers/CpuDxe/CpuDxe.h b/ArmPkg/Drivers/CpuDxe/CpuDxe.h
new file mode 100644
index 0000000000..36133e11c3
--- /dev/null
+++ b/ArmPkg/Drivers/CpuDxe/CpuDxe.h
@@ -0,0 +1,91 @@
+/** @file
+
+ Copyright (c) 2008-2009 Apple Inc. All rights reserved.<BR>
+
+ 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.
+
+**/
+
+#ifndef __CPU_DXE_ARM_EXCEPTION_H__
+#define __CPU_DXE_ARM_EXCEPTION_H__
+
+#include <Uefi.h>
+
+#include <Library/ArmLib.h>
+#include <Library/BaseMemoryLib.h>
+#include <Library/CacheMaintenanceLib.h>
+#include <Library/DebugLib.h>
+#include <Library/PcdLib.h>
+#include <Library/UefiBootServicesTableLib.h>
+
+#include <Protocol/Cpu.h>
+#include <Protocol/DebugSupport.h>
+#include <Protocol/DebugSupportPeriodicCallback.h>
+
+
+/**
+ This function registers and enables the handler specified by InterruptHandler for a processor
+ interrupt or exception type specified by InterruptType. If InterruptHandler is NULL, then the
+ handler for the processor interrupt or exception type specified by InterruptType is uninstalled.
+ The installed handler is called once for each processor interrupt or exception.
+
+ @param InterruptType A pointer to the processor's current interrupt state. Set to TRUE if interrupts
+ are enabled and FALSE if interrupts are disabled.
+ @param InterruptHandler A pointer to a function of type EFI_CPU_INTERRUPT_HANDLER that is called
+ when a processor interrupt occurs. If this parameter is NULL, then the handler
+ will be uninstalled.
+
+ @retval EFI_SUCCESS The handler for the processor interrupt was successfully installed or uninstalled.
+ @retval EFI_ALREADY_STARTED InterruptHandler is not NULL, and a handler for InterruptType was
+ previously installed.
+ @retval EFI_INVALID_PARAMETER InterruptHandler is NULL, and a handler for InterruptType was not
+ previously installed.
+ @retval EFI_UNSUPPORTED The interrupt specified by InterruptType is not supported.
+
+**/
+EFI_STATUS
+RegisterInterruptHandler (
+ IN EFI_EXCEPTION_TYPE InterruptType,
+ IN EFI_CPU_INTERRUPT_HANDLER InterruptHandler
+ );
+
+
+/**
+ This function registers and enables the handler specified by InterruptHandler for a processor
+ interrupt or exception type specified by InterruptType. If InterruptHandler is NULL, then the
+ handler for the processor interrupt or exception type specified by InterruptType is uninstalled.
+ The installed handler is called once for each processor interrupt or exception.
+
+ @param InterruptType A pointer to the processor's current interrupt state. Set to TRUE if interrupts
+ are enabled and FALSE if interrupts are disabled.
+ @param InterruptHandler A pointer to a function of type EFI_CPU_INTERRUPT_HANDLER that is called
+ when a processor interrupt occurs. If this parameter is NULL, then the handler
+ will be uninstalled.
+
+ @retval EFI_SUCCESS The handler for the processor interrupt was successfully installed or uninstalled.
+ @retval EFI_ALREADY_STARTED InterruptHandler is not NULL, and a handler for InterruptType was
+ previously installed.
+ @retval EFI_INVALID_PARAMETER InterruptHandler is NULL, and a handler for InterruptType was not
+ previously installed.
+ @retval EFI_UNSUPPORTED The interrupt specified by InterruptType is not supported.
+
+**/
+EFI_STATUS
+RegisterDebuggerInterruptHandler (
+ IN EFI_EXCEPTION_TYPE InterruptType,
+ IN EFI_CPU_INTERRUPT_HANDLER InterruptHandler
+ );
+
+
+EFI_STATUS
+InitializeExceptions (
+ IN EFI_CPU_ARCH_PROTOCOL *Cpu
+ );
+
+#endif // __CPU_DXE_ARM_EXCEPTION_H__
diff --git a/ArmPkg/Drivers/CpuDxe/CpuDxe.inf b/ArmPkg/Drivers/CpuDxe/CpuDxe.inf
new file mode 100644
index 0000000000..314965ca4a
--- /dev/null
+++ b/ArmPkg/Drivers/CpuDxe/CpuDxe.inf
@@ -0,0 +1,56 @@
+#%HEADER%
+#/** @file
+#
+# DXE CPU driver
+#
+# Copyright (c) 2009, Apple Inc. <BR>
+# 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.
+#
+#**/
+
+[Defines]
+ INF_VERSION = 0x00010005
+ BASE_NAME = ArmCpuDxe
+ FILE_GUID = B8D9777E-D72A-451F-9BDB-BAFB52A68415
+ MODULE_TYPE = DXE_DRIVER
+ VERSION_STRING = 1.0
+
+ ENTRY_POINT = CpuDxeInitialize
+
+[Sources.ARM]
+ CpuDxe.c
+ CpuDxe.h
+ DebugSupport.c
+ Exception.c
+ ExceptionSupport.asm | RVCT
+ ExceptionSupport.S | GCC
+
+[Packages]
+ ArmPkg/ArmPkg.dec
+ EmbeddedPkg/EmbeddedPkg.dec
+ MdePkg/MdePkg.dec
+
+[LibraryClasses]
+ BaseMemoryLib
+ CacheMaintenanceLib
+ UefiDriverEntryPoint
+ ArmLib
+
+[Protocols]
+ gEfiCpuArchProtocolGuid
+ gEfiDebugSupportPeriodicCallbackProtocolGuid
+
+[Pcd.common]
+ gArmTokenSpaceGuid.PcdCpuVectorBaseAddress
+
+[FeaturePcd.common]
+ gArmTokenSpaceGuid.PcdCpuDxeProduceDebugSupport
+
+[depex]
+ gHardwareInterruptProtocolGuid
diff --git a/ArmPkg/Drivers/CpuDxe/DebugSupport.c b/ArmPkg/Drivers/CpuDxe/DebugSupport.c
new file mode 100644
index 0000000000..b8a5584939
--- /dev/null
+++ b/ArmPkg/Drivers/CpuDxe/DebugSupport.c
@@ -0,0 +1,247 @@
+/** @file
+
+ Copyright (c) 2008-2009, Apple Inc. All rights reserved.
+
+ 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.
+
+**/
+/** @file
+ DXE Cpu Driver.
+
+ May need some porting work for platform specifics.
+
+ Copyright (c) 2008, Apple Inc
+ 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 "CpuDxe.h"
+
+EFI_PERIODIC_CALLBACK gPeriodicCallBack = (EFI_PERIODIC_CALLBACK)NULL;
+
+EFI_DEBUG_SUPPORT_PERIODIC_CALLBACK_PROTOCOL *gDebugSupportCallback = NULL;
+
+
+EFI_STATUS
+EFIAPI
+DebugSupportGetMaximumProcessorIndex (
+ IN EFI_DEBUG_SUPPORT_PROTOCOL *This,
+ OUT UINTN *MaxProcessorIndex
+ )
+/*++
+
+Routine Description: This is a DebugSupport protocol member function.
+
+Arguments:
+ This - The DebugSupport instance
+ MaxProcessorIndex - The maximuim supported processor index
+
+Returns:
+ Always returns EFI_SUCCESS with *MaxProcessorIndex set to 0
+
+--*/
+{
+ *MaxProcessorIndex = 0;
+ return EFI_SUCCESS;
+}
+
+EFI_STATUS
+EFIAPI
+DebugSupportRegisterPeriodicCallback (
+ IN EFI_DEBUG_SUPPORT_PROTOCOL *This,
+ IN UINTN ProcessorIndex,
+ IN EFI_PERIODIC_CALLBACK PeriodicCallback
+ )
+/*++
+
+Routine Description: This is a DebugSupport protocol member function.
+
+Arguments:
+ This - The DebugSupport instance
+ ProcessorIndex - Which processor the callback applies to.
+ PeriodicCallback - Callback function
+
+Returns:
+
+ EFI_SUCCESS
+ EFI_INVALID_PARAMETER - requested uninstalling a handler from a vector that has
+ no handler registered for it
+ EFI_ALREADY_STARTED - requested install to a vector that already has a handler registered.
+
+ Other possible return values are passed through from UnHookEntry and HookEntry.
+
+--*/
+{
+ if (ProcessorIndex != 0) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ if ((gPeriodicCallBack != (EFI_PERIODIC_CALLBACK)NULL) && (PeriodicCallback != (EFI_PERIODIC_CALLBACK)NULL)) {
+ return EFI_ALREADY_STARTED;
+ }
+
+ gPeriodicCallBack = PeriodicCallback;
+
+ if (gDebugSupportCallback != NULL) {
+ //
+ // We can only update this protocol if the Register Protocol Notify has fired. If it fires
+ // after this call it will update with gPeriodicCallBack value.
+ //
+ gDebugSupportCallback->PeriodicCallback = gPeriodicCallBack;
+ }
+
+ return EFI_SUCCESS;
+}
+
+
+EFI_STATUS
+EFIAPI
+DebugSupportRegisterExceptionCallback (
+ IN EFI_DEBUG_SUPPORT_PROTOCOL *This,
+ IN UINTN ProcessorIndex,
+ IN EFI_EXCEPTION_CALLBACK NewCallback,
+ IN EFI_EXCEPTION_TYPE ExceptionType
+ )
+/*++
+
+Routine Description:
+ This is a DebugSupport protocol member function.
+
+ This code executes in boot services context.
+
+Arguments:
+ This - The DebugSupport instance
+ ProcessorIndex - Which processor the callback applies to.
+ NewCallback - Callback function
+ ExceptionType - Which exception to hook
+
+Returns:
+
+ EFI_SUCCESS
+ EFI_INVALID_PARAMETER - requested uninstalling a handler from a vector that has
+ no handler registered for it
+ EFI_ALREADY_STARTED - requested install to a vector that already has a handler registered.
+
+ Other possible return values are passed through from UnHookEntry and HookEntry.
+
+--*/
+{
+ if (ProcessorIndex != 0) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ return RegisterDebuggerInterruptHandler (ExceptionType, NewCallback);
+}
+
+
+EFI_STATUS
+EFIAPI
+DebugSupportInvalidateInstructionCache (
+ IN EFI_DEBUG_SUPPORT_PROTOCOL *This,
+ IN UINTN ProcessorIndex,
+ IN VOID *Start,
+ IN UINT64 Length
+ )
+/*++
+
+Routine Description:
+ This is a DebugSupport protocol member function.
+ Calls assembly routine to flush cache.
+
+Arguments:
+ This - The DebugSupport instance
+ ProcessorIndex - Which processor the callback applies to.
+ Start - Physical base of the memory range to be invalidated
+ Length - mininum number of bytes in instruction cache to invalidate
+
+Returns:
+
+ EFI_SUCCESS - always return success
+
+--*/
+{
+ if (ProcessorIndex != 0) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ InvalidateInstructionCache();
+
+ return EFI_SUCCESS;
+}
+
+//
+// This is a global that is the actual interface
+//
+EFI_DEBUG_SUPPORT_PROTOCOL gDebugSupportProtocolInterface = {
+ IsaArm, // Fixme to be more generic
+ DebugSupportGetMaximumProcessorIndex,
+ DebugSupportRegisterPeriodicCallback,
+ DebugSupportRegisterExceptionCallback,
+ DebugSupportInvalidateInstructionCache
+};
+
+
+VOID
+EFIAPI
+DebugSupportPeriodicCallbackEventProtocolNotify (
+ IN EFI_EVENT Event,
+ IN VOID *Context
+ )
+{
+ EFI_STATUS Status;
+
+ Status = gBS->LocateProtocol (&gEfiDebugSupportPeriodicCallbackProtocolGuid, NULL, (VOID **)&gDebugSupportCallback);
+ if (!EFI_ERROR (Status)) {
+ gDebugSupportCallback->PeriodicCallback = gPeriodicCallBack;
+ }
+}
+
+VOID *gRegistration = NULL;
+
+
+EFI_DEBUG_SUPPORT_PROTOCOL *
+InitilaizeDebugSupport (
+ VOID
+ )
+{
+ // RPN gEfiDebugSupportPeriodicCallbackProtocolGuid
+ EFI_STATUS Status;
+ EFI_EVENT Event;
+
+ if (!FeaturePcdGet (PcdCpuDxeProduceDebugSupport)) {
+ // Don't include this code unless Feature Flag is set
+ return NULL;
+ }
+
+
+ Status = gBS->CreateEvent (
+ EVT_NOTIFY_SIGNAL,
+ TPL_CALLBACK,
+ DebugSupportPeriodicCallbackEventProtocolNotify,
+ NULL,
+ &Event
+ );
+ ASSERT_EFI_ERROR (Status);
+
+ Status = gBS->RegisterProtocolNotify (&gEfiDebugSupportPeriodicCallbackProtocolGuid, Event, &gRegistration);
+ ASSERT_EFI_ERROR (Status);
+
+ //
+ // We assume the Timer must depend on our driver to register interrupts so we don't need to do
+ // a gBS->SignalEvent (Event) here to check to see if the protocol allready exists
+ //
+
+ return &gDebugSupportProtocolInterface;
+}
diff --git a/ArmPkg/Drivers/CpuDxe/Exception.c b/ArmPkg/Drivers/CpuDxe/Exception.c
new file mode 100644
index 0000000000..fa256e60f8
--- /dev/null
+++ b/ArmPkg/Drivers/CpuDxe/Exception.c
@@ -0,0 +1,238 @@
+/** @file
+
+ Copyright (c) 2008-2009, Apple Inc. All rights reserved.
+
+ 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 "CpuDxe.h"
+#include <Library/CacheMaintenanceLib.h>
+
+VOID
+ExceptionHandlersStart (
+ VOID
+ );
+
+VOID
+ExceptionHandlersEnd (
+ VOID
+ );
+
+VOID
+CommonExceptionEntry (
+ VOID
+ );
+
+VOID
+AsmCommonExceptionEntry (
+ VOID
+ );
+
+
+EFI_EXCEPTION_CALLBACK gExceptionHandlers[MAX_ARM_EXCEPTION + 1];
+EFI_EXCEPTION_CALLBACK gDebuggerExceptionHandlers[MAX_ARM_EXCEPTION + 1];
+
+
+
+/**
+ This function registers and enables the handler specified by InterruptHandler for a processor
+ interrupt or exception type specified by InterruptType. If InterruptHandler is NULL, then the
+ handler for the processor interrupt or exception type specified by InterruptType is uninstalled.
+ The installed handler is called once for each processor interrupt or exception.
+
+ @param InterruptType A pointer to the processor's current interrupt state. Set to TRUE if interrupts
+ are enabled and FALSE if interrupts are disabled.
+ @param InterruptHandler A pointer to a function of type EFI_CPU_INTERRUPT_HANDLER that is called
+ when a processor interrupt occurs. If this parameter is NULL, then the handler
+ will be uninstalled.
+
+ @retval EFI_SUCCESS The handler for the processor interrupt was successfully installed or uninstalled.
+ @retval EFI_ALREADY_STARTED InterruptHandler is not NULL, and a handler for InterruptType was
+ previously installed.
+ @retval EFI_INVALID_PARAMETER InterruptHandler is NULL, and a handler for InterruptType was not
+ previously installed.
+ @retval EFI_UNSUPPORTED The interrupt specified by InterruptType is not supported.
+
+**/
+EFI_STATUS
+RegisterInterruptHandler (
+ IN EFI_EXCEPTION_TYPE InterruptType,
+ IN EFI_CPU_INTERRUPT_HANDLER InterruptHandler
+ )
+{
+ if (InterruptType > MAX_ARM_EXCEPTION) {
+ return EFI_UNSUPPORTED;
+ }
+
+ if ((InterruptHandler != NULL) && (gExceptionHandlers[InterruptType] != NULL)) {
+ return EFI_ALREADY_STARTED;
+ }
+
+ gExceptionHandlers[InterruptType] = InterruptHandler;
+
+ return EFI_SUCCESS;
+}
+
+
+/**
+ This function registers and enables the handler specified by InterruptHandler for a processor
+ interrupt or exception type specified by InterruptType. If InterruptHandler is NULL, then the
+ handler for the processor interrupt or exception type specified by InterruptType is uninstalled.
+ The installed handler is called once for each processor interrupt or exception.
+
+ @param InterruptType A pointer to the processor's current interrupt state. Set to TRUE if interrupts
+ are enabled and FALSE if interrupts are disabled.
+ @param InterruptHandler A pointer to a function of type EFI_CPU_INTERRUPT_HANDLER that is called
+ when a processor interrupt occurs. If this parameter is NULL, then the handler
+ will be uninstalled.
+
+ @retval EFI_SUCCESS The handler for the processor interrupt was successfully installed or uninstalled.
+ @retval EFI_ALREADY_STARTED InterruptHandler is not NULL, and a handler for InterruptType was
+ previously installed.
+ @retval EFI_INVALID_PARAMETER InterruptHandler is NULL, and a handler for InterruptType was not
+ previously installed.
+ @retval EFI_UNSUPPORTED The interrupt specified by InterruptType is not supported.
+
+**/
+EFI_STATUS
+RegisterDebuggerInterruptHandler (
+ IN EFI_EXCEPTION_TYPE InterruptType,
+ IN EFI_CPU_INTERRUPT_HANDLER InterruptHandler
+ )
+{
+ if (InterruptType > MAX_ARM_EXCEPTION) {
+ return EFI_UNSUPPORTED;
+ }
+
+ if ((InterruptHandler != NULL) && (gDebuggerExceptionHandlers[InterruptType] != NULL)) {
+ return EFI_ALREADY_STARTED;
+ }
+
+ gDebuggerExceptionHandlers[InterruptType] = InterruptHandler;
+
+ return EFI_SUCCESS;
+}
+
+
+
+VOID
+EFIAPI
+CommonCExceptionHandler (
+ IN EFI_EXCEPTION_TYPE ExceptionType,
+ IN OUT EFI_SYSTEM_CONTEXT SystemContext
+ )
+{
+ BOOLEAN Dispatched = FALSE;
+
+ if (ExceptionType <= MAX_ARM_EXCEPTION) {
+ if (gDebuggerExceptionHandlers[ExceptionType]) {
+ //
+ // If DebugSupport hooked the interrupt call the handler. This does not disable
+ // the normal handler.
+ //
+ gDebuggerExceptionHandlers[ExceptionType] (ExceptionType, SystemContext);
+ Dispatched = TRUE;
+ }
+ if (gExceptionHandlers[ExceptionType]) {
+ gExceptionHandlers[ExceptionType] (ExceptionType, SystemContext);
+ Dispatched = TRUE;
+ }
+ }
+
+ if (Dispatched) {
+ //
+ // We did work so this was an expected ExceptionType
+ //
+ return;
+ }
+
+ if (ExceptionType == EXCEPT_ARM_SOFTWARE_INTERRUPT) {
+ //
+ // ARM JTAG debuggers some times use this vector, so it is not an error to get one
+ //
+ return;
+ }
+
+ //
+ // Code after here is the default exception handler...
+ //
+ DEBUG ((EFI_D_ERROR, "Exception %d from %08x\n", ExceptionType, SystemContext.SystemContextArm->PC));
+ ASSERT (FALSE);
+
+}
+
+
+
+EFI_STATUS
+InitializeExceptions (
+ IN EFI_CPU_ARCH_PROTOCOL *Cpu
+ )
+{
+ EFI_STATUS Status;
+ UINTN Offset;
+ UINTN Length;
+ UINTN Index;
+ BOOLEAN Enabled;
+ EFI_PHYSICAL_ADDRESS Base;
+
+ //
+ // Disable interrupts
+ //
+ Cpu->GetInterruptState (Cpu, &Enabled);
+ Cpu->DisableInterrupt (Cpu);
+
+ //
+ // Initialize the C entry points for interrupts
+ //
+ for (Index = 0; Index <= MAX_ARM_EXCEPTION; Index++) {
+ Status = RegisterInterruptHandler (Index, NULL);
+ ASSERT_EFI_ERROR (Status);
+
+ Status = RegisterDebuggerInterruptHandler (Index, NULL);
+ ASSERT_EFI_ERROR (Status);
+ }
+
+ //
+ // Copy an implementation of the ARM exception vectors to 0x0.
+ //
+ Length = (UINTN)ExceptionHandlersEnd - (UINTN)ExceptionHandlersStart;
+
+ //
+ // Reserve space for the exception handlers
+ //
+ Base = (EFI_PHYSICAL_ADDRESS)PcdGet32 (PcdCpuVectorBaseAddress);
+ Status = gBS->AllocatePages (AllocateAddress, EfiBootServicesCode, EFI_SIZE_TO_PAGES (Length), &Base);
+ // If the request was for memory that's not in the memory map (which is often the case for 0x00000000
+ // on embedded systems, for example, we don't want to hang up. So we'll check here for a status of
+ // EFI_NOT_FOUND, and continue in that case.
+ if (EFI_ERROR(Status) && (Status != EFI_NOT_FOUND)) {
+ ASSERT_EFI_ERROR (Status);
+ }
+
+ CopyMem ((VOID *)(UINTN)PcdGet32 (PcdCpuVectorBaseAddress), (VOID *)ExceptionHandlersStart, Length);
+
+ //
+ // Patch in the common Assembly exception handler
+ //
+ Offset = (UINTN)CommonExceptionEntry - (UINTN)ExceptionHandlersStart;
+ *(UINTN *) ((UINT8 *)(UINTN)PcdGet32 (PcdCpuVectorBaseAddress) + Offset) = (UINTN)AsmCommonExceptionEntry;
+
+ // Flush Caches since we updated executable stuff
+ InvalidateInstructionCacheRange((VOID *)PcdGet32(PcdCpuVectorBaseAddress), Length);
+
+ if (Enabled) {
+ //
+ // Restore interrupt state
+ //
+ Status = Cpu->EnableInterrupt (Cpu);
+ }
+
+ return Status;
+}
diff --git a/ArmPkg/Drivers/CpuDxe/ExceptionSupport.S b/ArmPkg/Drivers/CpuDxe/ExceptionSupport.S
new file mode 100755
index 0000000000..8574af6d71
--- /dev/null
+++ b/ArmPkg/Drivers/CpuDxe/ExceptionSupport.S
@@ -0,0 +1,152 @@
+#------------------------------------------------------------------------------
+#
+# Copyright (c) 2008-2009 Apple Inc. All rights reserved.
+#
+# 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.
+#
+#------------------------------------------------------------------------------
+
+.text
+.align 3
+
+.globl ASM_PFX(ExceptionHandlersStart)
+.globl ASM_PFX(ExceptionHandlersEnd)
+.globl ASM_PFX(CommonExceptionEntry)
+.globl ASM_PFX(AsmCommonExceptionEntry)
+.globl ASM_PFX(CommonCExceptionHandler)
+
+ASM_PFX(ExceptionHandlersStart):
+
+ASM_PFX(Reset):
+ b ASM_PFX(ResetEntry)
+
+ASM_PFX(UndefinedInstruction):
+ b ASM_PFX(UndefinedInstructionEntry)
+
+ASM_PFX(SoftwareInterrupt):
+ b ASM_PFX(SoftwareInterruptEntry)
+
+ASM_PFX(PrefetchAbort):
+ b ASM_PFX(PrefetchAbortEntry)
+
+ASM_PFX(DataAbort):
+ b ASM_PFX(DataAbortEntry)
+
+ASM_PFX(ReservedException):
+ b ASM_PFX(ReservedExceptionEntry)
+
+ASM_PFX(Irq):
+ b ASM_PFX(IrqEntry)
+
+ASM_PFX(Fiq):
+ b ASM_PFX(FiqEntry)
+
+ASM_PFX(ResetEntry):
+ stmfd sp!,{r0-r1}
+ mov r0,#0
+ ldr r1,ASM_PFX(CommonExceptionEntry)
+ bx r1
+
+ASM_PFX(UndefinedInstructionEntry):
+ stmfd sp!,{r0-r1}
+ mov r0,#1
+ ldr r1,ASM_PFX(CommonExceptionEntry)
+ bx r1
+
+ASM_PFX(SoftwareInterruptEntry):
+ stmfd sp!,{r0-r1}
+ mov r0,#2
+ ldr r1,ASM_PFX(CommonExceptionEntry)
+ bx r1
+
+ASM_PFX(PrefetchAbortEntry):
+ stmfd sp!,{r0-r1}
+ mov r0,#3
+ sub lr,lr,#4
+ ldr r1,ASM_PFX(CommonExceptionEntry)
+ bx r1
+
+ASM_PFX(DataAbortEntry):
+ stmfd sp!,{r0-r1}
+ mov r0,#4
+ sub lr,lr,#8
+ ldr r1,ASM_PFX(CommonExceptionEntry)
+ bx r1
+
+ASM_PFX(ReservedExceptionEntry):
+ stmfd sp!,{r0-r1}
+ mov r0,#5
+ ldr r1,ASM_PFX(CommonExceptionEntry)
+ bx r1
+
+ASM_PFX(IrqEntry):
+ stmfd sp!,{r0-r1}
+ mov r0,#6
+ sub lr,lr,#4
+ ldr r1,ASM_PFX(CommonExceptionEntry)
+ bx r1
+
+ASM_PFX(FiqEntry):
+ stmfd sp!,{r0-r1}
+ mov r0,#7
+ sub lr,lr,#4
+ ldr r1,ASM_PFX(CommonExceptionEntry)
+ bx r1
+
+ASM_PFX(CommonExceptionEntry):
+ .byte 0x12
+ .byte 0x34
+ .byte 0x56
+ .byte 0x78
+
+ASM_PFX(ExceptionHandlersEnd):
+
+ASM_PFX(AsmCommonExceptionEntry):
+ mrc p15, 0, r1, c6, c0, 2 @ Read IFAR
+ stmfd sp!,{r1} @ Store the IFAR
+
+ mrc p15, 0, r1, c5, c0, 1 @ Read IFSR
+ stmfd sp!,{r1} @ Store the IFSR
+
+ mrc p15, 0, r1, c6, c0, 0 @ Read DFAR
+ stmfd sp!,{r1} @ Store the DFAR
+
+ mrc p15, 0, r1, c5, c0, 0 @ Read DFSR
+ stmfd sp!,{r1} @ Store the DFSR
+
+ mrs r1,spsr @ Read SPSR (which is the pre-exception CPSR)
+ stmfd sp!,{r1} @ Store the SPSR
+
+ stmfd sp!,{lr} @ Store the link register (which is the pre-exception PC)
+ stmfd sp,{sp,lr}^ @ Store user/system mode stack pointer and link register
+ nop @ Required by ARM architecture
+ sub sp,sp,#0x08 @ Adjust stack pointer
+ stmfd sp!,{r2-r12} @ Store general purpose registers
+
+ ldr r3,[sp,#0x50] @ Read saved R1 from the stack (it was saved by the exception entry routine)
+ ldr r2,[sp,#0x4C] @ Read saved R0 from the stack (it was saved by the exception entry routine)
+ stmfd sp!,{r2-r3} @ Store general purpose registers R0 and R1
+
+ mov r1,sp @ Prepare System Context pointer as an argument for the exception handler
+
+ sub sp,sp,#4 @ Adjust SP to preserve 8-byte alignment
+ bl ASM_PFX(CommonCExceptionHandler) @ Call exception handler
+ add sp,sp,#4 @ Adjust SP back to where we were
+
+ ldr r2,[sp,#0x40] @ Load CPSR from context, in case it has changed
+ msr SPSR_cxsf,r2 @ Store it back to the SPSR to be restored when exiting this handler
+
+ ldmfd sp!,{r0-r12} @ Restore general purpose registers
+ ldmia sp,{sp,lr}^ @ Restore user/system mode stack pointer and link register
+ nop @ Required by ARM architecture
+ add sp,sp,#0x08 @ Adjust stack pointer
+ ldmfd sp!,{lr} @ Restore the link register (which is the pre-exception PC)
+ add sp,sp,#0x1C @ Clear out the remaining stack space
+ movs pc,lr @ Return from exception
+
diff --git a/ArmPkg/Drivers/CpuDxe/ExceptionSupport.asm b/ArmPkg/Drivers/CpuDxe/ExceptionSupport.asm
new file mode 100755
index 0000000000..d91720cff3
--- /dev/null
+++ b/ArmPkg/Drivers/CpuDxe/ExceptionSupport.asm
@@ -0,0 +1,152 @@
+//------------------------------------------------------------------------------
+//
+// Copyright (c) 2008-2009 Apple Inc. All rights reserved.
+//
+// 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.
+//
+//------------------------------------------------------------------------------
+
+ EXPORT ExceptionHandlersStart
+ EXPORT ExceptionHandlersEnd
+ EXPORT CommonExceptionEntry
+ EXPORT AsmCommonExceptionEntry
+ IMPORT CommonCExceptionHandler
+
+ PRESERVE8
+ AREA DxeExceptionHandlers, CODE, READONLY
+
+ExceptionHandlersStart
+
+Reset
+ b ResetEntry
+
+UndefinedInstruction
+ b UndefinedInstructionEntry
+
+SoftwareInterrupt
+ b SoftwareInterruptEntry
+
+PrefetchAbort
+ b PrefetchAbortEntry
+
+DataAbort
+ b DataAbortEntry
+
+ReservedException
+ b ReservedExceptionEntry
+
+Irq
+ b IrqEntry
+
+Fiq
+ b FiqEntry
+
+ResetEntry
+ stmfd SP!,{R0-R1}
+ mov R0,#0
+ ldr R1,CommonExceptionEntry
+ bx R1
+
+UndefinedInstructionEntry
+ stmfd SP!,{R0-R1}
+ mov R0,#1
+ ldr R1,CommonExceptionEntry
+ bx R1
+
+SoftwareInterruptEntry
+ stmfd SP!,{R0-R1}
+ mov R0,#2
+ ldr R1,CommonExceptionEntry
+ bx R1
+
+PrefetchAbortEntry
+ stmfd SP!,{R0-R1}
+ mov R0,#3
+ SUB LR,LR,#4
+ ldr R1,CommonExceptionEntry
+ bx R1
+
+DataAbortEntry
+ stmfd SP!,{R0-R1}
+ mov R0,#4
+ SUB LR,LR,#8
+ ldr R1,CommonExceptionEntry
+ bx R1
+
+ReservedExceptionEntry
+ stmfd SP!,{R0-R1}
+ mov R0,#5
+ ldr R1,CommonExceptionEntry
+ bx R1
+
+IrqEntry
+ stmfd SP!,{R0-R1}
+ mov R0,#6
+ SUB LR,LR,#4
+ ldr R1,CommonExceptionEntry
+ bx R1
+
+FiqEntry
+ stmfd SP!,{R0-R1}
+ mov R0,#7
+ SUB LR,LR,#4
+ ldr R1,CommonExceptionEntry
+ bx R1
+
+CommonExceptionEntry
+ dcd 0x12345678
+
+ExceptionHandlersEnd
+
+AsmCommonExceptionEntry
+ mrc p15, 0, r1, c6, c0, 2 ; Read IFAR
+ stmfd SP!,{R1} ; Store the IFAR
+
+ mrc p15, 0, r1, c5, c0, 1 ; Read IFSR
+ stmfd SP!,{R1} ; Store the IFSR
+
+ mrc p15, 0, r1, c6, c0, 0 ; Read DFAR
+ stmfd SP!,{R1} ; Store the DFAR
+
+ mrc p15, 0, r1, c5, c0, 0 ; Read DFSR
+ stmfd SP!,{R1} ; Store the DFSR
+
+ mrs R1,SPSR ; Read SPSR (which is the pre-exception CPSR)
+ stmfd SP!,{R1} ; Store the SPSR
+
+ stmfd SP!,{LR} ; Store the link register (which is the pre-exception PC)
+ stmfd SP,{SP,LR}^ ; Store user/system mode stack pointer and link register
+ nop ; Required by ARM architecture
+ SUB SP,SP,#0x08 ; Adjust stack pointer
+ stmfd SP!,{R2-R12} ; Store general purpose registers
+
+ ldr R3,[SP,#0x50] ; Read saved R1 from the stack (it was saved by the exception entry routine)
+ ldr R2,[SP,#0x4C] ; Read saved R0 from the stack (it was saved by the exception entry routine)
+ stmfd SP!,{R2-R3} ; Store general purpose registers R0 and R1
+
+ mov R1,SP ; Prepare System Context pointer as an argument for the exception handler
+
+ sub SP,SP,#4 ; Adjust SP to preserve 8-byte alignment
+ blx CommonCExceptionHandler ; Call exception handler
+ add SP,SP,#4 ; Adjust SP back to where we were
+
+ ldr R2,[SP,#0x40] ; Load CPSR from context, in case it has changed
+ MSR SPSR_cxsf,R2 ; Store it back to the SPSR to be restored when exiting this handler
+
+ ldmfd SP!,{R0-R12} ; Restore general purpose registers
+ ldm SP,{SP,LR}^ ; Restore user/system mode stack pointer and link register
+ nop ; Required by ARM architecture
+ add SP,SP,#0x08 ; Adjust stack pointer
+ ldmfd SP!,{LR} ; Restore the link register (which is the pre-exception PC)
+ add SP,SP,#0x1C ; Clear out the remaining stack space
+ movs PC,LR ; Return from exception
+
+ END
+
+