/*
 * CDDL HEADER START
 *
 * The contents of this file are subject to the terms of the
 * Common Development and Distribution License (the "License").
 * You may not use this file except in compliance with the License.
 *
 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
 * or http://www.opensolaris.org/os/licensing.
 * See the License for the specific language governing permissions
 * and limitations under the License.
 *
 * When distributing Covered Code, include this CDDL HEADER in each
 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
 * If applicable, add the following below this CDDL HEADER, with the
 * fields enclosed by brackets "[]" replaced with your own identifying
 * information: Portions Copyright [yyyy] [name of copyright owner]
 *
 * CDDL HEADER END
 */

/*
 * Copyright 2010 Sun Microsystems, Inc.  All rights reserved.
 * Use is subject to license terms.
 */

	.file	"_rtboot.s"

! Bootstrap routine for alias ld.so.  Control arrives here either directly
! from exec() upon invocation of a dynamically linked program specifying our
! alias as its interpreter.
!
! On entry, the stack appears as:
!
!_______________________!  high addresses
!			!  
!	Information	!  
!	Block		!  
!	(size varies)	!  
!_______________________!
!	0 word		!
!_______________________!
!	Auxiliary	!
!	vector		!
!	2 word entries	!
!			!
!_______________________!
!	0 word		!
!_______________________!
!	Environment	!
!	pointers	!
!	...		!
!	(one word each)	!
!_______________________!
!	0 word		!
!_______________________!
!	Argument	! low addresses
!	pointers	!
!	Argc words	!
!_______________________!
!			!
!	Argc		!
!_______________________!<- %sp +64
!			!
!   Window save area	! 
!_______________________! <- %sp

#include <sys/asm_linkage.h>
#include <sys/param.h>
#include <sys/syscall.h>
#include <link.h>
#include "alias_boot.h"

	.section ".text"
	.volatile
	.global	__rtboot
	.local	__rtld
	.local	s.LDSO, s.ZERO
	.local	f.PANIC, f.OPENAT, f.MMAP, f.FSTATAT, f.SYSCONFIG
	.local	f.CLOSE, f.EXIT, f.MUNMAP
	.type	__rtboot, #function
	.align	4

! Create a stack frame, perform PIC set up.  If we're a "normal" start, we have
! to determine a bunch of things from our "environment" and construct an ELF
! boot attribute value vector.  Otherwise, it's already been done and we can
! skip it.

__rtboot:
	save	%sp, -SA(MINFRAME + (EB_MAX * 8) + ((S_MAX + F_MAX) * 4)), %sp
1:					! PIC prologue
	call	2f			! get PIC for PIC work

! Set up pointers to __rtld parameters.  eb[], strings[] and funcs[] are on
! the stack.  Note that we will call ld.so with an entry vector that causes
! it to use the stack frame we have.

	add	%sp, MINFRAME, %o0	! &eb[0]
2:
	add	%o0, (EB_MAX * 8), %o1	! &strings[0] == &eb[EB_MAX]
	add	%o1, (S_MAX * 4), %o2	! &funcs[0] == &strings[S_MAX]
	set	EB_ARGV, %l0		! code for this entry
	st	%l0, [%o0]		!   store it
	add	%fp, 68, %l0		! argument vector is at %fp+68
	st	%l0, [%o0 + 4]		!   store that
	ld	[%fp + 64], %l1		! get argument count
	inc	%l1			! account for last element of 0
	sll	%l1, 2, %l1		! multiply by 4
	add	%l0, %l1, %l0		!   and get address of first env ptr
	st	%l0, [%o0 + 12]		! store it in the vector
	set	EB_ENVP, %l1		! code for environment base
	st	%l1, [%o0 + 8]		!   store it
	set	EB_AUXV, %l1		! get code for auxiliary vector
	st	%l1, [%o0 + 16]		!   store it
2:
	ld	[%l0], %l1		! get an entry
	tst	%l1			! are we at a "0" entry in environment?
	bne	2b			!   no, go back and look again
	add	%l0, 4, %l0		!     incrementing pointer in delay
	st	%l0, [%o0 + 20]		! store aux vector pointer
	set	EB_NULL, %l0		! set up for the last pointer
	st	%l0, [%o0 + 24]		!   and store it

! Initialize strings and functions as appropriate

#define	SI(n) \
	set	(s./**/n  - 1b), %l0; \
	add	%o7, %l0, %l0; \
	st	%l0, [%o1 + (n/**/_S * 4)]
#define	FI(n) \
	set	(f./**/n - 1b), %l0; \
	add	%o7, %l0, %l0; \
	st	%l0, [%o2 + (n/**/_F * 4)]

	SI(LDSO)
	SI(ZERO)
	SI(EMPTY)
	FI(PANIC)
	FI(OPENAT)
	FI(MMAP)
	FI(FSTATAT)
	FI(SYSCONFIG)
	FI(CLOSE)
	FI(MUNMAP)

! Call the startup function to get the real loader in here.

	call	__rtld			! call it
	mov	%o0, %l0		!   and save &eb[0] for later

! On return, jump to the function in %o0, passing &eb[0] in %o0

	jmpl	%o0, %g0		! call main program
	mov	%l0, %i0		! set up parameter

! Functions

f.PANIC:
	save	%sp, -SA(MINFRAME), %sp	! make a frame
	mov	%i0, %o1		! set up pointer
	clr	%o2			! set up character counter
1:					! loop over all characters
	ldub	[%i0 + %o2], %o0	! get byte
	tst	%o0			! end of string?
	bne,a	1b			!   no,
	inc	%o2			!     increment count
	call	f.WRITE			! write(2, buf, %o2)
	mov	2, %o0
2:
	call	1f			! get PC
	mov	l.ERROR, %o2		! same with constant message
1:
	set	(s.ERROR - 2b), %o1	! get PC-relative address 
	add	%o7, %o1, %o1		!   and now make it absolute
	call	f.WRITE			! write it out
	mov	2, %o0			!   to standard error
	ba	f.EXIT			! leave
	nop

f.OPENAT:
	ba	__syscall
	mov	SYS_openat, %g1

f.MMAP:
	sethi	%hi(0x80000000), %g1	! MAP_NEW
	or	%g1, %o3, %o3
	ba	__syscall
	mov	SYS_mmap, %g1

f.MUNMAP:
	ba	__syscall
	mov	SYS_munmap, %g1

f.READ:
	ba	__syscall
	mov	SYS_read, %g1

f.WRITE:
	ba	__syscall
	mov	SYS_write, %g1

f.LSEEK:
	ba	__syscall
	mov	SYS_lseek, %g1

f.CLOSE:
	ba	__syscall
	mov	SYS_close, %g1

f.FSTATAT:
	ba	__syscall
	mov	SYS_fstatat, %g1

f.SYSCONFIG:
	ba	__syscall
	mov	SYS_sysconfig, %g1

f.EXIT:
	mov	SYS_exit, %g1

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

__err_exit:
	retl				! return
	mov	-1, %o0

! String constants

s.LDSO:	.asciz	"/usr/lib/ld.so.1"
s.ZERO:	.asciz	"/dev/zero"
s.EMPTY:.asciz	"(null)"
s.ERROR:.asciz	": no (or bad) /usr/lib/ld.so.1\n"
l.ERROR= . - s.ERROR
	.align	4
	.size	__rtboot, . - __rtboot

! During construction -- the assembly output of _rtld.c2s is placed here.

	.section ".text"
	.nonvolatile
