home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
OS/2 Professional
/
OS2PRO194.ISO
/
os2
/
sysutils
/
msshell
/
swap.asm
< prev
next >
Wrap
Assembly Source File
|
1992-06-20
|
24KB
|
1,356 lines
TITLE swap.asm
NAME swap
.8087
; MS-DOS System Function with Swaping - Front End
;
; MS-DOS System - Copyright (c) 1990,1,2 Data Logic Limited
;
; This code is subject to the following copyright restrictions:
;
; 1. Redistribution and use in source and binary forms are permitted
; provided that the above copyright notice is duplicated in the
; source form.
;
; $Header: c:/usr/src/shell/RCS/swap.asm 2.0 1992/05/21 16:49:54 Ian_Stewartson Exp $
;
; $Log: swap.asm $
; Revision 2.0 1992/05/21 16:49:54 Ian_Stewartson
; MS-Shell 2.0 Baseline release
;
; Revision 2.0 1992/04/13 17:39:45 Ian_Stewartson
; MS-Shell 2.0 Baseline release
;
;
; MODULE DEFINITION:
;
; This is the front end for the swapping version of system. When linked
; in, it should be the first module in the load line so that it appears in
; memory immediately after the psp. For example:
;
; link swap+x1+x2+x3+system;
;
; This module has no user changeable features. All selections are
; performed in the associated system function.
;
; If you want small model, you can only get small model data. This
; requires this module to be compiled with the -DSMALL_DATA switch to the
; assembler.
;
; More details in system.c
;
; Author:
; Ian Stewartson
; Data Logic, Queens House, Greenhill Way
; Harrow, Middlesex HA1 1YR, UK.
; istewart@datlog.co.uk or ukc!datlog!istewart
;
;
;
; Segment declarations
;
SWAP_TEXT segment word public 'CODE'
SWAP_TEXT ends
_DATA segment word public 'DATA'
_DATA ends
CONST segment word public 'CONST'
CONST ends
_BSS segment word public 'BSS'
_BSS ends
DGROUP group CONST, _BSS, _DATA
;
; Declare external functions and data
;
extrn __maperror:far
extrn _errno:word
extrn __psp:word
;
; Start of the spawn function
;
SWAP_TEXT segment
assume cs: SWAP_TEXT, ds: NOTHING, ss: DGROUP
;
; For this function, all the code and data space are in the code space
;
public _cmd_line
public _path_line
public _SW_intr
public _SW_Blocks
public _SW_fp
public _SW_EMstart
public _SW_Mode
public _SW_EMSFrame
public _SW_Int00
public _SW_Int23
public _SW_XMS_Driver
public _SW_XMS_Gversion
public _SW_XMS_Allocate
public _SW_XMS_Free
public _SW_XMS_Available
public _SW_I23_InShell
_cmd_line db 129 dup (?) ; Command line
_path_line db 80 dup (?) ; Path line
_SW_Blocks dw 0 ; Number of blocks to read/write
_SW_fp dw 0ffffH ; File ID
_SW_EMstart dd 0100000H ; Default Extended Mem start
_SW_Mode dw 0 ; Type of swapping to do
; 1 - disk
; 2 - Extended memory
; 3 - EMS driver
; 4 - XMS driver
_SW_EMSFrame dw 0 ; EMS Frame segment
_SW_intr dw 0 ; Interrupt 23 detected.
_SW_XMS_Driver dd 0 ; XMS Driver Interface
_SW_I23_InShell db 0 ; In shell flag for Interrupt 23
;
; Some addition variables
;
SW_LMstart dd 0 ; Low Mem start for Extended Mem swap
N_mcb dw 0 ; Start write address
Result dw 0 ; Return value
;
; Stack save pointers
;
S_ss dw 0 ; Save Stack pointers
S_sp dw 0
S_di dw 0 ; Save DI, SI
S_si dw 0
S_ds dw 0 ; Save the original DS
;
; Two blank FCB
;
FCB1 dw 16 dup (?)
FCB2 dw 16 dup (?)
;
; XMS Driver Move structure
;
XMS_DIF equ $
XMS_Length dd 0 ; Number of bytes
XMS_SHandle dw 0 ; Source Handler
XMS_Soffset dd 0 ; Source Offset
XMS_DHandle dw 0 ; Destination Handler
XMS_Doffset dd 0 ; Destination Offset
;
; Extended Memory Global Descriptor tables
;
org XMS_DIF
GD_table equ $
GDT_Dummy dw 4 dup (0) ; Dummy
GDT_self dw 4 dup (0) ; For self
GDT_src equ $ ; Source
dw 04000H ; Length - 16K bytes
GDT_src_low dw 0 ; Low Order address
GDT_src_high db 0 ; High Order address
db 093h ; Access Rights
dw 0 ; Reserved
GDT_dest equ $ ; Destination
dw 04000H ; Length - 16K bytes
GDT_dest_low dw 0 ; Low Order address
GDT_dest_high db 0 ; High Order address
db 093h ; Access Rights
dw 0 ; Reserved
GDT_bios dw 4 dup (0) ; Bios
GDT_stack dw 4 dup (0) ; Stack
;
; Execute interrupt structure
;
exec_parms equ $
exec_env dw 0
dw offset _cmd_line ; Command line address
exec_cseg dw ?
dw offset FCB1 ; FCB1 address
exec_f1seg dw ?
dw offset FCB2 ; FCB1 address
exec_f2seg dw ?
Swap_PANIC db 'PANIC: Swap file re-load error - REBOOT', 0aH, 0dH
db '$'
Swap_DZERO db 'PANIC: Divide by zero', 0aH, 0dH
db '$'
;
; OK - exec requires a local stack, cause some programs overwrite it
;
even
db 398 dup (0)
Local_Stack:
dw 0
;
; Code starts
;
public _SA_spawn
SA_spawn1 proc far
mov ds, word ptr cs:exec_env ; Load Env seg.
xor si, si ; Clear start offset
;
; Copy into Env Seg
;
$Copy_Env:
ifndef SMALL_DATA
les bx, dword ptr ss:[bp + 6] ; Check for end of loop
mov ax, word ptr es:[bx + 0]
or ax, word ptr es:[bx + 2]
else
mov dx, word ptr cs:S_ds ; Get original DS
mov es, dx ; and dump it in dx for later
mov bx, word ptr ss:[bp + 6] ; Check for end of loop
mov ax, word ptr es:[bx + 0]
or ax, ax
endif
je $Copy_End
;
; Save start address
;
; For small data model,the DX register contains the original DS
;
ifndef SMALL_DATA
add word ptr ss:[bp + 6], 4 ; Increment environment by 4
mov cx, word ptr es:[bx + 0] ; Load address of cur Env string
mov ax, word ptr es:[bx + 2] ; into es:bx
else
add word ptr ss:[bp + 6], 2 ; Increment environment by 2
mov cx, word ptr es:[bx + 0] ; Load address of cur Env string
mov ax, dx ; into es:bx
endif
mov es, ax
mov bx, cx
;
; Copy this value
;
$Copy_Val:
mov al, byte ptr es:[bx] ; Copy across
mov byte ptr ds:[si], al
inc bx ; Increment pointers
inc si
or al, al
jne $Copy_Val
jmp $Copy_Env
;
; Set up exec parameter block - DS is on stack
;
$Copy_End:
xor ax, ax
mov word ptr ds:[si], ax ; Terminate environment
add si, 2
;
; Set up new program length
;
add si, 16 ; Round up paras
mov dx, si ; Save end offset in DX
mov bx, ds
mov cl, 4
shr si, cl ; # paras used by Env
add si, bx ; End para number
mov bx, word ptr cs:N_mcb ; Load our MCB address in BX
mov ax, bx
inc ax
sub si, ax
mov cx, si ; Save new max paras in CX
;
; Use interrupt 4a to shrink memory. First release all memory above us.
;
push ax
push cx ; Save Max paras and location
mov ds, bx ; Set up the segement for MCB
mov cx, word ptr ds:3 ; Get the MCB length
; Are we the only one in the chain?
cmp byte ptr ds:0, 'Z' ; End of chain ?
jz $Shrink_First
;
; Loop round releasing memory blocks
;
; CX - original length of block;
; DS - segement of the previous block
;
$Shrink_Next:
mov ax, ds ; Move to the next block
add cx, ax
inc cx
mov ds, cx
cmp byte ptr ds:0, 'Z' ; End of chain ?
jz $Shrink_First
mov cx, word ptr ds:3 ; Save the length of this block
mov ax, ds ; Advance to the block itself
inc ax
mov es, ax ; Set up Block address
mov ah, 049H
int 021H
jmp $Shrink_Next
;
; Shrink the PSP segment
;
$Shrink_First:
pop cx
pop ax
mov es, ax ; Set PSP address
mov bx, cx ; Set max length
mov ah, 04aH
int 021H
;
; Execute function
;
mov word ptr cs: S_sp, sp ; Save the current stack
mov word ptr cs: S_ss, ss
;
; Move to the local stack so that it doesn't get overwritten.
;
mov ax, cs
cli
mov sp, offset Local_Stack
mov ss, ax
sti
; Clear out Interrupts
mov ah, 00bH ; Check Keyboard status
int 021H
;
; Check for interrupt 23 detected
;
mov ax, word ptr cs:_SW_intr
or ax, ax
jz $I23_Cf ; No - continue;
;
; Interrupt 23 detected - abort
;
mov ax, cs ; Set up for reload
cli
mov sp, offset Local_Stack
mov ss, ax
sti
mov ds, word ptr cs:S_ds ; Restore DS
xor ax, ax
jmp $Exec_Complete
;
; No interrupts - continue
;
$I23_Cf:
mov ax, cs ; Set up segments
mov es, ax
mov ds, ax
mov ax, 04b00H ; Load and execute function
mov dx, offset _path_line ; Load path
mov bx, offset exec_parms ; Load the execute structure
mov byte ptr cs:_SW_I23_InShell, 1 ; Set not shell flag
int 021H
mov byte ptr cs:_SW_I23_InShell, 0 ; Set in shell flag
; Disable interrupts while we restore the stack to the local one
mov ax, cs
cli
mov sp, offset Local_Stack
mov ss, ax
sti
;
; Did an error occur?
;
jnc $Exec_OK
;
; Error
;
$Map_error:
mov ds, word ptr cs:S_ds ; Restore DS
mov ah, al
call far ptr __maperror ; Map the error
$Exec_Error:
mov ax, 0FFFFH
jmp $Exec_Complete
;
; No - get the exit code and check for interrupts
;
$Exec_OK:
mov ax, 04d00H
int 021H
dec ah ; Interrupt termination ?
jnz $Exec_OK1
inc word ptr ds:_SW_intr ; Set Interrupt 23 detected.
$Exec_OK1:
xor ah, ah
;
; Save the result code
;
$Exec_Complete:
mov word ptr cs:Result, ax ; Save response
;
; Very Dangerous - Restore Environment
;
; Seek to 0x4000 in file
;
mov bx, word ptr cs:_SW_fp ; Load File Handler
mov ax, word ptr cs: _SW_Mode ; Skip if not disk
dec ax
jnz $Seek_OK
; Seek in file to skip 16K
mov dx, 04000H
call $Seek_Disk
;
; Load from N_mcb:0x4000 to end of file.
;
$Seek_OK:
mov si, word ptr cs:_SW_Blocks ; Load number of transfers
dec si ; Skip first block
;
; set up ES register with start of load
;
mov ax, word ptr cs:N_mcb ; Load the start address
add ax, 0400H
mov ds, ax
; load up extended memory GDT for destination
call $GDT_reload
call $Inc_Extend ; Increment addresses by 16K
;
; Check for end of copy - BX - File Handler for disk
;
$Read_loop:
or si, si
je $Read_Complete
; OK - Copy next 0x4000 bytes - switch on device
mov ax, word ptr cs: _SW_Mode
dec ax
jz $R_disk
dec ax
jz $R_extend
dec ax
jz $R_expand
;
; Read from XMS driver. In this case, we do one read and let the driver
; sort out the blocking
;
call $Read_XMS
jmp $Read_Complete
; Read from disk
$R_disk:
call $Read_disk
jmp $Read_loop
; Read from extended memory
$R_extend:
call $Read_extend
jmp $Read_loop
; Read from expanded memory
$R_expand:
call $Read_EMS
jmp $Read_loop
;
; Re-load is now complete, Restore original stack which has just been
; reloaded. BX contains FP
;
$Read_Complete:
cli
mov sp, word ptr cs: S_sp ; Save the current stack
mov ss, word ptr cs: S_ss
sti
; Save exit code
push word ptr cs:Result ; Save response
push word ptr cs:_SW_intr ; and interrupt flag
;
; Read in the first block - BX - File Handler
;
mov ax, word ptr cs: _SW_Mode ; Skip if not disk
dec ax
jnz $Seek1_OK
; Seek to 0 in file
xor dx, dx
call $Seek_Disk
;
; Load one block at N_mcb:0x0000
;
$Seek1_OK:
mov ds, word ptr cs:N_mcb ; Load the start address
call $GDT_reload ; Load the GDT for extend mem
mov ax, word ptr cs: _SW_Mode ; Skip if not disk
dec ax
jz $R1_Disk
dec ax
jz $R1_Extend
dec ax
jz $R1_Expand
mov si, 1 ; Read one block
call $Read_XMS
jmp $Read1_OK
$R1_Disk:
call $Read_disk
jmp $Read1_OK
$R1_Extend:
call $Read_extend
jmp $Read1_OK
$R1_Expand:
mov si, word ptr cs:_SW_Blocks ; Read first block
call $Read_EMS
;
; Complete - load error code and return
;
$Read1_OK:
pop word ptr cs:_SW_intr ; Restore interrupt flag
pop ax
;
; Exit function - Restore Control Interrupt handler
;
$SA_spawn_Exit:
mov di, word ptr cs:S_di ; Restore saved registers
mov si, word ptr cs:S_si
mov ds, word ptr cs:S_ds
mov sp, bp
pop bp
ret
SA_spawn1 endp
;
; READ XMS DRIVER FUNCTION
;
; BX - file handler
; SI - Block count
; DS - Output data segement
;
$Read_XMS proc near
xor ax, ax
mov word ptr cs:XMS_SHandle, bx ; Source - XMS
mov word ptr cs:XMS_DHandle, ax ; Dest - normal memory
mov word ptr cs:XMS_Soffset, ax ; Source offset - zero
mov word ptr cs:XMS_Soffset + 2, ax
mov word ptr cs:XMS_Doffset, ax ; Dest offset DS:0
mov ax, ds
mov word ptr cs:XMS_Doffset + 2, ax
cmp si, 1 ; If first block, the
jz $Read_X1 ; source offset is
; 4000H
mov word ptr cs:XMS_Soffset, 04000H
;
; Set up number of bytes: si * 16 * 1024
;
$Read_X1:
mov ax, si
mov dx, si
mov cl, 14
shl ax, cl
mov cl, 2
shr dx, cl
mov word ptr cs:XMS_Length, ax ; Load number of bytes
mov word ptr cs:XMS_Length + 2, dx
mov ah, 0BH ; Set up parameters
mov dx, cs
mov ds, dx
mov si, offset XMS_DIF
call cs:[_SW_XMS_Driver]
or ax, ax
jnz $Read_XMS1
jmp Load_Error ; XMS error - abort
$Read_XMS1:
ret
$Read_XMS endp
;
; READ DISK FUNCTION
;
; BX - file handler
; SI - Block count
; DS - Output data segement
;
$Read_disk proc near
mov ax, 03f00H ; Set up to read
mov cx, 04000H ; Load count
xor dx, dx ; Clear start address
int 021H ; Read the data
jnc $Read_OK ; NO - abort
jmp Load_Error ; Abort - swap file error
;
; Read OK - next block
;
$Read_OK:
dec si ; Decrement block count
mov ax, ds ; Increment offset
add ax, 0400H
mov ds, ax
ret
$Read_disk endp
;
; READ EMS FUNCTION
;
; BX - file handler
; SI - Block count - counts from max
; DS - Output data segement
;
$Read_EMS proc near
call $map_ems_page ; Map in the current EMS page
jnz Load_Error
push ds ; Save DS and SI
push si
mov ax, ds
mov es, ax
mov ds, word ptr cs:_SW_EMSFrame ; Set Dest Seg
xor si, si ; Clear start
xor di, di
mov cx, 02000H ; move 16K
pushf ; Save direction flag
cld
rep movsw
popf ; Restore direction flag
pop si ; And DS, SI
pop ds
jmp $Read_OK ; Increment DS and dec SI
$Read_EMS endp
;
; MAP IN THE CURRENT EMS PAGE
;
; BX - file handler
; SI - Block count - counts from max
; DS - Output data segement
;
$map_ems_page proc near
push bx ; Need to save BX
mov ax, 04400h ; Map into physical page zero
mov dx, bx ; Set up handler
mov bx, word ptr cs: _SW_Blocks
sub bx, si
int 067H
pop bx
or ah, ah
ret
$map_ems_page endp
;
; DISK SEEK FUNCTION
;
; BX - file handler
; DX - offset
;
$Seek_Disk proc near
mov ax, 04200H ; Set seek
xor cx, cx
int 021H
jc Load_Error ; Abort - swap file error
ret
$Seek_Disk endp
;
; PANIC - Abort
;
Load_Error proc near
mov di, offset Swap_PANIC
mov bx, cs
mov ds, bx
;
; Display message function
;
; DS:DI message
; AX is available
;
mov ah, 08H ; Get foreground colour
xor bx, bx
int 10H
mov bl, ah
and bl, 07h
;
; Loop until a $ is hit, outputting the characters
;
I24D:
mov al, byte ptr ds:[di]
cmp al, '$'
jz $Wait_L
push di
mov ah, 0EH
int 10H
pop di
inc di
jmp I24D
$Wait_L:
sti
hlt
jmp $Wait_L
Load_Error endp
;
; WRITE EXTENDED MEMORY
;
; SI - Block count
;
$Write_extend proc near
push si ; Save SI (block counter)
mov cx, 02000H ; Copy a 16K block
mov ax, cs ; Set up GDT address
mov es, ax
mov si, offset GD_table
mov ah, 087H ; EMS function
int 015H
pop si
ret
$Write_extend endp
;
; READ FROM EXTENDED MEMORY
;
; SI - Block count
;
$Read_extend proc near
call $Write_extend
jc Load_Error ; NO - abort
dec si ; Decrement block count
$Read_extend endp
;
; INCREMENT Extended MEMORY GDT
;
; AX - used
;
$Inc_Extend proc near
mov ax, 04000H ; Increment address by 16K
add word ptr cs:GDT_dest_low, ax
adc byte ptr cs:GDT_dest_high, 0
add word ptr cs:GDT_src_low, ax
adc byte ptr cs:GDT_src_high, 0
ret
$Inc_Extend endp
;
; LOAD SOURCE GDT ADDRESS
;
; AX - low order
; DL - high order
;
$GDT_src_load proc near
mov word ptr cs:GDT_src_low, ax
mov byte ptr cs:GDT_src_high, dl
ret
$GDT_src_load endp
;
; LOAD DESTINATION GDT ADDRESS
;
; AX - low order
; DL - high order
;
$GDT_dest_load proc near
mov word ptr cs:GDT_dest_low, ax
mov byte ptr cs:GDT_dest_high, dl
ret
$GDT_dest_load endp
;
; LOAD the GDT for reloading
;
$GDT_reload proc near
mov ax, word ptr cs:_SW_EMstart ; Load Full start address
mov dl, byte ptr cs:_SW_EMstart + 2
call $GDT_src_load
mov ax, word ptr cs:SW_LMstart ; Load Full start address
mov dl, byte ptr cs:SW_LMstart + 2
call $GDT_dest_load
ret
$GDT_reload endp
;
; CONTROL C INTERRUPT HANDLER - IGNORE
;
_SW_Int23 proc far
inc word ptr cs:_SW_intr ; Set Interrupt 23 detected.
cmp byte ptr cs:_SW_I23_InShell, 0 ; are we in the shell?
jz $SA_Ins
; In another program - move the stack around
stc
ret
; In shell - ignore interrupt 23 for the moment
$SA_Ins:
iret
_SW_Int23 endp
;
; DIVIDE BY ZERO INTERRUPT HANDLER - Output message
;
_SW_Int00 proc far
mov ax, 00900H
mov dx, offset Swap_DZERO
mov bx, cs
mov ds, bx
int 021H
mov ax, 04CFFh ; Exit
int 021H
_SW_Int00 endp
;
; Start of overwrite area for environment. Align on a paragraph
;
; Also the XMS driver functions used by SH3.C live here
;
ALIGN 16
Env_OWrite:
;
; XMS INTERFACE
;
; Get Version number. Return the release number in AX
;
_SW_XMS_Gversion proc far
push bp ; Save stack info
mov bp, sp
xor ax, ax
call cs:[_SW_XMS_Driver]
mov sp, bp
pop bp
ret
_SW_XMS_Gversion endp
;
; Allocate N kbytes. Return the Handler in AX or -1 and error code in
; errno.
;
; Size will be in bp + 6.
;
_SW_XMS_Allocate proc far
push bp ; Save stack info
mov bp, sp
mov dx, word ptr ss:[bp + 6]
mov ah, 09H
call cs:[_SW_XMS_Driver]
or ax, ax
jnz $SW_A1
;
; Allocate Failed - return error code
;
xor ax, ax
dec ax
xor bh, bh
mov word ptr ds:_errno, bx ; Save error code
jmp $SW_A2
;
; Allocate OK - return handler
;
$SW_A1:
mov ax, dx
$SW_A2:
mov sp, bp
pop bp
ret
_SW_XMS_Allocate endp
;
; Release handler. Return 0 or error code.
;
; Handler will be in bp + 6.
;
_SW_XMS_Free proc far
push bp ; Save stack info
mov bp, sp
mov dx, word ptr ss:[bp + 6]
mov ah, 0AH
call cs:[_SW_XMS_Driver]
or ax, ax
jnz $SW_F1
;
; Free Failed - return error code
;
mov al, bl
jmp $SW_F2
;
; Free OK - return zero
;
$SW_F1:
xor ax, ax
$SW_F2:
mov sp, bp
pop bp
ret
_SW_XMS_Free endp
;
; Get available memory space. Return 0 if failed.
;
_SW_XMS_Available proc far
push bp ; Save stack info
mov bp, sp
mov ah, 08H
call cs:[_SW_XMS_Driver]
or bl, bl
jz $SW_Avail1
;
; Free Failed - return zero
;
xor ax, ax
$SW_Avail1:
mov sp, bp
pop bp
ret
_SW_XMS_Available endp
;
; Main entry point
;
_SA_spawn proc far
push bp
mov bp, sp
;
; Entry Offsets
;
; Environment = 6
;
mov word ptr cs:S_di, di ; Save registers
mov word ptr cs:S_si, si
mov word ptr cs:S_ds, ds
;
; Save the length of the current MCB block;
;
mov ax, word ptr ds:__psp
dec ax
mov word ptr cs:N_mcb, ax ; Save MCB address for swap out
; Calculate low mem start for extended memory
mov bx, ax ; Save copy
mov cl, 4 ; mult low order by 16
shl ax, cl
mov word ptr cs:SW_LMstart, ax ; Save low order
mov cl, 12 ; div by 16 ** 3
shr bx, cl
mov byte ptr cs:SW_LMstart + 2, bl ; Save low order
;
; Set up Environment segment in execute structure
;
mov bx, cs
mov ax, offset Env_OWrite
mov cl, 4
shr ax, cl
add ax, bx
mov word ptr cs:exec_env, ax ; Save Env seg.
;
; Set up rest of execute structure
;
mov word ptr cs:exec_cseg, cs ; Command line address
mov word ptr cs:exec_f1seg, cs ; FCB 1 address
mov word ptr cs:exec_f2seg, cs ; FCB 2 address
;
; Generate the FCBs
;
mov ax, cs ; Set up segments
mov ds, ax
mov es, ax
mov ax, 02901H ; Set up FCB interrupt
mov si, offset _cmd_line + 1
mov di, offset FCB1 ; FCB 1;
int 021H ; Execute the interrupt
mov ax, cs ; Set up segment
mov es, ax
mov ax, 02901H ; Reset AX cause errors are ignored
mov di, offset FCB2 ; FCB 2;
int 021H ; Execute the interrupt
;
; Copy out to the swap file
;
mov bx, word ptr cs:_SW_fp ; Load file handler
mov si, word ptr cs:_SW_Blocks ; Load Number of blocks to read
mov ax, word ptr cs:N_mcb ; Load the start address
push ax
; load up extended memory GDT for destination
mov ax, word ptr cs:_SW_EMstart
mov dl, byte ptr cs:_SW_EMstart + 2
call $GDT_dest_load
;
; set up DS register with start of start copy
;
pop ax
mov ds, ax
mov ax, word ptr cs:SW_LMstart ; Load Full start address
mov dl, byte ptr cs:SW_LMstart + 2
call $GDT_src_load
;
; Check for end of copy - BX contains the file handler for disk write
;
$Write_loop:
or si, si
jnz $Write_L1
jmp $Write_Complete
; OK - Copy next 0x4000 bytes - switch on device
$Write_L1:
mov ax, word ptr cs: _SW_Mode
dec ax
jz $W_disk
dec ax
jnz $Write_L2
jmp $W_extend
$Write_L2:
dec ax
jnz $W_xms
jmp $W_expand
;
; Write to XMS driver. In this case, we do one write and let the driver
; sort out the blocking
;
$W_xms:
xor ax, ax
mov word ptr cs:XMS_SHandle, ax ; Source - normal memory
mov word ptr cs:XMS_DHandle, bx ; Dest - XMS
mov word ptr cs:XMS_Doffset, ax ; Dest offset - zero
mov word ptr cs:XMS_Doffset + 2, ax
mov word ptr cs:XMS_Soffset, ax ; Source offset DS:0
mov ax, ds
mov word ptr cs:XMS_Soffset + 2, ax
;
; Set up number of bytes SW_Block * 16 * 1024
;
mov ax, si
mov dx, si
mov cl, 14
shl ax, cl
mov cl, 2
shr dx, cl
mov word ptr cs:XMS_Length, ax ; Load number of bytes
mov word ptr cs:XMS_Length + 2, dx
mov ah, 0BH ; Set up parameters
mov dx, cs
mov ds, dx
mov si, offset XMS_DIF
call cs:[_SW_XMS_Driver]
or ax, ax
jnz $Write_Complete
; XMS error - abort
mov ah, bl
jmp $Write_error
;
; Write to disk
;
$W_disk:
call $Write_disk
; Increment counter
$Write_Incr:
dec si ; Decrement block count
mov ax, ds ; Increment offset
add ax, 0400H
mov ds, ax
jmp $Write_loop
; Write to extended memory
$W_extend:
call $Write_extend
jc $Write_error ; NO - abort
dec si ; Decrement block count
call $Inc_Extend
jmp $Write_loop
; Write to expanded memory
; BX - handler
; SI - count
; DS - source segment
;
$W_expand:
call $map_ems_page ; Map in the current EMS page
jnz $Write_error
push ds ; Save DS and SI
push si
mov es, word ptr cs:_SW_EMSFrame ; Set Dest Seg
xor si, si ; Clear start
xor di, di
mov cx, 02000H ; move 16K
pushf ; Save direction flag
cld
rep movsw
popf ; Restore direction flag
pop si ; And DS, SI
pop ds
jmp $Write_Incr ; Increment DS and dec SI
;
; Error - abort. The error code is in AH.
;
$Write_error:
mov ds, word ptr cs:S_ds ; Restore DS
mov al, ah
xor ah, ah
mov word ptr ds:_errno, ax ; Save error code
$Write_Error1:
mov ax, 0FFFEH
jmp $SA_spawn_Exit ; Exit
;
; Swap file is now written, set up environment. If this was a partial
; write, we need to write the first 4K.
;
$Write_Complete:
jmp SA_spawn1
_SA_spawn endp
;
; WRITE DISK FUNCTION
;
; BX - file handler
; SI - Block count
; DS - Output data segement
;
$Write_disk proc near
mov ax, 04000H ; Set up to write
mov cx, ax ; Load count
xor dx, dx ; Clear start address
push bx ; Save FP
push si ; Save count and Data Segment
int 021H ; Write the data
pop si ; Restore Regs
pop bx
jnc $Write_disk1 ; NO error - continue
;
; Error - abort
;
mov ds, word ptr cs:S_ds ; Restore DS
mov ah, al
call far ptr __maperror ; Map the error
jmp $Write_Error1
; Check for 16K write
$Write_disk1:
cmp ax, 04000H
jnz $Write_disk2
ret
$Write_disk2:
mov ax,01c1cH ; Set disk full
jmp $Write_error ; NO - abort
$Write_disk endp
;
; END OF SWAPPER
;
SWAP_TEXT ends
end