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

4.104.115
Last change on this file since 4a4201c was 4a4201c, checked in by Till Straumann <strauman@…>, on 11/10/09 at 06:51:52

2009-11-10 Till Straumann <strauman@…>

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