!
!	.asciz "@(#)crt0.s 1.1 94/10/31 SMI"
!
! Copyright (c) 1987 by Sun Microsystems, Inc.
!
!	crt0.s for the Sparc Architecture
!

#include <machine/asm_linkage.h>
#include <sys/syscall.h>
#include <sys/mman.h>

#ifdef	FIX_ALIGN
#include <machine/trap.h>
#endif	FIX_ALIGN

	.seg	"data"
	.global	_environ
_environ:
	.word	0
	.seg	"text"
	.align	4
	.global	start

!
! Start up a C program.
! On entry the stack frame looks like:
!
!	 _______________________  <- USRSTACK
!	|	    :		|
!	|  arg and env strings	|
!	|	    :		|
!	|-----------------------|
!	|	    0		|
!	|-----------------------|
!	|	    :		|
!	|  ptrs to env strings	|
!	|-----------------------|
!	|	    0		|
!	|-----------------------|
!	|	    :		|
!	|  ptrs to arg strings  |
!	|   (argc = # of wds)	|
!	|-----------------------|
!	|	   argc		|
!	|-----------------------|
!	|    window save area	|
!	|	 (16 wds)	|
!	|_______________________| <- %sp
!
start:
	mov	0, %fp			! stack frame link 0 in main -- for dbx
#ifdef	FIX_ALIGN
	ta	ST_FIX_ALIGN		! enable kernel alignment trap handler
#endif	FIX_ALIGN
	ld	[%sp + WINDOWSIZE], %o0	! argc
	add	%sp, WINDOWSIZE + 4, %o1! argv
	sll	%o0, 2, %o2		! argc * sizeof (int)
	add	%o2, 4, %o2		! skip 0 at end of arg ptrs
	add	%o1, %o2, %o2		! environment ptr
	sethi	%hi(_environ), %o3
	st	%o2, [%o3 + %lo(_environ)] ! store in _environ
	!
	! If the program requires dynamic link editing, call getrtld
	! to setup the run time loader.
	!
	sethi	%hi(__dp), %g1
	ld	[%g1 + %lo(__dp)], %g1 ! dynamically loaded?
	tst	%g1
	bz	1f			! no
	nop

	call	__getrtld		! yes, call getrtld
	nop
1:
	call	start_float		! initialize floating point
	nop

__main:
	call	_main			! main(argc, argv, envp)
	sub	%sp, SA(ARGPUSHSIZE+4), %sp ! leave room to push args

	call	_exit			! exit(main(...))
	nop

	call	__exit			! _exit(exit(0))
	nop
	/*NOTREACHED*/

/*
 * __getrtld: load and call the link editor.  When a program is link edited
 * by "ld", a structure is created if the program is "incomplete".  Such
 * programs must "complete themselves" by getting the link editor involved
 * again.
 */

/* struct exec */
/* XXX need to generate these symbols from a.out.h */
#define EXECSIZE	0x20
#define A_MAGIC		0x2
#define A_TEXT		0x4
#define A_DATA		0x8
#define A_BSS		0xc
#define A_ENTRY		0x14
#define ZMAGIC		0413

/* run time loader (ld.so) interface */
#define RTLD_VERS	1
#define VERS1NARGS	6
#define RTLDSIZE	(VERS1NARGS*4)

#define BASEADDR	0x0
#define DZFD		0x4
#define RLFD		0x8
#define UDP		0xc
#define ENV		0x10
#define BRKADDR		0x14

/* stack offsets */
#define FRAME		(MINFRAME+EXECSIZE+RTLDSIZE)
#define EXECOFF		(MINFRAME)		/* struct exec */
#define EXECP		%sp + EXECOFF
#define RTLDOFF		(MINFRAME+EXECSIZE)	/* run time loader interface */
#define RTLDP		%sp + RTLDOFF

/* mmap constants */
#define MMAP_RO		(PROT_READ|PROT_EXEC)
#define MMAP_PROT	(PROT_READ|PROT_WRITE|PROT_EXEC)
#define MMAP_FIXED	(_MAP_NEW|MAP_FIXED|MAP_PRIVATE)
#define MMAP_ASSIGN	(_MAP_NEW|MAP_PRIVATE)

/* registers */
#define errmp		l7
#define rlfd		l6
#define dzfd		l5
#define txt		l4
#define baseaddr	l3
#define td		l2
#define bss		l1

__getrtld:
	!
	! Allocate enough stack for MINFRAME, size of struct exec
	! and args passed to the runtime linker.
	!
	save	%sp, -SA(FRAME), %sp
	!
	! Find the link editor
	!
	set	Lerrmsg1, %errmp	! setup error message
	set	__link_editor, %o0
	call	__open, 2		! rlfd = open(".../ld.so",0)
	mov	0, %o1

	mov	%o0, %rlfd		! result
	!
	! Read in its exec header.
	!
	add	%sp, EXECOFF, %o1	! exec on stack
	call	__read, 3		! read(rlfd,&exec,sizeof(struct exec))
	mov	EXECSIZE, %o2
	cmp	%o0, EXECSIZE		! got full header?
	bne	__err_exit		! no
	nop
	!
	! Check out exec header.
	!
	lduh	[EXECP + A_MAGIC], %g1	! check magic number
	cmp	%g1, ZMAGIC
	bne	__err_exit		! wrong
	nop
	!
	! Determine how much of the address space the link editor will occupy.
	!
	ld	[EXECP + A_TEXT], %txt	! text size
	ld	[EXECP + A_DATA], %g1	! data size
	ld	[EXECP + A_BSS], %bss	! bss size
	add	%txt, %g1, %td		! size (o1) =
	add	%td, %bss, %o1		!   exec.a_text+exec.a_data+exec.a_bss
	!
	! Map in the link editor.
	! We map the whole thing in including bss so that we get an address
	! assignment which will accomodate the whole thing.
	!
	! baseaddr = mmap(0, size, MMAP_PROT, MMAP_ASSIGN, rlfd, 0)
	!
	set	Lerrmsg2, %errmp	! setup error message
	mov	0, %o0			! let system assign addr
					! how much we're mapping is in %o1
	set	MMAP_RO, %o2		! access protection
	set	MMAP_ASSIGN, %o3	! mapping flags
	mov	%rlfd, %o4		! fd for link editor
	call	__mmap, 6
	mov	0, %o5			! no offset

	mov	%o0, %baseaddr		! save addr
	add	%o0, %txt, %o0		! now map data segment read/write
	ld	[EXECP + A_DATA], %o1
	set	MMAP_PROT, %o2		! access protection
	set	MMAP_FIXED, %o3		! mapping flags
	mov	%rlfd, %o4		! fd for link editor
	call	__mmap, 6
	mov	%txt, %o5		! data  offset

	!
	! Obtain /dev/zero to map in for bss.
	!
	set	Lerrmsg3, %errmp	! setup error message
	set	Ldevzero, %o0		! dzfd = open("/dev/zero", 0)
	call	__open, 2
	mov	0, %o1

	mov	%o0, %dzfd		! result
	!
	! Map in /dev/zero to form bss for link editor.
	!
	ld	[EXECP + A_BSS], %g1	! if there is no bss skip this
	tst	%g1
	bz	1f
	.empty				! don't care about delay slot

	set	Lerrmsg2, %errmp
	!
	! mmap(baseaddr+exec.a_text+exec.a_data, exec.a_bss,
	!	MMAP_PROT, MMAP_FIXED, dzfd, 0)
	!
	add	%baseaddr, %td, %o0	! &bss = baseaddr+text+data
	mov	%bss, %o1		! map a bss's worth
	set	MMAP_PROT, %o2
	set	MMAP_FIXED, %o3		! use the address specified
	mov	%dzfd, %o4		! /dev/zero
	call	__mmap, 6
	mov	0, %o5			! map from offset zero
	!
	! Fill in the interface struct and call the link editor.
	!
1:
	ld	[EXECP + A_ENTRY], %g1	! compute ld.so entry point
	add	%baseaddr, %g1, %l0
	st	%baseaddr, [RTLDP + BASEADDR]	! pass base address
	st	%dzfd, [RTLDP + DZFD]		!  and /dev/zero
	st	%rlfd, [RTLDP + RLFD]		!  and ld.so file
	sethi	%hi(__dp), %g1
	ld	[%g1 + %lo(__dp)], %g1
	st	%g1, [RTLDP + UDP]		!  and program's DYNAMIC
	sethi	%hi(_environ), %g1
	ld	[%g1 + %lo(_environ)], %g1
	st	%g1, [RTLDP + ENV]		!  and _environ
	set	__main, %g1
	st	%g1, [RTLDP + BRKADDR]		! and breakpoint addr
	mov	RTLD_VERS, %o0
	jmpl	%l0, %o7		! ld.so(version number, intfc offset)
	mov	RTLDOFF, %o1
	!
	! Done.
	!
	ret
	restore

/*
 * System call interfaces.
 */

#define STDERR		2
#define ERRSTATUS	0x7f

__open:
	ba	__syscall
	mov	SYS_open, %g1

__mmap:
	ba	__syscall
	mov	SYS_mmap, %g1

__read:
	ba	__syscall
	mov	SYS_read, %g1

__syscall:
	t	0			! call the system call
	bcs	__err_exit		! test for error
	nop
	retl				! return
	nop

__err_exit:
	mov	STDERR, %o0
	add	%errmp, 0x4, %o1
	ld	[%errmp], %o2
	mov	SYS_write, %g1		! write(stderr, errmp+4, *errmp)
	t	0

	mov	ERRSTATUS, %o0		! exit(ERRSTATUS)
	mov	SYS_exit, %g1
	t	0
	/*NOTREACHED*/

/*
 * initialized, read only data.
 */
	.align	4
__dp:
	.word	__DYNAMIC
__link_editor:
	.ascii	"/usr/lib/ld.so\0"
Ldevzero:
	.ascii	"/dev/zero\0"
	.align	4
Lerrmsg1:
	.word	0x19
	.ascii	"crt0: no /usr/lib/ld.so\12\0"
	.align	4
Lerrmsg2:
	.word	0x26
	.ascii	"crt0: /usr/lib/ld.so mapping failure\12\0"
	.align	4
Lerrmsg3:
	.word	0x14
	.ascii	"crt0: no /dev/zero\12\0"
	.align	4
