home *** CD-ROM | disk | FTP | other *** search
/ OS/2 Shareware BBS: 10 Tools / 10-Tools.zip / caway349.zip / MISC / CWSWAPR.ASM < prev    next >
Assembly Source File  |  1998-05-22  |  75KB  |  3,325 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.  
  1411. do_spawn    PROC    FAR
  1412. ;    local    datseg:WORD,pspseg:WORD,currmcb:WORD
  1413. ;
  1414. ;
  1415.     mov    datseg,ds        ; save default DS
  1416. ;
  1417.  
  1418. ;
  1419.     mov    bx,PSP
  1420.     mov    pspseg,bx
  1421. ;
  1422. ;    Check if spawn is too low in memory
  1423. ;
  1424.     mov    ax,cs
  1425.     mov    dx,offset lowcode_begin
  1426.     mov    cl,4
  1427.     shr    dx,cl
  1428.     add    ax,dx            ; normalized start of this code
  1429.     mov    dx,keep_paras        ; the end of the modified area
  1430.     add    dx,bx            ; plus PSP = end paragraph
  1431.     cmp    ax,dx
  1432.     ja    doswap_ok    ; ok if start of code > end of low mem
  1433.     mov    ax,RC_TOOLOW
  1434.     ret
  1435. ;
  1436. doswap_ok:
  1437.     cmp    swapping,0
  1438.     jle    method_ok
  1439. ;
  1440. ;    check the swap method, to make sure prep_swap has been called
  1441. ;
  1442.     mov    al,swap_prep.swapmethod
  1443.     cmp    al,USE_EMS
  1444.     je    method_ok
  1445.     cmp    al,USE_XMS
  1446.     je    method_ok
  1447.     cmp    al,USE_FILE
  1448.     je    method_ok
  1449.     mov    ax,RC_BADPREP
  1450.     ret
  1451. ;
  1452. ;    Save the memory below the swap space.
  1453. ;    We must do this before swapping, so the saved memory is
  1454. ;    in the swapped out image.
  1455. ;    Anything else we'd want to save on the stack or anywhere
  1456. ;    else in "normal" memory also has to be saved here, any
  1457. ;    modifications done to memory after the swap will be lost.
  1458. ;
  1459. ;    Note that the memory save is done even when not swapping,
  1460. ;    because we use some of the variables in low core for
  1461. ;    simplicity.
  1462. ;
  1463. method_ok:
  1464.     mov    es,datseg
  1465.     mov    ds,pspseg        ; DS points to PSP
  1466.     mov    si,5ch
  1467.     mov    di,offset save_dat
  1468.     mov    cx,savespace / 2    ; NOTE: savespace is always even
  1469.     rep movsw
  1470. ;
  1471.     mov    ds,datseg
  1472. ;
  1473.     mov    ax,swapping
  1474.     cmp    ax,0
  1475.     jg    begin_swap
  1476. ;
  1477. ;    not swapping, prep_swap wasn't called. Init those variables in
  1478. ;      the 'swap_prep' block we need in any case.
  1479. ;
  1480.     mov    swap_prep.swapmethod,al
  1481.     je    no_reduce
  1482. ;
  1483.     mov    ax,pspseg
  1484.     dec    ax
  1485.     mov    swap_prep.psp_mcb,ax
  1486.     mov    swap_prep.first_mcb,ax
  1487.     inc    ax
  1488.     mov    es,ax
  1489.     mov    bx,es:psp_envptr
  1490.     mov    swap_prep.env_mcb,bx
  1491. ;    mov    swap_prep.noswap_mcb,0
  1492. ;    cmp    envlen,0
  1493. ;    jne    swp_can_swap_env
  1494.     mov    swap_prep.noswap_mcb,bx
  1495. ;
  1496. swp_can_swap_env:
  1497.     xor    bx,bx
  1498.     mov    es,bx
  1499.     mov    ah,52h            ; get list of lists
  1500.     int    21h
  1501.     mov    ax,es
  1502.     or    ax,bx
  1503.     jz    no_reduce
  1504.     mov    es,es:[bx-2]        ; first MCB
  1505.     cmp    es:id,4dh        ; normal ID?
  1506.     jne    no_reduce
  1507.     mov    swap_prep.first_mcb,es
  1508. ;
  1509. no_reduce:
  1510.     jmp    no_swap1
  1511. ;
  1512. ;    set up first block descriptor
  1513. ;
  1514. begin_swap:
  1515.     mov    ax,swap_prep.first_mcb
  1516.     mov    currmcb,ax
  1517.     mov    es,swap_prep.psp_mcb    ; let ES point to base MCB
  1518.     mov    ax,es:paras
  1519.     mov    currdesc.msize,ax
  1520.     sub    ax,keep_paras
  1521.     mov    currdesc.swsize,ax
  1522.     mov    currdesc.addr,es
  1523.     mov    currdesc.swoffset,swapbeg + 16
  1524. ;        NOTE: swapbeg is 1 para higher when seen from MCB
  1525.     mov    ax,swap_prep.total_mcbs
  1526.     mov    currdesc.num_follow,ax
  1527. ;
  1528. ;    init other vars
  1529. ;
  1530.     mov    xmsctl.destlo,0
  1531.     mov    xmsctl.desthi,0
  1532.     mov    ems_curpage,0
  1533.     mov    ems_curoff,ems_parasize
  1534. ;
  1535. ;    Do the swapping. Each MCB block (except the last) has an
  1536. ;    "mcbdesc" structure appended that gives location and size
  1537. ;    of the next MCB.
  1538. ;
  1539. swapout_main:
  1540.     cmp    currdesc.num_follow,0    ; next block?
  1541.     je    swapout_no_next        ; ok if not
  1542. ;
  1543. ;    There is another MCB block to be saved. So we don't have
  1544. ;    to do two calls to the save routine with complicated
  1545. ;    parameters, we set up the next MCB descriptor beforehand.
  1546. ;    Walk the MCB chain starting at the current MCB to find
  1547. ;    the next one belonging to this process.
  1548. ;
  1549.     mov    ax,currmcb
  1550.     mov    bx,pspseg
  1551.     mov    cx,swap_prep.psp_mcb
  1552.     mov    dx,swap_prep.noswap_mcb
  1553.     mov    si,swap_prep.noswap2_mcb
  1554. ;
  1555. swm_mcb_walk:
  1556.     mov    es,ax
  1557.     cmp    ax,cx
  1558.     jbe    swm_next_mcb
  1559.     cmp    ax,dx
  1560.     je    swm_next_mcb
  1561.     cmp    ax,si
  1562.     je    swm_next_mcb
  1563.     cmp    ax,swap_prep.noswap3_mcb
  1564.     je    swm_next_mcb
  1565. ;
  1566.     cmp    bx,es:owner        ; our process?
  1567.     je    swm_mcb_found        ; found it if yes
  1568. ;
  1569. swm_next_mcb:
  1570.     cmp    es:id,4dh        ; normal block?
  1571.     jne    swm_mcb_error        ; error if end of chain
  1572.     add    ax,es:paras        ; start + length
  1573.     inc    ax            ; next MCB
  1574.     jmp    swm_mcb_walk
  1575. ;
  1576. ;    MCB found, set up an mcbdesc in the "nextmcb" structure
  1577. ;
  1578. swm_mcb_found:
  1579.     mov    nextmcb.addr,es
  1580.     mov    ax,es:paras        ; get number of paragraphs
  1581.     mov    nextmcb.msize,ax    ; and save
  1582.     inc    ax
  1583.     mov    nextmcb.swsize,ax
  1584.     mov    bx,es
  1585.     add    bx,ax
  1586.     mov    currmcb,bx
  1587.     mov    nextmcb.swoffset,0
  1588.     mov    ax,currdesc.num_follow
  1589.     dec    ax
  1590.     mov    nextmcb.num_follow,ax
  1591. ;
  1592. swapout_no_next:
  1593.     cmp    swap_prep.swapmethod,USE_EMS
  1594.     je    swm_ems
  1595.     cmp    swap_prep.swapmethod,USE_XMS
  1596.     je    swm_xms
  1597.     call    swapout_file
  1598.     jmp    short swm_next
  1599. ;
  1600. swm_ems:
  1601.     call    swapout_ems
  1602.     jmp    short swm_next
  1603. ;
  1604. swm_xms:
  1605.     call    swapout_xms
  1606. ;
  1607. swm_next:
  1608.     jnz    swapout_error
  1609.     cmp    currdesc.num_follow,0
  1610.     je    swapout_complete
  1611. ;
  1612. ;    next MCB exists, copy the "nextmcb" descriptor into
  1613. ;    currdesc, and loop.
  1614. ;
  1615.     mov    es,datseg
  1616.     mov    si,offset nextmcb
  1617.     mov    di,offset currdesc
  1618.     mov    cx,TYPE mcbdesc
  1619.     rep movsb
  1620.     jmp    swapout_main
  1621. ;
  1622. ;
  1623. swm_mcb_error:
  1624.     mov    ax,RC_MCBERROR
  1625. ;
  1626. swapout_kill:
  1627.     cmp    swapping,0
  1628.     jl    swapout_error
  1629.     push    ax
  1630.     cmp    swap_prep.swapmethod,USE_FILE
  1631.     je    swm_mcberr_file
  1632.     cmp    swap_prep.swapmethod,USE_EMS
  1633.     je    swm_mcberr_ems
  1634. ;
  1635.     mov    ah,0ah            ; release XMS frame on error
  1636.     mov    dx,swap_prep.handle    ; XMS handle
  1637.     call    swap_prep.xmm
  1638.     pop    ax
  1639.     jmp    short swapout_error
  1640. ;
  1641. swm_mcberr_ems:
  1642.     mov    dx,swap_prep.handle    ; EMS handle
  1643.     mov    ah,45h            ; release EMS pages on error
  1644.     int    EMM_INT
  1645.     pop    ax
  1646.     jmp    short swapout_error
  1647. ;
  1648. swm_mcberr_file:
  1649.     mov    bx,swap_prep.handle
  1650.     cmp    bx,-1
  1651.     je    swm_noclose
  1652.     mov    ah,3eh            ; close file
  1653.     int    21h
  1654. swm_noclose:
  1655.     mov    dx,offset swap_prep.sp_swapfilename
  1656.     mov    ah,41h            ; delete file
  1657.     int    21h
  1658.     pop    ax
  1659. ;
  1660. swapout_error:
  1661.     ret
  1662. ;
  1663. ;
  1664. ;    Swapout complete. Close the handle (EMS/file only),
  1665. ;    then set up low memory.
  1666. ;
  1667. swapout_complete:
  1668.     cmp    swap_prep.swapmethod,USE_FILE
  1669.     jne    swoc_nofile
  1670. ;
  1671. ;    File swap: Close the swap file to make the handle available
  1672. ;
  1673.     mov    bx,swap_prep.handle
  1674.     mov    swap_prep.handle,-1
  1675.     mov    ah,3eh
  1676.     int    21h            ; close file
  1677.     mov    si,offset swapin_file
  1678.     jnc    swoc_ready
  1679.     mov    ax,RC_SWAPERROR
  1680.     jmp    swapout_kill
  1681. ;
  1682. swoc_nofile:
  1683.     cmp    swap_prep.swapmethod,USE_EMS
  1684.     jne    swoc_xms
  1685. ;
  1686. ;    EMS: Unmap page
  1687. ;
  1688.     mov    ax,4400h
  1689.     mov    bx,-1
  1690.     mov    dx,swap_prep.handle
  1691.     int    EMM_INT
  1692.     mov    si,offset swapin_ems
  1693.     jmp    short swoc_ready
  1694. ;
  1695. swoc_xms:
  1696.     mov    si,offset swapin_xms
  1697.     jmp    short swoc_ready
  1698. ;
  1699. no_swap1:
  1700.     mov    si,offset swapin_none
  1701. ;
  1702. ;    Copy the appropriate swap-in routine to low memory.
  1703. ;
  1704. swoc_ready:
  1705.     mov    es,pspseg
  1706.     mov    cx,swap_codelen / 4
  1707.     mov    di,codebeg + base_length
  1708.     push    ds
  1709.     mov    ax,cs
  1710.     mov    ds,ax
  1711.     rep movsd
  1712. ;
  1713. ;    And while we're at it, copy the MCB allocation routine (which
  1714. ;    also includes the initial MCB release and exec call) down.
  1715. ;
  1716.     mov    cx,base_length / 2
  1717.     mov    di,param_len
  1718.     mov    si,offset lowcode_begin
  1719.     rep movsw
  1720. ;
  1721.     pop    ds
  1722.     mov    bx,es
  1723.     dec    bx
  1724.     mov    es,bx        ; let ES point to base MCB
  1725. ;
  1726. ;    Again set up the base MCB descriptor, and copy it as well as
  1727. ;    the variables set up by prep_swap to low memory.
  1728. ;    This isn't too useful if we're not swapping, but it doesn't
  1729. ;    hurt, either. The only variable used when not swapping is
  1730. ;    lprep.swapmethod.
  1731. ;
  1732.     mov    ax,es:paras
  1733.     mov    currdesc.msize,ax
  1734.     sub    ax,keep_paras
  1735.     mov    currdesc.swsize,ax
  1736.     mov    currdesc.addr,es
  1737.     mov    currdesc.swoffset,swapbeg + 16
  1738.     mov    ax,swap_prep.total_mcbs
  1739.     mov    currdesc.num_follow,ax
  1740. ;
  1741.     mov    es,pspseg        ; ES points to PSP again
  1742. ;
  1743.     mov    cx,TYPE prep_block
  1744.     mov    si,offset swap_prep
  1745.     mov    di,lprep
  1746.     rep movsb
  1747.     mov    cx,TYPE mcbdesc
  1748.     mov    si,offset currdesc
  1749.     mov    di,lcurrdesc
  1750.     rep movsb
  1751. ;
  1752. ;    now set up other variables in low core
  1753. ;
  1754.     mov    ds,pspseg
  1755.     mov    ds:cgetmcb,getmcboff + codebeg
  1756.     mov    ds:eretcode,0
  1757.     mov    ds:retflags,0
  1758. ;
  1759. ;
  1760. ;    If 'NO_INHERIT' is nonzero, save the entries of the
  1761. ;    handle table, and set the last 15 to 0ffh (unused).
  1762. ;
  1763.     mov    si,psp_handletab
  1764.     mov    di,lhandlesave
  1765.     mov    cx,10
  1766.     rep movsw
  1767.     mov    si,psp_handlenum    ; Length of handle table
  1768.     mov    ax,[si]
  1769.     stosw
  1770.     mov    word ptr [si],20    ; set to default to be safe
  1771.     add    si,2
  1772.     lodsw                ; Handle table pointer
  1773.     mov    bx,ax
  1774.     stosw
  1775.     lodsw
  1776.     stosw
  1777.     cmp    ax,pspseg
  1778.     jne    copy_handles
  1779.     cmp    bx,psp_handletab
  1780.     je    no_handlecopy
  1781. ;
  1782. ;    if the handle table pointer in the PSP does not point to
  1783. ;    the default PSP location, copy the first five entries from
  1784. ;    this table into the PSP - but only if we have DOS >= 3.3.
  1785. ;
  1786. copy_handles:
  1787.     mov    ds,ax
  1788.     mov    si,bx
  1789.     mov    di,psp_handletab
  1790.     mov    es:psp_handleptro,di
  1791.     mov    es:psp_handleptrs,es
  1792.     movsw
  1793.     movsw
  1794.     movsb
  1795. ;
  1796. no_handlecopy:
  1797.     mov    di,psp_handletab+5
  1798.     mov    ax,0ffffh
  1799.     stosb
  1800.     mov    cx,7
  1801.     rep stosw
  1802. ;
  1803. ;
  1804. ;    Handle Redirection
  1805. ;
  1806.     IF    REDIRECT
  1807.     mov    es,pspseg
  1808.     mov    di,lstdinsav
  1809.     mov    ax,-1
  1810.     stosw
  1811.     stosw
  1812.     stosw
  1813.     mov    di,lstdinsav
  1814.     xor    cx,cx
  1815.     IF    ptrsize
  1816.     lds    si,stdin
  1817.     mov    ax,ds
  1818.     or    ax,si
  1819.     ELSE
  1820.     mov    si,stdin
  1821.     mov    ds,datseg
  1822.     or    si,si
  1823.     ENDIF
  1824.     call    @redirect
  1825.     jc    failed_redir
  1826.     inc    cx
  1827.     IF    ptrsize
  1828.     lds    si,stdout
  1829.     mov    ax,ds
  1830.     or    ax,si
  1831.     ELSE
  1832.     mov    si,stdout
  1833.     or    si,si
  1834.     ENDIF
  1835.     call    @redirect
  1836.     jc    failed_redir
  1837.     inc    cx
  1838.     IF    ptrsize
  1839.     lds    si,stderr
  1840.     mov    ax,ds
  1841.     or    ax,si
  1842.     ELSE
  1843.     mov    si,stderr
  1844.     or    si,si
  1845.     ENDIF
  1846.     call    @redirect
  1847.     jnc    redir_complete
  1848. ;
  1849. failed_redir:
  1850.     push    ax
  1851. ;
  1852. ;    restore handle table and pointer
  1853. ;
  1854.     mov    ds,pspseg
  1855.     mov    si,lstdinsav
  1856.     xor    cx,cx
  1857. ;
  1858. redirclose:
  1859.     lodsw
  1860.     cmp    ax,-1
  1861.     je    redclosenext
  1862.     mov    bx,ax
  1863.     mov    ah,46h
  1864.     int    21h
  1865. ;
  1866. redclosenext:
  1867.     inc    cx
  1868.     cmp    cx,3
  1869.     jb    redirclose
  1870. ;
  1871.     mov    ds,pspseg
  1872.     mov    es,pspseg
  1873.     mov    si,lhandlesave
  1874.     mov    di,psp_handletab
  1875.     mov    cx,10
  1876.     rep movsw
  1877.     mov    di,psp_handlenum
  1878.     movsw
  1879.     movsw
  1880.     movsw
  1881. ;
  1882. ;    Restore overwritten part of program
  1883. ;
  1884.     mov    ds,datseg
  1885.     mov    es,pspseg
  1886.     mov    si,offset save_dat
  1887.     mov    di,5ch
  1888.     mov    cx,savespace
  1889.     rep movsb
  1890. ;
  1891.     pop    ax
  1892.     mov    ah,RC_REDIRFAIL SHR 8
  1893.     jmp    swapout_kill
  1894. ;
  1895. redir_complete:
  1896.     mov    ds,pspseg
  1897.     mov    es,pspseg
  1898.     mov    si,psp_handletab+5
  1899.     mov    di,lredirsav
  1900.     mov    cx,3
  1901.     rep movsw
  1902.     mov    di,psp_handletab+5
  1903.     mov    cx,3
  1904.     mov    ax,0ffffh
  1905.     rep stosw
  1906.     ENDIF
  1907. ;
  1908. ;    Prepare exec parameter block
  1909. ;
  1910.     mov    ax,es
  1911.     mov    es:expar.fcb1seg,ax
  1912.     mov    es:expar.fcb2seg,ax
  1913.     mov    es:expar.pparseg,ax
  1914.     mov    es:expar.envseg,0
  1915. ;
  1916. ;    The 'zero' word is located at 80h in the PSP, the start of
  1917. ;    the command line. So as not to confuse MCB walking programs,
  1918. ;    a command line length of zero is inserted here.
  1919. ;
  1920.     mov    es:zero,0d00h        ; 00h,0dh = empty command line
  1921. ;
  1922. ;    Init default fcb's by parsing parameter string
  1923. ;
  1924. ;    IF    ptrsize
  1925. ;    lds    si,params
  1926. ;    ELSE
  1927.     mov    si,OFFSET params
  1928.     mov    ds,datseg
  1929. ;    ENDIF
  1930.     push    si
  1931.     mov    di,xfcb1
  1932.     mov    es:expar.fcb1,di
  1933.     push    di
  1934.     mov    cx,16
  1935.     xor    ax,ax
  1936.     rep stosw            ; init both fcb's to 0
  1937.     pop    di
  1938.     mov    ax,2901h
  1939.     int    21h
  1940.     mov    di,xfcb2
  1941.     mov    es:expar.fcb2,di
  1942.     mov    ax,2901h
  1943.     int    21h
  1944.     pop    si
  1945. ;
  1946. ;    move command tail string into low core
  1947. ;
  1948.     mov    di,progpars
  1949.     mov    es:expar.ppar,di
  1950.     xor    cx,cx
  1951.     inc    di
  1952. cmdcpy:
  1953.     lodsb
  1954.     or    al,al
  1955.     jz    cmdcpy_end
  1956.     stosb
  1957.     inc    cx
  1958.     jmp    cmdcpy
  1959. ;
  1960. cmdcpy_end:
  1961.     mov    al,0dh
  1962.     stosb
  1963.     mov    es:progpars,cl
  1964. ;
  1965. ;    move filename string into low core
  1966. ;
  1967. ;    IF    ptrsize
  1968. ;    lds    si,execfname
  1969. ;    ELSE
  1970.     mov    si,OFFSET execfname
  1971. ;    ENDIF
  1972.     mov    di,filename
  1973. fncpy:
  1974.     lodsb
  1975.     stosb
  1976.     or    al,al
  1977.     jnz    fncpy
  1978. ;
  1979. ;    Setup environment copy
  1980. ;
  1981.     mov    bx,keep_paras        ; paras to keep
  1982.  
  1983. ;    xor    bx,bx
  1984.  
  1985. COMMENT !
  1986.     mov    cx,envlen        ; environment size
  1987.     jcxz    no_environ        ; go jump if no environment
  1988.  
  1989.     cmp    swapping,0
  1990.     jne    do_envcopy
  1991. ;
  1992. ;    Not swapping, use the environment pointer directly.
  1993. ;    Note that the environment copy must be paragraph aligned.
  1994. ;
  1995.     IF    ptrsize
  1996.     mov    ax,word ptr (envp)+2
  1997.     mov    bx,word ptr (envp)
  1998.     ELSE
  1999.     mov    ax,ds
  2000.     mov    bx,envp
  2001.     ENDIF
  2002.     add    bx,15            ; make sure it's paragraph aligned
  2003.     mov    cl,4
  2004.     shr    bx,cl            ; and convert to segment addr
  2005.     add    ax,bx
  2006.     mov    es:expar.envseg,ax    ; new environment segment
  2007.     xor    cx,cx            ; mark no copy
  2008.     xor    bx,bx            ; and no shrink
  2009.     jmp    short no_environ
  2010. ;
  2011. ;    Swapping or EXECing without return. Set up the pointers for
  2012. ;    an environment copy (we can't do the copy yet, it might overwrite
  2013. ;    this code).
  2014. ;
  2015. do_envcopy:
  2016.     inc    cx
  2017.     shr    cx,1            ; words to copy
  2018.     mov    ax,cx            ; convert envsize to paras
  2019.     add    ax,7
  2020.     shr    ax,1
  2021.     shr    ax,1
  2022.     shr    ax,1
  2023.     add    bx,ax            ; add envsize to paras to keep
  2024.     IF    ptrsize
  2025.     lds    si,envp
  2026.     ELSE
  2027.     mov    si,envp
  2028.     ENDIF
  2029. ;
  2030.     mov    ax,es            ; low core segment
  2031.     add    ax,keep_paras        ; plus fixed paras
  2032.     mov    es:expar.envseg,ax    ; = new environment segment
  2033. END COMMENT !
  2034. ;
  2035. ;    Save stack regs, switch to local stack
  2036. ;
  2037. no_environ:
  2038.     mov    es:save_ss,ss
  2039.     mov    es:save_sp,sp
  2040.     mov    ax,es
  2041.     cli
  2042.     mov    ss,ax
  2043.     mov    sp,mystack
  2044.     sti
  2045. ;
  2046. ;    push    cx            ; save env length
  2047. ;    push    si            ; save env pointer
  2048.     push    ds            ; save env segment
  2049. ;
  2050. ;    save and patch INT0 (division by zero) vector
  2051. ;
  2052.     xor    ax,ax
  2053.     mov    ds,ax
  2054.     mov    ax,word ptr ds:0
  2055.     mov    es:div0_off,ax
  2056.     mov    ax,word ptr ds:2
  2057.     mov    es:div0_seg,ax
  2058.     mov    word ptr ds:0,codebeg + iretoff
  2059.     mov    word ptr ds:2,es
  2060. ;
  2061.     pop    ds            ; pop environment segment
  2062. ;    pop    si            ; pop environment offset
  2063. ;    pop    cx            ; pop environment length
  2064.     mov    di,swapbeg        ; environment destination
  2065. ;
  2066. ;    Push return address on local stack
  2067. ;
  2068.     push    cs            ; push return segment
  2069.     mov    ax,offset exec_cont
  2070.     push    ax            ; push return offset
  2071.     mov    es:spx,sp        ; save stack pointer
  2072. ;
  2073. ;    Goto low core code
  2074. ;
  2075.     push    es            ; push entry segment
  2076.     mov    ax,codebeg + doexec_entry
  2077.     push    ax            ; push entry offset
  2078.     retf
  2079. ;
  2080. ;----------------------------------------------------------------
  2081. ;
  2082. ;    Low core code will return to this location, with DS set to
  2083. ;    the PSP segment.
  2084. ;
  2085. exec_cont:
  2086.     push    ds
  2087.     pop    es
  2088.     cli
  2089.     mov    ss,ds:save_ss        ; reload stack
  2090.     mov    sp,ds:save_sp
  2091.     sti
  2092. ;
  2093. ;    restore handle table and pointer
  2094. ;
  2095.     mov    si,lhandlesave
  2096.     mov    di,psp_handletab
  2097.     mov    cx,10
  2098.     rep movsw
  2099.     mov    di,psp_handlenum
  2100.     movsw
  2101.     movsw
  2102.     movsw
  2103. ;
  2104. ;    restore INT0 (division by zero) vector
  2105. ;
  2106.     xor    cx,cx
  2107.     mov    ds,cx
  2108.     mov    cx,es:div0_off
  2109.     mov    word ptr ds:0,cx
  2110.     mov    cx,es:div0_seg
  2111.     mov    word ptr ds:2,cx
  2112. ;
  2113.     mov    ds,datseg
  2114. ;
  2115. ;
  2116.     mov    ax,es:eretcode
  2117.     mov    bx,es:retflags
  2118. ;
  2119. ;    Restore overwritten part of program
  2120. ;
  2121.     mov    si,offset save_dat
  2122.     mov    di,5ch
  2123.     mov    cx,savespace
  2124.     rep movsb
  2125. ;
  2126.  
  2127. ;    int    3
  2128.  
  2129.     test    bx,1            ; carry set?
  2130.     jnz    exec_fault        ; return EXEC error code if fault
  2131.     mov    ah,4dh            ; else get program return code
  2132.     int    21h
  2133.     xor    ah,ah            ; zap high value
  2134.     ret
  2135. ;
  2136. exec_fault:
  2137.     mov    ax,SWAPPERERROR
  2138. ;    mov    ah,3            ; return error as 03xx
  2139.     ret
  2140. ;
  2141. do_spawn    ENDP
  2142. ;
  2143. ;----------------------------------------------------------------------------
  2144. ;----------------------------------------------------------------------------
  2145. ;
  2146. emm_name    db    'EMMXXXX0'
  2147. ;
  2148. ;    prep_swap - prepare for swapping.
  2149. ;
  2150. ;    This routine checks all parameters necessary for swapping,
  2151. ;    and attempts to set up the swap-out area in EMS/XMS, or on file.
  2152. ;    In detail:
  2153. ;
  2154. ;         1) Check whether the do_spawn routine is located
  2155. ;        too low in memory, so it would get overwritten.
  2156. ;        If this is true, return an error code (-2).
  2157. ;
  2158. ;         2) Walk the memory control block chain, adding up the
  2159. ;        paragraphs in all blocks assigned to this process.
  2160. ;
  2161. ;         3) Check EMS (if the method parameter allows EMS):
  2162. ;        - is an EMS driver installed?
  2163. ;        - are sufficient EMS pages available?
  2164. ;        if all goes well, the EMS pages are allocated, and the
  2165. ;        routine returns success (1).
  2166. ;
  2167. ;         4) Check XMS (if the method parameter allows XMS):
  2168. ;        - is an XMS driver installed?
  2169. ;        - is a sufficient XMS block available?
  2170. ;        if all goes well, the XMS block is allocated, and the
  2171. ;        routine returns success (2).
  2172. ;
  2173. ;         5) Check file swap (if the method parameter allows it):
  2174. ;        - try to create the file
  2175. ;        - pre-allocate the file space needed by seeking to the end
  2176. ;          and writing a byte.
  2177. ;        If the file can be written, the routine returns success (4).
  2178. ;
  2179. ;         6) Return an error code (-1).
  2180. ;
  2181.         pmethod    DW    ?
  2182.  
  2183. ;prep_swap    PROC    uses si di,pmethod:word,swapfname:ptr byte
  2184. prep_swap    PROC    FAR
  2185.  
  2186.     LOCAL    totparas: word
  2187. ;
  2188. ;
  2189.     mov    ax,fs        ; ax -> wedge segment
  2190.     dec    ax
  2191.     cmp    DPMIFlag,0    ; see if using DPMI
  2192.     jne    isdpmi
  2193.     dec    ax            ; CauseWay uses 1 para for its own purposes, compute MCB
  2194.  
  2195. isdpmi:
  2196.     mov    swap_prep.noswap2_mcb,ax    ; don't swap out wedge segment
  2197.  
  2198.     mov    ax,PSP
  2199.     mov    es,ax        ; es -> PSP
  2200.     mov    ax,es:[36h]    ; es -> file handle table segment
  2201.     dec    ax
  2202.     cmp    DPMIFlag,0    ; see if using DPMI
  2203.     jne    isdpmi2
  2204.     dec    ax            ; CauseWay uses 1 para for its own purposes, compute MCB
  2205.  
  2206. isdpmi2:
  2207.     mov    swap_prep.noswap3_mcb,ax    ; don't swap out file handle table segment
  2208.  
  2209.     mov    ax,PSP
  2210.     dec    ax
  2211.     mov    swap_prep.psp_mcb,ax
  2212.     mov    swap_prep.first_mcb,ax    ; init first MCB to PSP
  2213. ;
  2214. ;    Make a copy of the environment pointer in the PSP
  2215. ;
  2216.     inc    ax
  2217.     mov    es,ax
  2218.     mov    bx,es:psp_envptr
  2219.     dec    bx
  2220.     mov    swap_prep.env_mcb,bx
  2221. ;    mov    swap_prep.noswap_mcb,0
  2222. ;    test    pmethod,DONT_SWAP_ENV
  2223. ;    jz    can_swap_env
  2224.     mov    swap_prep.noswap_mcb,bx
  2225. ;
  2226. can_swap_env:
  2227. ;
  2228. ;    Check if spawn is too low in memory
  2229. ;
  2230.     mov    bx,cs
  2231.     mov    dx,offset lowcode_begin
  2232.     mov    cl,4
  2233.     shr    dx,cl
  2234.     add    bx,dx            ; normalized start of this code
  2235.     mov    dx,keep_paras        ; the end of the modified area
  2236.     add    dx,ax            ; plus PSP = end paragraph
  2237.     cmp    bx,dx
  2238.     ja    prepswap_ok    ; ok if start of code > end of low mem
  2239.     mov    ax,-2
  2240.     mov    swap_prep.swapmethod,al
  2241.     ret
  2242. ;
  2243. ;    Walk the chain of memory blocks, adding up the paragraphs
  2244. ;    in all blocks belonging to this process.
  2245. ;    We try to find the first MCB by getting DOS's "list of lists",
  2246. ;    and fetching the word at offset -2 of the returned address.
  2247. ;    If this fails, we use our PSP as the starting point.
  2248. ;
  2249. prepswap_ok:
  2250.     xor    bx,bx
  2251.     mov    es,bx
  2252.     mov    ah,52h            ; get list of lists
  2253.     int    21h
  2254.     mov    ax,es
  2255.     or    ax,bx
  2256.     jz    prep_no_first
  2257.     mov    es,es:[bx-2]        ; first MCB
  2258.     cmp    es:id,4dh        ; normal ID?
  2259.     jne    prep_no_first
  2260.     mov    swap_prep.first_mcb,es
  2261. ;
  2262. prep_no_first:
  2263.     mov    es,swap_prep.psp_mcb    ; ES points to base MCB
  2264.     mov    cx,es            ; save this value
  2265.     mov    bx,es:owner        ; the current process
  2266.     mov    dx,es:paras        ; memory size in the base block
  2267.     sub    dx,keep_paras        ; minus resident paragraphs
  2268.     mov    si,0            ; number of MCBs except base
  2269.     mov    di,swap_prep.noswap_mcb
  2270.     mov    bp,swap_prep.noswap2_mcb
  2271.     mov    ax,swap_prep.first_mcb
  2272.     mov    swap_prep.first_mcb,0
  2273. ;
  2274. prep_mcb_walk:
  2275.     mov    es,ax
  2276.     cmp    ax,cx            ; base block?
  2277.     jbe    prep_walk_next        ; then don't count again
  2278.     cmp    ax,di            ; Non-swap MCB?
  2279.     je    prep_walk_next        ; then don't count
  2280.     cmp    ax,bp            ; Non-swap MCB?
  2281.     je    prep_walk_next        ; then don't count
  2282.     cmp    ax,swap_prep.noswap3_mcb    ; non-swap MCB
  2283.     je    prep_walk_next        ; then don't count
  2284.  
  2285. ;
  2286.     cmp    bx,es:owner        ; our process?
  2287.     jne    prep_walk_next        ; next if not
  2288.     inc    si
  2289.     mov    ax,es:paras        ; else get number of paragraphs
  2290.     add    ax,2            ; + 1 for descriptor + 1 for MCB
  2291.     add    dx,ax            ; total number of paras
  2292.     cmp    swap_prep.first_mcb,0
  2293.     jne    prep_walk_next
  2294.     mov    swap_prep.first_mcb,es
  2295. ;
  2296. prep_walk_next:
  2297.     cmp    es:id,4dh        ; normal block?
  2298.     jne    prep_mcb_ready        ; ready if end of chain
  2299.     mov    ax,es
  2300.     add    ax,es:paras        ; start + length
  2301.     inc    ax            ; next MCB
  2302.     jmp    prep_mcb_walk
  2303. ;
  2304. prep_mcb_ready:
  2305.     mov    totparas,dx
  2306.     mov    swap_prep.total_mcbs,si
  2307. ;
  2308. ;
  2309.     test    pmethod,XMS_FIRST
  2310.     jnz    check_xms
  2311. ;
  2312. ;    Check for EMS swap
  2313. ;
  2314. check_ems:
  2315.     test    pmethod,USE_EMS
  2316.     jz    prep_no_ems
  2317. ;
  2318.     push    ds
  2319.     mov    al,EMM_INT
  2320.     mov    ah,35h
  2321.     int    21h            ; get EMM int vector
  2322.     mov    ax,cs
  2323.     mov    ds,ax
  2324.     mov    si,offset emm_name
  2325.     mov    di,10
  2326.     mov    cx,8
  2327.     repz cmpsb            ; EMM name present?
  2328.     pop    ds
  2329.     jnz    prep_no_ems
  2330. ;
  2331.     mov    ah,40h            ; get EMS status
  2332.     int    EMM_INT
  2333.     or    ah,ah            ; EMS ok?
  2334.     jnz    prep_no_ems
  2335. ;
  2336.     mov    ah,46h            ; get EMS version
  2337.     int    EMM_INT
  2338.     or    ah,ah            ; AH must be 0
  2339.     jnz    prep_no_ems
  2340. ;
  2341.     cmp    al,30h            ; >= version 3.0?
  2342.     jb    prep_no_ems
  2343. ;
  2344.     mov    ah,41h            ; Get page frame address
  2345.     int    EMM_INT
  2346.     or    ah,ah
  2347.     jnz    prep_no_ems
  2348. ;
  2349. ;    EMS present, try to allocate pages
  2350. ;
  2351.     mov    swap_prep.ems_pageframe,bx
  2352.     mov    bx,totparas
  2353.     add    bx,ems_paramask
  2354.     mov    cl,ems_shift
  2355.     shr    bx,cl
  2356.     mov    ah,43h            ; allocate handle and pages
  2357.     int    EMM_INT
  2358.     or    ah,ah            ; success?
  2359.     jnz    prep_no_ems
  2360. ;
  2361. ;    EMS pages allocated, swap to EMS
  2362. ;
  2363.     mov    swap_prep.handle,dx
  2364.     mov    ax,USE_EMS
  2365.     mov    swap_prep.swapmethod,al
  2366.     ret
  2367. ;
  2368. ;    No EMS allowed, or EMS not present/full. Try XMS.
  2369. ;
  2370. prep_no_ems:
  2371.     test    pmethod,XMS_FIRST
  2372.     jnz    check_file        ; don't try again
  2373. ;
  2374. check_xms:
  2375.     test    pmethod,USE_XMS
  2376.     jz    prep_no_xms
  2377. ;
  2378.     mov    ax,4300h        ; check if XMM driver present
  2379.     int    2fh
  2380.     cmp    al,80h            ; is XMM installed?
  2381.     jne    prep_no_xms
  2382.     mov    ax,4310h        ; get XMM entrypoint
  2383.     int    2fh
  2384.     mov    word ptr swap_prep.xmm,bx    ; save entry address
  2385.     mov    word ptr swap_prep.xmm+2,es
  2386. ;
  2387.     mov    dx,totparas
  2388.     add    dx,xms_paramask        ; round to nearest multiple of 1k
  2389.     mov    cl,xms_shift
  2390.     shr    dx,cl            ; convert to k
  2391.     mov    ah,9            ; allocate extended memory block
  2392.     call    swap_prep.xmm
  2393.     or    ax,ax
  2394.     jz    prep_no_xms
  2395. ;
  2396. ;    XMS block allocated, swap to XMS
  2397. ;
  2398.     mov    swap_prep.handle,dx
  2399.     mov    ax,USE_XMS
  2400.     mov    swap_prep.swapmethod,al
  2401.     ret
  2402. ;
  2403. ;    No XMS allowed, or XMS not present/full. Try File swap.
  2404. ;
  2405. prep_no_xms:
  2406.     test    pmethod,XMS_FIRST
  2407.     jz    check_file
  2408.     jmp    check_ems
  2409. ;
  2410. check_file:
  2411.     test    pmethod,USE_FILE
  2412.     jnz    prep_do_file
  2413.     jmp    prep_no_file
  2414. ;
  2415. prep_do_file:
  2416.     push    ds
  2417. ;    IF    ptrsize
  2418. ;    lds    dx,swapfname
  2419. ;    ELSE
  2420.     mov    dx,OFFSET SwapFileName
  2421. ;    ENDIF
  2422.     mov    cx,2            ; hidden attribute
  2423.     test    pmethod,HIDE_FILE
  2424.     jnz    prep_hide
  2425.     xor    cx,cx            ; normal attribute
  2426. ;
  2427. prep_hide:
  2428.     mov    ah,3ch            ; create file
  2429.     test    pmethod,CREAT_TEMP
  2430.     jz    prep_no_temp
  2431.     mov    ah,5ah
  2432. ;
  2433. prep_no_temp:
  2434.     int    21h            ; create/create temp
  2435.     jnc    prep_got_file
  2436.     cmp    ax,3        ; see if path not found (bad TEMP setting)
  2437.     jne    prep_no_file
  2438.     mov    ah,19h        ; get current disk
  2439.     int    21h
  2440.     add    al,'A'        ; convert to ASCII drive
  2441.     mov    bx,dx
  2442.     mov    BYTE PTR ds:[bx],al    ; default to current drive root
  2443.     mov    BYTE PTR ds:[bx+1],':'
  2444.     mov    BYTE PTR ds:[bx+2],'\'
  2445.     mov    BYTE PTR ds:[bx+3],0    ; zero out path name and retry
  2446. ;    mov    BYTE PTR ds:[bx],0    ; zero out path name and retry
  2447.     jmp    SHORT prep_hide
  2448. ;
  2449. prep_got_file:
  2450.     mov    bx,ax            ; handle
  2451. ;
  2452. ;    save the file name
  2453. ;
  2454.     pop    es
  2455.     push    es
  2456.     mov    di,offset swap_prep.sp_swapfilename
  2457.     mov    cx,81
  2458.     mov    si,dx
  2459.     rep movsb
  2460. ;
  2461.     pop    ds
  2462.     mov    swap_prep.handle,bx
  2463. ;
  2464. ;    preallocate the file
  2465. ;
  2466.     test    pmethod,NO_PREALLOC
  2467.     jnz    prep_noprealloc
  2468.     test    pmethod,CHECK_NET
  2469.     jz    prep_nonetcheck
  2470. ;
  2471. ;    check whether file is on a network drive, and don't preallocate
  2472. ;    if so. preallocation can slow down swapping significantly when
  2473. ;    running on certain networks (Novell)
  2474. ;
  2475.     mov    ax,440ah    ; check if handle is remote
  2476.     int    21h
  2477.     jc    prep_nonetcheck    ; assume not remote if function fails
  2478.     test    dh,80h        ; DX bit 15 set ?
  2479.     jnz    prep_noprealloc    ; remote if yes
  2480. ;
  2481. prep_nonetcheck:
  2482.     mov    dx,totparas
  2483.     mov    cl,4
  2484.     rol    dx,cl
  2485.     mov    cx,dx
  2486.     and    dx,0fff0h
  2487.     and    cx,0000fh
  2488.     sub    dx,1
  2489.     sbb    cx,0
  2490.     mov    si,dx            ; save
  2491.     mov    ax,4200h        ; move file pointer, absolute
  2492.     int    21h
  2493.     jc    prep_file_err
  2494.     cmp    dx,cx
  2495.     jne    prep_file_err
  2496.     cmp    ax,si
  2497.     jne    prep_file_err
  2498.     mov    cx,1            ; write 1 byte
  2499.     mov    ah,40h
  2500.     int    21h
  2501.     jc    prep_file_err
  2502.     cmp    ax,cx
  2503.     jne    prep_file_err
  2504. ;
  2505.     mov    ax,4200h        ; move file pointer, absolute
  2506.     xor    dx,dx
  2507.     xor    cx,cx            ; rewind to beginning
  2508.     int    21h
  2509.     jc    prep_file_err
  2510. ;
  2511. prep_noprealloc:
  2512.     mov    ax,USE_FILE
  2513.     mov    swap_prep.swapmethod,al
  2514.     ret
  2515. ;
  2516. prep_file_err:
  2517.     mov    ah,3eh            ; close file
  2518.     int    21h
  2519.     mov    dx,offset swap_prep.sp_swapfilename
  2520.     mov    ah,41h            ; delete file
  2521.     int    21h
  2522. ;
  2523. prep_no_file:
  2524.     mov    ax,-1
  2525.     mov    swap_prep.swapmethod,al
  2526.     ret
  2527. ;
  2528. prep_swap    endp
  2529. ;
  2530.  
  2531. COMMENT !
  2532. O_RUNX:
  2533.     pusha
  2534.     push    ds
  2535.     push    es
  2536.  
  2537.     mov    bx,SWAP_TEXT
  2538.     mov    ax,0ff06h
  2539.     int    31h
  2540.     jc    SwapErr
  2541.     push    ax        ; save -> swap routine data
  2542.     mov    es,ax
  2543.     mov    BYTE PTR es:[params],0    ; kill leftovers
  2544.  
  2545. ; get length of first passed parameter
  2546.     push    1
  2547.     call    __parclen
  2548.     add    sp,2
  2549.     or    ax,ax
  2550.     je    med3        ; zero length
  2551.  
  2552. ; get first parameter string in dx:ax
  2553.     push    1
  2554.     call    __parc
  2555.     add    sp,2
  2556.     pop    es
  2557.     push    es
  2558.     mov    di,OFFSET params    ; es:di -> parameter storage
  2559.     push    ds        ; save ds -> DGROUP
  2560.     mov    ds,dx
  2561.     mov    si,ax        ; ds:si -> character string
  2562.     mov    ax,'/'+256*'C'    ; put in /C for command.com, transient command
  2563.     stosw
  2564.     mov    al,' '
  2565.     stosb
  2566.  
  2567. xparamloop1:
  2568.     movsb
  2569.     cmp    BYTE PTR ds:[si-1],0    ; see if hit null terminator
  2570.     jne    xparamloop1
  2571.     pop    ds            ; restore ds -> DGROUP
  2572.  
  2573.     dec    di            ; make di -> null terminator in case of second parameter
  2574.  
  2575. ; get length of second passed parameter
  2576.     push    2
  2577.     call    __parclen
  2578.     add    sp,2
  2579.     or    ax,ax
  2580.     je    med3        ; zero length
  2581.  
  2582. ; get second parameter string in dx:ax
  2583.     push    2
  2584.     call    __parc
  2585.     add    sp,2
  2586.     mov    ds,dx
  2587.     mov    si,ax        ; ds:si -> character string
  2588.     pop    es
  2589.     push    es        ; es:di -> current position of stored string
  2590.     mov    al,' '
  2591.     stosb            ; put in space
  2592.  
  2593. xparamloop2:
  2594.     movsb
  2595.     cmp    BYTE PTR ds:[si-1],0    ; see if stored null terminator
  2596.     jne    xparamloop2
  2597.     jmp    SHORT med3
  2598. END COMMENT !
  2599.  
  2600. ;SWPRUNCMD:
  2601. ;OverLay:
  2602. CWSwap_:
  2603.  
  2604.  
  2605.     pushad
  2606.     push    ds
  2607.     push    es
  2608.     cld
  2609.  
  2610.  
  2611. ;**JW**
  2612. ;works upto here...
  2613. ;    pop    es
  2614. ;    pop    ds
  2615. ;    popa
  2616. ;    db 66h
  2617. ;    retf
  2618.  
  2619.  
  2620.     push    eax        ; save -> command
  2621.     mov    bx,SWAP_TEXT
  2622.     mov    ax,0ff06h
  2623.     int    31h
  2624. ;    jc    SwapErr
  2625.     push    ax        ; save -> swap routine data
  2626.     mov    es,ax
  2627.     mov    BYTE PTR es:[params],0    ; kill leftovers
  2628.  
  2629. ; get length of passed parameter
  2630. ;    push    1
  2631. ;    call    __parclen
  2632. ;    add    sp,2
  2633. ;    or    ax,ax
  2634. ;    je    med3        ; zero length
  2635.  
  2636. ; get parameter string in dx:ax
  2637. ;    push    1
  2638. ;    call    __parc
  2639. ;    add    sp,2
  2640. ;    mov    ds,dx
  2641. ;    mov    si,ax        ; ds:si -> character string
  2642.  
  2643.     pop    es
  2644.     pop    esi            ; ds:esi -> command
  2645.     push    es
  2646.  
  2647.     mov    di,OFFSET params    ; es:di -> parameter storage
  2648.     mov    al,'/'
  2649.     mov    ax,'/'+256*'C'    ; put in /C for command.com, transient command
  2650.     stosw
  2651.     mov    al,' '
  2652.     stosb
  2653.  
  2654. paramloop:
  2655.     mov    al,ds:[esi]
  2656.     mov    es:[di],al
  2657.     inc    esi
  2658.     inc    di
  2659.     cmp    BYTE PTR ds:[esi-1],0    ; see if stored null terminator
  2660.     jne    paramloop
  2661.  
  2662. med3:
  2663.     pop    ds            ; ds -> swap routine data
  2664. ASSUME    ds:SWAP_TEXT,es:SWAP_TEXT
  2665.  
  2666.     mov    AliasSelector,ds
  2667.     mov    IntVectorSelector,0
  2668.     mov    LowMemSelector,0
  2669.     mov    WedgeMemSelector,0
  2670.  
  2671.     xor    bh,bh
  2672.     mov    ah,3
  2673.     int    10h            ; ready cursor size, position, and shape
  2674.     mov    CursorSize,cx
  2675.     mov    CursorRowCol,dx
  2676.  
  2677. ; get selector for interrupt vector table
  2678.     mov    ax,0ff03h        ; GetSel
  2679.     int    31h
  2680.     jc    SwapErr
  2681.     xor    cx,cx            ; point selector at 0:0 for interrupt vectors
  2682.     mov    dx,cx
  2683.     mov    di,400h
  2684.     mov    si,cx
  2685.     mov    ax,0ff09h        ; SetSelDet
  2686.     int    31h
  2687.     mov    INTVectorSelector,bx    ; save selector
  2688.  
  2689. ; get protected mode PSP of program
  2690.     mov    ah,62h        ; get PSP
  2691.     int    21h
  2692.  
  2693.     mov    PMPSP,bx    ; save protected mode PSP
  2694.     mov    ds,bx        ; ds -> protected mode psp
  2695.  
  2696.     mov    ax,ds:[EPSP_RealENV]    ; real mode environment block pointer
  2697.     mov    es:EnvironmentPointer,ax
  2698.  
  2699.     mov    edx,ds:[EPSP_INTMem]    ; interrupt/exception vectors linear address
  2700.     mov    ax,0ff03h    ; GetSel
  2701.     int    31h
  2702.     jc    SwapErr
  2703.     mov    ecx,(256*6)+(32*6)+400h    ; selector limit
  2704.     mov    ax,0ff0ah    ; SetSelDet32
  2705.     int    31h
  2706.  
  2707.     mov    ds,bx        ; ds -> selector
  2708.     mov    si,(256*6)+(32*6)    ; si -> past protected mode interrupt and exception vectors
  2709.     mov    di,OFFSET INTVectorTable    ; es:di -> real mode vector table storage
  2710.     mov    cx,256
  2711.     rep    movsd        ; save real mode vector table
  2712.  
  2713. ; release interrupt/exception vectors selector
  2714.     mov    ax,0ff04h        ; RelSel
  2715.     int    31h
  2716.  
  2717.     push    es
  2718.     pop    ds
  2719.  
  2720. ; get/save memory allocation strategy
  2721.     mov    ax,5800h        ; get allocation strategy
  2722.     int    21h
  2723.     mov    AllocStrat,ax    ; save original strategy
  2724.  
  2725. ; change memory allocation strategy to last fit
  2726.     mov    ax,5801h        ; set allocation strategy
  2727.     mov    bx,2            ; use highest available block that fits
  2728.     int    21h
  2729.  
  2730. ; get wedge memory for EXEC'ing
  2731.     mov    bx,(WedgeSpace+15)/16
  2732.     mov    ax,0ff21h
  2733.     int    31h
  2734.     jnc    savewedge
  2735.     pushf                ; setup stack so restore strategy still works properly
  2736.     push    ax
  2737.     jmp    NEAR PTR restalloc    ; error in dos allocation
  2738.  
  2739. ; save the wedge memory segment and selector
  2740. savewedge:
  2741. ;    mov    RealRegs.Real_FS,ax    ; save real mode segment of wedge memory
  2742. ; alternate save real mode segment of wedge memory into bx since NT doesn't restore FS properly
  2743.     mov    WORD PTR RealRegs.Real_EBX,ax
  2744.  
  2745.     mov    WedgeMemSelector,dx
  2746.  
  2747. ; copy wedge code to wedge segment
  2748.     mov    es,dx
  2749.     xor    di,di
  2750.     mov    si,OFFSET WedgeStart
  2751.     mov    cx,WedgeSpace
  2752.     push    cx
  2753.     shr    cx,2
  2754.     rep    movsd
  2755.     pop    cx
  2756.     and    cx,3
  2757.     rep    movsb
  2758.  
  2759.     push    ds
  2760.     pop    es
  2761.  
  2762. ; track if DPMI or non-, to determine where MCB is in relation to allocation
  2763.     mov    ax,0ff00h
  2764.     int    31h
  2765.     and    di,8            ; mask to DPMI bit
  2766.     mov    WORD PTR RealRegs.Real_EDX,di    ; save real mode flag
  2767.  
  2768. ; get DOS memory for moving code down for real mode execution
  2769.     mov    bx,(((OFFSET CodeEnd-OFFSET CodeStart)+15))/16    ; amount of low memory needed
  2770.     mov    ax,0ff21h
  2771.     int    31h
  2772.     pushf                ; save allocation error code
  2773.     push    ax            ; save segment
  2774.  
  2775. ; restore memory allocation strategy to original
  2776. restalloc:
  2777.     mov    ax,5801h        ; set allocation strategy
  2778.     mov    bx,AllocStrat    ; use highest available block that fits
  2779.     int    21h
  2780.  
  2781.     pop    ax                ; restore segment
  2782.     popf                ; restore allocation error code
  2783.     jnc    GotMemory
  2784.  
  2785. ; error using swapper
  2786. SwapErr:
  2787.     mov    ax,SWAPPERERROR
  2788.     mov    WORD PTR es:RealRegs.Real_EAX,ax    ; get return value
  2789.     jmp    NEAR PTR Done
  2790.  
  2791. ; got low DOS memory for code/data transfer, ax == segment, dx == selector
  2792. ; transfer code down to it
  2793. GotMemory:
  2794.     mov    WORD PTR RealRegs.Real_EAX,SWAPPERERROR    ; init return value
  2795.     mov    RealRegs.Real_CS,ax    ; save real mode segment
  2796.     mov    RealRegs.Real_IP,OFFSET NowInReal    ; transfer address in low memory
  2797.     mov    es,dx        ; es -> low memory selector
  2798.     mov    LowMemSelector,dx
  2799.     xor    di,di
  2800.     mov    si,OFFSET CodeStart
  2801.     mov    ax,(OFFSET CodeEnd-OFFSET CodeStart)
  2802.     mov    cx,ax
  2803.     shr    cx,2
  2804.     rep    movsd
  2805.     mov    cx,ax
  2806.     and    cx,3
  2807.     rep    movsb
  2808.     push    ds
  2809.     pop    es                ; es -> swap data
  2810.  
  2811.  
  2812. ;**JW**
  2813. ;
  2814. ;INC exec counter.
  2815. ;
  2816.  
  2817. ;    int    3
  2818.  
  2819.     mov    ah,62h        ; get PSP
  2820.     int    21h
  2821.  
  2822.     push    ds
  2823.     mov    ds,bx        ; ds -> protected mode psp
  2824.     lds    bx,ds:[EPSP_ExecCount]
  2825.     inc    byte ptr[bx]
  2826.     pop    ds
  2827.  
  2828. ; transfer to low DOS memory real mode operation
  2829.     mov    edi,OFFSET RealRegs    ; es:[e]di -> real mode register structure
  2830. ;    mov    ax,0ff02h    ; FarCallReal
  2831. ;    int    31h
  2832.  
  2833.  
  2834. ;**JW**
  2835. ;
  2836. ;Have to use DPMI far call function now because we've shut off CauseWay specific
  2837. ;functions.
  2838. ;
  2839.     mov    ax,301h
  2840.     xor    cx,cx
  2841.     xor    bx,bx
  2842.     mov    es:word ptr[di+Real_SP],0
  2843.     mov    es:word ptr[di+Real_SS],0
  2844.  
  2845.     int    31h
  2846.  
  2847. ;**JW**
  2848. ;
  2849. ;DEC exec counter.
  2850. ;
  2851. RestoreExecCount:
  2852.     mov    ah,62h        ; get PSP
  2853.     int    21h
  2854.     push    ds
  2855.     mov    ds,bx        ; ds -> protected mode psp
  2856.     lds    bx,ds:[EPSP_ExecCount]
  2857.     dec    byte ptr[bx]
  2858.     pop    ds
  2859.  
  2860. ; real mode code will return here
  2861. ; stack holds return value
  2862. Done:
  2863.     xor    bh,bh
  2864.     mov    dx,cs:CursorRowCol
  2865.     mov    ah,2            ; set cursor position
  2866.     int    10h
  2867.     mov    cx,cs:CursorSize
  2868.     mov    ah,1            ; set cursor size and shape
  2869.     int    10h
  2870.  
  2871.     mov    di,WORD PTR cs:RealRegs.Real_EAX    ; get return value
  2872.     mov    bx,cs:AliasSelector    ; release aliased selector
  2873.     or    bx,bx
  2874.     je    Adios
  2875.     mov    ax,0ff04h        ; RelSel
  2876.     int    31h
  2877.     mov    bx,cs:INTVectorSelector    ; release interrupt vector selector
  2878.     or    bx,bx
  2879.     je    Adios
  2880.     mov    ax,0ff04h        ; RelSel
  2881.     int    31h
  2882.     mov    dx,cs:WedgeMemSelector    ; release wedge memory
  2883.     or    dx,dx
  2884.     je    Adios
  2885.     mov    ax,0ff23h        ; RelMemDOS
  2886.     int    31h
  2887.     mov    dx,cs:LowMemSelector    ; release low memory
  2888.     or    dx,dx
  2889.     je    Adios
  2890.     mov    ax,0ff23h        ; RelMemDOS
  2891.     int    31h
  2892.  
  2893. Adios:
  2894.     pop    es
  2895.     pop    ds
  2896. ;    push    di
  2897. ;    xor    ah,ah
  2898. ;    or    di,di
  2899. ;    sete    al
  2900. ;    push    ax
  2901. ;    call    __retni    ; return value as integer to clipper
  2902. ;    add    sp,2        ; get return value off of stack
  2903.     popad
  2904.  
  2905. ;**JW**
  2906. ;Need to do a 32-bit far return to match the call.
  2907.     db 66h
  2908.  
  2909.     retf
  2910.  
  2911. ; this part is executing in low DOS memory real mode
  2912. ; fs -> wedge memory segment
  2913. ; dl is nonzero if DPMI environment
  2914. NowInReal    =    $
  2915. ;    DB    66h
  2916. ;    retf
  2917.  
  2918. ;    nop
  2919. ;    nop
  2920. ;    int    3
  2921.  
  2922.     mov    fs,bx        ; wedge memory segment to fs (NT bug workaround)
  2923.  
  2924. ; swap original interrupt vector table with current
  2925.     cli
  2926.     mov    cx,256
  2927.     push    cs
  2928.     pop    ds
  2929.     xor    di,di
  2930.     mov    es,di            ; es:di -> interrupt vector table
  2931.     mov    si,OFFSET IntVectorTable
  2932.  
  2933. vectloop:
  2934.     mov    eax,ds:[si]
  2935.     xchg    eax,es:[di]
  2936.     add    di,4
  2937.     mov    ds:[si],eax
  2938.     add    si,4
  2939.     loop    vectloop
  2940.     sti
  2941.  
  2942.     push    cs
  2943.     pop    es
  2944.  
  2945. ; reset mouse driver
  2946.     xor    ax,ax
  2947.     int    33h
  2948.  
  2949. ;    int    3
  2950.  
  2951. ; save DPMI flag status
  2952.     mov    DPMIFlag,dl
  2953.  
  2954. ; get real mode PSP of program
  2955.     mov    ah,62h        ; get PSP
  2956.     int    21h
  2957.     mov    PSP,bx
  2958.  
  2959. ; seek out EXE pathspec from environment block
  2960.     mov    ds,bx        ; ds -> PSP
  2961.     mov    ax,ds:[2ch]    ; get original PSP environment pointer
  2962.     mov    es:PSPEnvironPtr,ax    ; save original PSP environment pointer
  2963.     mov    ax,es:EnvironmentPointer
  2964.     mov    ds:[2ch],ax    ; update PSP environment pointer
  2965.     mov    ds,ax        ; ds -> real mode PSP environment block
  2966.     xor    si,si        ; ds:si -> start of environment
  2967.  
  2968. endloop:
  2969.     lodsb            ; get environment char
  2970.     or    al,ds:[si]    ; merge in next char
  2971.     jne    endloop        ; not at end of environment block
  2972.     add    si,3        ; si -> start of EXE file path
  2973.     mov    di,si        ; save -> start
  2974.     xor    bx,bx        ; init end of char pointer
  2975.  
  2976. pathloop:
  2977.     lodsb            ; get char of file path
  2978.     or    al,al        ; see if at end
  2979.     je    calcpath    ; yes
  2980.     cmp    al,'\'        ; see if directory indicator
  2981.     jne    pathloop    ; no
  2982.     mov    bx,si        ; save -> char past directory
  2983.     jmp    SHORT pathloop
  2984.  
  2985. calcpath:
  2986.     mov    si,di        ; ds:si -> start of file path
  2987.     mov    di,OFFSET SwapFileName    ; es:di -> swap file name slot
  2988.     or    bx,bx        ; see if any path
  2989.     je    calcdone    ; no
  2990.  
  2991. calcloop:
  2992.     movsb
  2993.     cmp    si,bx        ; see if at end of path
  2994.     jne    calcloop    ; no
  2995.  
  2996. calcdone:
  2997.     push    es
  2998.     pop    ds            ; ds -> swap data
  2999.  
  3000. ; search environment variable directories for TEMP setting
  3001. ; override EXE Name SwapFileName if exists
  3002.     mov    bx,OFFSET TEMPText    ; ds:bx -> string to match
  3003.  
  3004. ; see if environment variable is present
  3005.     xor    si,si
  3006.     mov    es,EnvironmentPointer    ; es:si -> environment block strings
  3007.  
  3008. t_sevscan:
  3009.     xor    di,di            ; offset into target string to match
  3010.  
  3011. t_matchloop:
  3012.     lods    BYTE PTR es:[0]    ; get byte from environment string
  3013.     cmp    al,ds:[bx+di]    ; see if matches target
  3014.     je    t_bytematch        ; yes
  3015.     or    al,es:[si]        ; two zero values in a row mean end of environment
  3016.     jne    t_sevscan            ; no target match, more chars left
  3017.     jmp    SHORT getcomspec    ; end of environment, no match, search failed
  3018.  
  3019. ; check that environment string match is not part of another environment string
  3020. t_bytematch:
  3021.     or    di,di            ; di is zero if matching first char
  3022.     jne    t_sevnext            ; not matching first char
  3023.     cmp    si,1            ; si==1 if first string in environment block
  3024.     je    t_sevnext            ; first string, not a part of another string by definition
  3025.     cmp    BYTE PTR es:[si-2],0    ; char before environment string in block must be nonzero
  3026.     jne    t_sevscan            ; nonzero, subset of another string, keep scanning for match
  3027.  
  3028. t_sevnext:
  3029.     inc    di                ; match, move to next byte of target
  3030.     cmp    di,5            ; check if all bytes matched
  3031.     jb    t_matchloop        ; not yet
  3032.  
  3033.     mov    di,OFFSET SwapFileName    ; di will -> TEMP SwapFilePrefix
  3034.  
  3035. t_transloop:
  3036.     lods    BYTE PTR es:[0]    ; get path character
  3037.     cmp    al,';'            ; see if terminator character
  3038.     je    t_namedone        ; yes, name complete
  3039.     cmp    al,' '            ; whitespace also terminates
  3040.     jbe    t_namedone
  3041.     mov    ds:[di],al        ; save path character
  3042.     inc    di                ; bump name storage slot
  3043.     jmp    SHORT t_transloop
  3044.  
  3045. t_namedone:
  3046.     cmp    di,OFFSET SwapFileName    ; see if any path
  3047.     je    t_nullit        ; no
  3048.     mov    al,'\'
  3049.     cmp    BYTE PTR ds:[di-1],al    ; see if backslash terminated
  3050.     je    t_nullit        ; yes
  3051.     mov    ds:[di],al        ; must be backslash terminated
  3052.  
  3053. t_nullit:
  3054.     xor    al,al            ; null terminate temporary file name
  3055.     mov    ds:[di],al
  3056.  
  3057. ;    int    3
  3058.  
  3059. ; get COMSPEC setting for execfname
  3060. getcomspec:
  3061.     xor    si,si
  3062. ;    mov    es,PSP
  3063. ;    mov    es,es:[2ch]        ; es:si -> environment block strings
  3064.     mov    es,EnvironmentPointer    ; es:si -> environment block strings
  3065.  
  3066. sevscan:
  3067.     mov    bx,OFFSET COMSPECText
  3068.     xor    di,di
  3069.  
  3070. matchloop:
  3071.     lods    BYTE PTR es:[0]    ; get byte from environment string
  3072.     cmp    al,ds:[bx+di]        ; see if matches target
  3073.     je    bytematch        ; yes
  3074.     or    al,es:[si]        ; two zero values in a row mean end of environment
  3075.     je    med2            ; end of environment, no match, search failed
  3076.     jmp    SHORT sevscan    ; no target match, more chars left
  3077.  
  3078. ; check that environment string match is not part of another environment string
  3079. bytematch:
  3080.     or    di,di            ; di is zero if matching first char
  3081.     jne    sevnext            ; not matching first char
  3082.     cmp    si,1            ; si==1 if first string in environment block
  3083.     je    sevnext            ; first string, not a part of another string by definition
  3084.     cmp    BYTE PTR es:[si-2],0    ; char before environment string in block must be nonzero
  3085.     jne    sevscan            ; nonzero, subset of another string, keep scanning for match
  3086.  
  3087. sevnext:
  3088.     inc    di                ; match, move to next byte of target
  3089.     cmp    di,8            ; check if all bytes matched (all extension are four chars)
  3090.     jb    matchloop        ; not yet
  3091.  
  3092.     mov    di,OFFSET execfname    ; di will -> exec'ing name with path
  3093.  
  3094. transloop:
  3095.     lods    BYTE PTR es:[0]    ; get path character
  3096.     cmp    al,';'            ; see if terminator character
  3097.     je    namedone        ; yes, name complete
  3098.     cmp    al,' '            ; whitespace also terminates
  3099.     jbe    namedone
  3100.     mov    ds:[di],al        ; save path character
  3101.     inc    di                ; bump name storage slot
  3102.     jmp    SHORT transloop
  3103.  
  3104. namedone:
  3105.     xor    al,al            ; null terminate COMSPEC
  3106.     mov    ds:[di],al
  3107.  
  3108. med2:
  3109.  
  3110. ; copy low memory save (original code) to wedge segment storage
  3111.     push    fs
  3112.     pop    es
  3113.     mov    di,WedgeSave-WedgeStart    ; es:di -> wedge storage
  3114.     mov    si,WEDGEOFFSET
  3115.     mov    ds,PSP        ; ds:si -> low memory save
  3116.     mov    cx,savespace-(WEDGEOFFSET-5ch)+3    ; bytes to copy
  3117.     push    cx
  3118.     shr    cx,2
  3119.     rep    movsd
  3120.     pop    cx
  3121.     and    cx,3
  3122.     rep    movsb
  3123.  
  3124.     mov    ax,cs
  3125.     mov    ds,ax
  3126.     mov    es,ax
  3127.     mov    pmethod,4184h
  3128.     mov    swapping,1
  3129. ;    mov    swapping,0
  3130.     call    prep_swap
  3131.     cmp    swap_prep.swapmethod,0ffh    ; see iferror opening temporary file
  3132.     jne    noterr
  3133.  
  3134.     mov    ax,SWAPPERERROR
  3135.     jmp    SHORT restevp    ; error, don't continue
  3136.  
  3137. noterr:
  3138.     call    do_spawn
  3139.  
  3140. ; restore original environment pointer in real mode PSP
  3141. restevp:
  3142.     push    cs
  3143.     pop    ds
  3144.     mov    ax,PSPEnvironPtr    ; ax holds original environment pointer value
  3145.     mov    ds,PSP        ; ds -> real mode PSP
  3146.     mov    ds:[2ch],ax    ; restore PSP environment pointer
  3147.  
  3148. ; restore interrupt vector table, ax holds return code
  3149.     mov    cx,256
  3150.     push    cs
  3151.     pop    ds
  3152.     xor    di,di
  3153.     mov    es,di            ; es:di -> interrupt vector table
  3154.     mov    si,OFFSET IntVectorTable
  3155.     cli
  3156.     rep    movsd            ; restore interrupt vector table
  3157.     sti
  3158.  
  3159.     retf                ; return to protected mode code
  3160. ENDP
  3161.  
  3162. ; wedge code
  3163. WedgeSpace    EQU    WedgeStackEnd-WedgeStart
  3164. WedgeStart:
  3165.     pop    WORD PTR cs:[CallerOffset-WedgeStart]    ; save return address
  3166.     pop    WORD PTR cs:[CallerSegment-WedgeStart]
  3167.     mov    cs:[OriginalStackOff-WedgeStart],sp    ; save stack and set to new
  3168.     mov    cs:[OriginalStackSeg-WedgeStart],ss
  3169.     mov    ax,cs
  3170.     mov    ss,ax
  3171.     mov    sp,WedgeStackEnd-WedgeStart
  3172.  
  3173. ; swap wedge storage (original code) with low memory (new code)
  3174.     push    ds
  3175.     push    es
  3176.     mov    ds,cs:[CallerSegment-WedgeStart]
  3177.     mov    si,WEDGEOFFSET
  3178.     mov    di,WedgeSave-WedgeStart    ; fs:di -> wedge storage
  3179. ;    mov    cx,(savespace-(WEDGEOFFSET-5ch)+3)/4    ; bytes to swap
  3180.     mov    cx,savespace-(WEDGEOFFSET-5ch)        ; bytes to swap
  3181.  
  3182. wedgeloop:
  3183. ;    mov    eax,ds:[si]
  3184. ;    xchg    eax,fs:[di]
  3185. ;    add    di,4
  3186. ;    mov    ds:[si],eax
  3187. ;    add    si,4
  3188. ;    loop    wedgeloop
  3189.  
  3190.     mov    al,ds:[si]
  3191.     xchg    al,fs:[di]
  3192.     inc    di
  3193.     mov    ds:[si],al
  3194.     inc    si
  3195.     dec    cx
  3196.     jne    wedgeloop
  3197.  
  3198.     pop    es
  3199.     pop    ds
  3200.  
  3201.     mov    ax,4b00h            ; do the exec
  3202.     int    21h
  3203.  
  3204.     mov    ax,cs
  3205.     mov    ss,ax
  3206.     mov    sp,WedgeStackEnd-WedgeStart
  3207.  
  3208. ; copy wedge storage (new code) to low memory
  3209.     push    cs
  3210.     pop    ds
  3211.     mov    si,WedgeSave-WedgeStart    ; ds:si -> wedge storage
  3212.     mov    es,cs:[CallerSegment-WedgeStart]
  3213.     mov    di,WEDGEOFFSET    ; es:di -> low memory save
  3214. ;    mov    cx,savespace-(WEDGEOFFSET-5ch)+3    ; bytes to copy
  3215.     mov    cx,savespace-(WEDGEOFFSET-5ch)    ; bytes to copy
  3216.     push    cx
  3217.     shr    cx,2
  3218.     rep    movsd
  3219.     pop    cx
  3220.     and    cx,3
  3221.     rep    movsb
  3222.  
  3223.     mov    ss,cs:[OriginalStackSeg-WedgeStart]    ; restore stack to original
  3224.     mov    sp,cs:[OriginalStackOff-WedgeStart]
  3225.  
  3226. ; transfer back to low memory
  3227.     jmp    DWORD PTR cs:[CallerOffset-WedgeStart]
  3228.  
  3229.     OriginalStackOff    DW    ?
  3230.     OriginalStackSeg    DW    ?
  3231.     CallerOffset    DW    ?
  3232.     CallerSegment    DW    ?
  3233. WedgeSave    DB    savespace-(WEDGEOFFSET-5ch)+3 DUP (?)
  3234. EVEN
  3235.     DB    256 DUP (?)        ; wedge stack
  3236. WedgeStackEnd    =    $-1
  3237.  
  3238. ; constant data
  3239. COMSPECText    DB    'COMSPEC='
  3240. TEMPText    DB    'TEMP='
  3241.  
  3242. ; initialized data
  3243. LowMemSelector    DW    0    ; selector for accessing low memory
  3244. WedgeMemSelector    DW    0    ; selector for accessing wedge memory
  3245. ReturnValue    DW    0    ; return value from swap
  3246. AllocStrat    DW    0        ; memory allocation strategy
  3247. SwapFileName    DB    81 DUP (0)
  3248.  
  3249. ; uninitialized data
  3250. AliasSelector    DW    ?    ; alias data selector for code writes
  3251. EnvironmentPointer    DW    ?    ; real mode environment block pointer
  3252. INTVectorSelector    DW    ?    ; selector for accessing interrupt vector table
  3253. ;PSP        DW    ?        ; real mode PSP
  3254. SwapFileHandle    DW    ?    ; swap file handle
  3255. CursorSize    DW    ?        ; saved cursor size
  3256. CursorRowCol    DW    ?    ; saved cursor row and column
  3257.  
  3258. RealRegsStruc struc
  3259. Real_EDI    dd ?    ;EDI
  3260. Real_ESI    dd ?    ;ESI
  3261. Real_EBP    dd ?    ;EBP
  3262.         dd ?    ;Reserved.
  3263. Real_EBX    dd ?    ;EBX
  3264. Real_EDX    dd ?    ;EDX
  3265. Real_ECX    dd ?    ;ECX
  3266. Real_EAX    dd ?    ;EAX
  3267. Real_Flags    dw ?    ;FLAGS
  3268. Real_ES    dw ?    ;ES
  3269. Real_DS    dw ?    ;DS
  3270. Real_FS    dw ?    ;FS
  3271. Real_GS    dw ?    ;GS
  3272. Real_IP    dw ?    ;IP
  3273. Real_CS    dw ?    ;CS
  3274. Real_SP    dw ?    ;SP
  3275. Real_SS    dw ?    ;SS
  3276. RealRegsStruc ends
  3277.  
  3278. RealRegs    RealRegsStruc    <>
  3279. ;Now the extended PSP structure.
  3280. EPSP_Struc        struc
  3281.         db 256 dup (?)
  3282.  EPSP_Parent        dw ?        ;Selector of parent/previous PSP, 0 for none.
  3283.  EPSP_Next        dw ?        ;Next PSP.
  3284.  EPSP_Resource    dd ?        ;Linear address of resource tracking table. 0
  3285.                 ;for none.
  3286.  EPSP_mcbHead    dd ?        ;Linear address of MCB memory head. 0 for none.
  3287.  EPSP_mcbMaxAlloc    dd ?        ;Size of MCB chunks.
  3288.  EPSP_DTA        df ?        ;DTA address.
  3289.  EPSP_TransProt    dw ?        ;Transfer buffer address.
  3290.  EPSP_TransReal    dw ?        ;Transfer buffer real mode segment value.
  3291.  EPSP_TransSize    dd ?        ;Transfer buffer size.
  3292.  EPSP_SSESP        df ?        ;Return SS:ESP to use.
  3293.  EPSP_INTMem        dd ?        ;linear address of interrupt/exception vector
  3294.                 ;save buffer. 0 for none.
  3295.  EPSP_DPMIMem    dw ?        ;selector for DPMI state save buffer. 0 for
  3296.                 ;none.
  3297.  EPSP_MemBase    dd ?        ;Program linear load address.
  3298.  EPSP_MemSize    dd ?        ;Program memory size.
  3299.  EPSP_SegBase    dw ?        ;Base program selector.
  3300.  EPSP_SegSize    dw ?        ;Number of program selectors.
  3301.  
  3302.  EPSP_NearBase    dd ?        ;NEAR function address translation base.
  3303.  
  3304.  EPSP_RealENV    dw ?        ;Original real mode environment SEGMENT.
  3305.  
  3306.  EPSP_NextPSP    dd ?        ;Pointer to next PSP
  3307.  EPSP_LastPSP    dd ?        ;Pointer to last PSP
  3308.  
  3309.  EPSP_Exports    dd ?        ;Pointer to export list.
  3310.  EPSP_Imports    dd ?        ;Pointer to import list.
  3311.  
  3312.  EPSP_Links        dd ?        ;Count of linked modules.
  3313.  
  3314.  EPSP_ExecCount    dd ?        ;PMode pointer to exec counter.
  3315.  
  3316. EPSP_Struc        ends
  3317.  
  3318. INTVectorTable    DD    256 DUP (?)    ; interrupt vector table storage
  3319.  
  3320. CodeEnd    =    $
  3321.  
  3322. ENDS
  3323.  
  3324. END
  3325.