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