2010-01-27 03:47:47 +01:00
/** @file
Default exception handler
2010-04-29 14:15:47 +02:00
Copyright ( c ) 2008 - 2010 , Apple Inc . All rights reserved . < BR >
2012-09-28 11:55:48 +02:00
Copyright ( c ) 2012 , ARM Ltd . All rights reserved . < BR >
2014-08-19 15:29:52 +02:00
2010-04-29 14:15:47 +02:00
This program and the accompanying materials
2010-01-27 03:47:47 +01:00
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 <Uefi.h>
# include <Library/BaseLib.h>
# include <Library/DebugLib.h>
# include <Library/PeCoffGetEntryPointLib.h>
2011-11-02 00:34:14 +01:00
# include <Library/PrintLib.h>
2010-02-01 19:25:18 +01:00
# include <Library/ArmDisassemblerLib.h>
2011-11-02 00:34:14 +01:00
# include <Library/SerialPortLib.h>
2010-01-27 03:47:47 +01:00
# include <Guid/DebugImageInfoTable.h>
2012-09-28 11:55:48 +02:00
# include <Protocol/DebugSupport.h>
# include <Library/DefaultExceptionHandlerLib.h>
2010-01-27 03:47:47 +01:00
EFI_DEBUG_IMAGE_INFO_TABLE_HEADER * gDebugImageTableHeader = NULL ;
typedef struct {
UINT32 BIT ;
CHAR8 Char ;
} CPSR_CHAR ;
CHAR8 *
GetImageName (
2013-03-12 01:50:46 +01:00
IN UINTN FaultAddress ,
OUT UINTN * ImageBase ,
OUT UINTN * PeCoffSizeOfHeaders
2012-09-28 11:55:48 +02:00
) ;
2010-01-27 03:47:47 +01:00
/**
2014-08-19 15:29:52 +02:00
Convert the Current Program Status Register ( CPSR ) to a string . The string is
a defacto standard in the ARM world .
2010-01-27 03:47:47 +01:00
It is possible to add extra bits by adding them to CpsrChar array .
@ param Cpsr ARM CPSR register value
@ param ReturnStr 32 byte string that contains string version of CPSR
* */
VOID
CpsrString (
IN UINT32 Cpsr ,
OUT CHAR8 * ReturnStr
)
{
2011-09-23 00:53:54 +02:00
UINTN Index ;
CHAR8 * Str ;
CHAR8 * ModeStr ;
2010-01-27 03:47:47 +01:00
CPSR_CHAR CpsrChar [ ] = {
{ 31 , ' n ' } ,
{ 30 , ' z ' } ,
{ 29 , ' c ' } ,
{ 28 , ' v ' } ,
{ 9 , ' e ' } ,
{ 8 , ' a ' } ,
{ 7 , ' i ' } ,
{ 6 , ' f ' } ,
{ 5 , ' t ' } ,
{ 0 , ' ? ' }
} ;
2014-08-19 15:29:52 +02:00
2011-09-23 00:53:54 +02:00
Str = ReturnStr ;
2010-01-27 03:47:47 +01:00
for ( Index = 0 ; CpsrChar [ Index ] . BIT ! = 0 ; Index + + , Str + + ) {
* Str = CpsrChar [ Index ] . Char ;
if ( ( Cpsr & ( 1 < < CpsrChar [ Index ] . BIT ) ) ! = 0 ) {
// Concert to upper case if bit is set
* Str & = ~ 0x20 ;
}
}
2014-08-19 15:29:52 +02:00
2010-01-27 03:47:47 +01:00
* Str + + = ' _ ' ;
* Str = ' \0 ' ;
2014-08-19 15:29:52 +02:00
2010-01-27 03:47:47 +01:00
switch ( Cpsr & 0x1f ) {
case 0x10 :
ModeStr = " usr " ;
break ;
case 0x011 :
ModeStr = " fiq " ;
break ;
case 0x12 :
ModeStr = " irq " ;
break ;
case 0x13 :
ModeStr = " svc " ;
break ;
case 0x16 :
ModeStr = " mon " ;
break ;
case 0x17 :
ModeStr = " abt " ;
break ;
case 0x1b :
ModeStr = " und " ;
break ;
case 0x1f :
ModeStr = " sys " ;
break ;
2014-08-19 15:29:52 +02:00
2010-01-27 03:47:47 +01:00
default :
ModeStr = " ??? " ;
break ;
}
2014-08-19 15:29:52 +02:00
2010-01-27 03:47:47 +01:00
AsciiStrCat ( Str , ModeStr ) ;
return ;
2014-08-19 15:29:52 +02:00
}
2010-01-29 22:49:26 +01:00
CHAR8 *
FaultStatusToString (
IN UINT32 Status
)
{
CHAR8 * FaultSource ;
switch ( Status ) {
case 0x01 : FaultSource = " Alignment fault " ; break ;
case 0x02 : FaultSource = " Debug event fault " ; break ;
case 0x03 : FaultSource = " Access Flag fault on Section " ; break ;
case 0x04 : FaultSource = " Cache maintenance operation fault[2] " ; break ;
case 0x05 : FaultSource = " Translation fault on Section " ; break ;
case 0x06 : FaultSource = " Access Flag fault on Page " ; break ;
case 0x07 : FaultSource = " Translation fault on Page " ; break ;
case 0x08 : FaultSource = " Precise External Abort " ; break ;
case 0x09 : FaultSource = " Domain fault on Section " ; break ;
case 0x0b : FaultSource = " Domain fault on Page " ; break ;
case 0x0c : FaultSource = " External abort on translation, first level " ; break ;
case 0x0d : FaultSource = " Permission fault on Section " ; break ;
case 0x0e : FaultSource = " External abort on translation, second level " ; break ;
case 0x0f : FaultSource = " Permission fault on Page " ; break ;
case 0x16 : FaultSource = " Imprecise External Abort " ; break ;
default : FaultSource = " No function " ; break ;
}
return FaultSource ;
}
2011-09-23 00:53:54 +02:00
STATIC CHAR8 * gExceptionTypeString [ ] = {
2010-01-27 03:47:47 +01:00
" Reset " ,
" Undefined OpCode " ,
2012-09-28 11:55:48 +02:00
" SVC " ,
2010-01-27 03:47:47 +01:00
" Prefetch Abort " ,
" Data Abort " ,
" Undefined " ,
" IRQ " ,
" FIQ "
} ;
/**
This is the default action to take on an unexpected exception
2014-08-19 15:29:52 +02:00
2010-01-27 03:47:47 +01:00
Since this is exception context don ' t do anything crazy like try to allcoate memory .
@ param ExceptionType Type of the exception
@ param SystemContext Register state at the time of the Exception
* */
VOID
DefaultExceptionHandler (
IN EFI_EXCEPTION_TYPE ExceptionType ,
IN OUT EFI_SYSTEM_CONTEXT SystemContext
)
{
2011-11-02 00:34:14 +01:00
CHAR8 Buffer [ 100 ] ;
UINTN CharCount ;
2010-01-29 22:49:26 +01:00
UINT32 DfsrStatus ;
2010-02-17 00:45:42 +01:00
UINT32 IfsrStatus ;
2010-01-29 22:49:26 +01:00
BOOLEAN DfsrWrite ;
2010-02-16 02:03:16 +01:00
UINT32 PcAdjust = 0 ;
2010-01-27 03:47:47 +01:00
2011-11-02 00:34:14 +01:00
CharCount = AsciiSPrint ( Buffer , sizeof ( Buffer ) , " \n %a Exception PC at 0x%08x CPSR 0x%08x " ,
ARM Packages: Replace tabs by spaces for indentation
Replace tabs by spaces for indentation to comply to EDK2 coding standards.
Done in files with extension ".S", ".c", ".h", ".asm", ".dsc", ".inc", "*.inf",
"*.dec" or ".fdf" and located in ArmPkg, ArmPlatformPkg, EmbeddedPkg,
BeagleBoardPkg or Omap35xxPkg.
Contributed-under: TianoCore Contribution Agreement 1.0
Signed-off-by: Ronald Cron <ronald.cron@arm.com>
Reviewed-By: Olivier Martin <olivier.martin@arm.com>
git-svn-id: https://svn.code.sf.net/p/edk2/code/trunk/edk2@15901 6f19259b-4bc3-4df7-8a09-765794883524
2014-08-26 12:14:17 +02:00
gExceptionTypeString [ ExceptionType ] , SystemContext . SystemContextArm - > PC , SystemContext . SystemContextArm - > CPSR ) ;
2011-11-02 00:34:14 +01:00
SerialPortWrite ( ( UINT8 * ) Buffer , CharCount ) ;
2010-01-27 03:47:47 +01:00
DEBUG_CODE_BEGIN ( ) ;
CHAR8 * Pdb ;
UINT32 ImageBase ;
UINT32 PeCoffSizeOfHeader ;
UINT32 Offset ;
CHAR8 CpsrStr [ 32 ] ; // char per bit. Lower 5-bits are mode that is a 3 char string
CHAR8 Buffer [ 80 ] ;
2010-02-01 19:25:18 +01:00
UINT8 * DisAsm ;
2010-02-05 07:50:09 +01:00
UINT32 ItBlock ;
2014-08-19 15:29:52 +02:00
2010-01-27 03:47:47 +01:00
CpsrString ( SystemContext . SystemContextArm - > CPSR , CpsrStr ) ;
DEBUG ( ( EFI_D_ERROR , " %a \n " , CpsrStr ) ) ;
2014-08-19 15:29:52 +02:00
2010-01-27 03:47:47 +01:00
Pdb = GetImageName ( SystemContext . SystemContextArm - > PC , & ImageBase , & PeCoffSizeOfHeader ) ;
Offset = SystemContext . SystemContextArm - > PC - ImageBase ;
if ( Pdb ! = NULL ) {
DEBUG ( ( EFI_D_ERROR , " %a \n " , Pdb ) ) ;
//
2014-08-19 15:29:52 +02:00
// A PE/COFF image loads its headers into memory so the headers are
2011-09-23 00:53:54 +02:00
// included in the linked addresses. ELF and Mach-O images do not
2010-01-27 03:47:47 +01:00
// include the headers so the first byte of the image is usually
// text (code). If you look at link maps from ELF or Mach-O images
2011-09-23 00:53:54 +02:00
// you need to subtract out the size of the PE/COFF header to get
2014-08-19 15:29:52 +02:00
// get the offset that matches the link map.
2010-01-27 03:47:47 +01:00
//
DEBUG ( ( EFI_D_ERROR , " loaded at 0x%08x (PE/COFF offset) 0x%x (ELF or Mach-O offset) 0x%x " , ImageBase , Offset , Offset - PeCoffSizeOfHeader ) ) ;
2014-08-19 15:29:52 +02:00
2010-01-27 03:47:47 +01:00
// If we come from an image it is safe to show the instruction. We know it should not fault
2010-02-01 19:25:18 +01:00
DisAsm = ( UINT8 * ) ( UINTN ) SystemContext . SystemContextArm - > PC ;
2010-02-05 07:50:09 +01:00
ItBlock = 0 ;
DisassembleInstruction ( & DisAsm , ( SystemContext . SystemContextArm - > CPSR & BIT5 ) = = BIT5 , TRUE , & ItBlock , Buffer , sizeof ( Buffer ) ) ;
2010-02-01 19:25:18 +01:00
DEBUG ( ( EFI_D_ERROR , " \n %a " , Buffer ) ) ;
2014-08-19 15:29:52 +02:00
2010-02-16 02:03:16 +01:00
switch ( ExceptionType ) {
case EXCEPT_ARM_UNDEFINED_INSTRUCTION :
case EXCEPT_ARM_SOFTWARE_INTERRUPT :
case EXCEPT_ARM_PREFETCH_ABORT :
case EXCEPT_ARM_DATA_ABORT :
// advance PC past the faulting instruction
PcAdjust = ( UINTN ) DisAsm - SystemContext . SystemContextArm - > PC ;
break ;
2014-08-19 15:29:52 +02:00
2010-02-16 02:03:16 +01:00
default :
break ;
}
2010-02-01 19:25:18 +01:00
2010-01-27 03:47:47 +01:00
}
DEBUG_CODE_END ( ) ;
DEBUG ( ( EFI_D_ERROR , " \n R0 0x%08x R1 0x%08x R2 0x%08x R3 0x%08x \n " , SystemContext . SystemContextArm - > R0 , SystemContext . SystemContextArm - > R1 , SystemContext . SystemContextArm - > R2 , SystemContext . SystemContextArm - > R3 ) ) ;
DEBUG ( ( EFI_D_ERROR , " R4 0x%08x R5 0x%08x R6 0x%08x R7 0x%08x \n " , SystemContext . SystemContextArm - > R4 , SystemContext . SystemContextArm - > R5 , SystemContext . SystemContextArm - > R6 , SystemContext . SystemContextArm - > R7 ) ) ;
DEBUG ( ( EFI_D_ERROR , " R8 0x%08x R9 0x%08x R10 0x%08x R11 0x%08x \n " , SystemContext . SystemContextArm - > R8 , SystemContext . SystemContextArm - > R9 , SystemContext . SystemContextArm - > R10 , SystemContext . SystemContextArm - > R11 ) ) ;
DEBUG ( ( EFI_D_ERROR , " R12 0x%08x SP 0x%08x LR 0x%08x PC 0x%08x \n " , SystemContext . SystemContextArm - > R12 , SystemContext . SystemContextArm - > SP , SystemContext . SystemContextArm - > LR , SystemContext . SystemContextArm - > PC ) ) ;
2010-01-29 22:49:26 +01:00
DEBUG ( ( EFI_D_ERROR , " DFSR 0x%08x DFAR 0x%08x IFSR 0x%08x IFAR 0x%08x \n " , SystemContext . SystemContextArm - > DFSR , SystemContext . SystemContextArm - > DFAR , SystemContext . SystemContextArm - > IFSR , SystemContext . SystemContextArm - > IFAR ) ) ;
// Bit10 is Status[4] Bit3:0 is Status[3:0]
DfsrStatus = ( SystemContext . SystemContextArm - > DFSR & 0xf ) | ( ( SystemContext . SystemContextArm - > DFSR > > 6 ) & 0x10 ) ;
DfsrWrite = ( SystemContext . SystemContextArm - > DFSR & BIT11 ) ! = 0 ;
if ( DfsrStatus ! = 0x00 ) {
DEBUG ( ( EFI_D_ERROR , " %a: %a 0x%08x \n " , FaultStatusToString ( DfsrStatus ) , DfsrWrite ? " write to " : " read from " , SystemContext . SystemContextArm - > DFAR ) ) ;
}
2010-02-17 00:45:42 +01:00
IfsrStatus = ( SystemContext . SystemContextArm - > IFSR & 0xf ) | ( ( SystemContext . SystemContextArm - > IFSR > > 6 ) & 0x10 ) ;
if ( IfsrStatus ! = 0 ) {
DEBUG ( ( EFI_D_ERROR , " Instruction %a at 0x%08x \n " , FaultStatusToString ( SystemContext . SystemContextArm - > IFSR & 0xf ) , SystemContext . SystemContextArm - > IFAR ) ) ;
2010-01-29 22:49:26 +01:00
}
2010-01-27 03:47:47 +01:00
2010-01-29 22:49:26 +01:00
DEBUG ( ( EFI_D_ERROR , " \n " ) ) ;
2010-01-27 03:47:47 +01:00
ASSERT ( FALSE ) ;
2014-08-19 15:29:52 +02:00
2010-04-13 21:27:03 +02:00
// Clear the error registers that we have already displayed incase some one wants to keep going
SystemContext . SystemContextArm - > DFSR = 0 ;
SystemContext . SystemContextArm - > IFSR = 0 ;
2014-08-19 15:29:52 +02:00
// If some one is stepping past the exception handler adjust the PC to point to the next instruction
2010-02-16 02:03:16 +01:00
SystemContext . SystemContextArm - > PC + = PcAdjust ;
2010-01-27 03:47:47 +01:00
}