[PATCH v1 3/5] cpukit/microblaze: Add exception extensions
Kinsey Moore
kinsey.moore at oarcorp.com
Tue Feb 1 15:25:56 UTC 2022
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
More information about the devel
mailing list