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