boot1.c revision 294721
11590Srgrimes/*-
21590Srgrimes * Copyright (c) 1998 Robert Nordier
31590Srgrimes * All rights reserved.
499821Sjoerg * Copyright (c) 2001 Robert Drehmel
599821Sjoerg * All rights reserved.
61590Srgrimes *
71590Srgrimes * Redistribution and use in source and binary forms are freely
81590Srgrimes * permitted provided that the above copyright notice and this
91590Srgrimes * paragraph and the following disclaimer are duplicated in all
101590Srgrimes * such forms.
111590Srgrimes *
121590Srgrimes * This software is provided "AS IS" and without any express or
131590Srgrimes * implied warranties, including, without limitation, the implied
141590Srgrimes * warranties of merchantability and fitness for a particular
151590Srgrimes * purpose.
161590Srgrimes */
171590Srgrimes
181590Srgrimes#include <sys/cdefs.h>
191590Srgrimes__FBSDID("$FreeBSD: stable/10/sys/boot/powerpc/boot1.chrp/boot1.c 294721 2016-01-25 10:55:52Z smh $");
201590Srgrimes
211590Srgrimes#include <sys/param.h>
221590Srgrimes#include <sys/dirent.h>
231590Srgrimes#include <machine/elf.h>
241590Srgrimes#include <machine/stdarg.h>
251590Srgrimes
261590Srgrimes#define _PATH_LOADER	"/boot/loader"
271590Srgrimes#define _PATH_KERNEL	"/boot/kernel/kernel"
281590Srgrimes
291590Srgrimes#define BSIZEMAX	16384
301590Srgrimes
311590Srgrimestypedef int putc_func_t(char c, void *arg);
321590Srgrimestypedef int32_t ofwh_t;
331590Srgrimes
3499821Sjoergstruct sp_data {
351590Srgrimes	char	*sp_buf;
3699821Sjoerg	u_int	sp_len;
3799821Sjoerg	u_int	sp_size;
38102247Sjohan};
391590Srgrimes
4079535Srustatic const char digits[] = "0123456789abcdef";
411590Srgrimes
421590Srgrimesstatic char bootpath[128];
431590Srgrimesstatic char bootargs[128];
441590Srgrimes
4568963Srustatic ofwh_t bootdev;
46102246Sjohan
47107276Srustatic struct fs fs;
4899377Sjohanstatic char blkbuf[BSIZEMAX];
491590Srgrimesstatic unsigned int fsblks;
501590Srgrimes
5168963Srustatic uint32_t fs_off;
5299821Sjoerg
5399821Sjoergint main(int ac, char **av);
54131491Sru
55131491Srustatic void exit(int) __dead2;
5699821Sjoergstatic void load(const char *);
5799821Sjoergstatic int dskread(void *, u_int64_t, int);
5899821Sjoerg
5999821Sjoergstatic void usage(void);
6099821Sjoerg
6199821Sjoergstatic void bcopy(const void *src, void *dst, size_t len);
6299821Sjoergstatic void bzero(void *b, size_t len);
6399821Sjoerg
6499821Sjoergstatic int domount(const char *device, int quiet);
6599821Sjoerg
661590Srgrimesstatic void panic(const char *fmt, ...) __dead2;
6716385Sjoergstatic int printf(const char *fmt, ...);
681590Srgrimesstatic int putchar(char c, void *arg);
691590Srgrimesstatic int vprintf(const char *fmt, va_list ap);
701590Srgrimesstatic int vsnprintf(char *str, size_t sz, const char *fmt, va_list ap);
7199821Sjoerg
72100608Sjohanstatic int __printf(const char *fmt, putc_func_t *putc, void *arg, va_list ap);
73107276Srustatic int __putc(char c, void *arg);
7499821Sjoergstatic int __puts(const char *s, putc_func_t *putc, void *arg);
7599821Sjoergstatic int __sputc(char c, void *arg);
76131491Srustatic char *__uitoa(char *buf, u_int val, int base);
77131491Srustatic char *__ultoa(char *buf, u_long val, int base);
7899821Sjoerg
7999821Sjoergvoid __syncicache(void *, int);
8099821Sjoerg
8199821Sjoerg/*
8299821Sjoerg * Open Firmware interface functions
8399821Sjoerg */
8499821Sjoergtypedef u_int32_t	ofwcell_t;
8599821Sjoergtypedef u_int32_t	u_ofwh_t;
8699821Sjoergtypedef int (*ofwfp_t)(void *);
8799821Sjoergofwfp_t ofw;			/* the prom Open Firmware entry */
88131491Sruofwh_t chosenh;
89131491Sru
9099821Sjoergvoid ofw_init(void *, int, int (*)(void *), char *, int);
9199821Sjoergstatic ofwh_t ofw_finddevice(const char *);
9299821Sjoergstatic ofwh_t ofw_open(const char *);
93131491Srustatic int ofw_close(ofwh_t);
94131491Srustatic int ofw_getprop(ofwh_t, const char *, void *, size_t);
9599821Sjoergstatic int ofw_setprop(ofwh_t, const char *, void *, size_t);
9699821Sjoergstatic int ofw_read(ofwh_t, void *, size_t);
9799821Sjoergstatic int ofw_write(ofwh_t, const void *, size_t);
98131491Srustatic int ofw_claim(void *virt, size_t len, u_int align);
99131491Srustatic int ofw_seek(ofwh_t, u_int64_t);
10099821Sjoergstatic void ofw_exit(void) __dead2;
10199821Sjoerg
102102246Sjohanofwh_t bootdevh;
103102246Sjohanofwh_t stdinh, stdouth;
10499821Sjoerg
10599821Sjoerg__asm("                         \n\
10699821Sjoerg        .data                   \n\
10799821Sjoerg	.align 4		\n\
10899821Sjoergstack:                          \n\
10999821Sjoerg        .space  16384           \n\
11099821Sjoerg                                \n\
11199821Sjoerg        .text                   \n\
11299821Sjoerg        .globl  _start          \n\
11399821Sjoerg_start:                         \n\
11499821Sjoerg        lis     %r1,stack@ha    \n\
11599821Sjoerg        addi    %r1,%r1,stack@l \n\
11699821Sjoerg        addi    %r1,%r1,8192    \n\
11799821Sjoerg                                \n\
11899821Sjoerg        b       ofw_init        \n\
11999821Sjoerg");
12099821Sjoerg
12199821Sjoergvoid
12299821Sjoergofw_init(void *vpd, int res, int (*openfirm)(void *), char *arg, int argl)
12399821Sjoerg{
12499821Sjoerg	char *av[16];
12599821Sjoerg	char *p;
12699821Sjoerg	int ac;
12799821Sjoerg
12899821Sjoerg	ofw = openfirm;
129131491Sru
130131491Sru	chosenh = ofw_finddevice("/chosen");
131102246Sjohan	ofw_getprop(chosenh, "stdin", &stdinh, sizeof(stdinh));
13299821Sjoerg	ofw_getprop(chosenh, "stdout", &stdouth, sizeof(stdouth));
13399821Sjoerg	ofw_getprop(chosenh, "bootargs", bootargs, sizeof(bootargs));
13499821Sjoerg	ofw_getprop(chosenh, "bootpath", bootpath, sizeof(bootpath));
13599821Sjoerg
13699821Sjoerg	bootargs[sizeof(bootargs) - 1] = '\0';
13799821Sjoerg	bootpath[sizeof(bootpath) - 1] = '\0';
13899821Sjoerg
13999821Sjoerg	p = bootpath;
14099821Sjoerg	while (*p != '\0') {
14199821Sjoerg		if (*p == ':') {
14299821Sjoerg			*(++p) = '\0';
14399821Sjoerg			break;
14499821Sjoerg		}
14599821Sjoerg		p++;
14699821Sjoerg	}
14799821Sjoerg
14899821Sjoerg	ac = 0;
14999821Sjoerg	p = bootargs;
15099821Sjoerg	for (;;) {
15199821Sjoerg		while (*p == ' ' && *p != '\0')
15299821Sjoerg			p++;
15399821Sjoerg		if (*p == '\0' || ac >= 16)
15499821Sjoerg			break;
15599821Sjoerg		av[ac++] = p;
15699821Sjoerg		while (*p != ' ' && *p != '\0')
1571590Srgrimes			p++;
15899821Sjoerg		if (*p != '\0')
15999821Sjoerg			*p++ = '\0';
16099821Sjoerg	}
16136057Sjkoshy
16216385Sjoerg	exit(main(ac, av));
1631590Srgrimes}
1641590Srgrimes
16568963Srustatic ofwh_t
16699970Scharnierofw_finddevice(const char *name)
16716385Sjoerg{
16899821Sjoerg	ofwcell_t args[] = {
16999821Sjoerg		(ofwcell_t)"finddevice",
17099821Sjoerg		1,
17199821Sjoerg		1,
17299821Sjoerg		(ofwcell_t)name,
17399821Sjoerg		0
17499821Sjoerg	};
17599821Sjoerg
17699821Sjoerg	if ((*ofw)(args)) {
17799821Sjoerg		printf("ofw_finddevice: name=\"%s\"\n", name);
17899821Sjoerg		return (1);
17999821Sjoerg	}
18099821Sjoerg	return (args[4]);
18199821Sjoerg}
18299821Sjoerg
18399821Sjoergstatic int
18499821Sjoergofw_getprop(ofwh_t ofwh, const char *name, void *buf, size_t len)
185102246Sjohan{
186102246Sjohan	ofwcell_t args[] = {
187102246Sjohan		(ofwcell_t)"getprop",
188102246Sjohan		4,
189102246Sjohan		1,
190102246Sjohan		(u_ofwh_t)ofwh,
191		(ofwcell_t)name,
192		(ofwcell_t)buf,
193		len,
194	0
195	};
196
197	if ((*ofw)(args)) {
198		printf("ofw_getprop: ofwh=0x%x buf=%p len=%u\n",
199			ofwh, buf, len);
200		return (1);
201	}
202	return (0);
203}
204
205static int
206ofw_setprop(ofwh_t ofwh, const char *name, void *buf, size_t len)
207{
208	ofwcell_t args[] = {
209		(ofwcell_t)"setprop",
210		4,
211		1,
212		(u_ofwh_t)ofwh,
213		(ofwcell_t)name,
214		(ofwcell_t)buf,
215		len,
216	0
217	};
218
219	if ((*ofw)(args)) {
220		printf("ofw_setprop: ofwh=0x%x buf=%p len=%u\n",
221			ofwh, buf, len);
222		return (1);
223	}
224	return (0);
225}
226
227static ofwh_t
228ofw_open(const char *path)
229{
230	ofwcell_t args[] = {
231		(ofwcell_t)"open",
232		1,
233		1,
234		(ofwcell_t)path,
235		0
236	};
237
238	if ((*ofw)(args)) {
239		printf("ofw_open: path=\"%s\"\n", path);
240		return (-1);
241	}
242	return (args[4]);
243}
244
245static int
246ofw_close(ofwh_t devh)
247{
248	ofwcell_t args[] = {
249		(ofwcell_t)"close",
250		1,
251		0,
252		(u_ofwh_t)devh
253	};
254
255	if ((*ofw)(args)) {
256		printf("ofw_close: devh=0x%x\n", devh);
257		return (1);
258	}
259	return (0);
260}
261
262static int
263ofw_claim(void *virt, size_t len, u_int align)
264{
265	ofwcell_t args[] = {
266		(ofwcell_t)"claim",
267		3,
268		1,
269		(ofwcell_t)virt,
270		len,
271		align,
272		0,
273		0
274	};
275
276	if ((*ofw)(args)) {
277		printf("ofw_claim: virt=%p len=%u\n", virt, len);
278		return (1);
279	}
280
281	return (0);
282}
283
284static int
285ofw_read(ofwh_t devh, void *buf, size_t len)
286{
287	ofwcell_t args[] = {
288		(ofwcell_t)"read",
289		3,
290		1,
291		(u_ofwh_t)devh,
292		(ofwcell_t)buf,
293		len,
294		0
295	};
296
297	if ((*ofw)(args)) {
298		printf("ofw_read: devh=0x%x buf=%p len=%u\n", devh, buf, len);
299		return (1);
300	}
301	return (0);
302}
303
304static int
305ofw_write(ofwh_t devh, const void *buf, size_t len)
306{
307	ofwcell_t args[] = {
308		(ofwcell_t)"write",
309		3,
310		1,
311		(u_ofwh_t)devh,
312		(ofwcell_t)buf,
313		len,
314		0
315	};
316
317	if ((*ofw)(args)) {
318		printf("ofw_write: devh=0x%x buf=%p len=%u\n", devh, buf, len);
319		return (1);
320	}
321	return (0);
322}
323
324static int
325ofw_seek(ofwh_t devh, u_int64_t off)
326{
327	ofwcell_t args[] = {
328		(ofwcell_t)"seek",
329		3,
330		1,
331		(u_ofwh_t)devh,
332		off >> 32,
333		off,
334		0
335	};
336
337	if ((*ofw)(args)) {
338		printf("ofw_seek: devh=0x%x off=0x%lx\n", devh, off);
339		return (1);
340	}
341	return (0);
342}
343
344static void
345ofw_exit(void)
346{
347	ofwcell_t args[3];
348
349	args[0] = (ofwcell_t)"exit";
350	args[1] = 0;
351	args[2] = 0;
352
353	for (;;)
354		(*ofw)(args);
355}
356
357static void
358bcopy(const void *src, void *dst, size_t len)
359{
360	const char *s = src;
361	char *d = dst;
362
363	while (len-- != 0)
364		*d++ = *s++;
365}
366
367static void
368memcpy(void *dst, const void *src, size_t len)
369{
370	bcopy(src, dst, len);
371}
372
373static void
374bzero(void *b, size_t len)
375{
376	char *p = b;
377
378	while (len-- != 0)
379		*p++ = 0;
380}
381
382static int
383strcmp(const char *s1, const char *s2)
384{
385	for (; *s1 == *s2 && *s1; s1++, s2++)
386		;
387	return ((u_char)*s1 - (u_char)*s2);
388}
389
390#include "ufsread.c"
391
392int
393main(int ac, char **av)
394{
395	const char *path;
396	char bootpath_full[255];
397	int i, len;
398
399	path = _PATH_LOADER;
400	for (i = 0; i < ac; i++) {
401		switch (av[i][0]) {
402		case '-':
403			switch (av[i][1]) {
404			default:
405				usage();
406			}
407			break;
408		default:
409			path = av[i];
410			break;
411		}
412	}
413
414	printf(" \n>> FreeBSD/powerpc Open Firmware boot block\n"
415	"   Boot path:   %s\n"
416	"   Boot loader: %s\n", bootpath, path);
417
418	len = 0;
419	while (bootpath[len] != '\0') len++;
420
421	memcpy(bootpath_full,bootpath,len+1);
422
423	if (bootpath_full[len-1] == ':') {
424		for (i = 0; i < 16; i++) {
425			if (i < 10) {
426				bootpath_full[len] = i + '0';
427				bootpath_full[len+1] = '\0';
428			} else {
429				bootpath_full[len] = '1';
430				bootpath_full[len+1] = i - 10 + '0';
431				bootpath_full[len+2] = '\0';
432			}
433
434			if (domount(bootpath_full,1) >= 0)
435				break;
436
437			if (bootdev > 0)
438				ofw_close(bootdev);
439		}
440
441		if (i >= 16)
442			panic("domount");
443	} else {
444		if (domount(bootpath_full,0) == -1)
445			panic("domount");
446	}
447
448	printf("   Boot volume:   %s\n",bootpath_full);
449	ofw_setprop(chosenh, "bootargs", bootpath_full, len+2);
450	load(path);
451	return (1);
452}
453
454static void
455usage(void)
456{
457
458	printf("usage: boot device [/path/to/loader]\n");
459	exit(1);
460}
461
462static void
463exit(int code)
464{
465
466	ofw_exit();
467}
468
469static struct dmadat __dmadat;
470
471static int
472domount(const char *device, int quiet)
473{
474
475	dmadat = &__dmadat;
476	if ((bootdev = ofw_open(device)) == -1) {
477		printf("domount: can't open device\n");
478		return (-1);
479	}
480	if (fsread(0, NULL, 0)) {
481		if (!quiet)
482			printf("domount: can't read superblock\n");
483		return (-1);
484	}
485	return (0);
486}
487
488static void
489load(const char *fname)
490{
491	Elf32_Ehdr eh;
492	Elf32_Phdr ph;
493	caddr_t p;
494	ufs_ino_t ino;
495	int i;
496
497	if ((ino = lookup(fname)) == 0) {
498		printf("File %s not found\n", fname);
499		return;
500	}
501	if (fsread(ino, &eh, sizeof(eh)) != sizeof(eh)) {
502		printf("Can't read elf header\n");
503		return;
504	}
505	if (!IS_ELF(eh)) {
506		printf("Not an ELF file\n");
507		return;
508	}
509	for (i = 0; i < eh.e_phnum; i++) {
510		fs_off = eh.e_phoff + i * eh.e_phentsize;
511		if (fsread(ino, &ph, sizeof(ph)) != sizeof(ph)) {
512			printf("Can't read program header %d\n", i);
513			return;
514		}
515		if (ph.p_type != PT_LOAD)
516			continue;
517		fs_off = ph.p_offset;
518		p = (caddr_t)ph.p_vaddr;
519		ofw_claim(p,(ph.p_filesz > ph.p_memsz) ?
520		    ph.p_filesz : ph.p_memsz,0);
521		if (fsread(ino, p, ph.p_filesz) != ph.p_filesz) {
522			printf("Can't read content of section %d\n", i);
523			return;
524		}
525		if (ph.p_filesz != ph.p_memsz)
526			bzero(p + ph.p_filesz, ph.p_memsz - ph.p_filesz);
527		__syncicache(p, ph.p_memsz);
528	}
529	ofw_close(bootdev);
530	(*(void (*)(void *, int, ofwfp_t, char *, int))eh.e_entry)(NULL, 0,
531	    ofw,NULL,0);
532}
533
534static int
535dskread(void *buf, u_int64_t lba, int nblk)
536{
537	/*
538	 * The Open Firmware should open the correct partition for us.
539	 * That means, if we read from offset zero on an open instance handle,
540	 * we should read from offset zero of that partition.
541	 */
542	ofw_seek(bootdev, lba * DEV_BSIZE);
543	ofw_read(bootdev, buf, nblk * DEV_BSIZE);
544	return (0);
545}
546
547static void
548panic(const char *fmt, ...)
549{
550	char buf[128];
551	va_list ap;
552
553	va_start(ap, fmt);
554	vsnprintf(buf, sizeof buf, fmt, ap);
555	printf("panic: %s\n", buf);
556	va_end(ap);
557
558	exit(1);
559}
560
561static int
562printf(const char *fmt, ...)
563{
564	va_list ap;
565	int ret;
566
567	va_start(ap, fmt);
568	ret = vprintf(fmt, ap);
569	va_end(ap);
570	return (ret);
571}
572
573static int
574putchar(char c, void *arg)
575{
576	char buf;
577
578	if (c == '\n') {
579		buf = '\r';
580		ofw_write(stdouth, &buf, 1);
581	}
582	buf = c;
583	ofw_write(stdouth, &buf, 1);
584	return (1);
585}
586
587static int
588vprintf(const char *fmt, va_list ap)
589{
590	int ret;
591
592	ret = __printf(fmt, putchar, 0, ap);
593	return (ret);
594}
595
596static int
597vsnprintf(char *str, size_t sz, const char *fmt, va_list ap)
598{
599	struct sp_data sp;
600	int ret;
601
602	sp.sp_buf = str;
603	sp.sp_len = 0;
604	sp.sp_size = sz;
605	ret = __printf(fmt, __sputc, &sp, ap);
606	return (ret);
607}
608
609static int
610__printf(const char *fmt, putc_func_t *putc, void *arg, va_list ap)
611{
612	char buf[(sizeof(long) * 8) + 1];
613	char *nbuf;
614	u_long ul;
615	u_int ui;
616	int lflag;
617	int sflag;
618	char *s;
619	int pad;
620	int ret;
621	int c;
622
623	nbuf = &buf[sizeof buf - 1];
624	ret = 0;
625	while ((c = *fmt++) != 0) {
626		if (c != '%') {
627			ret += putc(c, arg);
628			continue;
629		}
630		lflag = 0;
631		sflag = 0;
632		pad = 0;
633reswitch:	c = *fmt++;
634		switch (c) {
635		case '#':
636			sflag = 1;
637			goto reswitch;
638		case '%':
639			ret += putc('%', arg);
640			break;
641		case 'c':
642			c = va_arg(ap, int);
643			ret += putc(c, arg);
644			break;
645		case 'd':
646			if (lflag == 0) {
647				ui = (u_int)va_arg(ap, int);
648				if (ui < (int)ui) {
649					ui = -ui;
650					ret += putc('-', arg);
651				}
652				s = __uitoa(nbuf, ui, 10);
653			} else {
654				ul = (u_long)va_arg(ap, long);
655				if (ul < (long)ul) {
656					ul = -ul;
657					ret += putc('-', arg);
658				}
659				s = __ultoa(nbuf, ul, 10);
660			}
661			ret += __puts(s, putc, arg);
662			break;
663		case 'l':
664			lflag = 1;
665			goto reswitch;
666		case 'o':
667			if (lflag == 0) {
668				ui = (u_int)va_arg(ap, u_int);
669				s = __uitoa(nbuf, ui, 8);
670			} else {
671				ul = (u_long)va_arg(ap, u_long);
672				s = __ultoa(nbuf, ul, 8);
673			}
674			ret += __puts(s, putc, arg);
675			break;
676		case 'p':
677			ul = (u_long)va_arg(ap, void *);
678			s = __ultoa(nbuf, ul, 16);
679			ret += __puts("0x", putc, arg);
680			ret += __puts(s, putc, arg);
681			break;
682		case 's':
683			s = va_arg(ap, char *);
684			ret += __puts(s, putc, arg);
685			break;
686		case 'u':
687			if (lflag == 0) {
688				ui = va_arg(ap, u_int);
689				s = __uitoa(nbuf, ui, 10);
690			} else {
691				ul = va_arg(ap, u_long);
692				s = __ultoa(nbuf, ul, 10);
693			}
694			ret += __puts(s, putc, arg);
695			break;
696		case 'x':
697			if (lflag == 0) {
698				ui = va_arg(ap, u_int);
699				s = __uitoa(nbuf, ui, 16);
700			} else {
701				ul = va_arg(ap, u_long);
702				s = __ultoa(nbuf, ul, 16);
703			}
704			if (sflag)
705				ret += __puts("0x", putc, arg);
706			ret += __puts(s, putc, arg);
707			break;
708		case '0': case '1': case '2': case '3': case '4':
709		case '5': case '6': case '7': case '8': case '9':
710			pad = pad * 10 + c - '0';
711			goto reswitch;
712		default:
713			break;
714		}
715	}
716	return (ret);
717}
718
719static int
720__sputc(char c, void *arg)
721{
722	struct sp_data *sp;
723
724	sp = arg;
725	if (sp->sp_len < sp->sp_size)
726		sp->sp_buf[sp->sp_len++] = c;
727	sp->sp_buf[sp->sp_len] = '\0';
728	return (1);
729}
730
731static int
732__puts(const char *s, putc_func_t *putc, void *arg)
733{
734	const char *p;
735	int ret;
736
737	ret = 0;
738	for (p = s; *p != '\0'; p++)
739		ret += putc(*p, arg);
740	return (ret);
741}
742
743static char *
744__uitoa(char *buf, u_int ui, int base)
745{
746	char *p;
747
748	p = buf;
749	*p = '\0';
750	do
751		*--p = digits[ui % base];
752	while ((ui /= base) != 0);
753	return (p);
754}
755
756static char *
757__ultoa(char *buf, u_long ul, int base)
758{
759	char *p;
760
761	p = buf;
762	*p = '\0';
763	do
764		*--p = digits[ul % base];
765	while ((ul /= base) != 0);
766	return (p);
767}
768