Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
freebsd
GitHub Repository: freebsd/freebsd-src
Path: blob/main/stand/powerpc/boot1.chrp/boot1.c
34860 views
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/param.h>
19
#include <sys/dirent.h>
20
#include <sys/endian.h>
21
#include <sys/stdarg.h>
22
23
#include <machine/elf.h>
24
#include <machine/md_var.h>
25
26
#include <ufs/ffs/fs.h>
27
28
#include "paths.h"
29
30
#define BSIZEMAX 16384
31
32
typedef int putc_func_t(char c, void *arg);
33
typedef int32_t ofwh_t;
34
35
struct sp_data {
36
char *sp_buf;
37
u_int sp_len;
38
u_int sp_size;
39
};
40
41
static const char digits[] = "0123456789abcdef";
42
43
static char bootpath[128];
44
static char bootargs[128];
45
46
static ofwh_t bootdev;
47
48
static struct fs fs;
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 *, uint64_t, int);
59
60
static void usage(void) __dead2;
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 domount(const char *device, int quiet);
66
67
static void panic(const char *fmt, ...) __dead2;
68
static int printf(const char *fmt, ...);
69
static int putchar(char 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(char c, void *arg);
75
static int __puts(const char *s, putc_func_t *putc, void *arg);
76
static int __sputc(char 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 uint32_t ofwcell_t;
84
typedef uint32_t u_ofwh_t;
85
typedef int (*ofwfp_t)(ofwcell_t *);
86
ofwfp_t ofw; /* the prom Open Firmware entry */
87
ofwh_t chosenh;
88
89
void ofw_init(void *, int, ofwfp_t, char *, int);
90
static ofwh_t ofw_finddevice(const char *);
91
static ofwh_t ofw_open(const char *);
92
static int ofw_close(ofwh_t);
93
static int ofw_getprop(ofwh_t, const char *, void *, size_t);
94
static int ofw_setprop(ofwh_t, const char *, void *, size_t);
95
static int ofw_read(ofwh_t, void *, size_t);
96
static int ofw_write(ofwh_t, const void *, size_t);
97
static int ofw_claim(void *virt, size_t len, u_int align);
98
static int ofw_seek(ofwh_t, uint64_t);
99
static void ofw_exit(void) __dead2;
100
101
ofwh_t bootdevh;
102
ofwh_t stdinh, stdouth;
103
104
/*
105
* Note about the entry point:
106
*
107
* For some odd reason, the first page of the load appears to have trouble
108
* when entering in LE. The first five instructions decode weirdly.
109
* I suspect it is some cache weirdness between the ELF headers and .text.
110
*
111
* Ensure we have a gap between the start of .text and the entry as a
112
* workaround.
113
*/
114
__asm(" \n\
115
.data \n\
116
.align 4 \n\
117
stack: \n\
118
.space 16384 \n\
119
\n\
120
.text \n\
121
/* SLOF cache hack */ \n\
122
.space 4096 \n\
123
.globl _start \n\
124
_start: \n\
125
lis %r1,stack@ha \n\
126
addi %r1,%r1,stack@l \n\
127
addi %r1,%r1,8192 \n\
128
\n\
129
b ofw_init \n\
130
");
131
132
ofwfp_t realofw;
133
134
#if BYTE_ORDER == LITTLE_ENDIAN
135
/*
136
* Minimal endianness-swap trampoline for LE.
137
*/
138
__attribute__((naked)) int
139
ofwtramp(void *buf, ofwfp_t cb)
140
{
141
__asm(" \n\
142
mflr %r0 \n\
143
stw %r0, 4(%r1) \n\
144
stwu %r1, -16(%r1) \n\
145
stw %r30, 8(%r1) \n\
146
/* Save current MSR for restoration post-call. */ \n\
147
mfmsr %r30 \n\
148
mr %r5, %r30 \n\
149
/* Remove LE bit from MSR. */ \n\
150
clrrwi %r5, %r5, 1 \n\
151
mtsrr0 %r4 \n\
152
mtsrr1 %r5 \n\
153
bcl 20, 31, .+4 /* LOAD_LR_NIA */ \n\
154
1: \n\
155
mflr %r4 \n\
156
addi %r4, %r4, (2f - 1b) \n\
157
mtlr %r4 \n\
158
/* Switch to BE and transfer control to OF entry */ \n\
159
rfid \n\
160
2: \n\
161
/* Control is returned here, but in BE. */ \n\
162
.long 0x05009f42 /* LOAD_LR_NIA */\n\
163
/* 0: */\n\
164
.long 0xa603db7f /* mtsrr1 %r30 */\n\
165
.long 0xa602c87f /* mflr %r30 */\n\
166
.long 0x1400de3b /* addi %r30, %r30, (1f - 0b) */\n\
167
.long 0xa603da7f /* mtsrr0 %r30 */\n\
168
.long 0x2400004c /* rfid */\n\
169
/* 1: */\n\
170
1: \n\
171
/* Back to normal. Tidy up for return. */ \n\
172
lwz %r30, 8(%r1) \n\
173
lwz %r0, 20(%r1) \n\
174
addi %r1, %r1, 16 \n\
175
mtlr %r0 \n\
176
blr \n\
177
");
178
}
179
180
/*
181
* Little-endian OFW entrypoint replacement.
182
*
183
* We are doing all the byteswapping in one place here to save space.
184
* This means instance handles will be byteswapped as well.
185
*/
186
int
187
call_ofw(ofwcell_t* buf)
188
{
189
int ret, i, ncells;
190
191
ncells = 3 + buf[1] + buf[2];
192
for (i = 0; i < ncells; i++)
193
buf[i] = htobe32(buf[i]);
194
195
ret = (ofwtramp(buf, realofw));
196
for (i = 0; i < ncells; i++)
197
buf[i] = be32toh(buf[i]);
198
return (ret);
199
}
200
#endif
201
202
void
203
ofw_init(void *vpd, int res, ofwfp_t openfirm, char *arg, int argl)
204
{
205
char *av[16];
206
char *p;
207
int ac;
208
209
#if BYTE_ORDER == LITTLE_ENDIAN
210
realofw = openfirm;
211
ofw = call_ofw;
212
#else
213
realofw = ofw = openfirm;
214
#endif
215
216
chosenh = ofw_finddevice("/chosen");
217
ofw_getprop(chosenh, "stdin", &stdinh, sizeof(stdinh));
218
stdinh = be32toh(stdinh);
219
ofw_getprop(chosenh, "stdout", &stdouth, sizeof(stdouth));
220
stdouth = be32toh(stdouth);
221
ofw_getprop(chosenh, "bootargs", bootargs, sizeof(bootargs));
222
ofw_getprop(chosenh, "bootpath", bootpath, sizeof(bootpath));
223
224
bootargs[sizeof(bootargs) - 1] = '\0';
225
bootpath[sizeof(bootpath) - 1] = '\0';
226
227
p = bootpath;
228
while (*p != '\0') {
229
/* Truncate partition ID */
230
if (*p == ':') {
231
ofw_close(bootdev);
232
*(++p) = '\0';
233
break;
234
}
235
p++;
236
}
237
238
ac = 0;
239
p = bootargs;
240
for (;;) {
241
while (*p == ' ' && *p != '\0')
242
p++;
243
if (*p == '\0' || ac >= 16)
244
break;
245
av[ac++] = p;
246
while (*p != ' ' && *p != '\0')
247
p++;
248
if (*p != '\0')
249
*p++ = '\0';
250
}
251
252
exit(main(ac, av));
253
}
254
255
static ofwh_t
256
ofw_finddevice(const char *name)
257
{
258
ofwcell_t args[] = {
259
(ofwcell_t)"finddevice",
260
1,
261
1,
262
(ofwcell_t)name,
263
0
264
};
265
266
if ((*ofw)(args)) {
267
printf("ofw_finddevice: name=\"%s\"\n", name);
268
return (1);
269
}
270
return (args[4]);
271
}
272
273
static int
274
ofw_getprop(ofwh_t ofwh, const char *name, void *buf, size_t len)
275
{
276
ofwcell_t args[] = {
277
(ofwcell_t)"getprop",
278
4,
279
1,
280
(u_ofwh_t)ofwh,
281
(ofwcell_t)name,
282
(ofwcell_t)buf,
283
len,
284
0
285
};
286
287
if ((*ofw)(args)) {
288
printf("ofw_getprop: ofwh=0x%x buf=%p len=%u\n",
289
ofwh, buf, len);
290
return (1);
291
}
292
return (0);
293
}
294
295
static int
296
ofw_setprop(ofwh_t ofwh, const char *name, void *buf, size_t len)
297
{
298
ofwcell_t args[] = {
299
(ofwcell_t)"setprop",
300
4,
301
1,
302
(u_ofwh_t)ofwh,
303
(ofwcell_t)name,
304
(ofwcell_t)buf,
305
len,
306
0
307
};
308
309
if ((*ofw)(args)) {
310
printf("ofw_setprop: ofwh=0x%x buf=%p len=%u\n",
311
ofwh, buf, len);
312
return (1);
313
}
314
return (0);
315
}
316
317
static ofwh_t
318
ofw_open(const char *path)
319
{
320
ofwcell_t args[] = {
321
(ofwcell_t)"open",
322
1,
323
1,
324
(ofwcell_t)path,
325
0
326
};
327
328
if ((*ofw)(args)) {
329
printf("ofw_open: path=\"%s\"\n", path);
330
return (-1);
331
}
332
return (args[4]);
333
}
334
335
static int
336
ofw_close(ofwh_t devh)
337
{
338
ofwcell_t args[] = {
339
(ofwcell_t)"close",
340
1,
341
0,
342
(u_ofwh_t)devh
343
};
344
345
if ((*ofw)(args)) {
346
printf("ofw_close: devh=0x%x\n", devh);
347
return (1);
348
}
349
return (0);
350
}
351
352
static int
353
ofw_claim(void *virt, size_t len, u_int align)
354
{
355
ofwcell_t args[] = {
356
(ofwcell_t)"claim",
357
3,
358
1,
359
(ofwcell_t)virt,
360
len,
361
align,
362
0,
363
0
364
};
365
366
if ((*ofw)(args)) {
367
printf("ofw_claim: virt=%p len=%u\n", virt, len);
368
return (1);
369
}
370
371
return (0);
372
}
373
374
static int
375
ofw_read(ofwh_t devh, void *buf, size_t len)
376
{
377
ofwcell_t args[] = {
378
(ofwcell_t)"read",
379
3,
380
1,
381
(u_ofwh_t)devh,
382
(ofwcell_t)buf,
383
len,
384
0
385
};
386
387
if ((*ofw)(args)) {
388
printf("ofw_read: devh=0x%x buf=%p len=%u\n", devh, buf, len);
389
return (1);
390
}
391
return (0);
392
}
393
394
static int
395
ofw_write(ofwh_t devh, const void *buf, size_t len)
396
{
397
ofwcell_t args[] = {
398
(ofwcell_t)"write",
399
3,
400
1,
401
(u_ofwh_t)devh,
402
(ofwcell_t)buf,
403
len,
404
0
405
};
406
407
if ((*ofw)(args)) {
408
printf("ofw_write: devh=0x%x buf=%p len=%u\n", devh, buf, len);
409
return (1);
410
}
411
return (0);
412
}
413
414
static int
415
ofw_seek(ofwh_t devh, uint64_t off)
416
{
417
ofwcell_t args[] = {
418
(ofwcell_t)"seek",
419
3,
420
1,
421
(u_ofwh_t)devh,
422
off >> 32,
423
off,
424
0
425
};
426
427
if ((*ofw)(args)) {
428
printf("ofw_seek: devh=0x%x off=0x%lx\n", devh, off);
429
return (1);
430
}
431
return (0);
432
}
433
434
static void
435
ofw_exit(void)
436
{
437
ofwcell_t args[3];
438
439
args[0] = (ofwcell_t)"exit";
440
args[1] = 0;
441
args[2] = 0;
442
443
for (;;)
444
(*ofw)(args);
445
}
446
447
static void
448
bcopy(const void *src, void *dst, size_t len)
449
{
450
const char *s = src;
451
char *d = dst;
452
453
while (len-- != 0)
454
*d++ = *s++;
455
}
456
457
static void
458
memcpy(void *dst, const void *src, size_t len)
459
{
460
bcopy(src, dst, len);
461
}
462
463
static void
464
bzero(void *b, size_t len)
465
{
466
char *p = b;
467
468
while (len-- != 0)
469
*p++ = 0;
470
}
471
472
static int
473
strcmp(const char *s1, const char *s2)
474
{
475
for (; *s1 == *s2 && *s1; s1++, s2++)
476
;
477
return ((u_char)*s1 - (u_char)*s2);
478
}
479
480
#include "ufsread.c"
481
482
int
483
main(int ac, char **av)
484
{
485
const char *path;
486
char bootpath_full[255];
487
int i, len;
488
489
path = PATH_LOADER;
490
for (i = 0; i < ac; i++) {
491
switch (av[i][0]) {
492
case '-':
493
switch (av[i][1]) {
494
default:
495
usage();
496
}
497
break;
498
default:
499
path = av[i];
500
break;
501
}
502
}
503
504
printf(" \n>> FreeBSD/powerpc Open Firmware boot block\n"
505
" Boot path: %s\n"
506
" Boot loader: %s\n", bootpath, path);
507
508
len = 0;
509
while (bootpath[len] != '\0') len++;
510
511
memcpy(bootpath_full,bootpath,len+1);
512
513
if (bootpath_full[len-1] != ':') {
514
/* First try full volume */
515
if (domount(bootpath_full,1) == 0)
516
goto out;
517
518
/* Add a : so that we try partitions if that fails */
519
if (bootdev > 0)
520
ofw_close(bootdev);
521
bootpath_full[len] = ':';
522
len += 1;
523
}
524
525
/* Loop through first 16 partitions to find a UFS one */
526
for (i = 0; i < 16; i++) {
527
if (i < 10) {
528
bootpath_full[len] = i + '0';
529
bootpath_full[len+1] = '\0';
530
} else {
531
bootpath_full[len] = '1';
532
bootpath_full[len+1] = i - 10 + '0';
533
bootpath_full[len+2] = '\0';
534
}
535
536
if (domount(bootpath_full,1) >= 0)
537
break;
538
539
if (bootdev > 0)
540
ofw_close(bootdev);
541
}
542
543
if (i >= 16)
544
panic("domount");
545
546
out:
547
printf(" Boot volume: %s\n",bootpath_full);
548
ofw_setprop(chosenh, "bootargs", bootpath_full, len+2);
549
load(path);
550
return (1);
551
}
552
553
static void
554
usage(void)
555
{
556
557
printf("usage: boot device [/path/to/loader]\n");
558
exit(1);
559
}
560
561
static void
562
exit(int code)
563
{
564
565
ofw_exit();
566
}
567
568
static struct dmadat __dmadat;
569
570
static int
571
domount(const char *device, int quiet)
572
{
573
574
dmadat = &__dmadat;
575
if ((bootdev = ofw_open(device)) == -1) {
576
printf("domount: can't open device\n");
577
return (-1);
578
}
579
if (fsread(0, NULL, 0)) {
580
if (!quiet)
581
printf("domount: can't read superblock\n");
582
return (-1);
583
}
584
return (0);
585
}
586
587
static void
588
load(const char *fname)
589
{
590
Elf32_Ehdr eh;
591
Elf32_Phdr ph;
592
caddr_t p;
593
ufs_ino_t ino;
594
int i;
595
596
if ((ino = lookup(fname)) == 0) {
597
printf("File %s not found\n", fname);
598
return;
599
}
600
if (fsread(ino, &eh, sizeof(eh)) != sizeof(eh)) {
601
printf("Can't read elf header\n");
602
return;
603
}
604
if (!IS_ELF(eh)) {
605
printf("Not an ELF file\n");
606
return;
607
}
608
for (i = 0; i < eh.e_phnum; i++) {
609
fs_off = eh.e_phoff + i * eh.e_phentsize;
610
if (fsread(ino, &ph, sizeof(ph)) != sizeof(ph)) {
611
printf("Can't read program header %d\n", i);
612
return;
613
}
614
if (ph.p_type != PT_LOAD)
615
continue;
616
fs_off = ph.p_offset;
617
p = (caddr_t)ph.p_vaddr;
618
ofw_claim(p,(ph.p_filesz > ph.p_memsz) ?
619
ph.p_filesz : ph.p_memsz,0);
620
if (fsread(ino, p, ph.p_filesz) != ph.p_filesz) {
621
printf("Can't read content of section %d\n", i);
622
return;
623
}
624
if (ph.p_filesz != ph.p_memsz)
625
bzero(p + ph.p_filesz, ph.p_memsz - ph.p_filesz);
626
__syncicache(p, ph.p_memsz);
627
}
628
ofw_close(bootdev);
629
(*(void (*)(void *, int, ofwfp_t, char *, int))eh.e_entry)(NULL, 0,
630
realofw, NULL, 0);
631
}
632
633
static int
634
dskread(void *buf, uint64_t lba, int nblk)
635
{
636
/*
637
* The Open Firmware should open the correct partition for us.
638
* That means, if we read from offset zero on an open instance handle,
639
* we should read from offset zero of that partition.
640
*/
641
ofw_seek(bootdev, lba * DEV_BSIZE);
642
ofw_read(bootdev, buf, nblk * DEV_BSIZE);
643
return (0);
644
}
645
646
static void
647
panic(const char *fmt, ...)
648
{
649
char buf[128];
650
va_list ap;
651
652
va_start(ap, fmt);
653
vsnprintf(buf, sizeof buf, fmt, ap);
654
printf("panic: %s\n", buf);
655
va_end(ap);
656
657
exit(1);
658
}
659
660
static int
661
printf(const char *fmt, ...)
662
{
663
va_list ap;
664
int ret;
665
666
va_start(ap, fmt);
667
ret = vprintf(fmt, ap);
668
va_end(ap);
669
return (ret);
670
}
671
672
static int
673
putchar(char c, void *arg)
674
{
675
char buf;
676
677
if (c == '\n') {
678
buf = '\r';
679
ofw_write(stdouth, &buf, 1);
680
}
681
buf = c;
682
ofw_write(stdouth, &buf, 1);
683
return (1);
684
}
685
686
static int
687
vprintf(const char *fmt, va_list ap)
688
{
689
int ret;
690
691
ret = __printf(fmt, putchar, 0, ap);
692
return (ret);
693
}
694
695
static int
696
vsnprintf(char *str, size_t sz, const char *fmt, va_list ap)
697
{
698
struct sp_data sp;
699
int ret;
700
701
sp.sp_buf = str;
702
sp.sp_len = 0;
703
sp.sp_size = sz;
704
ret = __printf(fmt, __sputc, &sp, ap);
705
return (ret);
706
}
707
708
static int
709
__printf(const char *fmt, putc_func_t *putc, void *arg, va_list ap)
710
{
711
char buf[(sizeof(long) * 8) + 1];
712
char *nbuf;
713
u_long ul;
714
u_int ui;
715
int lflag;
716
int sflag;
717
char *s;
718
int pad;
719
int ret;
720
int c;
721
722
nbuf = &buf[sizeof buf - 1];
723
ret = 0;
724
while ((c = *fmt++) != 0) {
725
if (c != '%') {
726
ret += putc(c, arg);
727
continue;
728
}
729
lflag = 0;
730
sflag = 0;
731
pad = 0;
732
reswitch: c = *fmt++;
733
switch (c) {
734
case '#':
735
sflag = 1;
736
goto reswitch;
737
case '%':
738
ret += putc('%', arg);
739
break;
740
case 'c':
741
c = va_arg(ap, int);
742
ret += putc(c, arg);
743
break;
744
case 'd':
745
if (lflag == 0) {
746
ui = (u_int)va_arg(ap, int);
747
if (ui < (int)ui) {
748
ui = -ui;
749
ret += putc('-', arg);
750
}
751
s = __uitoa(nbuf, ui, 10);
752
} else {
753
ul = (u_long)va_arg(ap, long);
754
if (ul < (long)ul) {
755
ul = -ul;
756
ret += putc('-', arg);
757
}
758
s = __ultoa(nbuf, ul, 10);
759
}
760
ret += __puts(s, putc, arg);
761
break;
762
case 'l':
763
lflag = 1;
764
goto reswitch;
765
case 'o':
766
if (lflag == 0) {
767
ui = (u_int)va_arg(ap, u_int);
768
s = __uitoa(nbuf, ui, 8);
769
} else {
770
ul = (u_long)va_arg(ap, u_long);
771
s = __ultoa(nbuf, ul, 8);
772
}
773
ret += __puts(s, putc, arg);
774
break;
775
case 'p':
776
ul = (u_long)va_arg(ap, void *);
777
s = __ultoa(nbuf, ul, 16);
778
ret += __puts("0x", putc, arg);
779
ret += __puts(s, putc, arg);
780
break;
781
case 's':
782
s = va_arg(ap, char *);
783
ret += __puts(s, putc, arg);
784
break;
785
case 'u':
786
if (lflag == 0) {
787
ui = va_arg(ap, u_int);
788
s = __uitoa(nbuf, ui, 10);
789
} else {
790
ul = va_arg(ap, u_long);
791
s = __ultoa(nbuf, ul, 10);
792
}
793
ret += __puts(s, putc, arg);
794
break;
795
case 'x':
796
if (lflag == 0) {
797
ui = va_arg(ap, u_int);
798
s = __uitoa(nbuf, ui, 16);
799
} else {
800
ul = va_arg(ap, u_long);
801
s = __ultoa(nbuf, ul, 16);
802
}
803
if (sflag)
804
ret += __puts("0x", putc, arg);
805
ret += __puts(s, putc, arg);
806
break;
807
case '0': case '1': case '2': case '3': case '4':
808
case '5': case '6': case '7': case '8': case '9':
809
pad = pad * 10 + c - '0';
810
goto reswitch;
811
default:
812
break;
813
}
814
}
815
return (ret);
816
}
817
818
static int
819
__sputc(char c, void *arg)
820
{
821
struct sp_data *sp;
822
823
sp = arg;
824
if (sp->sp_len < sp->sp_size)
825
sp->sp_buf[sp->sp_len++] = c;
826
sp->sp_buf[sp->sp_len] = '\0';
827
return (1);
828
}
829
830
static int
831
__puts(const char *s, putc_func_t *putc, void *arg)
832
{
833
const char *p;
834
int ret;
835
836
ret = 0;
837
for (p = s; *p != '\0'; p++)
838
ret += putc(*p, arg);
839
return (ret);
840
}
841
842
static char *
843
__uitoa(char *buf, u_int ui, int base)
844
{
845
char *p;
846
847
p = buf;
848
*p = '\0';
849
do
850
*--p = digits[ui % base];
851
while ((ui /= base) != 0);
852
return (p);
853
}
854
855
static char *
856
__ultoa(char *buf, u_long ul, int base)
857
{
858
char *p;
859
860
p = buf;
861
*p = '\0';
862
do
863
*--p = digits[ul % base];
864
while ((ul /= base) != 0);
865
return (p);
866
}
867
868