]> CyberLeo.Net >> Repos - FreeBSD/releng/10.0.git/blob - sys/boot/sparc64/boot1/boot1.c
- Copy stable/10 (r259064) to releng/10.0 as part of the
[FreeBSD/releng/10.0.git] / sys / boot / sparc64 / boot1 / boot1.c
1 /*-
2  * Copyright (c) 1998 Robert Nordier
3  * All rights reserved.
4  * Copyright (c) 2001 Robert Drehmel
5  * All rights reserved.
6  *
7  * Redistribution and use in source and binary forms are freely
8  * permitted provided that the above copyright notice and this
9  * paragraph and the following disclaimer are duplicated in all
10  * such forms.
11  *
12  * This software is provided "AS IS" and without any express or
13  * implied warranties, including, without limitation, the implied
14  * warranties of merchantability and fitness for a particular
15  * purpose.
16  */
17
18 #include <sys/cdefs.h>
19 __FBSDID("$FreeBSD$");
20
21 #include <sys/param.h>
22 #include <sys/dirent.h>
23
24 #include <machine/elf.h>
25 #include <machine/stdarg.h>
26
27 #define _PATH_LOADER    "/boot/loader"
28 #define _PATH_KERNEL    "/boot/kernel/kernel"
29 #define READ_BUF_SIZE   8192
30
31 typedef int putc_func_t(char c, void *arg);
32 typedef int32_t ofwh_t;
33
34 struct sp_data {
35         char    *sp_buf;
36         u_int   sp_len;
37         u_int   sp_size;
38 };
39
40 static const char digits[] = "0123456789abcdef";
41
42 static char bootpath[128];
43 static char bootargs[128];
44
45 static ofwh_t bootdev;
46
47 static uint32_t fs_off;
48
49 int main(int ac, char **av);
50 static void exit(int) __dead2;
51 static void usage(void);
52
53 #ifdef ZFSBOOT
54 static void loadzfs(void);
55 static int zbread(char *buf, off_t off, size_t bytes);
56 #else
57 static void load(const char *);
58 #endif
59
60 static void bcopy(const void *src, void *dst, size_t len);
61 static void bzero(void *b, size_t len);
62
63 static int domount(const char *device);
64 static int dskread(void *buf, u_int64_t lba, int nblk);
65
66 static void panic(const char *fmt, ...) __dead2;
67 static int printf(const char *fmt, ...);
68 static int putchar(char c, void *arg);
69 static int vprintf(const char *fmt, va_list ap);
70 static int vsnprintf(char *str, size_t sz, const char *fmt, va_list ap);
71
72 static int __printf(const char *fmt, putc_func_t *putc, void *arg, va_list ap);
73 static int __puts(const char *s, putc_func_t *putc, void *arg);
74 static int __sputc(char c, void *arg);
75 static char *__uitoa(char *buf, u_int val, int base);
76 static char *__ultoa(char *buf, u_long val, int base);
77
78 /*
79  * Open Firmware interface functions
80  */
81 typedef u_int64_t       ofwcell_t;
82 typedef u_int32_t       u_ofwh_t;
83 typedef int (*ofwfp_t)(ofwcell_t []);
84 static ofwfp_t ofw;                     /* the PROM Open Firmware entry */
85
86 void ofw_init(int, int, int, int, ofwfp_t);
87 static ofwh_t ofw_finddevice(const char *);
88 static ofwh_t ofw_open(const char *);
89 static int ofw_getprop(ofwh_t, const char *, void *, size_t);
90 static int ofw_read(ofwh_t, void *, size_t);
91 static int ofw_write(ofwh_t, const void *, size_t);
92 static int ofw_seek(ofwh_t, u_int64_t);
93 static void ofw_exit(void) __dead2;
94
95 static ofwh_t stdinh, stdouth;
96
97 /*
98  * This has to stay here, as the PROM seems to ignore the
99  * entry point specified in the a.out header.  (or elftoaout is broken)
100  */
101
102 void
103 ofw_init(int d, int d1, int d2, int d3, ofwfp_t ofwaddr)
104 {
105         ofwh_t chosenh;
106         char *av[16];
107         char *p;
108         int ac;
109
110         ofw = ofwaddr;
111
112         chosenh = ofw_finddevice("/chosen");
113         ofw_getprop(chosenh, "stdin", &stdinh, sizeof(stdinh));
114         ofw_getprop(chosenh, "stdout", &stdouth, sizeof(stdouth));
115         ofw_getprop(chosenh, "bootargs", bootargs, sizeof(bootargs));
116         ofw_getprop(chosenh, "bootpath", bootpath, sizeof(bootpath));
117
118         bootargs[sizeof(bootargs) - 1] = '\0';
119         bootpath[sizeof(bootpath) - 1] = '\0';
120
121         ac = 0;
122         p = bootargs;
123         for (;;) {
124                 while (*p == ' ' && *p != '\0')
125                         p++;
126                 if (*p == '\0' || ac >= 16)
127                         break;
128                 av[ac++] = p;
129                 while (*p != ' ' && *p != '\0')
130                         p++;
131                 if (*p != '\0')
132                         *p++ = '\0';
133         }
134
135         exit(main(ac, av));
136 }
137
138 static ofwh_t
139 ofw_finddevice(const char *name)
140 {
141         ofwcell_t args[] = {
142                 (ofwcell_t)"finddevice",
143                 1,
144                 1,
145                 (ofwcell_t)name,
146                 0
147         };
148
149         if ((*ofw)(args)) {
150                 printf("ofw_finddevice: name=\"%s\"\n", name);
151                 return (1);
152         }
153         return (args[4]);
154 }
155
156 static int
157 ofw_getprop(ofwh_t ofwh, const char *name, void *buf, size_t len)
158 {
159         ofwcell_t args[] = {
160                 (ofwcell_t)"getprop",
161                 4,
162                 1,
163                 (u_ofwh_t)ofwh,
164                 (ofwcell_t)name,
165                 (ofwcell_t)buf,
166                 len,
167         0
168         };
169
170         if ((*ofw)(args)) {
171                 printf("ofw_getprop: ofwh=0x%x buf=%p len=%u\n",
172                         ofwh, buf, len);
173                 return (1);
174         }
175         return (0);
176 }
177
178 static ofwh_t
179 ofw_open(const char *path)
180 {
181         ofwcell_t args[] = {
182                 (ofwcell_t)"open",
183                 1,
184                 1,
185                 (ofwcell_t)path,
186                 0
187         };
188
189         if ((*ofw)(args)) {
190                 printf("ofw_open: path=\"%s\"\n", path);
191                 return (-1);
192         }
193         return (args[4]);
194 }
195
196 static int
197 ofw_close(ofwh_t devh)
198 {
199         ofwcell_t args[] = {
200                 (ofwcell_t)"close",
201                 1,
202                 0,
203                 (u_ofwh_t)devh
204         };
205
206         if ((*ofw)(args)) {
207                 printf("ofw_close: devh=0x%x\n", devh);
208                 return (1);
209         }
210         return (0);
211 }
212
213 static int
214 ofw_read(ofwh_t devh, void *buf, size_t len)
215 {
216         ofwcell_t args[] = {
217                 (ofwcell_t)"read",
218                 3,
219                 1,
220                 (u_ofwh_t)devh,
221                 (ofwcell_t)buf,
222                 len,
223                 0
224         };
225
226         if ((*ofw)(args)) {
227                 printf("ofw_read: devh=0x%x buf=%p len=%u\n", devh, buf, len);
228                 return (1);
229         }
230         return (0);
231 }
232
233 static int
234 ofw_write(ofwh_t devh, const void *buf, size_t len)
235 {
236         ofwcell_t args[] = {
237                 (ofwcell_t)"write",
238                 3,
239                 1,
240                 (u_ofwh_t)devh,
241                 (ofwcell_t)buf,
242                 len,
243                 0
244         };
245
246         if ((*ofw)(args)) {
247                 printf("ofw_write: devh=0x%x buf=%p len=%u\n", devh, buf, len);
248                 return (1);
249         }
250         return (0);
251 }
252
253 static int
254 ofw_seek(ofwh_t devh, u_int64_t off)
255 {
256         ofwcell_t args[] = {
257                 (ofwcell_t)"seek",
258                 3,
259                 1,
260                 (u_ofwh_t)devh,
261                 off >> 32,
262                 off,
263                 0
264         };
265
266         if ((*ofw)(args)) {
267                 printf("ofw_seek: devh=0x%x off=0x%lx\n", devh, off);
268                 return (1);
269         }
270         return (0);
271 }
272
273 static void
274 ofw_exit(void)
275 {
276         ofwcell_t args[3];
277
278         args[0] = (ofwcell_t)"exit";
279         args[1] = 0;
280         args[2] = 0;
281
282         for (;;)
283                 (*ofw)(args);
284 }
285
286 static void
287 bcopy(const void *src, void *dst, size_t len)
288 {
289         const char *s = src;
290         char *d = dst;
291
292         while (len-- != 0)
293                 *d++ = *s++;
294 }
295
296 static void
297 memcpy(void *dst, const void *src, size_t len)
298 {
299
300         bcopy(src, dst, len);
301 }
302
303 static void
304 bzero(void *b, size_t len)
305 {
306         char *p = b;
307
308         while (len-- != 0)
309                 *p++ = 0;
310 }
311
312 static int
313 strcmp(const char *s1, const char *s2)
314 {
315
316         for (; *s1 == *s2 && *s1; s1++, s2++)
317                 ;
318         return ((u_char)*s1 - (u_char)*s2);
319 }
320
321 int
322 main(int ac, char **av)
323 {
324         const char *path;
325         int i;
326
327         path = _PATH_LOADER;
328         for (i = 0; i < ac; i++) {
329                 switch (av[i][0]) {
330                 case '-':
331                         switch (av[i][1]) {
332                         default:
333                                 usage();
334                         }
335                         break;
336                 default:
337                         path = av[i];
338                         break;
339                 }
340         }
341
342 #ifdef ZFSBOOT
343         printf(" \n>> FreeBSD/sparc64 ZFS boot block\n   Boot path:   %s\n",
344             bootpath);
345 #else
346         printf(" \n>> FreeBSD/sparc64 boot block\n   Boot path:   %s\n"
347             "   Boot loader: %s\n", bootpath, path);
348 #endif
349
350         if (domount(bootpath) == -1)
351                 panic("domount");
352
353 #ifdef ZFSBOOT
354         loadzfs();
355 #else
356         load(path);
357 #endif
358         return (1);
359 }
360
361 static void
362 usage(void)
363 {
364
365         printf("usage: boot device [/path/to/loader]\n");
366         exit(1);
367 }
368
369 static void
370 exit(int code)
371 {
372
373         ofw_exit();
374 }
375
376 #ifdef ZFSBOOT
377
378 #define VDEV_BOOT_OFFSET        (2 * 256 * 1024)
379 static char zbuf[READ_BUF_SIZE];
380
381 static int
382 zbread(char *buf, off_t off, size_t bytes)
383 {
384         size_t len;
385         off_t poff;
386         off_t soff;
387         char *p;
388         unsigned int nb;
389         unsigned int lb;
390
391         p = buf;
392         soff = VDEV_BOOT_OFFSET + off;
393         lb = (soff + bytes + DEV_BSIZE - 1) / DEV_BSIZE;
394         poff = soff;
395         while (poff < soff + bytes) {
396                 nb = lb - poff / DEV_BSIZE;
397                 if (nb > READ_BUF_SIZE / DEV_BSIZE)
398                         nb = READ_BUF_SIZE / DEV_BSIZE;
399                 if (dskread(zbuf, poff / DEV_BSIZE, nb))
400                         break;
401                 if ((poff / DEV_BSIZE + nb) * DEV_BSIZE > soff + bytes)
402                         len = soff + bytes - poff;
403                 else
404                         len = (poff / DEV_BSIZE + nb) * DEV_BSIZE - poff;
405                 memcpy(p, zbuf + poff % DEV_BSIZE, len);
406                 p += len;
407                 poff += len;
408         }
409         return (poff - soff);
410 }
411
412 static void
413 loadzfs(void)
414 {
415         Elf64_Ehdr eh;
416         Elf64_Phdr ph;
417         caddr_t p;
418         int i;
419
420         if (zbread((char *)&eh, 0, sizeof(eh)) != sizeof(eh)) {
421                 printf("Can't read elf header\n");
422                 return;
423         }
424         if (!IS_ELF(eh)) {
425                 printf("Not an ELF file\n");
426                 return;
427         }
428         for (i = 0; i < eh.e_phnum; i++) {
429                 fs_off = eh.e_phoff + i * eh.e_phentsize;
430                 if (zbread((char *)&ph, fs_off, sizeof(ph)) != sizeof(ph)) {
431                         printf("Can't read program header %d\n", i);
432                         return;
433                 }
434                 if (ph.p_type != PT_LOAD)
435                         continue;
436                 fs_off = ph.p_offset;
437                 p = (caddr_t)ph.p_vaddr;
438                 if (zbread(p, fs_off, ph.p_filesz) != ph.p_filesz) {
439                         printf("Can't read content of section %d\n", i);
440                         return;
441                 }
442                 if (ph.p_filesz != ph.p_memsz)
443                         bzero(p + ph.p_filesz, ph.p_memsz - ph.p_filesz);
444         }
445         ofw_close(bootdev);
446         (*(void (*)(int, int, int, int, ofwfp_t))eh.e_entry)(0, 0, 0, 0, ofw);
447 }
448
449 #else
450
451 #include "ufsread.c"
452
453 static struct dmadat __dmadat;
454
455 static void
456 load(const char *fname)
457 {
458         Elf64_Ehdr eh;
459         Elf64_Phdr ph;
460         caddr_t p;
461         ufs_ino_t ino;
462         int i;
463
464         if ((ino = lookup(fname)) == 0) {
465                 printf("File %s not found\n", fname);
466                 return;
467         }
468         if (fsread(ino, &eh, sizeof(eh)) != sizeof(eh)) {
469                 printf("Can't read elf header\n");
470                 return;
471         }
472         if (!IS_ELF(eh)) {
473                 printf("Not an ELF file\n");
474                 return;
475         }
476         for (i = 0; i < eh.e_phnum; i++) {
477                 fs_off = eh.e_phoff + i * eh.e_phentsize;
478                 if (fsread(ino, &ph, sizeof(ph)) != sizeof(ph)) {
479                         printf("Can't read program header %d\n", i);
480                         return;
481                 }
482                 if (ph.p_type != PT_LOAD)
483                         continue;
484                 fs_off = ph.p_offset;
485                 p = (caddr_t)ph.p_vaddr;
486                 if (fsread(ino, p, ph.p_filesz) != ph.p_filesz) {
487                         printf("Can't read content of section %d\n", i);
488                         return;
489                 }
490                 if (ph.p_filesz != ph.p_memsz)
491                         bzero(p + ph.p_filesz, ph.p_memsz - ph.p_filesz);
492         }
493         ofw_close(bootdev);
494         (*(void (*)(int, int, int, int, ofwfp_t))eh.e_entry)(0, 0, 0, 0, ofw);
495 }
496
497 #endif /* ZFSBOOT */
498
499 static int
500 domount(const char *device)
501 {
502
503         if ((bootdev = ofw_open(device)) == -1) {
504                 printf("domount: can't open device\n");
505                 return (-1);
506         }
507 #ifndef ZFSBOOT
508         dmadat = &__dmadat;
509         if (fsread(0, NULL, 0)) {
510                 printf("domount: can't read superblock\n");
511                 return (-1);
512         }
513 #endif
514         return (0);
515 }
516
517 static int
518 dskread(void *buf, u_int64_t lba, int nblk)
519 {
520
521         /*
522          * The Open Firmware should open the correct partition for us.
523          * That means, if we read from offset zero on an open instance handle,
524          * we should read from offset zero of that partition.
525          */
526         ofw_seek(bootdev, lba * DEV_BSIZE);
527         ofw_read(bootdev, buf, nblk * DEV_BSIZE);
528         return (0);
529 }
530
531 static void
532 panic(const char *fmt, ...)
533 {
534         char buf[128];
535         va_list ap;
536
537         va_start(ap, fmt);
538         vsnprintf(buf, sizeof buf, fmt, ap);
539         printf("panic: %s\n", buf);
540         va_end(ap);
541
542         exit(1);
543 }
544
545 static int
546 printf(const char *fmt, ...)
547 {
548         va_list ap;
549         int ret;
550
551         va_start(ap, fmt);
552         ret = vprintf(fmt, ap);
553         va_end(ap);
554         return (ret);
555 }
556
557 static int
558 putchar(char c, void *arg)
559 {
560         char buf;
561
562         if (c == '\n') {
563                 buf = '\r';
564                 ofw_write(stdouth, &buf, 1);
565         }
566         buf = c;
567         ofw_write(stdouth, &buf, 1);
568         return (1);
569 }
570
571 static int
572 vprintf(const char *fmt, va_list ap)
573 {
574         int ret;
575
576         ret = __printf(fmt, putchar, 0, ap);
577         return (ret);
578 }
579
580 static int
581 vsnprintf(char *str, size_t sz, const char *fmt, va_list ap)
582 {
583         struct sp_data sp;
584         int ret;
585
586         sp.sp_buf = str;
587         sp.sp_len = 0;
588         sp.sp_size = sz;
589         ret = __printf(fmt, __sputc, &sp, ap);
590         return (ret);
591 }
592
593 static int
594 __printf(const char *fmt, putc_func_t *putc, void *arg, va_list ap)
595 {
596         char buf[(sizeof(long) * 8) + 1];
597         char *nbuf;
598         u_long ul;
599         u_int ui;
600         int lflag;
601         int sflag;
602         char *s;
603         int pad;
604         int ret;
605         int c;
606
607         nbuf = &buf[sizeof buf - 1];
608         ret = 0;
609         while ((c = *fmt++) != 0) {
610                 if (c != '%') {
611                         ret += putc(c, arg);
612                         continue;
613                 }
614                 lflag = 0;
615                 sflag = 0;
616                 pad = 0;
617 reswitch:       c = *fmt++;
618                 switch (c) {
619                 case '#':
620                         sflag = 1;
621                         goto reswitch;
622                 case '%':
623                         ret += putc('%', arg);
624                         break;
625                 case 'c':
626                         c = va_arg(ap, int);
627                         ret += putc(c, arg);
628                         break;
629                 case 'd':
630                         if (lflag == 0) {
631                                 ui = (u_int)va_arg(ap, int);
632                                 if (ui < (int)ui) {
633                                         ui = -ui;
634                                         ret += putc('-', arg);
635                                 }
636                                 s = __uitoa(nbuf, ui, 10);
637                         } else {
638                                 ul = (u_long)va_arg(ap, long);
639                                 if (ul < (long)ul) {
640                                         ul = -ul;
641                                         ret += putc('-', arg);
642                                 }
643                                 s = __ultoa(nbuf, ul, 10);
644                         }
645                         ret += __puts(s, putc, arg);
646                         break;
647                 case 'l':
648                         lflag = 1;
649                         goto reswitch;
650                 case 'o':
651                         if (lflag == 0) {
652                                 ui = (u_int)va_arg(ap, u_int);
653                                 s = __uitoa(nbuf, ui, 8);
654                         } else {
655                                 ul = (u_long)va_arg(ap, u_long);
656                                 s = __ultoa(nbuf, ul, 8);
657                         }
658                         ret += __puts(s, putc, arg);
659                         break;
660                 case 'p':
661                         ul = (u_long)va_arg(ap, void *);
662                         s = __ultoa(nbuf, ul, 16);
663                         ret += __puts("0x", putc, arg);
664                         ret += __puts(s, putc, arg);
665                         break;
666                 case 's':
667                         s = va_arg(ap, char *);
668                         ret += __puts(s, putc, arg);
669                         break;
670                 case 'u':
671                         if (lflag == 0) {
672                                 ui = va_arg(ap, u_int);
673                                 s = __uitoa(nbuf, ui, 10);
674                         } else {
675                                 ul = va_arg(ap, u_long);
676                                 s = __ultoa(nbuf, ul, 10);
677                         }
678                         ret += __puts(s, putc, arg);
679                         break;
680                 case 'x':
681                         if (lflag == 0) {
682                                 ui = va_arg(ap, u_int);
683                                 s = __uitoa(nbuf, ui, 16);
684                         } else {
685                                 ul = va_arg(ap, u_long);
686                                 s = __ultoa(nbuf, ul, 16);
687                         }
688                         if (sflag)
689                                 ret += __puts("0x", putc, arg);
690                         ret += __puts(s, putc, arg);
691                         break;
692                 case '0': case '1': case '2': case '3': case '4':
693                 case '5': case '6': case '7': case '8': case '9':
694                         pad = pad * 10 + c - '0';
695                         goto reswitch;
696                 default:
697                         break;
698                 }
699         }
700         return (ret);
701 }
702
703 static int
704 __sputc(char c, void *arg)
705 {
706         struct sp_data *sp;
707
708         sp = arg;
709         if (sp->sp_len < sp->sp_size)
710                 sp->sp_buf[sp->sp_len++] = c;
711         sp->sp_buf[sp->sp_len] = '\0';
712         return (1);
713 }
714
715 static int
716 __puts(const char *s, putc_func_t *putc, void *arg)
717 {
718         const char *p;
719         int ret;
720
721         ret = 0;
722         for (p = s; *p != '\0'; p++)
723                 ret += putc(*p, arg);
724         return (ret);
725 }
726
727 static char *
728 __uitoa(char *buf, u_int ui, int base)
729 {
730         char *p;
731
732         p = buf;
733         *p = '\0';
734         do
735                 *--p = digits[ui % base];
736         while ((ui /= base) != 0);
737         return (p);
738 }
739
740 static char *
741 __ultoa(char *buf, u_long ul, int base)
742 {
743         char *p;
744
745         p = buf;
746         *p = '\0';
747         do
748                 *--p = digits[ul % base];
749         while ((ul /= base) != 0);
750         return (p);
751 }