home *** CD-ROM | disk | FTP | other *** search
/ Liren Large Software Subsidy 7 / 07.iso / c / c070 / 4.ddi / TOOLS.4 / TCTSRC1.EXE / ISDISPAT.ASM < prev    next >
Encoding:
Assembly Source File  |  1989-03-31  |  15.9 KB  |  594 lines

  1.     page 60,126
  2. ;
  3. ; Name        isdispat -- Interrupt service routine dispatcher.
  4. ;
  5. ; Synopsis    This routine is NOT to be called from any user program!
  6. ;        It is designed to be called from the "Far Call"
  7. ;        instruction at the beginning of an ISR control block.
  8. ;
  9. ; Description    Blaise C TOOLS interrupt service routines (ISRs) are each
  10. ;        governed by their own ISR control block which is set up
  11. ;        by ISINSTAL.  When an ISR is installed, the address of
  12. ;        its control block is put into the relevant interrupt
  13. ;        vector.  The first item in each control block is a far
  14. ;        call instruction to this routine.  Therefore, when the
  15. ;        interrupt occurs, the next address in the control block
  16. ;        is pushed onto the stack and ISDISPAT is called.
  17. ;
  18. ;        This routine then performs the remaining operations
  19. ;        needed to invoke the user's ISR (which is assumed to be
  20. ;        written in C).    This consists of the following:
  21. ;
  22. ;            (1) saving all registers;
  23. ;            (2) finding the ISR control block and using
  24. ;            the information therein;
  25. ;            (3) deciding whether a new stack may be set up
  26. ;            for this invocation of the ISR (if not,
  27. ;            then ISDISPAT just returns);
  28. ;            (4) setting up and using a new stack;
  29. ;            (5) preparing copies of the ISR's arguments,
  30. ;            including an ALLREG structure containing
  31. ;            the values of the machine registers that
  32. ;            were in effect at the time of the interrupt;
  33. ;            (6) calling the ISR as a normal C function;
  34. ;            (7) retrieving the register values in the ALLREG
  35. ;            structure;
  36. ;            (8) restoring the original stack;
  37. ;            (9) discarding the stack that was created for
  38. ;            this invocation of the ISR (as well as any
  39. ;            stacks left by intervening invocations that
  40. ;            did not return);
  41. ;            (10) restoring the machine registers using
  42. ;             values from the ALLREG structure;
  43. ;            (11) performing an IRET or RETF, as selected
  44. ;             by the ISR.
  45. ;
  46. ;        The interrupt state (that is, whether interrupts are
  47. ;        enabled or disabled) is preserved unless the ISR
  48. ;        requests otherwise.
  49. ;
  50. ; Returns    ercode          Error code:  0 if okay, 1 if interrupt
  51. ;                  vector is invalid.
  52. ;        *preg          The values of the registers may be altered
  53. ;                  by the interrupt handler.
  54. ;
  55. ; Version    6.00 (C)Copyright Blaise Computing Inc. 1986, 1987, 1989
  56. ;
  57.  
  58.      include   beginasm.mac
  59.      beginMod  isdispat
  60.  
  61.      if TC100
  62.              ; Rely on macros defined in Turbo C's header file
  63.              ; to add leading underscore (if any) on external
  64.              ; names.
  65.  
  66.      if LONGDATA
  67.      ExtSym@  _stklen,word,notpascal    ; Stack growth limit.
  68. STK_GROWTH_LIMIT  equ    _stklen@
  69.      else
  70.      ExtSym@  __brklvl,word,notpascal   ; Stack growth limit.
  71. STK_GROWTH_LIMIT  equ    __brklvl@
  72.      endif
  73.  
  74.      endif ; TC100
  75.  
  76.  
  77.      if    MSC500
  78.      extrn    STKHQQ: word
  79. STK_GROWTH_LIMIT equ    STKHQQ
  80.      endif
  81.  
  82.  
  83.      beginCseg isdispat
  84.  
  85.      public    _isdispat
  86. _isdispat proc         far
  87.  
  88.  
  89. ISRCTRL struc                ; ISRCTRL:    ISR control block
  90.                     ; (This must match declaration in
  91.                     ; BINTRUPT.H.)
  92.                     ;
  93. icb_fcall_opcode    dw    ?        ; NOP + Far call opcode
  94.                     ;    (0x9A90)
  95. icb_isrdisp        dd    ?        ; Address of ISR dispatcher
  96. icb_iret_opcode     dw    ?        ; IRET + RETF opcodes (0xcbcf)
  97.                     ;    (Offset of icb_iret_opcode
  98.                     ;    is on stack on entry to ISDISPAT.)
  99.                     ;
  100. icb_isrstk_r        dw    ?        ; ISR stack region:  offset
  101. icb_isrstk_s        dw    ?        ;             segment
  102. icb_isrstksize        dw    ?        ; ISR stack size
  103. icb_isrsp        dw    ?        ; ISR SP value at start of
  104.                     ;    current ISR call
  105.                     ;
  106. icb_isrds        dw    ?        ; DS value required by ISR
  107. icb_isres        dw    ?        ; ES value required by ISR
  108. icb_isr         dd    ?        ; Address of ISR itself
  109. icb_isrpsp        dw    ?        ; PSP of program containing ISR
  110.                     ;
  111. icb_prev_vec        dd    ?        ; Previous value of vector
  112.                     ;
  113. icb_level        dw    ?        ; Number of calls in progress
  114.                     ;    (0 if not in progress)
  115. icb_limit        dw    ?        ; Maximum number of nested calls
  116. icb_signature        dw    ?        ; Signature identifying this
  117.                     ;    structure
  118. icb_sign2        dw    ?        ; One's complement of
  119.                     ;    "signature"
  120. icb_ident        db    16 dup (?)  ; Identifying name
  121. icb_control        dw    ?        ; Bit fields to control
  122.                     ;    dispatcher options
  123. icb_status        dw    ?        ; Status info left by
  124.                     ;    dispatcher
  125. icb_scratch        db    10 dup (?)  ; Scratch space for use by
  126.                     ;    dispatcher & related programs
  127. ISRCTRL ends
  128.  
  129. ;   Control bits in icb_control member of ISR control block.
  130. ;   These must match BINTRUPT.H.
  131.  
  132. ICB_NOCHECK    equ    1        ; Don't adjust stack growth limit.
  133.  
  134. ;   Exit style codes -- these must match BINTRUPT.H.
  135.  
  136. IEXIT_NORMAL    equ    0
  137. IEXIT_RETF    equ    1
  138.  
  139. ALLREG     struc                ; ALLREG structure
  140. reg_ax     dw    ?            ; (This must match declaration in
  141. reg_bx     dw    ?            ; BUTIL.H).
  142. reg_cx     dw    ?
  143. reg_dx     dw    ?
  144. reg_si     dw    ?
  145. reg_di     dw    ?
  146. reg_ds     dw    ?
  147. reg_es     dw    ?
  148. reg_ss     dw    ?
  149. reg_cs     dw    ?
  150. reg_flags dw    ?
  151. reg_bp     dw    ?
  152. reg_sp     dw    ?
  153. reg_ip     dw    ?
  154.  
  155. allreg_size    db  ?
  156. ALLREG     ends
  157.  
  158. ; ****************   BEGIN CODE HERE   ******************
  159.  
  160.      assume ds:nothing,es:nothing,ss:nothing
  161.  
  162. ;   Save initial register values so we can have some workspace.
  163.  
  164.      push    bp            ; Save original BP (used only here >--\ )
  165.      mov    bp,sp            ;                      |
  166.      push    bp            ; (Entry value of SP) - 2          |
  167.      push    [bp]            ; Original BP             <----/
  168.      push    ax            ; Original AX
  169.      push    bx            ; Original BX
  170.      push    cx            ; Original CX
  171.      push    dx            ; Original DX
  172.      push    ds            ; Original DS
  173.      pushf                ; Original flags
  174.      push    es            ; Original ES
  175.      push    si            ; Original SI
  176.  
  177.      add    word ptr [bp-2],6   ; Convert entry SP-2 to "Caller's SP"
  178.                     ;    thus ignoring the first BP we pushed
  179.                     ;    and segment and offset pushed by
  180.                     ;    the far call in the control block.
  181.  
  182. ;   Set up DS:BX to address these values we just saved on caller's stack.
  183.  
  184.      mov    bx,ss
  185.      mov    ds,bx
  186.      assume ds:nothing
  187.      mov    bx,bp
  188.  
  189.                     ; Current stack contents
  190.                     ; (high addresses to low):
  191.                     ;
  192. caller_flags equ word ptr [bx+10]   ;    Caller's flags
  193. caller_cs   equ word ptr [bx+8]     ;    Caller's CS
  194.                     ; "Caller's SP" points to . . .
  195. caller_ip   equ word ptr [bx+6]     ;    Caller's IP (see note below)
  196. ret_seg     equ word ptr [bx+4]     ;    Segment of ISR Control Block
  197.                     ; Entry SP pointed to . . .
  198. ret_offset  equ word ptr [bx+2]     ;    Offset of icb_iret_opcode in
  199.                     ;      ISR Control Block
  200.                     ; BX and BP point to . . .
  201.                     ;    Original BP (won't be used again)
  202. caller_sp   equ word ptr [bx-2]     ;  "Caller's SP value"
  203. orig_bp     equ word ptr [bx-4]     ;    Original BP again
  204. orig_ax     equ word ptr [bx-6]     ;    Original AX
  205. orig_bx     equ word ptr [bx-8]     ;    Original BX
  206. orig_cx     equ word ptr [bx-10]    ;    Original CX
  207. orig_dx     equ word ptr [bx-12]    ;    Original DX
  208. orig_ds     equ word ptr [bx-14]    ;    Original DS
  209. orig_flags  equ word ptr [bx-16]    ;    Original flags
  210. orig_es     equ word ptr [bx-18]    ;    Original ES
  211. orig_si     equ word ptr [bx-20]    ;    Original SI
  212.  
  213.     ; Note:  the value called "caller's SP" is the SP value
  214.     ;   immediately after the INT instruction that invoked
  215.     ;   this interrupt.  Any adjustments to "caller's SP" should
  216.     ;   be RELATIVE (e.g., to discard some stack items just before
  217.     ;   returning to caller, let the ISR add a fixed value to SP in
  218.     ;   the ALLREG structure).
  219.  
  220. ;   Set up ES:SI to point to beginning of ISR control block.
  221.  
  222.      mov    es,ret_seg
  223.      assume es:nothing
  224.      mov    si,ret_offset
  225.      sub    si,(icb_iret_opcode-icb_fcall_opcode)
  226.  
  227. ;   Make sure nesting depth isn't over limit.
  228.  
  229.      mov    ax,es:[si].icb_level
  230.      cmp    ax,es:[si].icb_limit
  231.      jb    level_ok
  232.  
  233.      jmp    exit            ; Nested too deep:    just exit.
  234.  
  235.                     ; Check that stack size is adequate.
  236.  
  237. ;   Generate a new stack for the ISR:  increment level & icb_isrsp.
  238.  
  239. level_ok:                ; Nesting depth is okay.
  240.  
  241.      inc    ax            ; Increment nesting depth.
  242.      cli
  243.      mov    es:[si].icb_level,ax
  244.      push    ax            ; Local copy of nesting depth
  245.                     ;    (will be popped later).
  246.  
  247.      mov    ax,es:[si].icb_isrsp; Former ISR stack pointer.
  248.      mov    dx,ax
  249.  
  250.      add    ax,es:[si].icb_isrstksize  ; Raise stack pointer
  251.      mov    es:[si].icb_isrsp,ax       ;   for a new stack.
  252.  
  253. ;   Switch to the ISR's own stack (which we just generated).
  254. ;   Interrupts must be disabled during this.
  255.  
  256.      mov    ax,sp            ; Save old SP (old SS is in DS register)
  257.  
  258.      if TC100 and LONGDATA
  259.                     ; Adjust SS and SP so that SP is as small
  260.                     ;    as possible.  This is necessary
  261.                     ;    for stack checking.
  262.  
  263.                     ; DX contains low address of this ISR's
  264.                     ;    stack.
  265.      add    dx,15            ; Round DX up to next multiple of 16
  266.      mov    cl,4            ;    bytes.    Convert to paragraph number.
  267.      shr    dx,cl
  268.      add    dx,es:[si].icb_isrstk_s   ; Compute first paragraph that
  269.                       ;   begins within this ISR's stack.
  270.                       ;   This will be used for SS.
  271.  
  272.      mov    cx,es:[si].icb_isrstksize ; Use stack size for SP value,
  273.      sub    cx,16              ;   but allow 16 bytes for safety
  274.                       ;   because SS value was adjusted
  275.                       ;   upward (wasting up to 15 bytes).
  276.  
  277.      mov    ss,dx
  278.      mov    sp,cx
  279.  
  280.      mov    dx,cx            ; Stack limit is high address of
  281.                     ; current stack.  (Stack overflow
  282.                     ; occurs if stack pushes below 0.)
  283.  
  284.      else                ; No special SP value required.
  285.  
  286.      mov    ss,es:[si].icb_isrstk_s   ; Switch to ISR's own stack.
  287.      assume ss:nothing
  288.      mov    sp,es:[si].icb_isrsp
  289.  
  290.      add    dx,6            ; For stack limit, use high address of
  291.                     ;    former ISR stack (plus 6 for safety).
  292.  
  293.      endif
  294.  
  295.      push    orig_flags        ; Restore original flags to
  296.      popff                ;  (possibly) re-enable interrupts.
  297.  
  298. ;   Now create an ALLREG structure on the ISR's own stack.
  299.  
  300.      push    caller_ip
  301.      push    caller_sp
  302.      push    orig_bp
  303.      push    caller_flags
  304.      push    caller_cs
  305.      push    ds            ; Caller's SS
  306.      push    orig_es
  307.      push    orig_ds
  308.      push    di
  309.      push    orig_si
  310.      push    orig_dx
  311.      push    orig_cx
  312.      push    orig_bx
  313.      push    orig_ax
  314.      mov    bp,sp            ; Now BP points to ALLREG structure.
  315. regs     equ    [bp]
  316.  
  317. ;   Create two-word area for messages between dispatcher (us) and ISR.
  318.  
  319.      push    orig_flags        ; "Working" flags -- depending on how
  320.                     ;    dispatcher exits, these may persist
  321.                     ;    on return to caller.
  322.      mov    cx,IEXIT_NORMAL
  323.      push    cx            ; Default exit style.
  324. message  equ    dword ptr [bp-4]
  325.  
  326. ;   Create local vector to the ISR
  327.  
  328.      if    LONGPROG
  329.      push    word ptr es:[si].icb_isr+2
  330.      push    word ptr es:[si].icb_isr
  331. vector_to_isr    equ    dword ptr [bp-8]
  332.      else
  333.      push    word ptr es:[si].icb_isr
  334. vector_to_isr    equ    word ptr [bp-6]
  335.      endif
  336.  
  337. ;   Save items needed locally by dispatcher (us)
  338.  
  339.      push    ds            ; Caller's SS
  340.      push    ax            ; SP in caller's stack just before
  341.                     ;    stack switch
  342.      push    bx            ; Frame pointer in caller's stack.
  343.      push    es            ; Segment of ISR control block.
  344.      push    si            ; Offset  of ISR control block.
  345.  
  346. ;   Point to ISR's data segment
  347.  
  348.      mov    ds,es:[si].icb_isrds
  349.      assume ds:nothing
  350.  
  351. ;   Save former stack growth limit and establish new value therefor.
  352. ;   (The stack growth limit variable is in the ISR's data segment.)
  353.  
  354.      test    es:[si].icb_control,ICB_NOCHECK
  355.      jnz    stack_limit_adjusted
  356.  
  357.      if LONGDATA
  358.  
  359.      push    es
  360.      mov    ax,seg STK_GROWTH_LIMIT
  361.      mov    es,ax
  362.      mov    ax,es:STK_GROWTH_LIMIT
  363.      mov    es:STK_GROWTH_LIMIT,dx          ; New limit.
  364.      pop    es
  365.      push    ax                  ; Save old limit.
  366.  
  367.      else
  368.  
  369.      push    ds:STK_GROWTH_LIMIT          ; Save old limit.
  370.      mov    ds:STK_GROWTH_LIMIT, dx       ; New limit.
  371.  
  372.      endif
  373.  
  374. stack_limit_adjusted:
  375.  
  376. ;   Save control bits (in part so we will know whether to restore
  377. ;   stack growth limit).
  378.  
  379.      push    es:[si].icb_control
  380.  
  381. ;   Push ISR's arguments.
  382.  
  383.      if    LONGDATA
  384.  
  385.      push    ss            ; Address of message area.
  386.      lea    ax,message
  387.      push    ax
  388.  
  389.      push    es            ; Address of ISR control block.
  390.      push    si
  391.  
  392.      push    ss            ; Address of ALLREG structure.
  393.      lea    ax,regs
  394.      push    ax
  395.  
  396.      else
  397.  
  398.      lea    ax,message        ; Address of message area.
  399.      push    ax
  400.  
  401.      push    si            ; Address of ISR control block.
  402.                     ;  (For S, P, and M model programs
  403.                     ;  this must be in ISR's default
  404.                     ;  data segment.)
  405.  
  406.      lea    ax,regs         ; Address of ALLREG structure.
  407.      push    ax
  408.  
  409.      endif
  410.  
  411. ;   Set up remaining registers required by ISR.
  412.  
  413.      cld
  414.      mov    es,es:[si].icb_isres
  415.      assume es:nothing
  416.  
  417. ;   Actually call the ISR.
  418.  
  419.      call    vector_to_isr
  420.  
  421. ;   Discard the ISR's arguments in usual C fashion.
  422.  
  423.      if    LONGDATA
  424.      add    sp,12
  425.      else
  426.      add    sp,6
  427.      endif
  428.  
  429. ;   Recall former control bits into CX.
  430.  
  431.      pop    cx            ; CX = former control bits.
  432.  
  433. ;   Restore former stack growth limit.
  434.  
  435.      test    cx,ICB_NOCHECK
  436.      jnz    stack_limit_restored
  437.  
  438.      if    LONGDATA
  439.      mov    si,seg STK_GROWTH_LIMIT
  440.      mov    es,si
  441.      pop    es:STK_GROWTH_LIMIT
  442.      else
  443.      pop    ds:STK_GROWTH_LIMIT
  444.      endif
  445.  
  446. stack_limit_restored:
  447.  
  448. ;   Restore dispatcher's various pointers.
  449.  
  450.      pop    si
  451.      pop    es            ; Now ES:SI point to ISR control block.
  452.      assume es:nothing
  453.      pop    bx
  454.      pop    ax
  455.      pop    ds            ; DS:AX is SS:SP in caller's stack
  456.      assume ds:nothing        ;    just before stack switch.
  457.                     ; DS:BX is frame pointer in caller's
  458.                     ;    stack.
  459.  
  460. ;   Discard the local vector to the ISR.
  461.  
  462.      if    LONGPROG
  463.      add    sp,4
  464.      else
  465.      inc    sp
  466.      inc    sp
  467.      endif
  468.  
  469. ;   Read the message area & react to it.
  470.  
  471.      pop    dx            ; "Exit style"
  472.      pop    orig_flags        ; "Working flags"
  473.  
  474. ;   Transfer ALLREG structure values into proper registers or into
  475. ;   holding locations.    These values may have been modified by the ISR.
  476.  
  477.      pop    orig_ax
  478.      pop    orig_bx
  479.      pop    orig_cx
  480.      pop    orig_dx
  481.      pop    orig_si
  482.      pop    di
  483.      pop    orig_ds
  484.      pop    orig_es
  485.      inc    sp            ; Discard SS value from structure.
  486.      inc    sp
  487.      pop    caller_cs
  488.      pop    caller_flags
  489.      pop    orig_bp
  490.      pop    caller_sp
  491.      pop    caller_ip
  492.  
  493. ;   Switch back to caller's stack.
  494.  
  495.      mov    cx,ds
  496.      cli
  497.      mov    ss,cx
  498.      assume ss:nothing
  499.      mov    sp,ax
  500.                     ; Now both DS and SS refer to
  501.                     ;  caller's stack segment.
  502.  
  503.                     ; Leave interrupts disabled.
  504.  
  505. ;   Discard the ISR stack created above, i.e. reset icb_level and icb_isrsp.
  506. ;
  507. ;   If icb_level exceeds our local (stacked) copy of level, then
  508. ;     this ISR invocation returned BEFORE a deeper-nested invocation returned.
  509. ;     In this case, assume that deeper invocations will never return.
  510. ;     Adjust icb_level and icb_isrsp to discard deeper stacks.
  511. ;
  512. ;   Interrupts are NOT okay during this operation.
  513.  
  514.      mov    cx,es:[si].icb_level
  515.      pop    ax            ; Local copy of nesting depth
  516.      dec    ax
  517.      mov    es:[si].icb_level,ax
  518.      sub    cx,ax            ; CX = number of stacks to discard
  519.                     ;       (normally 1)
  520.  
  521.      jbe    stacks_discarded
  522.      mov    ax,es:[si].icb_isrstksize
  523. discard_stack:
  524.      sub    es:[si].icb_isrsp,ax    ; Decrement beginning_SP once
  525.      loop    discard_stack        ;   for each stack discarded.
  526. stacks_discarded:
  527.                     ; Interrupts now okay.
  528.  
  529. ;   Consider optional exit style
  530.  
  531.      cmp    dx,IEXIT_RETF
  532.      je    retf_exit
  533.  
  534.                     ; If exit style code not recognized,
  535.                     ;    fall through to normal exit.
  536.  
  537. ;   Normal exit:  restore everything and do IRET.
  538. ;
  539. ;   Some of the values we restore were copied from the ALLREG structure,
  540. ;     so they may have been modified by the ISR.
  541.  
  542. exit:
  543.      pop    si
  544.      pop    es
  545.  
  546.      popff                ; Install "original" flags.
  547.                     ; These may have been modified via
  548.                     ;    the "WORKING_FLAGS" item in the
  549.                     ;    message area.
  550.  
  551.      pop    ds
  552.      pop    dx
  553.      pop    cx
  554.      pop    bx
  555.      pop    ax
  556.      pop    bp
  557.      pop    sp            ; Unless modified by ISR,
  558.                     ;    SP now contains the value
  559.                     ;    it had after the caller
  560.                     ;    performed an INT.
  561.      iret
  562.  
  563. ;   Special exit:  restore everything and do a RETF.
  564. ;
  565. ;   Some of the values we restore were copied from the ALLREG structure,
  566. ;     so they may have been modified by the ISR.
  567.  
  568. retf_exit:
  569.      pop    si
  570.      pop    es
  571.  
  572.      popff                ; Install "original" flags.
  573.                     ; These may have been modified via
  574.                     ;    the "working flags" item in the
  575.                     ;    message area.
  576.  
  577.      pop    ds
  578.      pop    dx
  579.      pop    cx
  580.      pop    bx
  581.      pop    ax
  582.      pop    bp
  583.      pop    sp            ; Unless modified by ISR,
  584.                     ;    SP now contains the value
  585.                     ;    it had after the caller
  586.                     ;    performed an INT.
  587.      ret
  588.  
  589. _isdispat endp
  590.  
  591.      endCseg    isdispat
  592.  
  593.      end
  594.