**
**  crt0.asm / ixemul startup code for vbcc/PhxLnk
**
**  This startup code will need at least PhxLnk v4.30 to find all
**  the required linker symbols.
**
**  Based on crt0.c by Loren J. Rittle
**  Written by Frank Wille 1997
**
**  Assemble with BASECRT0 set, to generate the small data version.
**
**  started: 07-Jan-97
**
** v0.1 (08-Jan-97) hard-coded __stk_limit, __stk_argbytes and __machtype,
**                  no small data support, no moncontrol support for
**                  profiling, etc... ;)
** v0.2 (09-Jan-97) omitting the __init_stk_limit()-call seems to be a better
**                  solution for the __stk_limit/__stk_argbytes problem (?)
** v0.9 (10-Jan-97) removed some obsolete xdefs, minor code optimizations,
**                  small data support by setting BASECRT0 (!)
** v1.0 (02-Feb-97) supports some (all?) nice ixemul.library v45 features
**                  (e.g. automatic stack extension, some network ini-
**                  tialization, etc.) so that v45 is *required* from now
**                  on,
**                  ___ixemulVer may be defined by the user to set the
**                  mininum ixemul-version, which the program requires,
**                  besides ___ixemulVer, some other symbols have moved
**                  into the ixemul.lib to give the user the possibility
**                  to overwrite them by an own definition: _expand_cmd_line,
**                  ___stk_limit, ___stk_argbytes and ___stack,
**                  the __init_stk_limit()-call is in the startup code again,
**                  BASECRT0 mode needs the exec-entries a_bss set to zero
**                  and a_data = _DATA_LEN_ + _BSS_LEN_, this is done by
**                  importing the new linker symbol _SMALL_DATA_LEN_, which
**                  PhxLnk defines since v4.30
**

IX_VERSION	equ	45		; minimum version for startup code

; exec.library LVOs
OpenLibrary	equ	-552
CloseLibrary	equ	-414
Forbid		equ	-132
GetMsg		equ	-372
ReplyMsg	equ	-378
WaitPort	equ	-384
CopyMem		equ	-624

; dos.library LVOs
FilePart	equ	-870

; intuition.library LVOs
EasyRequestArgs	equ	-588

; ixemul.library LVOs
ix_startup	equ	-552
ix_exec_entry	equ	-1896
ix_get_vars2	equ	-1902
ix_resident	equ	-2568
__init_stk_limit equ	-2904
__stkext_startup equ	-3450


	include	"exec/execbase.i"
	include	"exec/libraries.i"
	include	"dos/dosextens.i"
	include	"intuition/intuition.i"



	code

	xref	_main

	xref	_CODE_LEN_		; linker symbols, generated by PhxLnk
	xref	_DATA_LEN_
	xref	_BSS_LEN_
;	xref	___machtype
___machtype	equ	0		; currently hard-coded


	IFD	BASECRT0
	near	a4,-2			; activate small data mode
	xref	_SMALL_DATA_LEN_	; total small data size
	nref	_expand_cmd_line
	nref	___stk_limit
	nref	___stk_argbytes
	nref	___ixemulVer
	nref	___stack
	ELSE
	xref	_expand_cmd_line	; expand wildcards?
	xref	___stk_limit
	xref	___stk_argbytes
	xref	___ixemulVer		; ixemul.library version to open
	xref	___stack		; desired stack size
	ENDIF

; This is the first code executed.  Note that a_magic has to be at
; a known offset from the start of the code section in order for
; execve() to know that the program that it is starting uses the
; ixemul library.

	bra.w	_ENTRY

; this is a struct exec, for now only OMAGIC is supported 
	dc.w	___machtype 	; a_mid 
	dc.w	@407		; a_magic = OMAGIC
	dc.l	_CODE_LEN_	; a_text 
	IFND	BASECRT0
	dc.l	_DATA_LEN_	; a_data 
	dc.l	_BSS_LEN_	; a_bss 
	ELSE
	dc.l	_SMALL_DATA_LEN_
	dc.l	0
	ENDIF
	dc.l	0		; a_syms 
	dc.l	_exec_entry	; a_entry 
	dc.l	0		; a_trsize 
	dc.l	0		; a_drsize 


abort_txt:
	dc.b	"Abort",0
liberr_txt:
	dc.b	"Need at least version %ld of ixemul.library.",0
crt_txt:
	IFD	BASECRT0
	dc.b	"b"
	ENDIF
	dc.b	"crt0",0
	even


	xdef	_ix_get_variables	; should this be extern?
_ix_get_variables:
; int from_vfork_setup_child (0 or 1)
	move.l	_ixemulbase,a0
	pea	__res_socket
	lea	__res,a1		; set resolver state default settings
	move.l	a1,-(sp)
	move.l	#5,(a1)+		; retrans = RES_TIMEOUT
	move.l	#4,(a1)+		; retry = 4
	move.l	#$2c0,(a1)+		; options = RES_DEFAULT
	move.l	#1,(a1)+		; nscount = 1
	pea	_h_errno
	tst.l	4*4(sp)			; from_vfork_setup_child ?
	beq	.1
	pea	_errno
	pea	_environ
	bra	.2
.1:	clr.l	-(sp)
	clr.l	-(sp)
.2:	pea	_environ
	pea	___sF
	pea	_DOSBase
	pea	_SysBase
	pea	_sys_nerr
	pea	__ctype_
	pea	11.w
	jsr	ix_get_vars2(a0)
	add.w	#48,sp
	rts


_start_stdio:
; int argc, char **argv, char **env
	move.l	a6,-(sp)
	clr.l	-(sp)
	bsr	_ix_get_variables	; init SysBase, DOSBase, etc.

; we call a v36 dos.library function here, because crt0 should have
; already failed on a pre-v36 system.
	move.l	_DOSBase,a6
	move.l	4*4(sp),a0
	move.l	(a0),d1			; argv[0]
	beq	.1
	jsr	FilePart(a6)		; get program name
	move.l	d0,___progname

; call main
.1:	movem.l	3*4(sp),d0-d1/a0	; argc, argv, env
	move.l	a0,_environ
	movem.l	d0-d1/a0,-(sp)
	jsr	_main			; call main(argc,argv,env) entry point
	add.w	#16,sp
	move.l	(sp)+,a6
	rts


_exec_entry:
; struct Library *ibase, int argc, char *argv[], char *env[]
	IFD	BASECRT0
	bsr	_geta4
	move.l	4(sp),a0		; ibase
	move.l	a4,-(sp)
	pea	2.w
	jsr	ix_resident(a0)
	addq.w	#8,sp
	ENDIF
	move.l	4(sp),a0		; ibase
	move.l	a0,_ixemulbase		; set ixemulbase
	move.l	___ixemulVer,d0
	cmp.w	LIB_VERSION(a0),d0
	bls	.1			; version ok?

	move.l	4.w,a6
	move.l	d0,-(sp)
	pea	abort_txt(pc)
	pea	liberr_txt(pc)
	pea	crt_txt(pc)
	subq.w	#8,sp
	bsr	ix_panic
	add.w	#24,sp
	move.l	#(20<<8)|0,d0		; W_EXITCODE(20,0)
	rts

.1	move.l	a0,-(sp)
	move.l	___stk_argbytes,-(sp)
	pea	___stk_limit
	jsr	__init_stk_limit(a0)
	addq.w	#8,sp
	move.l	(sp)+,a0
	pea	_start_stdio(pc)
	pea	_errno
	move.l	24(sp),-(sp)		; env
	move.l	24(sp),-(sp)		; argv
	move.l	24(sp),-(sp)		; argc
	move.l	___stack,d0		; desired stack size set?
	beq	.2
	jsr	__stkext_startup(a0)	; stack extension, if required
.2	jsr	ix_exec_entry(a0)
	add.w	#20,sp
	rts


	IFD	BASECRT0
	xref	_DATA_BAS_
	xdef	_geta4
_geta4:
	lea	_DATA_BAS_+32766,a4	; init small data base register
	rts
	ENDIF


; Note: This routine must be far enough away from the start of code
; so that the PC relative offset won't fit in a byte and the assembler
; will generate the right instruction pattern that execve() is looking
; for to know that this is a program that uses the ixemul.library.

_ENTRY:
	IFD	BASECRT0
	movem.l	d2/a2/a4/a6,-(sp)
	bsr	_geta4
	ELSE
	movem.l	d2/a2/a6,-(sp)
	ENDIF
	move.l	a0,d2			; a2/d2 save command line
	move.l	d0,a2
	move.l	4.w,a6			; ExecBase (v37)
	cmp.w	#37,LIB_VERSION(a6)	; required for StackSwap()
	blo	.6
	move.l	___ixemulVer,d0		; user-defined version
	moveq	#IX_VERSION,d1		; minimum version required
	cmp.l	d1,d0
	bhs	.4
	move.l	d1,d0
	move.l	d0,___ixemulVer
.4:	lea	ixemul_name(pc),a1
	jsr	OpenLibrary(a6)		; open ixemul.library
	move.l	d0,_ixemulbase
	beq	.1

	move.l	d0,a6			; a6 ixemulbase
	IFD	BASECRT0
	move.l	a4,-(sp)
	pea	2.w
	jsr	ix_resident(a6)
	addq.w	#8,sp
	ENDIF
	move.l	___stk_argbytes,-(sp)
	pea	___stk_limit
	jsr	__init_stk_limit(a6)
	pea	_errno
	pea	_start_stdio(pc)
	move.l	_default_wb_window,-(sp)
	move.l	_expand_cmd_line,-(sp)
	move.l	a2,-(sp)
	move.l	d2,-(sp)
	move.l	___stack,d0		; desired stack size set?
	beq	.5
	jsr	__stkext_startup(a6)	; stack extension, if required
.5:	jsr	ix_startup(a6)		; ixemul startup

	move.l	d0,d2
	add.w	#32,sp
	move.l	a6,a1
	move.l	4.w,a6
	jsr	CloseLibrary(a6)	; close ixemul.library
	move.l	d2,d0
	bra	.3

.1:	move.l	___ixemulVer,-(sp)	; error on opening ixemul.library
	pea	abort_txt(pc)
	pea	liberr_txt(pc)
	pea	crt_txt(pc)
	subq.w	#8,sp
	bsr	ix_panic
	add.w	#24,sp
.6:	move.l	ThisTask(a6),a2
	tst.l	pr_CLI(a2)		; started from CLI?
	bne	.2
; Quickly deal with the WB startup message, as the library couldn't do
; this for us. Nothing at all is done that isn't necessary to just shutup
; workbench.
	jsr	Forbid(a6)
	add.w	#pr_MsgPort,a2
	move.l	a2,a0
	jsr	WaitPort(a6)
	move.l	a2,a0
	jsr	GetMsg(a6)
	move.l	d0,a1
	jsr	ReplyMsg(a6)		; reply WBStartup message
.2:	moveq	#20,d0
.3:	
	IFD	BASECRT0
	movem.l	(sp)+,d2/a2/a4/a6
	ELSE
	movem.l	(sp)+,d2/a2/a6
	ENDIF
	rts

ixemul_name:
	dc.b	"ixemul.library",0
intuition_name:
	dc.b	"intuition.library",0
	even


ix_panic:
; Displays a v36 easy-requester.
; A comlete EasyStruct is already on stack, when called. Only es_StructSize
; and es_Flags will be initialized here.
; a6 = ExecBase
	lea	intuition_name(pc),a1
	moveq	#36,d0
	jsr	OpenLibrary(a6)		; open intuition.library v36
	tst.l	d0
	beq	.1
	movem.l	a2-a3/a6,-(sp)
	move.l	d0,a6			; IntuitionBase
	sub.l	a0,a0
	lea	4*4(sp),a1		; EasyStruct
	move.l	#EasyStruct_SIZEOF,es_StructSize(a1)
	clr.l	es_Flags(a1)
	sub.l	a2,a2
	lea	EasyStruct_SIZEOF(a1),a3 ; ArgList
	jsr	EasyRequestArgs(a6)	; render panic requester
	move.l	a6,a1
	movem.l	(sp)+,a2-a3/a6
	jsr	CloseLibrary(a6)	; close intuition.library
.1:	rts


; null mcount and moncontrol, just in case some routine is 
; compiled for profiling
	xdef	mcount
	xdef	_moncontrol
_moncontrol:
mcount: 
	rts 



	IFD	BASECRT0
	section	__MERGED,data
	ELSE
	data
	ENDIF

_environ:
	dc.l	dummy_environ ; default for progs not started via exec_entry
___progname:
	dc.l	dummy_environ ; use dummy_environ as empty string
__res_socket:		; resolv socket used for communications
	dc.l	-1

	xdef	_environ
	xdef	___progname
	xdef	__res_socket



	IFD	BASECRT0
	section	__MERGED,bss
	ELSE
	bss
	ENDIF

_ixemulbase:
	ds.l	1
_errno:			; error results from the library
	ds.l	1
__ctype_:
	ds.l	1
_sys_nerr:		; number of system error codes
	ds.l	1
_SysBase:
	ds.l	1
_DOSBase:
	ds.l	1
___sF:
	ds.l	1
___SaveSP:
	ds.l	1
dummy_environ:
	ds.l	1
_default_wb_window:	; Default Workbench output window name
	ds.l	1
_h_errno:
	ds.l	1	; networking error code
__res:			; resolver state
	ds.b	448	; sizeof(struct __rest_state) + some extra bytes

	xdef	_ixemulbase
	xdef	_errno
	xdef	__ctype_
	xdef	_sys_nerr
	xdef	_SysBase
	xdef	_DOSBase
	xdef	___sF
	xdef	___SaveSP
	xdef	_h_errno
	xdef	__res

	end
