home *** CD-ROM | disk | FTP | other *** search
/ Power-Programmierung / CD2.mdf / c / library / dos / memory / sspawn / sspawn.asm < prev   
Encoding:
Assembly Source File  |  1993-12-12  |  17.4 KB  |  532 lines

  1. COMMENT ~
  2. /*-------------------------------------------------------------------------+
  3. | Module: SSPAWN.ASM                                                       |
  4. | Project: TOOLS                                                           |
  5. | Author: Paul A. Penrose                                                  |
  6. |         (c) 1993, 4D Interactive Systems, Inc.  All Rights Reserved.     |
  7. | Purpose:                                                                 |
  8. |   This module contains the code that will swap the current program to EMS|
  9. |   or a disk file and then load COMMAND.COM to execute the command passed |
  10. |   by the caller.  To assure that the maximum amount of memory is         |
  11. |   available to execute the command, place this module in the link just   |
  12. |   after the startup module (first in the project file).  Special thanks  |
  13. |   to Ray Duncan for his book "MSDOS Programming", and Andrew Schulman    |
  14. |   for his book "Undocumented DOS".  Both books were indispensable aids   |
  15. |   when writing this code.                                                |
  16. |                                                                          |
  17. |--- History --------------------------------------------------------------|
  18. | When        Who           What                                           |
  19. | 25 Jan 93   P. Penrose    Initial creation.                              |
  20. | 11 Dec 93   P. Penrose    Prepare for Freeware release.                  |
  21. +-------------------------------------------------------------------------*/ ~
  22.  
  23. IDEAL
  24.  
  25. MODEL HUGE,C
  26.  
  27. P286N
  28.  
  29. EXTRN   _psp:word
  30.  
  31. CODESEG
  32.  
  33. STRUC exec_pb
  34.    environment  DW ?
  35.    cmdline      DD ?
  36.    fcb1         DD ?
  37.    fcb2         DD ?
  38. ENDS
  39.  
  40. STRUC MCB
  41.    type         DB ?
  42.    owner        DW ?
  43.    size         DW ?
  44.    unused       DB 3 dup (?)
  45.    dos4         DB 8 dup (?)
  46. ENDS
  47.  
  48. stkseg          DW ?
  49. stkptr          DW ?
  50. newstk          DW 128 dup (?)
  51. ourmcb          DW ?
  52. handle          DW ?
  53. pageframe       DW ?
  54. pagenum         DW ?
  55. count           DW ?
  56. srcseg          DW ?
  57. keep            DW ?
  58. orgsize         DW ?
  59. retval          DW ?
  60. prgname         DB 128 dup (?)
  61. command         DB 128 dup (?)
  62. fcb1            DB 0
  63.                 DB 11 dup (' ')
  64.                 DB 25 dup (0)
  65. fcb2            DB 0
  66.                 DB 11 dup (' ')
  67.                 DB 25 dup (0)
  68. cmdcom          DB 'COMSPEC=',0
  69. ems_device_name DB 'EMMXXXX0', 0
  70. filespec        DB 128 dup (0)
  71. errmsg1         DB 'ERROR: Unable to recover original memory.',0DH,0AH,'$'
  72. errmsg2         DB 'ERROR: Unable to restore program from disk.',0DH,0AH,'$'
  73. copyright       DB 'SSPAWN is (c) 1993, 4D Interactive Systems, Inc.',0
  74. exec_parms      exec_pb ?
  75.  
  76.  
  77. PROC    sspawn
  78.         ARG     cmd:DWORD
  79.         ARG     path:DWORD
  80.  
  81.         push    ds              ;Save caller's state
  82.         push    si
  83.         push    di
  84.         cld
  85. ;
  86. ; First we need to copy the command passed by the caller into the command
  87. ; tail that will be used when we call EXEC.  If the address is NULL or the
  88. ; string is empty (first char is 0), then the command tail length is set to
  89. ; zero and just a command shell is spawned.
  90. ;
  91.         push    cs
  92.         pop     es
  93.         mov     di,offset command       ;Set up command tail to COMMAND.COM
  94.         xor     al,al                   ;Initially put nothing in it
  95.         stosb
  96.         lds     si,[cmd]                ;Get pointer to command
  97.         mov     ax,ds                   ;Get Segment
  98.         or      ax,si                   ;Is it NULL?
  99.         jz      get_cmdcom
  100.         mov     al,[si]                 ;Is it an empty string?
  101.         or      al,al
  102.         jz      get_cmdcom
  103.         mov     al,'/'                  ;Put "/C " into command tail
  104.         stosb
  105.         mov     al,'C'
  106.         stosb
  107.         mov     al,' '
  108.         stosb
  109.         mov     cx,124                  ;Maximum length of command tail
  110. copy_cmd:
  111.         lodsb                           ;append cmd to command tail
  112.         or      al,al
  113.         jz      cmd_copied
  114.         stosb
  115.         loop    copy_cmd
  116. cmd_copied:
  117.         mov     al,13                   ;append C/R
  118.         stosb
  119.         mov     ax,127                  ;Calc length
  120.         sub     ax,cx
  121.         mov     [cs:command],al
  122.  
  123. ;
  124. ; Now we need to search through the environment strings and find out where
  125. ; COMMAND.COM is located.  We need this to pass to EXEC to spawn a command
  126. ; shell.
  127. ;
  128. get_cmdcom:
  129.         push    cs
  130.         pop     ds
  131.         mov     ax,SEG _psp
  132.         mov     es,ax
  133.         mov     ax,[es:_psp]            ;Get our PSP segment
  134.         mov     es,ax
  135.         dec     ax
  136.         mov     [ourmcb],ax
  137.         mov     ax,[es:002CH]           ;Get segment of environment
  138.         mov     [exec_parms.environment],ax
  139.         mov     es,ax
  140.         xor     di,di                   ;Start search at beginning of env
  141. genv1:
  142.         mov     si,offset cmdcom        ;Init pointer to name to find
  143.         cmp     [byte ptr es:di],0      ;End of environment?
  144.         jne     genv2
  145.         mov     ax,8001H
  146.         jmp     error
  147. genv2:
  148.         lodsb                           ;get char from name
  149.         or      al,al                   ;end of name?
  150.         jz      copy_cmdcom
  151.         cmp     al,[es:di]              ;next char the same?
  152.         jne     genv3                   ;not the one, goto next
  153.         inc     di
  154.         jmp     genv2                   ;keep comparing
  155. genv3:
  156.         xor     al,al                   ;scan forward to start of next string
  157.         mov     cx,0FFFFH               ;  in the environment table
  158.         repnz   scasb
  159.         jmp     genv1
  160. copy_cmdcom:
  161.         push    es                      ;swap seg regs
  162.         pop     ds
  163.         push    cs
  164.         pop     es
  165.         mov     si,di
  166.         mov     di,offset prgname
  167. nextchar:
  168.         lodsb                           ;Get char from environment string
  169.         or      al,al
  170.         stosb
  171.         jnz     nextchar                ;Continue if not done
  172. ;
  173. ; Next we need to save everything after this module through the end of our
  174. ; allocated memory space to EMS if there is enough, or a temporary disk file.
  175. ;
  176.         push    cs
  177.         pop     ds
  178.         mov     ax,[ourmcb]             ;Point to our MCB
  179.         mov     es,ax
  180.         xor     bx,bx
  181.         mov     cx,[es:(MCB ptr bx).size] ;Get our mem size in paragraphs
  182.         mov     [orgsize],cx            ;save it for restoring later
  183.         mov     ax,offset last_addr     ;calc the number of paragraphs to save
  184.         shr     ax,4
  185.         mov     bx,ax
  186.         mov     ax,cs
  187.         add     ax,bx
  188.         mov     [srcseg],ax             ;save starting paragraph
  189.         sub     ax,[ourmcb]
  190.         mov     [keep],ax               ;save amount to keep when we spawn
  191.         dec     ax                      ;account for MCB
  192.         sub     cx,ax                   ;cx = number of paragraphs
  193.         mov     [count],cx              ;save count
  194. ;
  195. ; First check to see if there is an EMS driver loaded
  196. ;
  197.         mov     ax,3D00H                ;Open file, read only
  198.         mov     dx,offset ems_device_name
  199.         int     21H
  200.         jnc     emsck1
  201.         jmp     use_file
  202. emsck1: mov     bx,ax
  203.         push    bx
  204.         mov     ax,4400H                ;Get device info
  205.         int     21H
  206.         pop     bx
  207.         jnc     emsck2
  208.         jmp     use_file
  209. emsck2: test    dx,0080H                ;Is it a device?
  210.         jnz     emsck3
  211.         jmp     ems_no_driver
  212. emsck3: push    bx
  213.         mov     ax,4407H                ;Is the device ready?
  214.         int     21H
  215.         pop     bx
  216.         or      al,al
  217.         jnz     emsck4
  218.         jmp     ems_no_driver
  219. emsck4: mov     ax,3E00H                ;Close the driver
  220.         int     21H
  221. ;
  222. ; Check the EMS version, if not 3.0 or greater, don't use EMS
  223. ;
  224.         mov     ah,46H
  225.         int     67H
  226.         cmp     al,30H
  227.         jge     emsck5
  228.         jmp     use_file
  229. ;
  230. ; Next get the pageframe and store it for later reference
  231. ;
  232. emsck5: mov     ah,41H
  233.         int     67H
  234.         mov     [pageframe],bx
  235.         or      ah,ah
  236.         jz      emsck6
  237.         jmp     use_file
  238. ;
  239. ; Now check to see if there is enough EMS to save our memory
  240. ;
  241. emsck6: mov     ah,42H
  242.         int     67H
  243.         mov     ax,[count]              ;convert count from paras to EMS pages
  244.         shr     ax,10
  245.         inc     ax
  246.         cmp     ax,bx
  247.         jle     emsck7
  248.         jmp     use_file
  249. ;
  250. ; Allocate the number of EMS pages we need and copy our memory to them
  251. ;
  252. emsck7: mov     bx,ax                   ;AX still has the number of pages
  253.         mov     ah,43H
  254.         int     67H
  255.         mov     [handle],dx
  256.         mov     ah,47H                  ;save mapping context
  257.         int     67H
  258.         push    [srcseg]                ;save so we can restore it later
  259.         push    [count]
  260.         mov     [pagenum],0
  261.         mov     ax,[pageframe]
  262.         mov     es,ax
  263. emsnextblock:
  264.         mov     ax,[cs:srcseg]          ;Point DS at next block of data
  265.         mov     ds,ax
  266.         mov     ax,[cs:count]           ;figure out how many paras to copy
  267.         or      ax,ax
  268.         jz      emsdone
  269.         cmp     ax,400H
  270.         jc      emsnb1
  271.         mov     ax,400H
  272. emsnb1: sub     [cs:count],ax
  273.         add     [cs:srcseg],ax
  274.         shl     ax,3                    ;calc number of words
  275.         mov     cx,ax
  276.         mov     bx,[cs:pagenum]         ;page in the next page
  277.         mov     dx,[cs:handle]
  278.         mov     ax,4400H
  279.         push    cx
  280.         int     67H
  281.         pop     cx
  282.         xor     di,di                   ;copy the data to the ems page
  283.         xor     si,si
  284.         repnz   movsw
  285.         inc     [cs:pagenum]
  286.         jmp     emsnextblock
  287. emsdone:
  288.         push    cs                      ;Restore DS
  289.         pop     ds
  290.         pop     [count]
  291.         pop     [srcseg]
  292.  
  293.         jmp     relmem
  294.  
  295. ems_no_driver:
  296.         mov  ax,3E00H                   ;Close the EMS driver & use a file
  297.         int  21H
  298. ;
  299. ; Now save the rest of the memory to a file
  300. ;
  301. use_file:
  302.         mov     [pageframe],0           ;flag that we did NOT use EMS
  303.         mov     [filespec],0
  304.         push    cs
  305.         pop     es
  306.         mov     di,offset filespec
  307.         lds     si,[path]               ;check for a swap path
  308.         mov     ax,ds
  309.         or      ax,si                   ;is it NULL?
  310.         jz      createfile
  311. copypath:
  312.         lodsb                           ;copy the path
  313.         or      al,al
  314.         stosb
  315.         jnz     copypath
  316. createfile:
  317.         push    cs
  318.         pop     ds
  319.         mov     ah,5AH                  ;Create temp file
  320.         xor     cx,cx
  321.         mov     dx,offset filespec
  322.         int     21H
  323.         jnc     save2file
  324.         mov     ax,8002H
  325.         jmp     error
  326. save2file:
  327.         mov     [handle],ax             ;save the handle
  328.         push    [srcseg]                ;save so we can restore it later
  329.         push    [count]
  330. nextblock:
  331.         mov     ax,[cs:srcseg]          ;Point DS at next block of data
  332.         mov     ds,ax
  333.         mov     ax,[cs:count]           ;figure out how many paras to write
  334.         or      ax,ax
  335.         jz      closefile
  336.         cmp     ax,800H
  337.         jc      nb1
  338.         mov     ax,800H
  339. nb1:    sub     [cs:count],ax
  340.         add     [cs:srcseg],ax
  341.         shl     ax,4                    ;calc number of bytes
  342.         mov     cx,ax
  343.         xor     dx,dx
  344.         mov     ah,40H
  345.         mov     bx,[cs:handle]
  346.         int     21H
  347.         jnc     nextblock
  348.         add     sp,4
  349.         mov     ax,8003H
  350.         jmp     error
  351. closefile:
  352.         push    cs                      ;Restore DS and close the file
  353.         pop     ds
  354.         pop     [count]
  355.         pop     [srcseg]
  356.         mov     bx,[handle]
  357.         mov     ah,3EH
  358.         int     21H
  359.         jnc     relmem
  360.         mov     ax,8004H
  361.         jmp     error
  362. ;
  363. ; The next thing we need to do is save the current stack pointer and segment
  364. ; and then reset it to our internal storage.  Then we resize our memory block
  365. ; to release all unused memory (which was just saved).
  366. ;
  367. relmem:
  368.         mov     ax,ss                   ;save the stack segment
  369.         mov     [stkseg],ax
  370.         mov     [stkptr],sp             ;save the stack pointer
  371.         cli                             ;reset the stack to our internal
  372.         mov     sp,offset newstk+256
  373.         mov     ax,cs
  374.         mov     ss,ax
  375.         sti
  376.         mov     ax,[ourmcb]
  377.         inc     ax
  378.         mov     es,ax
  379.         mov     ah,4AH                  ;resize our memory allocation
  380.         mov     bx,[keep]               ;  to get rid of everything not needed
  381.         int     21H
  382. ;
  383. ; Now spawn a command shell using the EXEC function
  384. ;
  385.         mov     [retval],0
  386.         mov     ax,offset command
  387.         mov     [word ptr exec_parms.cmdline],ax
  388.         mov     ax,offset fcb1
  389.         mov     [word ptr exec_parms.fcb1],ax
  390.         mov     ax,offset fcb2
  391.         mov     [word ptr exec_parms.fcb2],ax
  392.         mov     ax,cs
  393.         mov     [word ptr (exec_parms.cmdline)+2],ax
  394.         mov     [word ptr (exec_parms.fcb1)+2],ax
  395.         mov     [word ptr (exec_parms.fcb2)+2],ax
  396.         mov     es,ax
  397.         mov     dx,offset prgname
  398.         mov     bx,offset exec_parms
  399.         mov     ax,4B00H
  400.         int     21H
  401.         jnc     restmem
  402.         mov     [cs:retval],8005H
  403. ;
  404. ; Now resize the memory allocation to the original size and then restore the
  405. ; memory contents.
  406. restmem:
  407.         push    cs
  408.         pop     ds
  409.         mov     ax,[ourmcb]
  410.         inc     ax
  411.         mov     es,ax
  412.         mov     ah,4AH                  ;resize our memory allocation to the
  413.         mov     bx,[orgsize]            ;  original size before the spawn
  414.         int     21H
  415.         jnc     restmem2
  416.         mov     dx,offset errmsg1       ;could not get original memory back!
  417.         mov     ah,9                    ;   tell user
  418.         int     21H
  419.         mov     ax,4C01H
  420.         int     21H                     ;   and exit
  421. ;
  422. ; If we saved to EMS, then restore from there, else restore from the file
  423. ;
  424. restmem2:
  425.         test    [pageframe],0FFFFH      ;In EMS?
  426.         jz      restfile                ;If not, go restore from file
  427.         mov     [pagenum],0
  428.         mov     ax,[pageframe]          ;Get segment of EMS pageframe
  429.         mov     ds,ax
  430. emsreadblock:
  431.         mov     ax,[cs:srcseg]          ;Point ES at next block of data
  432.         mov     es,ax
  433.         mov     ax,[cs:count]           ;figure out how many paras to copy
  434.         or      ax,ax
  435.         jz      emsrdone
  436.         cmp     ax,400H                 ;If more than 16K left, then
  437.         jc      emsrb1
  438.         mov     ax,400H                 ;truncate to 16K
  439. emsrb1: sub     [cs:count],ax
  440.         add     [cs:srcseg],ax
  441.         shl     ax,3                    ;calc number of words
  442.         mov     cx,ax
  443.         mov     bx,[cs:pagenum]         ;page in the next page
  444.         mov     dx,[cs:handle]
  445.         mov     ax,4400H
  446.         push    cx
  447.         int     67H
  448.         pop     cx
  449.         xor     di,di                   ;copy the data from the ems page
  450.         xor     si,si
  451.         repnz   movsw
  452.         inc     [cs:pagenum]
  453.         jmp     emsreadblock            ;Go get the next block
  454. emsrdone:
  455.         push    cs                      ;Restore DS and release our EMS memory
  456.         pop     ds
  457.         mov     ah,48H                  ;  but first restore the mapping context
  458.         mov     dx,[handle]
  459.         int     67H
  460.         mov     ah,45H
  461.         int     67H
  462.         jmp     restmem5
  463.  
  464. restfile:
  465.         mov     ax,3D00H                ;open file
  466.         mov     dx,offset filespec
  467.         int     21H
  468.         jnc     restfile2
  469.         mov     dx,offset errmsg2       ;could not open swap file!
  470.         mov     ah,9                    ;  tell the user
  471.         int     21H
  472.         mov     ax,4C02H
  473.         int     21H                     ;  and exit
  474. restfile2:
  475.         mov     [handle],ax
  476. readblock:
  477.         mov     ax,[cs:srcseg]          ;Point DS at next block of data
  478.         mov     ds,ax
  479.         mov     ax,[cs:count]           ;figure out how many paras to read
  480.         or      ax,ax
  481.         jz      restmem4
  482.         cmp     ax,800H                 ;If more than 32K left, then
  483.         jc      rb1
  484.         mov     ax,800H                 ;truncate to 32K
  485. rb1:    sub     [cs:count],ax
  486.         add     [cs:srcseg],ax
  487.         shl     ax,4                    ;calc number of bytes
  488.         mov     cx,ax
  489.         xor     dx,dx
  490.         mov     ah,3FH
  491.         mov     bx,[cs:handle]
  492.         int     21H
  493.         jnc     readblock
  494.         mov     dx,offset errmsg2       ;file read error!
  495.         mov     ah,9                    ;  tell user
  496.         int     21H
  497.         mov     ax,4C03H
  498.         int     21H                     ;  and exit
  499. restmem4:
  500.         push    cs                      ;Restore DS and close the file
  501.         pop     ds
  502.         mov     bx,[handle]
  503.         mov     ah,3EH
  504.         int     21H
  505.         mov     ah,41H                  ;Delete the swap file
  506.         mov     dx,offset filespec
  507.         int     21H
  508. ;
  509. ; Finally restore the stack.
  510. ;
  511. restmem5:
  512.         cli
  513.         mov     ax,[stkseg]
  514.         mov     ss,ax
  515.         mov     sp,[stkptr]
  516.         sti
  517. ;
  518. ; Return to the caller
  519. ;
  520.         mov     ax,[retval]
  521. error:  pop     di
  522.         pop     si
  523.         pop     ds
  524.         ret
  525. ENDP
  526.  
  527. PUBLIC  sspawn
  528.  
  529. last_addr:
  530.  
  531. END
  532.