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

Last change on this file since f91fbbf was f91fbbf, checked in by Sebastian Huber <sebastian.huber@…>, on Sep 30, 2015 at 1:30:09 PM

bsps/i386: Interrupt server support

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