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