From 2ef2b01e07c02db339f34004445734a2dbdd80e1 Mon Sep 17 00:00:00 2001 From: AJFISH Date: Sun, 6 Dec 2009 01:57:05 +0000 Subject: 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 --- ArmPkg/Drivers/CpuDxe/CpuDxe.c | 154 +++++++++++++ ArmPkg/Drivers/CpuDxe/CpuDxe.h | 91 ++++++++ ArmPkg/Drivers/CpuDxe/CpuDxe.inf | 56 +++++ ArmPkg/Drivers/CpuDxe/DebugSupport.c | 247 +++++++++++++++++++++ ArmPkg/Drivers/CpuDxe/Exception.c | 238 ++++++++++++++++++++ ArmPkg/Drivers/CpuDxe/ExceptionSupport.S | 152 +++++++++++++ ArmPkg/Drivers/CpuDxe/ExceptionSupport.asm | 152 +++++++++++++ ArmPkg/Drivers/DebugSupportDxe/DebugSupport.c | 119 ++++++++++ ArmPkg/Drivers/DebugSupportDxe/DebugSupportDxe.inf | 30 +++ 9 files changed, 1239 insertions(+) create mode 100644 ArmPkg/Drivers/CpuDxe/CpuDxe.c create mode 100644 ArmPkg/Drivers/CpuDxe/CpuDxe.h create mode 100644 ArmPkg/Drivers/CpuDxe/CpuDxe.inf create mode 100644 ArmPkg/Drivers/CpuDxe/DebugSupport.c create mode 100644 ArmPkg/Drivers/CpuDxe/Exception.c create mode 100755 ArmPkg/Drivers/CpuDxe/ExceptionSupport.S create mode 100755 ArmPkg/Drivers/CpuDxe/ExceptionSupport.asm create mode 100644 ArmPkg/Drivers/DebugSupportDxe/DebugSupport.c create mode 100644 ArmPkg/Drivers/DebugSupportDxe/DebugSupportDxe.inf (limited to 'ArmPkg/Drivers') 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.
+ + 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 + +#include +#include +#include +#include +#include +#include + +#include +#include +#include + + +/** + 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.
+# 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 + +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 + + diff --git a/ArmPkg/Drivers/DebugSupportDxe/DebugSupport.c b/ArmPkg/Drivers/DebugSupportDxe/DebugSupport.c new file mode 100644 index 0000000000..26f4c387dc --- /dev/null +++ b/ArmPkg/Drivers/DebugSupportDxe/DebugSupport.c @@ -0,0 +1,119 @@ +/** @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 + +#include +#include +#include + +#include +#include +#include + +EFI_STATUS +EFIAPI +DebugSupportGetMaximumProcessorIndex ( + IN EFI_DEBUG_SUPPORT_PROTOCOL *This, + OUT UINTN *MaxProcessorIndex + ) +{ + if (MaxProcessorIndex == NULL) { + return EFI_INVALID_PARAMETER; + } + + *MaxProcessorIndex = 0; + + return EFI_SUCCESS; +} + +EFI_STATUS +EFIAPI +DebugSupportRegisterPeriodicCallback ( + IN EFI_DEBUG_SUPPORT_PROTOCOL *This, + IN UINTN ProcessorIndex, + IN EFI_PERIODIC_CALLBACK PeriodicCallback + ) +{ + TIMER_DEBUG_SUPPORT_PROTOCOL *Timer; + EFI_STATUS Status; + + Status = gBS->LocateProtocol(&gTimerDebugSupportProtocolGuid, NULL, (VOID **)&Timer); + if (EFI_ERROR(Status)) { + return Status; + } + + Status = Timer->RegisterPeriodicCallback(Timer, PeriodicCallback); + + return Status; +} + +EFI_STATUS +EFIAPI +DebugSupportRegisterExceptionCallback ( + IN EFI_DEBUG_SUPPORT_PROTOCOL *This, + IN UINTN ProcessorIndex, + IN EFI_EXCEPTION_CALLBACK ExceptionCallback, + IN EFI_EXCEPTION_TYPE ExceptionType + ) +{ + EFI_CPU_ARCH_PROTOCOL *Cpu; + EFI_STATUS Status; + + Status = gBS->LocateProtocol(&gEfiCpuArchProtocolGuid, NULL, (VOID **)&Cpu); + if (EFI_ERROR(Status)) { + return Status; + } + + Status = Cpu->RegisterInterruptHandler(Cpu, ExceptionType, (EFI_CPU_INTERRUPT_HANDLER)ExceptionCallback); + + return Status; +} + +EFI_STATUS +EFIAPI +DebugSupportInvalidateInstructionCache ( + IN EFI_DEBUG_SUPPORT_PROTOCOL *This, + IN UINTN ProcessorIndex, + IN VOID *Start, + IN UINT64 Length + ) +{ + InvalidateInstructionCacheRange(Start, Length); + return EFI_SUCCESS; +} + +EFI_DEBUG_SUPPORT_PROTOCOL mDebugSupport = { + IsaArm, + DebugSupportGetMaximumProcessorIndex, + DebugSupportRegisterPeriodicCallback, + DebugSupportRegisterExceptionCallback, + DebugSupportInvalidateInstructionCache +}; + +EFI_STATUS +DebugSupportDxeInitialize ( + IN EFI_HANDLE ImageHandle, + IN EFI_SYSTEM_TABLE *SystemTable + ) +{ + EFI_STATUS Status; + EFI_HANDLE Handle = NULL; + + ASSERT_PROTOCOL_ALREADY_INSTALLED (NULL, &gEfiDebugSupportProtocolGuid); + Status = gBS->InstallMultipleProtocolInterfaces(&Handle, &gEfiDebugSupportProtocolGuid, &mDebugSupport, NULL); + + return Status; +} + diff --git a/ArmPkg/Drivers/DebugSupportDxe/DebugSupportDxe.inf b/ArmPkg/Drivers/DebugSupportDxe/DebugSupportDxe.inf new file mode 100644 index 0000000000..59f44879c4 --- /dev/null +++ b/ArmPkg/Drivers/DebugSupportDxe/DebugSupportDxe.inf @@ -0,0 +1,30 @@ +#%HEADER% +[Defines] + INF_VERSION = 0x00010005 + BASE_NAME = ArmDebugSupportDxe + FILE_GUID = 2e7c151b-cbd8-4df6-a0e3-cde660067c6a + MODULE_TYPE = DXE_DRIVER + VERSION_STRING = 1.0 + + ENTRY_POINT = DebugSupportDxeInitialize + +[Sources.common] + DebugSupport.c + +[Packages] + ArmPkg/ArmPkg.dec + MdePkg/MdePkg.dec + +[LibraryClasses] + BaseMemoryLib + CacheMaintenanceLib + UefiDriverEntryPoint + ArmLib + +[Protocols] + gEfiCpuArchProtocolGuid + gEfiDebugSupportProtocolGuid + gTimerDebugSupportProtocolGuid + +[Depex] + TRUE \ No newline at end of file -- cgit v1.2.3