Subject: Re: HyperSPARC woes...
To: None <mjacob@feral.com>
From: Michael J. Tuciarone <tooch@FirmWorks.COM>
List: port-sparc
Date: 10/27/1996 14:30:25
Yes indeed, you can make one common boot image that works on both
Sunmon and OBP SPARC machines. I had actually completed this before
I left Sun, but for some reason I never pushed it through to release
and nobody picked it up afterward. It was called "GUB"--Grand Unified
Boot--and you can have the name so far as I'm concerned.

It works like this: OBP loads the image and checks the header. If it
sees an "Open Boot Client Program" magic number--which happens to be
bit-identical to an a.out magic but IS NOT an a.out magic number; the
Sun Architecture Review Committee made me say that, so that no one can
be accused of contaminating the Brave New World of Solaris and ELF with
yucky old a.out executables--then it relocates the entire image 32 bytes
lower in memory, i.e. the size of an a.out header. OBP pays no attention
to the rest of the header, so effectively you have 28 bytes or seven
instructions to play with.

Sunmon does not inspect the header at all, but simply executes it as
raw code. The magic number turns out to be a no-op, o bona fortuna:
"sethi 0x30107,%g0".

The GUB startup code looks like this:

	ENTRY(start)
	.word	0x01030107		! sethi	0x30107, %g0 (yecch!)
	!
	! OK, that faked out the forth prom. We have seven more instructions,
	! then we must jump to the forth startup code.
	!
	! Set the psr into a known state, until we are sure it is:
	! supervisor mode, interrupt level >= 13, traps enabled
	!
	mov	%psr, %o0		! 1
	andn	%o0, PSR_PIL, %o0	! 2
	set	PSR_S|ipltospl(PSR_PIL_INIT)|PSR_ET, %o1	! 3
	or	%o0, %o1, %o0		! 4
	mov	%o0, %psr		! 5
	clr	%o0			! 6
	nop				! 7
!
! OBP gets control here!
!
! Don't munge %o0 since it contains the romp. Set _start and _end
! since we'll need those values for both OBP and sunmon.
!
	sethi	%hi(_start), %o1
	or	%o1, %lo(_start), %o1
	sethi	%hi(_end), %o2
	tst	%o0
	bz	sunmon
	or	%o2, %lo(_end), %o2	
	call	_goforth		! OBP only
	nop
sunmon:
	save	%o1, -SA(MINFRAME), %sp
	!
	! zero the bss
	!
	sethi	%hi(_edata), %o0	! Beginning of bss
	or	%o0, %lo(_edata), %o0
	call	_bzero
	sub	%i2, %o0, %o1		! end - edata = size of bss
	call	_main
	nop
	call	_exit
	mov	0, %o0
	ret				! ret to prom
	restore

As a further filigree, I implemented the UFS reader directly in the
first-stage bootblock, so there's no longer a need to stamp the
block numbers of /boot directly into the bootblock. You just load the
bootblock and ask for /vmunix by name. This took about 4k. The OBP
bootblock, as a futher experiment, was written directly in FCode
(including the UFS file reader package) and took about 1.5k, although
there's no reason the OBP bootblock can't be merged with the sunmon
bootblock using appropriate romvec wrappers. Add in about 1k for
bookkeeping and the whole thing fits snugly but comfortably in 7.5 KB,
the size of the bootblock. The nicest thing is that installing this 
bootblock could become an automatic part of newfs, so that every partition
is bootable and you don't ever have to run the installboot voodoo.

Don't forget--if you use this technique, you have to readjust the
image if you take the OBP branch, since the firmware has moved the image.

If you have any further questions or comments, or would like to cajole me into
doing some of the work, please contact me at tooch@firmworks.com.
(It's time I gave some karma back to the free software world.)

Yours,
Mike Tuciarone