The Design and Implementation of the FreeBSD Operating System, Second Edition
Now available: The Design and Implementation of the FreeBSD Operating System (Second Edition)


[ source navigation ] [ diff markup ] [ identifier search ] [ freetext search ] [ file search ] [ list types ] [ track identifier ]

FreeBSD/Linux Kernel Cross Reference
sys/i386/isa/vector.s

Version: -  FREEBSD  -  FREEBSD-13-STABLE  -  FREEBSD-13-0  -  FREEBSD-12-STABLE  -  FREEBSD-12-0  -  FREEBSD-11-STABLE  -  FREEBSD-11-0  -  FREEBSD-10-STABLE  -  FREEBSD-10-0  -  FREEBSD-9-STABLE  -  FREEBSD-9-0  -  FREEBSD-8-STABLE  -  FREEBSD-8-0  -  FREEBSD-7-STABLE  -  FREEBSD-7-0  -  FREEBSD-6-STABLE  -  FREEBSD-6-0  -  FREEBSD-5-STABLE  -  FREEBSD-5-0  -  FREEBSD-4-STABLE  -  FREEBSD-3-STABLE  -  FREEBSD22  -  l41  -  OPENBSD  -  linux-2.6  -  MK84  -  PLAN9  -  xnu-8792 
SearchContext: -  none  -  3  -  10 

    1 /*
    2  *      from: vector.s, 386BSD 0.1 unknown origin
    3  * $FreeBSD: src/sys/i386/isa/vector.s,v 1.21.2.5 1999/09/05 08:13:41 peter Exp $
    4  */
    5 
    6 /*
    7  * modified for PC98 by Kakefuda
    8  */
    9 
   10 #include "opt_auto_eoi.h"
   11 
   12 #include <i386/isa/icu.h>
   13 #ifdef PC98
   14 #include <pc98/pc98/pc98.h>
   15 #else
   16 #include <i386/isa/isa.h>
   17 #endif
   18 
   19 #ifdef PC98
   20 #define ICU_IMR_OFFSET          2       /* IO_ICU{1,2} + 2 */
   21 #else
   22 #define ICU_IMR_OFFSET          1       /* IO_ICU{1,2} + 1 */
   23 #endif
   24 
   25 #define ICU_EOI                 0x20    /* XXX - define elsewhere */
   26 
   27 #define IRQ_BIT(irq_num)        (1 << ((irq_num) % 8))
   28 #define IRQ_BYTE(irq_num)       ((irq_num) / 8)
   29 
   30 #ifdef AUTO_EOI_1
   31 #define ENABLE_ICU1             /* use auto-EOI to reduce i/o */
   32 #define OUTB_ICU1
   33 #else
   34 #define ENABLE_ICU1 \
   35         movb    $ICU_EOI,%al ;  /* as soon as possible send EOI ... */ \
   36         OUTB_ICU1               /* ... to clear in service bit */
   37 #define OUTB_ICU1 \
   38         outb    %al,$IO_ICU1
   39 #endif
   40 
   41 #ifdef AUTO_EOI_2
   42 /*
   43  * The data sheet says no auto-EOI on slave, but it sometimes works.
   44  */
   45 #define ENABLE_ICU1_AND_2       ENABLE_ICU1
   46 #else
   47 #define ENABLE_ICU1_AND_2 \
   48         movb    $ICU_EOI,%al ;  /* as above */ \
   49         outb    %al,$IO_ICU2 ;  /* but do second icu first ... */ \
   50         OUTB_ICU1               /* ... then first icu (if !AUTO_EOI_1) */
   51 #endif
   52 
   53 #ifdef FAST_INTR_HANDLER_USES_ES
   54 #define ACTUALLY_PUSHED         1
   55 #define MAYBE_MOVW_AX_ES        movl    %ax,%es
   56 #define MAYBE_POPL_ES           popl    %es
   57 #define MAYBE_PUSHL_ES          pushl   %es
   58 #else
   59 /*
   60  * We can usually skip loading %es for fastintr handlers.  %es should
   61  * only be used for string instructions, and fastintr handlers shouldn't
   62  * do anything slow enough to justify using a string instruction.
   63  */
   64 #define ACTUALLY_PUSHED         0
   65 #define MAYBE_MOVW_AX_ES
   66 #define MAYBE_POPL_ES
   67 #define MAYBE_PUSHL_ES
   68 #endif
   69 
   70 /*
   71  * Macros for interrupt interrupt entry, call to handler, and exit.
   72  *
   73  * XXX - the interrupt frame is set up to look like a trap frame.  This is
   74  * usually a waste of time.  The only interrupt handlers that want a frame
   75  * are the clock handler (it wants a clock frame), the npx handler (it's
   76  * easier to do right all in assembler).  The interrupt return routine
   77  * needs a trap frame for rare AST's (it could easily convert the frame).
   78  * The direct costs of setting up a trap frame are two pushl's (error
   79  * code and trap number), an addl to get rid of these, and pushing and
   80  * popping the call-saved regs %esi, %edi and %ebp twice,  The indirect
   81  * costs are making the driver interface nonuniform so unpending of
   82  * interrupts is more complicated and slower (call_driver(unit) would
   83  * be easier than ensuring an interrupt frame for all handlers.  Finally,
   84  * there are some struct copies in the npx handler and maybe in the clock
   85  * handler that could be avoided by working more with pointers to frames
   86  * instead of frames.
   87  *
   88  * XXX - should we do a cld on every system entry to avoid the requirement
   89  * for scattered cld's?
   90  *
   91  * Coding notes for *.s:
   92  *
   93  * If possible, avoid operations that involve an operand size override.
   94  * Word-sized operations might be smaller, but the operand size override
   95  * makes them slower on on 486's and no faster on 386's unless perhaps
   96  * the instruction pipeline is depleted.  E.g.,
   97  *
   98  *      Use movl to seg regs instead of the equivalent but more descriptive
   99  *      movw - gas generates an irelevant (slower) operand size override.
  100  *
  101  *      Use movl to ordinary regs in preference to movw and especially
  102  *      in preference to movz[bw]l.  Use unsigned (long) variables with the
  103  *      top bits clear instead of unsigned short variables to provide more
  104  *      opportunities for movl.
  105  *
  106  * If possible, use byte-sized operations.  They are smaller and no slower.
  107  *
  108  * Use (%reg) instead of 0(%reg) - gas generates larger code for the latter.
  109  *
  110  * If the interrupt frame is made more flexible,  INTR can push %eax first
  111  * and decide the ipending case with less overhead, e.g., by avoiding
  112  * loading segregs.
  113  */
  114 
  115 #define FAST_INTR(irq_num, vec_name, enable_icus) \
  116         .text ; \
  117         SUPERALIGN_TEXT ; \
  118 IDTVEC(vec_name) ; \
  119         pushl   %eax ;          /* save only call-used registers */ \
  120         pushl   %ecx ; \
  121         pushl   %edx ; \
  122         pushl   %ds ; \
  123         MAYBE_PUSHL_ES ; \
  124         movl    $KDSEL,%eax ; \
  125         movl    %ax,%ds ; \
  126         MAYBE_MOVW_AX_ES ; \
  127         FAKE_MCOUNT((4+ACTUALLY_PUSHED)*4(%esp)) ; \
  128         pushl   _intr_unit + (irq_num) * 4 ; \
  129         call    *_intr_handler + (irq_num) * 4 ; /* do the work ASAP */ \
  130         enable_icus ;           /* (re)enable ASAP (helps edge trigger?) */ \
  131         addl    $4,%esp ; \
  132         incl    _cnt+V_INTR ;   /* book-keeping can wait */ \
  133         movl    _intr_countp + (irq_num) * 4,%eax ; \
  134         incl    (%eax) ; \
  135         movl    _cpl,%eax ;     /* are we unmasking pending HWIs or SWIs? */ \
  136         notl    %eax ; \
  137         andl    _ipending,%eax ; \
  138         jne     2f ;            /* yes, maybe handle them */ \
  139 1: ; \
  140         MEXITCOUNT ; \
  141         MAYBE_POPL_ES ; \
  142         popl    %ds ; \
  143         popl    %edx ; \
  144         popl    %ecx ; \
  145         popl    %eax ; \
  146         iret ; \
  147 ; \
  148         ALIGN_TEXT ; \
  149 2: ; \
  150         cmpb    $3,_intr_nesting_level ;        /* is there enough stack? */ \
  151         jae     1b ;            /* no, return */ \
  152         movl    _cpl,%eax ; \
  153         /* XXX next line is probably unnecessary now. */ \
  154         movl    $HWI_MASK|SWI_MASK,_cpl ;       /* limit nesting ... */ \
  155         incb    _intr_nesting_level ;   /* ... really limit it ... */ \
  156         sti ;                   /* ... to do this as early as possible */ \
  157         MAYBE_POPL_ES ;         /* discard most of thin frame ... */ \
  158         popl    %ecx ;          /* ... original %ds ... */ \
  159         popl    %edx ; \
  160         xchgl   %eax,4(%esp) ;  /* orig %eax; save cpl */ \
  161         pushal ;                /* build fat frame (grrr) ... */ \
  162         pushl   %ecx ;          /* ... actually %ds ... */ \
  163         pushl   %es ; \
  164         movl    $KDSEL,%eax ; \
  165         movl    %ax,%es ; \
  166         movl    (2+8+0)*4(%esp),%ecx ;  /* ... %ecx from thin frame ... */ \
  167         movl    %ecx,(2+6)*4(%esp) ;    /* ... to fat frame ... */ \
  168         movl    (2+8+1)*4(%esp),%eax ;  /* ... cpl from thin frame */ \
  169         pushl   %eax ; \
  170         subl    $4,%esp ;       /* junk for unit number */ \
  171         MEXITCOUNT ; \
  172         jmp     _doreti
  173 
  174 #define INTR(irq_num, vec_name, icu, enable_icus, reg) \
  175         .text ; \
  176         SUPERALIGN_TEXT ; \
  177 IDTVEC(vec_name) ; \
  178         pushl   $0 ;            /* dummy error code */ \
  179         pushl   $0 ;            /* dummy trap type */ \
  180         pushal ; \
  181         pushl   %ds ;           /* save our data and extra segments ... */ \
  182         pushl   %es ; \
  183         movl    $KDSEL,%eax ;   /* ... and reload with kernel's own ... */ \
  184         movl    %ax,%ds ;       /* ... early for obsolete reasons */ \
  185         movl    %ax,%es ; \
  186         movb    _imen + IRQ_BYTE(irq_num),%al ; \
  187         orb     $IRQ_BIT(irq_num),%al ; \
  188         movb    %al,_imen + IRQ_BYTE(irq_num) ; \
  189         outb    %al,$icu+ICU_IMR_OFFSET ; \
  190         enable_icus ; \
  191         movl    _cpl,%eax ; \
  192         testb   $IRQ_BIT(irq_num),%reg ; \
  193         jne     2f ; \
  194         incb    _intr_nesting_level ; \
  195 __CONCAT(Xresume,irq_num): ; \
  196         FAKE_MCOUNT(12*4(%esp)) ;       /* XXX late to avoid double count */ \
  197         incl    _cnt+V_INTR ;   /* tally interrupts */ \
  198         movl    _intr_countp + (irq_num) * 4,%eax ; \
  199         incl    (%eax) ; \
  200         movl    _cpl,%eax ; \
  201         pushl   %eax ; \
  202         pushl   _intr_unit + (irq_num) * 4 ; \
  203         orl     _intr_mask + (irq_num) * 4,%eax ; \
  204         movl    %eax,_cpl ; \
  205         sti ; \
  206         call    *_intr_handler + (irq_num) * 4 ; \
  207         cli ;                   /* must unmask _imen and icu atomically */ \
  208         movb    _imen + IRQ_BYTE(irq_num),%al ; \
  209         andb    $~IRQ_BIT(irq_num),%al ; \
  210         movb    %al,_imen + IRQ_BYTE(irq_num) ; \
  211         outb    %al,$icu+ICU_IMR_OFFSET ; \
  212         sti ;                   /* XXX _doreti repeats the cli/sti */ \
  213         MEXITCOUNT ; \
  214         /* We could usually avoid the following jmp by inlining some of */ \
  215         /* _doreti, but it's probably better to use less cache. */ \
  216         jmp     _doreti ; \
  217 ; \
  218         ALIGN_TEXT ; \
  219 2: ; \
  220         /* XXX skip mcounting here to avoid double count */ \
  221         orb     $IRQ_BIT(irq_num),_ipending + IRQ_BYTE(irq_num) ; \
  222         popl    %es ; \
  223         popl    %ds ; \
  224         popal ; \
  225         addl    $4+4,%esp ; \
  226         iret
  227 
  228 MCOUNT_LABEL(bintr)
  229         FAST_INTR(0,fastintr0, ENABLE_ICU1)
  230         FAST_INTR(1,fastintr1, ENABLE_ICU1)
  231         FAST_INTR(2,fastintr2, ENABLE_ICU1)
  232         FAST_INTR(3,fastintr3, ENABLE_ICU1)
  233         FAST_INTR(4,fastintr4, ENABLE_ICU1)
  234         FAST_INTR(5,fastintr5, ENABLE_ICU1)
  235         FAST_INTR(6,fastintr6, ENABLE_ICU1)
  236         FAST_INTR(7,fastintr7, ENABLE_ICU1)
  237         FAST_INTR(8,fastintr8, ENABLE_ICU1_AND_2)
  238         FAST_INTR(9,fastintr9, ENABLE_ICU1_AND_2)
  239         FAST_INTR(10,fastintr10, ENABLE_ICU1_AND_2)
  240         FAST_INTR(11,fastintr11, ENABLE_ICU1_AND_2)
  241         FAST_INTR(12,fastintr12, ENABLE_ICU1_AND_2)
  242         FAST_INTR(13,fastintr13, ENABLE_ICU1_AND_2)
  243         FAST_INTR(14,fastintr14, ENABLE_ICU1_AND_2)
  244         FAST_INTR(15,fastintr15, ENABLE_ICU1_AND_2)
  245         INTR(0,intr0, IO_ICU1, ENABLE_ICU1, al)
  246         INTR(1,intr1, IO_ICU1, ENABLE_ICU1, al)
  247         INTR(2,intr2, IO_ICU1, ENABLE_ICU1, al)
  248         INTR(3,intr3, IO_ICU1, ENABLE_ICU1, al)
  249         INTR(4,intr4, IO_ICU1, ENABLE_ICU1, al)
  250         INTR(5,intr5, IO_ICU1, ENABLE_ICU1, al)
  251         INTR(6,intr6, IO_ICU1, ENABLE_ICU1, al)
  252         INTR(7,intr7, IO_ICU1, ENABLE_ICU1, al)
  253         INTR(8,intr8, IO_ICU2, ENABLE_ICU1_AND_2, ah)
  254         INTR(9,intr9, IO_ICU2, ENABLE_ICU1_AND_2, ah)
  255         INTR(10,intr10, IO_ICU2, ENABLE_ICU1_AND_2, ah)
  256         INTR(11,intr11, IO_ICU2, ENABLE_ICU1_AND_2, ah)
  257         INTR(12,intr12, IO_ICU2, ENABLE_ICU1_AND_2, ah)
  258         INTR(13,intr13, IO_ICU2, ENABLE_ICU1_AND_2, ah)
  259         INTR(14,intr14, IO_ICU2, ENABLE_ICU1_AND_2, ah)
  260         INTR(15,intr15, IO_ICU2, ENABLE_ICU1_AND_2, ah)
  261 MCOUNT_LABEL(eintr)
  262 
  263         .data
  264         .globl  _ihandlers
  265 _ihandlers:
  266 ihandlers:                      /* addresses of interrupt handlers */
  267                                 /* actually resumption addresses for HWI's */
  268         .long   Xresume0, Xresume1, Xresume2, Xresume3 
  269         .long   Xresume4, Xresume5, Xresume6, Xresume7
  270         .long   Xresume8, Xresume9, Xresume10, Xresume11
  271         .long   Xresume12, Xresume13, Xresume14, Xresume15 
  272         .long   swi_tty, swi_net, dummycamisr, dummycamisr
  273         .long   _swi_vm, 0, 0, 0
  274         .long   0, 0, 0, 0
  275         .long   0, 0, _softclock, swi_ast
  276 imasks:                         /* masks for interrupt handlers */
  277         .space  NHWI*4          /* padding; HWI masks are elsewhere */
  278         .long   SWI_TTY_MASK, SWI_NET_MASK, SWI_CAMNET_MASK, SWI_CAMBIO_MASK
  279         .long   SWI_VM_MASK, 0, 0, 0
  280         .long   0, 0, 0, 0
  281         .long   0, 0, SWI_CLOCK_MASK, SWI_AST_MASK
  282         .globl  _intr_nesting_level
  283 _intr_nesting_level:
  284         .byte   0
  285         .space  3
  286 
  287 /*
  288  * Interrupt counters and names.  The format of these and the label names
  289  * must agree with what vmstat expects.  The tables are indexed by device
  290  * ids so that we don't have to move the names around as devices are
  291  * attached.
  292  */
  293 #include "vector.h"
  294         .globl  _intrcnt, _eintrcnt
  295 _intrcnt:
  296         .space  (NR_DEVICES + ICU_LEN) * 4
  297 _eintrcnt:
  298 
  299         .globl  _intrnames, _eintrnames
  300 _intrnames:
  301         .ascii  DEVICE_NAMES
  302         .asciz  "stray irq0"
  303         .asciz  "stray irq1"
  304         .asciz  "stray irq2"
  305         .asciz  "stray irq3"
  306         .asciz  "stray irq4"
  307         .asciz  "stray irq5"
  308         .asciz  "stray irq6"
  309         .asciz  "stray irq7"
  310         .asciz  "stray irq8"
  311         .asciz  "stray irq9"
  312         .asciz  "stray irq10"
  313         .asciz  "stray irq11"
  314         .asciz  "stray irq12"
  315         .asciz  "stray irq13"
  316         .asciz  "stray irq14"
  317         .asciz  "stray irq15"
  318 _eintrnames:
  319 
  320         .text

Cache object: dfe35507b9039e4f6fba51486ca75c0a


[ source navigation ] [ diff markup ] [ identifier search ] [ freetext search ] [ file search ] [ list types ] [ track identifier ]


This page is part of the FreeBSD/Linux Linux Kernel Cross-Reference, and was automatically generated using a modified version of the LXR engine.