home *** CD-ROM | disk | FTP | other *** search
/ The C Users' Group Library 1994 August / wc-cdrom-cusersgrouplibrary-1994-08.iso / vol_300 / 330_03 / tskdos.asm < prev    next >
Assembly Source File  |  1990-10-12  |  36KB  |  1,587 lines

  1. ;
  2. ;    --- Version 2.2 90-10-12 10:37 ---
  3. ;
  4. ;    CTask - DOS access module.
  5. ;
  6. ;    Public Domain Software written by
  7. ;        Thomas Wagner
  8. ;        Ferrari electronic Gmbh
  9. ;        Beusselstrasse 27
  10. ;        D-1000 Berlin 21
  11. ;        Germany
  12. ;
  13. ; NOTE: Some routines have been moved to "tsksec.asm" in Version 2.1
  14. ;    to support a minimal secondary kernel.
  15. ;
  16. ;    The support for the critical section interrupt was dropped in
  17. ;    version 2.1. Swapping the DOS variable area eliminates
  18. ;    the need for maintaining critical sections across calls.
  19. ;
  20. ; The DOS interrupt (and the related direct disk I/O interrupts) are
  21. ; not reentrant. Access to DOS thus has to be channelled such that no
  22. ; two tasks use DOS services simultaneously. However, there is one
  23. ; exception to this rule. Whenever DOS is waiting for the keyboard, it
  24. ; issues a special interrupt, INT 28h, to signal that background
  25. ; processing for functions > 0Ch may be performed. This is used in the
  26. ; DOS interface for CTask in the following manner:
  27. ;
  28. ;   A task issuing a DOS interrupt will request one of two resources:
  29. ;   "lower_dos" for functions <= 0C, "upper_dos" for functions > 0C.
  30. ;   If a task gets access to "lower_dos", it will also request the
  31. ;   "upper_dos" resource to lock out other tasks from interrupting.
  32. ;   This "upper_dos" resource is shortly released on each INT 28, and
  33. ;   then immediately reclaimed, with task priority temporarily raised
  34. ;   to the maximum value. The first task waiting to execute a 
  35. ;   function > 0C will thus be scheduled to execute the request, but
  36. ;   the resource will be reassigned to the INT 28 handler as soon as
  37. ;   this request terminates, so the waiting task will not be delayed too
  38. ;   long.
  39. ;
  40. ; There are two additional safety measures which have to be taken to
  41. ; avoid getting into conflicts with other resident background programs,
  42. ; especially the DOS PRINT background spooler:
  43. ;
  44. ;   Before actually executing the request, the status of the DOS in-use
  45. ;   flag is checked. If this flag is set, the task enters a busy waiting
  46. ;   loop, calling the scheduler so that the processor is not tied up.
  47. ;
  48. ; NOTE: The method for checking the status of DOS is described in-depth
  49. ;    in the book "The MS-DOS Encyclopedia" from Microsoft Press, in
  50. ;    the chapter on TSR programming. The logic in this module was
  51. ;    developed without the help of this book, so if you compare
  52. ;    the code here with the routines in the Encyclopedia, you may
  53. ;    notice that not all re-entry conditions are checked here.
  54. ;    According to my experience with debugging TSR's and CTask, the
  55. ;    logic should be sufficient for all but the most obscure TSR's.
  56. ;    If you want to be completely on the safe side, you might consider
  57. ;    adding the more thorough checks listed in the Encyclopedia.
  58. ;
  59. ; CAUTION:    This module is not ROMable, and it can only be
  60. ;        installed in the primary kernel.
  61. ;
  62.     name    tskdos
  63. ;
  64.     include    tsk.mac
  65. ;
  66.     IF    DOS
  67. ;
  68.     .tsk_model
  69. ;
  70.     include    tskdeb.h
  71. ;
  72.     Pubfunc    tsk_install_dos
  73.     Pubfunc    tsk_remove_dos
  74.     Pubfunc    tsk_fatal
  75.     IF    CHECKING
  76.     Pubfunc    tsk_fatal_pmd
  77.     Globext    tsk_set_currdis
  78.     Globext    tsk_set_dualdis
  79.     Globext    tsk_rputc
  80.     Globext    tsk_rputs
  81.     Globext    tsk_vrprintf
  82.     CGlbext    tsk_rprintf
  83.     ENDIF
  84. ;
  85.     public    tsk_emergency_exit
  86. ;
  87.     Globext    create_resource
  88.     Globext    delete_resource
  89.     Globext    request_resource
  90.     Globext    request_cresource
  91.     Globext    release_resource
  92.     Globext    create_flag
  93.     Globext    delete_flag
  94.     Globext    set_flag
  95.     Globext    clear_flag
  96.     Globext    wait_flag_clear
  97.     Globext    yield
  98.     Globext    preempt_off
  99. ;
  100.     Locext    tsk_switch_stack
  101.     Locext    tsk_old_stack
  102.     Locext    tsk_remove_group
  103.     Locext    tsk_kill_group
  104.     Locext    tsk_remove_tasker
  105. ;
  106.     extrn    tsk_instflags: word
  107. ;
  108.     extrn    tsk_glob_rec: byte
  109.     IF    NOT SINGLE_DATA
  110.     extrn    tsk_global: dword
  111.     ENDIF
  112. ;
  113. get_in_use_flag    =    34h    ; DOS-function to get in_use_flag address
  114. get_invars    =    5d06h    ; DOS-function to get DOS-variables area
  115. ;
  116. psp_offset    =    10h-2    ; Offset of current PSP in DOS save area
  117. ;                ; (-2 because we add 2 to the start)
  118. ;
  119. ;    Structure of the start of a PSP, including undocumented fields
  120. ;
  121. psp_record    struc
  122. ;
  123.         dw    ?    ; INT 20
  124.         dw    ?    ; alloc block end
  125.         db    ?    ; reserved
  126.         db    5 dup(?) ; system call
  127. psp_exit_addr    dd    ?    ; exit routine address
  128. psp_ctlc_addr    dd    ?    ; control C routine address
  129. psp_cerr_addr    dd    ?    ; critical error routine address
  130. parent_psp    dw    ?    ; PSP of parent process
  131.         db    20 dup(?) ; files table
  132. psp_envseg    dw    ?    ; environment segment
  133. psp_ustack    dd    ?    ; ss/sp of caller
  134.         dw    ?    ; file table length
  135.         dd    ?    ; file table pointer
  136.         dd    ?    ; pointer to nested PSP (?)
  137. ;
  138. psp_record    ends
  139. ;
  140. ;
  141. intseg    segment at 0
  142.         org    10h*4
  143. vidoff        dw    ?    ; video interrupt
  144. vidseg        dw    ?
  145.         org    13h*4
  146. diskoff        dw    ?    ; disk i/o interrupt
  147. diskseg        dw    ?
  148.         org    20h*4
  149. termoff        dw    ?    ; program terminate vector
  150. termseg        dw    ?
  151.         org    21h*4
  152. idosoff        dw    ?    ; dos interrupt
  153. idosseg        dw    ?
  154.         org    25h*4
  155. absreadoff    dw    ?    ; absolute disk read
  156. absreadseg    dw    ?
  157.         org    26h*4
  158. abswriteoff    dw    ?    ; absolute disk write
  159. abswriteseg    dw    ?
  160.         org    27h*4
  161. keepoff        dw    ?    ; Terminate but stay resident
  162. keepseg        dw    ?
  163.         org    28h*4
  164. idleoff        dw    ?    ; dos idle interrupt
  165. idleseg        dw    ?
  166.         org    2ah*4
  167. csectoff    dw    ?    ; dos critical section
  168. csectseg    dw    ?
  169.         org    40h*4
  170. fdiskoff    dw    ?    ; redirected floppy disk I/O interrupt
  171. fdiskseg     dw    ?
  172. ;
  173. intseg    ends
  174. ;
  175. ;----------------------------------------------------------------------------
  176. ;
  177. ;    Variables
  178. ;
  179.     .tsk_data
  180. ;
  181. idle_active    db    0            ; Idle-Interrupt active
  182. dos310        db    0        ; DOS version >= 3.10
  183. ;
  184.     IF    TSK_NAMEPAR
  185. udos_name    db    "DOSUPPER",0
  186. ldos_name    db    "DOSLOWER",0
  187. hdio_name    db    "HARDDISK",0
  188. fdio_name    db    "FLEXDISK",0
  189. vid_name    db    "VIDEO",0
  190.     ENDIF
  191. ;
  192. ;
  193. in_error    dd    ?        ; Adress of DOS error-mode-flag
  194. ;
  195. lower_dos    resource <>
  196. upper_dos    resource <>
  197. hdisk_io    resource <>
  198. fdisk_io    resource <>
  199. video        resource <>
  200. ;
  201. vid_flags    dw    ?
  202. i13h_flags    dw    ?
  203. i13f_flags    dw    ?
  204. ;
  205.     .tsk_edata
  206.     .tsk_code
  207. ;
  208. ;---------------------------------------------------------------------------
  209. ;
  210. ;    Original Interrupt-Entries
  211. ;
  212. savvid        label    dword        ; original Video entry
  213. savvidoff    dw    ?
  214. savvidseg    dw    ?
  215. ;
  216. savdisk        label    dword        ; original Disk I/O entry
  217. savdiskoff    dw    ?
  218. savdiskseg    dw    ?
  219. ;
  220. savfdisk     label    dword        ; original Floppy Disk I/O entry
  221. savfdiskoff    dw    ?
  222. savfdiskseg    dw    ?
  223. ;
  224. savtermoff    dw    ?        ; Terminate vector save
  225. savtermseg    dw    ?
  226. ;
  227. savdos        label    dword        ; original DOS-Entry
  228. savdosoff    dw    ?
  229. savdosseg    dw    ?
  230. ;
  231. savidle        label    dword        ; original IDLE-Entry
  232. savidleoff    dw    ?
  233. savidleseg    dw    ?
  234. ;
  235. savcsect    label    dword        ; Critical Section save
  236. savcsectoff    dw    ?
  237. savcsectseg    dw    ?
  238. ;
  239. savabsread    label    dword        ; Absolute Disk Read save
  240. savabsreadoff    dw    ?
  241. savabsreadseg    dw    ?
  242. ;
  243. savabswrite    label    dword        ; Absolute Disk Write save
  244. savabswriteoff    dw    ?
  245. savabswriteseg    dw    ?
  246. ;
  247. savkeepoff    dw    ?        ; Terminate resident vector save
  248. savkeepseg    dw    ?
  249. ;
  250. ;
  251. dos_version    dw    ?        ; DOS version
  252. ;
  253. temp_1        dw    ?
  254. ;
  255. tsk_dgroup    dw    @CTASK_DATA
  256. ;
  257. zero        db    0
  258. ;
  259. calldos    macro
  260.     pushf
  261.     cli
  262.     call    cs:savdos
  263.     endm
  264. ;
  265. ;---------------------------------------------------------------------------
  266. ;
  267. ;    void tsk_install_dos (void)
  268. ;
  269. ;        Install DOS handler
  270. ;
  271. Localfunc tsk_install_dos
  272. ;
  273. ;    create needed resources & flags
  274. ;
  275.     IFDEF    LOAD_DS
  276.     push    ds
  277.     mov    ax,@CTASK_DATA
  278.     mov    ds,ax
  279.     ENDIF
  280. ;
  281.     IF    TSK_NAMEPAR
  282.     callp    create_resource,<<ds,#upper_dos>,<ds,#udos_name>>
  283.     ELSE
  284.     callp    create_resource,<<ds,#upper_dos>>
  285.     ENDIF
  286. ;
  287.     IF    TSK_NAMEPAR
  288.     callp    create_resource,<<ds,#lower_dos>,<ds,#ldos_name>>
  289.     ELSE
  290.     callp    create_resource,<<ds,#lower_dos>>
  291.     ENDIF
  292. ;
  293.     test    tsk_instflags,IFL_DISK
  294.     jz    inst_nodsk1
  295.     IF    TSK_NAMEPAR
  296.     callp    create_resource,<<ds,#hdisk_io>,<ds,#hdio_name>>
  297.     ELSE
  298.     callp    create_resource,<<ds,#hdisk_io>>
  299.     ENDIF
  300. ;
  301.     IF    TSK_NAMEPAR
  302.     callp    create_resource,<<ds,#fdisk_io>,<ds,#fdio_name>>
  303.     ELSE
  304.     callp    create_resource,<<ds,#fdisk_io>>
  305.     ENDIF
  306. ;
  307. inst_nodsk1:
  308.     test    tsk_instflags,IFL_VIDEO
  309.     jz    inst_novid1
  310.     IF    TSK_NAMEPAR
  311.     callp    create_resource,<<ds,#video>,<ds,#vid_name>>
  312.     ELSE
  313.     callp    create_resource,<<ds,#video>>
  314.     ENDIF
  315. ;
  316. inst_novid1:
  317. ;
  318.     mov    tsk_glob_rec.l_swap,0    ; init swap area length to 0
  319. ;
  320. ;    Get the DOS version. Only versions 3.1 and up support the
  321. ;    DOS variable swap, so disable swapping if it's an earlier version,
  322. ;    or if it's the OS/2 box.
  323. ;
  324.     mov    ah,30h
  325.     int    21h
  326.     mov    cs:dos_version,ax
  327.     cmp    al,3
  328.     jb    not_dos3
  329.     cmp    al,0ah
  330.     je    not_dos3    ; OS/2 compatibility box
  331.         cmp     al,3
  332.         jne     is_dos3         ; DOS 4.x 
  333.     cmp    ah,10
  334.     jb    not_dos3
  335. is_dos3:
  336.     inc    dos310
  337. ;
  338. ;    Get address and length of the DOS internal variable area.
  339. ;    This call is not documented, and not available in versions
  340. ;    prior to 3.1. It returns the address of the area in DS:SI,
  341. ;    and the length of the area that must be swapped between calls
  342. ;    from different groups in DX.
  343. ;    Additionally, the total length of the area, including
  344. ;    the DOS-stacks, minus the length in DX, is returned in CX.
  345. ;
  346. ;    The DOS in_error flag is at the start of this area, the
  347. ;    in_use flag is the second byte. Both bytes are excluded 
  348. ;    from the swap.
  349. ;
  350.     test    tsk_instflags,IFL_NODOSVARS
  351.     jnz    not_dos3
  352. ;
  353.     push    ds
  354.     mov    ax,get_invars
  355.     int    21h
  356.     mov    ax,ds
  357.     pop    ds
  358.     mov    word ptr in_error,si
  359.     mov    word ptr in_error+2,ax
  360.     inc    si
  361.     mov    word ptr tsk_glob_rec.dos_in_use,si
  362.     mov    word ptr tsk_glob_rec.dos_in_use+2,ax
  363.     inc    si
  364.     mov    word ptr tsk_glob_rec.dos_vars,si
  365.     mov    word ptr tsk_glob_rec.dos_vars+2,ax
  366.     sub    dx,2
  367.     mov    tsk_glob_rec.l_swap,dx
  368.     jmp    short save_ints
  369. ;
  370. ;    For versions < 3.10, and if the IFL_NODOSVARS flag is set,
  371. ;    get the address of DOS's in_use-flag. This flag indicates that
  372. ;    DOS is already active. This might happen if there are other
  373. ;    background tasks, like popups or print spoolers, active in
  374. ;    parallel to CTask.
  375. ;    This is also the address of the critical error flag in DOS. Beginning 
  376. ;    with DOS 3.10 the flag is located one byte before the in_use_flag.
  377. ;    With older DOS versions, we would have to search through DOS for the 
  378. ;    address. This is omitted here, but you could include the code
  379. ;    for pre 3.1 versions from pages 378-379 of the MS-DOS Encyclopedia.
  380. ;
  381. not_dos3:
  382.     mov    ah,get_in_use_flag
  383.     int    21h
  384.     mov    word ptr tsk_glob_rec.dos_in_use,bx
  385.     mov    word ptr tsk_glob_rec.dos_in_use+2,es
  386.     mov    word ptr in_error+2,es
  387.     dec    bx
  388.     mov    word ptr in_error,bx
  389.     cmp    dos310,0
  390.     jne    save_ints        ; OK for DOS >= 3.10
  391. ;
  392. ;    For DOS < 3.1, we simply ignore the error flag.
  393. ;    CTask's DOS handler will not work that great anyway with older
  394. ;    versions.
  395. ;
  396.     mov    word ptr in_error,offset zero
  397.     mov    word ptr in_error+2,cs
  398. ;
  399. ;    Save old interrupt vectors
  400. ;
  401. save_ints:
  402.         push    es
  403.     xor    ax,ax
  404.     mov    es,ax
  405. ;
  406.         assume  es:intseg
  407. ;
  408.     test    tsk_instflags,IFL_VIDEO
  409.     jz    inst_novid2
  410.     mov    ax,vidoff        ; video
  411.     mov    savvidoff,ax
  412.     mov    ax,vidseg
  413.     mov    savvidseg,ax
  414. ;
  415. inst_novid2:
  416.     test    tsk_instflags,IFL_DISK
  417.     jz    inst_nodsk2
  418.     mov    ax,diskoff        ; Disk I/O
  419.     mov    savdiskoff,ax
  420.     mov    ax,diskseg
  421.     mov    savdiskseg,ax
  422.     mov    ax,fdiskoff        ; Floppy Disk I/O
  423.     mov    savfdiskoff,ax
  424.     mov    ax,fdiskseg
  425.     mov    savfdiskseg,ax
  426. ;
  427. inst_nodsk2:
  428.     mov    ax,termoff        ; DOS
  429.     mov    savtermoff,ax
  430.     mov    ax,termseg
  431.     mov    savtermseg,ax
  432. ;
  433.     mov    ax,idosoff        ; DOS
  434.     mov    savdosoff,ax
  435.     mov    ax,idosseg
  436.     mov    savdosseg,ax
  437. ;
  438.     mov    ax,idleoff        ; IDLE
  439.     mov    savidleoff,ax
  440.     mov    ax,idleseg
  441.     mov    savidleseg,ax
  442. ;
  443.     mov    ax,csectoff        ; Critical Section
  444.     mov    savcsectoff,ax
  445.     mov    ax,csectseg
  446.     mov    savcsectseg,ax
  447. ;
  448.     mov    ax,absreadoff        ; Absolute Disk read
  449.     mov    savabsreadoff,ax
  450.     mov    ax,absreadseg
  451.     mov    savabsreadseg,ax
  452. ;
  453.     mov    ax,abswriteoff        ; Absolute Disk write
  454.     mov    savabswriteoff,ax
  455.     mov    ax,abswriteseg
  456.     mov    savabswriteseg,ax
  457. ;
  458.     mov    ax,keepoff        ; Terminate Resident
  459.     mov    savkeepoff,ax
  460.     mov    ax,keepseg
  461.     mov    savkeepseg,ax
  462. ;
  463. ;    Enter new Interrupt-Entries
  464. ;
  465.     cli
  466.     test    tsk_instflags,IFL_VIDEO
  467.     jz    inst_novid3
  468.     mov    vidoff,offset @videntry        ; Video Entry
  469.     mov    vidseg,cs
  470. ;
  471. inst_novid3:
  472.     test    tsk_instflags,IFL_DISK
  473.     jz    inst_nodsk3
  474.     mov    diskoff,offset @diskentry    ; Disk I/O Entry
  475.     mov    diskseg,cs
  476.     mov    fdiskoff,offset @fdiskentry    ; Floppy Disk I/O Entry
  477.     mov    fdiskseg,cs
  478. ;
  479. inst_nodsk3:
  480.     mov    idosoff,offset @dosentry    ; DOS-Entry
  481.     mov    idosseg,cs
  482.     mov    idleoff,offset @idleentry    ; Idle-Entry
  483.     mov    idleseg,cs
  484.     mov    termoff,offset terminate_int    ; Terminate Process Entry
  485.     mov    termseg,cs
  486.     mov    csectoff,offset @critsectint    ; Critical Section Entry
  487.     mov    csectseg,cs
  488.     mov    keepoff,offset keep_int        ; Keep Process Entry
  489.     mov    keepseg,cs
  490.     mov    absreadoff,offset absread_int    ; Absolute Disk Read Entry
  491.     mov    absreadseg,cs
  492.     mov    abswriteoff,offset abswrite_int    ; Absolute Disk Write Entry
  493.     mov    abswriteseg,cs
  494.     sti
  495. ;
  496.     assume    es:nothing
  497. ;
  498.         pop     es
  499.     IFDEF    LOAD_DS
  500.     pop    ds
  501.     ENDIF
  502.     ret
  503. ;
  504. ;
  505. tsk_install_dos    endp
  506. ;
  507. ;---------------------------------------------------------------------------
  508. ;
  509. ;    void tsk_remove_dos (void)
  510. ;
  511. ;        Un-install DOS handler
  512. ;
  513. Localfunc tsk_remove_dos
  514. ;
  515.     IFDEF    LOAD_DS
  516.     push    ds
  517.     mov    ax,@CTASK_DATA
  518.     mov    ds,ax
  519.     ENDIF
  520. ;
  521. ;    Delete resources & flags
  522. ;
  523.     callp    delete_resource,<<ds,#upper_dos>>
  524.     callp    delete_resource,<<ds,#lower_dos>>
  525. ;
  526.     test    tsk_instflags,IFL_DISK
  527.     jz    rem_nodsk1
  528.     callp    delete_resource,<<ds,#hdisk_io>>
  529.     callp    delete_resource,<<ds,#fdisk_io>>
  530. ;
  531. rem_nodsk1:
  532.     test    tsk_instflags,IFL_VIDEO
  533.     jz    rem_novid1
  534.     callp    delete_resource,<<ds,#video>>
  535. ;
  536. rem_novid1:
  537.         push    es
  538.     xor    ax,ax
  539.     mov    es,ax
  540. ;
  541.         assume  es:intseg
  542. ;
  543. ;    Restore interrupt entries
  544. ;
  545.     cli
  546.     test    tsk_instflags,IFL_VIDEO
  547.     jz    rem_novid2
  548.     mov    ax,savvidoff
  549.     mov    vidoff,ax
  550.     mov    ax,savvidseg
  551.     mov    vidseg,ax
  552. ;
  553. rem_novid2:
  554.     test    tsk_instflags,IFL_DISK
  555.     jz    rem_nodsk2
  556.     mov    ax,savdiskoff
  557.     mov    diskoff,ax
  558.     mov    ax,savdiskseg
  559.     mov    diskseg,ax
  560.     mov    ax,savfdiskoff
  561.     mov    fdiskoff,ax
  562.     mov    ax,savfdiskseg
  563.     mov    fdiskseg,ax
  564. ;
  565. rem_nodsk2:
  566.     mov    ax,savtermoff
  567.     mov    termoff,ax
  568.     mov    ax,savtermseg
  569.     mov    termseg,ax
  570. ;
  571.     mov    ax,savdosoff
  572.     mov    idosoff,ax
  573.     mov    ax,savdosseg
  574.     mov    idosseg,ax
  575. ;
  576.     mov    ax,savidleoff
  577.     mov    idleoff,ax
  578.     mov    ax,savidleseg
  579.     mov    idleseg,ax
  580. ;
  581.     mov    ax,savcsectoff
  582.     mov    csectoff,ax
  583.     mov    ax,savcsectseg
  584.     mov    csectseg,ax
  585. ;
  586.     mov    ax,savabsreadoff
  587.     mov    absreadoff,ax
  588.     mov    ax,savabsreadseg
  589.     mov    absreadseg,ax
  590. ;
  591.     mov    ax,savabswriteoff
  592.     mov    abswriteoff,ax
  593.     mov    ax,savabswriteseg
  594.     mov    abswriteseg,ax
  595. ;
  596.     mov    ax,savkeepoff
  597.     mov    keepoff,ax
  598.     mov    ax,savkeepseg
  599.     mov    keepseg,ax
  600. ;
  601.     sti
  602. ;
  603.         pop     es
  604.     IFDEF    LOAD_DS
  605.     pop    ds
  606.     ENDIF
  607.     ret
  608. ;
  609.     assume    es:nothing
  610. ;
  611. tsk_remove_dos    endp
  612. ;
  613. ;
  614. ;---------------------------------------------------------------------------
  615. ;---------------------------------------------------------------------------
  616. ;
  617. ;
  618. ;    INT 10: Video BIOS interrupt
  619. ;
  620. @videntry    proc    far
  621. ;
  622.     call    tsk_switch_stack
  623.     callp    request_cresource,<<ds,#video>,0,0>
  624.     mov    ax,caller_flags[bp]
  625.     mov    vid_flags,ax
  626.     call    tsk_old_stack
  627.     pushf
  628.     cli
  629.     call    savvid
  630.     call    tsk_switch_stack
  631.     mov    ax,vid_flags
  632.     mov    caller_flags[bp],ax
  633.     callp    release_resource,<<ds,#video>>
  634.     iret
  635. ;
  636. @videntry    endp
  637. ;
  638. ;---------------------------------------------------------------------------
  639. ;
  640. ;
  641. ;    INT 13 and INT 40: Disk I/O BIOS interrupt
  642. ;
  643. @diskentry    proc    far
  644. ;
  645.     call    tsk_switch_stack
  646.     test    dl,80h            ; fixed disk ?
  647.     jz    disk_floppy        ; jump if not
  648.     callp    request_cresource,<<ds,#hdisk_io>,0,0>
  649.     call    tsk_old_stack
  650.     pushf
  651.     cli
  652.     call    savdisk
  653.     call    tsk_switch_stack
  654.     callp    release_resource,<<ds,#hdisk_io>>
  655.     mov    ax,entry_flags[bp]
  656.     mov    caller_flags[bp],ax
  657.     iret
  658. ;
  659. disk_floppy:
  660.     callp    request_cresource,<<ds,#fdisk_io>,0,0>
  661.     call    tsk_old_stack
  662.     pushf
  663.     cli
  664.     call    savdisk
  665.     call    tsk_switch_stack
  666.     callp    release_resource,<<ds,#fdisk_io>>
  667.     mov    ax,entry_flags[bp]
  668.     mov    caller_flags[bp],ax
  669.     iret
  670. ;
  671. @diskentry    endp
  672. ;
  673. @fdiskentry    proc    far
  674. ;
  675.     call    tsk_switch_stack
  676.     callp    request_cresource,<<ds,#fdisk_io>,0,0>
  677.     call    tsk_old_stack
  678.     pushf
  679.     cli
  680.     call    savfdisk
  681.     call    tsk_switch_stack
  682.     callp    release_resource,<<ds,#fdisk_io>>
  683.     mov    ax,entry_flags[bp]
  684.     mov    caller_flags[bp],ax
  685.     iret
  686. ;
  687. @fdiskentry    endp
  688. ;
  689. ;---------------------------------------------------------------------------
  690. ;
  691. ;    Stack-Offsets relative to BP
  692. ;
  693. d_func    =    -2
  694. ;
  695. ;---------------------------------------------------------------------------
  696. ;
  697. ;    INT 25: Absolute Disk Read 
  698. ;
  699. ;    This interrupt is channeled through the normal DOS-function
  700. ;    processing, with function = 0x25 and special flag set.
  701. ;    It is re-translated later after the necessary resources
  702. ;    have been requested. INT 25 is handled like a function > 0C.
  703. ;    Interrupts 25 und 26 leave the flag-word on the stack.
  704. ;    Since flags are removed in normal processing, the flag-word
  705. ;    has to be duplicated on the stack here.
  706. ;
  707. absread_int:
  708.     sti
  709.     push    bp            ; reserve space
  710.     push    bp            ; save BP
  711.     mov    bp,sp
  712.     push    ax
  713.     mov    ax,4[bp]        ; Move return offset, segment down
  714.     mov    2[bp],ax
  715.     mov    ax,6[bp]
  716.     mov    4[bp],ax
  717.     mov    ax,8[bp]        ; duplicate flags
  718.     mov    6[bp],ax
  719.     pop    ax
  720.     pop    bp
  721.     call    tsk_switch_stack
  722.     mov    ax,2501h
  723.     mov    cx,ax
  724.     jmp    short dosentry_2
  725. ;
  726. ;
  727. ;---------------------------------------------------------------------------
  728. ;
  729. ;    INT 26: Absolute Disk Write
  730. ;
  731. ;    This interrupt is channeled through the normal DOS-function
  732. ;    processing, with function = 0x26 and special flag set.
  733. ;    It is re-translated later after the necessary resources
  734. ;    have been requested. INT 26 is handled like a function > 0C.
  735. ;    Interrupts 25 und 26 leave the flag-word on the stack.
  736. ;    Since flags are removed in normal processing, the flag-word
  737. ;    has to be duplicated on the stack here.
  738. ;
  739. abswrite_int:
  740.     sti
  741.     push    bp            ; reserve space
  742.     push    bp            ; save BP
  743.     mov    bp,sp
  744.     push    ax
  745.     mov    ax,4[bp]        ; Move return offset, segment down
  746.     mov    2[bp],ax
  747.     mov    ax,6[bp]
  748.     mov    4[bp],ax
  749.     mov    ax,8[bp]        ; duplicate flags
  750.     mov    6[bp],ax
  751.     pop    ax
  752.     pop    bp
  753.     call    tsk_switch_stack
  754.     mov    ax,2601h
  755.     mov    cx,ax
  756.     jmp    short dosentry_2
  757. ;
  758. ;---------------------------------------------------------------------------
  759. ;
  760. ;    INT 27: Terminate But Stay Resident Interrupt
  761. ;
  762. ;    This interrupt is translated to INT 21, function 31.
  763. ;
  764. keep_int:
  765.     call    tsk_switch_stack
  766. ;
  767.     add    dx,0fh            ; last addr + 0f to round
  768.     sub    dx,caller_cs[bp]    ; minus CS (= PSP)
  769.     mov    cl,4
  770.     shr    dx,cl            ; div 16 = paragraphs
  771.  
  772.     mov    ax,3100h        ; Keep process
  773.     mov    save_ax[bp],ax
  774.     mov    cx,ax
  775.     jmp    short dosentry_2
  776. ;
  777. ;---------------------------------------------------------------------------
  778. ;
  779. ;    INT 20: Terminate Program interrupt
  780. ;
  781. ;    This interrupt is translated to INT 21, function 4c.
  782. ;
  783. terminate_int:
  784.     call    tsk_switch_stack
  785.     mov    ax,4c00h
  786.     mov    save_ax[bp],ax
  787.     mov    cx,ax
  788.     jmp    short dosentry_2
  789. ;
  790. ;---------------------------------------------------------------------------
  791. ;
  792. ;    INT 21: DOS-Interrupt
  793. ;
  794. @dosentry        proc    far
  795. ;
  796.     call    tsk_switch_stack
  797.     xor    cl,cl
  798.     mov    ch,ah
  799. ;
  800. dosentry_2:
  801.     push    cx        ; BP-2: func in CH, special flag in CL
  802.     or    cl,cl
  803.     jnz    dosent_x    ; no function check if special
  804. ;
  805. ;    Check if this is a special 'get dos version' call to determine
  806. ;    if CTask is resident.
  807. ;
  808. ;    A special call has
  809. ;
  810. ;        AX = 3000h
  811. ;        BX = 1234h
  812. ;        DS:DX = pointer to version string
  813. ;
  814.     cmp    ax,3000h
  815.     jne    no_spdos
  816.     cmp    bx,1234h
  817.     jne    no_spdos
  818.     cmp    dx,0fff0h
  819.     jae    no_spdos
  820.     push    ds
  821.     mov    si,dx
  822.     mov    ds,save_ds[bp]
  823.     mov    di,offset tsk_glob_rec
  824.     mov    cx,8
  825.     repe cmpsb
  826.     pop    ds
  827.     jz    is_spdos
  828.     jmp    short no_spdos
  829. ;
  830. ;    Special version call returns global variable block address
  831. ;    in BX (offset) and CX (segment).
  832. ;
  833. is_spdos:
  834.     add    sp,2
  835.     call    tsk_old_stack
  836.     mov    ax,cs:dos_version
  837.     mov    bx,offset tsk_glob_rec
  838.     mov    cx,@CTASK_DATA
  839.     iret
  840. ;
  841. ;---------------------------------------------------------------------------
  842. ;
  843. ;
  844. no_spdos:
  845.     mov    ax,d_func[bp]
  846.         or    ah,ah            ; terminate?
  847.         jne     dosent_x
  848.         mov     save_ax[bp],4c00h    ; translate to fn 4c, retcode 0
  849.         mov     d_func[bp],4c00h
  850. ;
  851. ;    Now the real fun begins.
  852. ;
  853. dosent_x:
  854.     sti                ; Interrupts allowed now
  855. ;
  856. ;    DL is used as an "emergency" marker. If nonzero, no resources
  857. ;    are to be requested, and the in-dos flag is not to be checked.
  858. ;    There is an "emergency" if the task is marked as owning
  859. ;    DOS resources, but re-enters INT 21.
  860. ;
  861.     xor    dl,dl
  862.     les    bx,tsk_glob_rec.current_task
  863.     test    es:t_indos[bx],OWN_UPPER OR OWN_LOWER
  864.     jz    no_reenter        ; no trouble if task doesn't own DOS
  865. ;
  866.     call    @dosbusy        ; this sets DL nonzero if busy
  867.     jnz    no_reenter        ; Don't release resources if busy
  868. ;
  869. ;    If the task owns DOS resources, but DOS is not busy, something
  870. ;    strange is going on (this case should have been handled by the
  871. ;    'schedent' routine). Anyway, we assume that DOS is right about
  872. ;    not being busy, and release the resources. Although the resources
  873. ;    will be requested again a few instructions later, this is sensible
  874. ;    to give other tasks that might be waiting on the resource a chance
  875. ;    to execute.
  876. ;
  877.     call    @relres
  878.     xor    dl,dl
  879. ;
  880. ;    The preliminaries are done with, we now have to distinguish
  881. ;    between functions 00-0C and 0D-FF.
  882. ;
  883. no_reenter:
  884.     mov    ax,d_func[bp]
  885.     cmp    ah,0ch
  886.     jbe    lower_funcs
  887.     jmp    upper_funcs
  888. ;
  889. ;
  890. ;    Functions 00-0C
  891. ;
  892. lower_funcs:
  893. ;
  894. ;    first, request the "lower_dos" resource unless this is an emergency.
  895. ;
  896.     or    dl,dl
  897.     jnz    lower_emergency
  898.     callp    request_resource,<<ds,#lower_dos>,0,0>
  899. ;
  900. ;    we have it, now let's get the upper_dos resource, too
  901. ;
  902.     callp    request_resource,<<ds,#upper_dos>,0,0>
  903. ;
  904.     les    bx,tsk_glob_rec.current_task
  905.     mov    es:t_indos[bx],OWN_UPPER or OWN_LOWER
  906. ;
  907. ;    both resources gained, now we may execute the function if dos is free
  908. ;
  909.     call    @wait_dos_free
  910. ;
  911. ;    Set the scheduler entry function
  912. ;
  913.     cli
  914.     mov    word ptr es:sched_ent_func[bx],offset @schedent
  915.     mov    word ptr es:sched_ent_func+2[bx],cs
  916.     sti
  917. ;
  918. lower_emergency:
  919.     add    sp,2
  920.     push    caller_flags[bp]
  921.     popf
  922.     call    tsk_old_stack
  923. ;
  924.     calldos                ; execute function
  925. ;
  926. ;    Now we have to release the resources, unless DOS still indicates
  927. ;    that it is busy. This would indicate that a critical error has
  928. ;    occurred, and DOS processing is not really complete.
  929. ;
  930.     call    tsk_switch_stack
  931. ;
  932.     call    @dosbusy
  933.     jnz    no_relc            ; return if DOS still busy
  934. ;
  935. ;    Clear the flags in the TCB, and the scheduler entry function.
  936. ;
  937.     les    bx,tsk_glob_rec.current_task
  938.     cli
  939.     mov    es:t_indos[bx],0
  940.     mov    word ptr es:sched_ent_func[bx],0
  941.     mov    word ptr es:sched_ent_func+2[bx],0
  942.     sti
  943. ;
  944.     callp    release_resource,<<ds,#upper_dos>>
  945.     callp    release_resource,<<ds,#lower_dos>>
  946. ;
  947. ;    All done, restore registers and return.
  948. ;
  949. no_relc:
  950.     cli
  951.     mov    ax,entry_flags[bp]
  952.     mov    caller_flags[bp],ax
  953.     iret
  954. ;
  955. ;--------------------------------------------------------------------------
  956. ;
  957. ;    Functions 0D and above
  958. ;
  959. upper_funcs:
  960. ;
  961. ;    first, request the "upper_dos" resource unless this is an emergency.
  962. ;
  963.     or    dl,dl
  964.     jnz    upper_emergency
  965. ;
  966.     callp    request_resource,<<ds,#upper_dos>,0,0>
  967. ;
  968.     les    bx,tsk_glob_rec.current_task
  969.     mov    es:t_indos[bx],OWN_UPPER
  970. ;
  971. ;    resource gained, now we may execute the function if dos is free
  972. ;
  973.     call    @wait_dos_free
  974. ;
  975. ;    Set the scheduler entry function
  976. ;
  977.     cli
  978.     mov    word ptr es:sched_ent_func[bx],offset @schedent
  979.     mov    word ptr es:sched_ent_func+2[bx],cs
  980.     sti
  981. ;
  982. upper_emergency:
  983.     cmp    byte ptr d_func[bp],0
  984.     jne    no_term
  985.     mov    ax,save_ax[bp]
  986.     cmp    ah,31h        ; terminate resident?
  987.     jne    ckfunc1
  988.     jmp    term_resident
  989. ckfunc1:
  990.     cmp    ax,4b00h    ; spawn new process?
  991.     jne    ckfunc2
  992.     jmp    terminate
  993. ckfunc2:
  994.     cmp    ah,4ch        ; terminate program?
  995.     jne    no_term
  996.     jmp    terminate
  997. ;
  998. no_term:
  999. ;
  1000. ;    Filter special-functions 25/26 (Absolute Read/Write)
  1001. ;
  1002.     pop    ax
  1003.     cmp    ax,2501h
  1004.     jne    uf_exec1
  1005.     push    caller_flags[bp]
  1006.     popf
  1007.     call    tsk_old_stack
  1008.     pushf
  1009.     cli
  1010.     call    cs:savabsread
  1011.     pop    cs:temp_1        ; remove flags
  1012.     jmp    short uf_complete
  1013. ;
  1014. uf_exec1:
  1015.     cmp    ax,2601h
  1016.     jne    uf_exec2
  1017.     push    caller_flags[bp]
  1018.     popf
  1019.     call    tsk_old_stack
  1020.     pushf
  1021.     cli
  1022.     call    cs:savabswrite
  1023.     pop    cs:temp_1        ; remove flags
  1024.     jmp    short uf_complete
  1025. ;
  1026. uf_exec2:
  1027.     push    caller_flags[bp]
  1028.     popf
  1029.     call    tsk_old_stack
  1030. ;
  1031.     calldos                ; execute function
  1032. ;
  1033. ;    Now we have to release the resources, unless DOS still indicates
  1034. ;    that it is busy. This would indicate that a critical error has
  1035. ;    occurred, and DOS processing is not really complete.
  1036. ;    However, if we were called from INT 28, DOS must still be busy,
  1037. ;    so we only check the in_error flag.
  1038. ;
  1039. uf_complete:
  1040.     call    tsk_switch_stack
  1041. ;
  1042.     cmp    idle_active,0
  1043.     jnz    uf_nobsychk        ; don't check busy if INT 28 call
  1044.     les    bx,tsk_glob_rec.dos_in_use
  1045.     cmp    es:byte ptr [bx],0
  1046.     jne    no_relc_uf        ; don't release if busy
  1047. ;
  1048. uf_nobsychk:
  1049.     les    bx,in_error
  1050.     cmp    es:byte ptr [bx],0
  1051.     jnz    no_relc_uf        ; don't release if in error
  1052. ;
  1053.     les    bx,tsk_glob_rec.current_task
  1054.     cli
  1055.     mov    es:t_indos[bx],0
  1056.     mov    word ptr es:sched_ent_func[bx],0
  1057.     mov    word ptr es:sched_ent_func+2[bx],0
  1058.     sti
  1059. ;
  1060.     callp    release_resource,<<ds,#upper_dos>>
  1061. ;
  1062. ;    All done, restore registers and return.
  1063. ;
  1064. no_relc_uf:
  1065.     cli
  1066.     mov    ax,entry_flags[bp]
  1067.     mov    caller_flags[bp],ax
  1068.     iret
  1069. ;
  1070. ;--------------------------------------------------------------------------
  1071. ;
  1072. ;    Terminate, TSR and Spawn calls go directly to DOS.
  1073. ;    TSR has to reset the exit address if it's the PSP of the 
  1074. ;    current group, so the group is not deleted.
  1075. ;
  1076. term_resident:
  1077.     les    bx,tsk_glob_rec.dos_vars
  1078.     mov    ax,es:[bx+psp_offset]        ; current PSP
  1079.     les    bx,tsk_glob_rec.current_task
  1080.     les    bx,es:tgroup[bx]
  1081.     cmp    es:gcreate_psp[bx],ax
  1082.     jne    terminate
  1083.     push    ds
  1084.     mov    ds,ax
  1085.     mov    ax,word ptr es:grp_exit_addr[bx]
  1086.     mov    word ptr ds:psp_exit_addr,ax
  1087.     mov    ax,word ptr es:grp_exit_addr+2[bx]
  1088.     mov    word ptr ds:psp_exit_addr+2,ax
  1089.     pop    ds
  1090. ;
  1091. terminate:
  1092.     add    sp,2
  1093.     push    caller_flags[bp]
  1094.     popf
  1095.     call    tsk_old_stack
  1096.     cli
  1097.     jmp    cs:savdos
  1098. ;
  1099. @dosentry    endp
  1100. ;
  1101. ;--------------------------------------------------------------------------
  1102. ;
  1103. ;    'dosbusy' checks the DOS busy flags.
  1104. ;
  1105. ;    Entry:    -
  1106. ;    Exit:    DL is nonzero if DOS is busy.
  1107. ;
  1108. @dosbusy    proc    near
  1109. ;
  1110.     push    bx
  1111.     push    es
  1112.     les    bx,in_error
  1113.     mov    dl,es:byte ptr [bx]
  1114.     les    bx,tsk_glob_rec.dos_in_use
  1115.     or    dl,es:byte ptr [bx]
  1116.     pop    es
  1117.     pop    bx
  1118.     ret
  1119. ;
  1120. @dosbusy    endp
  1121. ;
  1122. ;--------------------------------------------------------------------------
  1123. ;
  1124. ;    Wait_dos_free uses busy waiting (calling _yield) in case
  1125. ;    some other background program has entered DOS without going
  1126. ;    through our INT 21 interface.
  1127. ;
  1128. @wait_dos_free    proc    near
  1129.     push    es
  1130.     push    bx
  1131. ;
  1132. in_use_loop:
  1133.     les    bx,in_error
  1134.     cmp    byte ptr es:[bx],0
  1135.     jne    is_in_use        ; wait if in_error set
  1136. ;
  1137.     cmp    idle_active,0        ; idle interrupt active?
  1138.     je    ck_inuse        ; check for flag if no
  1139.     pop    bx
  1140.     pop    es
  1141.     ret                ; else return immediately
  1142. ;
  1143. ck_inuse:
  1144.     les    bx,tsk_glob_rec.dos_in_use
  1145.     cmp    byte ptr es:[bx],0
  1146.     jne    is_in_use
  1147.     pop    bx
  1148.     pop    es
  1149.     ret
  1150. ;
  1151. is_in_use:
  1152.     call    yield
  1153.     jmp    in_use_loop
  1154. ;
  1155. @wait_dos_free    endp
  1156. ;
  1157. ;----------------------------------------------------------------------------
  1158. ;
  1159. ;    'relres' releases the DOS-resources of a task.
  1160. ;
  1161. ;    Entry:
  1162. ;        ES:BX = TCB pointer
  1163. ;
  1164. @relres    proc    near
  1165. ;
  1166.     test    es:t_indos[bx],OWN_UPPER
  1167.     jz    rel_lower
  1168.     xor    es:t_indos[bx],OWN_UPPER
  1169.     push    bx
  1170.     push    es
  1171.     callp    release_resource,<<ds,#upper_dos>>
  1172.     pop    es
  1173.     pop    bx
  1174. ;
  1175. rel_lower:
  1176.     test    es:t_indos[bx],OWN_LOWER
  1177.     jz    rel_exit
  1178.     xor    es:t_indos[bx],OWN_LOWER
  1179.     push    bx
  1180.     push    es
  1181.     callp    release_resource,<<ds,#lower_dos>>
  1182.     pop    es
  1183.     pop    bx
  1184. ;
  1185. rel_exit:
  1186.     ret
  1187. ;
  1188. @relres    endp
  1189. ;
  1190. ;----------------------------------------------------------------------------
  1191. ;
  1192. ;    The 'schedent' function is called by the scheduler if the
  1193. ;    scheduler is entered and the current task owns one of the
  1194. ;    DOS resources.
  1195. ;    This routine checks whether the DOS busy flags are clear now,
  1196. ;    which would mean that the task left DOS without passing through
  1197. ;    the return address. If that's the case, we release the resources.
  1198. ;
  1199. ;    The only catch is that there is a race condition if we just check
  1200. ;    the busy flags. There is a time slot where the function is set in
  1201. ;    the TCB, but the busy flag is clear because DOS has not yet been
  1202. ;    entered. Since we have no control over what will happen, and how 
  1203. ;    long it will take to reach the point where the in_use flag is 
  1204. ;    incremented, we can't simply disable preemption. So what we have
  1205. ;    to do is to wait for some other indication that DOS has begun
  1206. ;    executing the request, and mark this in the TCB. In all versions
  1207. ;    starting at 3.1, DOS will call the 'critical section' INT 2A
  1208. ;    with AX=8200 on functions > 0C after incrementing the in_use flag.
  1209. ;    We also have some indication that DOS is active if the 'idle'
  1210. ;    INT 28 is called, or if the in_use flag is set when we get here.
  1211. ;
  1212. ;    Entry:
  1213. ;        DS    CTask data segment
  1214. ;        BX    Global data block offset
  1215. ;        ES:DI    Task control block
  1216. ;
  1217. @schedent    proc    far
  1218. ;
  1219.     call    @dosbusy        ; DOS still busy ?
  1220.     jz    schedent_relres        ; release resources if not busy
  1221.     or    es:t_indos[di],DOS_ENTERED
  1222.     ret
  1223. ;
  1224. schedent_relres:    
  1225.     test    es:t_indos[di],DOS_ENTERED
  1226.     jz    schedent_ret        ; don't release if DOS not yet entered
  1227. ;
  1228.     mov    bx,di
  1229.     call    @relres
  1230. ;
  1231. schedent_ret:
  1232.     ret
  1233. ;
  1234. @schedent    endp
  1235. ;
  1236. ;----------------------------------------------------------------------------
  1237. ;
  1238. ;    INT 28: DOS Idle Interrupt
  1239. ;
  1240. @idleentry    proc    far
  1241. ;
  1242.     call    tsk_switch_stack
  1243. ;
  1244. ;    check the in_use flag. If it's set, set the DOS_ENTERED flag
  1245. ;    in the current TCB.
  1246. ;
  1247.     les    bx,tsk_glob_rec.dos_in_use
  1248.     cmp    byte ptr es:[bx],0
  1249.     je    no_entermark
  1250. ;
  1251.     les    bx,tsk_glob_rec.current_task
  1252.     or    es:t_indos[bx],DOS_ENTERED
  1253. ;
  1254. ;    Check if someone is waiting for upper_dos. If not, we can return
  1255. ;    immediately.
  1256. ;
  1257. no_entermark:
  1258.     les    bx,upper_dos.rwaiting.q_first
  1259.     test    es:q_kind[bx],Q_HEAD
  1260.     jnz    idle_exit
  1261. ;
  1262. ;    Also make sure this is not a second invocation of INT 28, and
  1263. ;    that the in_error flag is not set.
  1264. ;    Normally, this should never happen, but better safe than sorry.
  1265. ;
  1266.     cmp    idle_active,0
  1267.     jne    idle_exit
  1268.     les    bx,in_error
  1269.     cmp    byte ptr es:[bx],0
  1270.     jne    idle_exit
  1271. ;
  1272.     inc    idle_active
  1273. ;
  1274. ;    someone is waiting, let's please him by releasing the resource.
  1275. ;    temporarily increase priority
  1276. ;
  1277.     les    bx,tsk_glob_rec.current_task
  1278.     push    es:cqueue.q_el.q_prior[bx]
  1279.     push    es:cqueue.q_el.q_ini_prior[bx]
  1280.     mov    es:cqueue.q_el.q_prior[bx],0ffffh
  1281.     mov    es:cqueue.q_el.q_ini_prior[bx],0ffffh
  1282.     push    bx
  1283.     push    es
  1284. ;
  1285. ;    release resource & request it again
  1286. ;
  1287.     callp    release_resource,<<ds,#upper_dos>>
  1288.     callp    request_resource,<<ds,#upper_dos>,0,0>
  1289. ;
  1290. ;    ready, restore priority
  1291. ;
  1292.     cli
  1293.     pop    es
  1294.     pop    bx
  1295.     pop    es:cqueue.q_el.q_ini_prior[bx]
  1296.     pop    es:cqueue.q_el.q_prior[bx]
  1297. ;
  1298.     mov    idle_active,0
  1299. ;
  1300. idle_exit:
  1301.     push    caller_flags[bp]
  1302.     popf
  1303.     call    tsk_old_stack
  1304.     cli
  1305. ;
  1306.     jmp    cs:savidle        ; chain to original interrupt
  1307. ;
  1308. @idleentry    endp
  1309. ;
  1310. ;----------------------------------------------------------------------------
  1311. ;
  1312. ;    INT 2A: DOS Critical Section Interrupt
  1313. ;
  1314. ;    Not documented.
  1315. ;    Is used by DOS PRINT to mark Critical Regions.
  1316. ;    Usage by PRINT:
  1317. ;        AX = 8700 - Begin Critical Region
  1318. ;                Returns:
  1319. ;                Carry set if already active.
  1320. ;        AX = 8701 - End Critical Region
  1321. ;
  1322. ;    Other usage in DOS, function unknown:
  1323. ;        AH = 82 (AL undefined)
  1324. ;            seems to be called on DOS-Functions > 0C
  1325. ;        AH = 84 (AL undefined)
  1326. ;            seems to be called when DOS is idle
  1327. ;
  1328. ;    We only handle function number 82 in this version,
  1329. ;    it is used to mark that DOS has been entered. All functions
  1330. ;    are passed on to the next in chain.
  1331. ;
  1332. @critsectint    proc    far
  1333. ;
  1334.     cmp    ah,82h
  1335.     jne    cs_exit
  1336.     push    ds
  1337.     push    es
  1338.     push    bx
  1339.     mov    ds,cs:tsk_dgroup
  1340. ;
  1341. ;    check the in_use flag. If it's set, set the DOS_ENTERED flag
  1342. ;    in the current TCB.
  1343. ;
  1344.     les    bx,tsk_glob_rec.dos_in_use
  1345.     cmp    byte ptr es:[bx],0
  1346.     je    cs_no_enter
  1347. ;
  1348.     les    bx,tsk_glob_rec.current_task
  1349.     or    es:t_indos[bx],DOS_ENTERED
  1350. ;
  1351. cs_no_enter:
  1352.     pop    bx
  1353.     pop    es
  1354.     pop    ds
  1355. ;
  1356. cs_exit:
  1357.     jmp    cs:savcsect
  1358. ;
  1359. @critsectint    endp
  1360. ;
  1361. ;---------------------------------------------------------------------------
  1362. ;---------------------------------------------------------------------------
  1363. ;
  1364. term_err_msg    db    0dh,0ah,"Program terminated - CTask uninstalled"
  1365.         db    0dh,0ah,'$'
  1366. ;
  1367. group_term_msg    db    0dh,0ah,"Program terminated - Task Group removed"
  1368.         db    0dh,0ah,'$'
  1369. ;
  1370. gcb_mixup_err    db    0dh,0ah,"Group chain damaged - System halted"
  1371.         db    07h,'$'
  1372. ;
  1373. ;---------------------------------------------------------------------------
  1374. ;
  1375. ;    tsk_emergency_exit is entered by DOS when a task group exits
  1376. ;    without releasing the current group.
  1377. ;    Registers are set up, remove_group is called, and the program
  1378. ;    is terminated by jumping to the terminate_address.
  1379. ;
  1380. tsk_emergency_exit    proc    far
  1381. ;
  1382.     pushf
  1383.     sub    sp,4        ; make room for return addr
  1384.     push    bp
  1385.     mov    bp,sp
  1386.     push    ax
  1387.     push    bx
  1388.     push    cx
  1389.     push    dx
  1390.     push    si
  1391.     push    di
  1392.     push    ds
  1393.     push    es
  1394.     mov    ax,@CTASK_DATA
  1395.     mov    ds,ax
  1396. ;
  1397.     les    bx,tsk_glob_rec.current_task[bx]
  1398.     les    bx,es:tgroup[bx]
  1399.     mov    ax,word ptr es:grp_exit_addr[bx]
  1400.     mov    2[bp],ax
  1401.     mov    ax,word ptr es:grp_exit_addr+2[bx]
  1402.     mov    4[bp],ax
  1403. ;
  1404.     callp    tsk_remove_group,<<es,bx>,0>
  1405. ;
  1406.     mov    dx,offset group_term_msg
  1407.         cmp    ax,0
  1408.     je    emergency_end
  1409.     jb    pg_fatal
  1410. ;
  1411.     les    bx,tsk_glob_rec.current_task[bx]
  1412.     les    bx,es:tgroup[bx]
  1413.     callp    tsk_kill_group,<<es,bx>>
  1414.     call    tsk_remove_tasker
  1415. ;
  1416.     mov    dx,offset term_err_msg
  1417. ;
  1418. emergency_end:
  1419. ;
  1420.     mov    ax,cs
  1421.     mov    ds,ax
  1422.     mov    ah,9
  1423.     int    21h
  1424. ;
  1425.     pop    es
  1426.     pop    ds
  1427.     pop    di
  1428.     pop    si
  1429.     pop    dx
  1430.     pop    cx
  1431.     pop    bx
  1432.     pop    ax
  1433.     pop    bp
  1434.     iret
  1435. ;
  1436. pg_fatal:
  1437.     mov    si,offset gcb_mixup_err
  1438.     jmp    short fatal_error
  1439. ;
  1440. tsk_emergency_exit    endp
  1441. ;
  1442. ;--------------------------------------------------------------------------
  1443. ;
  1444. ;    fatal_error can be called if the system can't continue for
  1445. ;    some reason. It issues an error message and halts the system.
  1446. ;    SI must point to the '$'-terminated error message.
  1447. ;
  1448. ;    tsk_fatal does the same, but assumes C calling sequence and
  1449. ;    a zero-terminated string.
  1450. ;
  1451. Globalfunc tsk_fatal,<strp: far ptr>
  1452. ;
  1453.     cld
  1454.     lds    si,strp
  1455.     jmp    short dis_err
  1456. ;
  1457. tsk_fatal    endp
  1458. ;
  1459. fatal_error:
  1460.     mov    ax,cs
  1461.     mov    ds,ax
  1462. ;
  1463. dis_err:
  1464.     IF    IBM
  1465.     xor    ax,ax
  1466.     int    10h        ; re-init display
  1467. fatal_loop:
  1468.     lodsb
  1469.     cmp    al,'$'
  1470.     je    fatal_end
  1471.     or    al,al
  1472.     jz    fatal_end
  1473.         mov     bx,7
  1474.         mov     ah,14
  1475.     int    10h
  1476.     jmp    fatal_loop
  1477.     ELSE
  1478.     mov    dx,si
  1479.     mov    ah,9
  1480.     int    21h
  1481.     ENDIF
  1482. fatal_end:
  1483.     sti
  1484.     jmp    fatal_end
  1485. ;
  1486. ;--------------------------------------------------------------------------
  1487. ;
  1488. ;    void CGlobalfunc tsk_fatal_pmd (byteptr string, ...)
  1489. ;
  1490. ;    tsk_fatal_pmd is only present in "checking" mode.
  1491. ;    It does a minimal "post mortem dump", and displays the
  1492. ;    error message passed as parameter.
  1493. ;    The messages are output to both the primary and secondary 
  1494. ;    monitor via the "regen" printf routines in tskprf.
  1495. ;    The system is then halted, this routine never returns.
  1496. ;
  1497.     IF    CHECKING
  1498. ;
  1499. ;
  1500. CGlobalfunc    tsk_fatal_pmd,<txt: far ptr,argp:far ptr>
  1501. ;
  1502. ;    int    3    ; uncomment to break to debugger
  1503.     push    sp
  1504.     push    ss
  1505.     push    es
  1506.     push    ds
  1507.     push    di
  1508.     push    si
  1509.     push    dx
  1510.     push    cx
  1511.     push    bx
  1512.     push    ax
  1513. ;
  1514.     mov    ds,tsk_dgroup
  1515.     callp    preempt_off
  1516.     callp    tsk_set_currdis
  1517. ;
  1518.     callp    tsk_rputc,<0ch>
  1519.     les    di,txt
  1520.     lea    bx,argp
  1521.     call    @fatal_dump
  1522. ;
  1523.     callp    tsk_set_dualdis
  1524.     or    ax,ax
  1525.     jz    no_second
  1526. ;
  1527.     callp    tsk_rputc,<0ch>
  1528.     les    di,txt
  1529.     lea    bx,argp
  1530.     call    @fatal_dump
  1531. ;
  1532. no_second:
  1533.     jmp    fatal_end
  1534. ;
  1535. tsk_fatal_pmd    endp
  1536. ;
  1537. ;
  1538. pmd1    db    0ah
  1539.     db    'AX = %04X  BX = %04X  CX = %04X  DX = %04X',0ah
  1540.     db    'SI = %04X  DI = %04X  DS = %04X  ES = %04X',0ah
  1541.     db    'SS = %04X  SP = %04X  BP = %04X',0ah
  1542.     db    'IP = %04X  CS = %04X',0ah,0
  1543. pmd2    db    'Current Task = %FP'
  1544.     IF    TSK_NAMED
  1545.     db    ' (%s)'
  1546.     ENDIF
  1547.     db    0ah,0
  1548. pmde    db    'System Halted',0
  1549. ;
  1550. ;
  1551. @fatal_dump    proc    near
  1552. ;
  1553.     callp    tsk_vrprintf,<<es,di>,<ss,bx>>
  1554.     mov    bx,sp
  1555.     add    bx,2
  1556.     callp    tsk_vrprintf,<<cs,#pmd1>,<ss,bx>>
  1557. ;
  1558.     IF    SINGLE_DATA
  1559.     mov    bx,offset tsk_glob_rec
  1560.     push    ds
  1561.     pop    es
  1562.     ELSE
  1563.     les    bx,tsk_global
  1564.     ENDIF
  1565.     les    bx,es:current_task[bx]
  1566.     IF    TSK_NAMED
  1567.     lea    dx,tname.nname[bx]
  1568.     callp    tsk_rprintf,<<cs,#pmd2>,<es,bx>,<es,dx>>
  1569.     ELSE
  1570.     callp    tsk_rprintf,<<cs,#pmd2>,<es,bx>>
  1571.     ENDIF
  1572.     callp    tsk_rprintf,<<cs,#pmde>>
  1573.     ret
  1574. ;
  1575. @fatal_dump    endp
  1576. ;
  1577.     ENDIF
  1578. ;
  1579. ;---------------------------------------------------------------
  1580. ;
  1581.     .tsk_ecode
  1582. ;
  1583.     ENDIF
  1584. ;
  1585.         end
  1586.  
  1587.