1 /* 2 * FreeRTOS Kernel V11.1.0 3 * Copyright (C) 2021 Amazon.com, Inc. or its affiliates. All Rights Reserved. 4 * 5 * SPDX-License-Identifier: MIT 6 * 7 * Permission is hereby granted, free of charge, to any person obtaining a copy of 8 * this software and associated documentation files (the "Software"), to deal in 9 * the Software without restriction, including without limitation the rights to 10 * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of 11 * the Software, and to permit persons to whom the Software is furnished to do so, 12 * subject to the following conditions: 13 * 14 * The above copyright notice and this permission notice shall be included in all 15 * copies or substantial portions of the Software. 16 * 17 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 18 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS 19 * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR 20 * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER 21 * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN 22 * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 23 * 24 * https://www.FreeRTOS.org 25 * https://github.com/FreeRTOS 26 * 27 */ 28 29 /* Scheduler includes. */ 30 #include "FreeRTOS.h" 31 #include "task.h" 32 33 /* Hardware includes. */ 34 #include <microblaze_exceptions_i.h> 35 #include <microblaze_exceptions_g.h> 36 37 /* The Xilinx library defined exception entry point stacks a number of 38 * registers. These definitions are offsets from the stack pointer to the various 39 * stacked register values. */ 40 #define portexR3_STACK_OFFSET 4 41 #define portexR4_STACK_OFFSET 5 42 #define portexR5_STACK_OFFSET 6 43 #define portexR6_STACK_OFFSET 7 44 #define portexR7_STACK_OFFSET 8 45 #define portexR8_STACK_OFFSET 9 46 #define portexR9_STACK_OFFSET 10 47 #define portexR10_STACK_OFFSET 11 48 #define portexR11_STACK_OFFSET 12 49 #define portexR12_STACK_OFFSET 13 50 #define portexR15_STACK_OFFSET 16 51 #define portexR18_STACK_OFFSET 19 52 #define portexMSR_STACK_OFFSET 20 53 #define portexR19_STACK_OFFSET -1 54 55 /* This is defined to equal the size, in bytes, of the stack frame generated by 56 * the Xilinx standard library exception entry point. It is required to determine 57 * the stack pointer value prior to the exception being entered. */ 58 #define portexASM_HANDLER_STACK_FRAME_SIZE 84UL 59 60 /* The number of bytes a MicroBlaze instruction consumes. */ 61 #define portexINSTRUCTION_SIZE 4 62 63 /* Exclude this entire file if the MicroBlaze is not configured to handle 64 * exceptions, or the application defined configuration constant 65 * configINSTALL_EXCEPTION_HANDLERS is not set to 1. */ 66 #if ( MICROBLAZE_EXCEPTIONS_ENABLED == 1 ) && ( configINSTALL_EXCEPTION_HANDLERS == 1 ) 67 68 /* This variable is set in the exception entry code, before 69 * vPortExceptionHandler is called. */ 70 UINTPTR *pulStackPointerOnFunctionEntry = NULL; 71 72 /* This is the structure that is filled with the MicroBlaze context as it 73 * existed immediately prior to the exception occurrence. A pointer to this 74 * structure is passed into the vApplicationExceptionRegisterDump() callback 75 * function, if one is defined. */ 76 static xPortRegisterDump xRegisterDump; 77 78 /* This is the FreeRTOS exception handler that is installed for all exception 79 * types. It is called from vPortExceptionHandlerEntry() - which is itself defined 80 * in portasm.S. */ 81 void vPortExceptionHandler( void * pvExceptionID ); 82 extern void vPortExceptionHandlerEntry( void * pvExceptionID ); 83 /*-----------------------------------------------------------*/ 84 85 /* vApplicationExceptionRegisterDump() is a callback function that the 86 * application can optionally define to receive a populated xPortRegisterDump 87 * structure. If the application chooses not to define a version of 88 * vApplicationExceptionRegisterDump() then this weekly defined default 89 * implementation will be called instead. */ 90 extern void vApplicationExceptionRegisterDump( xPortRegisterDump * xRegisterDump ) __attribute__( ( weak ) ); vApplicationExceptionRegisterDump(xPortRegisterDump * xRegisterDump)91 void vApplicationExceptionRegisterDump( xPortRegisterDump * xRegisterDump ) 92 { 93 ( void ) xRegisterDump; 94 95 for( ; ; ) 96 { 97 portNOP(); 98 } 99 } 100 /*-----------------------------------------------------------*/ 101 vPortExceptionHandler(void * pvExceptionID)102 void vPortExceptionHandler( void * pvExceptionID ) 103 { 104 extern void * pxCurrentTCB; 105 106 /* Fill an xPortRegisterDump structure with the MicroBlaze context as it 107 * was immediately before the exception occurrence. */ 108 109 /* First fill in the name and handle of the task that was in the Running 110 * state when the exception occurred. */ 111 xRegisterDump.xCurrentTaskHandle = pxCurrentTCB; 112 xRegisterDump.pcCurrentTaskName = pcTaskGetName( NULL ); 113 114 configASSERT( pulStackPointerOnFunctionEntry ); 115 116 /* Obtain the values of registers that were stacked prior to this function 117 * being called, and may have changed since they were stacked. */ 118 xRegisterDump.ulR3 = pulStackPointerOnFunctionEntry[ portexR3_STACK_OFFSET ]; 119 xRegisterDump.ulR4 = pulStackPointerOnFunctionEntry[ portexR4_STACK_OFFSET ]; 120 xRegisterDump.ulR5 = pulStackPointerOnFunctionEntry[ portexR5_STACK_OFFSET ]; 121 xRegisterDump.ulR6 = pulStackPointerOnFunctionEntry[ portexR6_STACK_OFFSET ]; 122 xRegisterDump.ulR7 = pulStackPointerOnFunctionEntry[ portexR7_STACK_OFFSET ]; 123 xRegisterDump.ulR8 = pulStackPointerOnFunctionEntry[ portexR8_STACK_OFFSET ]; 124 xRegisterDump.ulR9 = pulStackPointerOnFunctionEntry[ portexR9_STACK_OFFSET ]; 125 xRegisterDump.ulR10 = pulStackPointerOnFunctionEntry[ portexR10_STACK_OFFSET ]; 126 xRegisterDump.ulR11 = pulStackPointerOnFunctionEntry[ portexR11_STACK_OFFSET ]; 127 xRegisterDump.ulR12 = pulStackPointerOnFunctionEntry[ portexR12_STACK_OFFSET ]; 128 xRegisterDump.ulR15_return_address_from_subroutine = pulStackPointerOnFunctionEntry[ portexR15_STACK_OFFSET ]; 129 xRegisterDump.ulR18 = pulStackPointerOnFunctionEntry[ portexR18_STACK_OFFSET ]; 130 xRegisterDump.ulR19 = pulStackPointerOnFunctionEntry[ portexR19_STACK_OFFSET ]; 131 xRegisterDump.ulMSR = pulStackPointerOnFunctionEntry[ portexMSR_STACK_OFFSET ]; 132 133 /* Obtain the value of all other registers. */ 134 xRegisterDump.ulR2_small_data_area = mfgpr( R2 ); 135 xRegisterDump.ulR13_read_write_small_data_area = mfgpr( R13 ); 136 xRegisterDump.ulR14_return_address_from_interrupt = mfgpr( R14 ); 137 xRegisterDump.ulR16_return_address_from_trap = mfgpr( R16 ); 138 xRegisterDump.ulR17_return_address_from_exceptions = mfgpr( R17 ); 139 xRegisterDump.ulR20 = mfgpr( R20 ); 140 xRegisterDump.ulR21 = mfgpr( R21 ); 141 xRegisterDump.ulR22 = mfgpr( R22 ); 142 xRegisterDump.ulR23 = mfgpr( R23 ); 143 xRegisterDump.ulR24 = mfgpr( R24 ); 144 xRegisterDump.ulR25 = mfgpr( R25 ); 145 xRegisterDump.ulR26 = mfgpr( R26 ); 146 xRegisterDump.ulR27 = mfgpr( R27 ); 147 xRegisterDump.ulR28 = mfgpr( R28 ); 148 xRegisterDump.ulR29 = mfgpr( R29 ); 149 xRegisterDump.ulR30 = mfgpr( R30 ); 150 xRegisterDump.ulR31 = mfgpr( R31 ); 151 xRegisterDump.ulR1_SP = ( ( UINTPTR ) pulStackPointerOnFunctionEntry ) + portexASM_HANDLER_STACK_FRAME_SIZE; 152 xRegisterDump.ulEAR = mfear(); 153 xRegisterDump.ulESR = mfesr(); 154 xRegisterDump.ulEDR = mfedr(); 155 156 /* Move the saved program counter back to the instruction that was executed 157 * when the exception occurred. This is only valid for certain types of 158 * exception. */ 159 xRegisterDump.ulPC = xRegisterDump.ulR17_return_address_from_exceptions - portexINSTRUCTION_SIZE; 160 161 #if ( XPAR_MICROBLAZE_USE_FPU != 0 ) 162 { 163 xRegisterDump.ulFSR = mffsr(); 164 } 165 #else 166 { 167 xRegisterDump.ulFSR = 0UL; 168 } 169 #endif 170 171 /* Also fill in a string that describes what type of exception this is. 172 * The string uses the same ID names as defined in the MicroBlaze standard 173 * library exception header files. */ 174 switch( ( uint32_t ) pvExceptionID ) 175 { 176 case XEXC_ID_FSL: 177 xRegisterDump.pcExceptionCause = ( int8_t * const ) "XEXC_ID_FSL"; 178 break; 179 180 case XEXC_ID_UNALIGNED_ACCESS: 181 xRegisterDump.pcExceptionCause = ( int8_t * const ) "XEXC_ID_UNALIGNED_ACCESS"; 182 break; 183 184 case XEXC_ID_ILLEGAL_OPCODE: 185 xRegisterDump.pcExceptionCause = ( int8_t * const ) "XEXC_ID_ILLEGAL_OPCODE"; 186 break; 187 188 case XEXC_ID_M_AXI_I_EXCEPTION: 189 xRegisterDump.pcExceptionCause = ( int8_t * const ) "XEXC_ID_M_AXI_I_EXCEPTION or XEXC_ID_IPLB_EXCEPTION"; 190 break; 191 192 case XEXC_ID_M_AXI_D_EXCEPTION: 193 xRegisterDump.pcExceptionCause = ( int8_t * const ) "XEXC_ID_M_AXI_D_EXCEPTION or XEXC_ID_DPLB_EXCEPTION"; 194 break; 195 196 case XEXC_ID_DIV_BY_ZERO: 197 xRegisterDump.pcExceptionCause = ( int8_t * const ) "XEXC_ID_DIV_BY_ZERO"; 198 break; 199 200 case XEXC_ID_STACK_VIOLATION: 201 xRegisterDump.pcExceptionCause = ( int8_t * const ) "XEXC_ID_STACK_VIOLATION or XEXC_ID_MMU"; 202 break; 203 204 #if ( XPAR_MICROBLAZE_USE_FPU != 0 ) 205 case XEXC_ID_FPU: 206 xRegisterDump.pcExceptionCause = ( int8_t * const ) "XEXC_ID_FPU see ulFSR value"; 207 break; 208 #endif /* XPAR_MICROBLAZE_USE_FPU */ 209 } 210 211 /* vApplicationExceptionRegisterDump() is a callback function that the 212 * application can optionally define to receive the populated xPortRegisterDump 213 * structure. If the application chooses not to define a version of 214 * vApplicationExceptionRegisterDump() then the weekly defined default 215 * implementation within this file will be called instead. */ 216 vApplicationExceptionRegisterDump( &xRegisterDump ); 217 218 /* Must not attempt to leave this function! */ 219 for( ; ; ) 220 { 221 portNOP(); 222 } 223 } 224 /*-----------------------------------------------------------*/ 225 vPortExceptionsInstallHandlers(void)226 void vPortExceptionsInstallHandlers( void ) 227 { 228 static uint32_t ulHandlersAlreadyInstalled = pdFALSE; 229 230 if( ulHandlersAlreadyInstalled == pdFALSE ) 231 { 232 ulHandlersAlreadyInstalled = pdTRUE; 233 234 #if XPAR_MICROBLAZE_UNALIGNED_EXCEPTIONS == 1 235 microblaze_register_exception_handler( XEXC_ID_UNALIGNED_ACCESS, vPortExceptionHandlerEntry, ( void * ) XEXC_ID_UNALIGNED_ACCESS ); 236 #endif /* XPAR_MICROBLAZE_UNALIGNED_EXCEPTIONS*/ 237 238 #if XPAR_MICROBLAZE_ILL_OPCODE_EXCEPTION == 1 239 microblaze_register_exception_handler( XEXC_ID_ILLEGAL_OPCODE, vPortExceptionHandlerEntry, ( void * ) XEXC_ID_ILLEGAL_OPCODE ); 240 #endif /* XPAR_MICROBLAZE_ILL_OPCODE_EXCEPTION */ 241 242 #if XPAR_MICROBLAZE_M_AXI_I_BUS_EXCEPTION == 1 243 microblaze_register_exception_handler( XEXC_ID_M_AXI_I_EXCEPTION, vPortExceptionHandlerEntry, ( void * ) XEXC_ID_M_AXI_I_EXCEPTION ); 244 #endif /* XPAR_MICROBLAZE_M_AXI_I_BUS_EXCEPTION */ 245 246 #if XPAR_MICROBLAZE_M_AXI_D_BUS_EXCEPTION == 1 247 microblaze_register_exception_handler( XEXC_ID_M_AXI_D_EXCEPTION, vPortExceptionHandlerEntry, ( void * ) XEXC_ID_M_AXI_D_EXCEPTION ); 248 #endif /* XPAR_MICROBLAZE_M_AXI_D_BUS_EXCEPTION */ 249 250 #if XPAR_MICROBLAZE_IPLB_BUS_EXCEPTION == 1 251 microblaze_register_exception_handler( XEXC_ID_IPLB_EXCEPTION, vPortExceptionHandlerEntry, ( void * ) XEXC_ID_IPLB_EXCEPTION ); 252 #endif /* XPAR_MICROBLAZE_IPLB_BUS_EXCEPTION */ 253 254 #if XPAR_MICROBLAZE_DPLB_BUS_EXCEPTION == 1 255 microblaze_register_exception_handler( XEXC_ID_DPLB_EXCEPTION, vPortExceptionHandlerEntry, ( void * ) XEXC_ID_DPLB_EXCEPTION ); 256 #endif /* XPAR_MICROBLAZE_DPLB_BUS_EXCEPTION */ 257 258 #if XPAR_MICROBLAZE_DIV_ZERO_EXCEPTION == 1 259 microblaze_register_exception_handler( XEXC_ID_DIV_BY_ZERO, vPortExceptionHandlerEntry, ( void * ) XEXC_ID_DIV_BY_ZERO ); 260 #endif /* XPAR_MICROBLAZE_DIV_ZERO_EXCEPTION */ 261 262 #if XPAR_MICROBLAZE_FPU_EXCEPTION == 1 263 microblaze_register_exception_handler( XEXC_ID_FPU, vPortExceptionHandlerEntry, ( void * ) XEXC_ID_FPU ); 264 #endif /* XPAR_MICROBLAZE_FPU_EXCEPTION */ 265 266 #if XPAR_MICROBLAZE_FSL_EXCEPTION == 1 267 microblaze_register_exception_handler( XEXC_ID_FSL, vPortExceptionHandlerEntry, ( void * ) XEXC_ID_FSL ); 268 #endif /* XPAR_MICROBLAZE_FSL_EXCEPTION */ 269 270 microblaze_enable_exceptions(); 271 } 272 } 273 274 /* Exclude the entire file if the MicroBlaze is not configured to handle 275 * exceptions, or the application defined configuration item 276 * configINSTALL_EXCEPTION_HANDLERS is not set to 1. */ 277 #endif /* ( MICROBLAZE_EXCEPTIONS_ENABLED == 1 ) && ( configINSTALL_EXCEPTION_HANDLERS == 1 ) */ 278