boot1.c revision 95342
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 19#include <sys/cdefs.h> 20__FBSDID("$FreeBSD: head/sys/boot/sparc64/boot1/boot1.c 95342 2002-04-24 02:50:59Z jake $"); 21 22#include <sys/param.h> 23#include <sys/reboot.h> 24#include <sys/diskslice.h> 25#include <sys/disklabel.h> 26#include <sys/dirent.h> 27#include <machine/elf.h> 28#include <machine/stdarg.h> 29 30#include <ufs/ffs/fs.h> 31#include <ufs/ufs/dinode.h> 32 33#define _PATH_LOADER "/boot/loader" 34#define _PATH_KERNEL "/boot/kernel/kernel" 35 36#define BSIZEMAX 8192 37 38/* 39 * This structure will be refined along with the addition of a bootpath 40 * parsing routine when it is necessary to cope with bootpaths that are 41 * not in the exact <devpath>@<controller>,<disk>:<partition> format and 42 * for which we need to evaluate the disklabel ourselves. 43 */ 44struct disk { 45 int meta; 46}; 47struct disk dsk; 48 49extern uint32_t _end; 50 51static char bname[1024]; /* name of the binary to load */ 52static uint32_t fs_off; 53 54int main(void); 55static void exit(int); 56static void load(const char *); 57static ino_t lookup(const char *); 58static ssize_t fsread(ino_t, void *, size_t); 59static int dskread(void *, u_int64_t, int); 60static int printf(const char *, ...); 61static int putchar(int); 62 63static void bcopy(const void *src, void *dst, size_t len); 64static void bzero(void *b, size_t len); 65 66/* 67 * Open Firmware interface functions 68 */ 69typedef u_int64_t ofwcell_t; 70typedef int32_t ofwh_t; 71typedef u_int32_t u_ofwh_t; 72typedef int (*ofwfp_t)(ofwcell_t []); 73ofwfp_t ofw; /* the prom Open Firmware entry */ 74 75void ofw_init(int, int, int, int, ofwfp_t); 76ofwh_t ofw_finddevice(const char *); 77ofwh_t ofw_open(const char *); 78int ofw_getprop(ofwh_t, const char *, void *, size_t); 79int ofw_read(ofwh_t, void *, size_t); 80int ofw_write(ofwh_t, const void *, size_t); 81int ofw_seek(ofwh_t, u_int64_t); 82 83ofwh_t bootdevh; 84ofwh_t stdinh, stdouth; 85char bootpath[64]; 86 87/* 88 * This has to stay here, as the PROM seems to ignore the 89 * entry point specified in the a.out header. (or elftoaout is broken) 90 */ 91 92void 93ofw_init(int d, int d1, int d2, int d3, ofwfp_t ofwaddr) 94{ 95 ofwh_t chosenh; 96 97 ofw = ofwaddr; 98 99 chosenh = ofw_finddevice("/chosen"); 100 ofw_getprop(chosenh, "stdin", &stdinh, sizeof(stdinh)); 101 ofw_getprop(chosenh, "stdout", &stdouth, sizeof(stdouth)); 102 ofw_getprop(chosenh, "bootpath", bootpath, sizeof(bootpath)); 103 104 if ((bootdevh = ofw_open(bootpath)) == -1) { 105 printf("Could not open boot device.\n"); 106 } 107 108 exit(main()); 109} 110 111ofwh_t 112ofw_finddevice(const char *name) 113{ 114 ofwcell_t args[] = { 115 (ofwcell_t)"finddevice", 116 1, 117 1, 118 (ofwcell_t)name, 119 0 120 }; 121 122 if ((*ofw)(args)) { 123 printf("ofw_finddevice: name=\"%s\"\n", name); 124 return (1); 125 } 126 return (args[4]); 127} 128 129int 130ofw_getprop(ofwh_t ofwh, const char *name, void *buf, size_t len) 131{ 132 ofwcell_t args[] = { 133 (ofwcell_t)"getprop", 134 4, 135 1, 136 (u_ofwh_t)ofwh, 137 (ofwcell_t)name, 138 (ofwcell_t)buf, 139 len, 140 0 141 }; 142 143 if ((*ofw)(args)) { 144 printf("ofw_getprop: ofwh=0x%x buf=%p len=%u\n", 145 ofwh, buf, len); 146 return (1); 147 } 148 return (0); 149} 150 151ofwh_t 152ofw_open(const char *path) 153{ 154 ofwcell_t args[] = { 155 (ofwcell_t)"open", 156 1, 157 1, 158 (ofwcell_t)path, 159 0 160 }; 161 162 if ((*ofw)(args)) { 163 printf("ofw_open: path=\"%s\"\n", path); 164 return (-1); 165 } 166 return (args[4]); 167} 168 169int 170ofw_close(ofwh_t devh) 171{ 172 ofwcell_t args[] = { 173 (ofwcell_t)"close", 174 1, 175 0, 176 (u_ofwh_t)devh 177 }; 178 179 if ((*ofw)(args)) { 180 printf("ofw_close: devh=0x%x\n", devh); 181 return (1); 182 } 183 return (0); 184} 185 186int 187ofw_read(ofwh_t devh, void *buf, size_t len) 188{ 189 ofwcell_t args[] = { 190 (ofwcell_t)"read", 191 4, 192 1, 193 (u_ofwh_t)devh, 194 (ofwcell_t)buf, 195 len, 196 0 197 }; 198 199 if ((*ofw)(args)) { 200 printf("ofw_read: devh=0x%x buf=%p len=%u\n", devh, buf, len); 201 return (1); 202 } 203 return (0); 204} 205 206int 207ofw_write(ofwh_t devh, const void *buf, size_t len) 208{ 209 ofwcell_t args[] = { 210 (ofwcell_t)"write", 211 3, 212 1, 213 (u_ofwh_t)devh, 214 (ofwcell_t)buf, 215 len, 216 0 217 }; 218 219 if ((*ofw)(args)) { 220 printf("ofw_write: devh=0x%x buf=%p len=%u\n", devh, buf, len); 221 return (1); 222 } 223 return (0); 224} 225 226int 227ofw_seek(ofwh_t devh, u_int64_t off) 228{ 229 ofwcell_t args[] = { 230 (ofwcell_t)"seek", 231 4, 232 1, 233 (u_ofwh_t)devh, 234 off >> 32, 235 off, 236 0 237 }; 238 239 if ((*ofw)(args)) { 240 printf("ofw_seek: devh=0x%x off=0x%lx\n", devh, off); 241 return (1); 242 } 243 return (0); 244} 245 246void 247ofw_exit(void) 248{ 249 ofwcell_t args[3]; 250 251 args[0] = (ofwcell_t)"exit"; 252 args[1] = 0; 253 args[2] = 0; 254 255 (*ofw)(args); 256} 257 258static void 259bcopy(const void *dst, void *src, size_t len) 260{ 261 const char *d = dst; 262 char *s = src; 263 264 while (len-- != 0) 265 *s++ = *d++; 266} 267 268static void 269bzero(void *b, size_t len) 270{ 271 char *p = b; 272 273 while (len-- != 0) 274 *p++ = 0; 275} 276 277static int 278strcmp(const char *s1, const char *s2) 279{ 280 for (; *s1 == *s2 && *s1; s1++, s2++) 281 ; 282 return ((u_char)*s1 - (u_char)*s2); 283} 284 285static int 286fsfind(const char *name, ino_t * ino) 287{ 288 char buf[DEV_BSIZE]; 289 struct dirent *d; 290 char *s; 291 ssize_t n; 292 293 fs_off = 0; 294 while ((n = fsread(*ino, buf, DEV_BSIZE)) > 0) { 295 for (s = buf; s < buf + DEV_BSIZE;) { 296 d = (void *)s; 297 if (!strcmp(name, d->d_name)) { 298 *ino = d->d_fileno; 299 return (d->d_type); 300 } 301 s += d->d_reclen; 302 } 303 } 304 return (0); 305} 306 307static void 308putc(int c) 309{ 310 char d; 311 312 d = c; 313 ofw_write(stdouth, &d, 1); 314} 315 316int 317main(void) 318{ 319 if (bname[0] == '\0') 320 bcopy(_PATH_LOADER, bname, sizeof(_PATH_LOADER)); 321 322 printf(" \n>> FreeBSD/sparc64 boot block\n" 323 " Boot path: %s\n" 324 " Boot loader: %s\n", bootpath, _PATH_LOADER); 325 load(bname); 326 return (1); 327} 328 329static void 330exit(int code) 331{ 332 333 ofw_exit(); 334} 335 336static void 337load(const char *fname) 338{ 339 Elf64_Ehdr eh; 340 Elf64_Phdr ph; 341 caddr_t p; 342 ino_t ino; 343 int i; 344 345 if ((ino = lookup(fname)) == 0) { 346 printf("File %s not found\n", fname); 347 return; 348 } 349 if (fsread(ino, &eh, sizeof(eh)) != sizeof(eh)) { 350 printf("Can't read elf header\n"); 351 return; 352 } 353 if (!IS_ELF(eh)) { 354 printf("Not an ELF file\n"); 355 return; 356 } 357 for (i = 0; i < eh.e_phnum; i++) { 358 fs_off = eh.e_phoff + i * eh.e_phentsize; 359 if (fsread(ino, &ph, sizeof(ph)) != sizeof(ph)) { 360 printf("Can't read program header %d\n", i); 361 return; 362 } 363 if (ph.p_type != PT_LOAD) 364 continue; 365 fs_off = ph.p_offset; 366 p = (caddr_t)ph.p_vaddr; 367 if (fsread(ino, p, ph.p_filesz) != ph.p_filesz) { 368 printf("Can't read content of section %d\n", i); 369 return; 370 } 371 if (ph.p_filesz != ph.p_memsz) 372 bzero(p + ph.p_filesz, ph.p_memsz - ph.p_filesz); 373 } 374 ofw_close(bootdevh); 375 (*(void (*)(int, int, int, int, ofwfp_t))eh.e_entry)(0, 0, 0, 0, ofw); 376} 377 378static ino_t 379lookup(const char *path) 380{ 381 char name[MAXNAMLEN + 1]; 382 const char *s; 383 ino_t ino; 384 ssize_t n; 385 int dt; 386 387 ino = ROOTINO; 388 dt = DT_DIR; 389 name[0] = '/'; 390 name[1] = '\0'; 391 for (;;) { 392 if (*path == '/') 393 path++; 394 if (!*path) 395 break; 396 for (s = path; *s && *s != '/'; s++) 397 ; 398 if ((n = s - path) > MAXNAMLEN) 399 return (0); 400 bcopy(path, name, n); 401 name[n] = 0; 402 if (dt != DT_DIR) { 403 printf("%s: not a directory.\n", name); 404 return (0); 405 } 406 if ((dt = fsfind(name, &ino)) <= 0) 407 break; 408 path = s; 409 } 410 return (dt == DT_REG ? ino : 0); 411} 412 413static ssize_t 414fsread(ino_t inode, void *buf, size_t nbyte) 415{ 416 static struct fs fs; 417 static struct dinode din; 418 static char blkbuf[BSIZEMAX]; 419 static ufs_daddr_t indbuf[BSIZEMAX / sizeof(ufs_daddr_t)]; 420 static ino_t inomap; 421 static ufs_daddr_t blkmap, indmap; 422 static unsigned int fsblks; 423 char *s; 424 ufs_daddr_t lbn, addr; 425 size_t n, nb, off; 426 427 if (!dsk.meta) { 428 inomap = 0; 429 if (dskread(blkbuf, SBOFF / DEV_BSIZE, SBSIZE / DEV_BSIZE)) 430 return (-1); 431 bcopy(blkbuf, &fs, sizeof(fs)); 432 if (fs.fs_magic != FS_MAGIC) { 433 printf("Not ufs\n"); 434 return (-1); 435 } 436 fsblks = fs.fs_bsize >> DEV_BSHIFT; 437 dsk.meta++; 438 } 439 if (!inode) 440 return (0); 441 if (inomap != inode) { 442 if (dskread(blkbuf, fsbtodb(&fs, ino_to_fsba(&fs, inode)), 443 fsblks)) 444 return (-1); 445 bcopy(blkbuf + ((inode % INOPB(&fs)) * sizeof(din)), &din, 446 sizeof(din)); 447 inomap = inode; 448 fs_off = 0; 449 blkmap = indmap = 0; 450 } 451 s = buf; 452 if (nbyte > (n = din.di_size - fs_off)) 453 nbyte = n; 454 nb = nbyte; 455 while (nb) { 456 lbn = lblkno(&fs, fs_off); 457 if (lbn < NDADDR) 458 addr = din.di_db[lbn]; 459 else { 460 if (indmap != din.di_ib[0]) { 461 if (dskread(indbuf, fsbtodb(&fs, din.di_ib[0]), 462 fsblks)) 463 return (-1); 464 indmap = din.di_ib[0]; 465 } 466 addr = indbuf[(lbn - NDADDR) % NINDIR(&fs)]; 467 } 468 n = dblksize(&fs, &din, lbn); 469 if (blkmap != addr) { 470 if (dskread(blkbuf, fsbtodb(&fs, addr), 471 n >> DEV_BSHIFT)) { 472 return (-1); 473 } 474 blkmap = addr; 475 } 476 off = blkoff(&fs, fs_off); 477 n -= off; 478 if (n > nb) 479 n = nb; 480 bcopy(blkbuf + off, s, n); 481 s += n; 482 fs_off += n; 483 nb -= n; 484 } 485 return (nbyte); 486} 487 488static int 489dskread(void *buf, u_int64_t lba, int nblk) 490{ 491 /* 492 * The OpenFirmware should open the correct partition for us. 493 * That means, if we read from offset zero on an open instance handle, 494 * we should read from offset zero of that partition. 495 */ 496 ofw_seek(bootdevh, lba * DEV_BSIZE); 497 ofw_read(bootdevh, buf, nblk * DEV_BSIZE); 498 return (0); 499} 500 501static int 502printf(const char *fmt,...) 503{ 504 static const char digits[16] = "0123456789abcdef"; 505 va_list ap; 506 char buf[10]; 507 char *s; 508 unsigned long int r, u; 509 int c, longp; 510 511 va_start(ap, fmt); 512 longp = 0; 513 while ((c = *fmt++)) { 514 if (c == '%' || longp) { 515 if (c == '%') 516 c = *fmt++; 517 switch (c) { 518 case 'c': 519 if (longp) 520 break; 521 putchar(va_arg(ap, int)); 522 continue; 523 case 's': 524 if (longp) 525 break; 526 for (s = va_arg(ap, char *); *s; s++) 527 putchar(*s); 528 continue; 529 case 'p': 530 if (longp) 531 break; 532 if (c == 'p') { 533 putchar('0'); 534 putchar('x'); 535 } 536 case 'u': 537 case 'x': 538 r = c == 'u' ? 10U : 16U; 539 u = (c == 'p' || longp) ? 540 va_arg(ap, unsigned long) : 541 va_arg(ap, unsigned int); 542 s = buf; 543 do 544 *s++ = digits[u % r]; 545 while (u /= r); 546 while (--s >= buf) 547 putchar(*s); 548 longp = 0; 549 continue; 550 case 'l': 551 if (longp) 552 break; 553 longp = 1; 554 continue; 555 } 556 longp = 0; 557 } 558 putchar(c); 559 } 560 va_end(ap); 561 return (0); 562} 563 564static int 565putchar(int c) 566{ 567 if (c == '\n') 568 putc('\r'); 569 putc(c); 570 return (c); 571} 572