home *** CD-ROM | disk | FTP | other *** search
/ High Voltage Shareware / high1.zip / high1 / DIR41 / CTASK22D.ZIP / TSKDOS.ASM < prev    next >
Assembly Source File  |  1993-06-08  |  42KB  |  1,924 lines

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