home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Power-Programmierung
/
CD1.mdf
/
assemblr
/
library
/
sampler0
/
swapout.asm
< prev
next >
Wrap
Assembly Source File
|
1989-07-15
|
44KB
|
1,087 lines
; 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