Do enough of the boot stub to produce an EXE header and enter DPMI protected
mode.
This commit is contained in:
parent
3716d49cd9
commit
1e0961c679
|
@ -12,141 +12,263 @@
|
||||||
|
|
||||||
.sect .text
|
.sect .text
|
||||||
.use16
|
.use16
|
||||||
|
exe_header:
|
||||||
|
.data2 0x5a4d ! magic number
|
||||||
|
.data2 0 ! number of bytes in last loadable page
|
||||||
|
.data2 exe_text_paras ! size of .exe, in pages
|
||||||
|
.data2 0 ! number of relocation entries
|
||||||
|
.data2 0 ! start of loadable area, in 16-byte paragraphs
|
||||||
|
.data2 exe_ram_paras ! required RAM size, in 16-byte paragraphs
|
||||||
|
.data2 0 ! maximum RAM siz, in 16-byte paragraphse
|
||||||
|
.data2 0 ! initial SS, relative to program
|
||||||
|
.data2 exe_stack ! initial SP
|
||||||
|
.data2 0 ! checksum (ignored)
|
||||||
|
.data2 exe_start ! initial IP
|
||||||
|
.data2 0 ! initial CS, relative to program
|
||||||
|
.data2 0 ! offset of relocation table
|
||||||
|
.data2 0 ! overlay number
|
||||||
|
|
||||||
|
dpmi_edi = 0x00
|
||||||
|
dpmi_esi = 0x04
|
||||||
|
dpmi_ebp = 0x08
|
||||||
|
dpmi_ebx = 0x10
|
||||||
|
dpmi_edx = 0x14
|
||||||
|
dpmi_ecx = 0x18
|
||||||
|
dpmi_eax = 0x1c
|
||||||
|
dpmi_flags = 0x20
|
||||||
|
dpmi_es = 0x22
|
||||||
|
dpmi_ds = 0x24
|
||||||
|
dpmi_fs = 0x26
|
||||||
|
dpmi_gs = 0x28
|
||||||
|
dpmi_ip = 0x2a
|
||||||
|
dpmi_cs = 0x2c
|
||||||
|
dpmi_sp = 0x2e
|
||||||
|
dpmi_ss = 0x30
|
||||||
|
|
||||||
|
dpmi_ps = 0x32 ! WORD: protected register segment
|
||||||
|
dpmi_rs = 0x34 ! WORD: real register segment
|
||||||
|
dpmi_psp = 0x36 ! WORD: PSP segment
|
||||||
|
dpmi_switch = 0x38 ! DWORD: far pointer of pmode switch routine
|
||||||
|
|
||||||
|
.seek 0x3c
|
||||||
|
exe_start:
|
||||||
|
! On entry, DS=ES=PSP. Make DS=CS, so we're running in tiny mode.
|
||||||
|
|
||||||
|
push cs
|
||||||
|
pop ds
|
||||||
|
mov (dpmi_rs), ds
|
||||||
|
mov (dpmi_psp), es
|
||||||
|
|
||||||
|
! Initialise DPMI.
|
||||||
|
|
||||||
|
mov ax, 0x1687
|
||||||
|
int 0x2f
|
||||||
|
or ax, ax
|
||||||
|
jnz no_dpmi
|
||||||
|
mov (dpmi_switch+0), di ! write back PMODE switch routine
|
||||||
|
mov (dpmi_switch+2), es
|
||||||
|
or si, si ! do we need a DPMI private area?
|
||||||
|
jz 1f
|
||||||
|
|
||||||
|
mov bx, si
|
||||||
|
movb ah, 0x48
|
||||||
|
int 0x21 ! allocate memory from DOS
|
||||||
|
mov es, ax ! data area segment -> es
|
||||||
|
1:
|
||||||
|
! Switch to protected mode.
|
||||||
|
|
||||||
|
mov ax, 1 ! 32-bit app
|
||||||
|
callf (dpmi_switch)
|
||||||
|
jc no_pmode
|
||||||
|
|
||||||
|
mov (dpmi_edx), go_msg
|
||||||
|
mov ax, (dpmi_rs)
|
||||||
|
mov (dpmi_ds), ax
|
||||||
|
mov (dpmi_eax+1), 9
|
||||||
|
call int21
|
||||||
|
mov ax, 0x4c00
|
||||||
|
int 0x21
|
||||||
|
|
||||||
|
! Simulate DOS interrupt bx.
|
||||||
|
int21:
|
||||||
|
mov bx, 0x21
|
||||||
|
callint:
|
||||||
|
xor ax, ax
|
||||||
|
mov (dpmi_ss), ax ! zero stack: DPMI host allocates one.
|
||||||
|
mov (dpmi_sp), ax
|
||||||
|
push ds
|
||||||
|
pop es
|
||||||
|
mov di, ax
|
||||||
|
mov ax, 0x300
|
||||||
|
int 0x31 ! simulate DOS interrupt
|
||||||
|
push cs
|
||||||
|
pop ds
|
||||||
|
ret
|
||||||
|
|
||||||
|
no_pmode: ! Could not switch to protected mode.
|
||||||
|
mov dx, no_pmode_msg
|
||||||
|
jmp exit_with_error
|
||||||
|
|
||||||
|
no_dpmi:
|
||||||
|
mov dx, no_dpmi_msg
|
||||||
|
! fall through
|
||||||
|
|
||||||
|
! Displays the message in dx and exits.
|
||||||
|
exit_with_error:
|
||||||
|
movb ah, 9
|
||||||
|
int 0x21 ! print $-terminated string
|
||||||
|
mov ax, 0x4cff
|
||||||
|
int 0x21 ! terminate with error code al
|
||||||
|
|
||||||
|
.use32
|
||||||
|
start_32bit:
|
||||||
|
|
||||||
|
go_msg:
|
||||||
|
.ascii "Go!$"
|
||||||
|
no_pmode_msg:
|
||||||
|
.ascii "Couldn't switch to protected mode$"
|
||||||
|
no_dpmi_msg:
|
||||||
|
.ascii "No DPMI$"
|
||||||
|
|
||||||
|
exe_top:
|
||||||
|
|
||||||
|
exe_stack = exe_top + 512
|
||||||
|
exe_text_paras = [exe_top - exe_header + 511] / 512
|
||||||
|
exe_ram_paras = [exe_stack - exe_top + 15] / 16
|
||||||
|
|
||||||
|
|
||||||
#define STACK_BUFFER 128 /* number of bytes to leave for stack */
|
#define STACK_BUFFER 128 /* number of bytes to leave for stack */
|
||||||
|
|
||||||
begtext:
|
begtext:
|
||||||
! Make sure we are running under MS-DOS 2 or above.
|
! Make sure we are running under MS-DOS 2 or above.
|
||||||
!
|
!
|
||||||
! While at it, also remember the actual DOS version, so that we know
|
! While at it, also remember the actual DOS version, so that we know
|
||||||
! whether DOS gives us the program's name in the environment
|
! whether DOS gives us the program's name in the environment
|
||||||
! segment. (DOS 3+ does; DOS 2.x does not.)
|
! segment. (DOS 3+ does; DOS 2.x does not.)
|
||||||
movb ah, 0x30
|
movb ah, 0x30
|
||||||
int 0x21
|
int 0x21
|
||||||
cbw
|
cbw
|
||||||
cmpb al, 2
|
cmpb al, 2
|
||||||
xchg bp, ax
|
xchg bp, ax
|
||||||
jnc ok_sys
|
jnc ok_sys
|
||||||
|
|
||||||
mov dx, bad_sys_msg
|
mov dx, bad_sys_msg
|
||||||
dos_msg:
|
dos_msg:
|
||||||
movb ah, 9
|
ret
|
||||||
int 0x21
|
|
||||||
ret
|
|
||||||
|
|
||||||
ok_sys:
|
ok_sys:
|
||||||
! Resize the program's memory control block (MCB) to cover only the
|
! Resize the program's memory control block (MCB) to cover only the
|
||||||
! program's near code and data space. Use the starting sp value as
|
! program's near code and data space. Use the starting sp value as
|
||||||
! a guide to how much memory we can grab. Abort on any failure.
|
! a guide to how much memory we can grab. Abort on any failure.
|
||||||
!
|
!
|
||||||
! As a side effect, this also frees up any memory allocated to our
|
! As a side effect, this also frees up any memory allocated to our
|
||||||
! program beyond 64 KiB. (The freed memory can possibly be used by
|
! program beyond 64 KiB. (The freed memory can possibly be used by
|
||||||
! e.g. child processes, in the future.)
|
! e.g. child processes, in the future.)
|
||||||
!
|
!
|
||||||
! Also check that we have some space between the BSS end and the
|
! Also check that we have some space between the BSS end and the
|
||||||
! starting sp.
|
! starting sp.
|
||||||
cmp sp, endbss+STACK_BUFFER
|
cmp sp, endbss+STACK_BUFFER
|
||||||
jb no_room
|
jb no_room
|
||||||
|
|
||||||
movb ah, 0x4a
|
movb ah, 0x4a
|
||||||
mov bx, sp
|
mov bx, sp
|
||||||
movb cl, 4
|
movb cl, 4
|
||||||
shr bx, cl
|
shr bx, cl
|
||||||
inc bx
|
inc bx
|
||||||
int 0x21
|
int 0x21
|
||||||
jc no_room
|
jc no_room
|
||||||
|
|
||||||
! Clear BSS.
|
! Clear BSS.
|
||||||
mov di, begbss
|
mov di, begbss
|
||||||
mov cx, endbss+1
|
mov cx, endbss+1
|
||||||
sub cx, di
|
sub cx, di
|
||||||
shr cx, 1
|
shr cx, 1
|
||||||
xor ax, ax
|
xor ax, ax
|
||||||
cld
|
cld
|
||||||
rep stosw
|
rep stosw
|
||||||
|
|
||||||
! Get the size of the environment variables plus (if present) the
|
! Get the size of the environment variables plus (if present) the
|
||||||
! program name. Also count the number of environment variables.
|
! program name. Also count the number of environment variables.
|
||||||
xor di, di
|
xor di, di
|
||||||
mov es, 0x002C(di)
|
mov es, 0x002C(di)
|
||||||
! ax = 0 from above
|
! ax = 0 from above
|
||||||
cwd ! dx = count of env. vars.
|
cwd ! dx = count of env. vars.
|
||||||
! cx = 0 from above
|
! cx = 0 from above
|
||||||
dec cx ! cx = max. str. bytes to scan
|
dec cx ! cx = max. str. bytes to scan
|
||||||
scasb ! handle special case of empty env.
|
scasb ! handle special case of empty env.
|
||||||
jz is_empty_env
|
jz is_empty_env
|
||||||
size_env:
|
size_env:
|
||||||
inc dx
|
inc dx
|
||||||
repnz scasb
|
repnz scasb
|
||||||
scasb
|
scasb
|
||||||
jnz size_env
|
jnz size_env
|
||||||
is_empty_env:
|
is_empty_env:
|
||||||
cmp bp, 2
|
cmp bp, 2
|
||||||
jz no_argv0
|
jz no_argv0
|
||||||
scasw
|
scasw
|
||||||
repnz scasb
|
repnz scasb
|
||||||
no_argv0:
|
no_argv0:
|
||||||
|
|
||||||
! Copy out the environment variables and (possibly) program name
|
! Copy out the environment variables and (possibly) program name
|
||||||
! onto the stack.
|
! onto the stack.
|
||||||
mov si, di
|
mov si, di
|
||||||
dec si
|
dec si
|
||||||
std
|
std
|
||||||
copy_env:
|
copy_env:
|
||||||
and si, -2
|
and si, -2
|
||||||
eseg lodsw
|
eseg lodsw
|
||||||
push ax
|
push ax
|
||||||
jnz copy_env
|
jnz copy_env
|
||||||
mov cx, sp
|
mov cx, sp
|
||||||
|
|
||||||
! Reset DF and es properly.
|
! Reset DF and es properly.
|
||||||
cld
|
cld
|
||||||
push ss
|
push ss
|
||||||
pop es
|
pop es
|
||||||
|
|
||||||
! Reserve space for argc and the argv and envp pointers on the
|
! Reserve space for argc and the argv and envp pointers on the
|
||||||
! stack. These will be passed to __m_a_i_n later.
|
! stack. These will be passed to __m_a_i_n later.
|
||||||
sub sp, 6
|
sub sp, 6
|
||||||
mov ax, sp
|
mov ax, sp
|
||||||
|
|
||||||
! Build up argc, argv[], and envp[].
|
! Build up argc, argv[], and envp[].
|
||||||
push ax ! output buffer for argc, argv, envp
|
push ax ! output buffer for argc, argv, envp
|
||||||
push bp ! MS-DOS version
|
push bp ! MS-DOS version
|
||||||
push cx ! env. string data
|
push cx ! env. string data
|
||||||
push dx ! count of env. vars.
|
push dx ! count of env. vars.
|
||||||
mov ax, 0x0080
|
mov ax, 0x0080
|
||||||
push ax ! raw command line
|
push ax ! raw command line
|
||||||
call __sys_initmain
|
call __sys_initmain
|
||||||
add sp, 10
|
add sp, 10
|
||||||
|
|
||||||
! Bail out if something went wrong.
|
! Bail out if something went wrong.
|
||||||
test ax, ax
|
test ax, ax
|
||||||
jnz no_room
|
jnz no_room
|
||||||
|
|
||||||
! argc, argv, and envp are now at the stack top. Now go.
|
! argc, argv, and envp are now at the stack top. Now go.
|
||||||
call __m_a_i_n
|
call __m_a_i_n
|
||||||
add sp, 6
|
add sp, 6
|
||||||
push ax
|
push ax
|
||||||
call _exit
|
call _exit
|
||||||
|
|
||||||
no_room:
|
no_room:
|
||||||
mov dx, no_room_msg
|
mov dx, no_room_msg
|
||||||
call dos_msg
|
call dos_msg
|
||||||
movb al, -1
|
movb al, -1
|
||||||
jmp al_exit
|
jmp al_exit
|
||||||
|
|
||||||
! Exit.
|
! Exit.
|
||||||
.define __exit
|
.define __exit
|
||||||
.extern __exit
|
.extern __exit
|
||||||
.define EXIT
|
.define EXIT
|
||||||
.extern EXIT
|
.extern EXIT
|
||||||
__exit:
|
__exit:
|
||||||
EXIT:
|
EXIT:
|
||||||
pop bx
|
pop bx
|
||||||
pop ax
|
pop ax
|
||||||
al_exit:
|
al_exit:
|
||||||
movb ah, 0x4c
|
movb ah, 0x4c
|
||||||
int 0x21
|
int 0x21
|
||||||
|
|
||||||
! Define symbols at the beginning of our various segments, so that we can find
|
! Define symbols at the beginning of our various segments, so that we can find
|
||||||
! them. (Except .text, which has already been done.)
|
! them. (Except .text, which has already been done.)
|
||||||
|
@ -168,3 +290,6 @@ no_room_msg: .ascii 'No room$'
|
||||||
.comm .trppc, 4
|
.comm .trppc, 4
|
||||||
.comm .ignmask, 4
|
.comm .ignmask, 4
|
||||||
.comm _errno, 4
|
.comm _errno, 4
|
||||||
|
|
||||||
|
! vim: ts=4 sw=4 et ft=asm
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue