home *** CD-ROM | disk | FTP | other *** search
- ; SWAP - (c) Copyright 1988 Nico Mak and Mansfield Software Group
- ; All rights reserved
- ;
- ; To rebuild SWAP.COM use the following instructions:
- ; masm swap;
- ; link swap;
- ; exe2bin swap swap.com
- ;
- cr equ 13
- lf equ 10
-
- error macro message ;; macro to display an error message
- local around, msg, msglen ;; and to jump to error_exit routine
- jmp around
- msg db &message,cr,lf ;; define error message
- msglen equ $-msg
- around:
- mov dx,offset msg ;; get address of error message
- mov cx,msglen ;; get length
- jmp error_exit ;; jump to error exit routine
- endm
-
- ; -------------------------------------------------------------------
- ; the following is copied over the swappee
- ; -------------------------------------------------------------------
- code segment 'code'
- assume cs:code,ds:code
- org 100h ; org past psp
- swap proc near
- jmp begin
- db 20 dup('STACK')
- stack equ $
-
- flag db 0 ; option flag
- flag_copy equ 80h ; copy stdout to 'con'
- flag_force equ 40h ; swap even if vector points to swappee
- flag_quiet equ 20h ; don't print hello message
- flag_disk equ 10h ; swap to disk
-
- emsg_ems db "SWAP EMS Error "
- ems_rc db 'xx function '
- ems_func db 'xx',cr,lf
- emsg_ems_len equ $-emsg_ems
-
- my_psp dw ? ; segment of SWAP's original psp
- swappee_psp dw ? ; segment of swappee's psp
-
- ; variables used when swapping to expanded memory
- ems_handle dw ? ; emm handle
- swap_pages dw ? ; number of pages for ems_handle
- ems_frame dw ? ; ems page frame
- last_ems_func db ? ; last emm function issued by swap
-
- ; variables used when swapping to disk
- swap_fid db "c:\swap.dat",0 ; asciiz string to open swap file
- swap_handle dw ? ; handle while swap file is open
-
- ; fields for int 21 function 4b (exec)
- commandcom_addr dd ? ; address of program to exec (command.com)
- exec_sp dw ? ; save area for reg clobbered by exec function
- command_line db ?,"/c" ; command line for command.com
- command_text db 130 dup (0) ; command line continued
- blank_fcb db 36 dup (0) ; dummy fcb for exec function
- exec_parm_block equ $ ; exec parameter block
- exec_env dw ? ; segment addr of environment
- cmdline_addr dw offset command_line ; address of command line
- cmdline_seg dw ?
- dw offset blank_fcb ; address of fcb
- fcb1_seg dw ?
- dw offset blank_fcb ; address of fcb
- fcb2_seg dw ?
-
- ; fields used by int 21 handler
- save_pid dw ? ; pid at time int 21 handler received control
- int21_vector dd ? ; original int 21 vector owner
- con db "con",0 ; asciiz string to open console
- handle dw ? ; handle while "con" is open
- char_buf db ? ; buffer for int 21 function 2 and 6 handlers
- save_ax dw ? ; register save areas for int 21 handler
- save_bx dw ?
- save_cx dw ?
- save_dx dw ?
- save_ds dw ?
-
- ; -------------------------------------------------------------------
- ; run_command - the following code is copied over the swappee
- ; -------------------------------------------------------------------
- run_command:
- call copy_start ; start copying stdout to the console
- call exec_user_cmd ; execute the user's command
- call copy_stop ; stop copying stdout to the console
- call swap_in ; swap in all but first 16k
- retf
-
- ; -------------------------------------------------------------------
- ; subroutines for run_command follow
- ; -------------------------------------------------------------------
-
- ; -----
- ; copy_start - if -c option specified, open handle for console and hook int 21
- ; -----
- copy_start:
- test flag,flag_copy ; will we copy stdout to display?
- jz copy_start_ret ; no
- ; ----- open a handle that points to "con"
- mov dx,offset con ; address of asciiz file name
- mov ax,3d01h ; code to open handle for writing
- int 21h ; open the file
- mov handle,ax ; remember handle
- jnc open_worked ; did open succeed?
- and flag,255-flag_copy ; no, then we won't copy stdout ...
- jmp short copy_start_ret ; ... and won't hook int 21
- open_worked:
- ; ----- hook int 21 vector
- mov ax,3521h ; code to get interrupt 21 vector
- int 21h ; ask dos for address in vector
- mov word ptr int21_vector,bx; save offset
- mov word ptr int21_vector[2],es ; save segment
- mov dx,offset int21_handler ; address of our int 21 handler
- mov ax,2521h ; code to set interrupt 21 address
- int 21h ; tell dos to set int 21 vector
- ; ----- ensure that standard error is redirected and copied
- mov al,cs:[19h] ; get stdout file handle array entry
- mov cs:[1ah],al ; use stdout entry for stderr entry
- copy_start_ret:
- ret
-
- ; -----
- ; exec_user_cmd - set up and issue the int 21 function 4b (exec)
- ; -----
- exec_user_cmd:
- mov cs:exec_sp,sp ; save register
- mov ax,cs:[2ch] ; pass address of our environment
- mov exec_env,ax ; to exec function
- mov word ptr cmdline_seg,ds ; address of command line
- mov word ptr fcb1_seg,ds ; fill in segments for fcbs
- mov word ptr fcb2_seg,ds
- push cs
- pop es
- mov bx,offset exec_parm_block ; bx = exec parameter block
- lds dx,commandcom_addr ; es:bx = asciiz string of command.com
- mov ax,4b00h ; code to load and execute a program
- int 21h ; tell dos to execute the user's program
- mov ds,cs:swappee_psp ; restore ds addressability
- cli ; turn off interrupts
- mov ss,swappee_psp ; restore stack
- mov sp,exec_sp
- sti ; allow interrupts
- ret
-
- ; -----
- ; copy_stop - close handle and restore original int 21 vector
- ; -----
- copy_stop:
- test cs:flag,flag_copy ; did we copy stdout to display?
- jz copy_stop_ret ; no
- ; ----- close handle for console
- mov bx,handle ; close handle for 'con'
- mov ah,3eh ; dos function = close handle
- int 21h ; tell dos to close 'con'
- ; ----- restore original int 21 vector
- push ds ; ds gets clobbered, so save it
- lds dx,int21_vector ; get address of old int 21 vector
- mov ax,2521h ; code to set interrupt 21 address
- int 21h ; tell dos to change it
- pop ds ; restore ds addressability
- copy_stop_ret:
- ret
-
- ; -----
- ; swap_in - swap in all but the first page of swappee
- ; -----
- swap_in:
- mov bx,cs ; bx = swappee's psp
- add bx,3ffh ; first page to swap in over
- mov es,bx
- test flag,flag_disk
- jnz swap_in_disk
- ; ----- swap in from expanded memory
- mov cx,1 ; start with second logical page
- cld
- swap_in_page: ; loop to swap 16K
- mov bx,cx ; logical page
- call map_page
- push ds ; save ds
- mov ds,ems_frame ; ds = where to swap from
- mov si,0
- mov di,0
- push cx
- mov cx,4000h ; copy 16K
- rep movsb
- pop cx
- pop ds ; restore ds
- mov bx,es
- add bx,400h
- mov es,bx ; es = next place to swap to
- inc cx
- cmp cx,swap_pages
- jl swap_in_page
- ret
- ; ----- swap in from disk
- swap_in_disk: ; es = first page to swap over
- call open_swap_file ; open the swap file
- mov cx,0 ; high order part of offset
- mov dx,4000h ; file pointer to start + 16k
- mov bx,swap_handle ; get swap file handle
- mov ax,4201h ; code to lseek from current location
- int 21h ; tell dos to lseek to 2nd page
- jnc lseek_done
- error "LSEEK on swap file failed"
- lseek_done:
- mov cx,1 ; start with second logical page
- swap_in_disk_page: ; loop to swap 16K
- call read_swap_file ; read 16k from swap file
- mov bx,es
- add bx,400h
- mov es,bx ; es = next place to swap to
- inc cx
- cmp cx,swap_pages
- jl swap_in_disk_page
- call close_swap_file
- ret
-
- ; -------------------------------------------------------------------
- ; int_21_handler and its subroutines follow
- ; -------------------------------------------------------------------
- assume ds:nothing
- int21_handler:
- ; ----- decide whether we will front-end this int 21 function
- cmp ah,02h
- je func02
- cmp ah,06h
- je func06
- cmp ah,09h
- je func09
- cmp ah,40h
- je func40
- ; ----- call the original int 21 vector owner
- do_real_thing:
- jmp cs:int21_vector
-
- ; -----
- ; handle int 21 function 9 (print dollar-sign delimited string)
- ; -----
- func09:
- call front_start
- push di
- push es
- mov di,dx
- mov es,save_ds ; address of string at es:di
- mov al,'$' ; scan for $
- mov cx,-1 ; max bytes to scan
- cld ; scan in forward direction
- repne scasb ; find the $
- sub di,dx
- mov cx,di ; length to write
- dec cx ; don't write the $
- pop es
- pop di
- mov ds,save_ds ; ds addressability is blown
- call write_to_con ; write buffer to display
- mov ds,cs:swappee_psp ; restore ds addressability
- jmp front_done
-
- ; -----
- ; handle int 21 function 6 (direct console i/o)
- ; -----
- func06:
- cmp dl,0ffh ; get input characters?
- je do_real_thing ; yes, then there is no output to copy
-
- ; -----
- ; handle int 21 function 2 (display character in dl register)
- ; -----
- func02:
- call front_start
- mov char_buf,dl ; put character to write in buffer
- mov dx,offset char_buf ; get address of buffer
- mov cx,1 ; get length
- call write_to_con ; write buffer to display
- jmp front_done
-
- ; -----
- ; handle int 21 function 40 (write to file handle)
- ; -----
- func40:
- call front_start
- ; ----- verify that file handle array entry for this handle == stdout entry
- push di
- push es
- mov bx,save_bx ; get caller's handle
- mov es,save_pid ; psp for process issuing int 21
- les di,es:34h ; address of caller's file handle array
- mov ah,es:[di+1] ; file handle array entry for stdout
- cmp ah,es:[di+bx] ; does handle entry == stdout entry?
- pop es
- pop di
- jne func40_done ; no, don't copy to console
- ; ----- call real int 21 handler with handle opened for 'con'
- mov ds,save_ds ; ds addressability blown
- call write_to_con ; write buffer to display
- mov ds,cs:swappee_psp ; restore ds addressability
- func40_done:
- jmp front_done
-
- ; -----
- ; front_start - start front-ending int 21
- ; -----
- front_start:
- assume ds:nothing
- ; ----- establish ds addressability and save registers
- mov save_ds,ds
- mov ds,cs:swappee_psp ; establish ds addressability
- assume ds:code ; tell assembler
- mov save_ax,ax ; save registers
- mov save_bx,bx
- mov save_cx,cx
- mov save_dx,dx
- ; ----- remember caller's pid
- mov ah,51h ; dos function = get pid
- int 21h ; tell dos to get pid
- mov save_pid,bx ; remember pid
- ; ----- set pid so our file handle array is used
- mov bx,cs ; pid = my cs register
- mov ah,50h ; dos function = set pid
- int 21h ; tell dos to set pid
- ret
-
- ; -----
- ; write_to_con - call original int 21H handler to write buffer to display
- ; -----
- write_to_con:
- assume ds:nothing
- mov bx,cs:handle ; handle opened for 'con'
- mov ah,40h ; dos function = write to handle
- pushf
- call dword ptr cs:int21_vector ; call dos
- ret
-
- ; -----
- ; front_done - almost done front-ending int 21
- ; -----
- front_done:
- assume ds:code
- ; ----- restore caller's pid
- mov bx,save_pid ; get pid of process that issued int 21
- mov ah,50h ; dos function = set pid
- int 21h ; set pid
- ; ----- restore registers & go jump to previous int 21 handler
- mov ax,save_ax
- mov bx,save_bx
- mov cx,save_cx
- mov dx,save_dx
- mov ds,save_ds ; ds addressability blown
- jmp do_real_thing
-
- ; -------------------------------------------------------------------
- ; the following routines are used by both parts of the program
- ; -------------------------------------------------------------------
-
- ; -----
- ; emm - remember emm function in case of error and issue int 67
- ; -----
- emm:
- mov last_ems_func,ah
- int 67h ; call expanded memory manager
- or ah,ah
- ret
-
- ; -----
- ; ems_error - handle ems errors
- ; -----
- ems_error:
- mov di,offset ems_rc
- call hex_to_ascii ; make ems error code printable
- mov ah,last_ems_func
- mov di,offset ems_func
- call hex_to_ascii ; make last ems function printable
- mov cx,emsg_ems_len
- mov dx,offset emsg_ems
- jmp error_exit ; go display error message and exit
-
- ; ------
- ; hex_to_ascii - convert ah register contents to ascii hexadecimal at ds:di
- ; ------
- hex_to_ascii:
- mov dl,ah
- mov cx,2
- hex_char:
- push cx
- mov cl,4
- rol dl,cl
- mov al,dl
- and al,00fh
- daa
- add al,0f0h
- adc al,040h
- mov [di],al
- inc di
- pop cx
- loop hex_char
- ret
-
- ; -----
- ; error_exit - display error message and exit
- ; ds:dx point to error message, cx has the length
- ; -----
- error_exit:
- push cx
- push dx
- mov dx,offset emsg_start
- mov cx,emsg_start_len
- mov bx,2 ; handle for stderr
- mov ah,40h ; dos function = handle write
- int 21h ; output error message to stderr
- pop dx
- pop cx
- mov bx,2 ; handle for stderr
- mov ah,40h ; dos function = handle write
- int 21h ; output error message to stderr
- jmp return
-
- ; -----
- ; routines to open, read from, and close the swap file
- ; -----
- open_swap_file:
- mov dx,offset swap_fid ; address of fileid to open
- mov ax,3d00h ; open file in read-only mode
- int 21h
- jnc open_exit
- error "Could not open swap file"
- open_exit:
- mov swap_handle,ax
- ret
-
- ; read_swap_file - read 16K from swap file to address in es:0
- ; saves cx
- read_swap_file:
- push cx
- mov bx,swap_handle ; get swap file handle
- mov cx,4000h ; read 16k
- mov dx,0 ; buffer offset
- push ds
- push es
- pop ds ; buffer segment
- mov ah,3fh ; dos function = handle read
- int 21h
- pop ds
- pop cx
- jnc read_exit
- error "Error reading swap file"
- read_exit:
- ret
-
- close_swap_file:
- mov bx,swap_handle ; get swap file handle
- mov ah,3eh ; dos function = close file
- int 21h
- ret
-
- ; -----
- ; return - return to DOS
- ; -----
- return:
- mov ax,4c00h ; dos function to terminate
- int 21h ; back to dos
-
- ; -----
- ; map_page - map EMS logical page in bx into physical page 0
- ; -----
- map_page:
- mov al,0 ; physical page
- mov dx,ems_handle ; ems handle
- mov ah,44h ; map handle page
- call emm
- jz map_page_exit
- jmp ems_error
- map_page_exit:
- ret
-
- lowend equ $ ; end of code copied to lower memory
-
- ; -------------------------------------------------------------------
- ; the following is *not* copied on top of the swappee
- ; -------------------------------------------------------------------
-
- hello db cr, lf, "SWAP Version 1.0 Copyright (c) 1988 Nico Mak"
- db " and Mansfield Software Group", cr, lf
- hello_len equ $-hello
- emsg_start db "SWAP Error: "
- emsg_start_len equ $-emsg_start
- run_addr dw offset run_command ; offset of run_command
- run_seg dw ? ; segment of run_command
- swappee_mcb dw ? ; segment of mcb for swappee psp
- swappee_end dw ? ; segment of mcb after swappee
- my_mcb_size dw ?
- next_mcb dw ? ; address of next mcb
- next_code db ? ; M/Z code in next MCB
- next_owner dw ? ; etc
- next_size dw ? ;
- ems_device_name db "EMMXXXX0",0 ; expanded memory manager signature
- comspec db 'COMSPEC=' ; environment variable name
- comspec_len equ $-comspec
-
- mcb_info struc ; important memory control block info
- addr dw ? ; address of mcb
- owner dw ? ; psp of owner
- len dw ? ; length of mcb
- mcb_info ends
-
- max_mcbs equ 100
- mcbs mcb_info <>
- mcb_length equ $-mcbs
- db (max_mcbs-1)*mcb_length dup (?)
-
- ; -------------------------------------------------------------------
- ; mainline code run from system prompt
- ; -------------------------------------------------------------------
- begin:
- assume ds:code,es:code
- mov sp,offset stack ; set up new stack pointer
- call say_hello ; print copyright message
- call process_cmdline ; check options, set up 'exec' cmdline
- call check_dos_version ; ensure we have dos 3.0 or later
- call find_comspec ; find comspec= in environment
- call shrink_ourself ; free unneeded memory
- call get_mcb_info ; get relevant info about mcbs
- call check_mcbs ; ensure mcbs are in expected order
- call vector_check ; ensure swappee has not hooked vectors
- call figure_pages ; determine how many ems pages we need
- call init_ems ; ems initialization, allocation, etc
- call swap_out ; swap out swappee, command.com, and us
- call muck_with_memory ; copy swap over swappee & set up mcbs
- mov ss,swappee_psp ; switch to stack in low memory
- call run_user_command ; go call run_command rtn in low memory
- mov ss,my_psp ; switch back to original stack
- call swap_first ; swap in first 16K
- call clean_up ; restore original environment
- exit:
- jmp return ; leave SWAP
-
- ; -------------------------------------------------------------------
- ; subroutines for code that is not copied to low memory follow
- ; -------------------------------------------------------------------
-
- ; -----
- ; process_cmdline - process options, set up command line for exec function
- ; -----
- process_cmdline:
- mov bx,80h
- option_check:
- inc bx
- cmp byte ptr [bx],cr ; carriage return?
- jne option_check2 ; no
- error "No command to execute"
- option_check2:
- cmp byte ptr [bx],' ' ; blank?
- je option_check
- cmp byte ptr [bx],'/' ; option signal?
- je got_option
- cmp byte ptr [bx],'-' ; option signal?
- jne copy_command_line
- got_option:
- mov byte ptr [bx],' ' ; blank out character on command line
- inc bx ; point at option
- mov al,byte ptr [bx] ; get option
- mov byte ptr [bx],' ' ; blank out character on command line
- or al,' ' ; convert option to lower case
- cmp al,'c' ; option 'c'?
- jne check_option_q
- or flag,flag_copy
- jmp option_check
- check_option_q:
- cmp al,'q' ; option 'q'?
- jne check_option_f
- or flag,flag_quiet
- jmp option_check
- check_option_f:
- cmp al,'f' ; option 'f'?
- jne check_option_d
- or flag,flag_force
- jmp option_check
- check_option_d:
- cmp al,'d' ; option 'd'?
- jne bad_option
- or flag,flag_disk
- jmp option_check
- bad_option:
- error "Invalid option"
- ; ----- copy remainder of our command line to command line for command.com
- copy_command_line:
- mov cl,ds:[80h] ; length of my command line
- inc cl ; add one for cr
- mov si,81h ; address of my command line
- mov di,offset command_text ; address of where to put it
- xor ch,ch ; zero uninitialized part of count
- cld ; scan in forward direction
- rep movsb ; copy command line
- ; set length of new command line
- mov cl,ds:[80h] ; length of my command line
- add cl,2 ; add 2 for "/c"
- mov command_line,cl ; save new length
- ret
-
- ; -----
- ; say_hello - print hello message
- ; -----
- say_hello:
- test flag,flag_quiet ; was -q option used?
- jnz say_hello_exit ; yes, skip this
- mov dx,offset hello ; get address of message
- mov cx,hello_len ; get length of message
- mov bx,2 ; handle for stderr
- mov ah,40h ; dos function = write to handle
- int 21h ; write copyright message
- say_hello_exit:
- ret
-
- ; -----
- ; check_dos_version - be sure this is dos 3.0 or higher
- ; -----
- check_dos_version:
- mov ah,30h ; dos function = get version
- int 21h ; get dos version
- cmp al,3 ; ok?
- jae dos_version_ret
- error "DOS version must be 3.0 or higher"
- dos_version_ret:
- ret
-
- ; -----
- ; find_comspec - find fileid for exec function
- ; -----
- find_comspec:
- mov es,es:2ch ; es = environment segment
- xor di,di ; point to start of env in es:di
- cld ; scan in forward direction
- ; ----- loop thru environment strings one by one, beginning here
- find_string:
- test byte ptr es:[di],-1 ; end of environment?
- jnz check_string ; nope, continue
- error "Could not find COMSPEC= in environment" ; very unlikely
- ; ----- compare current env string to 'COMSPEC='
- check_string:
- mov si,offset comspec ; point to 'COMSPEC=' string
- mov bx,di ; save ptr to start of env string
- mov cx,comspec_len ; length of 'COMSPEC='
- repe cmpsb ; compare
- je found_comspec ; found it
- mov di,bx ; restore ptr to start of env string
- xor al,al ; scan for end of string
- mov cx,-1
- repne scasb
- jmp find_string ; go back for next string
- ; ----- found COMSPEC=
- found_comspec:
- mov word ptr commandcom_addr[0],di ; remember address of ...
- mov word ptr commandcom_addr[2],es ; ... asciiz "command.com"
- ret
-
- ; -----
- ; shrink_ourself - release unneeded memory
- ; -----
- shrink_ourself:
- push cs
- pop es ; address of start of SWAP memory
- mov bx,offset endcode+15 ; address of end of SWAP code
- mov cl,4
- shr bx,cl ; convert to paragraphs
- mov ah,4ah ; dos function = SETBLOCK
- int 21h ; shrink ourselves
- ret
-
- ; -----
- ; get_mcb_info - get relevant info from mcb chain
- ; -----
- get_mcb_info:
- mov my_psp,cs ; remember address of our PSP
- mov ah,52h ; undocumented function
- int 21h ; get base of memory chain
- mov es,es:[bx]-2 ; this is it
- mov bx,offset mcbs
- mov dx,0 ; count of MCBs
- mem_loop:
- mov [bx].addr,es
- mov cx,word ptr es:1 ; owner of mcb
- mov [bx].owner,cx
- mov cx,word ptr es:3 ; length of mcb
- mov [bx].len,cx
- inc dx ; increment count of MCBs
- cmp dx,max_mcbs
- jle mem_loop1
- error "Over 100 Memory Control Blocks in system"
- mem_loop1:
- cmp byte ptr es:0,'Z' ; last memory block?
- jne mem_next
- error "Could not find SWAP's PSP"
- mem_next:
- mov cx,es ; copy seg addr of mcb
- inc cx ; next paragraph
- cmp cx,my_psp ; is this our psp?
- je found_our_psp ; yes
- add cx,[bx].len ; add length of this mcb
- mov es,cx ; this is next memory block
- add bx,mcb_length ; where next mcb goes
- jmp mem_loop ; proceed
- found_our_psp: ; have found our psp
- mov dx,[bx].len
- mov my_mcb_size,dx ; remember length of our mcb
- add cx,[bx].len ; add length of memory
- mov next_mcb,cx ; this is next memory block
- ; ----- remember information about the next mcb
- mov es,cx
- mov dl,es:0
- mov next_code,dl
- mov dx,es:1
- mov next_owner,dx
- mov dx,es:3
- mov next_size,dx
- ret
-
- ; -----
- ; check_mcbs - ensure mcbs are in expected order
- ; verify that our parent is command.com, find swappee psp, etc.
- ; -----
- check_mcbs:
- mov cx,cs:16h ; our parent's address
- mov es,cx
- mov ax,es:16h ; and our grandparent's address
- cmp ax,cx ; better be equal
- jne unknown_parent
- mov ax,cs:10h ; our ctrl-break handler
- cmp ax,cx ; better equal our parent's address
- je skip_our_env
- unknown_parent:
- error "SWAP not directly run from COMMAND.COM"
- ; ----- back up to find swappee's mcb. bx still points at entry for our mcb
- skip_our_env:
- mov cx,cs
- call prev_mcb
- cmp [bx].owner,cx ; is this mcb for our environment?
- jne skip_command
- call prev_mcb
- ; ----- back up over all mcb's owned by command.com (es == command.com psp)
- skip_command:
- mov cx,es ; address of command.com psp
- cmp [bx].owner,cx ; is this mcb owned by command.com?
- je command_loop ; yes
- error "COMMAND.COM must immediately precede SWAP in memory"
- command_loop:
- mov dx,[bx].addr ; remember address of mcb in case
- mov swappee_end,dx ; it is the one above swappee
- call prev_mcb ; back up one mcb
- cmp [bx].owner,cx ; is this mcb owned by command.com?
- je command_loop ; yes, skip it
- ; ----- assume we have one of swappee's mcbs
- ; back up over all it's mcb's till we reach psp
- mov cx,[bx].owner ; cx = swappee's psp
- find_swappee_psp:
- mov dx,[bx].addr ; address of this mcb
- inc dx ; address of memory
- cmp dx,cx ; is this swappee's psp?
- je found_swappee_psp ; yes
- call prev_mcb ; check previous psp
- cmp [bx].owner,cx ; still owned by swappee?
- je find_swappee_psp ; yes continue
- error "Unexpected MCB while looking for PSP of swappee"
- ; ----- we've found swappee's psp - bx points at mcb entry for swappee
- found_swappee_psp:
- mov es,[bx].owner ; es = swappee's psp
- mov swappee_psp,es ; remember swappee's psp
- cmp word ptr es:2ch,0 ; swappee must have an environment
- jne check_mcbs_ret
- error "Swappee does not have an environment"
- check_mcbs_ret:
- ret
-
- ; -----
- ; unless the -f option was specified, check whether vectors point at swappee
- ; note: only interrupts 1-79h (inclusive) are checked
- ; -----
- vector_check:
- test flag,flag_force
- jnz vector_check_ret
- mov cx,0 ; start at the beginning
- next_vector:
- inc cx ; next vector
- cmp cx,80h ; all done?
- jae vector_check_ret ; yes, no vectors hooked
- mov ah,35h ; get vector function
- mov al,cl ; vector number
- int 21h ; call dos to get vector address
- mov dx,es ; get segment addr
- push cx
- mov cl,4 ; shift count
- add bx,15 ; round up
- shr bx,cl ; divide offset by 16
- pop cx
- add dx,bx ; compute segment
- cmp swappee_psp,dx ; compare to start of swappee
- jae next_vector ; no problem, keep looking
- cmp dx,swappee_end ; compare to end of swappee
- jae next_vector ; no problem either
- error "Swappee has hooked an interrupt vector"
- vector_check_ret:
- ret
-
- ; -----
- ; figure_pages - figure how many 16K pages of EMS we need
- ; -----
- figure_pages:
- mov cx,swappee_psp
- dec cx ; cx = swappee's mcb
- mov swappee_mcb,cx ; remember address of mcb
- mov dx,next_mcb ; dx = mcb after swap.com
- sub dx,cx ; dx = difference in paragraphs
- mov cx,10
- shr dx,cl ; convert paragraphs to 16k pages
- or dx,dx
- jnz figure2
- error "Less than 16K to swap"
- figure2:
- inc dx
- mov swap_pages,dx
- ret
-
- ; -----
- ; init_ems - ensure ems is up to par, allocate pages, and save page map
- ; -----
- init_ems:
- test flag,flag_disk
- jz find_emm
- jmp init_ems_exit
- ; ----- determine whether ems is installed
- find_emm:
- mov ax,3567h ; code to get int 67 handler address
- int 21h ; get interrupt vector
- mov di,0ah ; offset to name string
- mov si,offset ems_device_name ; correct ems name
- mov cx,8 ; length of name
- cld ; scan in forward direction
- repe cmpsb ; do the compare
- jz test_status ; ems not loaded
- error "Could not find Expanded Memory Manager"
- ; ----- test ems status
- test_status:
- mov ah,40h ; code to test status
- call emm
- jz check_ems_version
- jmp ems_error
- ; ----- ensure that we have ems version 3.2 or later
- check_ems_version:
- mov ah,46h ; get version
- call emm
- jz got_ems_version
- jmp ems_error
- got_ems_version:
- cmp al,32h
- jnb get_page_frame
- error "Expanded Memory Manager version must be 3.2 or higher"
- ; ----- get page frame address
- get_page_frame:
- mov ah,41h ; code to get page frame addr
- call emm
- mov ems_frame,bx ; where ems memory starts
- jz alloc_pages
- jmp ems_error
- ; ----- allocate ems pages
- alloc_pages:
- mov ah,43h
- mov bx,swap_pages
- call emm
- mov ems_handle,dx
- jz save_page_map
- error "Not enough free expanded memory"
- ; ----- save ems page map
- save_page_map:
- mov ah,47h ; save page map
- mov dx,ems_handle
- call emm
- jz init_ems_exit
- jmp ems_error
- init_ems_exit:
- ret
-
- ; -----
- ; swap_out - swap out swappee, command.com, and ourself
- ; -----
- swap_out:
- mov es,swappee_mcb
- test flag,flag_disk ; swap to disk?
- jnz swap_out_disk ; yes
- ; ----- swap out to expanded memory
- mov cx,0
- cld
- swap_out_page: ; loop to swap 16K
- mov bx,cx ; logical page = loop count
- call map_page
- mov bx,ems_frame
- assume ds:nothing
- push es
- pop ds ; ds = where to swap from
- mov es,bx ; es = ems_frame
- mov si,0
- mov di,0
- push cx
- mov cx,4000h ; copy 16K
- rep movsb
- pop cx
- mov bx,ds ; where to swap from
- add bx,400h ; add 16K
- mov es,bx ; es = next place to swap from
- push cs
- pop ds
- assume ds:code
- inc cx
- cmp cx,swap_pages ; done swapping?
- jl swap_out_page ; no, swap the next page
- ret
- ; ----- swap out to disk
- swap_out_disk: ; es = swappee's mcb
- mov cx,0 ; attribute
- mov dx,offset swap_fid
- mov ah,3ch ; dos function = create a file
- int 21h
- jnc create_done
- error "Could not create swap file"
- create_done:
- mov swap_handle,ax
- mov cx,0 ; number of pages swapped
- swap_out_disk_page: ; loop to swap 16K
- push cx ; remember number pages swapped
- mov bx,swap_handle ; handle to write to
- mov cx,04000h ; write 16k
- xor dx,dx ; offset to write from
- push ds
- push es
- pop ds ; segment to write from
- mov ah,40h ; dos function = write to handle
- int 21h
- pop ds
- jnc write_worked1
- error "Error writing to swap file"
- write_worked1:
- mov bx,es ; where to swap from
- add bx,400h ; add 16K
- mov es,bx ; es = next place to swap from
- pop cx ; remember number of pages swapped
- inc cx ; now we've swapped one more page
- cmp cx,swap_pages ; done swapping?
- jl swap_out_disk_page ; no, swap the next page
- call close_swap_file
- ret
-
- ; -----
- ; muck_with_memory - copy part of SWAP over swappee's psp, set up mcbs, etc
- ; -----
- muck_with_memory:
- mov es,swappee_psp
- ; ----- copy code over swappee's psp
- cld ; copy in forward direction
- mov cx,offset lowend ; length of code to copy
- mov si,100h ; start copying after psp
- mov di,100h ; where to copy
- rep movsb ; copy code over swappee's psp
- ; ----- copy our file handle array down to swappee's psp
- mov cx,20 ; length of file handle table
- mov si,18h ; address of our file handle table
- mov di,18h ; where to put file handle table
- rep movsb ; copy file handle table to swappee psp
- ; ----- set the file handle array size and offset in swappee's psp
- mov word ptr es:32h,20 ; length of file handle table
- mov word ptr es:34h,18h ; offset of file handle table
- mov word ptr es:36h,es ; segment of file handle table
- ; ----- now fix up the swappee's mcb (still has an M)
- mov es,swappee_mcb ; address of swappee's mcb
- mov dx,offset lowend+15 ; offset to end of SWAP code
- mov cx,4
- shr dx,cl ; convert to paragraphs
- mov word ptr es:3,dx ; put result in swappee's mcb
- ; ----- find address of mcb for memory that was freed up
- mov bx,swappee_psp ; address of swappee's psp
- add bx,dx ; add paragraphs in swappee's mcb
- mov es,bx ; this is where mcb for free mem goes
- ; ----- fill in new mcb
- mov dx,next_mcb ; address of mcb after original swap
- sub dx,bx ; compute paragraphs of free space
- add dx,next_size ; add paragraphs for next mcb
- mov word ptr es:3,dx ; fill in size
- mov dl,next_code ; get id from next mcb
- mov byte ptr es:0,dl ; copy id (M or Z)
- mov word ptr es:1,0 ; mark block as free
- ret
-
- ; -----
- ; run_user_command - call run_command routine in low memory
- ; -----
- run_user_command:
- ; ----- put swappee segment address into pointer to run_command
- mov bx,swappee_psp
- mov word ptr run_seg,bx ; segment of swappee psp
- ; ----- set pid to address of swappee psp
- mov ah,50h ; dos function = set pid
- int 21h ; set process id
- ; ----- call run_command in low memory
- mov ds,bx
- assume ds:nothing
- call dword ptr cs:run_addr ; call run_command
- mov ds,cs:my_psp
- assume ds:code
- ; ----- restore pid to SWAP's psp
- mov bx,cs ; pid = my cs register
- mov ah,50h ; code to set pid
- int 21h
- ret
-
- ; -----
- ; swap_first - swap in first page that was swapped out
- ; -----
- swap_first:
- mov es,swappee_mcb
- test flag,flag_disk ; swapping in from disk?
- jnz swap_first_disk ; yes
- ; ----- swap in from expanded memory
- mov bx,0 ; logical page = 0
- call map_page
- push ds ; save ds
- mov ds,ems_frame ; ds = where to swap from
- mov si,0
- mov di,0
- mov cx,4000h ; copy 16K
- cld
- rep movsb
- pop ds ; restore ds
- ret
- ; ----- swap in from disk
- swap_first_disk:
- call open_swap_file
- call read_swap_file
- call close_swap_file
- ret
-
- ; -----
- ; clean_up - restore ems or delete swap file
- ; -----
- clean_up:
- test flag,flag_disk
- jnz clean_up_disk
- ; ----- restore ems page map
- mov ah,48h ; restore page map
- mov dx,ems_handle
- call emm
- jz deallocate
- jmp ems_error
- ; ----- deallocate the ems pages
- deallocate:
- mov ah,45h ; deallocate pages
- mov dx,ems_handle
- call emm
- jz clean_up_exit
- jmp ems_error
- ; ----- delete swap disk file
- clean_up_disk:
- mov dx,offset swap_fid ; file handle for swap file
- mov ah,41h ; code to delete a file
- int 21h
- clean_up_exit:
- ret
-
- ; -----
- ; prev_mcb - back up one entry in table of MCBs
- ; -----
- prev_mcb:
- sub bx,mcb_length
- cmp bx,offset mcbs
- jae prev_mcb_ret
- error "Memory Control Blocks not in expected order"
- prev_mcb_ret:
- ret
-
- endcode equ $
- align 16
- db 16 dup(0) ; so that at least on mcb follows swap
- swap endp
- code ends
- end swap
-