pcs/pro2real.asm

1707 lines
53 KiB
NASM
Raw Normal View History

2023-05-20 05:57:05 -04:00
; =====> PRO2REAL.ASM
; PC Scheme Protected Mode -> Real Mode Interface
; (c) 1987 by Texas Instruments Incorporated -- all rights reserved
;
; This Module contains code which interfaces to external programs via
; either the External Language Interface (XLI), Software Interrupt,
; or the Real Procedure Call (RPC). The RPC is specific to protected
; mode scheme only, and is used to implement XLI.
; Author: Terry Caudill (from Bob Beal's original source)
; History:
; rb 3/20/87 - original
; tc 8/7/87 - to work in protected mode scheme
; tc 10/13/87 - cleanup
page 84,120
name EXTPROG
title PC Scheme External Program Interface
.286c
subttl Includes and Local Equates
page
include scheme.equ
include sinterp.arg
include xli.equ
include xli_pro.mac
include rpc.equ
;
; Dos function requests
;
DOS equ 021h ; Dos Function Request
DELETE_SEG equ 04900h ; Delete Segment
REAL_INTRP equ 0E3h ; Issue Real Interrupt - from AIA
BLOCK_XFER equ 0EC00h ; Block Transfer - from AIA
ALLOC_REAL equ 0E802h ; Create Real Data Seg - from AIA
CREATE_WIN equ 0E803h ; Create Real Window - from AIA
subttl Group and Constant definitions
page
pgroup group prog
xgroup group progx
dgroup group data
subttl Data segment definitions
page
data segment para public 'DATA'
assume ds:dgroup
public rpc_handle
public REAL_MODE_BUFFER,REAL_BUF_OFFSET,REAL_BUF_SELECTOR
public REAL_BUF_PARA,REAL_BUF_TOP
public C_fn
public mem_entry,mem_table
; external variables
extrn ctl_file:word,pcs_sysd:word
extrn regs:word
extrn vid_mode:word,char_hgt:word
;
; The following data definitions are used in communication with real
; mode procedures and the real procedure call (RPC) mechanism provided
; in OS/286 by AI Architects.
;
rpc_real db "realschm.exe",0 ; Name of RPC file to load
rpc_real_len equ $-rpc_real
rpc_handle db 0 ; Handle to real mode scheme routines
rpc_loaded db 0 ; Flag to note if rpc load was successful
rpc_saved_sp dw ? ; Saved stack pointer
REAL_MODE_BUFFER equ $ ; selector and offset of real mode
REAL_BUF_OFFSET dw 0 ; offset of real mode buffer
REAL_BUF_SELECTOR dw 0 ; segment selector of real mode buffer
REAL_BUF_PARA dw 0 ; segment address of real mode buffer
REAL_BUF_TOP dw 0 ; note buffer top
;
; The following are xli filenames which must be loaded and used by pcs
;
io_exe db "realio.exe" ,0 ;EXE file providing I/O support
io_exe_len equ $-io_exe
graph_exe db "graphics.exe" ,0 ;EXE file providing graphics support
graph_exe_len equ $-graph_exe
trig_exe db "newtrig.exe" ,0 ;EXE file providing trig support
trig_exe_len equ $-trig_exe
;
; The following table is used to load the system files required by pcs. The
; xli system files are order dependent.
sys_files equ $
;system xli files, order is dependent (see rpc.equ and realschm.asm)
dw io_exe,io_exe_len ;io support - xli system file
dw graph_exe,graph_exe_len ;graphics support - xli system file
;normal xli files
normal_files equ $
dw trig_exe,trig_exe_len ;trig file - normal xli file
dw 0
;
; If the above files cannot be found, issue this message and abort scheme
;
FILERR db 0Dh,0Ah,"Fatal Error - unable to load file "
FILNAM db 20 dup (0)
;
; The following table contains gateways from the prog segment to the
; progx segment. The order is dependent on
; Table of RPC functions currently defined. Calling any of these functions
; requires synchronization with the real mode routine.
;
FAR_RPC equ $
frpc_bid equ $-FAR_RPC
dw init_rpc,progx ; bid real procedure
frpc_init equ $-FAR_RPC
dw xpcinit,progx ; get machine type
frpc_setcrt equ $-FAR_RPC
dw xsetcrt,progx ; set crt interrupt
frpc_resetcrt equ $-FAR_RPC
dw xresetcrt,progx ; reset crt interrupt
frpc_ldall equ $-FAR_RPC
dw load_all,progx ; load xli files
frpc_unld equ $-FAR_RPC
dw unload_all,progx ; unload xli files
frpc_xesc equ $-FAR_RPC
dw xesc,progx ; perform xesc call
;
; The following hooks are used to call routines in the PROG segment
; from the PROGX segment. See the far_C routine in this module.
;
C_fn dw ?
C_retadr dw ? ; Used to call C routines from PROGX
dw ?
;
; Mem_table is used to hold selectors to real memory which must be allocated
; over the life of an xli call. At present, the memory is allocated so that
; xli routines may access far strings. See SSR within.
;
mem_entry dw 0 ;entry into memory table
mem_table dw N_ARGS dup (0) ;record memory allocated during xli call
;
; The following structures allow xesc and sw-int to share code
;
xesc_func db ? ;0 = sw-int, 1 = xesc
error_return dw ? ;address of error handler
which_func dw swi_txt,xli_txt ;will be indexed by xesc_func above
swi_txt db 'SW-INT',0
xli_txt db 'XCALL',0
;
; Error return values for software interrupt
;
SWI_ERR_ARGN_BAD_TYPE equ 1 ; Bad argument passed to sw-int
SWI_ERR_VALUE_BAD_TYPE equ 2 ; Bad type passed to sw-int
SWI_ERR_BIG_TO_32_BITS equ 3 ; Number to large for sw-int
swi_errs dw swi_arg0,swi_arg1,swi_arg2
;
; Software Interrupt error messages
;
swi_arg0 db 'Invalid argument to SW-INT',0
swi_arg1 db 'Invalid return value for SW-INT',0
swi_arg2 db 'Argument to SW-INT too large to fit in 32 bits',0
;
; Protected Mode Fatal type errors
;
cr_win db 'CREATE WINDOW',0
al_seg db 'ALLOCATE SEGMENT',0
dl_seg db 'DELETE SEGMENT',0
rl_int db 'ISSUE REAL INTERRUPT',0
;
; Gate to abort code in sc.asm
;
data ends
subttl Progx code segment definitions
page
; external routines
extrn alloc_fl:near,int2long:near,long2int:near,alloc_bl:near
extrn getbase:near
extrn chg_vmode:near
extrn pro_erro:near
progx segment para public 'PROGX'
assume cs:xgroup,ds:dgroup,es:dgroup,ss:dgroup
extrn xcabt:far
public init_rpc,xpcinit,xsetcrt,xresetcrt,xesc,load_all,unload_all
public ssr
public do_floarg,do_fixarg,do_bigarg,do_strarg
public do_floval,do_intval,do_TFval,do_strval
public softint,swi_strarg,swi_strval
subttl RPC interface routines
page
; INIT_RPC
; Load the real mode portion of scheme and save the handle in rpc_handle.
; Then call the rpc routine to return the real address of a buffer which
; will be used on subsequent rpc requests. This buffer is mapped to a
; protected mode selector and stored in REAL_BUF_SELECTOR.
;
; The transaction buffer for an rpc must be pointed to by DS:DX. Note that
; we build this buffer up on the local stack.
;
init_rpc proc far
push bp
sub sp,80 ;allocate transaction buffer
mov bp,sp ;should be large enough for filename
cld
mov di,pcs_sysd ;di => system directory pathname
mov cx,64 ;cx = max length
mov al,0
repne scasb ;scan pathname for eos character (=0)
jcxz ini_10 ;jump if none
dec di ;di => end of pathname
ini_10:
mov cx,di
sub cx,pcs_sysd ;cx = length of system directory
mov di,sp ;di => stack (transaction buffer)
mov si,pcs_sysd ;si => pcs-sysdir
rep movsb ;copy system directory into buffer
mov al,'\' ;follow directory name with \
stosb
mov si,offset rpc_real
mov cx,rpc_real_len
rep movsb ;follow directory w/real proc filename
;Initialize real procedure call
mov dx,sp ;ds:dx => real procedure filename
mov ah,RPC_INIT ;load and init real procedure
int DOS ;extended Dos call for Protected mode
jnc ini_20 ;continue if no error encountered
mov ax, offset rpc_real ;ax => file that couldn't load
mov cx,rpc_real_len ;cx => length of filename
jmp fatal_file_err ;jump to fatal error handler
ini_20:
mov rpc_handle,al ;save handle to real procedure
inc rpc_loaded ;note real procedure loaded
; Obtain communication buffer for subsequent RPC calls
mov dx,bp ;ds:dx => transaction buffer
mov word ptr [bp],RPCRETBUF ;return real buffer opcode
mov cx,8 ;pass 8 bytes
mov bx,cx ;expect 8 bytes returned
mov ah,RPC ;issue Real Procedure Call
int DOS ;extended Dos call for Protected mode
;ignore return status
mov dx,[bp]+2 ;get length of buffer
sub dx,2 ;calc top of stack
mov REAL_BUF_TOP,dx ; and save
mov si,sp
add si,4 ;ds:si => real address of buffer
mov ax,[si]+2 ;get paragraph address
mov REAL_BUF_PARA,ax ; and save
;ds:si=> offset,seg of real buffer, dx=length
call map_real_mem ;map real address to protected selector
mov REAL_BUF_SELECTOR,ax ; and save
add sp,80 ;now clean up the stack
pop bp
ret ;and return
init_rpc endp
; XPCINIT
; Determine the machine type and perform machine specific initialization.
; Call the real mode routine to perform initialization functions via the
; RPC mechanism.
;
; Input: none
; Output: return status, pc machine type, and video mode are returned
; in the communications buffer accessed by REAL_MODE_SELECTOR.
;
xpcinit proc far
push RPCTYPE ; Type code
mov dx,sp ; ds:dx => arg buffer
mov cx,2 ; cx = # arg bytes passed
mov bx,cx ; bx = # result bytes expected
mov al,rpc_handle ; Handle to real mode part
mov ah,RPC ; Real Procedure Call
int DOS ; Extended Dos call for Protected mode
; Check for errors here
pop ax ; ignore return status
; Get the return values from the real mode buffer
MOVE_ARGS_FROM_BUF <PC_MAKE,VID_MODE,CHAR_HGT>,REAL_MODE_BUFFER
mov ax,ds
mov es,ax ; restore extra seg reg
ret ; and return
xpcinit endp
; XSETCRT
; Take over the real mode crt interrupt handler during a dos-call so that
; display will not be written to.
;
; Input: none
; Output: screen output will be inhibited
;
xsetcrt proc far
push RPCTAKCRT ; Take over crt interrupt handler
mov dx,sp ; ds:dx => arg buffer
mov cx,2 ; cx = # arg bytes passed
mov bx,cx ; bx = # result bytes expected
mov al,rpc_handle ; Handle to real mode part
mov ah,RPC ; Real Procedure Call
int DOS ; Extended Dos call for Protected mode
pop ax ; ignore return status
ret ; and return
xsetcrt endp
; XRESETCRT
; Restore the original crt interrupt handler after a dos call so that the
; display can once again be written to.
;
; Input: none
; Output: screen output will be restored
;
xresetcrt proc far
push RPCRSTCRT ; Restore crt interrupt handler
mov dx,sp ; ds:dx => arg buffer
mov cx,2 ; cx = # arg bytes passed
mov bx,cx ; bx = # result bytes expected
mov al,rpc_handle ; Handle to real mode part
mov ah,RPC ; Real Procedure Call
int DOS ; Extended Dos call for Protected mode
; Check for errors here
pop ax ; ignore return status
ret ; and return
xresetcrt endp
subttl RPC interface routines to XLI
page
; LOAD_ALL
; A portion of the XLI routines is in real mode and is communicated with
; via the Real Procedure Call (RPC). Data must be passed to the real mode
; routine via the real buffer REAL_MODE_BUFFER
;
; Any errors encountered are currently ignored.
l_save struc
exe_name dw ? ;index to start of exe name
handle dw ? ;file handle
l_len db ? ;marker for size of local area
l_save ends
load_all proc far
push bp
sub sp,l_len ;allocate local storage
mov bp,sp
; calc length of pathname
cld
mov di,pcs_sysd
mov cx,64 ;max length of pathname
mov al,0
repne scasb ;look for eos character (=0)
jcxz la_10 ;jump if none
dec di
la_10:
mov cx,di
sub cx,pcs_sysd ;cx = length of pcs-sysdir
; copy pcs-sysdir into transaction buffer
push cx ;tempsave length
RESET_REAL_BUFFER_OFFSET ;ensure start at buffer start
MOVE_ARGS_TO_BUF <1>,REAL_MODE_BUFFER,autoincr ;system file first
add di,2 ;save space for exe index
pop cx ;restore length
mov si,pcs_sysd ;ds:si addresses pcs-sysdir
MOVE_TO_REAL_BUF autoincr ;move to real memory buffer
mov al,'\' ;append \ onto pcs-sysdir name
MOVE_BYTE_TO_BUF al,,autoincr
;save index to exe filename
mov [bp].exe_name,di ;save offset after pcs-sysdir
mov bx,di ;save offset after pcs-sysdir
mov di,2
MOVE_ARGS_TO_BUF <bx> ;save index to exe file
mov di,bx ;position offset for .EXE name
;save control filename to transaction buffer
mov bx,ctl_file ;get address of ctl file
cmp byte ptr [bx],'-' ;user override normal xli files?
jne sysload ; no, jump
mov word ptr normal_files,0 ; Yes, don't load normal xli files
inc ctl_file ; bump ptr to name
sysload:
; load all system files - di should not be modified in following loop
mov si,offset sys_files
loadfile:
push si ;save offset into file table
mov cx,ds:[si+2] ;cx = length
mov si,ds:[si] ;si => filename
MOVE_TO_REAL_BUF ;copy filename to buffer
push RPCLDEXE ;RPC request code to load EXE
mov dx,sp ;ds:dx => rpc request code
mov cx,2 ;cx = # arg bytes passed
mov bx,cx ;bx = # arg bytes returned
mov al,rpc_handle ;al = handle
mov ah,RPC ;Issue Real Procedure Call
int DOS ;Issue extended dos funcall
pop ax ;ah = flags, al= return status
pop si ;restore index into file table
sahf ;load flags
jnc load_10 ;no carry, proceed
mov cx,ds:[si+2] ;cx = length
mov ax,ds:[si] ;si => filename
jmp fatal_file_err ;go report error
load_10:
add si,4 ;address next entry
cmp word ptr ds:[si],0 ;any more entrys?
jne loadfile ; yes, loop
userload:
xor di,di ;address system flag
MOVE_ARGS_TO_BUF <0> ;indicate user defined xli
mov di,[bp].exe_name ;di = index to exe name
; open XLI control file
mov dx,ctl_file ;dx = address of filename
mov ax,FR_OPEN ;dos function - open file
int DOS
mov [bp].handle,ax ;save handle
jnc next_file ;jump if no open errors
jmp close1 ;can't open file, exit
; read in next filename off the control file and append it to
; the pcs-sysdir name.
next_file:
mov di,[bp].exe_name ;es:di => buffer after pathname
mov bx,[bp].handle ;bx = file handle
next_char:
push 0 ;allocate place on stack
mov dx,sp ;dx = address of buffer
mov cx,1 ;read one character
mov ax,FR_READ ;dos function - read file
int DOS ;ignore errors
pop dx ;retrieve character
jnc la_20 ;jump if no error, else
;suddenly can't read control
;file, close it and exit
close:
mov bx,[bp].handle ;bx = file handle
mov ax,FR_CLOSE ;dos functions - close file
int DOS ;ignore errors
close1:
add sp,l_len ;adjust stack
pop bp
ret ;return
la_20: cmp ax,0 ;at eof?
jz close ;yes, jump
; we've read a character
cmp dl,0Dh ;carriage return?
je got_file ;yes, jump
cmp dl,' ' ;blank or control char?
jle next_char ;yes, skip it
MOVE_BYTE_TO_BUF dl,,autoincr ;move character to buffer
jmp next_char
; we've read a complete filename, go load it
got_file:
MOVE_BYTE_TO_BUF 0 ;form ASCZII string
push RPCLDEXE ;RPC request code to load EXE
mov dx,sp ;ds:dx => rpc buffer
mov cx,2 ;cx = # arg bytes passed
mov bx,cx ;bx = # arg bytes returned
mov al,rpc_handle ;al = handle
mov ah,RPC ;Issue Real Procedure Call
int DOS ;Issue extended dos funcall
pop ax ;bump result arg from stack
sahf ;ah = flags
jnc next_file ;jump if no errors
xor ah,ah ;clear flags from result
cmp ax,0 ;any open slots?
je close ;no, jump
cmp ax,2 ;file found?
je next_file ;no, jump
cmp ax,8 ;ran out of memory?
jne next_file ;no, jump; ignorable error
jmp close ;yes
load_all endp
; UNLOAD_ALL
; Call the real mode routine to unload all exe files.
;
; Upon exit:
; All previously bid xli programs will be released from real memory.
;
unload_all proc far
push RPCUNLDALL ; RPC request code to unload all exe's
mov dx,sp ; ds:dx => arg buffer
mov cx,2 ; cx = # arg bytes passed
mov bx,2 ; bx = # result bytes expected
mov al,rpc_handle ; Handle to real mode part
mov ah,RPC ; Real Procedure Call
int DOS ; Extended Dos call for Protected mode
pop ax ; ignore errors
ret
unload_all endp
; FATAL_FILE_ERR
; We are unable to load a system file in real mode, and cannot
; continue with scheme. The routine XCABT (in sc.asm) will output
; a message (via DOS function 9) to the console and abort. Our
; io may not be available at the time of this error.
;
; On entry:
; ax => filename we are trying to load
; cx = length of filename
;
public fatal_file_err
fat_err proc near
fatal_file_err label near
mov bx,ss
mov ds,bx
mov es,bx ;ds,es,ss = data segment
mov si,ax ;ds:si addresses filename
mov di,offset FILNAM ;es:di addresses message
rep movsb ;move filename into message
mov byte ptr es:[di],"$" ;terminate byte
cmp rpc_loaded,0 ;have we gotten past rpc load?
je fat_exit ; no, exit
call unload_all ; yes, ensure all xli's unloaded
fat_exit:
mov dx,offset FILERR ;ds:dx => message
jmp pgroup:xcabt ;exit to DOS
fat_err endp
; FATAL_PRO_ERR
; A protected mode operation has failed. Call pro_error in serror.c to
; output an error message and attempt a scheme-reset.
; a scheme reset.
;
; On entry:
; ax = error number
; bx => function call name
; cx => operation being performed (sw-int, xcall, etc.)
;
pro_err proc near
fatal_pro_err label near
push bp
mov bp,sp ;set up stack for call
push ss
pop ds ;ensure ds = data segment
push ax ;error number
push bx ;function call
push cx ;routine
mov C_fn, offset pgroup:pro_erro
call far ptr far_C ;control will not return here
pro_err endp
; XESC
; Handler for the "%xesc" opcode.
;
; On entry:
; AX = length of xesc call (= inst length - 1)
; ES:SI = pointer to bytecode arguments of the %xesc opcode
;
; On exit:
; normal: the VM reg that contained the name string on entry will
; contain the page:offset of the return value; there may
; be side effects in strings that were arguments to %xesc
; BX = 0 (no errors)
; error: BX = error#
;
; Description:
; A buffer is built for an RPC call to the real mode handler for
; an external subroutine call (XCALL). The buffer is built in a
; buffer in the real mode routine as follows:
;
; +----------------------------------------+
; | Routine name length (1 word) |
; | Routine name (above length) |
; | |
; | Number of XCALL Arguments (1 word) |
; | |
; | Type of Arg1 (1 word) |
; | Arg1 (type dependent) |
; | . |
; | . |
; | . |
; | Type of Argn (1 word) |
; | Argn (type dependent) |
; +----------------------------------------+
;
; After calling the real mode handler, the buffer will contain
; result info and return values. See the structure "xesc_result"
; for a description of the buffer upon return.
;
;
; This following data will be allocated locally within xesc
;
local_save struc
; following is used to store return data from xli routines
xesc_status dw ? ; return status
xesc_vtype dw ? ; type of value being returned
xesc_value dw 4 dup (?) ; return value
; following is local data used in building xli call
saved_si dw ? ; segment offset of vm bytecode
saved_es dw ? ; segment address of vm bytecode
first_arg dw ? ; first actual argument
arg_count dw ? ; number of args (len,name are not args)
rvreg dw ? ; vm register to hold return value
local_save ends
arg_ptr equ saved_si ; alias for current argument pointer
ssr_status equ xesc_status ; ssr return status (will be -1)
ssr_argnum equ xesc_vtype ; argument requested (zero based) by ssr
ssr_len equ xesc_value ; length requested
ssr_offset equ xesc_value+2 ; real mode offset to store arg
ssr_seg equ xesc_value+4 ; real mode segment to store arg
result_buf_len equ saved_si-xesc_status ; length of result buffer
xesc proc far
push bp ;save callers bp
sub sp,rvreg+2 ;reserve for local storage
mov rpc_saved_sp,sp ;save off stack pointer
mov bp,sp ; and update BP
mov xesc_func,1
lea bx,xesc_err_exit ; Set up error handler for xesc
mov error_return,bx
mov [bp].saved_es,es ;save segaddr of arguments
inc si ;bump past name to first arg
mov [bp].saved_si,si ; and save
mov [bp].first_arg,si
dec si
sub ax,2 ;calc # args (not incl. name)
mov [bp].arg_count,ax ; and save
RESET_REAL_BUFFER_OFFSET ;ensure start at zero
;
; Move the string name to the real mode buffer
;
xor bh,bh
mov bl,byte ptr es:[si] ;BX is reg# of name string
lea bx,regs[bx] ;VM reg @
mov [bp].rvreg,bx ; save as return register
mov si,[bx].C_page
cmp ptype[si],STRTYPE*2 ;is it a string?
je xesc_15 ;yes, jump
cmp ptype[si],SYMTYPE*2 ;is it a symbol?
je xesc_10 ;yes, jump
mov ax,XLI_ERR_NAME_BAD_TYPE ;error: name not string, symbol
jmp xesc_err_exit
;
; Warning : DS is not used for the local data segment in the following code
;
xesc_10:
%LoadPage ds,si ;page# in SI -> para# in DS
mov si,ss:[bx].C_disp ;DS:SI is symbol object @
mov cx,[si].sym_len ;get symbol object length
sub cx,sym_ovhd ;subtract symbol's overhead
add si,sym_ovhd ;skip past overhead
jmp short xesc_25
xesc_15: %LoadPage ds,si ;page# in SI -> para# in DS
mov si,ss:[bx].C_disp ;DS:DI is string object @
mov cx,[si].str_len ;get string object length
cmp cx,0 ;is it positive?
jge xesc_20 ;yes, jump; normal string
add cx,str_ovhd*2 ;no, assume short string
;rather than really long string
;and make positive
xesc_20: sub cx,str_ovhd ;subtract string's overhead
add si,str_ovhd ;skip past overhead
xesc_25:
push ds
push si ;temp save string ptr
push cx ;and length
mov ax,ss ;get local data seg
mov ds,ax
MOVE_ARGS_TO_BUF cx,REAL_MODE_BUFFER,autoincr ;move length to buf
pop cx
pop si
pop ds ;ds:si => string ptr
MOVE_TO_REAL_BUF autoincr ;move string to buf
;
; Warning : DS is not used for the local data segment in the above code
;
mov ax,ss
mov ds,ax ;restore data segment
;
; Move argument count to real mode buffer
;
mov bx,[bp].arg_count
MOVE_ARGS_TO_BUF bx,,autoincr,save ;move #args to buffer
;
; Move the xesc arguments to the real mode buffer.
;
cmp bx,0 ;any arguments?
je xloop_done ; no, jump
xesc_loop:
les si,dword ptr [bp].arg_ptr ;es:si => argument
inc [bp].saved_si ;bump for next time thru
xor bh,bh
mov bl,byte ptr es:[si] ;pick up arg
lea bx,regs[bx] ;BX is VM reg @
mov si,[bx].C_page ;get its page#
mov si,ptype[si] ; and type
push si ;save around following
;move type info to buffer
MOVE_ARGS_TO_BUF si,REAL_MODE_BUFFER,autoincr
; Dispatch on argument type
pop si ;restore type #
call cs:word ptr do_arg[si] ;process argument (by type)
dec [bp].arg_count ;any more args left
jnz xesc_loop ; yes, loop
xloop_done:
RESET_REAL_BUFFER_OFFSET ;reset buffer ptr for later
;
; Now issue the RPC call, real routine knows where the buffer is
;
push 0 ;dummy word
push RPCXESC ;RPC REQUEST CODE
xesc_57:
mov dx,sp ;DS:DX = transaction buffer
mov cx,4
mov bx,cx ;DX = length of result
mov al,rpc_handle
mov ah,RPC ;Issue RPC
int DOS ;Extended Dos func
pop ax ;get return status
mov sp,bp ;dump args off stack
or ax,ax ;error during xesc call?
je normal ; no, continue
cmp ax,XLI_ERR_NO_SUCH_NAME ;calling an unknown xli func?
jne xesc_null_err_exit ; no, return error
mov bx,[bp].rvreg ;load bx with name requested
jmp xesc_err_exit ;and return with error
; We're back with a return value--unless it's a special service call.
; At this point, ES:DI should point to buffer.
normal: cld
mov si,sp ;store data on stack (ds:si)
les di,dword ptr REAL_MODE_BUFFER ;address real buffer (es:di)
mov cx,result_buf_len ;cx = length
MOVE_FROM_REAL_BUF ;move return data to local stack
mov ax,[bp].xesc_status ;get return status
or ax,ax ;Check status
jl ssr ; <0 = SSR
; 0 = normal return
mov di,[bp].xesc_vtype ;get return value type
cmp di,N_RV*2 ;out of range?
jb xesc_70 ; no, jump
cmp di,RV_ERR*2 ;xli program error?
jne xesc_65 ; no, jump
mov si,bp ;
add si,xesc_value ;DS:SI => return value
mov bx,[bp].rvreg ;bx = return reg address
call do_strval ;go get the error message
mov ax,XLI_ERR_EXTERNAL_ERROR ;ax=error indication
mov bx,[bp].rvreg ;bx = return reg address
jmp xesc_err_exit ;bx=message
xesc_65:
mov ax,XLI_ERR_VALUE_BAD_TYPE ;unkown return type
jmp xesc_null_err_exit ;return error
xesc_70:
mov si,bp
add si,xesc_value ;DS:SI => return value
mov bx,[bp].rvreg ;bx = return reg address
call cs:word ptr do_val[di] ;process return value
mov ax,0 ;AX=0 says no errors
xesc_null_err_exit:
lea bx,nil_reg ;"nil irritant" for some errors
; ax = error indicator (0 = no error), bx=irritant
xesc_err_exit label near
mov cx,mem_entry ;any entries in mem_table?
jcxz xesc_ex10 ;no, jump
push ax ;tempsave error indicators
push bx
xor bx,bx
mov mem_entry,bx ;see if any real mode segments
xesc_ex05:
mov es,mem_table[bx] ;get entry in mem_table
mov ax,DELETE_SEG ;delete the real mode segment
int dos
jnc xesc_ex07
mov bx,offset dl_seg
mov cx,offset xli_txt
jmp fatal_pro_err ;control will not return here
xesc_ex07:
inc bx
inc bx ;address next entry
loop xesc_ex05 ;go release next one
pop bx ;restore error indicators
pop ax
; at this point, ax = error number, bx = irritant (if error)
xesc_ex10:
mov sp,rpc_saved_sp ;clean up stack
add sp,rvreg+2
pop bp ;restore callers bp
ret ;return
; SSR
; A real procedure has issued a System Service Request (SSR). Currently,
; this means to pass a string to the real procedure. The result buffer
; indicates the argument from the %xesc call requested (0 based), the
; length of the string, and the real mode segment/offset to place the
; string. This routine copies the data into the real routine's address
; space, and returns.
;
ssr label near
mov si,[bp].first_arg ;arg list pointer
add si,[bp].ssr_argnum ;now address arg desired
mov es,[bp].saved_es ;ES:SI addresses the arg
mov bl,byte ptr es:[si] ;get reg #
xor bh,bh
lea bx,regs[bx] ;BX is reg@
mov si,[bx].C_disp ;si = string object offset
mov bx,[bx].C_page ;bx = string object page #
%LoadPage es,bx ;es:si => string object
inc si ;skip over tag
cld
lods word ptr es:[si] ;get string's length
cmp ax,0 ;a short string?
jge ss_5 ;no, jump
add ax,str_ovhd*2 ;yes
ss_5: sub ax,str_ovhd ;subtract off overhead
;
; es:si => string, ax = length
;
mov dx,[bp].ssr_len ;get length of dest string
or dx,dx ;if non-zero
jnz ss_10 ; then jump
;
; A length of zero indicates that the xli routine wants to address far
; strings. Allocate real memory and put the real segment address into
; the transaction buffer. PRO2REAL will move the string to real memory.
; The real memory selector is saved in mem_table, and released when we
; exit this xesc call.
;
push ax ;save length
push si
push es ;save ptr to string
xor cx,cx
mov dx,ax ;cx:dx = string length
mov ax,ALLOC_REAL ;Allocate real segment
int dos ;Allocate real segment
jnc ss_07
mov bx,offset al_seg
mov cx,offset xli_txt
jmp fatal_pro_err ;control will not return here
ss_07:
; ax=selector, bx=para address
push ax ;tempsave selector
les di,dword ptr REAL_MODE_BUFFER
add di,ssr_seg ;address of real buffer (es:di)
MOVE_ARGS_TO_BUF bx ;save segment to real mode
mov dx,cx ;dx = length
pop ax ;restore selector
; save real memory selector in table
mov bx,mem_entry ;get entry number
inc mem_entry ;bump number of entries
shl bx,1 ;index into memory table
mov mem_table[bx],ax ;save selector there
pop es
pop di ;es:di => string to copy
pop dx ;restore length
jmp ss_25
; We have a string length here, set ds:si to point to the real memory
; address. PRO2REAL will create a real window over this area, and copy
; the string to it.
ss_10:
cmp ax,dx ;string len >= buffer len?
jae ss_20 ;yes, jump
mov dx,ax ;dx = #chars to copy
ss_20:
mov di,si ;es:di = string to copy
mov si,bp
add si,ssr_offset ;ds:si => real memory address
xor ax,ax ;use ds:si to map address
ss_25:
call pro2real ;copy to real memory
push cx
push RPCXLISSR
jmp xesc_57
xesc endp
; SOFTINT
; Handler for the "software interrupt"
;
; Use:
; call SOFTINT 7,op,intnum,return-type,ax,bx,cx,dx
; where all arguments are pcs registers
;
; On exit:
; The first register will contain the returned value
;
; Description:
; All args are interrogated to determine the length of a buffer
; required to hold the args. A buffer is allocated in real mode
; (via function E8), the args are then copied into the buffer,
; and the software interrupt is issued. Upon return, the return
; value is processed, the buffer is deallocated, and the first
; register is set with the return value.
;
; This following data will be allocated locally within SWINT
;
local_save struc
; Following is the machine state block for Issue Real Interrupt request
msb_ax dw ? ; ax register for interrupt
msb_bx dw ? ; bx register for interrupt
msb_cx dw ? ; cx register for interrupt
msb_dx dw ? ; dx register for interrupt
msb_si dw ? ; si register for interrupt
msb_di dw ? ; di register for interrupt
msb_flags dw ? ; flags register for interrupt
msb_ds dw ? ; ds register for interrupt
msb_es dw ? ; es register for interrupt
; The following local data contains ptrs into the real segment
selector dw ? ; selector for real segment
buf_ptr dw ? ; local pointer into real segment
msb_ptr dw ? ; local pointer into msb
stop dw ? ; temp data
work_spc dd ? ; temp working storage
; Following definitions define the stack upon call
caller_bp dw ? ; callers bp
farret dd ? ; far return address
dummy dw ? ; %esc first arg = # operands
arg4 dw ? ; arg4 = dx
arg3 dw ? ; arg4 = cx
arg2 dw ? ; arg4 = bx
arg1 dw ? ; arg4 = ax
ret_type dw ? ; return type
intnum dw ? ; interrupt number
op dw ? ; op-code
local_save ends
softint proc far
push bp ;save callers bp
sub sp,caller_bp ;allocate local storage
mov bp,sp ;and update BP
and xesc_func,0 ;note sw-int
lea bx,swi_err_exit ;error handler for sw-int
mov error_return,bx
; Sum up the space required to hold all the arguments
mov si,bp
add si,arg4-2 ;SI => args
mov [bp].stop,si ;save for later
mov di,bp
add di,msb_dx ;DI => regs in msb
mov cx,4 ;CX = number of args
xor dx,dx ;DX = space required
sum_spc:
push di ;temp save di
add si,2 ;address arg
mov bx,[si] ;get vm reg
mov di,[bx].C_page ;get its page#
cmp ptype[di],STRTYPE*2 ;Is it a string?
jne sum_010 ; no, jump
%LoadPage es,di ; yes,
mov di,[bx].C_disp ; es:di => string
inc di ; skip tag
mov ax,es:[di] ; get string object length
cmp ax,0 ; is it positive?
jge sum_005 ; yes, jump; normal string
add ax,str_ovhd*2 ; no, short string
sum_005: sub ax,str_ovhd ; subtract overhead
inc ax ; add 1 for null terminator
jmp short sum_020
sum_010:
mov ax,4 ;non-string at least 4 bytes
cmp ptype[di],FLOTYPE*2 ;floating point object?
jne sum_020 ; no, jump
add ax,4 ; yes, floats are 8 bytes
sum_020:
pop di ;msb register ptr
mov ds:[di],ax ; save length of object
sub di,2 ; next msb register ptr
add dx,ax ;sum space required
loop sum_spc ;and loop
; CX:DX = space required to buffer the args, SI => arg 1 at this point
mov ax,ALLOC_REAL ;Create real segment
int DOS ;Extended Dos Function request
jnc swi_07
mov bx,offset al_seg
mov cx,offset swi_txt
jmp fatal_pro_err ;control will not return here
swi_07:
mov [bp].selector,ax ;save segment selector
mov es,ax ;es = real buffer selector
mov [bp].msb_ds,bx ;save para address in msb
mov [bp].msb_es,bx ;save para address in msb
mov [bp].buf_ptr,0 ;pointer within real segment
mov [bp].msb_ptr,bp ;pointer into msb regs
; Move each arg into the buffer, SI => arg1 at this point
;
swi_020:
cmp si,[bp].stop ;all args processed?
je swi_025 ; yes, jump
std
lods word ptr [si] ;pick up arg
mov bx,ax ;save in BX
mov di,[bp].msb_ptr ;di = ptr to reg in msb
add [bp].msb_ptr,2 ; set for next time
mov cx,ds:[di] ;cx = length of object
mov ax,[bp].buf_ptr ;ax = ptr into buffer
add [bp].buf_ptr,cx ; set for next time
mov ds:[di],ax ;update msb reg with buf ptr
mov di,ax ;es:di => buffer
; Dispatch on argument type
push si ;tempsave arg ptr
mov si,[bx].C_page ;get page#
mov si,ptype[si] ; and type
; BX=page #, CX=length, ES:DI=>buffer
call cs:word ptr do_arg[si] ;Handle each object.
pop si ;restore arg ptr
jmp swi_020
; At this time all args are in the buffer, Issue the sofware interrupt
swi_025:
cld
mov bx,[bp].intnum ;get reg holding int
mov ax,[bx].C_disp ;AL = interrupt number
mov dx,bp ;DS:DX => machine state block
mov bx,msb_es+2 ;# bytes which may change
mov ah,REAL_INTRP ;AH = Issue Real Interrupt
int DOS ;Extended Dos Function Request
jnc swi_27
mov bx,offset rl_int
mov cx,offset swi_txt
jmp fatal_pro_err ;control will not return here
swi_27:
; We're back from software interrupt, lets get return value
mov bx,[bp].ret_type ;get vm reg
mov di,[bx].C_disp
shl di,1 ;make index into valu table
cmp di,N_RV*2 ;return value out of range?
jb swi_070
;bx = reg holding return type
mov ax,SWI_ERR_VALUE_BAD_TYPE ;ax = error indicator
jmp swi_err_exit
swi_070:
; now go convert the return values
mov si,bp ;ds:si => address of ret value
mov bx,[bp].op ;bx = return register
call cs:word ptr do_val[di] ;handle one type of return value
mov ax,0 ;AX=0 says no errors
; ax= error indicator (if nonzero, bx = irritant)
swi_err_exit label near
push ax ;push error number
push bx ;push irritant
mov es,[bp].selector
mov ax,DELETE_SEG ;Delete Real Segment
int DOS ;Extended Dos Function
jnc swi_077
mov bx,offset dl_seg
mov cx,offset swi_txt
jmp fatal_pro_err ;control will not return here
swi_077:
pop cx ;cx = irritant
pop ax ;ax = error indication
mov bx,ax ; move to bx
dec bx ; form index
js swi_ret ;negative - no error
shl bx,1 ;form index
mov bx,swi_errs[bx] ;bx => error message
mov ax,1 ;note non-restartable
; ax= error indicator (if nonzero bx=message address, cx = irritant)
swi_ret:
mov sp,bp
add sp,caller_bp
pop bp
ret
softint endp
subttl Code segment: Copy arguments to xfer buffer
page
;; Jump tables to handle arguments to the %xesc call
; indexed by argument type (standard PCS type tag)
do_arg dw do_lstarg ;0=list (#f only)
dw do_fixarg ;1=fixnum
dw do_floarg ;2=flonum
dw do_bigarg ;3=bignum
dw do_symarg ;4=symbol (#t only)
dw do_strarg ;5=string
dw do_errarg ;6 the rest we don't care about
dw do_errarg ;7
dw do_errarg ;8
dw do_errarg ;9
dw do_errarg ;10
dw do_errarg ;11
dw do_errarg ;12
dw do_errarg ;13
dw do_errarg ;14
dw do_errarg ;15
; On entry to all the argument handler routines:
; ES:DI = pointer to real mode buffer to store data
; BX = address of VM reg with page:offset of Scheme object
; SI = Type of operand code
;
; On exit:
; CX = number of bytes moved to the buffer pointed to by ES:DI
;
; Process list argument
;
do_lstarg label near ;looking for false only
cmp [bx].C_page,NIL_PAGE*2
je do_lst01
jmp do_errarg
do_lst01:
xor ax,ax
jmp do_log
;
; Process fixnum argument
;
do_fixarg label near
mov ax,[bx].C_disp ;get the fixnum data
shl ax,1 ;deal with sign bit
sar ax,1 ;ax = 16-bit signed int
; True and false are treated as the numbers 1 and 0, respectively.
; Boolean-argument processing merges into integer processing at this point.
do_log: cwd ;dx:ax is 32-bit signed int
MOVE_ARGS_TO_BUF <dx,ax>,,autoincr,save
ret ;and return
;
; Process float argument
;
do_floarg label near
push ds ;preserve data seg
mov si,[bx].C_page ;get float's page #
mov ax,[bx].C_disp ; and offset
%LoadPage ds,si
mov si,ax ;ds:si => float
inc si ;bump past header
mov cx,8 ;cx = length of float
MOVE_TO_REAL_BUF autoincr,save ;move float to buffer
pop ds ;restore data seg
ret ;and return
;
; Process bignum argument
;
do_bigarg label near
; Stage the conversion to longint on the stack
sub sp,4 ;allocate stack space for long
mov ax,sp ;note its address
; ok to add to stack here because we've reserved space above.
push es ;save regs around call
push di
push bp
mov bp,sp
push bx ;push VM reg@
push ax ;push buffer@
mov C_fn,offset pgroup:int2long ;convert bignum to long
call far ptr far_C
pop bx ;dump buffer@
pop bx ;restore VM reg@
pop bp ;restore bp
pop di ; di
pop es ; es
; above cleans stack up from calling C routine
cmp ax,0 ;did bignum convert OK?
je do_big5 ;yes, jump
; there was an error in converting the number
mov ax,XLI_ERR_BIG_TO_32_BITS ;ax = error # (default xli)
cmp xesc_func,0 ;performing xli function?
jne do_bigerr ; yes, jump
mov ax,SWI_ERR_BIG_TO_32_BITS ;ax = error # (for sw-int)
; ax=error number, bx=irritant
do_bigerr:
jmp error_return
do_big5:
mov si,sp ;ds:si => long int
mov cx,8 ;cx = length
MOVE_TO_REAL_BUF autoincr,save ;move float to buffer
add sp,4 ;clean up stack
ret ;and return
;
; Process symbol argument
;
do_symarg label near ;looking for true only
cmp [bx].C_page,T_PAGE*2
jne do_errarg
cmp [bx].C_disp,T_DISP
jne do_errarg
mov ax,1
jmp do_log
;
; Process string arguments
;
do_strarg label near
or xesc_func,0 ;doing xesc?
jz swi_strarg ; no, jump
MOVE_ARGS_TO_BUF <-1>,,autoincr,save ; yes, indicate string
ret
swi_strarg: ;move string to swint buffer
push ds ;preserve regs
push si
mov ax,[bx].C_disp ;get offset
mov si,[bx].C_page ;get page #
%LoadPage ds,si
mov si,ax ;ds:si => string
inc si ;skip tag
cld
lods word ptr [si] ;get length
or ax,ax ;is it positive?
jge swi_str05 ;yes, jump; normal string
add ax,str_ovhd*2 ;no, short string
swi_str05:
sub ax,str_ovhd ;subtract overhead
mov cx,ax ;CX = length of string
MOVE_TO_REAL_BUF autoincr ;move string across
mov ax,ss
mov ds,ax
push cx ;save # bytes just written
MOVE_BYTE_TO_BUF 0,,autoincr ;write out null terminator
pop cx
inc cx ;cx = total # bytes written
pop si ;restore preserved regs
pop ds
ret
do_errarg label near
mov ax,XLI_ERR_ARGN_BAD_TYPE ;ax = error # (default xli)
cmp xesc_func,0 ;performing xli function?
jne do_errerr ; yes, jump
mov ax,SWI_ERR_ARGN_BAD_TYPE ;ax = error # (for sw-int)
; ax = error number, bx=irritant
do_errerr:
jmp error_return
subttl Code segment: Copy return value back into Scheme
page
;; Jump tables to handle values returned from the real routine
; indexed by value type (SW-INT return types)
do_val dw do_intval ;0=integer
dw do_TFval ;1=true/false
dw do_strval ;2=string
dw do_floval ;3=flonum
; On entry to all the value handler routines:
; BX = result register address
; DS:SI = pointer to return value
;
; Process integer return value
;
do_intval proc near
do_int10:
push bp
mov bp,sp ;get BP set for C call
or xesc_func,0 ;doing xesc?
jnz doint_05 ; yes, jump
push [si] ;si=> msb_ax on stack. remember
push [si]+2 ;lattice's return conventions
jmp doint_07
doint_05: push [si]+2 ;push longint
push [si]
doint_07: push bx ;push vm reg address
mov C_fn,offset pgroup:long2int ;allocate integer
call far ptr far_C ;C longint -> PCS integer
;(bignum or fixnum)
mov sp,bp ;pop C args
pop bp ;restore callers bp
ret ; and return
do_intval endp
;
; Process true/false return value
;
do_TFval proc near
mov cx,0
or xesc_func,0 ;doing xesc?
jnz dotf_05 ; yes, jump
mov ax,[si]+2 ;si=> msb_ax on stack. remember
jmp dotf_07 ;lattice's return convention
dotf_05: mov ax,[si] ;get value
dotf_07: or ax,ax ;zero?
jz do_TF10 ; yes (false object)
mov ax,T_DISP ; no (true object)
mov cx,T_PAGE*2
do_TF10:
mov [bx].C_disp,ax
mov [bx].C_page,cx
ret
do_TFval endp
;
; Process float return value
;
do_floval proc near
push bp
mov bp,sp
or xesc_func,0 ;doing xesc?
jnz doflo_05 ; yes, jump
push [si] ;si=> msb_ax on stack. remember
push [si]+2 ;lattice's return conventions
push [si]+4 ;and push args appropriately.
push [si]+6
jmp doflo_07
doflo_05: push [si]+6 ;push float values
push [si]+4
push [si]+2
push [si]
doflo_07: push bx ;push vm return reg
mov C_fn,offset pgroup:alloc_fl ;allocate float
call far ptr far_C ;C double -> PCS flonum
mov sp,bp ;pop args from stack
pop bp
ret
do_floval endp
;
; Process string return values
;
do_strval proc near
or xesc_func,0 ;doing xesc?
jz swi_strval ; no, jump
;
; Do it for xli
;
push bp
mov bp,sp
mov cx,[si] ;get string length
cmp cx,16380 ;string length short enough?
jbe do_stv15 ;yes, jump
mov cx,16380 ;no, truncate at max
do_stv15:
; allocate the space for the return value string object
push cx ;save length for later
push si ; pointer to buffer
push bx ; return value VM reg
push bp
mov bp,sp ;get BP set for C call
push cx ;push length
push STRTYPE ;push type
push bx ;push return value VM reg @
mov C_fn,offset pgroup:alloc_bl ;allocate block
call far ptr far_C ;go do it
mov sp,bp ;pop C args
pop bp
pop bx ;return VM reg
mov di,[bx].C_disp
mov bx,[bx].C_page
%LoadPage es,bx
add di,3 ;es:si => destination
pop si
add si,2 ;ds:si => real mode address
pop dx ;dx = length
call real2pro ;xfer from real mem to pro mem
mov sp,bp ;clean up stack
pop bp ;restore caller's bp
ret ;and return
;
; Do it for software interrupt
;
swi_strval:
push ds ;tempsave ds
mov si,[bp].msb_ax
mov ds,[bp].selector ;DS:SI points to string
push ss
pop es
mov di,bp
add di,work_spc ;ES:DI => destination
mov ax,BLOCK_XFER ;grab one byte and test zero
mov cx,1
mov dx,0FFFFh
swi_str01:
inc dx ;# bytes read
int DOS ;xfer 1 byte
inc si ;next byte to read
cmp byte ptr es:[di],0 ;is it zero?
jne swi_str01 ;no, get next char
swi_stv15:
pop ds ;restore ds
push dx ;save length for later
;
; allocate the space for the return value string object
;
mov ax,[bp].op ;get return vm reg
push bp ;tempsave around call
mov bp,sp ;get BP set for C call
push dx ;push length
push STRTYPE
push ax ;push vm reg
mov C_fn,offset pgroup:alloc_bl
call far ptr far_C ;allocate string object;
;"alloc_block" takes care
;of overhead matters
mov sp,bp ;pop C args
pop bp
mov bx,[bp].op ;return value VM reg
mov di,[bx].C_disp
mov bx,[bx].C_page
%LoadPage es,bx ;ES:DI is dest object @
add di,3 ;skip past string's overhead
mov si,[bp].msb_ax
mov ds,[bp].selector ;DS:SI is string in buffer
pop cx ;CX = length
mov ax,BLOCK_XFER ;copy into scheme heap
int DOS ;Extended Dos function call
mov ax,ss
mov ds,ax
ret
do_strval endp
do_errval proc near
mov ax,XLI_ERR_VALUE_BAD_TYPE
jmp error_return
do_errval endp
public pro2real,real2pro,map_real_mem
; REAL2PRO
;
; On entry:
; DS:SI => address of real mode buffer
; ES:DI => scheme heap
; DX = length
;
; On exit:
; CX is number of chars xfered
real2pro proc near
push ds ; save data segment
call map_real_mem ; create real window (selector in ax)
; Error Checks here
mov cx,dx ; cx = length
; WARNING: DS addresses real memory below
mov ds,ax ; real mode selector
xor si,si ; ds:si = source (real data)
mov ax,BLOCK_XFER ; do block xfer
int DOS
mov ax,ds
mov es,ax ; es = mapped selector
mov ax,DELETE_SEG ; Delete Segment
int DOS
jnc r2p_next
xor bx,bx
mov bl,ss:xesc_func
shl bx,1
mov cx,ss:which_func[bx]
mov bx,offset dl_seg
jmp fatal_pro_err ;control will not return here
r2p_next:
; WARNING: DS does not address scheme's data segment above
pop ds ; restore data segment
ret
real2pro endp
; PRO2REAL
; Copy data from protected mode memory to real mode memory. If ax is
; non-zero, then it already contains a real selector where we can move
; the data - in this case we don't create a real window and delete the
; segment selector after the copy.
;
; On entry:
; if AX = 0
; then DX = length
; DS:SI => address of real mode buffer
; ES:DI => scheme heap
; else
; AX = selector to real mode buffer
; DX = length
; ES:DI => scheme heap
;
; On exit:
; CX is number of chars xfered
pro2real proc near
push ds ; callers data segment
push ax ; indicator
push di ; offset to data
or ax,ax ; do we have a selector already?
jnz p2r_010 ; yes, don't create real window (jump)
call map_real_mem ; no, create real window
; selector returned in ax
; Error Checks here
p2r_010:
mov cx,dx ; cx = length
; WARNING: DS addresses scheme heap below
mov bx,es
mov ds,bx
pop si ; ds:si = source (in scheme heap)
mov es,ax ; real mode selector
xor di,di ; es:di = destination (in real mode)
mode_xfer:
mov dx,ax ; tempsave selector
mov ax,BLOCK_XFER ; do block xfer
int DOS
pop ax ; restore indicator
or ax,ax ; was a selector passed in?
jnz mode_xf01 ; yes, then don't delete it
mov es,dx ; es = mapped selector
mov ax,DELETE_SEG ; Delete Segment
int DOS
jnc mode_next
xor bx,bx
mov bl,ss:xesc_func
shl bx,1
mov cx,ss:which_func[bx]
mov bx,offset dl_seg
jmp fatal_pro_err ;control will not return here
mode_next:
; WARNING: DS does not address scheme's data segment above
mode_xf01:
mov ax,ds
mov es,ax ; restore ptr to scheme heap
pop ds ; restore data segment
ret
pro2real endp
; MAP_REAL_MEM
; Map a real memory address into a selector for use in protected memory.
;
; DS:SI => address of real mode buffer
; DX = length
;
; On exit:
; Carry flag set on error
; AX = selector for real memory or error if carry flag set
;
; Regs used: ax,bx,cx,si - all destroyed
map_real_mem proc near
; create real mode window
xor ax,ax
mov cx,4 ; shift count
mov bx,[si]+2 ; bx = real segment address
mov al,bh ; create 32 bit address in SI:BX
shr ax,cl
shl bx,cl ; shift for physical mem calc
add bx,[si] ; add effective memory address
jnc mr_25
inc ax ; SI:BX = real memory address
mr_25:
mov si,ax ; si:bx = real memory address
xor cx,cx ; CX:DX = length
mov ax,CREATE_WIN ; Create Window function request
int DOS ; Return selector in AX
jnc mr_ret
xor bx,bx
mov bl,ss:xesc_func
shl bx,1
mov cx,ss:which_func[bx]
mov bx,offset cr_win
jmp fatal_pro_err ;control will not return here
mr_ret:
ret
map_real_mem endp
progx ends
subttl Prog segment code definitions
page
prog segment byte public 'PROG'
assume cs:pgroup
extrn next_SP:near,src_err:near
extrn fix_intr:near
public pcinit,set_crtint,reset_crtint,xli_ldall,xli_term,xli_xesc
; PC_INIT
; Perform initializations, some of which are PC specific.
;
pcinit proc near
call bid_rpc ;bid the real mode code
cmp pcs_sysd,0 ;have we found the system directory?
jz pcini_00 ; no, skip loading of xli
call xli_ldall ; yes, load xli stuff
pcini_00:
call pc_init ;get specific pc info
call fix_intr ;take over interrupts
ret ;return to caller
pcinit endp
; The following routines are gateways to routines in the progx segment
; for real procedure calls (RPC) and external language interface (XLI).
; Note that the progx routines are jumped to via the FAR_RPC table, however
; they return to the caller of this routine because we fix up the stack.
;
bid_rpc proc near
mov bx,frpc_bid ;initialize real procedure
jmp rpc_call
pc_init:
mov bx,frpc_init ;get machine type
jmp rpc_call
set_crtint:
mov bx,frpc_setcrt ;set crt interrupt
jmp rpc_call
reset_crtint:
mov bx,frpc_resetcrt ;reset crt interrupt
jmp rpc_call
xli_ldall:
mov bx,frpc_ldall ;load xli files
jmp rpc_call
xli_term:
mov bx,frpc_unld ;unload xli files
jmp rpc_call
xli_xesc:
mov bx,frpc_xesc ;perform xesc
jmp rpc_call
rpc_call:
pop dx ;pop return address
push prog ;push segment return
push dx ;then offset
jmp dword ptr FAR_RPC+[bx] ;jump to progx routine
ret ;we'll never return here
bid_rpc endp
; Far linkage *from* XLI
; (all the memory allocation routines are written in C).
; The caller of this should have set BP from SP before pushing the C args,
; then restore SP from BP afterwards to remove them from the stack.
; We don't preserve ES across the call.
public far_C
far_C proc far
push ds ;C likes ES=DS
pop es
pop C_retadr ;get far @ off stack so C sees its args
pop C_retadr+2
call [C_fn]
push C_retadr+2
push C_retadr
ret ;C returns with return value in AX..DX
far_C endp
prog ends
end