Metropoli BBS
VIEWER: c0.asm MODE: TEXT (ASCII)
;PMODE/W v1.31+ (DOS/4GW or WDOSX) startup code

include startup.inc
include dos.inc
include string.inc
include math.inc
include conio.inc
include stdlib.inc
include stdio.inc
include errno.inc
include process.inc

_QLIB_CFG_ segment dword public use32 'CODE' ;the 1st segment
align 4
db 'QLIB_MEM'   ;this MUST stay here! (used by qsetup)
                ;I place in code so it will be near beginning of EXE file
HEAP_MAX dd -1         ;max that will be alloced for heap
  ;NOTE:you should use pmwsetup to modify how much RAM the DOS extender
  ; allocs.  The values here will have no effect how much it allocs unless
  ; you are running under a DPMI server.  In which case pmwsetup has no
  ; effect.  So use QSETUP which will modify these vales directly in the
  ; EXE file which will guaranty you that RAM is avail for spawn...()
  ; and other system calls
HEAP_MIN dd 32 * 1024   ;min size needed to run
_QLIB_CFG_ ends

.code
NULLPROC proc
  ret
NULLPROC endp

.data
  _argv dd offset _args   ;this is argv!
  _args dd 64 dup (0) ; the pointers
  rational db 'RATIONAL DOS/4G',0
  errno dw 0

.stack ;this is not the default '.stack' thingy! (see startup.inc)
 db 16*1024 dup (?) ;default 16K stack

.data?
  _argstr db 128 dup (?) ; arguments copied from PSP
public argc
  argc label byte           ;needed for Watcom
  _argc db ?             ; # of arguments
    db 3 dup (?)
  _pmmode db ?           ;mode  1=raw 2=XMS 4=VCPI 8=DPMI
  _filename dd ?         ;pts to filename as loaded (also @ _argv[0*4])
  _size dd ?             ;size of the EXE file after LINKing
  _8087 db 3h            ; (for WATCOM compatibility) FIXED : v2.00 Beta #4
  _fpu db ?              ;80387 FPU?  0=no 1=yes
  _8kbufferseg dw ?      ;segment of 8k temp buffer (use as you like!)
  _8kbuffer dd ?         ;linear addr of 8k buffer
  _os_typ db ?           ;OS detected (see os.inc)
  _os_ver_major db ?     ;OS version
  _os_ver_minor db ?
  _dos_ver_major db ?    ;DOS version
  _dos_ver_minor db ?
  _ansi_sys db ?         ;ANSI.SYS loaded?

  align 4 ;for speed!
  selcode dw ?           ;selctor for code
  selzero label word     ; " zero base
  seldata dw ?           ; " data
  dw ? ;make all perfectly aligned!
  _environ dd ?          ; environment offset
  _psp dd ?              ; PSP linear offset
  _dta dd ?              ; DTA linear offset
  _ds_ dw 0  ; both loaded into Sregs during int 10h
  _es_ dw 0  ; Use these to send info to int 10h
             ; there is an 8k buffer alloc during init for this purpose
             ; it's _8kbufferseg (linear addr=_8kbuffer)
  _dosXver dw ?    ;DOS extender version  (if possible)
  _dosXtyp db ?    ;DOS extender type (0=PMODE/W 1=DOS/4GW 2=DOS32v3.5+)
  _cpu label byte
  _processor db ?  ;3=386 4=486 5=586 ...

;private data
  ;saved vectors
  _int_10h df ?   ;df=6 bytes(for sel:offset)
  _int_21h df ?

  align 4
  _int dw ? ;interrupt # to call
  _saved_ints db 1024 dup (?) ;saved RM ints

PMODEW equ 1
include meminit.asm
include osinit.asm 
include mathinit.asm

.code
;Error messages
Cantgetbase:
  mov edx,"DPMI Error:Unable to get selector base.\r\n$"
  jmp @f
Cantsetint:
  mov edx,"DPMI Error:Unable to set INT vects\r\n$"
  jmp @f
Cantgetint:
  mov edx,"DPMI Error:Unable to get INT vects\r\n$"
  jmp @f
req131:
  mov edx,"PMODE/W v1.31+ required\r\n$"
  jmp @f

@@:
  mov ah,9
  int 21h
  mov ax,4c00h
  int 21h

externdef main:near
externdef cstart_:near

align 4
  ;required by Watcom C compiler for some reason but never gets called?
cstart_:
__entry32__:
  jmp short begin
  db 'WATCOM',0  ;keep this here in case you use DOS/4GW.EXE
begin:

  sti
  cld

  mov ax,ds
  mov es,ax
  mov fs,ax
  mov gs,ax
  mov seldata,ax
  mov selcode,cs

  mov ax,0eeffh
  int 31h
  .if eax=='PMDW'
    ;Using PMODE/W
    mov _dosXtyp,DOSX_PMODEW
    mov _pmmode,ch
    mov _processor,cl
    mov _dosXver,dx
    .if dx<100h+31
      jmp req131
    .endif
    jmp @f
  .endif
  mov ax,0a00h   ;detect DOS/4GW
  mov esi,offset rational
  int 31h
  mov ds,cs:seldata   ;restore DS
  .if !carry?
    ;Using DOS/4GW
    mov _dosXtyp,DOSX_DOS4GW
    mov _dosXver,0
  .else
    ;DOS extender unknown
    mov _dosXtyp,DOSX_UNKNOWN
    mov _dosXver,0
  .endif
  mov ax,ds
  mov es,ax
  mov fs,ax
  mov gs,ax
  mov _pmmode,SRV_UNKNOWN   ;what server DOS/4gw is using is undetectable
  mov _processor,3          ;assume 386 at least!

@@:
  mov ah,62h    ;get PSP selector  (PMODE/W v1.31+)
  int 21h
  mov ax,6
  int 31h
  .if carry?
    jmp Cantgetbase
  .endif

  shl ecx,16
  mov cx,dx
  mov _psp,ecx

  mov bx,[ecx+44]  ;get enviroment selector
  mov ax,6
  int 31h
  .if carry?
    jmp Cantgetbase
  .endif

  shl ecx,16
  mov cx,dx
  mov _environ,ecx

  mov ah,1ah
  mov edx,_psp
  add edx,80h
  mov _dta,edx
  int 21h  ;set DTA addr

  mov ax,100h   ;alloc 8k DOS memory for temp buffer
  mov bx,8*1024/16
  int 31h
  jc outofram  ;within meminit.asm

  ;ax=RMODE segment
  xor ecx,ecx
  mov cx,ax
  shl ecx,4
  mov _8kbufferseg,ax
  mov _8kbuffer,ecx

;ANSI.SYS detection
  mov ax,1a00h
  int 2fh
  mov _ansi_sys,al    ;0ffh = installed     0 = not installed

;save ALL RM INTS
  mov esi,0   ;the real mode INT table
  mov edi,offset _saved_ints
  mov ecx,256
  rep movsd   ;save 1024 bytes!!!

;save selected PM ints
  mov ax,204h
  mov bl,21h
  int 31h
  jc Cantgetint
  mov wptr[_int_21h+4],cx
  mov dptr[_int_21h+0],edx

  mov ax,204h
  mov bl,10h
  int 31h
  jc Cantgetint
  mov wptr[_int_10h+4],cx
  mov dptr[_int_10h+0],edx

;set PM ints
  mov ax,205h
  mov bl,10h
  mov edx,offset _int10h
  mov cx,cs
  int 31h
  jc Cantsetint

;init all necessary stuff
  call math_init
  .if eax==ERROR
    mov _fpu,0
  .else
    mov _fpu,3
  .endif

  include c0c1.asm  ;setup args

  call os_detect

  call alloc_init

  call call_init

  xor eax,eax
  xor ebx,ebx
  xor ecx,ecx
  xor edx,edx
  xor ebp,ebp
  xor esi,esi
  xor edi,edi

  .if _dosXtyp==DOSX_DOS4GW
    int 3  ;call debugger if loaded
  .endif

;main()
  push _environ
  push _argv
  push dptr _argc
  call main  ;called as main(_argc,_argv,_environ)
  add esp,12
;main()

  push ax
  call exit
;end of __entry32__

_c_exit proc
;restore all RM ints
  mov esi,offset _saved_ints
  mov edi,0
  mov ecx,256
  rep movsd

;restore PM ints
  mov ax,205h
  mov bl,10h
  mov cx,wptr[_int_10h+4]
  mov edx,dptr[_int_10h+0]
  int 31h
  jc Cantsetint

  mov ax,205h
  mov bl,21h
  mov cx,wptr[_int_21h+4]
  mov edx,dptr[_int_21h+0]
  int 31h
  jc Cantsetint

  call call_exit  ;deinit everything  (also calls global deconstructors)

  ret
_c_exit endp

include c0c2.asm
include c0c3.asm

endseg

end __entry32__
[ RETURN TO DIRECTORY ]