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