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 uint32_t * 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 86 /* vApplicationExceptionRegisterDump() is a callback function that the 87 * application can optionally define to receive a populated xPortRegisterDump 88 * structure. If the application chooses not to define a version of 89 * vApplicationExceptionRegisterDump() then this weekly defined default 90 * implementation will be called instead. */ 91 extern void vApplicationExceptionRegisterDump( xPortRegisterDump * xRegisterDump ) __attribute__( ( weak ) ); vApplicationExceptionRegisterDump(xPortRegisterDump * xRegisterDump)92 void vApplicationExceptionRegisterDump( xPortRegisterDump * xRegisterDump ) 93 { 94 ( void ) xRegisterDump; 95 96 for( ; ; ) 97 { 98 portNOP(); 99 } 100 } 101 /*-----------------------------------------------------------*/ 102 vPortExceptionHandler(void * pvExceptionID)103 void vPortExceptionHandler( void * pvExceptionID ) 104 { 105 extern void * pxCurrentTCB; 106 107 /* Fill an xPortRegisterDump structure with the MicroBlaze context as it 108 * was immediately before the exception occurrence. */ 109 110 /* First fill in the name and handle of the task that was in the Running 111 * state when the exception occurred. */ 112 xRegisterDump.xCurrentTaskHandle = pxCurrentTCB; 113 xRegisterDump.pcCurrentTaskName = pcTaskGetName( NULL ); 114 115 configASSERT( pulStackPointerOnFunctionEntry ); 116 117 /* Obtain the values of registers that were stacked prior to this function 118 * being called, and may have changed since they were stacked. */ 119 xRegisterDump.ulR3 = pulStackPointerOnFunctionEntry[ portexR3_STACK_OFFSET ]; 120 xRegisterDump.ulR4 = pulStackPointerOnFunctionEntry[ portexR4_STACK_OFFSET ]; 121 xRegisterDump.ulR5 = pulStackPointerOnFunctionEntry[ portexR5_STACK_OFFSET ]; 122 xRegisterDump.ulR6 = pulStackPointerOnFunctionEntry[ portexR6_STACK_OFFSET ]; 123 xRegisterDump.ulR7 = pulStackPointerOnFunctionEntry[ portexR7_STACK_OFFSET ]; 124 xRegisterDump.ulR8 = pulStackPointerOnFunctionEntry[ portexR8_STACK_OFFSET ]; 125 xRegisterDump.ulR9 = pulStackPointerOnFunctionEntry[ portexR9_STACK_OFFSET ]; 126 xRegisterDump.ulR10 = pulStackPointerOnFunctionEntry[ portexR10_STACK_OFFSET ]; 127 xRegisterDump.ulR11 = pulStackPointerOnFunctionEntry[ portexR11_STACK_OFFSET ]; 128 xRegisterDump.ulR12 = pulStackPointerOnFunctionEntry[ portexR12_STACK_OFFSET ]; 129 xRegisterDump.ulR15_return_address_from_subroutine = pulStackPointerOnFunctionEntry[ portexR15_STACK_OFFSET ]; 130 xRegisterDump.ulR18 = pulStackPointerOnFunctionEntry[ portexR18_STACK_OFFSET ]; 131 xRegisterDump.ulR19 = pulStackPointerOnFunctionEntry[ portexR19_STACK_OFFSET ]; 132 xRegisterDump.ulMSR = pulStackPointerOnFunctionEntry[ portexMSR_STACK_OFFSET ]; 133 134 /* Obtain the value of all other registers. */ 135 xRegisterDump.ulR2_small_data_area = mfgpr( R2 ); 136 xRegisterDump.ulR13_read_write_small_data_area = mfgpr( R13 ); 137 xRegisterDump.ulR14_return_address_from_interrupt = mfgpr( R14 ); 138 xRegisterDump.ulR16_return_address_from_trap = mfgpr( R16 ); 139 xRegisterDump.ulR17_return_address_from_exceptions = mfgpr( R17 ); 140 xRegisterDump.ulR20 = mfgpr( R20 ); 141 xRegisterDump.ulR21 = mfgpr( R21 ); 142 xRegisterDump.ulR22 = mfgpr( R22 ); 143 xRegisterDump.ulR23 = mfgpr( R23 ); 144 xRegisterDump.ulR24 = mfgpr( R24 ); 145 xRegisterDump.ulR25 = mfgpr( R25 ); 146 xRegisterDump.ulR26 = mfgpr( R26 ); 147 xRegisterDump.ulR27 = mfgpr( R27 ); 148 xRegisterDump.ulR28 = mfgpr( R28 ); 149 xRegisterDump.ulR29 = mfgpr( R29 ); 150 xRegisterDump.ulR30 = mfgpr( R30 ); 151 xRegisterDump.ulR31 = mfgpr( R31 ); 152 xRegisterDump.ulR1_SP = ( ( uint32_t ) pulStackPointerOnFunctionEntry ) + portexASM_HANDLER_STACK_FRAME_SIZE; 153 xRegisterDump.ulEAR = mfear(); 154 xRegisterDump.ulESR = mfesr(); 155 xRegisterDump.ulEDR = mfedr(); 156 157 /* Move the saved program counter back to the instruction that was executed 158 * when the exception occurred. This is only valid for certain types of 159 * exception. */ 160 xRegisterDump.ulPC = xRegisterDump.ulR17_return_address_from_exceptions - portexINSTRUCTION_SIZE; 161 162 #if ( XPAR_MICROBLAZE_USE_FPU != 0 ) 163 { 164 xRegisterDump.ulFSR = mffsr(); 165 } 166 #else 167 { 168 xRegisterDump.ulFSR = 0UL; 169 } 170 #endif 171 172 /* Also fill in a string that describes what type of exception this is. 173 * The string uses the same ID names as defined in the MicroBlaze standard 174 * library exception header files. */ 175 switch( ( uint32_t ) pvExceptionID ) 176 { 177 case XEXC_ID_FSL: 178 xRegisterDump.pcExceptionCause = ( int8_t * const ) "XEXC_ID_FSL"; 179 break; 180 181 case XEXC_ID_UNALIGNED_ACCESS: 182 xRegisterDump.pcExceptionCause = ( int8_t * const ) "XEXC_ID_UNALIGNED_ACCESS"; 183 break; 184 185 case XEXC_ID_ILLEGAL_OPCODE: 186 xRegisterDump.pcExceptionCause = ( int8_t * const ) "XEXC_ID_ILLEGAL_OPCODE"; 187 break; 188 189 case XEXC_ID_M_AXI_I_EXCEPTION: 190 xRegisterDump.pcExceptionCause = ( int8_t * const ) "XEXC_ID_M_AXI_I_EXCEPTION or XEXC_ID_IPLB_EXCEPTION"; 191 break; 192 193 case XEXC_ID_M_AXI_D_EXCEPTION: 194 xRegisterDump.pcExceptionCause = ( int8_t * const ) "XEXC_ID_M_AXI_D_EXCEPTION or XEXC_ID_DPLB_EXCEPTION"; 195 break; 196 197 case XEXC_ID_DIV_BY_ZERO: 198 xRegisterDump.pcExceptionCause = ( int8_t * const ) "XEXC_ID_DIV_BY_ZERO"; 199 break; 200 201 case XEXC_ID_STACK_VIOLATION: 202 xRegisterDump.pcExceptionCause = ( int8_t * const ) "XEXC_ID_STACK_VIOLATION or XEXC_ID_MMU"; 203 break; 204 205 #if ( XPAR_MICROBLAZE_USE_FPU != 0 ) 206 case XEXC_ID_FPU: 207 xRegisterDump.pcExceptionCause = ( int8_t * const ) "XEXC_ID_FPU see ulFSR value"; 208 break; 209 #endif /* XPAR_MICROBLAZE_USE_FPU */ 210 } 211 212 /* vApplicationExceptionRegisterDump() is a callback function that the 213 * application can optionally define to receive the populated xPortRegisterDump 214 * structure. If the application chooses not to define a version of 215 * vApplicationExceptionRegisterDump() then the weekly defined default 216 * implementation within this file will be called instead. */ 217 vApplicationExceptionRegisterDump( &xRegisterDump ); 218 219 /* Must not attempt to leave this function! */ 220 for( ; ; ) 221 { 222 portNOP(); 223 } 224 } 225 /*-----------------------------------------------------------*/ 226 vPortExceptionsInstallHandlers(void)227 void vPortExceptionsInstallHandlers( void ) 228 { 229 static uint32_t ulHandlersAlreadyInstalled = pdFALSE; 230 231 if( ulHandlersAlreadyInstalled == pdFALSE ) 232 { 233 ulHandlersAlreadyInstalled = pdTRUE; 234 235 #if XPAR_MICROBLAZE_UNALIGNED_EXCEPTIONS == 1 236 microblaze_register_exception_handler( XEXC_ID_UNALIGNED_ACCESS, vPortExceptionHandlerEntry, ( void * ) XEXC_ID_UNALIGNED_ACCESS ); 237 #endif /* XPAR_MICROBLAZE_UNALIGNED_EXCEPTIONS*/ 238 239 #if XPAR_MICROBLAZE_ILL_OPCODE_EXCEPTION == 1 240 microblaze_register_exception_handler( XEXC_ID_ILLEGAL_OPCODE, vPortExceptionHandlerEntry, ( void * ) XEXC_ID_ILLEGAL_OPCODE ); 241 #endif /* XPAR_MICROBLAZE_ILL_OPCODE_EXCEPTION */ 242 243 #if XPAR_MICROBLAZE_M_AXI_I_BUS_EXCEPTION == 1 244 microblaze_register_exception_handler( XEXC_ID_M_AXI_I_EXCEPTION, vPortExceptionHandlerEntry, ( void * ) XEXC_ID_M_AXI_I_EXCEPTION ); 245 #endif /* XPAR_MICROBLAZE_M_AXI_I_BUS_EXCEPTION */ 246 247 #if XPAR_MICROBLAZE_M_AXI_D_BUS_EXCEPTION == 1 248 microblaze_register_exception_handler( XEXC_ID_M_AXI_D_EXCEPTION, vPortExceptionHandlerEntry, ( void * ) XEXC_ID_M_AXI_D_EXCEPTION ); 249 #endif /* XPAR_MICROBLAZE_M_AXI_D_BUS_EXCEPTION */ 250 251 #if XPAR_MICROBLAZE_IPLB_BUS_EXCEPTION == 1 252 microblaze_register_exception_handler( XEXC_ID_IPLB_EXCEPTION, vPortExceptionHandlerEntry, ( void * ) XEXC_ID_IPLB_EXCEPTION ); 253 #endif /* XPAR_MICROBLAZE_IPLB_BUS_EXCEPTION */ 254 255 #if XPAR_MICROBLAZE_DPLB_BUS_EXCEPTION == 1 256 microblaze_register_exception_handler( XEXC_ID_DPLB_EXCEPTION, vPortExceptionHandlerEntry, ( void * ) XEXC_ID_DPLB_EXCEPTION ); 257 #endif /* XPAR_MICROBLAZE_DPLB_BUS_EXCEPTION */ 258 259 #if XPAR_MICROBLAZE_DIV_ZERO_EXCEPTION == 1 260 microblaze_register_exception_handler( XEXC_ID_DIV_BY_ZERO, vPortExceptionHandlerEntry, ( void * ) XEXC_ID_DIV_BY_ZERO ); 261 #endif /* XPAR_MICROBLAZE_DIV_ZERO_EXCEPTION */ 262 263 #if XPAR_MICROBLAZE_FPU_EXCEPTION == 1 264 microblaze_register_exception_handler( XEXC_ID_FPU, vPortExceptionHandlerEntry, ( void * ) XEXC_ID_FPU ); 265 #endif /* XPAR_MICROBLAZE_FPU_EXCEPTION */ 266 267 #if XPAR_MICROBLAZE_FSL_EXCEPTION == 1 268 microblaze_register_exception_handler( XEXC_ID_FSL, vPortExceptionHandlerEntry, ( void * ) XEXC_ID_FSL ); 269 #endif /* XPAR_MICROBLAZE_FSL_EXCEPTION */ 270 271 microblaze_enable_exceptions(); 272 } 273 } 274 275 /* Exclude the entire file if the MicroBlaze is not configured to handle 276 * exceptions, or the application defined configuration item 277 * configINSTALL_EXCEPTION_HANDLERS is not set to 1. */ 278 #endif /* ( MICROBLAZE_EXCEPTIONS_ENABLED == 1 ) && ( configINSTALL_EXCEPTION_HANDLERS == 1 ) */ 279