Initial commit (from git)
This commit is contained in:
@@ -0,0 +1,984 @@
|
||||
; Copyright (C) 1998 DJ Delorie, see COPYING.DJ for details
|
||||
; Copyright (C) 1997 DJ Delorie, see COPYING.DJ for details
|
||||
; Copyright (C) 1996 DJ Delorie, see COPYING.DJ for details
|
||||
; Copyright (C) 1995 DJ Delorie, see COPYING.DJ for details
|
||||
; -*- asm -*-
|
||||
;
|
||||
; KLUDGE-WARNING!
|
||||
;
|
||||
; So you say you want to change this file, right? Are you really sure
|
||||
; that's a good idea? Let me tell you a bit about the pitfalls here:
|
||||
;
|
||||
; * Some code runs in protected mode, some in real-mode, some in both.
|
||||
; * Some code must run on a 8088 without crashing it.
|
||||
; * Registers and flags may be expected to survive for a long time.
|
||||
; * The code is optimized for size, not for speed or readability.
|
||||
; * Some comments are parsed by other programs.
|
||||
;
|
||||
; You still want to change it? Oh well, go ahead, but don't come
|
||||
; crying back saying you weren't warned.
|
||||
;
|
||||
;-----------------------------------------------------------------------------
|
||||
; djgpp extender-less stub loader
|
||||
;
|
||||
; (C) Copyright 1993-1995 DJ Delorie
|
||||
;
|
||||
; Redistribution and use in source and binary forms are permitted
|
||||
; provided that: (1) source distributions retain this entire copyright
|
||||
; notice and comment, (2) distributions including binaries display
|
||||
; the following acknowledgement: ``This product includes software
|
||||
; developed by DJ Delorie and contributors to the djgpp project''
|
||||
; in the documentation or other materials provided with the distribution
|
||||
; and in all advertising materials mentioning features or use of this
|
||||
; software, and (3) binary distributions include information sufficient
|
||||
; for the binary user to obtain the sources for the binary and utilities
|
||||
; required to built and use it. Neither the name of DJ Delorie nor the
|
||||
; names of djgpp's contributors may be used to endorse or promote
|
||||
; products derived from this software without specific prior written
|
||||
; permission.
|
||||
;
|
||||
; THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
|
||||
; IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
|
||||
; WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
|
||||
;
|
||||
; Revision history:
|
||||
;
|
||||
; 93/12/05 DJ Delorie Initial version v2.00, requires DPMI 0.9
|
||||
; 94/10/13 CW Sandmann v2.01, accumlated changes: 60K load bug, limits, cwsdpmi, optimization
|
||||
; 94/10/29 CW Sandmann v2.03, M Welinder changes; cwsdpmi load anywhere, size decrease
|
||||
;
|
||||
.copyright "The STUB.EXE stub loader is Copyright (C) 1993-1995 DJ Delorie. "
|
||||
.copyright "Permission granted to use for any purpose provided this copyright "
|
||||
.copyright "remains present and unmodified. "
|
||||
.copyright "This only applies to the stub, and not necessarily the whole program.\n"
|
||||
.id
|
||||
;
|
||||
;-----------------------------------------------------------------------------
|
||||
; Interface to 32-bit executable:
|
||||
;
|
||||
; cs:eip according to COFF header
|
||||
; ds 32-bit data segment for COFF program
|
||||
; fs selector for our data segment (fs:0 is stubinfo)
|
||||
; ss:sp our stack (ss to be freed)
|
||||
; <others> All unspecified registers have unspecified values in them.
|
||||
;-----------------------------------------------------------------------------
|
||||
; This is the stubinfo structure. The presence of this structure
|
||||
; indicates that the executable is a djgpp v2.00 executable.
|
||||
; Fields will never be deleted from this structure, only obsoleted.
|
||||
;
|
||||
.org 0 ; just in case
|
||||
stubinfo:
|
||||
stubinfo_magic: ; char [16]
|
||||
.db "go32stub, v 2.02" ; version may change, [0..7] won't
|
||||
stubinfo_size: ; unsigned long
|
||||
.dd stubinfo_end ; bytes in structure
|
||||
stubinfo_minstack: ; unsigned long
|
||||
.dd 0x80000 ; minimum amount of DPMI stack space (512K)
|
||||
stubinfo_memory_handle: ; unsigned long
|
||||
.dd 0 ; DPMI memory handle
|
||||
stubinfo_initial_size: ; unsigned long
|
||||
.dd 0 ; size of initial segment
|
||||
stubinfo_minkeep: ; unsigned short
|
||||
.dw 16384 ; amount of automatic real-mode buffer
|
||||
stubinfo_ds_selector: ; unsigned short
|
||||
.dw 0 ; our DS selector (used for transfer buffer)
|
||||
stubinfo_ds_segment: ; unsigned short
|
||||
.dw 0 ; our DS segment (used for simulated calls)
|
||||
stubinfo_psp_selector: ; unsigned short
|
||||
.dw 0 ; PSP selector
|
||||
stubinfo_cs_selector: ; unsigned short
|
||||
.dw 0 ; to be freed
|
||||
stubinfo_env_size: ; unsigned short
|
||||
.dw 0 ; number of bytes of environment
|
||||
stubinfo_basename: ; char [8]
|
||||
.db 8 .dup 0 ; base name of executable to load (asciiz if < 8)
|
||||
stubinfo_argv0: ; char [16]
|
||||
.db 16 .dup 0 ; used ONLY by the application (asciiz if < 16)
|
||||
stubinfo_dpmi_server: ; char [16]
|
||||
.db "CWSDPMI.EXE\0\0\0\0\0" ; used by stub to load DPMI server if no DPMI already present
|
||||
|
||||
.align 4
|
||||
stubinfo_end:
|
||||
|
||||
;-----------------------------------------------------------------------------
|
||||
; First, set up our memory and stack environment
|
||||
|
||||
.start ; execution begins here
|
||||
push cs
|
||||
pop ds
|
||||
mov [stubinfo_ds_segment], ds
|
||||
|
||||
mov [psp_segment], es ; save the PSP segment
|
||||
cld
|
||||
|
||||
;-----------------------------------------------------------------------------
|
||||
; Check that we have DOS 3.00 or later. (We need this because earlier
|
||||
; versions don't supply argv[0] to us and will scrog registers on dpmi exec).
|
||||
mov ah, 0x30
|
||||
int 0x21
|
||||
cmp al, 3
|
||||
jae dos3ok
|
||||
mov al, 109
|
||||
mov dx, msg_bad_dos
|
||||
jmpl error
|
||||
dos3ok:
|
||||
mov [dos_major], al
|
||||
mov si, stubinfo_minkeep
|
||||
|
||||
;-----------------------------------------------------------------------------
|
||||
; Resize memory in case we need to exec a DPMI server
|
||||
|
||||
resize_again:
|
||||
mov ax, [si] ; si=&stubinfo_minkeep
|
||||
or ax, ax
|
||||
jnz @f1
|
||||
; mov ax,0xfe00 ; 0 was probably 64k, so max it! (mod 512)
|
||||
mov ah,0xfe ; al already 0
|
||||
@f1:
|
||||
mov bx, end_of_memory ; does not include PSP
|
||||
cmp bx, ax ; is our program big enough to hold it?
|
||||
jae @f1
|
||||
mov bx, ax
|
||||
@f1:
|
||||
mov [si], bx ; si=&stubinfo_minkeep store for reference
|
||||
inc bh ; add 256 bytes for PSP
|
||||
mov cx, 0xff04 ; 0xff is for below
|
||||
shr bx, cl ; bytes to paragraphs
|
||||
|
||||
mov ah, 0x4a ; ES = PSP segment from above
|
||||
int 0x21 ; resize our memory block
|
||||
jnc @f1 ; did it work?
|
||||
shl bx,cl ; calculate smaller [keep] value
|
||||
dec bh
|
||||
mov [si], bx ; si=&stubinfo_minkeep
|
||||
jmp resize_again ; and try again
|
||||
@f1:
|
||||
|
||||
;-----------------------------------------------------------------------------
|
||||
; Scan environment for "PATH=" and the stub's full name after environment
|
||||
|
||||
mov es, es:[0x2c] ; get environment segment
|
||||
xor di, di ; begin search for NUL/NUL (di = 0)
|
||||
; mov cx, 0xff04 ; effectively `infinite' loop
|
||||
xor al, al
|
||||
.db 0xa9 ; "test ax,...." -- skip 2 bytes
|
||||
scan_environment:
|
||||
repne
|
||||
scasb ; search for NUL
|
||||
cmpw es:[di], 0x4150 ; "PA"
|
||||
jne not_path
|
||||
scasw
|
||||
cmpw es:[di], 0x4854 ; "TH"
|
||||
jne not_path
|
||||
scasw
|
||||
cmpb es:[di], '='
|
||||
jne not_path
|
||||
inc di ; Point to PATH contents
|
||||
mov [path_off], di ; save for later
|
||||
dec di ; in case the PATH is empty
|
||||
not_path:
|
||||
scasb
|
||||
jne scan_environment ; no, still environment
|
||||
scasw ; adjust pointer to point to prog name
|
||||
|
||||
;; When we are spawned from a program which has more than 20 handles in use,
|
||||
;; all the handles passed to us by DOS are taken (since only the first 20
|
||||
;; handles are inherited), and opening the .exe file will fail.
|
||||
;; Therefore, we forcefully close handles 18 and 19, to make sure at least two
|
||||
;; handles are available.
|
||||
|
||||
mov ah, 0x3e
|
||||
mov bx, 19
|
||||
int 0x21 ; don't care about errors
|
||||
mov ah, 0x3e
|
||||
mov bx, 18
|
||||
int 0x21 ; don't care about errors
|
||||
|
||||
;-----------------------------------------------------------------------------
|
||||
; Get DPMI information before doing anything 386-specific
|
||||
|
||||
push es
|
||||
push di
|
||||
xor cx, cx ; flag for load attempt set cx = 0
|
||||
jz @f2 ; We always jump, shorter than jmp
|
||||
@b1:
|
||||
mov al, 110
|
||||
mov dx, msg_no_dpmi
|
||||
jmpl error
|
||||
@b2:
|
||||
or cx, cx
|
||||
jnz @b1 ; we already tried load once before
|
||||
inc cx
|
||||
call load_dpmi
|
||||
jc @b1
|
||||
@f2:
|
||||
mov ax, 0x1687 ; get DPMI entry point
|
||||
int 0x2f
|
||||
or ax, ax
|
||||
jnz @b2 ; if 0 then it's there
|
||||
and bl, 1 ; 32 bit capable?
|
||||
jz @b2
|
||||
@f3:
|
||||
mov [modesw], di ; store the DPMI entry point
|
||||
mov [modesw+2], es
|
||||
mov [modesw_mem], si
|
||||
pop di
|
||||
pop es
|
||||
|
||||
;-----------------------------------------------------------------------------
|
||||
; Now, find the name of the program file we are supposed to load.
|
||||
|
||||
; xor ah, ah ; termination character (set above!)
|
||||
call store_env_string ; copy it to loadname, set bx
|
||||
|
||||
mov [stubinfo_env_size], di
|
||||
mov [loadname_nul], si ; remember nul so we can change it to $
|
||||
cmpb stubinfo_basename[0], 0
|
||||
je no_symlink
|
||||
|
||||
;-----------------------------------------------------------------------------
|
||||
; Replace the stub's file name with the link's name after the directory
|
||||
|
||||
mov cx, 8 ; max length of basename
|
||||
mov di, stubinfo_basename ; pointer to new basename
|
||||
@b1:
|
||||
mov al, [di] ; get next character
|
||||
inc di
|
||||
or al, al ; end of basename?
|
||||
je @f1
|
||||
mov [bx], al ; store character
|
||||
inc bx
|
||||
loop @b1 ; eight characters?
|
||||
@f1:
|
||||
movd [bx], 0x4558452e ; append ".EXE"
|
||||
add bx, 4
|
||||
movb [bx], 0 ; null terminate
|
||||
mov [loadname_nul], bx ; remember nul so we can change it to $
|
||||
|
||||
no_symlink:
|
||||
|
||||
;-----------------------------------------------------------------------------
|
||||
; Load the COFF information from the file
|
||||
|
||||
mov ax, 0x3d00 ; open file for reading
|
||||
mov dx, loadname
|
||||
int 0x21
|
||||
jcl error_no_progfile ; do rest of error message
|
||||
|
||||
@f1:
|
||||
mov [program_file], ax ; store for future reference
|
||||
|
||||
mov bx, ax
|
||||
mov cx, exe_header_length
|
||||
mov dx, exe_header
|
||||
mov ah, 0x3f ; read EXE header
|
||||
int 0x21
|
||||
|
||||
xor dx, dx ; dx = 0
|
||||
xor cx, cx ; offset of COFF header
|
||||
|
||||
mov ax, [exe_magic]
|
||||
cmp ax, 0x014c ; COFF?
|
||||
je file_is_just_coff
|
||||
cmp ax, 0x5a4d ; EXE magic value
|
||||
jnel error_not_exe
|
||||
|
||||
mov dx, [exe_sectors]
|
||||
shl dx, 9 ; 512 bytes per sector
|
||||
mov bx, [exe_bytes_last_page]
|
||||
or bx, bx ; is bx = 0 ?
|
||||
je @f1
|
||||
sub dh, 2 ; dx -= 512
|
||||
add dx, bx
|
||||
@f1:
|
||||
|
||||
file_is_just_coff: ; cx:dx is offset
|
||||
mov coff_offset[0], dx
|
||||
mov coff_offset[2], cx
|
||||
mov ax, 0x4200 ; seek from beginning
|
||||
mov bx, [program_file]
|
||||
int 0x21
|
||||
|
||||
mov cx, coff_header_length
|
||||
mov dx, coff_header
|
||||
mov ah, 0x3f ; read file (bx = handle)
|
||||
int 0x21
|
||||
|
||||
cmp ax, coff_header_length
|
||||
jne @f2
|
||||
cmpw coff_header[coff_magic], 0x014c
|
||||
@f2:
|
||||
jnel error_not_coff
|
||||
|
||||
mov eax, aout_header[aout_entry]
|
||||
mov [start_eip], eax
|
||||
|
||||
mov ecx, [coff_offset]
|
||||
|
||||
mov eax, text_section[s_scnptr]
|
||||
add eax, ecx
|
||||
mov [text_foffset], eax
|
||||
|
||||
mov eax, data_section[s_scnptr]
|
||||
add eax, ecx
|
||||
mov [data_foffset], eax
|
||||
|
||||
mov ebx, bss_section[s_vaddr]
|
||||
mov eax, bss_section[s_size]
|
||||
add ebx, eax
|
||||
mov eax, 0x00010001
|
||||
cmp ebx, eax
|
||||
jae @f1
|
||||
mov ebx, eax ; ensure 32-bit segment
|
||||
@f1:
|
||||
add ebx, 0x0000ffff ; ensure 64K rounded
|
||||
xor bx, bx ; clear rounded bits
|
||||
mov [stubinfo_initial_size], ebx
|
||||
|
||||
;-----------------------------------------------------------------------------
|
||||
; Set up for the DPMI environment
|
||||
|
||||
call include_umb
|
||||
mov bx, [modesw_mem]
|
||||
or bx, bx
|
||||
jz no_dos_alloc
|
||||
|
||||
mov ah, 0x48 ; allocate memory for the DPMI host
|
||||
int 0x21
|
||||
jcl error_no_dos_memory_umb
|
||||
mov es, ax
|
||||
|
||||
no_dos_alloc:
|
||||
call restore_umb
|
||||
mov ax, 1 ; indicates a 32-bit client
|
||||
callf [modesw] ; enter protected mode
|
||||
|
||||
jcl error_in_modesw
|
||||
|
||||
;-----------------------------------------------------------------------------
|
||||
; We're in protected mode at this point.
|
||||
|
||||
mov [stubinfo_psp_selector], es
|
||||
mov [stubinfo_cs_selector], cs
|
||||
mov ax, ds
|
||||
mov [stubinfo_ds_selector], ax
|
||||
mov es, ax
|
||||
|
||||
xor ax, ax ; AX = 0x0000
|
||||
mov cx, 1
|
||||
int 0x31 ; allocate LDT descriptor
|
||||
jc @f2
|
||||
mov [client_cs], ax
|
||||
|
||||
xor ax, ax ; AX = 0x0000
|
||||
; mov cx, 1 ; already set above
|
||||
int 0x31 ; allocate LDT descriptor
|
||||
@f2:
|
||||
jcl perror_no_selectors
|
||||
mov [client_ds], ax
|
||||
|
||||
; Try getting a DPMI 1.0 memory block first, then try DPMI 0.9
|
||||
; Note: This causes the Borland Windows VxD to puke, commented for now with ;*
|
||||
;* mov ax, 0x0504
|
||||
;* xor ebx, ebx ; don't specify linear address
|
||||
mov ecx, stubinfo_initial_size[0]
|
||||
;* mov edx, 1 ; allocate committed pages
|
||||
;* int 0x31 ; allocate memory block
|
||||
;* jc try_old_dpmi_alloc
|
||||
;* mov client_memory[0], ebx
|
||||
;* mov stubinfo_memory_handle[0], esi
|
||||
;* jmp got_dpmi_memory
|
||||
try_old_dpmi_alloc:
|
||||
mov ax, 0x0501
|
||||
mov bx, stubinfo_initial_size[2]
|
||||
; mov cx, stubinfo_initial_size[0] ;Set above
|
||||
int 0x31 ; allocate memory block
|
||||
jcl perror_no_dpmi_memory
|
||||
mov client_memory[2], bx
|
||||
mov client_memory[0], cx
|
||||
mov stubinfo_memory_handle[2], si
|
||||
mov stubinfo_memory_handle[0], di
|
||||
got_dpmi_memory:
|
||||
|
||||
mov ax, 0x0007
|
||||
mov bx, [client_cs] ; initialize client CS
|
||||
mov cx, client_memory[2]
|
||||
mov dx, client_memory[0]
|
||||
int 0x31 ; set segment base address
|
||||
|
||||
mov ax, 0x0009
|
||||
; mov bx, [client_cs] ; already set above
|
||||
mov cx, cs ; get CPL
|
||||
and cx, 0x0003
|
||||
shl cx, 5
|
||||
push cx ; save shifted CPL for below
|
||||
or cx, 0xc09b ; 32-bit, big, code, non-conforming, readable
|
||||
int 0x31 ; set descriptor access rights
|
||||
|
||||
mov ax, 0x0008
|
||||
; mov bx, [client_cs] ; already set above
|
||||
mov cx, stubinfo_initial_size[2]
|
||||
dec cx
|
||||
mov dx, 0xffff
|
||||
int 0x31 ; set segment limit
|
||||
|
||||
mov ax, 0x0007
|
||||
mov bx, [client_ds] ; initialize client DS
|
||||
mov cx, client_memory[2]
|
||||
mov dx, client_memory[0]
|
||||
int 0x31 ; set segment base address
|
||||
|
||||
mov ax, 0x0009
|
||||
; mov bx, [client_ds] ; already set above
|
||||
pop cx ; shifted CPL from above
|
||||
or cx, 0xc093 ; 32-bit, big, data, r/w, expand-up
|
||||
int 0x31 ; set descriptor access rights
|
||||
|
||||
mov ax, 0x0008
|
||||
; mov bx, [client_ds] ; already set above
|
||||
mov cx, stubinfo_initial_size[2]
|
||||
dec cx
|
||||
mov dx, 0xffff
|
||||
int 0x31 ; set segment limit
|
||||
|
||||
;-----------------------------------------------------------------------------
|
||||
; Load the program data
|
||||
|
||||
mov ax, 0x0100
|
||||
mov bx, 0x0f00 ; 60K DOS block size
|
||||
int 0x31 ; allocate DOS memory
|
||||
jnc @f1
|
||||
cmp ax, 0x0008
|
||||
jnel perror_no_dos_memory
|
||||
mov ax, 0x0100 ; try again with new value in bx
|
||||
int 0x31 ; allocate DOS memory
|
||||
jcl perror_no_dos_memory
|
||||
@f1:
|
||||
mov [dos_block_seg], ax
|
||||
mov [dos_block_sel], dx
|
||||
shl bx, 4 ; paragraphs to bytes
|
||||
mov [dos_block_size], bx
|
||||
|
||||
mov esi, [text_foffset] ; load text section
|
||||
mov edi, text_section[s_vaddr]
|
||||
mov ecx, text_section[s_size]
|
||||
call read_section
|
||||
|
||||
mov esi, [data_foffset] ; load data section
|
||||
mov edi, data_section[s_vaddr]
|
||||
mov ecx, data_section[s_size]
|
||||
call read_section
|
||||
|
||||
mov es, [client_ds] ; clear the BSS section
|
||||
mov edi, bss_section[s_vaddr]
|
||||
mov ecx, bss_section[s_size]
|
||||
xor eax,eax
|
||||
shr ecx,2
|
||||
.addrsize
|
||||
rep
|
||||
stosd
|
||||
|
||||
mov ah,0x3e
|
||||
mov bx, [program_file]
|
||||
int 0x21 ; close the file
|
||||
|
||||
mov ax, 0x0101
|
||||
mov dx, [dos_block_sel]
|
||||
int 0x31 ; free up the DOS memory
|
||||
|
||||
push ds
|
||||
pop fs
|
||||
mov ds, [client_ds]
|
||||
.opsize
|
||||
jmpf fs:[start_eip] ; start program
|
||||
|
||||
;-----------------------------------------------------------------------------
|
||||
; Read a section from the program file
|
||||
|
||||
read_section:
|
||||
mov eax, esi ; sector alignment by default
|
||||
and eax, 0x1ff
|
||||
add ecx, eax
|
||||
sub si, ax ; sector align disk offset (can't carry)
|
||||
sub edi, eax ; memory maybe not aligned!
|
||||
|
||||
mov [read_size], ecx ; store for later reference
|
||||
mov [read_soffset], edi
|
||||
|
||||
call zero_regs
|
||||
mov dpmi_regs[dr_dx], si ; store file offset
|
||||
shr esi, 16
|
||||
mov dpmi_regs[dr_cx], si
|
||||
mov bx, [program_file]
|
||||
mov dpmi_regs[dr_bx], bx
|
||||
movw dpmi_regs[dr_ax], 0x4200
|
||||
call pm_dos ; seek to start of data
|
||||
|
||||
; Note, handle set above
|
||||
mov ax, [dos_block_seg]
|
||||
mov dpmi_regs[dr_ds], ax
|
||||
movw dpmi_regs[dr_dx], 0 ; store file offset
|
||||
read_loop:
|
||||
movb dpmi_regs[dr_ah], 0x3f
|
||||
mov ax, read_size[2] ; see how many bytes to read
|
||||
or ax, ax
|
||||
jnz read_too_big
|
||||
mov ax, read_size[0]
|
||||
cmp ax, [dos_block_size]
|
||||
jna read_size_in_ax ; jna shorter than jmp
|
||||
read_too_big:
|
||||
mov ax, [dos_block_size]
|
||||
read_size_in_ax:
|
||||
mov dpmi_regs[dr_cx], ax
|
||||
call pm_dos ; read the next chunk of file data
|
||||
|
||||
xor ecx, ecx
|
||||
mov cx, dpmi_regs[dr_ax] ; get byte count
|
||||
mov edi, [read_soffset] ; adjust pointers
|
||||
add [read_soffset], ecx
|
||||
sub [read_size], ecx
|
||||
|
||||
xor esi, esi ; esi=0 offset for copy data
|
||||
shr cx, 2 ; ecx < 64K
|
||||
push ds
|
||||
push es
|
||||
mov es, [client_ds]
|
||||
mov ds, [dos_block_sel]
|
||||
.addrsize
|
||||
rep
|
||||
movsd
|
||||
pop es
|
||||
pop ds
|
||||
|
||||
add ecx, [read_size] ; ecx zero from the rep movsd
|
||||
jnz read_loop
|
||||
|
||||
ret
|
||||
|
||||
;-----------------------------------------------------------------------------
|
||||
; Routine to check al for delimiter
|
||||
|
||||
test_delim:
|
||||
cmp al, ':' ; watch for file name part
|
||||
je @f3
|
||||
cmp al, '/'
|
||||
je @f3
|
||||
cmp al, '\\'
|
||||
@f3:
|
||||
ret
|
||||
|
||||
;-----------------------------------------------------------------------------
|
||||
; Copy string from environment to loadname.
|
||||
; On entry: di = environment offset
|
||||
; ah = termination character (null also does)
|
||||
; On exit: bx = pointer to one character after last observed file delimiter
|
||||
; di = pointer to one character after last copied
|
||||
; si = pointer to the copied termination character
|
||||
; al = terminating character
|
||||
|
||||
store_env_string:
|
||||
mov si, loadname ; pointer to buffer
|
||||
mov bx, si ; in case no delimiters
|
||||
@b1:
|
||||
mov al, es:[di] ; copy a character to buffer
|
||||
inc di
|
||||
mov [si], al
|
||||
cmp al, ah ; end of file name?
|
||||
je @f1
|
||||
or al, al ; end of file name?
|
||||
je @f1
|
||||
inc si
|
||||
call test_delim
|
||||
jne @b1
|
||||
mov bx, si ; remember pointer to first char of
|
||||
je @b1 ; next name component (shorter than jmp)
|
||||
@f1:
|
||||
ret
|
||||
|
||||
;-----------------------------------------------------------------------------
|
||||
; Most errors come here, early ones jump direct (8088 instructions)
|
||||
|
||||
error_no_progfile:
|
||||
mov al, 102
|
||||
mov dx, msg_no_progfile
|
||||
jmp error_fn
|
||||
|
||||
error_not_exe:
|
||||
mov al, 103
|
||||
mov dx, msg_not_exe
|
||||
jmp error_fn
|
||||
|
||||
error_not_coff:
|
||||
mov al, 104
|
||||
mov dx, msg_not_coff
|
||||
; jmp error_fn
|
||||
|
||||
error_fn:
|
||||
push dx
|
||||
mov bx, [loadname_nul] ; error, print file name
|
||||
movb [bx], '$'
|
||||
mov bx, loadname
|
||||
jmp @f1
|
||||
|
||||
error_no_dos_memory_umb:
|
||||
call restore_umb
|
||||
error_no_dos_memory:
|
||||
mov al, 105
|
||||
mov dx, msg_no_dos_memory
|
||||
jmp error
|
||||
|
||||
error_in_modesw:
|
||||
mov al, 106
|
||||
mov dx, msg_error_in_modesw
|
||||
jmp error
|
||||
|
||||
perror_no_selectors:
|
||||
mov al, 107
|
||||
mov dx, msg_no_selectors
|
||||
jmp error
|
||||
|
||||
perror_no_dpmi_memory:
|
||||
mov al, 108
|
||||
mov dx, msg_no_dpmi_memory
|
||||
jmp error
|
||||
|
||||
perror_no_dos_memory:
|
||||
mov al, 105
|
||||
mov dx, msg_no_dos_memory
|
||||
; jmp error
|
||||
|
||||
error:
|
||||
push dx
|
||||
mov bx, err_string
|
||||
@f1:
|
||||
call printstr
|
||||
pop bx
|
||||
call printstr
|
||||
exit:
|
||||
mov bx, crlfdollar
|
||||
call printstr
|
||||
mov ah, 0x4c ; error exit - exit code is in al
|
||||
int 0x21
|
||||
|
||||
printstr1:
|
||||
inc bx
|
||||
push ax ; have to preserve al set by error call
|
||||
mov ah, 2
|
||||
int 0x21
|
||||
pop ax ; restore ax (John A.)
|
||||
printstr:
|
||||
mov dl, [bx]
|
||||
cmp dl, '$'
|
||||
jne printstr1
|
||||
ret
|
||||
|
||||
crlfdollar:
|
||||
.db 13,10,'$'
|
||||
;-----------------------------------------------------------------------------
|
||||
; DPMI utility functions
|
||||
|
||||
zero_regs:
|
||||
push ax
|
||||
push cx
|
||||
push di
|
||||
xor ax, ax
|
||||
mov di, dpmi_regs
|
||||
mov cx, 0x19
|
||||
rep
|
||||
stosw
|
||||
pop di
|
||||
pop cx
|
||||
pop ax
|
||||
ret
|
||||
|
||||
pm_dos:
|
||||
mov ax, 0x0300 ; simulate interrupt
|
||||
mov bx, 0x0021 ; int 21, no flags
|
||||
xor cx, cx ; cx = 0x0000 (copy no args)
|
||||
mov edi, dpmi_regs
|
||||
int 0x31
|
||||
ret
|
||||
|
||||
;-----------------------------------------------------------------------------
|
||||
; load DPMI server if not present
|
||||
; First check directory from which stub is loaded, then path, then default
|
||||
; On entry di points to image name
|
||||
|
||||
path_off:
|
||||
.dw 0 ; If stays zero, no path
|
||||
|
||||
load_dpmi:
|
||||
xor ah, ah ; Copy until this character (=0)
|
||||
call store_env_string ; copy stub image to "loadname"
|
||||
mov si, bx ; remove name so we can add DPMI name
|
||||
mov di, [path_off] ; Pointer to path contents (next try)
|
||||
jmp @f2
|
||||
loadloop:
|
||||
mov ah, ';' ; Copy until this character
|
||||
call store_env_string ; to "loadname"
|
||||
cmp si, loadname ; anything there?
|
||||
je do_exec ; final try (no path) let it return
|
||||
mov al, [si-1]
|
||||
call test_delim ; is final character a path delimiter
|
||||
je @f2
|
||||
movb [si], '\\' ; no, add separator between path & name
|
||||
inc si
|
||||
@f2:
|
||||
call do_exec ; copy our name to string and try load
|
||||
jc loadloop
|
||||
ret
|
||||
|
||||
;-----------------------------------------------------------------------------
|
||||
; add the string CWSDPMI to path ending
|
||||
|
||||
do_exec:
|
||||
call include_umb
|
||||
mov bx, stubinfo_dpmi_server
|
||||
@b1:
|
||||
mov al, [bx]
|
||||
mov [si], al
|
||||
inc bx
|
||||
inc si
|
||||
or al, al
|
||||
jne @b1
|
||||
; movw [si], 0x0a0d ;debug
|
||||
; movb [si+2], '$' ;debug
|
||||
|
||||
push es ; Save in case of failure
|
||||
push di
|
||||
|
||||
;memory saving - use dpmi_regs as a temporary parameter block
|
||||
push ds
|
||||
pop es ;zero_regs needs es set
|
||||
call zero_regs
|
||||
mov bx, dpmi_regs
|
||||
mov [bx+4], ds ;segment of command tail
|
||||
mov [bx+2], bx ;offset (point to zero)
|
||||
|
||||
mov dx, loadname
|
||||
; mov ah, 9 ;debug
|
||||
; int 0x21 ;debug
|
||||
mov ax, 0x4b00 ;Do program exec
|
||||
int 0x21
|
||||
pop di
|
||||
pop es
|
||||
jc @f1 ;carry set if exec failed
|
||||
|
||||
mov ah, 0x4d ;get return code
|
||||
int 0x21
|
||||
sub ax, 0x300 ;ah=3 TSR, al=code (success)
|
||||
neg ax ;CY, if not originally 0x300
|
||||
@f1:
|
||||
jmp restore_umb ;called func. return for us.
|
||||
|
||||
;-----------------------------------------------------------------------------
|
||||
; Make upper memory allocatable. Clobbers Ax and Bx.
|
||||
|
||||
include_umb:
|
||||
cmpb [dos_major], 5 ; Won't work before dos 5
|
||||
jb @f1
|
||||
mov ax, 0x5800 ; get allocation strategy
|
||||
int 0x21
|
||||
mov [old_strategy],al
|
||||
mov ax, 0x5802 ; Get UMB status.
|
||||
int 0x21
|
||||
mov [old_umb],al
|
||||
mov ax, 0x5801
|
||||
mov bx, 0x0080 ; first fit, first high then low
|
||||
int 0x21
|
||||
mov ax, 0x5803
|
||||
mov bx, 0x0001 ; include UMB in memory chain
|
||||
int 0x21
|
||||
@f1:
|
||||
ret
|
||||
|
||||
; Restore upper memory status. All registers and flags preserved.
|
||||
|
||||
restore_umb:
|
||||
pushf
|
||||
cmpb [dos_major], 5 ; Won't work before dos 5
|
||||
jb @f1
|
||||
push ax
|
||||
push bx
|
||||
mov ax, 0x5803 ; restore UMB status.
|
||||
mov bl,[old_umb]
|
||||
xor bh, bh
|
||||
int 0x21
|
||||
mov ax, 0x5801 ; restore allocation strategy
|
||||
mov bl,[old_strategy]
|
||||
xor bh, bh
|
||||
int 0x21
|
||||
pop bx
|
||||
pop ax
|
||||
@f1:
|
||||
popf
|
||||
ret
|
||||
|
||||
;-----------------------------------------------------------------------------
|
||||
; Stored Data
|
||||
err_string:
|
||||
.db "Load error: $"
|
||||
msg_no_progfile:
|
||||
.db ": can't open$"
|
||||
msg_not_exe:
|
||||
.db ": not EXE$"
|
||||
msg_not_coff:
|
||||
.db ": not COFF (Check for viruses)$"
|
||||
msg_no_dpmi:
|
||||
.db "no DPMI - Get csdpmi*b.zip$"
|
||||
msg_no_dos_memory:
|
||||
.db "no DOS memory$"
|
||||
msg_bad_dos:
|
||||
.db "need DOS 3$"
|
||||
msg_error_in_modesw:
|
||||
.db "can't switch mode$"
|
||||
msg_no_selectors:
|
||||
.db "no DPMI selectors$"
|
||||
msg_no_dpmi_memory:
|
||||
.db "no DPMI memory$"
|
||||
|
||||
;-----------------------------------------------------------------------------
|
||||
; Unstored Data, available during and after mode switch
|
||||
|
||||
last_generated_byte:
|
||||
|
||||
.align 512 ; Align ourselves to a sector
|
||||
; boundary for startup speed.
|
||||
.bss ; data after this isn't in file.
|
||||
|
||||
modesw: ; address of DPMI mode switch
|
||||
.dd 0
|
||||
modesw_mem: ; amount of memory DPMI needs
|
||||
.dw 0
|
||||
|
||||
program_file: ; file ID of program data
|
||||
.dw 0
|
||||
|
||||
text_foffset: ; offset in file
|
||||
.dd 0
|
||||
|
||||
data_foffset: ; offset in file
|
||||
.dd 0
|
||||
|
||||
start_eip: ; EIP value to start at
|
||||
.dd 0
|
||||
client_cs: ; must follow start_eip
|
||||
.dw 0
|
||||
client_ds:
|
||||
.dw 0
|
||||
|
||||
client_memory:
|
||||
.dd 0
|
||||
|
||||
dos_block_seg:
|
||||
.dw 0
|
||||
dos_block_sel:
|
||||
.dw 0
|
||||
dos_block_size:
|
||||
.dw 0
|
||||
|
||||
read_soffset:
|
||||
.dd 0
|
||||
read_size:
|
||||
.dd 0
|
||||
|
||||
dpmi_regs:
|
||||
.db 0x32 .dup 0
|
||||
dr_edi = 0x00
|
||||
dr_di = 0x00
|
||||
dr_esi = 0x04
|
||||
dr_si = 0x04
|
||||
dr_ebp = 0x08
|
||||
dr_bp = 0x08
|
||||
dr_ebx = 0x10
|
||||
dr_bx = 0x10
|
||||
dr_bl = 0x10
|
||||
dr_bh = 0x11
|
||||
dr_edx = 0x14
|
||||
dr_dx = 0x14
|
||||
dr_dl = 0x14
|
||||
dr_dh = 0x15
|
||||
dr_ecx = 0x18
|
||||
dr_cx = 0x18
|
||||
dr_cl = 0x18
|
||||
dr_ch = 0x19
|
||||
dr_eax = 0x1c
|
||||
dr_ax = 0x1c
|
||||
dr_al = 0x1c
|
||||
dr_ah = 0x1d
|
||||
dr_efl = 0x20
|
||||
dr_es = 0x22
|
||||
dr_ds = 0x24
|
||||
dr_fs = 0x26
|
||||
dr_gs = 0x28
|
||||
dr_ip = 0x2a
|
||||
dr_cs = 0x2c
|
||||
dr_sp = 0x2e
|
||||
dr_ss = 0x30
|
||||
|
||||
;-----------------------------------------------------------------------------
|
||||
|
||||
.align 16 ; so that stack ends on para boundary
|
||||
.dw 128 .dup 0
|
||||
.stack
|
||||
|
||||
;-----------------------------------------------------------------------------
|
||||
; At one time real mode only data. Header stuff now used during image load.
|
||||
|
||||
psp_segment:
|
||||
.dw 0
|
||||
|
||||
loadname_nul: ; offset of NUL so it can become '$'
|
||||
.dw 0
|
||||
loadname: ; name of program file to load, if it
|
||||
.db 81 .dup 0 ; gets really long ok to overwrite next
|
||||
|
||||
exe_header: ; loaded from front of loadfile
|
||||
exe_magic:
|
||||
.dw 0
|
||||
exe_bytes_last_page:
|
||||
.dw 0
|
||||
exe_sectors:
|
||||
.dw 0
|
||||
exe_header_length = . - exe_header
|
||||
|
||||
coff_offset:
|
||||
.dd 0 ; from start of file
|
||||
|
||||
coff_header: ; loaded from after stub
|
||||
.db 20 .dup 0
|
||||
aout_header:
|
||||
.db 28 .dup 0
|
||||
text_section:
|
||||
.db 40 .dup 0
|
||||
data_section:
|
||||
.db 40 .dup 0
|
||||
bss_section:
|
||||
.db 40 .dup 0
|
||||
coff_header_length = . - coff_header
|
||||
|
||||
old_strategy:
|
||||
.db 0
|
||||
old_umb:
|
||||
.db 0
|
||||
|
||||
dos_major:
|
||||
.db 0
|
||||
|
||||
.align 16 ; Align ourselves to a paragraph
|
||||
end_of_memory: ; resize is done early so must keep all
|
||||
|
||||
;-----------------------------------------------------------------------------
|
||||
; structure definitions
|
||||
;
|
||||
|
||||
coff_magic = 0 ; from coff header
|
||||
|
||||
aout_entry = 16 ; from aout header
|
||||
|
||||
s_paddr = 8 ; from section headers
|
||||
s_vaddr = 12
|
||||
s_size = 16
|
||||
s_scnptr = 20
|
||||
|
||||
|
||||
Reference in New Issue
Block a user