home *** CD-ROM | disk | FTP | other *** search
- ;
- ; startup code for the CC386 system. This code provides the standard
- ; startup routines used by the CC386 compiler. They are prefaced by
- ; init code to initialize TRAN's PMODE.
- ;
- ; This program is designed for use with TASM; in particular it uses
- ; the TLINK convention that if two segments are defined for the same
- ; class in the first .obj loaded the first is put at the BEGINNING of
- ; of the linked segment and the second is placed at the END. I don't
- ; have any idea if MASM or the microsoft linker will deal with this
- ; in a way that will allow the code to work.
- ;
- ; This program:
- ; 1) Allocates memory
- ; 2) allocates and initializes descriptors
- ; 3) copies the C program into the allocated memory
- ; 4) runs the C program
- ; 5) cleans up
- ; 6) exits
- ;
- ; Copyright (c) 1997 LADsoft
- ;
- ; David Lindauer, gclind01@starbase.spd.louisville.edu
- ;
- .386p
- locals
-
- STACKLEN = 40h ; size of stack in paragraphs
- PROGRAM_STACK = 20*1024 ; stack size of the prog
- SELSTOALLOC = 4
- MAXMEM = 32
- GDTENTRY macro base,limit,type
- dw limit AND 0ffffh
- dw base AND 0ffffh
- db (base SHR 16) AND 0ffh
- dw type OR ((limit SHR 8) AND 0f00h)
- db base SHR 24
- ENDM
-
- STUB_TEXT segment para public use16 'TRAN'
- extrn spawnblock:word
- STUB_TEXT ends
- PMODE_TEXT segment para public use16 'TRAN'
- PMODE_TEXT ends
- EXE_STACK segment para stack use16 'STACK'
- EXE_STACK ends
- _TEXT segment para public use32 'CODE'
- extrn __argv_arr:DWORD,__argc:DWORD,__env_arr:DWORD,__cmdline:DWORD
- extrn _main:PROC, llsignal:proc, llsigdown:proc
- extrn llfpini:proc, llfpdown:proc
- _TEXT ends
- cstartup SEGMENT DWORD PUBLIC USE32 'INITDATA'
- InitStart label dword
- ENDS
- _STARTUPEND_ SEGMENT DWORD PUBLIC USE32 'INITDATA'
- InitEnd label dword
- ENDS
- crundown SEGMENT DWORD PUBLIC USE32 'EXITDATA'
- ExitStart label dword
- ENDS
- _RUNDOWNEND_ SEGMENT DWORD PUBLIC USE32 'EXITDATA'
- ExitEnd label dword
- ENDS
- _CPP_ SEGMENT DWORD PUBLIC USE32 'CPPDATA'
- CppStart label dword
- dd cpproutine
- ENDS
- _CPPEND_ SEGMENT DWORD PUBLIC USE32 'CPPDATA'
- CppEnd label dword
- ENDS
- _DATA SEGMENT DWORD PUBLIC USE32 'DATA'
- ENDS
- _BSS SEGMENT PARA PUBLIC USE32 'BSS'
- BssStart label dword
- ENDS
- _BSSEND SEGMENT PARA PUBLIC USE32 'BSS'
- BssEnd label dword
- ENDS
-
- DGROUP group _TEXT, cstartup,_STARTUPEND_,crundown,_RUNDOWNEND_,_CPP_,_CPPEND_,_DATA,_BSS,_BSSEND
-
- extrn _pm_info:far, _pm_init:far, _pm_rmstacks:BYTE, _pm_pmstacks:BYTE
- extrn _pm_pagetables:byte, _pm_mode: byte
- public __rexit, __transferx, __stacktop
- public __pspseg, __linear, __pmodew,__rmseg
-
- STUB_TEXT segment
- assume cs:STUB_TEXT, ds:STUB_TEXT
- org 0
- ;═════════════════════════════════════════════════════════════════════════════
- ;
- ; Header for external debuggers... must be FIRST THING after EXE header
- ;
- ifndef DEBUG
- dd 'XDBG' ; signature
- dd 'i386'
- dw 1 ; some Version info
- dw DGROUP ; to locate entry + globals
- dd offset DGROUP:BssEnd ; to determine memory size
- dd PROGRAM_STACK ; yet to add this...
- dd offset DGROUP:start32 ; true entry point
- dd offset DGROUP:_main ; where to set a breakpoint
- dd offset DGROUP:__pmodew ; to fake this
- endif
- ;
- ; local vars
- ;
- banner db 'Stub-386, Copyright (c) 1997, LADsoft',10,13
- db 'DPMI subsystem Copyright (c) 1994, TRAN (Thomas Pytel)',10,13,'$'
- errmsgtbl dw errmsg0,errmsg1,errmsg2,errmsg3
- dw errmsg4,errmsg5,errmsg6,errmsg7
-
- errmsg0 db 'Not enough low memory!',13,10,36
- errmsg1 db '80386 or better not detected!',13,10,36
- errmsg2 db 'System already in protected mode and no VCPI or DPMI found!',13,10,36
- errmsg3 db 'DPMI host is not 32bit!',13,10,36
- errmsg4 db 'Could not enable A20 gate!',13,10,36
- errmsg5 db 'Could not enter DPMI 32bit protected mode!',13,10,36
- errmsg6 db 'Could not allocate needed DPMI selectors!',13,10,36
- errmsg7 db 'MS-DOS 2.0 required for this program',10,13,'$'
-
- nomemerr db 'Not enough extended memory',10,13,36
- initerr db 'Unexpected error while initializing dpmi',10,13,36
-
-
- regstruc_edi label dword
- regstruc_di dw ?,?
- regstruc_esi label dword
- regstruc_si dw ?,?
- regstruc_ebp label dword
- regstruc_bp dw ?,?
- dd ?
- regstruc_ebx label dword
- regstruc_bx label word
- regstruc_bl db ?
- regstruc_bh db ?,?,?
- regstruc_edx label dword
- regstruc_dx label word
- regstruc_dl db ?
- regstruc_dh db ?,?,?
- regstruc_ecx label dword
- regstruc_cx label word
- regstruc_cl db ?
- regstruc_ch db ?,?,?
- regstruc_eax label dword
- regstruc_ax label word
- regstruc_al db ?
- regstruc_ah db ?,?,?
- regstruc_flags dw ?
- regstruc_es dw ?
- regstruc_ds dw ?
- regstruc_fs dw ?
- regstruc_gs dw ?
- regstruc_ip dw ?
- regstruc_cs dw ?
- regstruc_sp dw ?
- regstruc_ss dw ?
-
- sel32 dw ?
- selx dw ?
- psp dw ?
- modeval db ?
- newcodebase dw ?
- transfersel dw ?
- align 4
- linearbase dd ?
- blockhandle dd ?
- blocksize dd ?
-
- cdesc label dword
- GDTENTRY 0,0fffffh,0c09Ah ; 386 code
- ddesc label dword
- GDTENTRY 0,0fffffh,0c092H ; 386 data
- ;═════════════════════════════════════════════════════════════════════════════
- ;
- ; program start
- ;
- start: ; execution starts here
-
- push cs ; DS = CS
- pop ds
- mov [psp],es
- mov ax,es:[2ch]
- mov [spawnblock],ax
- ifdef COPYRIGHT ; Joss
- mov dx,offset banner ; do the banner
- mov ah,9
- int 21h
- endif
-
- mov ah,30h ; Check for dos 2.0
- int 21h
- cmp al,2
- jnc @@dosok
- mov ax,7 ; err if not
- jmp @@startf1
-
- @@dosok:
- ;
- ; Init to try for VCPI
- ;
- mov [_pm_pagetables],MAXMEM/4 ; Max out at 32 MB
- mov [_pm_mode],1 ; select VCPI if it exists
- mov [_pm_rmstacks],6
- mov [_pm_pmstacks],6
-
- call _pm_info ; get information
- jnc short @@startf0 ; if no error, go on
-
- @@startf1:
- mov si,ax ; print error message for code AX
- add si,ax
- mov dx,errmsgtbl[si]
- mov ah,9
- int 21h
- mov ax,4cffh
- int 21h
-
- @@startf0:
- call optimize_realmem ; optimize mem for spawns
- jc nomem
- mov [newcodebase],ax
- mov es,bx
- call _pm_init ; enter protected mode
- jc @@startf1 ; if error, go to error message
-
- ;
- ; At this point we are in pmode
- ;
- mov [modeval],ch ; VCPI/DPMI/RAW/XMS flag
- ; = 3 for DPMI, 2 for VCPI
-
- mov [psp],es ; save our PSP for later
-
- push ds
- pop es
-
- mov ax,cs ; fix the priv levels of our descriptors
- and al,3
- shl al,5
- or byte ptr [cdesc+5],al
- or byte ptr [ddesc+5],al
- ;
- ; Get program size
- ;
-
- mov ecx,offset DGROUP:BssEnd ; min mem program needs
- add ecx,PROGRAM_STACK ; later we will make this a link-time
- ; parameter
- mov [blocksize],ecx
- mov ebx,ecx
- shr ebx,16
-
- ;
- ; Allocate memory for the program
- ;
- ; the program WILL run in extended memory
- ;
- mov ax,501h ; allocate memory and save the
- int 31h ; base address of it
- jc nomem ; Should not get an error from this
- ; but get out if we do
- mov ax,bx
- shl eax,16
- mov ax,cx
- mov [linearbase],eax
- mov ax,si
- shl eax,16
- mov ax,di
- mov [blockhandle],eax
-
- mov ax,3 ; Now get the selector increase value
- int 31h
- mov [selx],ax
- ;
- ; Allocate selectors and initialize the descriptors for
- ; 32-bit segments
- ;
- mov ax,0 ; Allocate the 32-bit selectors
- mov cx,SELSTOALLOC ; CODE, DATA/stack,
- int 31h
- jc initbad
- mov [sel32],ax
-
- mov bx,[sel32] ; set CS descriptr
- mov edi,offset cdesc ;
- mov ax,000ch ;
- int 31h
- jc initbad ; Should not get an error from this
-
- mov bx,[sel32] ; set DS descriptor
- mov edi,offset ddesc ;
- add bx,[selx]
- mov ax,000ch
- int 31h
- jc initbad ; Should not get an error from this
-
- mov bx,[sel32] ; set ABSOLUTE descriptor
- mov edi,offset ddesc ;
- add bx,[selx]
- add bx,[selx]
- mov ax,000ch
- int 31h
- jc initbad ; Should not get an error from this
-
- mov bx,[sel32] ; set transfer descriptor
- mov edi,offset ddesc ;
- add bx,[selx]
- add bx,[selx]
- add bx,[selx]
- mov [transfersel],bx
- mov ax,000ch
- int 31h
- jc initbad ; Should not get an error from this
- ;
- ; Set the base of the code and data segments to the linear address
- ; of the memory block
- ;
- mov eax,[linearbase] ; code segment
- mov dx,ax
- shr eax,16
- mov cx,ax
- mov bx,[sel32]
- mov ax,7
- int 31h
- jc initbad
-
- mov eax,[linearbase] ; data segment
- mov dx,ax
- shr eax,16
- mov cx,ax
- mov bx,[sel32]
- add bx,[selx]
- mov ax,7
- int 31h
- jc initbad
- ; absolute segment already initted
- sub eax,eax ; transfer segment
- mov ax,_TEXT
- shl eax,4
- mov dx,ax
- shr eax,16
- mov cx,ax
- mov bx,[transfersel]
- mov ax,7
- int 31h
- jc initbad
- ;
- ; Set the limit of the code and data segments to the block size
- ;
- mov eax,[blocksize] ; code segment
- dec eax
- mov dx,ax
- shr eax,16
- mov cx,ax
- mov bx,[sel32]
- mov ax,8
- int 31h
- jc initbad
-
- mov eax,[blocksize] ; data segment
- dec eax
- mov dx,ax
- shr eax,16
- mov cx,ax
- mov bx,[sel32]
- add bx,[selx]
- mov ax,8
- int 31h
- jc initbad
- ; absolute segment already initted
- mov eax,1023 ; transfer segment
- mov dx,ax
- shr eax,16
- mov cx,ax
- mov bx,[transfersel]
- mov ax,8
- int 31h
- jc initbad
- ;
- ; blit the program to our memory block
- ;
- sub eax,eax ; calculate source
- mov ax,[newcodebase]
- shl eax,4
- mov esi,eax
-
- mov edi,[linearbase] ; calculate dest
- mov es,[psp] ; calculate len
- sub ecx,ecx
- mov cx,es:[2]
- shl ecx,4
- sub ecx,esi
- cmp ecx,[blocksize]
- jc takeprog
- mov ecx,[blocksize]
- takeprog:
- shr ecx,2 ; guranteed to be paragraph multiple
-
- push ds ; switch to abs seg and do blit
- mov ax,[sel32]
- add ax,[selx]
- add ax,[selx]
- mov ds,ax
- mov es,ax
- db 67h ; shift us to 32 bits...
- rep movsd ; do the blit
- pop ds
-
- ;
- ; now call the 32-bit C0 routine
- ;
- ; must return with a RETF
- ;
- push ds
-
- push 0 ; return address... returning from
- push cs ; a 32 bit segment so two dwords
- sub eax,eax
- mov ax,offset retpos
- push eax
-
- push [sel32] ; address of 32-bit code
- ; returning from this seg to
- mov eax,offset DGROUP:start32 ; a 32-bit seg, two words
- push ax
-
- mov ax,[sel32] ; set up selectors
- add ax,[selx]
- mov es,[psp] ; ES: PSP
- mov ebx,[blocksize] ; EBX
- mov ecx,[linearbase] ; ECX
- mov dx,[transfersel]
- mov ds,ax
- mov ax,_TEXT
-
- retf
-
- retpos: ; when 32-bit code exits with a retf
- pop ds ; we come here
-
-
- getout:
- push ax ; save return code
- mov bx,[sel32]
- or bx,bx
- mov cx,SELSTOALLOC
- mov ax,1
- selfrlp:
- pusha
- int 31h
- popa
- add bx,[selx]
- loop selfrlp
-
- releasemem:
- mov eax,[blockhandle] ; Free the program block
- or eax,eax
- jz endprog
- mov di,ax
- shr eax,16
- mov si,ax
- mov ax,502h
- int 31h
-
- endprog:
- pop ax
- mov ah,4ch ; exit to DOS
- int 21h
- nomem:
- mov regstruc_dx,offset nomemerr
- jmp puterr
- initbad:
- mov regstruc_dx,offset initerr
- puterr:
- call message
- mov al,0ffh ; error 255
- jmp getout
-
- message:
- mov edi,offset regstruc_edi ; offset of register structure
- xor cx,cx ; no parameters on stack
- mov bx,21h ; call interrupt 21h
- mov ax,300h ; INT 31h function 0300h
-
- mov regstruc_ah,9 ; function code 9, put string
- mov regstruc_ds,STUB_TEXT ; set DS:DX for DOS string put
- mov regstruc_ss,0 ; SS:SP = 0, PMODE will provide stack
- mov regstruc_sp,0
-
- push ds
- pop es
- int 31h ; do the call to real mode
- ret
-
- ;─────────────────────────────────────────────────────────────────────────────
- ;
- ; real mode subroutines
- ;
- optimize_realmem proc
- ;
- ; check if we have space for the pmode data seg
- ;
- mov ax,es:[2]
- mov ecx,offset DGROUP:BssStart
- shr ecx,4
- sub ax,cx
- push ax
- jc or_err
- sub ax,bx
- jc or_err
- sub ax,STACKLEN + 1024/16
- jc or_err
- sub ax,_TEXT
- jc or_err
- ;
- ; now relocate the pmode program to end of real memory
- ;
- std
- push ds
- push es
- mov ax,es:[2]
- sub ax,1000h
- mov es,ax
- mov di,0fffeh
- mov si,di
- mov eax,offset DGROUP:BssStart
- shr eax,4
- add ax,_TEXT
- sub ax,1000h
- mov ds,ax
- shl ecx,3
- or_lp:
- cmp ecx,8000h
- jbe lastmv
- push ecx
- mov cx,8000h
- rep movsw
- pop ecx
- sub ecx,8000h
- mov ax,ds
- sub ax,1000h
- mov ds,ax
- mov ax,es
- sub ax,1000h
- mov es,ax
- jmp or_lp
- lastmv:
- rep movsw
- cld
- pop es
- pop ds
- ;
- ; calculate address of pmode data struct
- ;
- mov ax,_TEXT
- add ax,1024/16+STACKLEN
- push ax
- ;
- ; resize memory
- ;
- add bx,ax
- sub bx,[psp]
- mov es,[psp]
- mov ah,4ah
- int 21h
- pop bx
- jc or_err
- clc
- or_err:
- pop ax
- ret
- optimize_realmem endp
-
- STUB_TEXT ends
-
- ;─────────────────────────────────────────────────────────────────────────────
- EXE_STACK segment para stack use16 'STACK'
- db STACKLEN*10h dup(?)
- EXE_STACK ends
-
-
-
- _DATA SEGMENT DWORD PUBLIC USE32 'DATA'
- db "Copyright (c) 1997 LADsoft C runtime library"
- db " (i386/DOS)"
- align 4
- __linear dd 0
- __stacktop dd 0
- stackpos df 0
- __transferx dw 0
- __pspseg dw 0
- __pmodew dw 0
- __rmseg dw 0
- filename db 128 dup (0)
- dcml db 128 dup (0)
- ENDS
- _TEXT SEGMENT
- assume cs:DGROUP,ds:DGROUP
- ;
- ; C startup procedures
- ;
- start32:
- ;
- ; save DTA and PSP
- ;
- push ebx ; save TOM for stack init
- mov [__transferx],dx ; disk transfer address
- mov [__pspseg],es ; program psp segment
- mov [__linear],ecx
- mov [__rmseg],ax
- ;
- ; Init fs and gs in case someone needs them
- ;
- mov eax,ds
- mov fs,eax
- mov gs,eax
- ;
- ; Clear BSS
- ;
- push ds
- pop es
- mov edi,offset DGROUP:BssStart
- mov ecx,offset DGROUP:BssEnd
- sub ecx,edi
- sub eax,eax
- cld
- rep stosb
- ;
- ; Initialize the signal system
- ;
- call llfpini
- call llsignal
- ;
- ; Set up command line for RTL
- ;
- mov es,[__pspseg]
- mov edi,offset DGROUP:dcml
- mov [__cmdline],edi
- inc [__cmdline]
- push ds
- push ds
- push es
- pop ds ; blit the command line into our mem
- pop es
- mov esi,80h
- mov ecx,128
- rep movsb
- pop ds
- ; turn into C string form
- sub ebx,ebx
- mov bl,[dcml]
- mov byte ptr [dcml + ebx + 1],0
- ;
- ; initialize stack
- ;
- pop ebx ; get TOM back
- mov dword ptr [stackpos],esp ; save old stack for later
- mov word ptr [stackpos+4],ss
- cli
- push ds ; set up stack
- pop ss ;
- and ebx,0fffffffch ;
- sub ebx,4
- mov esp,ebx ;
- mov [__stacktop],ebx
- sti
- ;
- ; Execute startup routines
- ;
- push ds ; reset es to ds
- pop es
- mov ecx,offset DGROUP:InitStart
- mov edx,offset DGROUP:InitEnd
- call sexproc
-
- ;
- ; Now we are going to patch the name of the file into argv[0]
- ;
- mov es,[__pspseg] ; get environment
- mov es,es:[2ch]
- sub eax,eax ; set up for scan
- mov edi,eax
- mov ecx,-1
- mov esi,offset DGROUP:filename
- lp:
- repnz scasb ; scan for end of environment
- test byte ptr es:[edi],0ffh
- jnz lp
- add edi,3 ; got it, index to command line
- lp1:
- mov al,es:[edi] ; now transfer the file name
- mov [esi],al ; to a local buffer
- inc esi
- inc edi
- or al,al
- jnz lp1
-
- mov eax,[__argv_arr]
- mov dword ptr [eax],offset DGROUP:filename
-
- push ds
- pop es
- ;
- ;
- ; Call main
- ;
- push __env_arr
- push __argv_arr
- push __argc
- ifdef DEBUG
- extrn monitor_init:proc
- call monitor_init
- endif
- call _main
- add esp,12
-
- ; exit/abort comes here
- ;
- __rexit:
- ;
- ; Execute rundown routines
- ;
- push eax ; saving C return code
- mov ecx,offset DGROUP:ExitStart
- mov edx,offset DGROUP:ExitEnd
- call sexproc
- ;
- ; rundown signal handler
- ;
- call llsigdown
- call llfpdown
- ;
- ; get original stack
- ;
- exitpos:
- pop eax ; return code in EAX
- lss esp,stackpos
- retf ; exit back to the 16-bit seg
- ;
- ; Handle startup/rundown routines
- ;
- sexproc:
- cmp ecx,edx
- jz short sexpdone
- mov edi,ecx
- sub ebx,ebx
- sub eax,eax
- spl2:
- cmp edi,edx
- jz short spo
- test dword ptr [edi+4],-1
- jz short spl3
- cmp eax,[edi+4]
- jnc short spl3
- mov ebx,edi
- mov eax,[edi+4]
- spl3:
- add edi,8
- jmp spl2
- spo:
- or ebx,ebx
- jz short sexpdone
- mov dword ptr [ebx+4],0
- push edx
- push ecx
- call [ebx]
- pop ecx
- pop edx
- jmp sexproc
- sexpdone:
- ret
-
- ; This is called as the first thing from the C++ main routine
- cpproutine:
- ret
- ;
- ; Put a message out on the console
- ;
- _TEXT ends
- end start