]> CyberLeo.Net >> Repos - FreeBSD/releng/9.2.git/blob - sys/boot/sparc64/boot1/boot1.c
- Copy stable/9 to releng/9.2 as part of the 9.2-RELEASE cycle.
[FreeBSD/releng/9.2.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         ino_t ino;
419         int i;
420
421         if (zbread((char *)&eh, 0, sizeof(eh)) != sizeof(eh)) {
422                 printf("Can't read elf header\n");
423                 return;
424         }
425         if (!IS_ELF(eh)) {
426                 printf("Not an ELF file\n");
427                 return;
428         }
429         for (i = 0; i < eh.e_phnum; i++) {
430                 fs_off = eh.e_phoff + i * eh.e_phentsize;
431                 if (zbread((char *)&ph, fs_off, sizeof(ph)) != sizeof(ph)) {
432                         printf("Can't read program header %d\n", i);
433                         return;
434                 }
435                 if (ph.p_type != PT_LOAD)
436                         continue;
437                 fs_off = ph.p_offset;
438                 p = (caddr_t)ph.p_vaddr;
439                 if (zbread(p, fs_off, ph.p_filesz) != ph.p_filesz) {
440                         printf("Can't read content of section %d\n", i);
441                         return;
442                 }
443                 if (ph.p_filesz != ph.p_memsz)
444                         bzero(p + ph.p_filesz, ph.p_memsz - ph.p_filesz);
445         }
446         ofw_close(bootdev);
447         (*(void (*)(int, int, int, int, ofwfp_t))eh.e_entry)(0, 0, 0, 0, ofw);
448 }
449
450 #else
451
452 #include "ufsread.c"
453
454 static struct dmadat __dmadat;
455
456 static void
457 load(const char *fname)
458 {
459         Elf64_Ehdr eh;
460         Elf64_Phdr ph;
461         caddr_t p;
462         ino_t ino;
463         int i;
464
465         if ((ino = lookup(fname)) == 0) {
466                 printf("File %s not found\n", fname);
467                 return;
468         }
469         if (fsread(ino, &eh, sizeof(eh)) != sizeof(eh)) {
470                 printf("Can't read elf header\n");
471                 return;
472         }
473         if (!IS_ELF(eh)) {
474                 printf("Not an ELF file\n");
475                 return;
476         }
477         for (i = 0; i < eh.e_phnum; i++) {
478                 fs_off = eh.e_phoff + i * eh.e_phentsize;
479                 if (fsread(ino, &ph, sizeof(ph)) != sizeof(ph)) {
480                         printf("Can't read program header %d\n", i);
481                         return;
482                 }
483                 if (ph.p_type != PT_LOAD)
484                         continue;
485                 fs_off = ph.p_offset;
486                 p = (caddr_t)ph.p_vaddr;
487                 if (fsread(ino, p, ph.p_filesz) != ph.p_filesz) {
488                         printf("Can't read content of section %d\n", i);
489                         return;
490                 }
491                 if (ph.p_filesz != ph.p_memsz)
492                         bzero(p + ph.p_filesz, ph.p_memsz - ph.p_filesz);
493         }
494         ofw_close(bootdev);
495         (*(void (*)(int, int, int, int, ofwfp_t))eh.e_entry)(0, 0, 0, 0, ofw);
496 }
497
498 #endif /* ZFSBOOT */
499
500 static int
501 domount(const char *device)
502 {
503
504         if ((bootdev = ofw_open(device)) == -1) {
505                 printf("domount: can't open device\n");
506                 return (-1);
507         }
508 #ifndef ZFSBOOT
509         dmadat = &__dmadat;
510         if (fsread(0, NULL, 0)) {
511                 printf("domount: can't read superblock\n");
512                 return (-1);
513         }
514 #endif
515         return (0);
516 }
517
518 static int
519 dskread(void *buf, u_int64_t lba, int nblk)
520 {
521
522         /*
523          * The Open Firmware should open the correct partition for us.
524          * That means, if we read from offset zero on an open instance handle,
525          * we should read from offset zero of that partition.
526          */
527         ofw_seek(bootdev, lba * DEV_BSIZE);
528         ofw_read(bootdev, buf, nblk * DEV_BSIZE);
529         return (0);
530 }
531
532 static void
533 panic(const char *fmt, ...)
534 {
535         char buf[128];
536         va_list ap;
537
538         va_start(ap, fmt);
539         vsnprintf(buf, sizeof buf, fmt, ap);
540         printf("panic: %s\n", buf);
541         va_end(ap);
542
543         exit(1);
544 }
545
546 static int
547 printf(const char *fmt, ...)
548 {
549         va_list ap;
550         int ret;
551
552         va_start(ap, fmt);
553         ret = vprintf(fmt, ap);
554         va_end(ap);
555         return (ret);
556 }
557
558 static int
559 putchar(char c, void *arg)
560 {
561         char buf;
562
563         if (c == '\n') {
564                 buf = '\r';
565                 ofw_write(stdouth, &buf, 1);
566         }
567         buf = c;
568         ofw_write(stdouth, &buf, 1);
569         return (1);
570 }
571
572 static int
573 vprintf(const char *fmt, va_list ap)
574 {
575         int ret;
576
577         ret = __printf(fmt, putchar, 0, ap);
578         return (ret);
579 }
580
581 static int
582 vsnprintf(char *str, size_t sz, const char *fmt, va_list ap)
583 {
584         struct sp_data sp;
585         int ret;
586
587         sp.sp_buf = str;
588         sp.sp_len = 0;
589         sp.sp_size = sz;
590         ret = __printf(fmt, __sputc, &sp, ap);
591         return (ret);
592 }
593
594 static int
595 __printf(const char *fmt, putc_func_t *putc, void *arg, va_list ap)
596 {
597         char buf[(sizeof(long) * 8) + 1];
598         char *nbuf;
599         u_long ul;
600         u_int ui;
601         int lflag;
602         int sflag;
603         char *s;
604         int pad;
605         int ret;
606         int c;
607
608         nbuf = &buf[sizeof buf - 1];
609         ret = 0;
610         while ((c = *fmt++) != 0) {
611                 if (c != '%') {
612                         ret += putc(c, arg);
613                         continue;
614                 }
615                 lflag = 0;
616                 sflag = 0;
617                 pad = 0;
618 reswitch:       c = *fmt++;
619                 switch (c) {
620                 case '#':
621                         sflag = 1;
622                         goto reswitch;
623                 case '%':
624                         ret += putc('%', arg);
625                         break;
626                 case 'c':
627                         c = va_arg(ap, int);
628                         ret += putc(c, arg);
629                         break;
630                 case 'd':
631                         if (lflag == 0) {
632                                 ui = (u_int)va_arg(ap, int);
633                                 if (ui < (int)ui) {
634                                         ui = -ui;
635                                         ret += putc('-', arg);
636                                 }
637                                 s = __uitoa(nbuf, ui, 10);
638                         } else {
639                                 ul = (u_long)va_arg(ap, long);
640                                 if (ul < (long)ul) {
641                                         ul = -ul;
642                                         ret += putc('-', arg);
643                                 }
644                                 s = __ultoa(nbuf, ul, 10);
645                         }
646                         ret += __puts(s, putc, arg);
647                         break;
648                 case 'l':
649                         lflag = 1;
650                         goto reswitch;
651                 case 'o':
652                         if (lflag == 0) {
653                                 ui = (u_int)va_arg(ap, u_int);
654                                 s = __uitoa(nbuf, ui, 8);
655                         } else {
656                                 ul = (u_long)va_arg(ap, u_long);
657                                 s = __ultoa(nbuf, ul, 8);
658                         }
659                         ret += __puts(s, putc, arg);
660                         break;
661                 case 'p':
662                         ul = (u_long)va_arg(ap, void *);
663                         s = __ultoa(nbuf, ul, 16);
664                         ret += __puts("0x", putc, arg);
665                         ret += __puts(s, putc, arg);
666                         break;
667                 case 's':
668                         s = va_arg(ap, char *);
669                         ret += __puts(s, putc, arg);
670                         break;
671                 case 'u':
672                         if (lflag == 0) {
673                                 ui = va_arg(ap, u_int);
674                                 s = __uitoa(nbuf, ui, 10);
675                         } else {
676                                 ul = va_arg(ap, u_long);
677                                 s = __ultoa(nbuf, ul, 10);
678                         }
679                         ret += __puts(s, putc, arg);
680                         break;
681                 case 'x':
682                         if (lflag == 0) {
683                                 ui = va_arg(ap, u_int);
684                                 s = __uitoa(nbuf, ui, 16);
685                         } else {
686                                 ul = va_arg(ap, u_long);
687                                 s = __ultoa(nbuf, ul, 16);
688                         }
689                         if (sflag)
690                                 ret += __puts("0x", putc, arg);
691                         ret += __puts(s, putc, arg);
692                         break;
693                 case '0': case '1': case '2': case '3': case '4':
694                 case '5': case '6': case '7': case '8': case '9':
695                         pad = pad * 10 + c - '0';
696                         goto reswitch;
697                 default:
698                         break;
699                 }
700         }
701         return (ret);
702 }
703
704 static int
705 __sputc(char c, void *arg)
706 {
707         struct sp_data *sp;
708
709         sp = arg;
710         if (sp->sp_len < sp->sp_size)
711                 sp->sp_buf[sp->sp_len++] = c;
712         sp->sp_buf[sp->sp_len] = '\0';
713         return (1);
714 }
715
716 static int
717 __puts(const char *s, putc_func_t *putc, void *arg)
718 {
719         const char *p;
720         int ret;
721
722         ret = 0;
723         for (p = s; *p != '\0'; p++)
724                 ret += putc(*p, arg);
725         return (ret);
726 }
727
728 static char *
729 __uitoa(char *buf, u_int ui, int base)
730 {
731         char *p;
732
733         p = buf;
734         *p = '\0';
735         do
736                 *--p = digits[ui % base];
737         while ((ui /= base) != 0);
738         return (p);
739 }
740
741 static char *
742 __ultoa(char *buf, u_long ul, int base)
743 {
744         char *p;
745
746         p = buf;
747         *p = '\0';
748         do
749                 *--p = digits[ul % base];
750         while ((ul /= base) != 0);
751         return (p);
752 }