/* First stage loader bootstrap for both v0, v2 and SUNW,Ultra's IEEE 1275 PROM
   designed for the romfs.
   
   Copyright (C) 1996,1997,1998,2000 Jakub Jelinek
   
   This program is free software; you can redistribute it and/or modify
   it under the terms of the GNU General Public License as published by
   the Free Software Foundation; either version 2 of the License, or
   (at your option) any later version.
   
   This program is distributed in the hope that it will be useful,
   but WITHOUT ANY WARRANTY; without even the implied warranty of
   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
   GNU General Public License for more details.

   You should have received a copy of the GNU General Public License
   along with this program; if not, write to the Free Software
   Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307,
   USA.  */

#define BLOCK_START	0x3dc
#define promvec		%l5
#define buffer		%l0
#define fd		%l6
#define stdouth		%l7
#define promvers	%l7
#define dest		%l4

	.text
	.align 4
	.global _start, letter_here, digit_here

_start:
bootmain:
	tst	%o4
	be	sparc_v8
	sethi	%hi(0x4000), buffer
	or	buffer, (BLOCK_START + 3 * 512), %i5
	sethi	%hi(0x10000), dest
	mov	%o4, promvec

	add	buffer, %lo(chosen), %o1
	call	prom11
	 add	buffer, %lo(finddevice), %o0
	ldx	[dest + 32], fd
	call	getprop
	 add	buffer, %lo(stdout), %o0
	lduw	[dest + 256], stdouth
	call	putchar
	 mov 	'S', %o0
	call	getprop
	 add	buffer, %lo(bootpath), %o0
	add	dest, 256, %o0
	mov	':', %o4
2:
	ldub	[%o0], %o3
	brz,pn	%o3, 3f
	 cmp	%o3, %o4
	bne,a,pt %icc, 2b
	 inc	%o0
3:
	stb	%o4, [%o0]
letter_here:
	mov	0xDD, %o4
	stb	%o4, [%o0 + 1]
	stb	%g0, [%o0 + 2]
	add	dest, 256, %o1
	call	prom11
	 add	buffer, %lo(open), %o0

	ldx	[dest + 32], fd
	or	buffer, BLOCK_START, %l2

	lduw	[%l2], %l3
	add	%l3, 4, %l3
	sll	%l3, 9, %o3
	srl	%l3, 23, %o2
	call	rwprom31
	 add	buffer, %lo(seek), %o0
	ldx	[dest + 48], %o0
	brlz,pn	%o0, 9f
	 lduw	[%l2 - 4], %l3

	call	putchar
	 mov	'I', %o0

	sub	%l3, 2048, %l3
	mov	%l3, %o3
	add	dest, 1024, %o2
	call	rwprom31
	 add	buffer, %lo(read), %o0
	ldx	[dest + 48], %o0
	cmp	%o0, %l3
	bne,pn	%icc, 9f
	 mov	fd, %o1

	call	prom11
	 add	buffer, %lo(close), %o0
	ldub	[dest + 1024 + 0x08], %o0
	cmp	%o0, 'L'
	bne,a,pn %icc, 10f
	 add	buffer, %lo(exit), %o0

	call	putchar
	 flush	dest + 1024

	mov	promvec, %o4
	jmpl	dest + 1024, %g0
	 clr	%l3
putchar:
	stb 	%o0, [buffer]
	mov	stdouth, %o1
	mov	buffer, %o2
	mov	1, %o3
	ba,pt	%xcc, prom31
	 add	buffer, %lo(write), %o0
9:
	add	buffer, %lo(exit), %o0
10:
	call	prom11
getprop:
	 stx	%o0, [dest + 32]
	add	dest, 256, %o0
	stx	%o0, [dest + 40]
	mov	1024, %o0
	stx	%o0, [dest + 48]
	mov	fd, %o1
	add	buffer, %lo(getprops), %o0
	mov	4, %o2
	stx	%o2, [dest + 8]
2:
	ba,pt	%xcc, 1f
prom11:
	 mov	1, %o2
	stx	%o2, [dest + 8]
1:
	stx	%o0, [dest]
	stx	%o2, [dest + 16]
	stx	%o1, [dest + 24]
	jmpl	promvec + %g0, %g0
	 mov	dest, %o0
rwprom31:
	mov	fd, %o1
prom31:
	mov	3, %o4
	stx	%o4, [dest + 8]
	stx	%o2, [dest + 32]
	ba,pt	%xcc, 2b
	 stx	%o3, [dest + 40]

finddevice:
	.asciz	"finddevice"
getprops:
	.asciz	"getprop"
bootpath:
	.asciz	"bootpath"
stdout:
	.asciz	"stdout"
open:
	.asciz	"open"
close:
	.asciz	"close"
seek:
	.asciz	"seek"
read:
	.asciz	"read"
write:
	.asciz	"write"
chosen:
	.asciz	"/chosen"
exit:
	.asciz	"exit"

	.align	512
sparc_v8:
	mov	%o0, promvec
	ld	[promvec+4], promvers
	sethi	%hi(0x4000), buffer
	sethi	%hi(0x10000), dest
	call	putchar_v8
	 mov 	'S', %o0

	tst	promvers
	bne,a	1f
	 ld	[promvec+136], %o0		! pv_v2bootargs.bootpath

	ld	[promvec+128], %o0
	ld	[%o0], %o3			! o3 = *pv_v0bootargs
	lduh	[%o3+132], %o1			! 'sd', 'fd' or whatever
	sll	%o1, 8, %o1
	or	%o1, '(', %o1
	sll	%o1, 8, %o1
	ld	[%o3+136], %o0			! controler id (hope it is less than 10)
	add	%o0, '0', %o0
	or	%o1, %o0, %o2
	mov	',', %o1
	sll	%o1, 8, %o1
	ld	[%o3+140], %o4			! unit id (again, hope nobody uses wide on v0 prom)
	add	%o4, '0', %o4
	or	%o4, %o1, %o4
	sll	%o4, 16, %o4
	or	%o4, %o1, %o4
digit_here:
	or	%o4, 0xDD, %o3
	std	%o2, [buffer + 0x400]		! put the 'sd(i,j,k' somewhere...
	mov	')', %o2
	sll	%o2, 8, %o2
	sth	%o2, [buffer + 0x408]		! put there the rest ')\0' as well...
	b	4f
	ld	[promvec+36], %o1		! pv_v0devops.v0_devopen
1:
	ld	[promvec+172], %o1
	ld	[%o0], %o0
	add	buffer, 0x400, %o2
	mov	':', %o4
2:
	ldub	[%o0], %o3
	tst	%o3
	be	3f
	 cmp	%o3, %o4

	be	3f
	 stb	%o3, [%o2]
	add	%o2, 1, %o2
	b	2b
	 add	%o0, 1, %o0
3:
	stb	%o4, [%o2]
	ldub	[buffer + (letter_here - _start + 3)], %o4
	stb	%o4, [%o2 + 1]
	stb	%g0, [%o2 + 2]
4:
	call	%o1
	 add	buffer, 0x400, %o0

	mov	%o0, fd
	or	buffer, BLOCK_START, %l2

	ld	[%l2], %l3
	tst	promvers
	bne	6f
	 add	%l3, 4, %l3
	ld	[promvec+44], %o4		! pv_v0devops.v0_rdblkdev
	ld	[%l2 - 4], %l2
	srl	%l2, 9, %l2
	sub	%l2, 4, %l2
	mov	%l2, %o1
	mov	%l3, %o2
	mov	dest, %o3
	call	%o4
	 mov	fd, %o0
	mov	%o0, %l3
	
	call	putchar_v8
	 mov	'I', %o0

	cmp	%l3, %l2
	b,a	0f
6:
	ld	[promvec+188], %o4		! pv_v2devops.v2_dev_seek
	mov	%g0, %o1
	sll	%l3, 9, %o2
	call	%o4
	 mov	fd, %o0
	cmp	%o0, -1
	be	9f
	 ld	[%l2 - 4], %l3
	call	putchar_v8
	 mov	'I', %o0

	ld	[promvec+180], %o4		! pv_v2devops.v2_dev_read
	sub	%l3, 2048, %l3
	mov	%l3, %o2
	mov	dest, %o1
	call	%o4
	 mov	fd, %o0
	cmp	%o0, %l3
0:
	bne	9f
	 ldub	[dest + 0x08], %o0
	cmp	%o0, 'L'
	bne	9f
	 clr	%l3

	call	putchar_v8
	 ld	[promvec+176], %l1		! pv_v2devops.v2_dev_close

	tst	promvers
	be,a	8f
	 ld	[promvec+40], %l1		! pv_v0devops.v0_dev_close
8:
	call	%l1
	 mov	fd, %o0
	clr	%o4				! we are not an Ultra
	jmpl	dest + %g0, %g0
	 mov	promvec, %o0
9:
	ld	[promvec+116], %g1
	jmpl	%g1 + %g0, %g0
putchar_v8:
	tst	promvers
	bne	1f
	 ld	[promvec+92], %o1		! pv_nbputchar

	jmpl 	%o1 + %g0, %g0
	 or	buffer, (BLOCK_START + 3 * 512), %i5
1:
	stb 	%o0, [buffer]
	ld 	[promvec+148], %o0		! pv_v2bootargs.fd_stdout
	ld 	[promvec+184], %o3		! pv_v2devops.v2_dev_write
	mov	buffer, %o1
	ld	[%o0], %o0
	mov	1, %o2
	jmpl 	%o3 + %g0, %g0
	 or	buffer, (BLOCK_START + 3 * 512), %i5
