Subject: Re: passing in the booted kernel name...?
To: None <port-sparc@netbsd.org, tech-kern@netbsd.org>
From: Chris Torek <torek@BSDI.COM>
List: tech-kern
Date: 01/09/1999 06:18:08
Not sure why this is going to both "port-sparc" *and* "tech-kern",
but anyway...

>You appear to be talking about a communication between
>the bootloader and the kernel.  Why would this be hard?

It is not, really.  There already is *some* communication on most
if not all ports (for passing "boot into single user mode" flags
and the like).  In BSD/OS we formalized this stuff into a series
of "boot parameters" defined in <sys/reboot.h> and <machine/bootparam.h>:

	[reboot.h; minor comment-editing for indentation]
	/*
	 * Definition of parameters passed to kernel by bootstrap.
	 * We pass a variable number of variable sized parameters,
	 * thus we use an array of self-describing elements.
	 * The bootparamhdr structure is the header for the whole array,
	 * and the bootparam structure heads each element of the array.
	 */
	#define	BOOT_MAGIC	0xB00DEF01

	#ifndef LOCORE
	struct bootparamhdr {
		u_int32_t b_magic;	/* BOOT_MAGIC */
		u_int32_t b_len;	/* total length, including header */
	};
	#else
	/* XXX for bootstrap startup code */
	#define	B_MAGIC	0
	#define	B_LEN	4
	#endif /* LOCORE */

	#ifndef LOCORE
	struct bootparam {
		u_int32_t b_type;	/* parameter type */
		u_int32_t b_len;	/* element length, including header */
		/* then parameter value */
	};

	/* given pointer to bootparamhdr, return pointer to first element */
	#define	B_FIRSTPARAM(bph)	((struct bootparam *)((bph) + 1))

	/* given pointer to bootparam, return pointer to next bootparam */
	#define	B_NEXTPARAM(bph, bp) \
		(((caddr_t)(bp) + (bp)->b_len + sizeof(struct bootparam) > \
		   (caddr_t)(bph) + (bph)->b_len) ? (struct bootparam *)NULL : \
		    (struct bootparam *)((caddr_t)(bp) + ALIGN((bp)->b_len)))

	/* given pointer to struct bootparam, return pointer to data */
	#define	B_DATA(bp)		((u_char *)((bp) + 1))
	#endif /* LOCORE */

The way the bootparamhdr and its following data is located is
machine-dependent; on the sparc, I have the boot loader stuff
it right after the kernel bss area, so that it appears at
"extern char end[]; ALIGN(end)".

Given that you probably will not want the exact same boot parameter
type codes as BSD/OS, if you do it this way, you might want a
different BOOT_MAGIC (b00def02?).  (I have left out the type-codes
and corresponding data structures for brevity, and on the assumption
that you do not want to duplicate any mistakes we made, like fixing
the "memory size" boot parameter as supposedly MI but hopelessly
32-bit.  Define a B_MACHDEP_BASE -- ours is 0x10000 -- and pass in
MD "bootparam"s as type-code B_MACHDEP_BASE+n, n >= 0.  Give any
"here is how much memory is available to the kernel" parameter+struct
a machine-dependent type-code and layout.)

Note that once you commit to forcing people to boot your kernel
from your boot block, you can move all sorts of interesting and
problematical kernel bootstrapping problem code into the boot loader
and out of the kernel proper.  (On the i386, for instance, you can
do all the hairy memory-sizing stuff in /boot instead of in /netbsd.
You can, although I have not yet done so myself myself, have the
sparc boot loader set up the VM hardware and map all kernel contexts
on the sun4c, and so on.)  In other words, /boot gets bigger, and
the kernel gets smaller, which is generally desirable.

Chris