home *** CD-ROM | disk | FTP | other *** search
/ OS/2 Shareware BBS: 10 Tools / 10-Tools.zip / caway349.zip / MISC / CWSWAPS.ASM < prev    next >
Assembly Source File  |  1998-05-22  |  75KB  |  3,335 lines

  1. .386
  2.  
  3. ;*****************************
  4. ;* Equates                   *
  5. ;*****************************
  6.  
  7. SWAPPERERROR    EQU    9999
  8. WEDGEOFFSET    EQU    180h
  9.  
  10. ;*****************************
  11. ;* Public declarations       *
  12. ;*****************************
  13.  
  14. PUBLIC    CWSwap
  15. ;PUBLIC    SWPRUNCMD
  16. ;PUBLIC    OverLay
  17. ;PUBLIC    O_RUNX
  18.  
  19. ;PUBLIC    Done
  20.  
  21. ;*****************************
  22. ;* External data             *
  23. ;*****************************
  24.  
  25. ;EXTRN    __retni:FAR
  26. ;EXTRN    __parclen:FAR
  27. ;EXTRN    __parc:FAR
  28.  
  29. ;*****************************
  30. ;* SPAWN Structures          *
  31. ;*****************************
  32.  
  33. ;
  34. ;    --- Version 3.3 92-03-30 21:39 ---
  35. ;
  36. ;    SPAWN.ASM - Main function for memory swapping spawn call.
  37. ;
  38. ;    Public Domain Software written by
  39. ;        Thomas Wagner
  40. ;        Ferrari electronic GmbH
  41. ;        Beusselstrasse 27
  42. ;        D-1000 Berlin 21
  43. ;        Germany
  44. ;
  45. ;
  46. ; Assemble with
  47. ;
  48. ; tasm  /DPASCAL spawn,spawnp          - Turbo Pascal (Tasm only), near
  49. ; tasm  /DPASCAL /DFARCALL spawn,spawnp    - Turbo Pascal (Tasm only), far
  50. ; ?asm  spawn;                  - C, default model (small)
  51. ; ?asm  /DMODL=large spawn          - C, large model
  52. ;
  53. ;    NOTE:    For C, change the 'model' directive below according to your
  54. ;        memory model, or define MODL=xxx on the command line.
  55. ;
  56. ;        For Turbo C Huge model, you must give /DTC_HUGE on the
  57. ;        command line, or define it here.
  58. ;
  59. ;
  60. ; Main function:
  61. ;
  62.  
  63. ;   C:
  64. ;       int do_spawn (int swapping,
  65. ;              char *execfname,
  66. ;              char *cmdtail,
  67. ;              unsigned envlen,
  68. ;              char *envp,
  69. ;              char *stdin,
  70. ;              char *stdout,
  71. ;              char *stderr)
  72. ;
  73. ;   Parameters:
  74. ;
  75. ;    swapping - swap/spawn/exec function:
  76. ;            < 0: Exec, don't swap
  77. ;                0: Spawn, don't swap
  78. ;            > 0: Spawn, swap
  79. ;                 in this case, prep_swap must have
  80. ;                 been called beforehand (see below).
  81. ;
  82. ;    cmdtail - command tail for EXEC.
  83. ;
  84. ;    execfname - name and path of file to execute.
  85. ;
  86. ;    envlen - length of environment copy (may be 0).
  87. ;
  88. ;    envp -  pointer to environment block (must be aligned on
  89. ;        paragraph boundary). Unused if envlen is 0.
  90. ;
  91. ;    'cmdtail' and 'execfname' must be zero terminated, even when
  92. ;    calling from Pascal. For Pascal, the length byte of the string
  93. ;    is ignored.
  94. ;
  95. ;   Returns:
  96. ;    0000..00ff:    Returncode of EXECed program
  97. ;    03xx:        DOS-Error xx calling EXEC
  98. ;    0500:        Swapping requested, but prep_swap has not
  99. ;            been called or returned an error
  100. ;    0501:        MCBs don't match expected setup
  101. ;    0502:        Error while swapping out
  102. ;    06xx:        DOS-Error xx on redirection
  103. ;
  104. ;
  105. ; For swapping, the swap method must be prepared before calling do_spawn.
  106. ;
  107. ;   C:
  108. ;    int prep_swap (unsigned method, char *swapfname)
  109. ;
  110. ;   Parameters:
  111. ;
  112. ;    method    - bit-map of allowed swap devices:
  113. ;            01 - Allow EMS
  114. ;            02 - Allow XMS
  115. ;            04 - Allow File swap
  116. ;            10 - Try XMS first, then EMS
  117. ;            40 - Create file as "hidden"
  118. ;            80 - Use "create temp" call for file swap
  119. ;               100 - Don't preallocate file
  120. ;               200 - Check for Network, don't preallocate if net
  121. ;              4000 - Environment block will not be swapped
  122. ;
  123. ;    swapfname - swap file name (may be undefined if the
  124. ;            "method" parameters disallows file swap).
  125. ;            The string must be zero terminated, even
  126. ;            when calling from Pascal. For Pascal, the
  127. ;            length byte of the string is ignored.
  128. ;
  129. ;   Returns:
  130. ;
  131. ;       A positive integer on success:
  132. ;        1 - EMS swap initialized
  133. ;        2 - XMS swap initialized
  134. ;        4 - File swap initialized
  135. ;    A negative integer on failure:
  136. ;        -1 - Couldn't allocate swap space
  137. ;        -2 - The spawn module is located too low in memory
  138. ;
  139. ;--------------------------------------------------------------------------
  140. ;
  141. ;
  142. ;    Set NO_INHERIT to FALSE if you don't want do_exec to mess with
  143. ;    the handle table in the PSP, and/or you do want the child process
  144. ;    to inherit all open files.
  145. ;    If NO_INHERIT is TRUE, only the first five handles (the standard
  146. ;    ones) will be inherited, all others will be hidden. This allows
  147. ;    the child to open more files, and also protects you from the child
  148. ;    messing with any open handles.
  149. ;    NO_INHERIT should always be TRUE if you use functions to extend
  150. ;    the handle table (for more than 20 open files).
  151. ;
  152. ;    Set REDIRECT to FALSE if you do not want do_spawn to support redirection.
  153. ;
  154. ;
  155. ;
  156. FALSE        =    0
  157. TRUE        =    NOT FALSE
  158. ;
  159. NO_INHERIT    =    TRUE
  160. REDIRECT    =    FALSE
  161. ;
  162. ;
  163. ;
  164. ;    IFNDEF    MODL
  165. ;    .model    small,c
  166. ;    %out    small model
  167. ;    ELSE
  168. ;%    .model    MODL,c
  169. ;%    %out    MODL model
  170. ;    ENDIF
  171. ;
  172. ;ptrsize    =    @DataSize
  173. ptrsize    =    1
  174. ;
  175. ;    extrn    _psp: word
  176. ;
  177. ;    public    do_spawn
  178. ;    public    prep_swap
  179. ;    public    swap_prep
  180. ;
  181. stacklen    =    256        ; local stack
  182. ;
  183. ;    "ems_size" is the EMS block size: 16k.
  184. ;
  185. ems_size    =    16 * 1024    ; EMS block size
  186. ems_parasize    =    ems_size / 16    ; same in paragraphs
  187. ems_shift    =    10        ; shift factor for paragraphs
  188. ems_paramask    =    ems_parasize-1    ; block mask
  189. ;
  190. ;    "xms_size" is the unit of measurement for XMS: 1k
  191. ;
  192. xms_size    =    1024        ; XMS block size
  193. xms_parasize    =    xms_size / 16    ; same in paragraphs
  194. xms_shift    =    6        ; shift factor for paragraphs
  195. xms_paramask    =    xms_parasize-1    ; block mask
  196. ;
  197. ;    Method flags
  198. ;
  199. USE_EMS        =    01h
  200. USE_XMS        =    02h
  201. USE_FILE    =    04h
  202. XMS_FIRST    =    10h
  203. HIDE_FILE    =    40h
  204. CREAT_TEMP    =    80h
  205. NO_PREALLOC    =    100h
  206. CHECK_NET    =    200h
  207. DONT_SWAP_ENV    =    4000h
  208. ;
  209. ;    Return codes
  210. ;
  211. RC_TOOLOW    =    0102h
  212. RC_BADPREP    =    0500h
  213. RC_MCBERROR    =    0501h
  214. RC_SWAPERROR    =    0502h
  215. RC_REDIRFAIL    =    0600h
  216. ;
  217. EMM_INT        =    67h
  218. ;
  219. ;    The EXEC function parameter block
  220. ;
  221. exec_block    struc
  222. envseg    dw    ?        ; environment segment
  223. ppar    dw    ?        ; program parameter string offset
  224. pparseg    dw    ?        ; program parameter string segment
  225. fcb1    dw    ?        ; FCB offset
  226. fcb1seg    dw    ?        ; FCB segment
  227. fcb2    dw    ?        ; FCB offset
  228. fcb2seg    dw    ?        ; FCB segment
  229. exec_block    ends
  230. ;
  231. ;    Structure of an XMS move control block
  232. ;
  233. xms_control    struc
  234. lenlo        dw    ?    ; length to move (doubleword)
  235. lenhi        dw    ?
  236. srchnd        dw    ?    ; source handle (0 for standard memory)
  237. srclo        dw    ?    ; source address (doubleword or seg:off)
  238. srchi        dw    ?
  239. desthnd        dw    ?    ; destination handle (0 for standard memory)
  240. destlo        dw    ?    ; destination address (doubleword or seg:off)
  241. desthi        dw    ?
  242. xms_control    ends
  243. ;
  244. ;    The structure of the start of an MCB (memory control block)
  245. ;
  246. mcb        struc
  247. id        db    ?
  248. owner        dw    ?
  249. paras        dw    ?
  250. mcb        ends
  251. ;
  252. ;    The structure of an internal MCB descriptor.
  253. ;    CAUTION: This structure is assumed to be no larger than 16 bytes
  254. ;    in several places in the code, and to be exactly 16 bytes when
  255. ;    swapping in from file. Be careful when changing this structure.
  256. ;
  257. mcbdesc        struc
  258. addr        dw    ?    ; paragraph address of the MCB
  259. msize        dw    ?    ; size in paragraphs (excluding header)
  260. swoffset    dw    ?    ; swap offset (0 in all blocks except first)
  261. swsize        dw    ?    ; swap size (= msize + 1 except in first)
  262. num_follow    dw    ?    ; number of following MCBs
  263.         dw    3 dup(?) ; pad to paragraph (16 bytes)
  264. mcbdesc        ends
  265. ;
  266. ;    The variable block set up by prep_swap
  267. ;
  268. prep_block    struc
  269. xmm        dd    ?        ; XMM entry address
  270. first_mcb    dw    ?        ; Segment of first MCB
  271. psp_mcb        dw    ?        ; Segment of MCB of our PSP
  272. env_mcb        dw    ?        ; MCB of Environment segment
  273. noswap_mcb    dw    ?        ; Env MCB that may not be swapped
  274. noswap2_mcb    dw    ?        ; Wedge MCB that may not be swapped
  275. noswap3_mcb    dw    ?        ; File handle MCB that may not be swapped
  276. ems_pageframe    dw    ?        ; EMS page frame address
  277. handle        dw    ?        ; EMS/XMS/File handle
  278. total_mcbs    dw    ?        ; Total number of MCBs
  279. swapmethod    db    ?        ; Method for swapping
  280. sp_swapfilename    db    81 dup(?)    ; Swap file name if swapping to file
  281. prep_block    ends
  282. ;
  283. ;----------------------------------------------------------------------
  284. ;
  285. ;    Since we'll be moving code and data around in memory,
  286. ;    we can't address locations in the resident block with
  287. ;    normal address expressions. MASM does not support
  288. ;    defining variables with a fixed offset, so we have to resort
  289. ;    to a kludge, and define the shrunk-down code as a structure.
  290. ;    It would also be possible to use an absolute segment for the
  291. ;    definition, but this is not supported by the Turbo Pascal linker.
  292. ;
  293. ;    All references to low-core variables from low-core itself
  294. ;    are made through DS, so we define a text macro "lmem" that
  295. ;    expands to "ds:". When setting up low core from the normal
  296. ;    code, ES is used to address low memory, so this can't be used.
  297. ;
  298. lmem    equ    <ds:>
  299. ;
  300. ;    The memory structure for the shrunk-down code, excluding the
  301. ;    code itself. The code follows this block.
  302. ;    The start of this block is the PSP.
  303. ;
  304. parseg        struc
  305.         db    18h dup(?)
  306. psp_handletab    db    20 dup(?)    ; Handle Table
  307. psp_envptr    dw    ?        ; Environment Pointer
  308.         dd    ?
  309. psp_handlenum    dw    ?        ; Number of Handles (DOS >= 3.3)
  310. psp_handleptro    dw    ?        ; Handle Table Pointer (DOS >= 3.3)
  311. psp_handleptrs    dw    ?        ; Handle Table Pointer Segment
  312.         db    5ch-38h dup(?)    ; start after PSP
  313. ;
  314. save_ss        dw    ?        ; 5C - saved global ss
  315. save_sp        dw    ?        ; 5E - saved global sp
  316. xfcb1        db    16 dup(?)    ; 60..6F - default FCB
  317. xfcb2        db    16 dup(?)    ; 70..7F - default FCB
  318. zero        dw    ?        ; 80 Zero command tail length (dummy)
  319. ;
  320. expar        db    TYPE exec_block dup (?) ; exec-parameter-block
  321. spx        dw    ?        ; saved local sp
  322. div0_off    dw    ?        ; divide by zero vector save
  323. div0_seg    dw    ?
  324. lhandlesave    db    26 dup(?)    ; saved handle table and pointer
  325.         IF    REDIRECT
  326. lredirsav    db    6 dup(?)    ; saved redirection handles
  327. lstdinsav    dw    3 dup(?)    ; duped redirection handles
  328.         ENDIF
  329. filename    db    82 dup(?)    ; exec filename
  330. progpars    db    128 dup(?)    ; command tail
  331.         db    stacklen dup(?)    ; local stack space
  332. mystack        db    ?
  333. lprep        db    TYPE prep_block dup(?)    ; the swapping variables
  334. lcurrdesc    db    TYPE mcbdesc dup(?)    ; the current MCB descriptor
  335. lxmsctl        db    TYPE xms_control dup(?)
  336. eretcode    dw    ?        ; EXEC return code
  337. retflags    dw    ?        ; EXEC return flags
  338. cgetmcb        dw    ?        ; address of get_mcb
  339. dtasave        DD    ?        ; address of original DTA
  340. GoToWedge    DD    ?        ; address of wedge code
  341. ;
  342. parseg    ends
  343. ;
  344. param_len    =    ((TYPE parseg + 1) / 2) * 2    ; make even
  345. codebeg        =    param_len
  346. ;
  347.  
  348. ;*****************************
  349. ;* Code begins               *
  350. ;*****************************
  351.  
  352. SWAP_TEXT    SEGMENT PARA PRIVATE USE16 'CODE'
  353.  
  354. ASSUME    cs:SWAP_TEXT
  355.  
  356. CodeStart    =    $
  357.  
  358. ;lookie    DW    keep_paras
  359.  
  360. ;
  361. ;------------------------------------------------------------------------
  362. ;
  363. lowcode_begin:
  364. ;
  365. ;       The following parts of the program code will be moved to
  366. ;    low core and executed there, so there must be no absolute
  367. ;    memory references.
  368. ;    The call to get_mcb must be made indirect, since the offset
  369. ;    from the swap-in routine to get_mcb will not be the same
  370. ;    after moving.
  371. ;
  372. ;
  373. ;    get_mcb allocates a block of memory by modifying the MCB chain
  374. ;    directly.
  375. ;
  376. ;    On entry, lcurrdesc has the mcb descriptor for the block to
  377. ;          allocate.
  378. ;
  379. ;    On exit,  Carry is set if the block couldn't be allocated.
  380. ;
  381. ;    Uses     AX, BX, CX, ES
  382. ;    Modifies lprep.first_mcb
  383. ;
  384. get_mcb    proc    near
  385. ;
  386.     mov    ax,lmem lprep.first_mcb
  387.     mov    bx,lmem lcurrdesc.addr
  388. ;
  389. getmcb_loop:
  390.     mov    es,ax
  391.     cmp    ax,bx
  392.     ja    gmcb_abort        ; halt if MCB > wanted
  393.     je    mcb_found        ; jump if same addr as wanted
  394.     add    ax,es:paras        ; last addr
  395.     inc    ax            ; next mcb
  396.     cmp    ax,bx
  397.     jbe    getmcb_loop        ; Loop if next <= wanted
  398. ;
  399. ;
  400. ;    The wanted MCB starts within the current MCB. We now have to
  401. ;    create a new MCB at the wanted position, which is initially
  402. ;    free, and shorten the current MCB to reflect the reduced size.
  403. ;
  404.     cmp    es:owner,0
  405.     jne    gmcb_abort        ; halt if not free
  406.     mov    bx,es            ; current
  407.     inc    bx            ; + 1 (header doesn't count)
  408.     mov    ax,lmem lcurrdesc.addr
  409.     sub    ax,bx            ; paragraphs between MCB and wanted
  410.     mov    bx,es:paras        ; paras in current MCB
  411.     sub    bx,ax            ; remaining paras
  412.     dec    bx            ; -1 for header
  413.     mov    es:paras,ax        ; set new size for current
  414.     mov    cl,es:id        ; old id
  415.     mov    es:id,4dh        ; set id: there is a next
  416.     mov    ax,lmem lcurrdesc.addr
  417.     mov    es,ax
  418.     mov    es:id,cl        ; and init to free
  419.     mov    es:owner,0
  420.     mov    es:paras,bx
  421. ;
  422. ;    We have found an MCB at the right address. If it's not free,
  423. ;    abort. Else check the size. If the size is ok, we're done
  424. ;    (more or less).
  425. ;
  426. mcb_found:
  427.     mov    es,ax
  428.     cmp    es:owner,0
  429.     je    mcb_check        ; continue if free
  430. ;
  431. gmcb_abort:
  432.     stc
  433.     ret
  434. ;
  435. mcb_check:
  436.     mov    ax,es:paras        ; size
  437.     cmp    ax,lmem lcurrdesc.msize    ; needed size
  438.     jae    mcb_ok            ; ok if enough space
  439. ;
  440. ;    If there's not enough room in this MCB, check if the next
  441. ;    MCB is free, too. If so, coalesce both MCB's and check again.
  442. ;
  443.     cmp    es:id,4dh
  444.     jnz    gmcb_abort        ; halt if no next
  445.     push    es            ; save current
  446.     mov    bx,es
  447.     add    ax,bx
  448.     inc    ax            ; next MCB
  449.     mov    es,ax
  450.     cmp    es:owner,0        ; next free ?
  451.     jne    gmcb_abort        ; halt if not
  452.     mov    ax,es:paras        ; else load size
  453.     inc    ax            ; + 1 for header
  454.     mov    cl,es:id        ; and load ID
  455.     pop    es            ; back to last MCB
  456.     add    es:paras,ax        ; increase size
  457.     mov    es:id,cl        ; and store ID
  458.     jmp    mcb_check        ; now try again
  459. ;
  460. ;    The MCB is free and large enough. If it's larger than the
  461. ;    wanted size, create another MCB after the wanted.
  462. ;
  463. mcb_ok:
  464.     mov    bx,es:paras
  465.     sub    bx,lmem lcurrdesc.msize
  466.     jz    mcb_no_next        ; ok, no next to create
  467.     push    es
  468.     dec    bx            ; size of next block
  469.     mov    ax,es
  470.     add    ax,lmem lcurrdesc.msize
  471.     inc    ax            ; next MCB addr
  472.     mov    cl,es:id        ; id of this block
  473.     mov    es,ax            ; address next
  474.     mov    es:id,cl        ; store id
  475.     mov    es:paras,bx        ; store size
  476.     mov    es:owner,0        ; and mark as free
  477.     pop    es            ; back to old MCB
  478.     mov    es:id,4dh        ; mark next block present
  479.     mov    ax,lmem lcurrdesc.msize    ; and set size to wanted
  480.     mov    es:paras,ax
  481. ;
  482. mcb_no_next:
  483.     mov    es:owner,cx        ; set owner to current PSP
  484. ;
  485. ;    Set the 'first_mcb' pointer to the current one, so we don't
  486. ;    walk through all the previous blocks the next time.
  487. ;    Also, check if the block we just allocated is the environment
  488. ;    segment of the program. If so, restore the environment pointer
  489. ;    in the PSP.
  490. ;
  491.     mov    ax,es
  492.     mov    lmem lprep.first_mcb,ax
  493. ;    cmp    lmem lprep.env_mcb,ax
  494. ;    jne    getmcb_finis
  495. ;    inc    ax
  496. ;    mov    lmem psp_envptr,ax
  497. ;
  498. getmcb_finis:
  499.     clc
  500.     ret                ; all finished (whew!)
  501. ;
  502. get_mcb    endp
  503. ;
  504. ;
  505. ireti:
  506.     iret
  507. ;
  508. ;
  509. ;    The actual EXEC call.
  510. ;    Registers on entry:
  511. ;        BX    = paragraphs to keep (0 if no swap)
  512. ;        CX     = length of environment to copy (words) or zero
  513. ;        DS:SI    = environment source
  514. ;        ES:DI    = environment destination
  515. ;        (ES = our low core code segment)
  516. ;
  517. ;
  518. ;    copy environment buffer down if present
  519. ;
  520. doexec:
  521. ;    jcxz    noenvcpy
  522. ;    rep movsw
  523. ;
  524. noenvcpy:
  525.     push    es            ; DS = ES = low core = PSP
  526.     pop    ds
  527.     or    bx,bx
  528.     jz    no_shrink
  529. ;
  530. ;    first, shrink the base memory block down.
  531. ;
  532. ;    int    3
  533.  
  534. IFDEF SHRINKPSP
  535.     mov    ah,04ah
  536.     int    21h                     ; resize memory block
  537. ENDIF
  538. ;
  539. ;    Again walk all MCBs. This time, all blocks owned by the
  540. ;    current process are released.
  541. ;
  542.     mov    si,lmem lprep.first_mcb
  543.     or    si,si
  544.     jz    no_shrink
  545.     mov    dx,lmem lprep.psp_mcb
  546.     mov    bx,dx
  547.     inc    bx            ; base PSP (MCB owner)
  548.     mov    di,lmem lprep.noswap_mcb
  549.     mov    cx,lmem lprep.noswap2_mcb
  550. ;
  551. free_loop:
  552.     cmp    si,dx
  553.     je    free_next        ; don't free base block
  554.     cmp    si,di
  555.     je    free_next
  556.     cmp    si,cx
  557.     je    free_next
  558.     cmp    si,lmem lprep.noswap3_mcb
  559.     je    free_next
  560.  
  561.     mov    es,si
  562.     cmp    bx,es:owner        ; our process?
  563.     jne    free_next        ; next if not
  564. ;    cmp    si,lmem lprep.env_mcb    ; is this the environment block?
  565. ;    jne    free_noenv
  566. ;    mov    ds:psp_envptr,0        ; else clear PSP pointer
  567. ;
  568. free_noenv:
  569.     inc    si
  570.     mov    es,si
  571.     dec    si
  572.     mov    ah,049h            ; free memory block
  573.     int    21h
  574. ;
  575. free_next:
  576.     mov    es,si
  577.     cmp    es:id,4dh        ; normal block?
  578.     jne    free_ready        ; ready if end of chain
  579.     add    si,es:paras        ; start + length
  580.     inc    si            ; next MCB
  581.     jmp    free_loop
  582. ;
  583. free_ready:
  584. no_shrink:
  585.     mov    ah,2fh        ; get DTA address
  586.     int    21h
  587.     mov    WORD PTR lmem dtasave,bx    ; save original DTA
  588.     mov    WORD PTR lmem dtasave+2,es
  589.     mov    ax,ds
  590.     mov    es,ax
  591.     mov    WORD PTR lmem GoToWedge,0
  592.     mov    WORD PTR lmem GoToWedge+2,fs
  593. ;
  594.  
  595. ;    int    3
  596.  
  597.     mov    dx,filename        ; params for exec
  598.     mov    bx,expar
  599.  
  600.     call    dword ptr lmem [GoToWedge]
  601. ;    mov    ax,04b00h
  602. ;    int    21h            ; exec
  603. ;
  604. ;    Return from EXEC system call. Don't count on any register except
  605. ;    CS to be restored (DOS 2.11 and previous versions killed all regs).
  606. ;
  607.     mov    bx,cs
  608.     mov    ds,bx
  609.     mov    es,bx
  610.     cli
  611.     mov    ss,bx
  612.     mov    sp,lmem spx
  613.     sti
  614.     cld
  615.     mov    lmem eretcode,ax    ; save return code
  616.     pushf
  617.     pop    bx
  618.     mov    lmem retflags,bx    ; and returned flags
  619.  
  620. ; restore dta
  621.     push    ds
  622.     lds    dx,lmem dtasave
  623.     mov    ah,1ah        ; set DTA address
  624.     int    21h
  625.     pop    ds
  626. ;
  627. ;    Cancel Redirection
  628. ;
  629.     IF    REDIRECT
  630.     mov    si,lredirsav
  631.     mov    di,psp_handletab+5
  632.     mov    cx,3
  633.     rep movsw
  634.     mov    si,lstdinsav
  635.     xor    cx,cx
  636. ;
  637. lredirclose:
  638.     lodsw
  639.     cmp    ax,-1
  640.     je    lredclosenext
  641.     mov    bx,ax
  642.     mov    ah,46h
  643.     int    21h
  644. ;
  645. lredclosenext:
  646.     inc    cx
  647.     cmp    cx,3
  648.     jb    lredirclose
  649.     ENDIF
  650. ;
  651. IFDEF SHRINKPSP
  652.     cmp    lmem lprep.swapmethod,0
  653.     je    exec_memok
  654.     jg    exec_expand
  655. ELSE
  656.     jmp    NEAR PTR exec_memok
  657. ENDIF
  658. ;
  659. ;    Terminate.
  660. ;
  661.     test    lmem retflags,1        ; carry?
  662.     jnz    exec_term        ; use EXEc retcode if set
  663.     mov    ah,4dh            ; else get program return code
  664.     int    21h
  665. ;
  666. exec_term:
  667.     mov    ah,4ch
  668.     int    21h
  669. ;
  670.  
  671. ;
  672. exec_expand:
  673. IFDEF SHRINKPSP
  674.     mov    ah,4ah            ; expand memory
  675.     mov    bx,lmem lcurrdesc.msize
  676.     int    21h
  677.     jnc    exec_memok
  678.     mov    ax,4cffh
  679.     int    21h            ; terminate on error
  680. ENDIF
  681. ;
  682. ;    Swap memory back
  683. ;
  684.     nop
  685.     nop
  686.     nop
  687.  
  688. ;
  689. exec_memok:
  690. ;
  691. ;    FALL THROUGH to the appropriate swap-in routine
  692. ;
  693. ;
  694. getmcboff    =    offset get_mcb - offset lowcode_begin
  695. iretoff        =    offset ireti - offset lowcode_begin
  696. doexec_entry    =    offset doexec - offset lowcode_begin
  697. base_length    =    offset $ - offset lowcode_begin
  698. ;
  699. ;-----------------------------------------------------------------------
  700. ;
  701. ;    The various swap in routines follow. Only one of the routines
  702. ;    is copied to low memory.
  703. ;    Note that the routines are never actually called, the EXEC return
  704. ;    code falls through. The final RET thus will return to the restored
  705. ;    memory image.
  706. ;
  707. ;    On entry, DS must point to low core.
  708. ;    On exit to the restored code, DS is unchanged.
  709. ;
  710. ;
  711. ;    swapin_ems:    swap in from EMS.
  712. ;
  713. swapin_ems    proc    far
  714. ;
  715.     xor    bx,bx
  716.     mov    si,ems_parasize
  717.     mov    dx,lmem lprep.handle    ; EMS handle
  718. ;
  719. swinems_main:
  720.     push    ds
  721.     mov    cx,lmem lcurrdesc.swsize    ; block length in paras
  722.     mov    di,lmem lcurrdesc.swoffset    ; swap offset
  723.     mov    es,lmem lcurrdesc.addr        ; segment to swap
  724.     mov    ds,lmem lprep.ems_pageframe    ; page frame address
  725. ;
  726.     mov    ax,ems_parasize        ; max length
  727.     sub    ax,si            ; minus current offset
  728.     jnz    swinems_ok        ; go copy if nonzero
  729. ;
  730. swinems_loop:
  731.     mov    ax,4400h        ; map in next page
  732.     int    EMM_INT
  733.     or    ah,ah
  734.     jnz    swinems_error
  735.     mov    si,0            ; reset offset
  736.     inc    bx            ; bump up page number
  737.     mov    ax,ems_parasize        ; max length to copy
  738. ;
  739. swinems_ok:
  740.     cmp    ax,cx            ; length to copy
  741.     jbe    swinems_doit        ; go do it if <= total length
  742.     mov    ax,cx            ; else use total length
  743. ;
  744. swinems_doit:
  745.     sub    cx,ax            ; subtract copy length from total
  746.     push    cx            ; and save
  747.     push    ax            ; save the copy length in paras
  748.     push    si
  749.     push    di
  750.     mov    cl,3
  751.     shl    ax,cl            ; convert to number of words (!)
  752.     inc    cl
  753.     shl    si,cl            ; convert to byte address
  754.     mov    cx,ax
  755.     rep movsw
  756.     pop    di
  757.     pop    si
  758.     pop    cx            ; copy length in paras
  759.     mov    ax,es
  760.     add    ax,cx            ; add copy length to dest segment
  761.     add    si,cx            ; and EMS page offset
  762.     mov    es,ax
  763.     pop    cx            ; remaining length
  764.     or    cx,cx            ; did we copy everything?
  765.     jnz    swinems_loop        ; go loop if not
  766. ;
  767.     pop    ds
  768.     cmp    lmem lcurrdesc.num_follow,0    ; another MCB?
  769.     je    swinems_complete    ; exit if not
  770. ;
  771. ;    Another MCB follows, read next mcb descriptor into currdesc
  772. ;
  773.     cmp    si,ems_parasize
  774.     jb    swinems_nonewpage    ; no new block needed
  775.     mov    ax,4400h        ; map page, phys = 0
  776.     int    EMM_INT
  777.     or    ah,ah
  778.     jnz    swinems_error1
  779.     mov    si,0
  780.     inc    bx
  781. ;
  782. swinems_nonewpage:
  783.     push    si
  784.     push    ds
  785.     mov    ax,ds
  786.     mov    es,ax
  787.     mov    ds,lmem lprep.ems_pageframe    ; page frame address
  788.     mov    cl,4
  789.     shl    si,cl            ; convert to byte address
  790.     mov    cx,TYPE mcbdesc
  791.     mov    di,lcurrdesc
  792.     rep movsb
  793.     pop    ds
  794.     pop    si
  795.     inc    si            ; one paragraph
  796. ;
  797.     push    bx
  798.     call    lmem cgetmcb
  799.     pop    bx
  800.     jc    swinems_error1
  801.     jmp    swinems_main
  802. ;
  803. swinems_complete:
  804.     mov    ah,45h            ; release EMS pages
  805.     int    EMM_INT
  806.     ret
  807. ;
  808. swinems_error:
  809.     pop    ds
  810. swinems_error1:
  811.     mov    ah,45h            ; release EMS pages on error
  812.     int    EMM_INT
  813.     mov    ax,4cffh
  814.     int    21h            ; terminate
  815. ;
  816. swapin_ems    endp
  817. ;
  818. swinems_length    = offset $ - offset swapin_ems
  819. ;
  820. ;
  821. ;    swapin_xms:    swap in from XMS.
  822. ;
  823. swapin_xms    proc    far
  824. ;
  825.     mov    ax,lmem lprep.handle    ; XMS handle
  826.     mov    lmem lxmsctl.srchnd,ax     ; source is XMS
  827.     mov    lmem lxmsctl.desthnd,0     ; dest is normal memory
  828.     mov    lmem lxmsctl.srclo,0
  829.     mov    lmem lxmsctl.srchi,0
  830. ;
  831. swinxms_main:
  832.     mov    ax,lmem lcurrdesc.swsize ; size in paragraphs
  833.     mov    cl,4
  834.     rol    ax,cl            ; size in bytes + high nibble
  835.     mov    dx,ax
  836.     and    ax,0fff0h        ; low word
  837.     and    dx,0000fh        ; high word
  838.     mov    lmem lxmsctl.lenlo,ax    ; into control block
  839.     mov    lmem lxmsctl.lenhi,dx
  840.     mov    ax,lmem lcurrdesc.swoffset    ; swap offset
  841.     mov    lmem lxmsctl.destlo,ax         ; into control block
  842.     mov    ax,lmem lcurrdesc.addr        ; segment to swap
  843.     mov    lmem lxmsctl.desthi,ax
  844.     mov    si,lxmsctl
  845.     mov    ah,0bh
  846.     call    lmem lprep.xmm        ; move it
  847.     or    ax,ax
  848.     jz    swinxms_error
  849.     mov    ax,lmem lxmsctl.lenlo    ; adjust source addr
  850.     add    lmem lxmsctl.srclo,ax
  851.     mov    ax,lmem lxmsctl.lenhi
  852.     adc    lmem lxmsctl.srchi,ax
  853. ;
  854.     cmp    lmem lcurrdesc.num_follow,0    ; another MCB?
  855.     je    swinxms_complete
  856. ;
  857.     mov    lmem lxmsctl.lenlo,TYPE mcbdesc
  858.     mov    lmem lxmsctl.lenhi,0
  859.     mov    lmem lxmsctl.desthi,ds
  860.     mov    lmem lxmsctl.destlo,lcurrdesc
  861.     mov    si,lxmsctl
  862.     mov    ah,0bh
  863.     call    lmem lprep.xmm        ; move it
  864.     or    ax,ax
  865.     jz    swinxms_error
  866.     add    lmem lxmsctl.srclo,16    ; one paragraph
  867.     adc    lmem lxmsctl.srchi,0
  868. ;
  869.     call    lmem cgetmcb
  870.     jc    swinxms_error
  871.     jmp    swinxms_main
  872. ;
  873. swinxms_complete:
  874.     mov    ah,0ah            ; release XMS frame
  875.     mov    dx,lmem lprep.handle       ; XMS handle
  876.     call    lmem lprep.xmm
  877.     ret
  878. ;
  879. swinxms_error:
  880.     mov    ah,0ah            ; release XMS frame on error
  881.     call    lmem lprep.xmm
  882.     mov    ax,4c00h
  883.     int    21h
  884. ;
  885. swapin_xms    endp
  886. ;
  887. swinxms_length    = offset $ - offset swapin_xms
  888. ;
  889. ;
  890. ;    swapin_file:    swap in from file.
  891. ;
  892. swapin_file    proc    far
  893. ;
  894.     mov    dx,lprep.sp_swapfilename
  895.     mov    ax,3d00h            ; open file
  896.     int    21h
  897.     jc    swinfile_error2
  898.     mov    bx,ax                ; file handle
  899. ;
  900. ; do this in case of shrinkage of non-owned MCB between PSP MCB and next owned MCB
  901.     mov    ax,ds            ; ax==PSP
  902.     dec    ax                ; ax==PSP MCB
  903.     mov    lmem lprep.first_mcb,ax    ; init first MCB to PSP
  904.  
  905. swinfile_main:
  906.     push    ds
  907.     mov    cx,lmem lcurrdesc.swsize    ; size in paragraphs
  908.     mov    dx,lmem lcurrdesc.swoffset    ; swap offset
  909.     mov    ds,lmem lcurrdesc.addr        ; segment to swap
  910. ;
  911. swinfile_loop:
  912.     mov    ax,cx
  913.     cmp    ah,8h            ; above 32k?
  914.     jbe    swinfile_ok        ; go read if not
  915.     mov    ax,800h            ; else read 32k
  916. ;
  917. swinfile_ok:
  918.     sub    cx,ax            ; remaining length
  919.     push    cx            ; save it
  920.     push    ax            ; and save paras to read
  921.     mov    cl,4
  922.     shl    ax,cl            ; convert to bytes
  923.     mov    cx,ax
  924.     mov    ah,3fh            ; read
  925.     int    21h
  926.     jc    swinfile_error
  927.     cmp    ax,cx
  928.     jne    swinfile_error
  929.     pop    cx            ; paras read
  930.     mov    ax,ds
  931.     add    ax,cx            ; bump up dest segment
  932.     mov    ds,ax
  933.     pop    cx            ; remaining length
  934.     or    cx,cx            ; anything left?
  935.     jnz    swinfile_loop        ; go loop if yes
  936. ;
  937.     pop    ds
  938.     cmp    lmem lcurrdesc.num_follow,0    ; another MCB?
  939.     je    swinfile_complete    ; ready if not
  940.     mov    cx,16            ; read one paragraph
  941.     mov    dx,lcurrdesc
  942.     mov    ah,3fh
  943.     int    21h
  944.     jc    swinfile_error1
  945.     cmp    ax,cx
  946.     jne    swinfile_error1
  947. ;
  948.     push    bx
  949.     call    lmem cgetmcb
  950.     pop    bx
  951.     jc    swinfile_error1
  952.     jmp    swinfile_main
  953. ;
  954. ;
  955. swinfile_complete:
  956.     mov    ah,3eh            ; close file
  957.     int    21h
  958.     mov    dx,lprep.sp_swapfilename
  959.     mov    ah,41h            ; delete file
  960.     int    21h
  961.     ret
  962. ;
  963. swinfile_error:
  964.     pop    cx
  965.     pop    cx
  966.     pop    ds
  967. swinfile_error1:
  968.     mov    ah,3eh            ; close file
  969.     int    21h
  970. swinfile_error2:
  971.     mov    dx,lprep.sp_swapfilename
  972.     mov    ah,41h            ; delete file
  973.     int    21h
  974.     mov    ax,4cffh
  975.     int    21h
  976. ;
  977. swapin_file    endp
  978. ;
  979. swinfile_length    = offset $ - offset swapin_file
  980. ;
  981. ;
  982. ;    swapin_none:    no swap, return immediately.
  983. ;
  984. swapin_none    proc    far
  985. ;
  986.     ret
  987. ;
  988. swapin_none    endp
  989. ;
  990. ;
  991.     IF    swinems_length GT swinxms_length
  992. swcodelen    =    swinems_length
  993.     ELSE
  994. swcodelen    =    swinxms_length
  995.     ENDIF
  996.     IF    swinfile_length GT swcodelen
  997. swcodelen    =    swinfile_length
  998.     ENDIF
  999. ;
  1000. swap_codelen    =    ((swcodelen + 3) / 4) * 4
  1001. ;
  1002. codelen        =    base_length + swap_codelen
  1003. reslen        =    codebeg + codelen
  1004. keep_paras    =    (reslen + 15) shr 4    ; paragraphs to keep
  1005. swapbeg        =    keep_paras shl 4    ; start of swap space
  1006. savespace    =    swapbeg - 5ch    ; length of overwritten area
  1007. ;
  1008. ;--------------------------------------------------------------------
  1009. ;
  1010. ;
  1011. ;
  1012. ;    Space for saving the part of the memory image below the
  1013. ;    swap area that is overwritten by our code.
  1014. ;
  1015. save_dat    db    savespace dup(?)
  1016. ;
  1017. ;    Variables used while swapping out.
  1018. ;    The "swap_prep" structure is initialized by prep_swap.
  1019. ;
  1020. swap_prep    prep_block    <>
  1021. nextmcb        mcbdesc        <>
  1022. currdesc    mcbdesc        <>
  1023. xmsctl        xms_control    <>
  1024. ems_curpage    dw        ?    ; current EMS page number
  1025. ems_curoff    dw        ?    ; current EMS offset (paragraph)
  1026. ;
  1027. ;--------------------------------------------------------------------
  1028. ;
  1029. ;
  1030. ;    swapout_ems:    swap out an MCB block to EMS.
  1031. ;
  1032. ;    Entry:    "currdesc"     contains description of block to swap
  1033. ;        "nextmcb"    contains MCB-descriptor of next block
  1034. ;                if currdesc.num_follow is nonzero
  1035. ;
  1036. ;    Exit:    0 if OK, != 0 if error, Zero-flag set accordingly.
  1037. ;
  1038. ;    Uses:    All regs excpt DS
  1039. ;
  1040. swapout_ems    proc    near
  1041. ;
  1042.     push    ds
  1043.     mov    cx,currdesc.swsize    ; block length in paras
  1044.     mov    si,currdesc.swoffset    ; swap offset
  1045.     mov    dx,swap_prep.handle    ; EMS handle
  1046.     mov    bx,ems_curpage        ; current EMS page
  1047.     mov    di,ems_curoff        ; current EMS page offset (paras)
  1048.     mov    es,swap_prep.ems_pageframe    ; page frame address
  1049.     mov    ds,currdesc.addr    ; segment to swap
  1050. ;
  1051.     mov    ax,ems_parasize        ; max length
  1052.     sub    ax,di            ; minus current offset
  1053.     jnz    swems_ok        ; go copy if there's room
  1054. ;
  1055. swems_loop:
  1056.     mov    ax,4400h        ; map in next page
  1057.     int    EMM_INT
  1058.     or    ah,ah
  1059.     jnz    swems_error
  1060.     mov    di,0            ; reset offset
  1061.     inc    bx            ; bump up page number
  1062.     mov    ax,ems_parasize        ; max length to copy
  1063. ;
  1064. swems_ok:
  1065.     cmp    ax,cx            ; length to copy
  1066.     jbe    swems_doit        ; go do it if <= total length
  1067.     mov    ax,cx            ; else use total length
  1068. ;
  1069. swems_doit:
  1070.     sub    cx,ax            ; subtract copy length from total
  1071.     push    cx            ; and save
  1072.     push    ax            ; save the copy length in paras
  1073.     push    si
  1074.     push    di
  1075.     mov    cl,3
  1076.     shl    ax,cl            ; convert to number of words (!)
  1077.     inc    cl
  1078.     shl    di,cl            ; convert to byte address
  1079.     mov    cx,ax
  1080.     rep movsw
  1081.     pop    di
  1082.     pop    si
  1083.     pop    cx            ; copy length in paras
  1084.     mov    ax,ds
  1085.     add    ax,cx            ; add copy length to source segment
  1086.     add    di,cx            ; and EMS page offset
  1087.     mov    ds,ax
  1088.     pop    cx            ; remaining length
  1089.     or    cx,cx            ; did we copy everything?
  1090.     jnz    swems_loop        ; go loop if not
  1091. ;
  1092.     pop    ds
  1093.     cmp    currdesc.num_follow,0    ; another MCB?
  1094.     je    swems_complete        ; exit if not
  1095. ;
  1096. ;    Another MCB follows, append nextmcb to save block.
  1097. ;
  1098.     cmp    di,ems_parasize
  1099.     jb    swems_nonewpage        ; no new block needed
  1100.     mov    ax,4400h        ; map page, phys = 0
  1101.     int    EMM_INT
  1102.     or    ah,ah
  1103.     jnz    swems_error1
  1104.     mov    di,0
  1105.     inc    bx
  1106. ;
  1107. swems_nonewpage:
  1108.     push    di
  1109.     mov    cl,4
  1110.     shl    di,cl            ; convert to byte address
  1111.     mov    cx,TYPE mcbdesc
  1112.     mov    si,offset nextmcb
  1113.     rep movsb
  1114.     pop    di
  1115.     inc    di            ; one paragraph
  1116. ;
  1117. swems_complete:
  1118.     mov    ems_curpage,bx
  1119.     mov    ems_curoff,di
  1120.     xor    ax,ax
  1121.     ret
  1122. ;
  1123. swems_error:
  1124.     pop    ds
  1125. swems_error1:
  1126.     mov    ah,45h            ; release EMS pages on error
  1127.     int    EMM_INT
  1128.     mov    ax,RC_SWAPERROR
  1129.     or    ax,ax
  1130.     ret
  1131. ;
  1132. swapout_ems    endp
  1133. ;
  1134. ;
  1135. ;    swapout_xms:    swap out an MCB block to XMS.
  1136. ;
  1137. ;    Entry:    "currdesc"     contains description of block to swap
  1138. ;        "nextmcb"    contains MCB-descriptor of next block
  1139. ;                if currdesc.num_follow is nonzero
  1140. ;
  1141. ;    Exit:    0 if OK, -1 if error, Zero-flag set accordingly.
  1142. ;
  1143. ;    Uses:    All regs excpt DS
  1144. ;
  1145. swapout_xms    proc    near
  1146. ;
  1147.     push    ds
  1148.     pop    es
  1149.     mov    ax,currdesc.swsize    ; size in paragraphs
  1150.     mov    cl,4
  1151.     rol    ax,cl            ; size in bytes + high nibble
  1152.     mov    dx,ax
  1153.     and    ax,0fff0h        ; low word
  1154.     and    dx,0000fh        ; high word
  1155.     mov    xmsctl.lenlo,ax        ; into control block
  1156.     mov    xmsctl.lenhi,dx
  1157.     mov    xmsctl.srchnd,0        ; source is normal memory
  1158.     mov    ax,currdesc.swoffset    ; swap offset
  1159.     mov    xmsctl.srclo,ax        ; into control block
  1160.     mov    ax,currdesc.addr    ; segment to swap
  1161.     mov    xmsctl.srchi,ax
  1162.     mov    ax,swap_prep.handle    ; XMS handle
  1163.     mov    xmsctl.desthnd,ax
  1164.     mov    si,offset xmsctl
  1165.     mov    ah,0bh
  1166.     call    swap_prep.xmm        ; move it
  1167.     or    ax,ax
  1168.     jz    swxms_error
  1169.     mov    ax,xmsctl.lenlo        ; adjust destination addr
  1170.     add    xmsctl.destlo,ax
  1171.     mov    ax,xmsctl.lenhi
  1172.     adc    xmsctl.desthi,ax
  1173. ;
  1174.     cmp    currdesc.num_follow,0    ; another MCB?
  1175.     je    swxms_complete
  1176. ;
  1177.     mov    xmsctl.lenlo,TYPE mcbdesc
  1178.     mov    xmsctl.lenhi,0
  1179.     mov    xmsctl.srchi,ds
  1180.     mov    xmsctl.srclo,offset nextmcb
  1181.     mov    si,offset xmsctl
  1182.     mov    ah,0bh
  1183.     call    swap_prep.xmm        ; move it
  1184.     or    ax,ax
  1185.     jz    swxms_error
  1186.     add    xmsctl.destlo,16    ; one paragraph
  1187.     adc    xmsctl.desthi,0
  1188. ;
  1189. swxms_complete:
  1190.     xor    ax,ax
  1191.     ret
  1192. ;
  1193. swxms_error:
  1194.     mov    ah,0ah            ; release XMS frame on error
  1195.     mov    dx,swap_prep.handle    ; XMS handle
  1196.     call    swap_prep.xmm
  1197.     mov    ax,RC_SWAPERROR
  1198.     or    ax,ax
  1199.     ret
  1200. ;
  1201. swapout_xms    endp
  1202. ;
  1203. ;
  1204. ;    swapout_file:    swap out an MCB block to file.
  1205. ;
  1206. ;    Entry:    "currdesc"     contains description of block to swap
  1207. ;        "nextmcb"    contains MCB-descriptor of next block
  1208. ;                if currdesc.num_follow is nonzero
  1209. ;
  1210. ;    Exit:    0 if OK, -1 if error, Zero-flag set accordingly.
  1211. ;
  1212. ;    Uses:    All regs excpt DS
  1213. ;
  1214. swapout_file    proc    near
  1215. ;
  1216.     push    ds
  1217.     mov    cx,currdesc.swsize    ; size in paragraphs
  1218.     mov    bx,swap_prep.handle    ; file handle
  1219.     mov    dx,currdesc.swoffset    ; swap offset
  1220.     mov    ds,currdesc.addr    ; segment to swap
  1221. ;
  1222. swfile_loop:
  1223.     mov    ax,cx
  1224.     cmp    ah,8h            ; above 32k?
  1225.     jbe    swfile_ok        ; go write if not
  1226.     mov    ax,800h            ; else write 32k
  1227. ;
  1228. swfile_ok:
  1229.     sub    cx,ax            ; remaining length
  1230.     push    cx            ; save it
  1231.     push    ax            ; and save paras to write
  1232.     mov    cl,4
  1233.     shl    ax,cl            ; convert to bytes
  1234.     mov    cx,ax
  1235.     mov    ah,40h            ; write
  1236.     int    21h
  1237.     jc    swfile_error
  1238.     cmp    ax,cx
  1239.     jne    swfile_error
  1240.     pop    cx            ; paras written
  1241.     mov    ax,ds
  1242.     add    ax,cx            ; bump up source segment
  1243.     mov    ds,ax
  1244.     pop    cx            ; remaining length
  1245.     or    cx,cx            ; anything left?
  1246.     jnz    swfile_loop        ; go loop if yes
  1247. ;
  1248.     pop    ds
  1249.     cmp    currdesc.num_follow,0    ; another MCB?
  1250.     je    swfile_complete        ; ready if not
  1251.     mov    cx,16            ; write one paragraph
  1252.     mov    dx,offset nextmcb
  1253.     mov    ah,40h
  1254.     int    21h
  1255.     jc    swfile_error1
  1256.     cmp    ax,cx
  1257.     jne    swfile_error1
  1258. ;
  1259. swfile_complete:
  1260.     xor    ax,ax
  1261.     ret
  1262. ;
  1263. swfile_error:
  1264.     pop    cx
  1265.     pop    cx
  1266.     pop    ds
  1267. swfile_error1:
  1268.     mov    ah,3eh            ; close file
  1269.     int    21h
  1270.     mov    dx,offset swap_prep.sp_swapfilename
  1271.     mov    ah,41h            ; delete file
  1272.     int    21h
  1273.     mov    ax,RC_SWAPERROR
  1274.     or    ax,ax
  1275.     ret
  1276. ;
  1277. swapout_file    endp
  1278. ;
  1279. ;--------------------------------------------------------------------------
  1280. ;
  1281.     IF    REDIRECT
  1282. ;
  1283. ;    @redirect: Redirect a file.
  1284. ;
  1285. ;    Entry:    DS:SI = Filename pointer
  1286. ;        AX zero if filename is NULL
  1287. ;        CX    = Handle to redirect
  1288. ;        ES:DI = Handle save pointer
  1289. ;
  1290. ;    Exit:    Carry set on error, then AL has DOS error code
  1291. ;        ES:DI updated
  1292. ;
  1293. ;    Uses:    AX,BX,DX,SI
  1294. ;
  1295. @redirect    proc    near
  1296.         local    doserr:WORD
  1297. ;
  1298.     or    ax,ax
  1299.     jz    no_redirect
  1300.     cmp    byte ptr [si],0
  1301.     jne    do_redirect
  1302. ;
  1303. no_redirect:
  1304.     mov    ax,-1
  1305.     stosw
  1306.     ret
  1307. ;
  1308. do_redirect:
  1309.     or    cx,cx
  1310.     jnz    redir_write
  1311.     mov    dx,si
  1312.     mov    ax,3d00h    ; open file, read only
  1313.     int    21h
  1314.     mov    doserr,ax
  1315.     jc    redir_failed
  1316. ;
  1317. redir_ok:
  1318.     mov    dx,ax
  1319.     mov    ah,45h        ; duplicate handle
  1320.     mov    bx,cx
  1321.     int    21h
  1322.     mov    doserr,ax
  1323.     jc    redir_failed_dup
  1324.     push    ax
  1325.     mov    bx,dx
  1326.     mov    ah,46h        ; force duplicate handle
  1327.     int    21h
  1328.     mov    doserr,ax
  1329.     pop    ax
  1330.     jc    redir_failed_force
  1331.     stosw
  1332.     mov    ah,3eh        ; close file
  1333.     int    21h
  1334.     clc
  1335.     ret
  1336. ;
  1337. redir_failed_force:
  1338.     mov    bx,ax
  1339.     mov    ah,3eh        ; close file
  1340.     int    21h
  1341. ;
  1342. redir_failed_dup:
  1343.     mov    bx,dx
  1344.     mov    ah,3eh        ; close file
  1345.     int    21h
  1346. ;
  1347. redir_failed:
  1348.     mov    ax,doserr
  1349.     stc
  1350.     ret
  1351. ;
  1352. redir_write:
  1353.     cmp    byte ptr [si],'>'
  1354.     jne    no_append
  1355.     inc    si
  1356.     mov    dx,si
  1357.     mov    ax,3d02h        ; open file, read/write
  1358.     int    21h
  1359.     jc    no_append
  1360.     mov    bx,ax
  1361.     push    cx
  1362.     mov    ax,4202h        ; move file, offset from EOF
  1363.     xor    cx,cx
  1364.     mov    dx,cx
  1365.     int    21h
  1366.     mov    doserr,ax
  1367.     pop    cx
  1368.     mov    ax,bx
  1369.     jnc    redir_ok
  1370.     mov    dx,ax
  1371.     jmp    redir_failed_dup
  1372. ;
  1373. no_append:
  1374.     mov    dx,si
  1375.     mov    ah,3ch
  1376.     push    cx
  1377.     xor    cx,cx
  1378.     int    21h
  1379.     mov    doserr,ax
  1380.     pop    cx
  1381.     jc    redir_failed
  1382.     jmp    redir_ok
  1383. ;
  1384. @redirect    endp
  1385. ;
  1386.     ENDIF
  1387. ;
  1388. ;--------------------------------------------------------------------------
  1389. ;
  1390. ;--------------------------------------------------------------------------
  1391. ;--------------------------------------------------------------------------
  1392. ;
  1393. ;
  1394. ;do_spawn    PROC    uses si di,swapping: word, execfname:ptr byte,params:ptr byte,envlen:word,envp:ptr byte,stdin:ptr byte, stdout:ptr byte, stderr:ptr byte
  1395.  
  1396. ;    execfname    DB    "C:\DOS\COMMAND.COM",81 DUP (0)
  1397. ;    params    DB    2,"/C",0dh,81 DUP (0)
  1398.     swapping    DW    ?
  1399.     datseg    DW    ?
  1400.     pspseg    DW    ?
  1401.     currmcb    DW    ?
  1402.  
  1403.     execfname    DB    "C:\COMMAND.COM",82 DUP (0)
  1404. ;    params    DB    "/C C:\DOS\MEM.EXE",129 DUP (0)
  1405.     params    DB    129 DUP (0)
  1406. PSP        DW    ?        ; real mode PSP
  1407. PSPEnvironPtr    DW    ?    ; real mode PSP Environment Pointer
  1408. PMPSP    DW    ?        ; protected mode PSP
  1409. DPMIFlag    DB    ?    ; nonzero if DPMI
  1410. ReturnValue    DW    0    ; return value from swap
  1411.  
  1412. do_spawn    PROC    FAR
  1413. ;    local    datseg:WORD,pspseg:WORD,currmcb:WORD
  1414. ;
  1415. ;
  1416.     mov    datseg,ds        ; save default DS
  1417. ;
  1418.  
  1419. ;
  1420.     mov    bx,PSP
  1421.     mov    pspseg,bx
  1422. ;
  1423. ;    Check if spawn is too low in memory
  1424. ;
  1425.     mov    ax,cs
  1426.     mov    dx,offset lowcode_begin
  1427.     mov    cl,4
  1428.     shr    dx,cl
  1429.     add    ax,dx            ; normalized start of this code
  1430.     mov    dx,keep_paras        ; the end of the modified area
  1431.     add    dx,bx            ; plus PSP = end paragraph
  1432.     cmp    ax,dx
  1433.     ja    doswap_ok    ; ok if start of code > end of low mem
  1434.     mov    ax,RC_TOOLOW
  1435.     ret
  1436. ;
  1437. doswap_ok:
  1438.     cmp    swapping,0
  1439.     jle    method_ok
  1440. ;
  1441. ;    check the swap method, to make sure prep_swap has been called
  1442. ;
  1443.     mov    al,swap_prep.swapmethod
  1444.     cmp    al,USE_EMS
  1445.     je    method_ok
  1446.     cmp    al,USE_XMS
  1447.     je    method_ok
  1448.     cmp    al,USE_FILE
  1449.     je    method_ok
  1450.     mov    ax,RC_BADPREP
  1451.     ret
  1452. ;
  1453. ;    Save the memory below the swap space.
  1454. ;    We must do this before swapping, so the saved memory is
  1455. ;    in the swapped out image.
  1456. ;    Anything else we'd want to save on the stack or anywhere
  1457. ;    else in "normal" memory also has to be saved here, any
  1458. ;    modifications done to memory after the swap will be lost.
  1459. ;
  1460. ;    Note that the memory save is done even when not swapping,
  1461. ;    because we use some of the variables in low core for
  1462. ;    simplicity.
  1463. ;
  1464. method_ok:
  1465.     mov    es,datseg
  1466.     mov    ds,pspseg        ; DS points to PSP
  1467.     mov    si,5ch
  1468.     mov    di,offset save_dat
  1469.     mov    cx,savespace / 2    ; NOTE: savespace is always even
  1470.     rep movsw
  1471. ;
  1472.     mov    ds,datseg
  1473. ;
  1474.     mov    ax,swapping
  1475.     cmp    ax,0
  1476.     jg    begin_swap
  1477. ;
  1478. ;    not swapping, prep_swap wasn't called. Init those variables in
  1479. ;      the 'swap_prep' block we need in any case.
  1480. ;
  1481.     mov    swap_prep.swapmethod,al
  1482.     je    no_reduce
  1483. ;
  1484.     mov    ax,pspseg
  1485.     dec    ax
  1486.     mov    swap_prep.psp_mcb,ax
  1487.     mov    swap_prep.first_mcb,ax
  1488.     inc    ax
  1489.     mov    es,ax
  1490.     mov    bx,es:psp_envptr
  1491.     mov    swap_prep.env_mcb,bx
  1492. ;    mov    swap_prep.noswap_mcb,0
  1493. ;    cmp    envlen,0
  1494. ;    jne    swp_can_swap_env
  1495.     mov    swap_prep.noswap_mcb,bx
  1496. ;
  1497. swp_can_swap_env:
  1498.     xor    bx,bx
  1499.     mov    es,bx
  1500.     mov    ah,52h            ; get list of lists
  1501.     int    21h
  1502.     mov    ax,es
  1503.     or    ax,bx
  1504.     jz    no_reduce
  1505.     mov    es,es:[bx-2]        ; first MCB
  1506.     cmp    es:id,4dh        ; normal ID?
  1507.     jne    no_reduce
  1508.     mov    swap_prep.first_mcb,es
  1509. ;
  1510. no_reduce:
  1511.     jmp    no_swap1
  1512. ;
  1513. ;    set up first block descriptor
  1514. ;
  1515. begin_swap:
  1516.     mov    ax,swap_prep.first_mcb
  1517.     mov    currmcb,ax
  1518.     mov    es,swap_prep.psp_mcb    ; let ES point to base MCB
  1519.     mov    ax,es:paras
  1520.     mov    currdesc.msize,ax
  1521.     sub    ax,keep_paras
  1522.     mov    currdesc.swsize,ax
  1523.     mov    currdesc.addr,es
  1524.     mov    currdesc.swoffset,swapbeg + 16
  1525. ;        NOTE: swapbeg is 1 para higher when seen from MCB
  1526.     mov    ax,swap_prep.total_mcbs
  1527.     mov    currdesc.num_follow,ax
  1528. ;
  1529. ;    init other vars
  1530. ;
  1531.     mov    xmsctl.destlo,0
  1532.     mov    xmsctl.desthi,0
  1533.     mov    ems_curpage,0
  1534.     mov    ems_curoff,ems_parasize
  1535. ;
  1536. ;    Do the swapping. Each MCB block (except the last) has an
  1537. ;    "mcbdesc" structure appended that gives location and size
  1538. ;    of the next MCB.
  1539. ;
  1540. swapout_main:
  1541.     cmp    currdesc.num_follow,0    ; next block?
  1542.     je    swapout_no_next        ; ok if not
  1543. ;
  1544. ;    There is another MCB block to be saved. So we don't have
  1545. ;    to do two calls to the save routine with complicated
  1546. ;    parameters, we set up the next MCB descriptor beforehand.
  1547. ;    Walk the MCB chain starting at the current MCB to find
  1548. ;    the next one belonging to this process.
  1549. ;
  1550.     mov    ax,currmcb
  1551.     mov    bx,pspseg
  1552.     mov    cx,swap_prep.psp_mcb
  1553.     mov    dx,swap_prep.noswap_mcb
  1554.     mov    si,swap_prep.noswap2_mcb
  1555. ;
  1556. swm_mcb_walk:
  1557.     mov    es,ax
  1558.     cmp    ax,cx
  1559.     jbe    swm_next_mcb
  1560.     cmp    ax,dx
  1561.     je    swm_next_mcb
  1562.     cmp    ax,si
  1563.     je    swm_next_mcb
  1564.     cmp    ax,swap_prep.noswap3_mcb
  1565.     je    swm_next_mcb
  1566. ;
  1567.     cmp    bx,es:owner        ; our process?
  1568.     je    swm_mcb_found        ; found it if yes
  1569. ;
  1570. swm_next_mcb:
  1571.     cmp    es:id,4dh        ; normal block?
  1572.     jne    swm_mcb_error        ; error if end of chain
  1573.     add    ax,es:paras        ; start + length
  1574.     inc    ax            ; next MCB
  1575.     jmp    swm_mcb_walk
  1576. ;
  1577. ;    MCB found, set up an mcbdesc in the "nextmcb" structure
  1578. ;
  1579. swm_mcb_found:
  1580.     mov    nextmcb.addr,es
  1581.     mov    ax,es:paras        ; get number of paragraphs
  1582.     mov    nextmcb.msize,ax    ; and save
  1583.     inc    ax
  1584.     mov    nextmcb.swsize,ax
  1585.     mov    bx,es
  1586.     add    bx,ax
  1587.     mov    currmcb,bx
  1588.     mov    nextmcb.swoffset,0
  1589.     mov    ax,currdesc.num_follow
  1590.     dec    ax
  1591.     mov    nextmcb.num_follow,ax
  1592. ;
  1593. swapout_no_next:
  1594.     cmp    swap_prep.swapmethod,USE_EMS
  1595.     je    swm_ems
  1596.     cmp    swap_prep.swapmethod,USE_XMS
  1597.     je    swm_xms
  1598.     call    swapout_file
  1599.     jmp    short swm_next
  1600. ;
  1601. swm_ems:
  1602.     call    swapout_ems
  1603.     jmp    short swm_next
  1604. ;
  1605. swm_xms:
  1606.     call    swapout_xms
  1607. ;
  1608. swm_next:
  1609.     jnz    swapout_error
  1610.     cmp    currdesc.num_follow,0
  1611.     je    swapout_complete
  1612. ;
  1613. ;    next MCB exists, copy the "nextmcb" descriptor into
  1614. ;    currdesc, and loop.
  1615. ;
  1616.     mov    es,datseg
  1617.     mov    si,offset nextmcb
  1618.     mov    di,offset currdesc
  1619.     mov    cx,TYPE mcbdesc
  1620.     rep movsb
  1621.     jmp    swapout_main
  1622. ;
  1623. ;
  1624. swm_mcb_error:
  1625.     mov    ax,RC_MCBERROR
  1626. ;
  1627. swapout_kill:
  1628.     cmp    swapping,0
  1629.     jl    swapout_error
  1630.     push    ax
  1631.     cmp    swap_prep.swapmethod,USE_FILE
  1632.     je    swm_mcberr_file
  1633.     cmp    swap_prep.swapmethod,USE_EMS
  1634.     je    swm_mcberr_ems
  1635. ;
  1636.     mov    ah,0ah            ; release XMS frame on error
  1637.     mov    dx,swap_prep.handle    ; XMS handle
  1638.     call    swap_prep.xmm
  1639.     pop    ax
  1640.     jmp    short swapout_error
  1641. ;
  1642. swm_mcberr_ems:
  1643.     mov    dx,swap_prep.handle    ; EMS handle
  1644.     mov    ah,45h            ; release EMS pages on error
  1645.     int    EMM_INT
  1646.     pop    ax
  1647.     jmp    short swapout_error
  1648. ;
  1649. swm_mcberr_file:
  1650.     mov    bx,swap_prep.handle
  1651.     cmp    bx,-1
  1652.     je    swm_noclose
  1653.     mov    ah,3eh            ; close file
  1654.     int    21h
  1655. swm_noclose:
  1656.     mov    dx,offset swap_prep.sp_swapfilename
  1657.     mov    ah,41h            ; delete file
  1658.     int    21h
  1659.     pop    ax
  1660. ;
  1661. swapout_error:
  1662.     ret
  1663. ;
  1664. ;
  1665. ;    Swapout complete. Close the handle (EMS/file only),
  1666. ;    then set up low memory.
  1667. ;
  1668. swapout_complete:
  1669.     cmp    swap_prep.swapmethod,USE_FILE
  1670.     jne    swoc_nofile
  1671. ;
  1672. ;    File swap: Close the swap file to make the handle available
  1673. ;
  1674.     mov    bx,swap_prep.handle
  1675.     mov    swap_prep.handle,-1
  1676.     mov    ah,3eh
  1677.     int    21h            ; close file
  1678.     mov    si,offset swapin_file
  1679.     jnc    swoc_ready
  1680.     mov    ax,RC_SWAPERROR
  1681.     jmp    swapout_kill
  1682. ;
  1683. swoc_nofile:
  1684.     cmp    swap_prep.swapmethod,USE_EMS
  1685.     jne    swoc_xms
  1686. ;
  1687. ;    EMS: Unmap page
  1688. ;
  1689.     mov    ax,4400h
  1690.     mov    bx,-1
  1691.     mov    dx,swap_prep.handle
  1692.     int    EMM_INT
  1693.     mov    si,offset swapin_ems
  1694.     jmp    short swoc_ready
  1695. ;
  1696. swoc_xms:
  1697.     mov    si,offset swapin_xms
  1698.     jmp    short swoc_ready
  1699. ;
  1700. no_swap1:
  1701.     mov    si,offset swapin_none
  1702. ;
  1703. ;    Copy the appropriate swap-in routine to low memory.
  1704. ;
  1705. swoc_ready:
  1706.     mov    es,pspseg
  1707.     mov    cx,swap_codelen / 4
  1708.     mov    di,codebeg + base_length
  1709.     push    ds
  1710.     mov    ax,cs
  1711.     mov    ds,ax
  1712.     rep movsd
  1713. ;
  1714. ;    And while we're at it, copy the MCB allocation routine (which
  1715. ;    also includes the initial MCB release and exec call) down.
  1716. ;
  1717.     mov    cx,base_length / 2
  1718.     mov    di,param_len
  1719.     mov    si,offset lowcode_begin
  1720.     rep movsw
  1721. ;
  1722.     pop    ds
  1723.     mov    bx,es
  1724.     dec    bx
  1725.     mov    es,bx        ; let ES point to base MCB
  1726. ;
  1727. ;    Again set up the base MCB descriptor, and copy it as well as
  1728. ;    the variables set up by prep_swap to low memory.
  1729. ;    This isn't too useful if we're not swapping, but it doesn't
  1730. ;    hurt, either. The only variable used when not swapping is
  1731. ;    lprep.swapmethod.
  1732. ;
  1733.     mov    ax,es:paras
  1734.     mov    currdesc.msize,ax
  1735.     sub    ax,keep_paras
  1736.     mov    currdesc.swsize,ax
  1737.     mov    currdesc.addr,es
  1738.     mov    currdesc.swoffset,swapbeg + 16
  1739.     mov    ax,swap_prep.total_mcbs
  1740.     mov    currdesc.num_follow,ax
  1741. ;
  1742.     mov    es,pspseg        ; ES points to PSP again
  1743. ;
  1744.     mov    cx,TYPE prep_block
  1745.     mov    si,offset swap_prep
  1746.     mov    di,lprep
  1747.     rep movsb
  1748.     mov    cx,TYPE mcbdesc
  1749.     mov    si,offset currdesc
  1750.     mov    di,lcurrdesc
  1751.     rep movsb
  1752. ;
  1753. ;    now set up other variables in low core
  1754. ;
  1755.     mov    ds,pspseg
  1756.     mov    ds:cgetmcb,getmcboff + codebeg
  1757.     mov    ds:eretcode,0
  1758.     mov    ds:retflags,0
  1759. ;
  1760. ;
  1761. ;    If 'NO_INHERIT' is nonzero, save the entries of the
  1762. ;    handle table, and set the last 15 to 0ffh (unused).
  1763. ;
  1764.     mov    si,psp_handletab
  1765.     mov    di,lhandlesave
  1766.     mov    cx,10
  1767.     rep movsw
  1768.     mov    si,psp_handlenum    ; Length of handle table
  1769.     mov    ax,[si]
  1770.     stosw
  1771.     mov    word ptr [si],20    ; set to default to be safe
  1772.     add    si,2
  1773.     lodsw                ; Handle table pointer
  1774.     mov    bx,ax
  1775.     stosw
  1776.     lodsw
  1777.     stosw
  1778.     cmp    ax,pspseg
  1779.     jne    copy_handles
  1780.     cmp    bx,psp_handletab
  1781.     je    no_handlecopy
  1782. ;
  1783. ;    if the handle table pointer in the PSP does not point to
  1784. ;    the default PSP location, copy the first five entries from
  1785. ;    this table into the PSP - but only if we have DOS >= 3.3.
  1786. ;
  1787. copy_handles:
  1788.     mov    ds,ax
  1789.     mov    si,bx
  1790.     mov    di,psp_handletab
  1791.     mov    es:psp_handleptro,di
  1792.     mov    es:psp_handleptrs,es
  1793.     movsw
  1794.     movsw
  1795.     movsb
  1796. ;
  1797. no_handlecopy:
  1798.     mov    di,psp_handletab+5
  1799.     mov    ax,0ffffh
  1800.     stosb
  1801.     mov    cx,7
  1802.     rep stosw
  1803. ;
  1804. ;
  1805. ;    Handle Redirection
  1806. ;
  1807.     IF    REDIRECT
  1808.     mov    es,pspseg
  1809.     mov    di,lstdinsav
  1810.     mov    ax,-1
  1811.     stosw
  1812.     stosw
  1813.     stosw
  1814.     mov    di,lstdinsav
  1815.     xor    cx,cx
  1816.     IF    ptrsize
  1817.     lds    si,stdin
  1818.     mov    ax,ds
  1819.     or    ax,si
  1820.     ELSE
  1821.     mov    si,stdin
  1822.     mov    ds,datseg
  1823.     or    si,si
  1824.     ENDIF
  1825.     call    @redirect
  1826.     jc    failed_redir
  1827.     inc    cx
  1828.     IF    ptrsize
  1829.     lds    si,stdout
  1830.     mov    ax,ds
  1831.     or    ax,si
  1832.     ELSE
  1833.     mov    si,stdout
  1834.     or    si,si
  1835.     ENDIF
  1836.     call    @redirect
  1837.     jc    failed_redir
  1838.     inc    cx
  1839.     IF    ptrsize
  1840.     lds    si,stderr
  1841.     mov    ax,ds
  1842.     or    ax,si
  1843.     ELSE
  1844.     mov    si,stderr
  1845.     or    si,si
  1846.     ENDIF
  1847.     call    @redirect
  1848.     jnc    redir_complete
  1849. ;
  1850. failed_redir:
  1851.     push    ax
  1852. ;
  1853. ;    restore handle table and pointer
  1854. ;
  1855.     mov    ds,pspseg
  1856.     mov    si,lstdinsav
  1857.     xor    cx,cx
  1858. ;
  1859. redirclose:
  1860.     lodsw
  1861.     cmp    ax,-1
  1862.     je    redclosenext
  1863.     mov    bx,ax
  1864.     mov    ah,46h
  1865.     int    21h
  1866. ;
  1867. redclosenext:
  1868.     inc    cx
  1869.     cmp    cx,3
  1870.     jb    redirclose
  1871. ;
  1872.     mov    ds,pspseg
  1873.     mov    es,pspseg
  1874.     mov    si,lhandlesave
  1875.     mov    di,psp_handletab
  1876.     mov    cx,10
  1877.     rep movsw
  1878.     mov    di,psp_handlenum
  1879.     movsw
  1880.     movsw
  1881.     movsw
  1882. ;
  1883. ;    Restore overwritten part of program
  1884. ;
  1885.     mov    ds,datseg
  1886.     mov    es,pspseg
  1887.     mov    si,offset save_dat
  1888.     mov    di,5ch
  1889.     mov    cx,savespace
  1890.     rep movsb
  1891. ;
  1892.     pop    ax
  1893.     mov    ah,RC_REDIRFAIL SHR 8
  1894.     jmp    swapout_kill
  1895. ;
  1896. redir_complete:
  1897.     mov    ds,pspseg
  1898.     mov    es,pspseg
  1899.     mov    si,psp_handletab+5
  1900.     mov    di,lredirsav
  1901.     mov    cx,3
  1902.     rep movsw
  1903.     mov    di,psp_handletab+5
  1904.     mov    cx,3
  1905.     mov    ax,0ffffh
  1906.     rep stosw
  1907.     ENDIF
  1908. ;
  1909. ;    Prepare exec parameter block
  1910. ;
  1911.     mov    ax,es
  1912.     mov    es:expar.fcb1seg,ax
  1913.     mov    es:expar.fcb2seg,ax
  1914.     mov    es:expar.pparseg,ax
  1915.     mov    es:expar.envseg,0
  1916. ;
  1917. ;    The 'zero' word is located at 80h in the PSP, the start of
  1918. ;    the command line. So as not to confuse MCB walking programs,
  1919. ;    a command line length of zero is inserted here.
  1920. ;
  1921.     mov    es:zero,0d00h        ; 00h,0dh = empty command line
  1922. ;
  1923. ;    Init default fcb's by parsing parameter string
  1924. ;
  1925. ;    IF    ptrsize
  1926. ;    lds    si,params
  1927. ;    ELSE
  1928.     mov    si,OFFSET params
  1929.     mov    ds,datseg
  1930. ;    ENDIF
  1931.     push    si
  1932.     mov    di,xfcb1
  1933.     mov    es:expar.fcb1,di
  1934.     push    di
  1935.     mov    cx,16
  1936.     xor    ax,ax
  1937.     rep stosw            ; init both fcb's to 0
  1938.     pop    di
  1939.     mov    ax,2901h
  1940.     int    21h
  1941.     mov    di,xfcb2
  1942.     mov    es:expar.fcb2,di
  1943.     mov    ax,2901h
  1944.     int    21h
  1945.     pop    si
  1946. ;
  1947. ;    move command tail string into low core
  1948. ;
  1949.     mov    di,progpars
  1950.     mov    es:expar.ppar,di
  1951.     xor    cx,cx
  1952.     inc    di
  1953. cmdcpy:
  1954.     lodsb
  1955.     or    al,al
  1956.     jz    cmdcpy_end
  1957.     stosb
  1958.     inc    cx
  1959.     jmp    cmdcpy
  1960. ;
  1961. cmdcpy_end:
  1962.     mov    al,0dh
  1963.     stosb
  1964.     mov    es:progpars,cl
  1965. ;
  1966. ;    move filename string into low core
  1967. ;
  1968. ;    IF    ptrsize
  1969. ;    lds    si,execfname
  1970. ;    ELSE
  1971.     mov    si,OFFSET execfname
  1972. ;    ENDIF
  1973.     mov    di,filename
  1974. fncpy:
  1975.     lodsb
  1976.     stosb
  1977.     or    al,al
  1978.     jnz    fncpy
  1979. ;
  1980. ;    Setup environment copy
  1981. ;
  1982.     mov    bx,keep_paras        ; paras to keep
  1983.  
  1984. ;    xor    bx,bx
  1985.  
  1986. COMMENT !
  1987.     mov    cx,envlen        ; environment size
  1988.     jcxz    no_environ        ; go jump if no environment
  1989.  
  1990.     cmp    swapping,0
  1991.     jne    do_envcopy
  1992. ;
  1993. ;    Not swapping, use the environment pointer directly.
  1994. ;    Note that the environment copy must be paragraph aligned.
  1995. ;
  1996.     IF    ptrsize
  1997.     mov    ax,word ptr (envp)+2
  1998.     mov    bx,word ptr (envp)
  1999.     ELSE
  2000.     mov    ax,ds
  2001.     mov    bx,envp
  2002.     ENDIF
  2003.     add    bx,15            ; make sure it's paragraph aligned
  2004.     mov    cl,4
  2005.     shr    bx,cl            ; and convert to segment addr
  2006.     add    ax,bx
  2007.     mov    es:expar.envseg,ax    ; new environment segment
  2008.     xor    cx,cx            ; mark no copy
  2009.     xor    bx,bx            ; and no shrink
  2010.     jmp    short no_environ
  2011. ;
  2012. ;    Swapping or EXECing without return. Set up the pointers for
  2013. ;    an environment copy (we can't do the copy yet, it might overwrite
  2014. ;    this code).
  2015. ;
  2016. do_envcopy:
  2017.     inc    cx
  2018.     shr    cx,1            ; words to copy
  2019.     mov    ax,cx            ; convert envsize to paras
  2020.     add    ax,7
  2021.     shr    ax,1
  2022.     shr    ax,1
  2023.     shr    ax,1
  2024.     add    bx,ax            ; add envsize to paras to keep
  2025.     IF    ptrsize
  2026.     lds    si,envp
  2027.     ELSE
  2028.     mov    si,envp
  2029.     ENDIF
  2030. ;
  2031.     mov    ax,es            ; low core segment
  2032.     add    ax,keep_paras        ; plus fixed paras
  2033.     mov    es:expar.envseg,ax    ; = new environment segment
  2034. END COMMENT !
  2035. ;
  2036. ;    Save stack regs, switch to local stack
  2037. ;
  2038. no_environ:
  2039.     mov    es:save_ss,ss
  2040.     mov    es:save_sp,sp
  2041.     mov    ax,es
  2042.     cli
  2043.     mov    ss,ax
  2044.     mov    sp,mystack
  2045.     sti
  2046. ;
  2047. ;    push    cx            ; save env length
  2048. ;    push    si            ; save env pointer
  2049.     push    ds            ; save env segment
  2050. ;
  2051. ;    save and patch INT0 (division by zero) vector
  2052. ;
  2053.     xor    ax,ax
  2054.     mov    ds,ax
  2055.     mov    ax,word ptr ds:0
  2056.     mov    es:div0_off,ax
  2057.     mov    ax,word ptr ds:2
  2058.     mov    es:div0_seg,ax
  2059.     mov    word ptr ds:0,codebeg + iretoff
  2060.     mov    word ptr ds:2,es
  2061. ;
  2062.     pop    ds            ; pop environment segment
  2063. ;    pop    si            ; pop environment offset
  2064. ;    pop    cx            ; pop environment length
  2065.     mov    di,swapbeg        ; environment destination
  2066. ;
  2067. ;    Push return address on local stack
  2068. ;
  2069.     push    cs            ; push return segment
  2070.     mov    ax,offset exec_cont
  2071.     push    ax            ; push return offset
  2072.     mov    es:spx,sp        ; save stack pointer
  2073. ;
  2074. ;    Goto low core code
  2075. ;
  2076.     push    es            ; push entry segment
  2077.     mov    ax,codebeg + doexec_entry
  2078.     push    ax            ; push entry offset
  2079.     retf
  2080. ;
  2081. ;----------------------------------------------------------------
  2082. ;
  2083. ;    Low core code will return to this location, with DS set to
  2084. ;    the PSP segment.
  2085. ;
  2086. exec_cont:
  2087.     push    ds
  2088.     pop    es
  2089.     cli
  2090.     mov    ss,ds:save_ss        ; reload stack
  2091.     mov    sp,ds:save_sp
  2092.     sti
  2093. ;
  2094. ;    restore handle table and pointer
  2095. ;
  2096.     mov    si,lhandlesave
  2097.     mov    di,psp_handletab
  2098.     mov    cx,10
  2099.     rep movsw
  2100.     mov    di,psp_handlenum
  2101.     movsw
  2102.     movsw
  2103.     movsw
  2104. ;
  2105. ;    restore INT0 (division by zero) vector
  2106. ;
  2107.     xor    cx,cx
  2108.     mov    ds,cx
  2109.     mov    cx,es:div0_off
  2110.     mov    word ptr ds:0,cx
  2111.     mov    cx,es:div0_seg
  2112.     mov    word ptr ds:2,cx
  2113. ;
  2114.     mov    ds,datseg
  2115. ;
  2116. ;
  2117.     mov    ax,es:eretcode
  2118.     mov    bx,es:retflags
  2119. ;
  2120. ;    Restore overwritten part of program
  2121. ;
  2122.     mov    si,offset save_dat
  2123.     mov    di,5ch
  2124.     mov    cx,savespace
  2125.     rep movsb
  2126. ;
  2127.  
  2128. ;    int    3
  2129.  
  2130.     test    bx,1            ; carry set?
  2131.     jnz    exec_fault        ; return EXEC error code if fault
  2132.     mov    ah,4dh            ; else get program return code
  2133.     int    21h
  2134.     xor    ah,ah            ; zap high value
  2135.     ret
  2136. ;
  2137. exec_fault:
  2138.     mov    ax,SWAPPERERROR
  2139. ;    mov    ah,3            ; return error as 03xx
  2140.     ret
  2141. ;
  2142. do_spawn    ENDP
  2143. ;
  2144. ;----------------------------------------------------------------------------
  2145. ;----------------------------------------------------------------------------
  2146. ;
  2147. emm_name    db    'EMMXXXX0'
  2148. ;
  2149. ;    prep_swap - prepare for swapping.
  2150. ;
  2151. ;    This routine checks all parameters necessary for swapping,
  2152. ;    and attempts to set up the swap-out area in EMS/XMS, or on file.
  2153. ;    In detail:
  2154. ;
  2155. ;         1) Check whether the do_spawn routine is located
  2156. ;        too low in memory, so it would get overwritten.
  2157. ;        If this is true, return an error code (-2).
  2158. ;
  2159. ;         2) Walk the memory control block chain, adding up the
  2160. ;        paragraphs in all blocks assigned to this process.
  2161. ;
  2162. ;         3) Check EMS (if the method parameter allows EMS):
  2163. ;        - is an EMS driver installed?
  2164. ;        - are sufficient EMS pages available?
  2165. ;        if all goes well, the EMS pages are allocated, and the
  2166. ;        routine returns success (1).
  2167. ;
  2168. ;         4) Check XMS (if the method parameter allows XMS):
  2169. ;        - is an XMS driver installed?
  2170. ;        - is a sufficient XMS block available?
  2171. ;        if all goes well, the XMS block is allocated, and the
  2172. ;        routine returns success (2).
  2173. ;
  2174. ;         5) Check file swap (if the method parameter allows it):
  2175. ;        - try to create the file
  2176. ;        - pre-allocate the file space needed by seeking to the end
  2177. ;          and writing a byte.
  2178. ;        If the file can be written, the routine returns success (4).
  2179. ;
  2180. ;         6) Return an error code (-1).
  2181. ;
  2182.         pmethod    DW    ?
  2183.  
  2184. ;prep_swap    PROC    uses si di,pmethod:word,swapfname:ptr byte
  2185. prep_swap    PROC    FAR
  2186.  
  2187.     LOCAL    totparas: word
  2188. ;
  2189. ;
  2190.     mov    ax,fs        ; ax -> wedge segment
  2191.     dec    ax
  2192.     cmp    DPMIFlag,0    ; see if using DPMI
  2193.     jne    isdpmi
  2194.     dec    ax            ; CauseWay uses 1 para for its own purposes, compute MCB
  2195.  
  2196. isdpmi:
  2197.     mov    swap_prep.noswap2_mcb,ax    ; don't swap out wedge segment
  2198.  
  2199.     mov    ax,PSP
  2200.     mov    es,ax        ; es -> PSP
  2201.     mov    ax,es:[36h]    ; es -> file handle table segment
  2202.     dec    ax
  2203.     cmp    DPMIFlag,0    ; see if using DPMI
  2204.     jne    isdpmi2
  2205.     dec    ax            ; CauseWay uses 1 para for its own purposes, compute MCB
  2206.  
  2207. isdpmi2:
  2208.     mov    swap_prep.noswap3_mcb,ax    ; don't swap out file handle table segment
  2209.  
  2210.     mov    ax,PSP
  2211.     dec    ax
  2212.     mov    swap_prep.psp_mcb,ax
  2213.     mov    swap_prep.first_mcb,ax    ; init first MCB to PSP
  2214. ;
  2215. ;    Make a copy of the environment pointer in the PSP
  2216. ;
  2217.     inc    ax
  2218.     mov    es,ax
  2219.     mov    bx,es:psp_envptr
  2220.     dec    bx
  2221.     mov    swap_prep.env_mcb,bx
  2222. ;    mov    swap_prep.noswap_mcb,0
  2223. ;    test    pmethod,DONT_SWAP_ENV
  2224. ;    jz    can_swap_env
  2225.     mov    swap_prep.noswap_mcb,bx
  2226. ;
  2227. can_swap_env:
  2228. ;
  2229. ;    Check if spawn is too low in memory
  2230. ;
  2231.     mov    bx,cs
  2232.     mov    dx,offset lowcode_begin
  2233.     mov    cl,4
  2234.     shr    dx,cl
  2235.     add    bx,dx            ; normalized start of this code
  2236.     mov    dx,keep_paras        ; the end of the modified area
  2237.     add    dx,ax            ; plus PSP = end paragraph
  2238.     cmp    bx,dx
  2239.     ja    prepswap_ok    ; ok if start of code > end of low mem
  2240.     mov    ax,-2
  2241.     mov    swap_prep.swapmethod,al
  2242.     ret
  2243. ;
  2244. ;    Walk the chain of memory blocks, adding up the paragraphs
  2245. ;    in all blocks belonging to this process.
  2246. ;    We try to find the first MCB by getting DOS's "list of lists",
  2247. ;    and fetching the word at offset -2 of the returned address.
  2248. ;    If this fails, we use our PSP as the starting point.
  2249. ;
  2250. prepswap_ok:
  2251.     xor    bx,bx
  2252.     mov    es,bx
  2253.     mov    ah,52h            ; get list of lists
  2254.     int    21h
  2255.     mov    ax,es
  2256.     or    ax,bx
  2257.     jz    prep_no_first
  2258.     mov    es,es:[bx-2]        ; first MCB
  2259.     cmp    es:id,4dh        ; normal ID?
  2260.     jne    prep_no_first
  2261.     mov    swap_prep.first_mcb,es
  2262. ;
  2263. prep_no_first:
  2264.     mov    es,swap_prep.psp_mcb    ; ES points to base MCB
  2265.     mov    cx,es            ; save this value
  2266.     mov    bx,es:owner        ; the current process
  2267.     mov    dx,es:paras        ; memory size in the base block
  2268.     sub    dx,keep_paras        ; minus resident paragraphs
  2269.     mov    si,0            ; number of MCBs except base
  2270.     mov    di,swap_prep.noswap_mcb
  2271.     mov    bp,swap_prep.noswap2_mcb
  2272.     mov    ax,swap_prep.first_mcb
  2273.     mov    swap_prep.first_mcb,0
  2274. ;
  2275. prep_mcb_walk:
  2276.     mov    es,ax
  2277.     cmp    ax,cx            ; base block?
  2278.     jbe    prep_walk_next        ; then don't count again
  2279.     cmp    ax,di            ; Non-swap MCB?
  2280.     je    prep_walk_next        ; then don't count
  2281.     cmp    ax,bp            ; Non-swap MCB?
  2282.     je    prep_walk_next        ; then don't count
  2283.     cmp    ax,swap_prep.noswap3_mcb    ; non-swap MCB
  2284.     je    prep_walk_next        ; then don't count
  2285.  
  2286. ;
  2287.     cmp    bx,es:owner        ; our process?
  2288.     jne    prep_walk_next        ; next if not
  2289.     inc    si
  2290.     mov    ax,es:paras        ; else get number of paragraphs
  2291.     add    ax,2            ; + 1 for descriptor + 1 for MCB
  2292.     add    dx,ax            ; total number of paras
  2293.     cmp    swap_prep.first_mcb,0
  2294.     jne    prep_walk_next
  2295.     mov    swap_prep.first_mcb,es
  2296. ;
  2297. prep_walk_next:
  2298.     cmp    es:id,4dh        ; normal block?
  2299.     jne    prep_mcb_ready        ; ready if end of chain
  2300.     mov    ax,es
  2301.     add    ax,es:paras        ; start + length
  2302.     inc    ax            ; next MCB
  2303.     jmp    prep_mcb_walk
  2304. ;
  2305. prep_mcb_ready:
  2306.     mov    totparas,dx
  2307.     mov    swap_prep.total_mcbs,si
  2308. ;
  2309. ;
  2310.     test    pmethod,XMS_FIRST
  2311.     jnz    check_xms
  2312. ;
  2313. ;    Check for EMS swap
  2314. ;
  2315. check_ems:
  2316.     test    pmethod,USE_EMS
  2317.     jz    prep_no_ems
  2318. ;
  2319.     push    ds
  2320.     mov    al,EMM_INT
  2321.     mov    ah,35h
  2322.     int    21h            ; get EMM int vector
  2323.     mov    ax,cs
  2324.     mov    ds,ax
  2325.     mov    si,offset emm_name
  2326.     mov    di,10
  2327.     mov    cx,8
  2328.     repz cmpsb            ; EMM name present?
  2329.     pop    ds
  2330.     jnz    prep_no_ems
  2331. ;
  2332.     mov    ah,40h            ; get EMS status
  2333.     int    EMM_INT
  2334.     or    ah,ah            ; EMS ok?
  2335.     jnz    prep_no_ems
  2336. ;
  2337.     mov    ah,46h            ; get EMS version
  2338.     int    EMM_INT
  2339.     or    ah,ah            ; AH must be 0
  2340.     jnz    prep_no_ems
  2341. ;
  2342.     cmp    al,30h            ; >= version 3.0?
  2343.     jb    prep_no_ems
  2344. ;
  2345.     mov    ah,41h            ; Get page frame address
  2346.     int    EMM_INT
  2347.     or    ah,ah
  2348.     jnz    prep_no_ems
  2349. ;
  2350. ;    EMS present, try to allocate pages
  2351. ;
  2352.     mov    swap_prep.ems_pageframe,bx
  2353.     mov    bx,totparas
  2354.     add    bx,ems_paramask
  2355.     mov    cl,ems_shift
  2356.     shr    bx,cl
  2357.     mov    ah,43h            ; allocate handle and pages
  2358.     int    EMM_INT
  2359.     or    ah,ah            ; success?
  2360.     jnz    prep_no_ems
  2361. ;
  2362. ;    EMS pages allocated, swap to EMS
  2363. ;
  2364.     mov    swap_prep.handle,dx
  2365.     mov    ax,USE_EMS
  2366.     mov    swap_prep.swapmethod,al
  2367.     ret
  2368. ;
  2369. ;    No EMS allowed, or EMS not present/full. Try XMS.
  2370. ;
  2371. prep_no_ems:
  2372.     test    pmethod,XMS_FIRST
  2373.     jnz    check_file        ; don't try again
  2374. ;
  2375. check_xms:
  2376.     test    pmethod,USE_XMS
  2377.     jz    prep_no_xms
  2378. ;
  2379.     mov    ax,4300h        ; check if XMM driver present
  2380.     int    2fh
  2381.     cmp    al,80h            ; is XMM installed?
  2382.     jne    prep_no_xms
  2383.     mov    ax,4310h        ; get XMM entrypoint
  2384.     int    2fh
  2385.     mov    word ptr swap_prep.xmm,bx    ; save entry address
  2386.     mov    word ptr swap_prep.xmm+2,es
  2387. ;
  2388.     mov    dx,totparas
  2389.     add    dx,xms_paramask        ; round to nearest multiple of 1k
  2390.     mov    cl,xms_shift
  2391.     shr    dx,cl            ; convert to k
  2392.     mov    ah,9            ; allocate extended memory block
  2393.     call    swap_prep.xmm
  2394.     or    ax,ax
  2395.     jz    prep_no_xms
  2396. ;
  2397. ;    XMS block allocated, swap to XMS
  2398. ;
  2399.     mov    swap_prep.handle,dx
  2400.     mov    ax,USE_XMS
  2401.     mov    swap_prep.swapmethod,al
  2402.     ret
  2403. ;
  2404. ;    No XMS allowed, or XMS not present/full. Try File swap.
  2405. ;
  2406. prep_no_xms:
  2407.     test    pmethod,XMS_FIRST
  2408.     jz    check_file
  2409.     jmp    check_ems
  2410. ;
  2411. check_file:
  2412.     test    pmethod,USE_FILE
  2413.     jnz    prep_do_file
  2414.     jmp    prep_no_file
  2415. ;
  2416. prep_do_file:
  2417.     push    ds
  2418. ;    IF    ptrsize
  2419. ;    lds    dx,swapfname
  2420. ;    ELSE
  2421.     mov    dx,OFFSET SwapFileName
  2422. ;    ENDIF
  2423.     mov    cx,2            ; hidden attribute
  2424.     test    pmethod,HIDE_FILE
  2425.     jnz    prep_hide
  2426.     xor    cx,cx            ; normal attribute
  2427. ;
  2428. prep_hide:
  2429.     mov    ah,3ch            ; create file
  2430.     test    pmethod,CREAT_TEMP
  2431.     jz    prep_no_temp
  2432.     mov    ah,5ah
  2433. ;
  2434. prep_no_temp:
  2435.     int    21h            ; create/create temp
  2436.     jnc    prep_got_file
  2437.     cmp    ax,3        ; see if path not found (bad TEMP setting)
  2438.     jne    prep_no_file
  2439.     mov    ah,19h        ; get current disk
  2440.     int    21h
  2441.     add    al,'A'        ; convert to ASCII drive
  2442.     mov    bx,dx
  2443.     mov    BYTE PTR ds:[bx],al    ; default to current drive root
  2444.     mov    BYTE PTR ds:[bx+1],':'
  2445.     mov    BYTE PTR ds:[bx+2],'\'
  2446.     mov    BYTE PTR ds:[bx+3],0    ; zero out path name and retry
  2447. ;    mov    BYTE PTR ds:[bx],0    ; zero out path name and retry
  2448.     jmp    SHORT prep_hide
  2449. ;
  2450. prep_got_file:
  2451.     mov    bx,ax            ; handle
  2452. ;
  2453. ;    save the file name
  2454. ;
  2455.     pop    es
  2456.     push    es
  2457.     mov    di,offset swap_prep.sp_swapfilename
  2458.     mov    cx,81
  2459.     mov    si,dx
  2460.     rep movsb
  2461. ;
  2462.     pop    ds
  2463.     mov    swap_prep.handle,bx
  2464. ;
  2465. ;    preallocate the file
  2466. ;
  2467.     test    pmethod,NO_PREALLOC
  2468.     jnz    prep_noprealloc
  2469.     test    pmethod,CHECK_NET
  2470.     jz    prep_nonetcheck
  2471. ;
  2472. ;    check whether file is on a network drive, and don't preallocate
  2473. ;    if so. preallocation can slow down swapping significantly when
  2474. ;    running on certain networks (Novell)
  2475. ;
  2476.     mov    ax,440ah    ; check if handle is remote
  2477.     int    21h
  2478.     jc    prep_nonetcheck    ; assume not remote if function fails
  2479.     test    dh,80h        ; DX bit 15 set ?
  2480.     jnz    prep_noprealloc    ; remote if yes
  2481. ;
  2482. prep_nonetcheck:
  2483.     mov    dx,totparas
  2484.     mov    cl,4
  2485.     rol    dx,cl
  2486.     mov    cx,dx
  2487.     and    dx,0fff0h
  2488.     and    cx,0000fh
  2489.     sub    dx,1
  2490.     sbb    cx,0
  2491.     mov    si,dx            ; save
  2492.     mov    ax,4200h        ; move file pointer, absolute
  2493.     int    21h
  2494.     jc    prep_file_err
  2495.     cmp    dx,cx
  2496.     jne    prep_file_err
  2497.     cmp    ax,si
  2498.     jne    prep_file_err
  2499.     mov    cx,1            ; write 1 byte
  2500.     mov    ah,40h
  2501.     int    21h
  2502.     jc    prep_file_err
  2503.     cmp    ax,cx
  2504.     jne    prep_file_err
  2505. ;
  2506.     mov    ax,4200h        ; move file pointer, absolute
  2507.     xor    dx,dx
  2508.     xor    cx,cx            ; rewind to beginning
  2509.     int    21h
  2510.     jc    prep_file_err
  2511. ;
  2512. prep_noprealloc:
  2513.     mov    ax,USE_FILE
  2514.     mov    swap_prep.swapmethod,al
  2515.     ret
  2516. ;
  2517. prep_file_err:
  2518.     mov    ah,3eh            ; close file
  2519.     int    21h
  2520.     mov    dx,offset swap_prep.sp_swapfilename
  2521.     mov    ah,41h            ; delete file
  2522.     int    21h
  2523. ;
  2524. prep_no_file:
  2525.     mov    ax,-1
  2526.     mov    swap_prep.swapmethod,al
  2527.     ret
  2528. ;
  2529. prep_swap    endp
  2530. ;
  2531.  
  2532. COMMENT !
  2533. O_RUNX:
  2534.     pusha
  2535.     push    ds
  2536.     push    es
  2537.  
  2538.     mov    bx,SWAP_TEXT
  2539.     mov    ax,0ff06h
  2540.     int    31h
  2541.     jc    SwapErr
  2542.     push    ax        ; save -> swap routine data
  2543.     mov    es,ax
  2544.     mov    BYTE PTR es:[params],0    ; kill leftovers
  2545.  
  2546. ; get length of first passed parameter
  2547.     push    1
  2548.     call    __parclen
  2549.     add    sp,2
  2550.     or    ax,ax
  2551.     je    med3        ; zero length
  2552.  
  2553. ; get first parameter string in dx:ax
  2554.     push    1
  2555.     call    __parc
  2556.     add    sp,2
  2557.     pop    es
  2558.     push    es
  2559.     mov    di,OFFSET params    ; es:di -> parameter storage
  2560.     push    ds        ; save ds -> DGROUP
  2561.     mov    ds,dx
  2562.     mov    si,ax        ; ds:si -> character string
  2563.     mov    ax,'/'+256*'C'    ; put in /C for command.com, transient command
  2564.     stosw
  2565.     mov    al,' '
  2566.     stosb
  2567.  
  2568. xparamloop1:
  2569.     movsb
  2570.     cmp    BYTE PTR ds:[si-1],0    ; see if hit null terminator
  2571.     jne    xparamloop1
  2572.     pop    ds            ; restore ds -> DGROUP
  2573.  
  2574.     dec    di            ; make di -> null terminator in case of second parameter
  2575.  
  2576. ; get length of second passed parameter
  2577.     push    2
  2578.     call    __parclen
  2579.     add    sp,2
  2580.     or    ax,ax
  2581.     je    med3        ; zero length
  2582.  
  2583. ; get second parameter string in dx:ax
  2584.     push    2
  2585.     call    __parc
  2586.     add    sp,2
  2587.     mov    ds,dx
  2588.     mov    si,ax        ; ds:si -> character string
  2589.     pop    es
  2590.     push    es        ; es:di -> current position of stored string
  2591.     mov    al,' '
  2592.     stosb            ; put in space
  2593.  
  2594. xparamloop2:
  2595.     movsb
  2596.     cmp    BYTE PTR ds:[si-1],0    ; see if stored null terminator
  2597.     jne    xparamloop2
  2598.     jmp    SHORT med3
  2599. END COMMENT !
  2600.  
  2601. ;SWPRUNCMD:
  2602. ;OverLay:
  2603. CWSwap:
  2604.  
  2605.  
  2606.     pushad
  2607.     push    ds
  2608.     push    es
  2609.     cld
  2610.  
  2611.  
  2612. ;**JW**
  2613. ;works upto here...
  2614. ;    pop    es
  2615. ;    pop    ds
  2616. ;    popa
  2617. ;    db 66h
  2618. ;    retf
  2619.  
  2620. ; get command pointer on stack
  2621.     mov    eax,ss:[esp+44]    ; 32 for pushad, 4 for push ds,es, 8 for return address
  2622.  
  2623.     push    eax        ; save -> command
  2624.     mov    bx,SWAP_TEXT
  2625.     mov    ax,0ff06h
  2626.     int    31h
  2627. ;    jc    SwapErr
  2628.     push    ax        ; save -> swap routine data
  2629.     mov    es,ax
  2630.     mov    BYTE PTR es:[params],0    ; kill leftovers
  2631.  
  2632. ; get length of passed parameter
  2633. ;    push    1
  2634. ;    call    __parclen
  2635. ;    add    sp,2
  2636. ;    or    ax,ax
  2637. ;    je    med3        ; zero length
  2638.  
  2639. ; get parameter string in dx:ax
  2640. ;    push    1
  2641. ;    call    __parc
  2642. ;    add    sp,2
  2643. ;    mov    ds,dx
  2644. ;    mov    si,ax        ; ds:si -> character string
  2645.  
  2646.     pop    es
  2647.     pop    esi            ; ds:esi -> command
  2648.     push    es
  2649.  
  2650.     mov    di,OFFSET params    ; es:di -> parameter storage
  2651.     mov    al,'/'
  2652.     mov    ax,'/'+256*'C'    ; put in /C for command.com, transient command
  2653.     stosw
  2654.     mov    al,' '
  2655.     stosb
  2656.  
  2657. paramloop:
  2658.     mov    al,ds:[esi]
  2659.     mov    es:[di],al
  2660.     inc    esi
  2661.     inc    di
  2662.     cmp    BYTE PTR ds:[esi-1],0    ; see if stored null terminator
  2663.     jne    paramloop
  2664.  
  2665. med3:
  2666.     pop    ds            ; ds -> swap routine data
  2667. ASSUME    ds:SWAP_TEXT,es:SWAP_TEXT
  2668.  
  2669.     mov    AliasSelector,ds
  2670.     mov    IntVectorSelector,0
  2671.     mov    LowMemSelector,0
  2672.     mov    WedgeMemSelector,0
  2673.  
  2674.     xor    bh,bh
  2675.     mov    ah,3
  2676.     int    10h            ; ready cursor size, position, and shape
  2677.     mov    CursorSize,cx
  2678.     mov    CursorRowCol,dx
  2679.  
  2680. ; get selector for interrupt vector table
  2681.     mov    ax,0ff03h        ; GetSel
  2682.     int    31h
  2683.     jc    SwapErr
  2684.     xor    cx,cx            ; point selector at 0:0 for interrupt vectors
  2685.     mov    dx,cx
  2686.     mov    di,400h
  2687.     mov    si,cx
  2688.     mov    ax,0ff09h        ; SetSelDet
  2689.     int    31h
  2690.     mov    INTVectorSelector,bx    ; save selector
  2691.  
  2692. ; get protected mode PSP of program
  2693.     mov    ah,62h        ; get PSP
  2694.     int    21h
  2695.  
  2696.     mov    PMPSP,bx    ; save protected mode PSP
  2697.     mov    ds,bx        ; ds -> protected mode psp
  2698.  
  2699.     mov    ax,ds:[EPSP_RealENV]    ; real mode environment block pointer
  2700.     mov    es:EnvironmentPointer,ax
  2701.  
  2702.     mov    edx,ds:[EPSP_INTMem]    ; interrupt/exception vectors linear address
  2703.     mov    ax,0ff03h    ; GetSel
  2704.     int    31h
  2705.     jc    SwapErr
  2706.     mov    ecx,(256*6)+(32*6)+400h    ; selector limit
  2707.     mov    ax,0ff0ah    ; SetSelDet32
  2708.     int    31h
  2709.  
  2710.     mov    ds,bx        ; ds -> selector
  2711.     mov    si,(256*6)+(32*6)    ; si -> past protected mode interrupt and exception vectors
  2712.     mov    di,OFFSET INTVectorTable    ; es:di -> real mode vector table storage
  2713.     mov    cx,256
  2714.     rep    movsd        ; save real mode vector table
  2715.  
  2716. ; release interrupt/exception vectors selector
  2717.     mov    ax,0ff04h        ; RelSel
  2718.     int    31h
  2719.  
  2720.     push    es
  2721.     pop    ds
  2722.  
  2723. ; get/save memory allocation strategy
  2724.     mov    ax,5800h        ; get allocation strategy
  2725.     int    21h
  2726.     mov    AllocStrat,ax    ; save original strategy
  2727.  
  2728. ; change memory allocation strategy to last fit
  2729.     mov    ax,5801h        ; set allocation strategy
  2730.     mov    bx,2            ; use highest available block that fits
  2731.     int    21h
  2732.  
  2733. ; get wedge memory for EXEC'ing
  2734.     mov    bx,(WedgeSpace+15)/16
  2735.     mov    ax,0ff21h
  2736.     int    31h
  2737.     jnc    savewedge
  2738.     pushf                ; setup stack so restore strategy still works properly
  2739.     push    ax
  2740.     jmp    NEAR PTR restalloc    ; error in dos allocation
  2741.  
  2742. ; save the wedge memory segment and selector
  2743. savewedge:
  2744. ;    mov    RealRegs.Real_FS,ax    ; save real mode segment of wedge memory
  2745. ; alternate save real mode segment of wedge memory into bx since NT doesn't restore FS properly
  2746.     mov    WORD PTR RealRegs.Real_EBX,ax
  2747.  
  2748.     mov    WedgeMemSelector,dx
  2749.  
  2750. ; copy wedge code to wedge segment
  2751.     mov    es,dx
  2752.     xor    di,di
  2753.     mov    si,OFFSET WedgeStart
  2754.     mov    cx,WedgeSpace
  2755.     push    cx
  2756.     shr    cx,2
  2757.     rep    movsd
  2758.     pop    cx
  2759.     and    cx,3
  2760.     rep    movsb
  2761.  
  2762.     push    ds
  2763.     pop    es
  2764.  
  2765. ; track if DPMI or non-, to determine where MCB is in relation to allocation
  2766.     mov    ax,0ff00h
  2767.     int    31h
  2768.     and    di,8            ; mask to DPMI bit
  2769.     mov    WORD PTR RealRegs.Real_EDX,di    ; save real mode flag
  2770.  
  2771. ; get DOS memory for moving code down for real mode execution
  2772.     mov    bx,(((OFFSET CodeEnd-OFFSET CodeStart)+15))/16    ; amount of low memory needed
  2773.     mov    ax,0ff21h
  2774.     int    31h
  2775.     pushf                ; save allocation error code
  2776.     push    ax            ; save segment
  2777.  
  2778. ; restore memory allocation strategy to original
  2779. restalloc:
  2780.     mov    ax,5801h        ; set allocation strategy
  2781.     mov    bx,AllocStrat    ; use highest available block that fits
  2782.     int    21h
  2783.  
  2784.     pop    ax                ; restore segment
  2785.     popf                ; restore allocation error code
  2786.     jnc    GotMemory
  2787.  
  2788. ; error using swapper
  2789. SwapErr:
  2790.     mov    ax,SWAPPERERROR
  2791.     mov    WORD PTR es:RealRegs.Real_EAX,ax    ; get return value
  2792.     jmp    NEAR PTR Done
  2793.  
  2794. ; got low DOS memory for code/data transfer, ax == segment, dx == selector
  2795. ; transfer code down to it
  2796. GotMemory:
  2797.     mov    WORD PTR RealRegs.Real_EAX,SWAPPERERROR    ; init return value
  2798.     mov    RealRegs.Real_CS,ax    ; save real mode segment
  2799.     mov    RealRegs.Real_IP,OFFSET NowInReal    ; transfer address in low memory
  2800.     mov    es,dx        ; es -> low memory selector
  2801.     mov    LowMemSelector,dx
  2802.     xor    di,di
  2803.     mov    si,OFFSET CodeStart
  2804.     mov    ax,(OFFSET CodeEnd-OFFSET CodeStart)
  2805.     mov    cx,ax
  2806.     shr    cx,2
  2807.     rep    movsd
  2808.     mov    cx,ax
  2809.     and    cx,3
  2810.     rep    movsb
  2811.     push    ds
  2812.     pop    es                ; es -> swap data
  2813.  
  2814.  
  2815. ;**JW**
  2816. ;
  2817. ;INC exec counter.
  2818. ;
  2819.  
  2820. ;    int    3
  2821.  
  2822.     mov    ah,62h        ; get PSP
  2823.     int    21h
  2824.  
  2825.     push    ds
  2826.     mov    ds,bx        ; ds -> protected mode psp
  2827.     lds    bx,ds:[EPSP_ExecCount]
  2828.     inc    byte ptr[bx]
  2829.     pop    ds
  2830.  
  2831. ; transfer to low DOS memory real mode operation
  2832.     mov    edi,OFFSET RealRegs    ; es:[e]di -> real mode register structure
  2833. ;    lea    edi,RealRegs    ; es:[e]di -> real mode register structure
  2834.  
  2835. ;    mov    ax,0ff02h    ; FarCallReal
  2836. ;    int    31h
  2837.  
  2838.  
  2839. ;**JW**
  2840. ;
  2841. ;Have to use DPMI far call function now because we've shut off CauseWay specific
  2842. ;functions.
  2843. ;
  2844.     mov    ax,301h
  2845.     xor    cx,cx
  2846.     xor    bx,bx
  2847.     mov    es:word ptr[di+Real_SP],0
  2848.     mov    es:word ptr[di+Real_SS],0
  2849.  
  2850.     int    31h
  2851.  
  2852. ;**JW**
  2853. ;
  2854. ;DEC exec counter.
  2855. ;
  2856. RestoreExecCount:
  2857. ;    push    ds
  2858. ;    mov    ds,cs:AliasSelector
  2859. ;    movzx    eax,WORD PTR ds:ReturnValue
  2860. ;    mov    ds:RealRegs.Real_EAX,eax    ; save return value
  2861. ;    pop    ds
  2862.  
  2863.     mov    ah,62h        ; get PSP
  2864.     int    21h
  2865.     push    ds
  2866.     mov    ds,bx        ; ds -> protected mode psp
  2867.     lds    bx,ds:[EPSP_ExecCount]
  2868.     dec    byte ptr[bx]
  2869.     pop    ds
  2870.  
  2871. ; real mode code will return here
  2872. Done:
  2873.     xor    bh,bh
  2874.     mov    dx,cs:CursorRowCol
  2875.     mov    ah,2            ; set cursor position
  2876.     int    10h
  2877.     mov    cx,cs:CursorSize
  2878.     mov    ah,1            ; set cursor size and shape
  2879.     int    10h
  2880.  
  2881. ;    mov    di,WORD PTR cs:RealRegs.Real_EAX    ; get return value
  2882.     mov    bx,cs:AliasSelector    ; release aliased selector
  2883.     or    bx,bx
  2884.     je    Adios
  2885.     mov    ax,0ff04h        ; RelSel
  2886.     int    31h
  2887.     mov    bx,cs:INTVectorSelector    ; release interrupt vector selector
  2888.     or    bx,bx
  2889.     je    Adios
  2890.     mov    ax,0ff04h        ; RelSel
  2891.     int    31h
  2892.     mov    dx,cs:WedgeMemSelector    ; release wedge memory
  2893.     or    dx,dx
  2894.     je    Adios
  2895.     mov    ax,0ff23h        ; RelMemDOS
  2896.     int    31h
  2897.     mov    dx,cs:LowMemSelector    ; release low memory
  2898.     or    dx,dx
  2899.     je    Adios
  2900.     mov    ax,0ff23h        ; RelMemDOS
  2901.     int    31h
  2902.  
  2903. Adios:
  2904.     pop    es
  2905.     pop    ds
  2906. ;    push    di
  2907. ;    xor    ah,ah
  2908. ;    or    di,di
  2909. ;    sete    al
  2910. ;    push    ax
  2911. ;    call    __retni    ; return value as integer to clipper
  2912. ;    add    sp,2        ; get return value off of stack
  2913.     popad
  2914. ;    mov    eax,cs:RealRegs.Real_EAX    ; get return value
  2915.  
  2916. ;**JW**
  2917. ;Need to do a 32-bit far return to match the call.
  2918.     db 66h
  2919.  
  2920.     retf
  2921.  
  2922. ; this part is executing in low DOS memory real mode
  2923. ; fs -> wedge memory segment
  2924. ; dl is nonzero if DPMI environment
  2925. NowInReal    =    $
  2926. ;    DB    66h
  2927. ;    retf
  2928.  
  2929. ;    int    3
  2930.  
  2931.     mov    fs,bx        ; wedge memory segment to fs (NT bug workaround)
  2932.  
  2933. ; swap original interrupt vector table with current
  2934.     cli
  2935.     mov    cx,256
  2936.     push    cs
  2937.     pop    ds
  2938.     xor    di,di
  2939.     mov    es,di            ; es:di -> interrupt vector table
  2940.     mov    si,OFFSET IntVectorTable
  2941.  
  2942. vectloop:
  2943.     mov    eax,ds:[si]
  2944.     xchg    eax,es:[di]
  2945.     add    di,4
  2946.     mov    ds:[si],eax
  2947.     add    si,4
  2948.     loop    vectloop
  2949.     sti
  2950.  
  2951.     push    cs
  2952.     pop    es
  2953.  
  2954. ; reset mouse driver
  2955.     xor    ax,ax
  2956.     int    33h
  2957.  
  2958. ;    int    3
  2959.  
  2960. ; save DPMI flag status
  2961.     mov    DPMIFlag,dl
  2962.  
  2963. ; get real mode PSP of program
  2964.     mov    ah,62h        ; get PSP
  2965.     int    21h
  2966.     mov    PSP,bx
  2967.  
  2968. ; seek out EXE pathspec from environment block
  2969.     mov    ds,bx        ; ds -> PSP
  2970.     mov    ax,ds:[2ch]    ; get original PSP environment pointer
  2971.     mov    es:PSPEnvironPtr,ax    ; save original PSP environment pointer
  2972.     mov    ax,es:EnvironmentPointer
  2973.     mov    ds:[2ch],ax    ; update PSP environment pointer
  2974.     mov    ds,ax        ; ds -> real mode PSP environment block
  2975.     xor    si,si        ; ds:si -> start of environment
  2976.  
  2977. endloop:
  2978.     lodsb            ; get environment char
  2979.     or    al,ds:[si]    ; merge in next char
  2980.     jne    endloop        ; not at end of environment block
  2981.     add    si,3        ; si -> start of EXE file path
  2982.     mov    di,si        ; save -> start
  2983.     xor    bx,bx        ; init end of char pointer
  2984.  
  2985. pathloop:
  2986.     lodsb            ; get char of file path
  2987.     or    al,al        ; see if at end
  2988.     je    calcpath    ; yes
  2989.     cmp    al,'\'        ; see if directory indicator
  2990.     jne    pathloop    ; no
  2991.     mov    bx,si        ; save -> char past directory
  2992.     jmp    SHORT pathloop
  2993.  
  2994. calcpath:
  2995.     mov    si,di        ; ds:si -> start of file path
  2996.     mov    di,OFFSET SwapFileName    ; es:di -> swap file name slot
  2997.     or    bx,bx        ; see if any path
  2998.     je    calcdone    ; no
  2999.  
  3000. calcloop:
  3001.     movsb
  3002.     cmp    si,bx        ; see if at end of path
  3003.     jne    calcloop    ; no
  3004.  
  3005. calcdone:
  3006.     push    es
  3007.     pop    ds            ; ds -> swap data
  3008.  
  3009. ; search environment variable directories for TEMP setting
  3010. ; override EXE Name SwapFileName if exists
  3011.     mov    bx,OFFSET TEMPText    ; ds:bx -> string to match
  3012.  
  3013. ; see if environment variable is present
  3014.     xor    si,si
  3015.     mov    es,EnvironmentPointer    ; es:si -> environment block strings
  3016.  
  3017. t_sevscan:
  3018.     xor    di,di            ; offset into target string to match
  3019.  
  3020. t_matchloop:
  3021.     lods    BYTE PTR es:[0]    ; get byte from environment string
  3022.     cmp    al,ds:[bx+di]    ; see if matches target
  3023.     je    t_bytematch        ; yes
  3024.     or    al,es:[si]        ; two zero values in a row mean end of environment
  3025.     jne    t_sevscan            ; no target match, more chars left
  3026.     jmp    SHORT getcomspec    ; end of environment, no match, search failed
  3027.  
  3028. ; check that environment string match is not part of another environment string
  3029. t_bytematch:
  3030.     or    di,di            ; di is zero if matching first char
  3031.     jne    t_sevnext            ; not matching first char
  3032.     cmp    si,1            ; si==1 if first string in environment block
  3033.     je    t_sevnext            ; first string, not a part of another string by definition
  3034.     cmp    BYTE PTR es:[si-2],0    ; char before environment string in block must be nonzero
  3035.     jne    t_sevscan            ; nonzero, subset of another string, keep scanning for match
  3036.  
  3037. t_sevnext:
  3038.     inc    di                ; match, move to next byte of target
  3039.     cmp    di,5            ; check if all bytes matched
  3040.     jb    t_matchloop        ; not yet
  3041.  
  3042.     mov    di,OFFSET SwapFileName    ; di will -> TEMP SwapFilePrefix
  3043.  
  3044. t_transloop:
  3045.     lods    BYTE PTR es:[0]    ; get path character
  3046.     cmp    al,';'            ; see if terminator character
  3047.     je    t_namedone        ; yes, name complete
  3048.     cmp    al,' '            ; whitespace also terminates
  3049.     jbe    t_namedone
  3050.     mov    ds:[di],al        ; save path character
  3051.     inc    di                ; bump name storage slot
  3052.     jmp    SHORT t_transloop
  3053.  
  3054. t_namedone:
  3055.     cmp    di,OFFSET SwapFileName    ; see if any path
  3056.     je    t_nullit        ; no
  3057.     mov    al,'\'
  3058.     cmp    BYTE PTR ds:[di-1],al    ; see if backslash terminated
  3059.     je    t_nullit        ; yes
  3060.     mov    ds:[di],al        ; must be backslash terminated
  3061.  
  3062. t_nullit:
  3063.     xor    al,al            ; null terminate temporary file name
  3064.     mov    ds:[di],al
  3065.  
  3066. ;    int    3
  3067.  
  3068. ; get COMSPEC setting for execfname
  3069. getcomspec:
  3070.     xor    si,si
  3071. ;    mov    es,PSP
  3072. ;    mov    es,es:[2ch]        ; es:si -> environment block strings
  3073.     mov    es,EnvironmentPointer    ; es:si -> environment block strings
  3074.  
  3075. sevscan:
  3076.     mov    bx,OFFSET COMSPECText
  3077.     xor    di,di
  3078.  
  3079. matchloop:
  3080.     lods    BYTE PTR es:[0]    ; get byte from environment string
  3081.     cmp    al,ds:[bx+di]        ; see if matches target
  3082.     je    bytematch        ; yes
  3083.     or    al,es:[si]        ; two zero values in a row mean end of environment
  3084.     je    med2            ; end of environment, no match, search failed
  3085.     jmp    SHORT sevscan    ; no target match, more chars left
  3086.  
  3087. ; check that environment string match is not part of another environment string
  3088. bytematch:
  3089.     or    di,di            ; di is zero if matching first char
  3090.     jne    sevnext            ; not matching first char
  3091.     cmp    si,1            ; si==1 if first string in environment block
  3092.     je    sevnext            ; first string, not a part of another string by definition
  3093.     cmp    BYTE PTR es:[si-2],0    ; char before environment string in block must be nonzero
  3094.     jne    sevscan            ; nonzero, subset of another string, keep scanning for match
  3095.  
  3096. sevnext:
  3097.     inc    di                ; match, move to next byte of target
  3098.     cmp    di,8            ; check if all bytes matched (all extension are four chars)
  3099.     jb    matchloop        ; not yet
  3100.  
  3101.     mov    di,OFFSET execfname    ; di will -> exec'ing name with path
  3102.  
  3103. transloop:
  3104.     lods    BYTE PTR es:[0]    ; get path character
  3105.     cmp    al,';'            ; see if terminator character
  3106.     je    namedone        ; yes, name complete
  3107.     cmp    al,' '            ; whitespace also terminates
  3108.     jbe    namedone
  3109.     mov    ds:[di],al        ; save path character
  3110.     inc    di                ; bump name storage slot
  3111.     jmp    SHORT transloop
  3112.  
  3113. namedone:
  3114.     xor    al,al            ; null terminate COMSPEC
  3115.     mov    ds:[di],al
  3116.  
  3117. med2:
  3118.  
  3119. ; copy low memory save (original code) to wedge segment storage
  3120.     push    fs
  3121.     pop    es
  3122.     mov    di,WedgeSave-WedgeStart    ; es:di -> wedge storage
  3123.     mov    si,WEDGEOFFSET
  3124.     mov    ds,PSP        ; ds:si -> low memory save
  3125.     mov    cx,savespace-(WEDGEOFFSET-5ch)+3    ; bytes to copy
  3126.     push    cx
  3127.     shr    cx,2
  3128.     rep    movsd
  3129.     pop    cx
  3130.     and    cx,3
  3131.     rep    movsb
  3132.  
  3133.     mov    ax,cs
  3134.     mov    ds,ax
  3135.     mov    es,ax
  3136.     mov    pmethod,4184h
  3137.     mov    swapping,1
  3138. ;    mov    swapping,0
  3139.     call    prep_swap
  3140.     cmp    swap_prep.swapmethod,0ffh    ; see iferror opening temporary file
  3141.     jne    noterr
  3142.  
  3143.     mov    ax,SWAPPERERROR
  3144.     jmp    SHORT restevp    ; error, don't continue
  3145.  
  3146. noterr:
  3147.     call    do_spawn
  3148.  
  3149. ; restore original environment pointer in real mode PSP
  3150. restevp:
  3151.     push    cs
  3152.     pop    ds
  3153.  
  3154.     mov    ReturnValue,ax
  3155.     mov    ax,PSPEnvironPtr    ; ax holds original environment pointer value
  3156.     mov    ds,PSP        ; ds -> real mode PSP
  3157.     mov    ds:[2ch],ax    ; restore PSP environment pointer
  3158.  
  3159. ; restore interrupt vector table, ax holds return code
  3160.     mov    cx,256
  3161.     push    cs
  3162.     pop    ds
  3163.     xor    di,di
  3164.     mov    es,di            ; es:di -> interrupt vector table
  3165.     mov    si,OFFSET IntVectorTable
  3166.     cli
  3167.     rep    movsd            ; restore interrupt vector table
  3168.     sti
  3169.  
  3170.     retf                ; return to protected mode code
  3171. ENDP
  3172.  
  3173. ; wedge code
  3174. WedgeSpace    EQU    WedgeStackEnd-WedgeStart
  3175. WedgeStart:
  3176.     pop    WORD PTR cs:[CallerOffset-WedgeStart]    ; save return address
  3177.     pop    WORD PTR cs:[CallerSegment-WedgeStart]
  3178.     mov    cs:[OriginalStackOff-WedgeStart],sp    ; save stack and set to new
  3179.     mov    cs:[OriginalStackSeg-WedgeStart],ss
  3180.     mov    ax,cs
  3181.     mov    ss,ax
  3182.     mov    sp,WedgeStackEnd-WedgeStart
  3183.  
  3184. ; swap wedge storage (original code) with low memory (new code)
  3185.     push    ds
  3186.     push    es
  3187.     mov    ds,cs:[CallerSegment-WedgeStart]
  3188.     mov    si,WEDGEOFFSET
  3189.     mov    di,WedgeSave-WedgeStart    ; fs:di -> wedge storage
  3190. ;    mov    cx,(savespace-(WEDGEOFFSET-5ch)+3)/4    ; bytes to swap
  3191.     mov    cx,savespace-(WEDGEOFFSET-5ch)        ; bytes to swap
  3192.  
  3193. wedgeloop:
  3194. ;    mov    eax,ds:[si]
  3195. ;    xchg    eax,fs:[di]
  3196. ;    add    di,4
  3197. ;    mov    ds:[si],eax
  3198. ;    add    si,4
  3199. ;    loop    wedgeloop
  3200.  
  3201.     mov    al,ds:[si]
  3202.     xchg    al,fs:[di]
  3203.     inc    di
  3204.     mov    ds:[si],al
  3205.     inc    si
  3206.     dec    cx
  3207.     jne    wedgeloop
  3208.  
  3209.     pop    es
  3210.     pop    ds
  3211.  
  3212.     mov    ax,4b00h            ; do the exec
  3213.     int    21h
  3214.  
  3215.     mov    ax,cs
  3216.     mov    ss,ax
  3217.     mov    sp,WedgeStackEnd-WedgeStart
  3218.  
  3219. ; copy wedge storage (new code) to low memory
  3220.     push    cs
  3221.     pop    ds
  3222.     mov    si,WedgeSave-WedgeStart    ; ds:si -> wedge storage
  3223.     mov    es,cs:[CallerSegment-WedgeStart]
  3224.     mov    di,WEDGEOFFSET    ; es:di -> low memory save
  3225. ;    mov    cx,savespace-(WEDGEOFFSET-5ch)+3    ; bytes to copy
  3226.     mov    cx,savespace-(WEDGEOFFSET-5ch)    ; bytes to copy
  3227.     push    cx
  3228.     shr    cx,2
  3229.     rep    movsd
  3230.     pop    cx
  3231.     and    cx,3
  3232.     rep    movsb
  3233.  
  3234.     mov    ss,cs:[OriginalStackSeg-WedgeStart]    ; restore stack to original
  3235.     mov    sp,cs:[OriginalStackOff-WedgeStart]
  3236.  
  3237. ; transfer back to low memory
  3238.     jmp    DWORD PTR cs:[CallerOffset-WedgeStart]
  3239.  
  3240.     OriginalStackOff    DW    ?
  3241.     OriginalStackSeg    DW    ?
  3242.     CallerOffset    DW    ?
  3243.     CallerSegment    DW    ?
  3244. WedgeSave    DB    savespace-(WEDGEOFFSET-5ch)+3 DUP (?)
  3245. EVEN
  3246.     DB    256 DUP (?)        ; wedge stack
  3247. WedgeStackEnd    =    $-1
  3248.  
  3249. ; constant data
  3250. COMSPECText    DB    'COMSPEC='
  3251. TEMPText    DB    'TEMP='
  3252.  
  3253. ; initialized data
  3254. LowMemSelector    DW    0    ; selector for accessing low memory
  3255. WedgeMemSelector    DW    0    ; selector for accessing wedge memory
  3256. AllocStrat    DW    0        ; memory allocation strategy
  3257. SwapFileName    DB    81 DUP (0)
  3258.  
  3259. ; uninitialized data
  3260. AliasSelector    DW    ?    ; alias data selector for code writes
  3261. EnvironmentPointer    DW    ?    ; real mode environment block pointer
  3262. INTVectorSelector    DW    ?    ; selector for accessing interrupt vector table
  3263. ;PSP        DW    ?        ; real mode PSP
  3264. ;SwapFileHandle    DW    ?    ; swap file handle
  3265. CursorSize    DW    ?        ; saved cursor size
  3266. CursorRowCol    DW    ?    ; saved cursor row and column
  3267.  
  3268. RealRegsStruc struc
  3269. Real_EDI    dd ?    ;EDI
  3270. Real_ESI    dd ?    ;ESI
  3271. Real_EBP    dd ?    ;EBP
  3272.         dd ?    ;Reserved.
  3273. Real_EBX    dd ?    ;EBX
  3274. Real_EDX    dd ?    ;EDX
  3275. Real_ECX    dd ?    ;ECX
  3276. Real_EAX    dd ?    ;EAX
  3277. Real_Flags    dw ?    ;FLAGS
  3278. Real_ES    dw ?    ;ES
  3279. Real_DS    dw ?    ;DS
  3280. Real_FS    dw ?    ;FS
  3281. Real_GS    dw ?    ;GS
  3282. Real_IP    dw ?    ;IP
  3283. Real_CS    dw ?    ;CS
  3284. Real_SP    dw ?    ;SP
  3285. Real_SS    dw ?    ;SS
  3286. RealRegsStruc ends
  3287.  
  3288. RealRegs    RealRegsStruc    <>
  3289. ;Now the extended PSP structure.
  3290. EPSP_Struc        struc
  3291.         db 256 dup (?)
  3292.  EPSP_Parent        dw ?        ;Selector of parent/previous PSP, 0 for none.
  3293.  EPSP_Next        dw ?        ;Next PSP.
  3294.  EPSP_Resource    dd ?        ;Linear address of resource tracking table. 0
  3295.                 ;for none.
  3296.  EPSP_mcbHead    dd ?        ;Linear address of MCB memory head. 0 for none.
  3297.  EPSP_mcbMaxAlloc    dd ?        ;Size of MCB chunks.
  3298.  EPSP_DTA        df ?        ;DTA address.
  3299.  EPSP_TransProt    dw ?        ;Transfer buffer address.
  3300.  EPSP_TransReal    dw ?        ;Transfer buffer real mode segment value.
  3301.  EPSP_TransSize    dd ?        ;Transfer buffer size.
  3302.  EPSP_SSESP        df ?        ;Return SS:ESP to use.
  3303.  EPSP_INTMem        dd ?        ;linear address of interrupt/exception vector
  3304.                 ;save buffer. 0 for none.
  3305.  EPSP_DPMIMem    dw ?        ;selector for DPMI state save buffer. 0 for
  3306.                 ;none.
  3307.  EPSP_MemBase    dd ?        ;Program linear load address.
  3308.  EPSP_MemSize    dd ?        ;Program memory size.
  3309.  EPSP_SegBase    dw ?        ;Base program selector.
  3310.  EPSP_SegSize    dw ?        ;Number of program selectors.
  3311.  
  3312.  EPSP_NearBase    dd ?        ;NEAR function address translation base.
  3313.  
  3314.  EPSP_RealENV    dw ?        ;Original real mode environment SEGMENT.
  3315.  
  3316.  EPSP_NextPSP    dd ?        ;Pointer to next PSP
  3317.  EPSP_LastPSP    dd ?        ;Pointer to last PSP
  3318.  
  3319.  EPSP_Exports    dd ?        ;Pointer to export list.
  3320.  EPSP_Imports    dd ?        ;Pointer to import list.
  3321.  
  3322.  EPSP_Links        dd ?        ;Count of linked modules.
  3323.  
  3324.  EPSP_ExecCount    dd ?        ;PMode pointer to exec counter.
  3325.  
  3326. EPSP_Struc        ends
  3327.  
  3328. INTVectorTable    DD    256 DUP (?)    ; interrupt vector table storage
  3329.  
  3330. CodeEnd    =    $
  3331.  
  3332. ENDS
  3333.  
  3334. END
  3335.