source: rtems/c/src/lib/libbsp/i386/shared/irq/irq_asm.S @ c499856

4.115
Last change on this file since c499856 was c499856, checked in by Chris Johns <chrisj@…>, on 03/20/14 at 21:10:47

Change all references of rtems.com to rtems.org.

  • Property mode set to 100644
File size: 8.5 KB
Line 
1/* irq.c
2 *
3 *  This file contains the implementation of the function described in irq.h
4 *
5 *  Copyright (C) 1998 valette@crf.canon.fr
6 *
7 *  COPYRIGHT (c) 1989-2011.
8 *  On-Line Applications Research Corporation (OAR).
9 *
10 *  The license and distribution terms for this file may be
11 *  found in found in the file LICENSE in this distribution or at
12 *  http://www.rtems.org/license/LICENSE.
13 */
14
15#include <rtems/asm.h>
16#include <rtems/system.h>
17#include <bspopts.h>
18#include <bsp/irq_asm.h>
19#include <rtems/score/cpu.h>
20#include <rtems/score/percpu.h>
21
22#ifndef CPU_STACK_ALIGNMENT
23#error "Missing header? CPU_STACK_ALIGNMENT is not defined here"
24#endif
25
26/* Stack frame we use for intermediate storage               */
27#define ARG_OFF 0
28#define MSK_OFF 4
29#define EBX_OFF 8        /* ebx                              */
30#define EBP_OFF 12       /* code restoring ebp/esp relies on */
31#define ESP_OFF 16       /* esp being on top of ebp!         */
32#ifdef __SSE__
33/* need to be on 16 byte boundary for SSE, add 12 to do that */
34#define FRM_SIZ (20+12+512)
35#define SSE_OFF 32
36#else
37#define FRM_SIZ 20
38#endif
39
40        BEGIN_CODE
41
42SYM (_ISR_Handler):
43        /*
44         *  Before this was point is reached the vectors unique
45         *  entry point did the following:
46         *
47         *     1. saved scratch registers registers eax edx ecx"
48         *     2. put the vector number in ecx.
49         *
50         * BEGINNING OF ESTABLISH SEGMENTS
51         *
52         *  WARNING: If an interrupt can occur when the segments are
53         *           not correct, then this is where we should establish
54         *           the segments.  In addition to establishing the
55         *           segments, it may be necessary to establish a stack
56         *           in the current data area on the outermost interrupt.
57         *
58         *  NOTE:  If the previous values of the segment registers are
59         *         pushed, do not forget to adjust SAVED_REGS.
60         *
61         *  NOTE:  Make sure the exit code which restores these
62         *         when this type of code is needed.
63         */
64
65        /***** ESTABLISH SEGMENTS CODE GOES HERE  ******/
66
67        /*
68         * END OF ESTABLISH SEGMENTS
69         */
70
71        /*
72         * Establish an aligned stack frame
73         *   original sp
74         *   saved ebx
75         *   saved ebp
76         *   saved irq mask
77         *   vector arg to C_dispatch_isr   <- aligned SP
78         */
79        movl      esp, eax
80        subl      $FRM_SIZ, esp
81        andl      $ - CPU_STACK_ALIGNMENT, esp
82        movl      ebx, EBX_OFF(esp)
83        movl      eax, ESP_OFF(esp)
84        movl      ebp, EBP_OFF(esp)
85
86#ifdef __SSE__
87        /* NOTE: SSE only is supported if the BSP enables fxsave/fxrstor
88         * to save/restore SSE context! This is so far only implemented
89         * for pc386!.
90         */
91
92        /* We save SSE here (on the task stack) because we possibly
93         * call other C-code (besides the ISR, namely _Thread_Dispatch())
94         */
95    /*  don't wait here; a possible exception condition will eventually be
96     *  detected when the task resumes control and executes a FP instruction
97        fwait
98     */
99        fxsave SSE_OFF(esp)
100        fninit                          /* clean-slate FPU                */
101        movl   $0x1f80, ARG_OFF(esp)    /* use ARG_OFF as scratch space   */
102        ldmxcsr ARG_OFF(esp)            /* clean-slate MXCSR              */
103#endif
104
105        /* Do not disable any 8259 interrupts if this isn't from one */
106        cmp       ecx, 16               /* is this a PIC IRQ? */
107        jge       .check_stack_switch
108
109        /*
110         * acknowledge the interrupt
111         */
112        movw      SYM (i8259s_cache), ax /* save current i8259 interrupt mask */
113        movl      eax, MSK_OFF(esp)      /* save in stack frame */
114
115        /*
116         * compute the new PIC mask:
117         *
118         * <new mask> = <old mask> | irq_mask_or_tbl[<intr number aka ecx>]
119         */
120        movw      SYM (irq_mask_or_tbl) (,ecx,2), dx
121        orw       dx, ax
122        /*
123         * Install new computed value on the i8259 and update cache
124         * accordingly
125         */
126        movw      ax, SYM (i8259s_cache)
127        outb      $PIC_MASTER_IMR_IO_PORT
128        movb      ah, al
129        outb      $PIC_SLAVE_IMR_IO_PORT
130
131        movb      $PIC_EOI, al
132        cmpl      $7, ecx
133        jbe      .master
134        outb      $PIC_SLAVE_COMMAND_IO_PORT
135.master:
136        outb      $PIC_MASTER_COMMAND_IO_PORT
137
138        /*
139         *  Now switch stacks if necessary
140         */
141
142PUBLIC (ISR_STOP)
143ISR_STOP:
144.check_stack_switch:
145        movl      esp, ebp                  /* ebp = previous stack pointer */
146
147#ifdef RTEMS_SMP
148        call      SYM(_CPU_SMP_Get_current_processor)
149        sall      $PER_CPU_CONTROL_SIZE_LOG2, eax
150        addl      $SYM(_Per_CPU_Information), eax
151        movl      eax, ebx
152#else
153        movl      $SYM(_Per_CPU_Information), ebx
154#endif
155
156        /* is this the outermost interrupt? */
157        cmpl      $0, PER_CPU_ISR_NEST_LEVEL(ebx)
158        jne       nested                    /* No, then continue */
159        movl      PER_CPU_INTERRUPT_STACK_HIGH(ebx), esp
160
161        /*
162         *  We want to insure that the old stack pointer is in ebp
163         *  By saving it on every interrupt, all we have to do is
164         *  movl ebp->esp near the end of every interrupt.
165         */
166
167nested:
168        incl      PER_CPU_ISR_NEST_LEVEL(ebx)  /* one nest level deeper */
169        incl      PER_CPU_THREAD_DISPATCH_DISABLE_LEVEL(ebx) /* disable
170                                                                multitasking */
171        /*
172         * GCC versions starting with 4.3 no longer place the cld
173         * instruction before string operations.  We  need to ensure
174         * it is set correctly for ISR handlers.
175         */
176        cld
177
178        /*
179         * re-enable interrupts at processor level as the current
180         * interrupt source is now masked via i8259
181         */
182        sti
183
184        /*
185         *  ECX is preloaded with the vector number; store as arg
186         *  on top of stack. Note that _CPU_Interrupt_stack_high
187         *  was adjusted in _CPU_Interrupt_stack_setup() (score/rtems/cpu.h)
188         *  to make sure there is space.
189         */
190
191        movl      ecx, ARG_OFF(esp)  /* store vector arg in stack */
192        call      C_dispatch_isr
193
194        /*
195         * disable interrupts_again
196         */
197        cli
198
199        movl      ARG_OFF(esp), ecx     /* grab vector arg from stack */
200
201        /*
202         * Restore stack. This moves back to the task stack
203         * when all interrupts are unnested.
204         */
205        movl      ebp, esp
206
207        /*
208         * restore the original i8259 masks
209         */
210        /* Do not touch 8259 interrupts if this isn't from one */
211        cmp       ecx, 16               /* is this a PIC IRQ? */
212        jge       .dont_restore_i8259
213
214        movl      MSK_OFF(esp), eax
215        movw      ax, SYM (i8259s_cache)
216        outb      $PIC_MASTER_IMR_IO_PORT
217        movb      ah, al
218        outb      $PIC_SLAVE_IMR_IO_PORT
219
220.dont_restore_i8259:
221        decl      PER_CPU_ISR_NEST_LEVEL(ebx)  /* one less ISR nest level */
222                                            /* If interrupts are nested, */
223                                            /*   then dispatching is disabled */
224
225        decl      PER_CPU_THREAD_DISPATCH_DISABLE_LEVEL(ebx)
226                                            /* unnest multitasking */
227                                            /* Is dispatch disabled */
228        jne       .exit                     /* Yes, then exit */
229
230        cmpb      $0, PER_CPU_DISPATCH_NEEDED(ebx)
231                                            /* Is task switch necessary? */
232        jne       .schedule                 /* Yes, then call the scheduler */
233        jmp       .exit                     /* No, exit */
234
235.schedule:
236        /*
237         * the scratch registers have already been saved and we are already
238         * back on the thread system stack. So we can call _Thread_Dispatch
239         * directly
240         */
241        call      _Thread_Dispatch
242        /*
243         * fall through exit to restore complete contex (scratch registers
244         * eip, CS, Flags).
245         */
246.exit:
247
248#ifdef __SSE__
249        fwait
250        fxrstor   SSE_OFF(esp)
251#endif
252
253        /* restore ebx, ebp and original esp */
254        addl      $EBX_OFF, esp
255        popl      ebx
256        popl      ebp
257        popl      esp
258
259        /*
260         * BEGINNING OF DE-ESTABLISH SEGMENTS
261         *
262         *  NOTE:  Make sure there is code here if code is added to
263         *         load the segment registers.
264         *
265         */
266
267        /******* DE-ESTABLISH SEGMENTS CODE GOES HERE ********/
268
269        /*
270         * END OF DE-ESTABLISH SEGMENTS
271         */
272        popl      edx
273        popl      ecx
274        popl      eax
275        iret
276
277#define DISTINCT_INTERRUPT_ENTRY(_vector) \
278        .p2align 4                         ; \
279        PUBLIC (rtems_irq_prologue_ ## _vector ) ; \
280SYM (rtems_irq_prologue_ ## _vector ):             \
281        pushl     eax                ; \
282        pushl     ecx                ; \
283        pushl     edx                ; \
284        movl      $ _vector, ecx     ; \
285        jmp       SYM (_ISR_Handler) ;
286
287DISTINCT_INTERRUPT_ENTRY(0)
288DISTINCT_INTERRUPT_ENTRY(1)
289DISTINCT_INTERRUPT_ENTRY(2)
290DISTINCT_INTERRUPT_ENTRY(3)
291DISTINCT_INTERRUPT_ENTRY(4)
292DISTINCT_INTERRUPT_ENTRY(5)
293DISTINCT_INTERRUPT_ENTRY(6)
294DISTINCT_INTERRUPT_ENTRY(7)
295DISTINCT_INTERRUPT_ENTRY(8)
296DISTINCT_INTERRUPT_ENTRY(9)
297DISTINCT_INTERRUPT_ENTRY(10)
298DISTINCT_INTERRUPT_ENTRY(11)
299DISTINCT_INTERRUPT_ENTRY(12)
300DISTINCT_INTERRUPT_ENTRY(13)
301DISTINCT_INTERRUPT_ENTRY(14)
302DISTINCT_INTERRUPT_ENTRY(15)
303DISTINCT_INTERRUPT_ENTRY(16)
304
305        /*
306         * routine used to initialize the IDT by default
307         */
308
309PUBLIC (default_raw_idt_handler)
310PUBLIC (raw_idt_notify)
311
312SYM (default_raw_idt_handler):
313        pusha
314        cld
315        mov       esp, ebp
316        andl     $ - CPU_STACK_ALIGNMENT, esp
317        call      raw_idt_notify
318        mov       ebp, esp
319        popa
320        iret
321
322END_CODE
323
324END
Note: See TracBrowser for help on using the repository browser.