Add the functions necessary to support RTEMS_EXCEPTION_EXTENSIONS and mark this functionality as available on MicroBlaze. --- cpukit/score/cpu/microblaze/cpu.c | 133 +++++++++++++++++ cpukit/score/cpu/microblaze/cpu_asm.S | 137 ++++++++++++++++++ .../cpu/microblaze/include/rtems/score/cpu.h | 38 +++++ spec/build/cpukit/optexceptionextensions.yml | 1 + 4 files changed, 309 insertions(+)
diff --git a/cpukit/score/cpu/microblaze/cpu.c b/cpukit/score/cpu/microblaze/cpu.c index c75aa0f147..009d93793f 100644 --- a/cpukit/score/cpu/microblaze/cpu.c +++ b/cpukit/score/cpu/microblaze/cpu.c @@ -43,6 +43,7 @@ #include <rtems/bspIo.h> #include <rtems/fatal.h> #include <rtems/score/isr.h> +#include <rtems/score/threadimpl.h> #include <rtems/score/tls.h> #include <rtems/score/wkspace.h> @@ -230,3 +231,135 @@ void _CPU_Debug_handle( CPU_Exception_frame *ef ) rtems_fatal( RTEMS_FATAL_SOURCE_EXCEPTION, (rtems_fatal_code) ef ); } + +RTEMS_NO_RETURN void _CPU_Exception_resume( CPU_Exception_frame *frame ) +{ + /* Break in progress */ + if ( ( frame->msr & MICROBLAZE_MSR_BIP ) != 0 ) { + _CPU_Exception_resume_from_break( frame ); + } + + /* Exception in progress */ + if ( ( frame->msr & MICROBLAZE_MSR_EIP ) != 0 ) { + _CPU_Exception_resume_from_exception( frame ); + } + + /* Execution should never reach this point */ + rtems_fatal( RTEMS_FATAL_SOURCE_EXCEPTION, (rtems_fatal_code) frame ); +} + +void _CPU_Exception_disable_thread_dispatch( void ) +{ + Per_CPU_Control *cpu_self = _Per_CPU_Get(); + + /* Increment interrupt nest and thread dispatch disable level */ + ++cpu_self->thread_dispatch_disable_level; + ++cpu_self->isr_nest_level; +} + +/* -1 means not mappable/recoverable */ +int _CPU_Exception_frame_get_signal( CPU_Exception_frame *ef ) +{ + uint32_t EC = ef->esr & MICROBLAZE_ESR_EC_MASK; + + /* Break in progress */ + if ( ( ef->msr & MICROBLAZE_MSR_BIP ) != 0 ) { + return -1; + } + + switch ( EC ) { + case 0x0: /* Stream */ + case 0x7: /* Privileged or Stack Protection */ + return -1; + + case 0x5: /* Divide */ + case 0x6: /* FPU */ + return SIGFPE; + + case 0x3: /* Instruction Abort */ + case 0x4: /* Data Abort */ + return SIGSEGV; + + case 0x1: /* Unaligned access */ + case 0x2: /* Illegal op-code */ + default: + return SIGILL; + } +} + +void _CPU_Exception_frame_set_resume( CPU_Exception_frame *ef, void *address ) +{ + /* Break in progress */ + if ( ( ef->msr & MICROBLAZE_MSR_BIP ) != 0 ) { + ef->r16 = address; + return; + } + + /* Exception in progress */ + if ( ( ef->msr & MICROBLAZE_MSR_EIP ) != 0 ) { + ef->r17 = address; + return; + } + + Per_CPU_Control *cpu_self = _Per_CPU_Get(); + + /* Interrupt in progress must be determined by stack pointer location */ + if ( + ef->r1 >= (uint32_t) cpu_self->interrupt_stack_low + && ef->r1 < (uint32_t) cpu_self->interrupt_stack_high + ) { + ef->r14 = address; + return; + } + + /* Default to normal link register */ + ef->r15 = address; +} + +/* + * This returns the target return address, not necessarily the address of the + * instruction that caused exception. These are the same if it's a MMU exception + * and the BTR overrides the return address if the exception occurred in a delay + * slot. */ +uint32_t *_MicroBlaze_Get_return_address( CPU_Exception_frame *ef ) +{ + /* Break in progress */ + if ( ( ef->msr & MICROBLAZE_MSR_BIP ) != 0 ) { + return ef->r16; + } + + /* Exception in progress */ + if ( ( ef->msr & MICROBLAZE_MSR_EIP ) != 0 ) { + if ( ( ef->esr & MICROBLAZE_ESR_DS ) != 0 ) { + return ef->btr; + } + + return ef->r17; + } + + Per_CPU_Control *cpu_self = _Per_CPU_Get(); + + /* Interrupt in progress must be determined by stack pointer location */ + if ( + ef->r1 >= (uint32_t) cpu_self->interrupt_stack_low + && ef->r1 < (uint32_t) cpu_self->interrupt_stack_high + ) { + return ef->r14; + } + + /* Default to normal link register */ + return ef->r15; +} + +/* + * This can only change the resume address in the case of an exception in a + * branch delay slot instruction. + */ +void _CPU_Exception_frame_make_resume_next_instruction( + CPU_Exception_frame *ef +) +{ + uintptr_t ret_addr = (uintptr_t) _MicroBlaze_Get_return_address( ef ); + + _CPU_Exception_frame_set_resume( ef, (uint32_t *) ret_addr ); +} diff --git a/cpukit/score/cpu/microblaze/cpu_asm.S b/cpukit/score/cpu/microblaze/cpu_asm.S index 92cf15e901..bf5080d2e1 100644 --- a/cpukit/score/cpu/microblaze/cpu_asm.S +++ b/cpukit/score/cpu/microblaze/cpu_asm.S @@ -38,6 +38,9 @@ .text .globl _ISR_Handler + .globl _CPU_Exception_dispatch_and_resume + .globl _CPU_Exception_resume_from_exception + .globl _CPU_Exception_resume_from_break .align 2 _ISR_Handler: @@ -179,3 +182,137 @@ thread_dispatch: addik r1, r1, 52 bri quick_exit + +_CPU_Exception_dispatch_and_resume: + /* Subtract 1 from ISR_NEST_LEVEL */ + lwi r3, r0, _Per_CPU_Information + 8 + addik r3, r3, -1 + swi r3, r0, _Per_CPU_Information + 8 + + /* Subtract 1 from THREAD_DISPATCH_DISABLE_LEVEL */ + lwi r3, r0, _Per_CPU_Information + 16 + addik r3, r3, -1 + swi r3, r0, _Per_CPU_Information + 16 + + /* Is THREAD_DISPATCH_DISABLE_LEVEL != 0? */ + bnei r3, _CPU_Exception_resume_from_exception + + /* Is DISPATCH_NEEDED == 0? */ + lwi r3, r0, _Per_CPU_Information + 20 + beqi r3, _CPU_Exception_resume_from_exception + + bralid r15, _Thread_Dispatch + nop +/* Fall through to restore exception frame */ + +_CPU_Exception_resume_from_exception: + /* Move argument to stack pointer */ + addi r1, r5, 0 + + /* Retrieve and store MSR */ + lwi r3, r1, MICROBLAZE_EXCEPTION_FRAME_MSR + mts rmsr, r3 + + /* Retrieve and store EAR */ + lwi r3, r1, MICROBLAZE_EXCEPTION_FRAME_EAR + mts rear, r3 + + /* Retrieve and store ESR */ + lwi r3, r1, MICROBLAZE_EXCEPTION_FRAME_ESR + mts resr, r3 + + /* Restore program state */ + lwi r2, r1, MICROBLAZE_EXCEPTION_FRAME_R2 + lwi r3, r1, MICROBLAZE_EXCEPTION_FRAME_R3 + lwi r4, r1, MICROBLAZE_EXCEPTION_FRAME_R4 + lwi r5, r1, MICROBLAZE_EXCEPTION_FRAME_R5 + lwi r6, r1, MICROBLAZE_EXCEPTION_FRAME_R6 + lwi r7, r1, MICROBLAZE_EXCEPTION_FRAME_R7 + lwi r8, r1, MICROBLAZE_EXCEPTION_FRAME_R8 + lwi r9, r1, MICROBLAZE_EXCEPTION_FRAME_R9 + lwi r10, r1, MICROBLAZE_EXCEPTION_FRAME_R10 + lwi r11, r1, MICROBLAZE_EXCEPTION_FRAME_R11 + lwi r12, r1, MICROBLAZE_EXCEPTION_FRAME_R12 + lwi r13, r1, MICROBLAZE_EXCEPTION_FRAME_R13 + lwi r14, r1, MICROBLAZE_EXCEPTION_FRAME_R14 + lwi r15, r1, MICROBLAZE_EXCEPTION_FRAME_R15 + lwi r16, r1, MICROBLAZE_EXCEPTION_FRAME_R16 + lwi r17, r1, MICROBLAZE_EXCEPTION_FRAME_R17 + lwi r18, r1, MICROBLAZE_EXCEPTION_FRAME_R18 + lwi r19, r1, MICROBLAZE_EXCEPTION_FRAME_R19 + lwi r20, r1, MICROBLAZE_EXCEPTION_FRAME_R20 + lwi r21, r1, MICROBLAZE_EXCEPTION_FRAME_R21 + lwi r22, r1, MICROBLAZE_EXCEPTION_FRAME_R22 + lwi r23, r1, MICROBLAZE_EXCEPTION_FRAME_R23 + lwi r24, r1, MICROBLAZE_EXCEPTION_FRAME_R24 + lwi r25, r1, MICROBLAZE_EXCEPTION_FRAME_R25 + lwi r26, r1, MICROBLAZE_EXCEPTION_FRAME_R26 + lwi r27, r1, MICROBLAZE_EXCEPTION_FRAME_R27 + lwi r28, r1, MICROBLAZE_EXCEPTION_FRAME_R28 + lwi r29, r1, MICROBLAZE_EXCEPTION_FRAME_R29 + lwi r30, r1, MICROBLAZE_EXCEPTION_FRAME_R30 + lwi r31, r1, MICROBLAZE_EXCEPTION_FRAME_R31 + + /* Free stack space */ + addik r1, r1, CPU_EXCEPTION_FRAME_SIZE + + /* Return from exception mode */ + /* Branch to BTR is handled by upper layers */ + rted r17, 0 + nop + +/* There is no dispatch version of resume from break */ +_CPU_Exception_resume_from_break: + /* Move argument to stack pointer */ + addi r1, r5, 0 + + /* Retrieve and store MSR */ + lwi r3, r1, MICROBLAZE_EXCEPTION_FRAME_MSR + mts rmsr, r3 + + /* Retrieve and store EAR */ + lwi r3, r1, MICROBLAZE_EXCEPTION_FRAME_EAR + mts rear, r3 + + /* Retrieve and store ESR */ + lwi r3, r1, MICROBLAZE_EXCEPTION_FRAME_ESR + mts resr, r3 + + /* Restore program state */ + lwi r2, r1, MICROBLAZE_EXCEPTION_FRAME_R2 + lwi r3, r1, MICROBLAZE_EXCEPTION_FRAME_R3 + lwi r4, r1, MICROBLAZE_EXCEPTION_FRAME_R4 + lwi r5, r1, MICROBLAZE_EXCEPTION_FRAME_R5 + lwi r6, r1, MICROBLAZE_EXCEPTION_FRAME_R6 + lwi r7, r1, MICROBLAZE_EXCEPTION_FRAME_R7 + lwi r8, r1, MICROBLAZE_EXCEPTION_FRAME_R8 + lwi r9, r1, MICROBLAZE_EXCEPTION_FRAME_R9 + lwi r10, r1, MICROBLAZE_EXCEPTION_FRAME_R10 + lwi r11, r1, MICROBLAZE_EXCEPTION_FRAME_R11 + lwi r12, r1, MICROBLAZE_EXCEPTION_FRAME_R12 + lwi r13, r1, MICROBLAZE_EXCEPTION_FRAME_R13 + lwi r14, r1, MICROBLAZE_EXCEPTION_FRAME_R14 + lwi r15, r1, MICROBLAZE_EXCEPTION_FRAME_R15 + lwi r16, r1, MICROBLAZE_EXCEPTION_FRAME_R16 + lwi r17, r1, MICROBLAZE_EXCEPTION_FRAME_R17 + lwi r18, r1, MICROBLAZE_EXCEPTION_FRAME_R18 + lwi r19, r1, MICROBLAZE_EXCEPTION_FRAME_R19 + lwi r20, r1, MICROBLAZE_EXCEPTION_FRAME_R20 + lwi r21, r1, MICROBLAZE_EXCEPTION_FRAME_R21 + lwi r22, r1, MICROBLAZE_EXCEPTION_FRAME_R22 + lwi r23, r1, MICROBLAZE_EXCEPTION_FRAME_R23 + lwi r24, r1, MICROBLAZE_EXCEPTION_FRAME_R24 + lwi r25, r1, MICROBLAZE_EXCEPTION_FRAME_R25 + lwi r26, r1, MICROBLAZE_EXCEPTION_FRAME_R26 + lwi r27, r1, MICROBLAZE_EXCEPTION_FRAME_R27 + lwi r28, r1, MICROBLAZE_EXCEPTION_FRAME_R28 + lwi r29, r1, MICROBLAZE_EXCEPTION_FRAME_R29 + lwi r30, r1, MICROBLAZE_EXCEPTION_FRAME_R30 + lwi r31, r1, MICROBLAZE_EXCEPTION_FRAME_R31 + + /* Free stack space */ + addik r1, r1, CPU_EXCEPTION_FRAME_SIZE + + /* Return from debug mode */ + rtbd r16, 0 + nop diff --git a/cpukit/score/cpu/microblaze/include/rtems/score/cpu.h b/cpukit/score/cpu/microblaze/include/rtems/score/cpu.h index 37b6779481..9ba3e2a595 100644 --- a/cpukit/score/cpu/microblaze/include/rtems/score/cpu.h +++ b/cpukit/score/cpu/microblaze/include/rtems/score/cpu.h @@ -194,6 +194,10 @@ typedef struct { #define MICROBLAZE_MSR_C ( 1 << 2 ) #define MICROBLAZE_MSR_IE ( 1 << 1 ) +#define MICROBLAZE_ESR_DS ( 1 << 12 ) +#define MICROBLAZE_ESR_EC_MASK 0x1f +#define MICROBLAZE_ESR_ESS_MASK 0x7f +#define MICROBLAZE_ESR_ESS_SHIFT 5 #define _CPU_MSR_GET( _msr_value ) \ do { \ @@ -358,6 +362,40 @@ void _CPU_Context_switch( Context_Control *heir ); +/* Selects the appropriate resume function based on CEF state */ +RTEMS_NO_RETURN void _CPU_Exception_resume( CPU_Exception_frame *frame ); + +RTEMS_NO_RETURN void _CPU_Exception_resume_from_exception( + CPU_Exception_frame *frame +); + +RTEMS_NO_RETURN void _CPU_Exception_resume_from_break( + CPU_Exception_frame *frame +); + +/* + * Only functions for exception cases since debug exception frames will never + * need dispatch + */ +RTEMS_NO_RETURN void _CPU_Exception_dispatch_and_resume( + CPU_Exception_frame *frame +); + +void _CPU_Exception_disable_thread_dispatch( void ); + +int _CPU_Exception_frame_get_signal( CPU_Exception_frame *frame ); + +void _CPU_Exception_frame_set_resume( + CPU_Exception_frame *frame, + void *address +); + +void _CPU_Exception_frame_make_resume_next_instruction( + CPU_Exception_frame *frame +); + +uint32_t *_MicroBlaze_Get_return_address( CPU_Exception_frame *ef ); + RTEMS_NO_RETURN void _CPU_Context_restore( Context_Control *new_context ); diff --git a/spec/build/cpukit/optexceptionextensions.yml b/spec/build/cpukit/optexceptionextensions.yml index 5ae1594f72..d1c815776d 100644 --- a/spec/build/cpukit/optexceptionextensions.yml +++ b/spec/build/cpukit/optexceptionextensions.yml @@ -13,6 +13,7 @@ description: | frames. enabled-by: - aarch64 +- microblaze links: [] name: RTEMS_EXCEPTION_EXTENSIONS type: build -- 2.30.2 _______________________________________________ devel mailing list devel@rtems.org http://lists.rtems.org/mailman/listinfo/devel