boot1.c revision 95339
1131377Stjr/* 2312335Sdelphij * Copyright (c) 1998 Robert Nordier 3131377Stjr * All rights reserved. 417651Speter * Copyright (c) 2001 Robert Drehmel 517651Speter * All rights reserved. 617651Speter * 717651Speter * Redistribution and use in source and binary forms are freely 8131377Stjr * permitted provided that the above copyright notice and this 917651Speter * paragraph and the following disclaimer are duplicated in all 1017651Speter * such forms. 11311285Sdelphij * 12311285Sdelphij * This software is provided "AS IS" and without any express or 13131377Stjr * implied warranties, including, without limitation, the implied 1417651Speter * warranties of merchantability and fitness for a particular 15131377Stjr * purpose. 16131377Stjr * 17131377Stjr */ 18131377Stjr 19131377Stjr#include <sys/cdefs.h> 20131377Stjr__FBSDID("$FreeBSD: head/sys/boot/sparc64/boot1/boot1.c 95339 2002-04-24 02:10:35Z jake $"); 21131377Stjr 2217651Speter#include <sys/param.h> 23131377Stjr#include <sys/reboot.h> 2417651Speter#include <sys/diskslice.h> 25131377Stjr#include <sys/disklabel.h> 26131377Stjr#include <sys/dirent.h> 27131377Stjr#include <machine/elf.h> 28131377Stjr#include <machine/stdarg.h> 29131377Stjr 3017651Speter#include <ufs/ffs/fs.h> 31131377Stjr#include <ufs/ufs/dinode.h> 3217651Speter 33131377Stjr#define _PATH_LOADER "/boot/loader" 34131377Stjr#define _PATH_KERNEL "/boot/kernel/kernel" 35131377Stjr 3617651Speter#define BSIZEMAX 8192 37131377Stjr 3817651Speter/* 39131377Stjr * This structure will be refined along with the addition of a bootpath 40131377Stjr * parsing routine when it is necessary to cope with bootpaths that are 41131377Stjr * not in the exact <devpath>@<controller>,<disk>:<partition> format and 42131377Stjr * for which we need to evaluate the disklabel ourselves. 43131377Stjr */ 4417651Speterstruct disk { 45131377Stjr int meta; 46131377Stjr}; 47131377Stjrstruct disk dsk; 48131377Stjr 49131377Stjrextern uint32_t _end; 50206905Sdelphij 51131377Stjrstatic char bname[1024]; /* name of the binary to load */ 52131377Stjrstatic uint32_t fs_off; 53131377Stjr 54131377Stjrint main(void); 55250224Sdelphijvoid exit(int); 56250224Sdelphijstatic void load(const char *); 57131377Stjrstatic ino_t lookup(const char *); 58131377Stjrstatic ssize_t fsread(ino_t, void *, size_t); 59131377Stjrstatic int dskread(void *, u_int64_t, int); 60157043Sdesstatic int printf(const char *, ...); 61157043Sdesstatic int putchar(int); 62157043Sdes 63131377Stjrstatic void *memcpy(void *, const void *, size_t); 64131377Stjrstatic void *memset(void *, int, size_t); 65205194Sdelphij 66131377Stjr/* 67131377Stjr * Open Firmware interface functions 68131377Stjr */ 69131377Stjrtypedef u_int64_t ofwcell_t; 70131377Stjrtypedef int32_t ofwh_t; 71131377Stjrtypedef u_int32_t u_ofwh_t; 72131377Stjrtypedef int (*ofwfp_t)(ofwcell_t []); 73205194Sdelphijofwfp_t ofw; /* the prom Open Firmware entry */ 74131377Stjr 75131377Stjrvoid ofw_init(int, int, int, int, ofwfp_t); 76131377Stjrofwh_t ofw_finddevice(const char *); 77131377Stjrofwh_t ofw_open(const char *); 78131377Stjrint ofw_getprop(ofwh_t, const char *, void *, size_t); 79131377Stjrint ofw_read(ofwh_t, void *, size_t); 80131377Stjrint ofw_write(ofwh_t, const void *, size_t); 81131377Stjrint ofw_seek(ofwh_t, u_int64_t); 82311285Sdelphij 83131377Stjrofwh_t bootdevh; 84311285Sdelphijofwh_t stdinh, stdouth; 85131377Stjrchar bootpath[64]; 86131377Stjr 87157043Sdes/* 88157043Sdes * This has to stay here, as the PROM seems to ignore the 89157043Sdes * entry point specified in the a.out header. (or elftoaout is broken) 90131377Stjr */ 91131377Stjr 92205194Sdelphijvoid 93131377Stjrofw_init(int d, int d1, int d2, int d3, ofwfp_t ofwaddr) 94131377Stjr{ 95131377Stjr ofwh_t chosenh; 96131377Stjr 97131377Stjr ofw = ofwaddr; 98131377Stjr 99131377Stjr chosenh = ofw_finddevice("/chosen"); 100131377Stjr ofw_getprop(chosenh, "stdin", &stdinh, sizeof(stdinh)); 101131377Stjr ofw_getprop(chosenh, "stdout", &stdouth, sizeof(stdouth)); 102131377Stjr ofw_getprop(chosenh, "bootpath", bootpath, sizeof(bootpath)); 103131377Stjr 104131377Stjr if ((bootdevh = ofw_open(bootpath)) == -1) { 105311285Sdelphij printf("Could not open boot device.\n"); 106131377Stjr } 107311285Sdelphij 108131377Stjr main(); 109131377Stjr d = d1 = d2 = d3; /* make GCC happy */ 110205194Sdelphij} 111131377Stjr 112205194Sdelphijofwh_t 113131377Stjrofw_finddevice(const char *name) 114131377Stjr{ 115205194Sdelphij ofwcell_t args[] = { 116131377Stjr (ofwcell_t)"finddevice", 117205194Sdelphij 1, 118131377Stjr 1, 119205194Sdelphij (ofwcell_t)name, 120311285Sdelphij 0 121131377Stjr }; 122131377Stjr 123205194Sdelphij if ((*ofw)(args)) { 124131377Stjr printf("ofw_finddevice: name=\"%s\"\n", name); 125131377Stjr return (1); 126131377Stjr } 127311285Sdelphij return (args[4]); 128131377Stjr} 129131377Stjr 130131377Stjrint 131131377Stjrofw_getprop(ofwh_t ofwh, const char *name, void *buf, size_t len) 132131377Stjr{ 13317651Speter ofwcell_t args[] = { 134131377Stjr (ofwcell_t)"getprop", 135131377Stjr 4, 136311285Sdelphij 1, 137131377Stjr (u_ofwh_t)ofwh, 138311285Sdelphij (ofwcell_t)name, 139131377Stjr (ofwcell_t)buf, 14092111Sgreen len, 141205194Sdelphij 0 142131377Stjr }; 143205194Sdelphij 144131377Stjr if ((*ofw)(args)) { 145131377Stjr printf("ofw_getprop: ofwh=0x%x buf=%p len=%u\n", 146205194Sdelphij ofwh, buf, len); 147131377Stjr return (1); 148205194Sdelphij } 149131377Stjr return (0); 150131377Stjr} 151311285Sdelphij 152131377Stjrofwh_t 153131377Stjrofw_open(const char *path) 154311285Sdelphij{ 155131377Stjr ofwcell_t args[] = { 156131377Stjr (ofwcell_t)"open", 157131377Stjr 1, 158131377Stjr 1, 159157043Sdes (ofwcell_t)path, 160157043Sdes 0 161157043Sdes }; 162157043Sdes 163157043Sdes if ((*ofw)(args)) { 164157043Sdes printf("ofw_open: path=\"%s\"\n", path); 165157043Sdes return (-1); 166131377Stjr } 167131377Stjr return (args[4]); 168131377Stjr} 169131377Stjr 170131377Stjrint 171131377Stjrofw_close(ofwh_t devh) 172131377Stjr{ 173205194Sdelphij ofwcell_t args[] = { 174205194Sdelphij (ofwcell_t)"close", 175205194Sdelphij 1, 176205194Sdelphij 0, 177205194Sdelphij (u_ofwh_t)devh 178205194Sdelphij }; 179205194Sdelphij 180205194Sdelphij if ((*ofw)(args)) { 181205194Sdelphij printf("ofw_close: devh=0x%x\n", devh); 182311285Sdelphij return (1); 183205194Sdelphij } 184205194Sdelphij return (0); 185205194Sdelphij} 186205194Sdelphij 187205194Sdelphijint 188311285Sdelphijofw_read(ofwh_t devh, void *buf, size_t len) 189205194Sdelphij{ 190205194Sdelphij ofwcell_t args[] = { 191205194Sdelphij (ofwcell_t)"read", 192205194Sdelphij 4, 193311285Sdelphij 1, 194205194Sdelphij (u_ofwh_t)devh, 195205194Sdelphij (ofwcell_t)buf, 196205194Sdelphij len, 197205194Sdelphij 0 198131377Stjr }; 199311285Sdelphij 200205194Sdelphij if ((*ofw)(args)) { 201131377Stjr printf("ofw_read: devh=0x%x buf=%p len=%u\n", devh, buf, len); 202131377Stjr return (1); 203131377Stjr } 204131377Stjr return (0); 205311285Sdelphij} 206131377Stjr 207131377Stjrint 208131377Stjrofw_write(ofwh_t devh, const void *buf, size_t len) 209131377Stjr{ 210205194Sdelphij ofwcell_t args[] = { 211205194Sdelphij (ofwcell_t)"write", 212205194Sdelphij 3, 213131377Stjr 1, 214131377Stjr (u_ofwh_t)devh, 215131377Stjr (ofwcell_t)buf, 216311285Sdelphij len, 217131377Stjr 0 218311285Sdelphij }; 219205194Sdelphij 220205194Sdelphij if ((*ofw)(args)) { 221131377Stjr printf("ofw_write: devh=0x%x buf=%p len=%u\n", devh, buf, len); 222131377Stjr return (1); 223311285Sdelphij } 224131377Stjr return (0); 225131377Stjr} 226131377Stjr 227131377Stjrint 228131377Stjrofw_seek(ofwh_t devh, u_int64_t off) 229131377Stjr{ 230205194Sdelphij ofwcell_t args[] = { 231131377Stjr (ofwcell_t)"seek", 232131377Stjr 4, 233131377Stjr 1, 234311285Sdelphij (u_ofwh_t)devh, 235131377Stjr off >> 32, 236131377Stjr off, 237131377Stjr 0 238131377Stjr }; 239131377Stjr 240311285Sdelphij if ((*ofw)(args)) { 241311285Sdelphij printf("ofw_seek: devh=0x%x off=0x%lx\n", devh, off); 242311285Sdelphij return (1); 243131377Stjr } 244131377Stjr return (0); 245131377Stjr} 246311285Sdelphij 247131377Stjrstatic int 248311285Sdelphijstrcmp(const char *s1, const char *s2) 249131377Stjr{ 250131377Stjr for (; *s1 == *s2 && *s1; s1++, s2++) 251131377Stjr ; 252131377Stjr return ((u_char)*s1 - (u_char)*s2); 253131377Stjr} 254311285Sdelphij 255311285Sdelphijstatic void * 256311285Sdelphijmemset(void *dst, int val, size_t len) 257131377Stjr{ 258131377Stjr void *ret; 259131377Stjr 260311285Sdelphij ret = dst; 261131377Stjr while (len) { 262311285Sdelphij *((char *)dst)++ = val; 263131377Stjr len--; 264131377Stjr } 265131377Stjr return (ret); 266131377Stjr} 267205194Sdelphij 268131377Stjrstatic int 269131377Stjrfsfind(const char *name, ino_t * ino) 270131377Stjr{ 271131377Stjr char buf[DEV_BSIZE]; 272131377Stjr struct dirent *d; 273131377Stjr char *s; 274131377Stjr ssize_t n; 275131377Stjr 276131377Stjr fs_off = 0; 277205194Sdelphij while ((n = fsread(*ino, buf, DEV_BSIZE)) > 0) { 278131377Stjr for (s = buf; s < buf + DEV_BSIZE;) { 279131377Stjr d = (void *)s; 280131377Stjr if (!strcmp(name, d->d_name)) { 281131377Stjr *ino = d->d_fileno; 282131377Stjr return (d->d_type); 28317651Speter } 28417651Speter s += d->d_reclen; 285131377Stjr } 286131377Stjr } 287131377Stjr return (0); 288131377Stjr} 289131377Stjr 290131377Stjrstatic void 29117651Speterputc(int c) 292131377Stjr{ 293131377Stjr char d; 294131377Stjr 295131377Stjr d = c; 296131377Stjr ofw_write(stdouth, &d, 1); 297131377Stjr} 298131377Stjr 299311285Sdelphijint 300311285Sdelphijmain(void) 301131377Stjr{ 302131377Stjr if (bname[0] == '\0') 303131377Stjr memcpy(bname, _PATH_LOADER, sizeof(_PATH_LOADER)); 304131377Stjr 305131377Stjr printf(" \n>> FreeBSD/sparc64 boot block\n" 306131377Stjr " Boot path: %s\n" 30717651Speter " Boot loader: %s\n", bootpath, _PATH_LOADER); 308131377Stjr load(bname); 309131377Stjr return (1); 310131377Stjr} 311131377Stjr 312131377Stjrstatic void 313205194Sdelphijload(const char *fname) 314131377Stjr{ 315131377Stjr Elf64_Ehdr eh; 316131377Stjr Elf64_Phdr ph; 317131377Stjr caddr_t p; 318131377Stjr ino_t ino; 319131377Stjr int i; 320131377Stjr 321131377Stjr if ((ino = lookup(fname)) == 0) { 322131377Stjr printf("File %s not found\n", fname); 323131377Stjr return; 324 } 325 if (fsread(ino, &eh, sizeof(eh)) != sizeof(eh)) { 326 printf("Can't read elf header\n"); 327 return; 328 } 329 if (!IS_ELF(eh)) { 330 printf("Not an ELF file\n"); 331 return; 332 } 333 for (i = 0; i < eh.e_phnum; i++) { 334 fs_off = eh.e_phoff + i * eh.e_phentsize; 335 if (fsread(ino, &ph, sizeof(ph)) != sizeof(ph)) { 336 printf("Can't read program header %d\n", i); 337 return; 338 } 339 if (ph.p_type != PT_LOAD) 340 continue; 341 fs_off = ph.p_offset; 342 p = (caddr_t)ph.p_vaddr; 343 if (fsread(ino, p, ph.p_filesz) != ph.p_filesz) { 344 printf("Can't read content of section %d\n", i); 345 return; 346 } 347 if (ph.p_filesz != ph.p_memsz) 348 memset(p + ph.p_filesz, 0, ph.p_memsz - ph.p_filesz); 349 } 350 ofw_close(bootdevh); 351 (*(void (*)(int, int, int, int, ofwfp_t))eh.e_entry)(0, 0, 0, 0, ofw); 352} 353 354static ino_t 355lookup(const char *path) 356{ 357 char name[MAXNAMLEN + 1]; 358 const char *s; 359 ino_t ino; 360 ssize_t n; 361 int dt; 362 363 ino = ROOTINO; 364 dt = DT_DIR; 365 name[0] = '/'; 366 name[1] = '\0'; 367 for (;;) { 368 if (*path == '/') 369 path++; 370 if (!*path) 371 break; 372 for (s = path; *s && *s != '/'; s++) 373 ; 374 if ((n = s - path) > MAXNAMLEN) 375 return (0); 376 memcpy(name, path, n); 377 name[n] = 0; 378 if (dt != DT_DIR) { 379 printf("%s: not a directory.\n", name); 380 return (0); 381 } 382 if ((dt = fsfind(name, &ino)) <= 0) 383 break; 384 path = s; 385 } 386 return (dt == DT_REG ? ino : 0); 387} 388 389static ssize_t 390fsread(ino_t inode, void *buf, size_t nbyte) 391{ 392 static struct fs fs; 393 static struct dinode din; 394 static char blkbuf[BSIZEMAX]; 395 static ufs_daddr_t indbuf[BSIZEMAX / sizeof(ufs_daddr_t)]; 396 static ino_t inomap; 397 static ufs_daddr_t blkmap, indmap; 398 static unsigned int fsblks; 399 char *s; 400 ufs_daddr_t lbn, addr; 401 size_t n, nb, off; 402 403 if (!dsk.meta) { 404 inomap = 0; 405 if (dskread(blkbuf, SBOFF / DEV_BSIZE, SBSIZE / DEV_BSIZE)) 406 return (-1); 407 memcpy(&fs, blkbuf, sizeof(fs)); 408 if (fs.fs_magic != FS_MAGIC) { 409 printf("Not ufs\n"); 410 return (-1); 411 } 412 fsblks = fs.fs_bsize >> DEV_BSHIFT; 413 dsk.meta++; 414 } 415 if (!inode) 416 return (0); 417 if (inomap != inode) { 418 if (dskread(blkbuf, fsbtodb(&fs, ino_to_fsba(&fs, inode)), 419 fsblks)) 420 return (-1); 421 din = ((struct dinode *)blkbuf)[inode % INOPB(&fs)]; 422 inomap = inode; 423 fs_off = 0; 424 blkmap = indmap = 0; 425 } 426 s = buf; 427 if (nbyte > (n = din.di_size - fs_off)) 428 nbyte = n; 429 nb = nbyte; 430 while (nb) { 431 lbn = lblkno(&fs, fs_off); 432 if (lbn < NDADDR) 433 addr = din.di_db[lbn]; 434 else { 435 if (indmap != din.di_ib[0]) { 436 if (dskread(indbuf, fsbtodb(&fs, din.di_ib[0]), 437 fsblks)) 438 return (-1); 439 indmap = din.di_ib[0]; 440 } 441 addr = indbuf[(lbn - NDADDR) % NINDIR(&fs)]; 442 } 443 n = dblksize(&fs, &din, lbn); 444 if (blkmap != addr) { 445 if (dskread(blkbuf, fsbtodb(&fs, addr), 446 n >> DEV_BSHIFT)) { 447 return (-1); 448 } 449 blkmap = addr; 450 } 451 off = blkoff(&fs, fs_off); 452 n -= off; 453 if (n > nb) 454 n = nb; 455 memcpy(s, blkbuf + off, n); 456 s += n; 457 fs_off += n; 458 nb -= n; 459 } 460 return (nbyte); 461} 462 463static int 464dskread(void *buf, u_int64_t lba, int nblk) 465{ 466 /* 467 * The OpenFirmware should open the correct partition for us. 468 * That means, if we read from offset zero on an open instance handle, 469 * we should read from offset zero of that partition. 470 */ 471 ofw_seek(bootdevh, lba * DEV_BSIZE); 472 ofw_read(bootdevh, buf, nblk * DEV_BSIZE); 473 return (0); 474} 475 476static int 477printf(const char *fmt,...) 478{ 479 static const char digits[16] = "0123456789abcdef"; 480 va_list ap; 481 char buf[10]; 482 char *s; 483 unsigned long int r, u; 484 int c, longp; 485 486 va_start(ap, fmt); 487 longp = 0; 488 while ((c = *fmt++)) { 489 if (c == '%' || longp) { 490 if (c == '%') 491 c = *fmt++; 492 switch (c) { 493 case 'c': 494 if (longp) 495 break; 496 putchar(va_arg(ap, int)); 497 continue; 498 case 's': 499 if (longp) 500 break; 501 for (s = va_arg(ap, char *); *s; s++) 502 putchar(*s); 503 continue; 504 case 'p': 505 if (longp) 506 break; 507 if (c == 'p') { 508 putchar('0'); 509 putchar('x'); 510 } 511 case 'u': 512 case 'x': 513 r = c == 'u' ? 10U : 16U; 514 u = (c == 'p' || longp) ? 515 va_arg(ap, unsigned long) : 516 va_arg(ap, unsigned int); 517 s = buf; 518 do 519 *s++ = digits[u % r]; 520 while (u /= r); 521 while (--s >= buf) 522 putchar(*s); 523 longp = 0; 524 continue; 525 case 'l': 526 if (longp) 527 break; 528 longp = 1; 529 continue; 530 } 531 longp = 0; 532 } 533 putchar(c); 534 } 535 va_end(ap); 536 return (0); 537} 538 539static int 540putchar(int c) 541{ 542 if (c == '\n') 543 putc('\r'); 544 putc(c); 545 return (c); 546} 547 548static void * 549memcpy(void *dst, const void *src, size_t size) 550{ 551 const char *s; 552 char *d; 553 554 for (d = dst, s = src; size; size--) 555 *d++ = *s++; 556 return (dst); 557} 558