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 ; origin 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 address 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 ; stopy 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 ; open handle for writing
- int 21h
- 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 ; get interrupt vector
- int 21h
- mov word ptr int21_vector,bx ; save offset
- mov word ptr int21_vector[2],es ; save segment
- mov dx, offset int21_handler ; address of out int 21
- mov ax, 2521h ; set interrupt vector
- int 21h
- ; ----- 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 fcb's
- 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 ; load and execute a program
- int 21h
- mov ds, cs:swappee_psp ; restore ds addressability
- cli ; turn off interrupts
- mov ss, swappee_psp
- 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 ; handle for 'con'
- mov ah, 3eh ; dos 'close handle' function
- int 21h
- ; ----- restore original int 21 vector
- push ds ; ds gets clobbered, so save it
- lds dx, int21_vector ; get address of old vector
- mov ax, 2521h ; set interrupt vector
- int 21h
- pop ds
- 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 position
- int 21h ; let dos lseep 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
- ; --------------------------------------------------
- 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 $ 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 06 (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 02 (display character in dl register)
- ; -----
- func02:
- call front_start
- mov char_buf, dl ; put character in write 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 ; 51h = get pid
- int 21h
- 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 ; 50h = set pid
- int 21h
- ret
-
- ; -----
- ; write_to_con - call original int 21 handler to write buffer to display
- ; -----
- write_to_con:
- assume ds:nothing
- mov bx, cs:handle ; handle opened for 'con'
- mov ah, 40h ; 40h = 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 ; 50 = set pid
- int 21h
- ; ----- 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 to ascii hexidecimal 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:di 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 ; 40h = dos handle write
- int 21h
- pop dx
- pop cx
- mov bx, 2
- mov ah, 40h
- int 21h
- 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 ; save swap file handle
- ret
-
- ; read_swap_file -- read 16K from swap file to address in es:0
- ; saves cs
- 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 ; 3f = dos read (handle)
- 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 ; 3e = dos close file
- int 21h
- ret
-
- ; -----
- ; return - return to DOS
- ; -----
- return:
- mov ax, 4c00h ; dos terminate function
- int 21h
-
- ; -----
- ; 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 "SWAP Version 1.0 (c) Copyright 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 process_cmdline ; check options, set up 'exec' cmdline
- call say_hello ; print copyright message
- 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 relavent 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 commmand 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 address
- mov bx, 2 ; handle for stderr
- mov ah, 40h ; 40h = dos write to handle
- int 21h
- say_hello_exit:
- ret
-
- ; -----
- ; check_dos_version - be sure this is dos 3.0 or higher
- ; -----
- check_dos_version:
- mov ah, 30h ; 30h = dos get version
- int 21h
- 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 through 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 ; 4a = dos set block
- int 21h
- ret
-
- ; -----
- ; get_mcb_info - get relavent 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:
- mov dx, [bx].len
- mov my_mcb_size, dx ; remember length of our mcb
- add cx, [bx].len ; add length to 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 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 to 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 ; 35h = dos get vector
- mov al, cl ; vector number
- int 21h
- 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
- 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:
- mov 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 to
- 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 ; 3c = dos create 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 of 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 ; 40h = dos 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
- 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 mcb's, 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 had 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 next 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 ; 50h = dos set pid
- int 21h
-
- ; ----- 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 ; 50h = dos 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 one mcb follow swap
- swap endp
- code ends
- end swap