[PATCH v1 5/9] bsp/pc386: Define interrupt stack frame for smp

Jan Sommer jan.sommer at dlr.de
Sun May 31 14:22:55 UTC 2020


- Defines CPU_Interrupt_frame in cpu_impl.h
- Updates isq_asm.S to save/restore registers in matching order to
interrupt frame
---
 bsps/i386/shared/irq/irq_asm.S                     | 102 +++++++++++----------
 cpukit/score/cpu/i386/include/rtems/score/cpu.h    |  28 +++---
 .../score/cpu/i386/include/rtems/score/cpuimpl.h   |   2 +
 3 files changed, 73 insertions(+), 59 deletions(-)

diff --git a/bsps/i386/shared/irq/irq_asm.S b/bsps/i386/shared/irq/irq_asm.S
index 2d65a79fe2..6a399f0c15 100644
--- a/bsps/i386/shared/irq/irq_asm.S
+++ b/bsps/i386/shared/irq/irq_asm.S
@@ -25,17 +25,19 @@
 #endif
 
 /* Stack frame we use for intermediate storage               */
-#define ARG_OFF	0
-#define MSK_OFF 4        /* not used any more                */
-#define EBX_OFF 8        /* ebx                              */
-#define EBP_OFF 12       /* code restoring ebp/esp relies on */
-#define ESP_OFF 16       /* esp being on top of ebp!         */
+#define ARG_OFF  0
+#define EBX_OFF  4        /* ebx                              */
+#define EBP_OFF  8       /* code restoring ebp/esp relies on */
+#define ESP_OFF 12       /* esp being on top of ebp!         */
 #ifdef __SSE__
+#ifdef RTEMS_SMP
+#error SMP with SSE support has not been tested. Use at your own risk.
+#endif
 /* need to be on 16 byte boundary for SSE, add 12 to do that */
 #define FRM_SIZ (20+12+512)
 #define SSE_OFF 32
 #else
-#define FRM_SIZ 20
+#define FRM_SIZ 16
 #endif
 
 	BEGIN_CODE
@@ -59,7 +61,7 @@ SYM (_ISR_Handler):
 	 *  NOTE:  If the previous values of the segment registers are
 	 *         pushed, do not forget to adjust SAVED_REGS.
 	 *
-	 *  NOTE:  Make sure the exit code which restores these
+	 *  NOTE:  Make sure the Lthread_dispatch_done code restores these
 	 *         when this type of code is needed.
 	 */
 
@@ -72,17 +74,15 @@ SYM (_ISR_Handler):
 	/*
 	 * Establish an aligned stack frame
 	 *   original sp
-         *   saved ebx
 	 *   saved ebp
-	 *   saved irq mask
+	 *   saved ebx
 	 *   vector arg to BSP_dispatch_isr   <- aligned SP
 	 */
 	movl      esp, eax
 	subl      $FRM_SIZ, esp
-	andl      $ - CPU_STACK_ALIGNMENT, esp
-	movl      ebx, EBX_OFF(esp)
 	movl      eax, ESP_OFF(esp)
 	movl      ebp, EBP_OFF(esp)
+	movl      ebx, EBX_OFF(esp)
 
 	/*
 	 * GCC versions starting with 4.3 no longer place the cld
@@ -100,10 +100,10 @@ SYM (_ISR_Handler):
 	/* We save SSE here (on the task stack) because we possibly
 	 * call other C-code (besides the ISR, namely _Thread_Dispatch())
 	 */
-    /*  don't wait here; a possible exception condition will eventually be
-     *  detected when the task resumes control and executes a FP instruction
+	/*  don't wait here; a possible exception condition will eventually be
+	 *  detected when the task resumes control and executes a FP instruction
 	fwait
-     */
+	 */
 	fxsave SSE_OFF(esp)
 	fninit                          /* clean-slate FPU                */
 	movl   $0x1f80, ARG_OFF(esp)	/* use ARG_OFF as scratch space   */
@@ -118,15 +118,9 @@ PUBLIC (ISR_STOP)
 ISR_STOP:
 .check_stack_switch:
 	movl      esp, ebp                  /* ebp = previous stack pointer */
+	andl      $ - CPU_STACK_ALIGNMENT, esp  /* Make sure esp is 16 byte aligned */
 
-#ifdef RTEMS_SMP
-	call      SYM(_CPU_SMP_Get_current_processor)
-	sall      $PER_CPU_CONTROL_SIZE_LOG2, eax
-	addl      $SYM(_Per_CPU_Information), eax
-	movl      eax, ebx
-#else
-	movl      $SYM(_Per_CPU_Information), ebx
-#endif
+	GET_SELF_CPU_CONTROL ebx
 
 	/* is this the outermost interrupt? */
 	cmpl      $0, PER_CPU_ISR_NEST_LEVEL(ebx)
@@ -161,32 +155,48 @@ nested:
 	 */
 	movl      ebp, esp
 
-	decl      PER_CPU_ISR_NEST_LEVEL(ebx)  /* one less ISR nest level */
-	                                    /* If interrupts are nested, */
-	                                    /*   then dispatching is disabled */
-
-	decl      PER_CPU_THREAD_DISPATCH_DISABLE_LEVEL(ebx)
-	                                    /* unnest multitasking */
-	                                    /* Is dispatch disabled */
-	jne       .exit                     /* Yes, then exit */
-
-	cmpb      $0, PER_CPU_DISPATCH_NEEDED(ebx)
-	                                    /* Is task switch necessary? */
-	jne       .schedule                 /* Yes, then call the scheduler */
-	jmp       .exit                     /* No, exit */
-
-.schedule:
-	/*
-	 * the scratch registers have already been saved and we are already
-	 * back on the thread system stack. So we can call _Thread_Dispatch
-	 * directly
-	 */
-	call      _Thread_Dispatch
 	/*
-	 * fall through exit to restore complete contex (scratch registers
-	 * eip, CS, Flags).
+	 * Thread dispatching is necessary and allowed if and only if
+	 *   dispatch_necessary == 1 and
+	 *   isr_dispatch_disable == 0 and
+	 *   thread_dispatch_disable_level == 0.
+	 *
+	 * Otherwise, continue with .Lthread_dispatch_done
 	 */
-.exit:
+	movl      PER_CPU_DISPATCH_NEEDED(ebx), eax
+	xorl      PER_CPU_THREAD_DISPATCH_DISABLE_LEVEL(ebx), eax
+	decl      PER_CPU_THREAD_DISPATCH_DISABLE_LEVEL(ebx)
+	orl       PER_CPU_THREAD_DISPATCH_DISABLE_LEVEL(ebx), eax
+	orl       PER_CPU_ISR_DISPATCH_DISABLE(ebx), eax
+	decl      PER_CPU_ISR_NEST_LEVEL(ebx)  /* one less ISR nest level */
+
+	cmpl      $0, eax
+	jne       .Lthread_dispatch_done    /* Is task switch necessary? */
+
+.Ldo_thread_dispatch:
+	  /* Set ISR dispatch disable and thread dispatch disable level to one */
+	  movl    $1, PER_CPU_ISR_DISPATCH_DISABLE(ebx)
+	  movl    $1, PER_CPU_THREAD_DISPATCH_DISABLE_LEVEL(ebx)
+	  /* Call Thread_Do_dispatch(), this function will enable interrupts */
+	  push    $EFLAGS_INTR_ENABLE      /* Set interrupt flag manually */
+	  push    ebx
+	  call    _Thread_Do_dispatch
+
+      /* Disable interrupts */
+	  cli
+	  addl    $8, esp
+	  /* Sometimes after returning from _Thread_Do_dispatch current CPU and ebx ptr are different */
+	  GET_SELF_CPU_CONTROL ebx
+	  cmpb    $0, PER_CPU_DISPATCH_NEEDED(ebx)
+	  jne     .Ldo_thread_dispatch
+
+	  /* We are done with thread dispatching */
+	  movl    $0, PER_CPU_ISR_DISPATCH_DISABLE(ebx)
+	 /*
+	  * fall through Lthread_dispatch_done to restore complete contex (scratch registers
+	  * eip, CS, Flags).
+	  */
+.Lthread_dispatch_done:
 
 #ifdef __SSE__
 	fwait
diff --git a/cpukit/score/cpu/i386/include/rtems/score/cpu.h b/cpukit/score/cpu/i386/include/rtems/score/cpu.h
index 7669c4a0cf..0145ff8db3 100644
--- a/cpukit/score/cpu/i386/include/rtems/score/cpu.h
+++ b/cpukit/score/cpu/i386/include/rtems/score/cpu.h
@@ -264,25 +264,27 @@ typedef void (*cpuExcHandlerType) (CPU_Exception_frame*);
 extern cpuExcHandlerType _currentExcHandler;
 extern void rtems_exception_init_mngt(void);
 
-#ifdef RTEMS_SMP
-  /* Throw compile-time error to indicate incomplete support */
-  #error "i386 targets do not support SMP.\
- See: https://devel.rtems.org/ticket/3335"
-
-  /*
-   * This size must match the size of the CPU_Interrupt_frame, which must be
-   * used in the SMP context switch code, which is incomplete at the moment.
-   */
-  #define CPU_INTERRUPT_FRAME_SIZE 4
-#endif
-
 /*
  * This port does not pass any frame info to the
  * interrupt handler.
  */
 
 typedef struct {
-  uint32_t todo_replace_with_apt_registers;
+/* allow for 16B alignment (worst case 12 Bytes more) and isr right after pushfl */
+  uint32_t reserved[3];
+/* registers saved by _ISR_Handler */
+  uint32_t isr_vector;
+  uint32_t ebx;
+  uint32_t ebp;
+  uint32_t esp;
+/* registers saved by rtems_irq_prologue_##_vector */
+  uint32_t edx;
+  uint32_t ecx;
+  uint32_t eax;
+/* registers saved by CPU */
+  uint32_t eip;
+  uint32_t cs;
+  uint32_t eflags;
 } CPU_Interrupt_frame;
 
 typedef enum {
diff --git a/cpukit/score/cpu/i386/include/rtems/score/cpuimpl.h b/cpukit/score/cpu/i386/include/rtems/score/cpuimpl.h
index a89b1fedfb..570b5cc167 100644
--- a/cpukit/score/cpu/i386/include/rtems/score/cpuimpl.h
+++ b/cpukit/score/cpu/i386/include/rtems/score/cpuimpl.h
@@ -29,6 +29,8 @@
 
 #define CPU_PER_CPU_CONTROL_SIZE 0
 
+#define CPU_INTERRUPT_FRAME_SIZE 52
+
 #ifndef ASM
 
 #ifdef __cplusplus
-- 
2.12.3



More information about the devel mailing list