xref: /openbsd/sys/arch/sparc64/stand/ofwboot/boot.c (revision 73471bf0)
1 /*	$OpenBSD: boot.c,v 1.38 2021/10/26 10:45:55 patrick Exp $	*/
2 /*	$NetBSD: boot.c,v 1.3 2001/05/31 08:55:19 mrg Exp $	*/
3 /*
4  * Copyright (c) 1997, 1999 Eduardo E. Horvath.  All rights reserved.
5  * Copyright (c) 1997 Jason R. Thorpe.  All rights reserved.
6  * Copyright (C) 1995, 1996 Wolfgang Solfrank.
7  * Copyright (C) 1995, 1996 TooLs GmbH.
8  * All rights reserved.
9  *
10  * ELF support derived from NetBSD/alpha's boot loader, written
11  * by Christopher G. Demetriou.
12  *
13  * Redistribution and use in source and binary forms, with or without
14  * modification, are permitted provided that the following conditions
15  * are met:
16  * 1. Redistributions of source code must retain the above copyright
17  *    notice, this list of conditions and the following disclaimer.
18  * 2. Redistributions in binary form must reproduce the above copyright
19  *    notice, this list of conditions and the following disclaimer in the
20  *    documentation and/or other materials provided with the distribution.
21  * 3. All advertising materials mentioning features or use of this software
22  *    must display the following acknowledgement:
23  *	This product includes software developed by TooLs GmbH.
24  * 4. The name of TooLs GmbH may not be used to endorse or promote products
25  *    derived from this software without specific prior written permission.
26  *
27  * THIS SOFTWARE IS PROVIDED BY TOOLS GMBH ``AS IS'' AND ANY EXPRESS OR
28  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
29  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
30  * IN NO EVENT SHALL TOOLS GMBH BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
31  * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
32  * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
33  * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
34  * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
35  * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
36  * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
37  */
38 
39 /*
40  * First try for the boot code
41  *
42  * Input syntax is:
43  *	[promdev[{:|,}partition]]/[filename] [flags]
44  */
45 
46 #define ELFSIZE 64
47 
48 #include <lib/libsa/stand.h>
49 #include <lib/libkern/funcs.h>
50 
51 #include <sys/param.h>
52 #include <sys/exec.h>
53 #include <sys/exec_elf.h>
54 #include <sys/reboot.h>
55 #include <sys/disklabel.h>
56 
57 #include <machine/cpu.h>
58 #include <lib/libsa/arc4.h>
59 
60 #ifdef SOFTRAID
61 #include <sys/param.h>
62 #include <sys/queue.h>
63 #include <dev/biovar.h>
64 #include <dev/softraidvar.h>
65 #include <lib/libsa/softraid.h>
66 
67 #include "disk.h"
68 #include "softraid_sparc64.h"
69 #endif
70 
71 #include "ofdev.h"
72 #include "openfirm.h"
73 
74 #ifdef BOOT_DEBUG
75 uint32_t	boot_debug = 0
76 		    /* | BOOT_D_OFDEV */
77 		    /* | BOOT_D_OFNET */
78 		;
79 #endif
80 
81 #define	MEG	(1024*1024)
82 
83 /*
84  * Boot device is derived from ROM provided information, or if there is none,
85  * this list is used in sequence, to find a kernel.
86  */
87 char *kernels[] = {
88 	"bsd",
89 	NULL
90 };
91 
92 char bootdev[128];
93 extern char bootfile[128];
94 int boothowto;
95 int debug;
96 
97 char rnddata[BOOTRANDOM_MAX];
98 struct rc4_ctx randomctx;
99 
100 int	elf64_exec(int, Elf64_Ehdr *, u_int64_t *, void **, void **);
101 
102 /*
103  *	parse:
104  *		[kernel-name] [-options]
105  *	leave kernel-name in passed-in string
106  *	put options into *howtop
107  *	return -1 iff syntax error (no - before options)
108  */
109 
110 static int
111 parseargs(char *str, int *howtop)
112 {
113 	char *cp;
114 	int i;
115 
116 	*howtop = 0;
117 	cp = str;
118 	while (*cp == ' ')
119 		++cp;
120 	if (*cp != '-') {
121 		while (*cp && *cp != ' ')
122 			*str++ = *cp++;
123 		while (*cp == ' ')
124 			++cp;
125 	}
126 	/*
127 	 * Note that, if only options have been passed, without a kernel
128 	 * name, str == cp and options will be ignored at the boot blocks
129 	 * level.
130 	 * This a feature intended to make `boot -a' behave as intended.
131 	 * If you want the bootblocks to handle arguments explicitly, a
132 	 * kernel filename needs to be provided (as in `boot bsd -a').
133 	 */
134 	*str = 0;
135 	switch (*cp) {
136 	default:
137 		printf("boot options string <%s> must start with -\n", cp);
138 		return -1;
139 	case 0:
140 		return 0;
141 	case '-':
142 		break;
143 	}
144 
145 	++cp;
146 	while (*cp) {
147 		switch (*cp++) {
148 		case 'a':
149 			*howtop |= RB_ASKNAME;
150 			break;
151 		case 'd':
152 			if (!debug) debug = 1;
153 			break;
154 		case 'D':
155 			debug = 2;
156 			break;
157 		}
158 	}
159 	return 0;
160 }
161 
162 
163 static void
164 chain(u_int64_t pentry, char *args, void *ssym, void *esym)
165 {
166 	extern char end[];
167 	void (*entry)();
168 	int l, machine_tag;
169 	long newargs[3];
170 
171 	entry = (void *)(long)pentry;
172 
173 	/*
174 	 * When we come in args consists of a pointer to the boot
175 	 * string.  We need to fix it so it takes into account
176 	 * other params such as romp.
177 	 */
178 
179 	/*
180 	 * Stash pointer to end of symbol table after the argument
181 	 * strings.
182 	 */
183 	l = strlen(args) + 1;
184 	bcopy(&esym, args + l, sizeof(esym));
185 	l += sizeof(esym);
186 
187 	/*
188 	 * Tell the kernel we're an OpenFirmware system.
189 	 */
190 #define SPARC_MACHINE_OPENFIRMWARE		0x44444230
191 	machine_tag = SPARC_MACHINE_OPENFIRMWARE;
192 	bcopy(&machine_tag, args + l, sizeof(machine_tag));
193 	l += sizeof(machine_tag);
194 
195 	/*
196 	 * Since we don't need the boot string (we can get it from /chosen)
197 	 * we won't pass it in.  Just pass in esym and magic #
198 	 */
199 	newargs[0] = SPARC_MACHINE_OPENFIRMWARE;
200 	newargs[1] = (long)esym;
201 	newargs[2] = (long)ssym;
202 	args = (char *)newargs;
203 	l = sizeof(newargs);
204 
205 #ifdef DEBUG
206 	printf("chain: calling OF_chain(%x, %x, %x, %x, %x)\n",
207 	    (void *)RELOC, end - (char *)RELOC, entry, args, l);
208 #endif
209 	/* if -D is set then pause in the PROM. */
210 	if (debug > 1) OF_enter();
211 	OF_chain((void *)RELOC, ((end - (char *)RELOC)+PAGE_SIZE)%PAGE_SIZE,
212 	    entry, args, l);
213 	panic("chain");
214 }
215 
216 int
217 loadfile(int fd, char *args)
218 {
219 	union {
220 		Elf64_Ehdr elf64;
221 	} hdr;
222 	int rval;
223 	u_int64_t entry = 0;
224 	void *ssym;
225 	void *esym;
226 
227 	ssym = NULL;
228 	esym = NULL;
229 
230 	/* Load the header. */
231 #ifdef DEBUG
232 	printf("loadfile: reading header\n");
233 #endif
234 	if ((rval = read(fd, &hdr, sizeof(hdr))) != sizeof(hdr)) {
235 		if (rval == -1)
236 			printf("read header: %s\n", strerror(errno));
237 		else
238 			printf("read header: short read (only %d of %d)\n",
239 			    rval, sizeof(hdr));
240 		rval = 1;
241 		goto err;
242 	}
243 
244 	/* Determine file type, load kernel. */
245 	if (bcmp(hdr.elf64.e_ident, ELFMAG, SELFMAG) == 0 &&
246 	    hdr.elf64.e_ident[EI_CLASS] == ELFCLASS64) {
247 		printf("Booting %s\n", opened_name);
248 		rval = elf64_exec(fd, &hdr.elf64, &entry, &ssym, &esym);
249 	} else {
250 		rval = 1;
251 		printf("unknown executable format\n");
252 	}
253 
254 	if (rval)
255 		goto err;
256 
257 	printf(" start=0x%lx\n", (unsigned long)entry);
258 
259 	close(fd);
260 
261 #ifdef SOFTRAID
262 	if (bootdev_dip)
263 		OF_close(bootdev_dip->sr_handle);
264 	sr_clear_keys();
265 #endif
266 	chain(entry, args, ssym, esym);
267 	/* NOTREACHED */
268 
269  err:
270 	close(fd);
271 	return (rval);
272 }
273 
274 static int
275 upgrade(void)
276 {
277 	struct stat sb;
278 
279 	if (stat("/bsd.upgrade", &sb) < 0)
280 		return 0;
281 	return 1;
282 }
283 
284 int
285 loadrandom(char *path, char *buf, size_t buflen)
286 {
287 	struct stat sb;
288 	int fd, i, error = 0;
289 
290 	fd = open(path, O_RDONLY);
291 	if (fd == -1)
292 		return -1;
293 	if (fstat(fd, &sb) == -1) {
294 		error = -1;
295 		goto done;
296 	}
297 	if (read(fd, buf, buflen) != buflen) {
298 		error = -1;
299 		goto done;
300 	}
301 	if (sb.st_mode & S_ISTXT) {
302 		printf("NOTE: random seed is being reused.\n");
303 		error = -1;
304 		goto done;
305 	}
306 	fchmod(fd, sb.st_mode | S_ISTXT);
307 done:
308 	close(fd);
309 	return (error);
310 }
311 
312 #ifdef SOFTRAID
313 /* Set bootdev_dip to the softraid boot volume, if specified. */
314 static int
315 srbootdev(const char *bootline)
316 {
317 	struct sr_boot_volume *bv;
318 	int unit;
319 
320 	bootdev_dip = NULL;
321 
322 	/*
323 	 * Look for softraid disks in bootline.
324 	 * E.g. 'sr0', 'sr0:bsd', or 'sr0a:/bsd'
325 	 */
326 	if (bootline[0] == 's' && bootline[1] == 'r' &&
327 	    '0' <= bootline[2] && bootline[2] <= '9') {
328 		unit = bootline[2] - '0';
329 
330 		/* Create a fake diskinfo for this softraid volume. */
331 		SLIST_FOREACH(bv, &sr_volumes, sbv_link)
332 			if (bv->sbv_unit == unit)
333 				break;
334 		if (bv == NULL) {
335 			printf("Unknown device: sr%d\n", unit);
336 			return ENODEV;
337 		}
338 
339 		if ((bv->sbv_flags & BIOC_SCBOOTABLE) == 0) {
340 			printf("device sr%d is not bootable\n", unit);
341 			return ENODEV;
342 		}
343 
344 		if (bv->sbv_level == 'C' && bv->sbv_keys == NULL)
345 			if (sr_crypto_unlock_volume(bv) != 0)
346 				return EPERM;
347 
348 		if (bv->sbv_diskinfo == NULL) {
349 			struct sr_boot_chunk *bc;
350 			struct diskinfo *dip, *bc_dip;
351 			int sr_handle;
352 
353 			/* All reads will come from the boot chunk. */
354 			bc = sr_vol_boot_chunk(bv);
355 			if (bc == NULL)
356 				return ENXIO;
357 			bc_dip = (struct diskinfo *)bc->sbc_diskinfo;
358 			sr_handle = OF_open(bc_dip->path);
359 			if (sr_handle == -1)
360 				return EIO;
361 
362 			dip = alloc(sizeof(struct diskinfo));
363 			bzero(dip, sizeof(*dip));
364 			dip->sr_vol = bv;
365 			dip->sr_handle = sr_handle;
366 			bv->sbv_diskinfo = dip;
367 		}
368 
369 		/* strategy() and devopen() will use bootdev_dip */
370 		bootdev_dip = bv->sbv_diskinfo;
371 
372 		/* Attempt to read disklabel. */
373 		bv->sbv_part = 'c';
374 		if (sr_getdisklabel(bv, &bootdev_dip->disklabel)) {
375 			OF_close(bootdev_dip->sr_handle);
376 			free(bv->sbv_diskinfo, sizeof(struct diskinfo));
377 			bv->sbv_diskinfo = NULL;
378 			bootdev_dip = NULL;
379 			return ERDLAB;
380 		}
381 	}
382 
383 	return 0;
384 }
385 #endif
386 
387 int
388 main(void)
389 {
390 	extern char version[];
391 	int chosen;
392 	char bootline[512];		/* Should check size? */
393 	char *cp;
394 	int i, fd;
395 #ifdef SOFTRAID
396 	int err;
397 #endif
398 	char **bootlp;
399 	char *just_bootline[2];
400 
401 	printf(">> OpenBSD BOOT %s\n", version);
402 
403 	/*
404 	 * Get the boot arguments from Openfirmware
405 	 */
406 	if ((chosen = OF_finddevice("/chosen")) == -1 ||
407 	    OF_getprop(chosen, "bootpath", bootdev, sizeof bootdev) < 0 ||
408 	    OF_getprop(chosen, "bootargs", bootline, sizeof bootline) < 0) {
409 		printf("Invalid Openfirmware environment\n");
410 		exit();
411 	}
412 
413 #ifdef SOFTRAID
414 	diskprobe();
415 	srprobe();
416 	err = srbootdev(bootline);
417 	if (err) {
418 		printf("Cannot boot from softraid: %s\n", strerror(err));
419 		_rtt();
420 	}
421 #endif
422 
423 	/*
424 	 * case 1:	boot net -a
425 	 *			-> getln loop
426 	 * case 2:	boot net kernel [options]
427 	 *			-> boot kernel, getln loop
428 	 * case 3:	boot net [options]
429 	 *			-> iterate boot list, getln loop
430 	 */
431 
432 	bootlp = kernels;
433 	if (parseargs(bootline, &boothowto) == -1 ||
434 	    (boothowto & RB_ASKNAME)) {
435 		bootlp = 0;
436 	} else if (*bootline) {
437 		just_bootline[0] = bootline;
438 		just_bootline[1] = 0;
439 		bootlp = just_bootline;
440 	}
441 	if (bootlp == kernels && upgrade()) {
442 		just_bootline[0] = "/bsd.upgrade";
443 		just_bootline[1] = 0;
444 		bootlp = just_bootline;
445 		printf("upgrade detected: switching to %s\n", *bootlp);
446 	}
447 	for (;;) {
448 		if (bootlp) {
449 			cp = *bootlp++;
450 			if (!cp) {
451 				printf("\n");
452 				bootlp = 0;
453 				kernels[0] = 0;	/* no more iteration */
454 			} else if (cp != bootline) {
455 				printf("Trying %s...\n", cp);
456 				if (strlcpy(bootline, cp, sizeof bootline)
457 				    >= sizeof bootline) {
458 					printf("bootargs too long: %s\n",
459 					    bootline);
460 					_rtt();
461 				}
462 			}
463 		}
464 		if (!bootlp) {
465 			printf("Boot: ");
466 			getln(bootline, sizeof bootline);
467 			if (parseargs(bootline, &boothowto) == -1)
468 				continue;
469 			if (!*bootline) {
470 				bootlp = kernels;
471 				continue;
472 			}
473 			if (strcmp(bootline, "exit") == 0 ||
474 			    strcmp(bootline, "halt") == 0) {
475 				_rtt();
476 			}
477 		}
478 		if (loadrandom(BOOTRANDOM, rnddata, sizeof(rnddata)) == 0)
479 			boothowto |= RB_GOODRANDOM;
480 
481 		rc4_keysetup(&randomctx, rnddata, sizeof rnddata);
482 		rc4_skip(&randomctx, 1536);
483 
484 		if ((fd = open(bootline, O_RDONLY)) < 0) {
485 			printf("open %s: %s\n", opened_name, strerror(errno));
486 			continue;
487 		}
488 		/* XXX void, for now */
489 #ifdef DEBUG
490 		if (debug)
491 			printf("main: Calling loadfile(fd, %s)\n", opened_name);
492 #endif
493 		(void)loadfile(fd, opened_name);
494 	}
495 	return 0;
496 }
497