Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
freebsd
GitHub Repository: freebsd/freebsd-src
Path: blob/main/stand/i386/boot2/boot2.c
34691 views
1
/*-
2
* Copyright (c) 1998 Robert Nordier
3
* All rights reserved.
4
*
5
* Redistribution and use in source and binary forms are freely
6
* permitted provided that the above copyright notice and this
7
* paragraph and the following disclaimer are duplicated in all
8
* such forms.
9
*
10
* This software is provided "AS IS" and without any express or
11
* implied warranties, including, without limitation, the implied
12
* warranties of merchantability and fitness for a particular
13
* purpose.
14
*/
15
16
#include <sys/param.h>
17
#include <sys/disklabel.h>
18
#include <sys/diskmbr.h>
19
#include <sys/dirent.h>
20
#include <sys/reboot.h>
21
22
#include <machine/bootinfo.h>
23
#include <machine/elf.h>
24
25
#include <stdarg.h>
26
27
#include <a.out.h>
28
29
#include <btxv86.h>
30
31
#include "boot2.h"
32
#include "lib.h"
33
#include "paths.h"
34
#include "rbx.h"
35
36
/* Define to 0 to omit serial support */
37
#ifndef SERIAL
38
#define SERIAL 1
39
#endif
40
41
#define IO_KEYBOARD 1
42
#define IO_SERIAL 2
43
44
#if SERIAL
45
#define DO_KBD (ioctrl & IO_KEYBOARD)
46
#define DO_SIO (ioctrl & IO_SERIAL)
47
#else
48
#define DO_KBD (1)
49
#define DO_SIO (0)
50
#endif
51
52
#define SECOND 18 /* Circa that many ticks in a second. */
53
54
#define ARGS 0x900
55
#define NOPT 14
56
#define NDEV 3
57
#define MEM_BASE 0x12
58
#define MEM_EXT 0x15
59
60
#define DRV_HARD 0x80
61
#define DRV_MASK 0x7f
62
63
#define TYPE_AD 0
64
#define TYPE_DA 1
65
#define TYPE_MAXHARD TYPE_DA
66
#define TYPE_FD 2
67
68
extern uint32_t _end;
69
70
static const char optstr[NOPT] = "DhaCcdgmnpqrsv"; /* Also 'P', 'S' */
71
static const unsigned char flags[NOPT] = {
72
RBX_DUAL,
73
RBX_SERIAL,
74
RBX_ASKNAME,
75
RBX_CDROM,
76
RBX_CONFIG,
77
RBX_KDB,
78
RBX_GDB,
79
RBX_MUTE,
80
RBX_NOINTR,
81
RBX_PAUSE,
82
RBX_QUIET,
83
RBX_DFLTROOT,
84
RBX_SINGLE,
85
RBX_VERBOSE
86
};
87
88
static const char *const dev_nm[NDEV] = {"ad", "da", "fd"};
89
static const unsigned char dev_maj[NDEV] = {30, 4, 2};
90
91
static struct dsk {
92
unsigned drive;
93
unsigned type;
94
unsigned unit;
95
uint8_t slice;
96
uint8_t part;
97
unsigned start;
98
int init;
99
} dsk;
100
static char cmd[512], cmddup[512], knamebuf[1024];
101
static const char *kname;
102
uint32_t opts;
103
static struct bootinfo bootinfo;
104
#if SERIAL
105
static int comspeed = SIOSPD;
106
static uint8_t ioctrl = IO_KEYBOARD;
107
#endif
108
109
int main(void);
110
void exit(int);
111
static void load(void);
112
static int parse(void);
113
static int dskread(void *, unsigned, unsigned);
114
static void printf(const char *,...);
115
static void putchar(int);
116
static int drvread(void *, unsigned, unsigned);
117
static int keyhit(unsigned);
118
static int xputc(int);
119
static int xgetc(int);
120
static inline int getc(int);
121
122
static void memcpy(void *, const void *, int);
123
static void
124
memcpy(void *dst, const void *src, int len)
125
{
126
const char *s;
127
char *d;
128
129
s = src;
130
d = dst;
131
132
while (len--)
133
*d++ = *s++;
134
}
135
136
static inline int
137
strcmp(const char *s1, const char *s2)
138
{
139
140
for (; *s1 == *s2 && *s1; s1++, s2++);
141
return ((unsigned char)*s1 - (unsigned char)*s2);
142
}
143
144
#define UFS_SMALL_CGBASE
145
#include "ufsread.c"
146
147
static int
148
xfsread(ufs_ino_t inode, void *buf, size_t nbyte)
149
{
150
151
if ((size_t)fsread(inode, buf, nbyte) != nbyte) {
152
printf("Invalid %s\n", "format");
153
return (-1);
154
}
155
return (0);
156
}
157
158
static inline void
159
getstr(void)
160
{
161
char *s;
162
int c;
163
164
s = cmd;
165
for (;;) {
166
switch (c = xgetc(0)) {
167
case 0:
168
break;
169
case '\177':
170
case '\b':
171
if (s > cmd) {
172
s--;
173
printf("\b \b");
174
}
175
break;
176
case '\n':
177
case '\r':
178
*s = 0;
179
return;
180
default:
181
if (s - cmd < sizeof(cmd) - 1)
182
*s++ = c;
183
putchar(c);
184
}
185
}
186
}
187
188
static inline void
189
putc(int c)
190
{
191
192
v86.addr = 0x10;
193
v86.eax = 0xe00 | (c & 0xff);
194
v86.ebx = 0x7;
195
v86int();
196
}
197
198
int
199
main(void)
200
{
201
uint8_t autoboot;
202
ufs_ino_t ino;
203
size_t nbyte;
204
205
dmadat = (void *)(roundup2(__base + (int32_t)&_end, 0x10000) - __base);
206
v86.ctl = V86_FLAGS;
207
v86.efl = PSL_RESERVED_DEFAULT | PSL_I;
208
dsk.drive = *(uint8_t *)PTOV(ARGS);
209
dsk.type = dsk.drive & DRV_HARD ? TYPE_AD : TYPE_FD;
210
dsk.unit = dsk.drive & DRV_MASK;
211
dsk.slice = *(uint8_t *)PTOV(ARGS + 1) + 1;
212
bootinfo.bi_version = BOOTINFO_VERSION;
213
bootinfo.bi_size = sizeof(bootinfo);
214
215
/* Process configuration file */
216
217
autoboot = 1;
218
219
if ((ino = lookup(PATH_CONFIG)) ||
220
(ino = lookup(PATH_DOTCONFIG))) {
221
nbyte = fsread(ino, cmd, sizeof(cmd) - 1);
222
cmd[nbyte] = '\0';
223
}
224
225
if (*cmd) {
226
memcpy(cmddup, cmd, sizeof(cmd));
227
if (parse())
228
autoboot = 0;
229
if (!OPT_CHECK(RBX_QUIET))
230
printf("%s: %s", PATH_CONFIG, cmddup);
231
/* Do not process this command twice */
232
*cmd = 0;
233
}
234
235
/*
236
* Try to exec stage 3 boot loader. If interrupted by a keypress,
237
* or in case of failure, try to load a kernel directly instead.
238
*/
239
240
if (!kname) {
241
kname = PATH_LOADER;
242
if (autoboot && !keyhit(3*SECOND)) {
243
load();
244
kname = PATH_KERNEL;
245
}
246
}
247
248
/* Present the user with the boot2 prompt. */
249
250
for (;;) {
251
if (!autoboot || !OPT_CHECK(RBX_QUIET))
252
printf("\nFreeBSD/x86 boot\n"
253
"Default: %u:%s(%u,%c)%s\n"
254
"boot: ",
255
dsk.drive & DRV_MASK, dev_nm[dsk.type], dsk.unit,
256
'a' + dsk.part, kname);
257
if (DO_SIO)
258
sio_flush();
259
if (!autoboot || keyhit(3*SECOND))
260
getstr();
261
else if (!autoboot || !OPT_CHECK(RBX_QUIET))
262
putchar('\n');
263
autoboot = 0;
264
if (parse())
265
putchar('\a');
266
else
267
load();
268
}
269
}
270
271
/* XXX - Needed for btxld to link the boot2 binary; do not remove. */
272
void
273
exit(int x)
274
{
275
276
}
277
278
static void
279
load(void)
280
{
281
union {
282
struct exec ex;
283
Elf32_Ehdr eh;
284
} hdr;
285
static Elf32_Phdr ep[2];
286
static Elf32_Shdr es[2];
287
caddr_t p;
288
ufs_ino_t ino;
289
uint32_t addr;
290
int k;
291
uint8_t i, j;
292
293
if (!(ino = lookup(kname))) {
294
if (!ls)
295
printf("No %s\n", kname);
296
return;
297
}
298
if (xfsread(ino, &hdr, sizeof(hdr)))
299
return;
300
301
if (N_GETMAGIC(hdr.ex) == ZMAGIC) {
302
addr = hdr.ex.a_entry & 0xffffff;
303
p = PTOV(addr);
304
fs_off = PAGE_SIZE;
305
if (xfsread(ino, p, hdr.ex.a_text))
306
return;
307
p += roundup2(hdr.ex.a_text, PAGE_SIZE);
308
if (xfsread(ino, p, hdr.ex.a_data))
309
return;
310
} else if (IS_ELF(hdr.eh)) {
311
fs_off = hdr.eh.e_phoff;
312
for (j = k = 0; k < hdr.eh.e_phnum && j < 2; k++) {
313
if (xfsread(ino, ep + j, sizeof(ep[0])))
314
return;
315
if (ep[j].p_type == PT_LOAD)
316
j++;
317
}
318
for (i = 0; i < 2; i++) {
319
p = PTOV(ep[i].p_paddr & 0xffffff);
320
fs_off = ep[i].p_offset;
321
if (xfsread(ino, p, ep[i].p_filesz))
322
return;
323
}
324
p += roundup2(ep[1].p_memsz, PAGE_SIZE);
325
bootinfo.bi_symtab = VTOP(p);
326
if (hdr.eh.e_shnum == hdr.eh.e_shstrndx + 3) {
327
fs_off = hdr.eh.e_shoff + sizeof(es[0]) *
328
(hdr.eh.e_shstrndx + 1);
329
if (xfsread(ino, &es, sizeof(es)))
330
return;
331
for (i = 0; i < 2; i++) {
332
*(Elf32_Word *)p = es[i].sh_size;
333
p += sizeof(es[i].sh_size);
334
fs_off = es[i].sh_offset;
335
if (xfsread(ino, p, es[i].sh_size))
336
return;
337
p += es[i].sh_size;
338
}
339
}
340
addr = hdr.eh.e_entry & 0xffffff;
341
bootinfo.bi_esymtab = VTOP(p);
342
} else {
343
printf("Invalid %s\n", "format");
344
return;
345
}
346
347
bootinfo.bi_kernelname = VTOP(kname);
348
bootinfo.bi_bios_dev = dsk.drive;
349
__exec((caddr_t)addr, RB_BOOTINFO | (opts & RBX_MASK),
350
MAKEBOOTDEV(dev_maj[dsk.type], dsk.slice, dsk.unit, dsk.part),
351
0, 0, 0, VTOP(&bootinfo));
352
}
353
354
static int
355
parse(void)
356
{
357
char *arg, *ep, *p, *q;
358
const char *cp;
359
unsigned int drv;
360
int c, i, j;
361
size_t k;
362
363
arg = cmd;
364
365
while ((c = *arg++)) {
366
if (c == ' ' || c == '\t' || c == '\n')
367
continue;
368
for (p = arg; *p && *p != '\n' && *p != ' ' && *p != '\t'; p++);
369
ep = p;
370
if (*p)
371
*p++ = 0;
372
if (c == '-') {
373
while ((c = *arg++)) {
374
if (c == 'P') {
375
if (*(uint8_t *)PTOV(0x496) & 0x10) {
376
cp = "yes";
377
} else {
378
opts |= OPT_SET(RBX_DUAL) |
379
OPT_SET(RBX_SERIAL);
380
cp = "no";
381
}
382
printf("Keyboard: %s\n", cp);
383
continue;
384
#if SERIAL
385
} else if (c == 'S') {
386
j = 0;
387
while ((u_int)(i = *arg++ - '0') <= 9)
388
j = j * 10 + i;
389
if (j > 0 && i == -'0') {
390
comspeed = j;
391
break;
392
}
393
/*
394
* Fall through to error below
395
* ('S' not in optstr[]).
396
*/
397
#endif
398
}
399
for (i = 0; c != optstr[i]; i++)
400
if (i == NOPT - 1)
401
return (-1);
402
opts ^= OPT_SET(flags[i]);
403
}
404
#if SERIAL
405
ioctrl = OPT_CHECK(RBX_DUAL) ? (IO_SERIAL|IO_KEYBOARD) :
406
OPT_CHECK(RBX_SERIAL) ? IO_SERIAL : IO_KEYBOARD;
407
if (DO_SIO) {
408
if (sio_init(115200 / comspeed) != 0)
409
ioctrl &= ~IO_SERIAL;
410
}
411
#endif
412
} else {
413
for (q = arg--; *q && *q != '('; q++);
414
if (*q) {
415
drv = -1;
416
if (arg[1] == ':') {
417
drv = *arg - '0';
418
if (drv > 9)
419
return (-1);
420
arg += 2;
421
}
422
if (q - arg != 2)
423
return (-1);
424
for (i = 0; arg[0] != dev_nm[i][0] ||
425
arg[1] != dev_nm[i][1]; i++)
426
if (i == NDEV - 1)
427
return (-1);
428
dsk.type = i;
429
arg += 3;
430
dsk.unit = *arg - '0';
431
if (arg[1] != ',' || dsk.unit > 9)
432
return (-1);
433
arg += 2;
434
dsk.slice = WHOLE_DISK_SLICE;
435
if (arg[1] == ',') {
436
dsk.slice = *arg - '0' + 1;
437
if (dsk.slice > NDOSPART + 1)
438
return (-1);
439
arg += 2;
440
}
441
if (arg[1] != ')')
442
return (-1);
443
dsk.part = *arg - 'a';
444
if (dsk.part > 7)
445
return (-1);
446
arg += 2;
447
if (drv == -1)
448
drv = dsk.unit;
449
dsk.drive = (dsk.type <= TYPE_MAXHARD
450
? DRV_HARD : 0) + drv;
451
dsk_meta = 0;
452
}
453
k = ep - arg;
454
if (k > 0) {
455
if (k >= sizeof(knamebuf))
456
return (-1);
457
memcpy(knamebuf, arg, k + 1);
458
kname = knamebuf;
459
}
460
}
461
arg = p;
462
}
463
return (0);
464
}
465
466
static int
467
dskread(void *buf, unsigned lba, unsigned nblk)
468
{
469
struct dos_partition *dp;
470
struct disklabel *d;
471
char *sec;
472
unsigned i;
473
uint8_t sl;
474
const char *reason;
475
476
if (!dsk_meta) {
477
sec = dmadat->secbuf;
478
dsk.start = 0;
479
if (drvread(sec, DOSBBSECTOR, 1))
480
return (-1);
481
dp = (void *)(sec + DOSPARTOFF);
482
sl = dsk.slice;
483
if (sl < BASE_SLICE) {
484
for (i = 0; i < NDOSPART; i++)
485
if (dp[i].dp_typ == DOSPTYP_386BSD &&
486
(dp[i].dp_flag & 0x80 || sl < BASE_SLICE)) {
487
sl = BASE_SLICE + i;
488
if (dp[i].dp_flag & 0x80 ||
489
dsk.slice == COMPATIBILITY_SLICE)
490
break;
491
}
492
if (dsk.slice == WHOLE_DISK_SLICE)
493
dsk.slice = sl;
494
}
495
if (sl != WHOLE_DISK_SLICE) {
496
if (sl != COMPATIBILITY_SLICE)
497
dp += sl - BASE_SLICE;
498
if (dp->dp_typ != DOSPTYP_386BSD) {
499
reason = "slice";
500
goto error;
501
}
502
dsk.start = dp->dp_start;
503
}
504
if (drvread(sec, dsk.start + LABELSECTOR, 1))
505
return (-1);
506
d = (void *)(sec + LABELOFFSET);
507
if (d->d_magic != DISKMAGIC || d->d_magic2 != DISKMAGIC) {
508
if (dsk.part != RAW_PART) {
509
reason = "label";
510
goto error;
511
}
512
} else {
513
if (!dsk.init) {
514
if (d->d_type == DTYPE_SCSI)
515
dsk.type = TYPE_DA;
516
dsk.init++;
517
}
518
if (dsk.part >= d->d_npartitions ||
519
!d->d_partitions[dsk.part].p_size) {
520
reason = "partition";
521
goto error;
522
}
523
dsk.start += d->d_partitions[dsk.part].p_offset;
524
dsk.start -= d->d_partitions[RAW_PART].p_offset;
525
}
526
}
527
return (drvread(buf, dsk.start + lba, nblk));
528
error:
529
printf("Invalid %s\n", reason);
530
return (-1);
531
}
532
533
static void
534
printf(const char *fmt,...)
535
{
536
va_list ap;
537
static char buf[10];
538
char *s;
539
unsigned u;
540
int c;
541
542
va_start(ap, fmt);
543
while ((c = *fmt++)) {
544
if (c == '%') {
545
c = *fmt++;
546
switch (c) {
547
case 'c':
548
putchar(va_arg(ap, int));
549
continue;
550
case 's':
551
for (s = va_arg(ap, char *); *s; s++)
552
putchar(*s);
553
continue;
554
case 'u':
555
u = va_arg(ap, unsigned);
556
s = buf;
557
do
558
*s++ = '0' + u % 10U;
559
while (u /= 10U);
560
while (--s >= buf)
561
putchar(*s);
562
continue;
563
}
564
}
565
putchar(c);
566
}
567
va_end(ap);
568
return;
569
}
570
571
static void
572
putchar(int c)
573
{
574
575
if (c == '\n')
576
xputc('\r');
577
xputc(c);
578
}
579
580
static int
581
drvread(void *buf, unsigned lba, unsigned nblk)
582
{
583
static unsigned c = 0x2d5c7c2f;
584
585
if (!OPT_CHECK(RBX_QUIET)) {
586
xputc(c = c << 8 | c >> 24);
587
xputc('\b');
588
}
589
v86.ctl = V86_ADDR | V86_CALLF | V86_FLAGS;
590
v86.addr = XREADORG; /* call to xread in boot1 */
591
v86.es = VTOPSEG(buf);
592
v86.eax = lba;
593
v86.ebx = VTOPOFF(buf);
594
v86.ecx = lba >> 16;
595
v86.edx = nblk << 8 | dsk.drive;
596
v86int();
597
v86.ctl = V86_FLAGS;
598
if (V86_CY(v86.efl)) {
599
printf("error %u lba %u\n", v86.eax >> 8 & 0xff, lba);
600
return (-1);
601
}
602
return (0);
603
}
604
605
static int
606
keyhit(unsigned ticks)
607
{
608
uint32_t t0, t1;
609
610
if (OPT_CHECK(RBX_NOINTR))
611
return (0);
612
t0 = 0;
613
for (;;) {
614
if (xgetc(1))
615
return (1);
616
t1 = *(uint32_t *)PTOV(0x46c);
617
if (!t0)
618
t0 = t1;
619
if ((uint32_t)(t1 - t0) >= ticks)
620
return (0);
621
}
622
}
623
624
static int
625
xputc(int c)
626
{
627
628
if (DO_KBD)
629
putc(c);
630
if (DO_SIO)
631
sio_putc(c);
632
return (c);
633
}
634
635
static int
636
getc(int fn)
637
{
638
639
v86.addr = 0x16;
640
v86.eax = fn << 8;
641
v86int();
642
return (fn == 0 ? v86.eax & 0xff : !V86_ZR(v86.efl));
643
}
644
645
static int
646
xgetc(int fn)
647
{
648
649
if (OPT_CHECK(RBX_NOINTR))
650
return (0);
651
for (;;) {
652
if (DO_KBD && getc(1))
653
return (fn ? 1 : getc(0));
654
if (DO_SIO && sio_ischar())
655
return (fn ? 1 : sio_getc());
656
if (fn)
657
return (0);
658
}
659
}
660
661