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