main.c revision 165325
1/*- 2 * Initial implementation: 3 * Copyright (c) 2001 Robert Drehmel 4 * All rights reserved. 5 * 6 * As long as the above copyright statement and this notice remain 7 * unchanged, you can do what ever you want with this file. 8 */ 9 10#include <sys/cdefs.h> 11__FBSDID("$FreeBSD: head/sys/boot/sparc64/loader/main.c 165325 2006-12-18 07:35:14Z kmacy $"); 12/* 13 * FreeBSD/sparc64 kernel loader - machine dependent part 14 * 15 * - implements copyin and readin functions that map kernel 16 * pages on demand. The machine independent code does not 17 * know the size of the kernel early enough to pre-enter 18 * TTEs and install just one 4MB mapping seemed to limiting 19 * to me. 20 */ 21 22#include <stand.h> 23#include <sys/exec.h> 24#include <sys/param.h> 25#include <sys/queue.h> 26#include <sys/linker.h> 27#include <sys/types.h> 28 29#include <vm/vm.h> 30#include <machine/asi.h> 31#include <machine/atomic.h> 32#include <machine/cpufunc.h> 33#include <machine/elf.h> 34#include <machine/lsu.h> 35#include <machine/metadata.h> 36#include <machine/tte.h> 37#include <machine/upa.h> 38 39#include "bootstrap.h" 40#include "libofw.h" 41#include "dev_net.h" 42 43enum { 44 HEAPVA = 0x800000, 45 HEAPSZ = 0x1000000, 46 LOADSZ = 0x1000000 /* for kernel and modules */ 47}; 48 49struct memory_slice { 50 vm_offset_t pstart; 51 vm_offset_t size; 52}; 53 54struct mmu_ops { 55 void (*tlb_init)(void); 56 int (*mmu_mapin)(vm_offset_t va, vm_size_t len); 57} *mmu_ops; 58 59 60typedef void kernel_entry_t(vm_offset_t mdp, u_long o1, u_long o2, u_long o3, 61 void *openfirmware); 62 63extern void itlb_enter(u_long vpn, u_long data); 64extern void dtlb_enter(u_long vpn, u_long data); 65extern vm_offset_t itlb_va_to_pa(vm_offset_t); 66extern vm_offset_t dtlb_va_to_pa(vm_offset_t); 67extern vm_offset_t md_load(char *, vm_offset_t *); 68static int __elfN(exec)(struct preloaded_file *); 69static int sparc64_autoload(void); 70static int mmu_mapin_sun4u(vm_offset_t, vm_size_t); 71static int mmu_mapin_sun4v(vm_offset_t, vm_size_t); 72static void tlb_init_sun4u(void); 73static void tlb_init_sun4v(void); 74 75struct mmu_ops mmu_ops_sun4u = { tlb_init_sun4u, mmu_mapin_sun4u }; 76struct mmu_ops mmu_ops_sun4v = { tlb_init_sun4v, mmu_mapin_sun4v }; 77 78extern char bootprog_name[], bootprog_rev[], bootprog_date[], bootprog_maker[]; 79 80/* sun4u */ 81struct tlb_entry *dtlb_store; 82struct tlb_entry *itlb_store; 83int dtlb_slot; 84int itlb_slot; 85int dtlb_slot_max; 86int itlb_slot_max; 87 88/* sun4v */ 89struct tlb_entry *tlb_store; 90int is_sun4v = 0; 91/* 92 * no direct TLB access on sun4v 93 * we somewhat arbitrarily declare enough 94 * slots to cover a 4GB AS with 4MB pages 95 */ 96#define SUN4V_TLB_SLOT_MAX (1 << 10) 97 98 99extern char bootprog_name[], bootprog_rev[], bootprog_date[], bootprog_maker[]; 100 101struct tlb_entry *dtlb_store; 102struct tlb_entry *itlb_store; 103 104int dtlb_slot; 105int itlb_slot; 106int dtlb_slot_max; 107int itlb_slot_max; 108 109vm_offset_t curkva = 0; 110vm_offset_t heapva; 111phandle_t pmemh; /* OFW memory handle */ 112 113struct memory_slice memslices[18]; 114 115/* 116 * Machine dependent structures that the machine independent 117 * loader part uses. 118 */ 119struct devsw *devsw[] = { 120#ifdef LOADER_DISK_SUPPORT 121 &ofwdisk, 122#endif 123#ifdef LOADER_NET_SUPPORT 124 &netdev, 125#endif 126 0 127}; 128struct arch_switch archsw; 129 130struct file_format sparc64_elf = { 131 __elfN(loadfile), 132 __elfN(exec) 133}; 134struct file_format *file_formats[] = { 135 &sparc64_elf, 136 0 137}; 138struct fs_ops *file_system[] = { 139#ifdef LOADER_UFS_SUPPORT 140 &ufs_fsops, 141#endif 142#ifdef LOADER_CD9660_SUPPORT 143 &cd9660_fsops, 144#endif 145#ifdef LOADER_ZIP_SUPPORT 146 &zipfs_fsops, 147#endif 148#ifdef LOADER_GZIP_SUPPORT 149 &gzipfs_fsops, 150#endif 151#ifdef LOADER_BZIP2_SUPPORT 152 &bzipfs_fsops, 153#endif 154#ifdef LOADER_NFS_SUPPORT 155 &nfs_fsops, 156#endif 157#ifdef LOADER_TFTP_SUPPORT 158 &tftp_fsops, 159#endif 160 0 161}; 162struct netif_driver *netif_drivers[] = { 163#ifdef LOADER_NET_SUPPORT 164 &ofwnet, 165#endif 166 0 167}; 168 169extern struct console ofwconsole; 170struct console *consoles[] = { 171 &ofwconsole, 172 0 173}; 174 175#ifdef LOADER_DEBUG 176static int 177watch_phys_set_mask(vm_offset_t pa, u_long mask) 178{ 179 u_long lsucr; 180 181 stxa(AA_DMMU_PWPR, ASI_DMMU, pa & (((2UL << 38) - 1) << 3)); 182 lsucr = ldxa(0, ASI_LSU_CTL_REG); 183 lsucr = ((lsucr | LSU_PW) & ~LSU_PM_MASK) | 184 (mask << LSU_PM_SHIFT); 185 stxa(0, ASI_LSU_CTL_REG, lsucr); 186 return (0); 187} 188 189static int 190watch_phys_set(vm_offset_t pa, int sz) 191{ 192 u_long off; 193 194 off = (u_long)pa & 7; 195 /* Test for misaligned watch points. */ 196 if (off + sz > 8) 197 return (-1); 198 return (watch_phys_set_mask(pa, ((1 << sz) - 1) << off)); 199} 200 201 202static int 203watch_virt_set_mask(vm_offset_t va, u_long mask) 204{ 205 u_long lsucr; 206 207 stxa(AA_DMMU_VWPR, ASI_DMMU, va & (((2UL << 41) - 1) << 3)); 208 lsucr = ldxa(0, ASI_LSU_CTL_REG); 209 lsucr = ((lsucr | LSU_VW) & ~LSU_VM_MASK) | 210 (mask << LSU_VM_SHIFT); 211 stxa(0, ASI_LSU_CTL_REG, lsucr); 212 return (0); 213} 214 215static int 216watch_virt_set(vm_offset_t va, int sz) 217{ 218 u_long off; 219 220 off = (u_long)va & 7; 221 /* Test for misaligned watch points. */ 222 if (off + sz > 8) 223 return (-1); 224 return (watch_virt_set_mask(va, ((1 << sz) - 1) << off)); 225} 226#endif 227 228/* 229 * archsw functions 230 */ 231static int 232sparc64_autoload(void) 233{ 234 printf("nothing to autoload yet.\n"); 235 return 0; 236} 237 238static ssize_t 239sparc64_readin(const int fd, vm_offset_t va, const size_t len) 240{ 241 mmu_ops->mmu_mapin(va, len); 242 return read(fd, (void *)va, len); 243} 244 245static ssize_t 246sparc64_copyin(const void *src, vm_offset_t dest, size_t len) 247{ 248 mmu_ops->mmu_mapin(dest, len); 249 memcpy((void *)dest, src, len); 250 return len; 251} 252 253static void 254sparc64_maphint(vm_offset_t va, size_t len) 255{ 256 vm_paddr_t pa; 257 vm_offset_t mva; 258 size_t size; 259 int i, ret, free_excess = 0; 260 261 if (!is_sun4v) 262 return; 263 264 if (tlb_store[va >> 22].te_pa != -1) 265 return; 266 267 /* round up to nearest 4MB page */ 268 size = (len + PAGE_MASK_4M) & ~PAGE_MASK_4M; 269#if 0 270 pa = (vm_offset_t)OF_alloc_phys(PAGE_SIZE_256M, PAGE_SIZE_256M); 271 272 if (pa != -1) 273 free_excess = 1; 274 else 275#endif 276 pa = (vm_offset_t)OF_alloc_phys(size, PAGE_SIZE_256M); 277 if (pa == -1) 278 pa = (vm_offset_t)OF_alloc_phys(size, PAGE_SIZE_4M); 279 if (pa == -1) 280 panic("out of memory"); 281 282 for (i = 0; i < size; i += PAGE_SIZE_4M) { 283 mva = (vm_offset_t)OF_claim_virt(va + i, PAGE_SIZE_4M, 0); 284 if (mva != (va + i)) { 285 panic("can't claim virtual page " 286 "(wanted %#lx, got %#lx)", 287 va, mva); 288 } 289 290 tlb_store[mva >> 22].te_pa = pa + i; 291 if ((ret = OF_map_phys(-1, PAGE_SIZE_4M, mva, pa + i)) != 0) 292 printf("OF_map_phys failed: %d\n", ret); 293 } 294 if (free_excess) 295 OF_release_phys((vm_offset_t)pa, PAGE_SIZE_256M); 296} 297 298 299/* 300 * other MD functions 301 */ 302static int 303__elfN(exec)(struct preloaded_file *fp) 304{ 305 struct file_metadata *fmp; 306 vm_offset_t mdp; 307 Elf_Addr entry; 308 Elf_Ehdr *e; 309 int error; 310 311 if ((fmp = file_findmetadata(fp, MODINFOMD_ELFHDR)) == 0) { 312 return EFTYPE; 313 } 314 e = (Elf_Ehdr *)&fmp->md_data; 315 316 if ((error = md_load(fp->f_args, &mdp)) != 0) 317 return error; 318 319 printf("jumping to kernel entry at %#lx.\n", e->e_entry); 320#if 0 321 pmap_print_tlb('i'); 322 pmap_print_tlb('d'); 323#endif 324 325 entry = e->e_entry; 326 327 OF_release((void *)heapva, HEAPSZ); 328 329 ((kernel_entry_t *)entry)(mdp, 0, 0, 0, openfirmware); 330 331 panic("exec returned"); 332} 333 334static int 335mmu_mapin_sun4u(vm_offset_t va, vm_size_t len) 336{ 337 vm_offset_t pa, mva; 338 u_long data; 339 340 if (va + len > curkva) 341 curkva = va + len; 342 343 pa = (vm_offset_t)-1; 344 len += va & PAGE_MASK_4M; 345 va &= ~PAGE_MASK_4M; 346 while (len) { 347 if (dtlb_va_to_pa(va) == (vm_offset_t)-1 || 348 itlb_va_to_pa(va) == (vm_offset_t)-1) { 349 /* Allocate a physical page, claim the virtual area */ 350 if (pa == (vm_offset_t)-1) { 351 pa = (vm_offset_t)OF_alloc_phys(PAGE_SIZE_4M, 352 PAGE_SIZE_4M); 353 if (pa == (vm_offset_t)-1) 354 panic("out of memory"); 355 mva = (vm_offset_t)OF_claim_virt(va, 356 PAGE_SIZE_4M, 0); 357 if (mva != va) { 358 panic("can't claim virtual page " 359 "(wanted %#lx, got %#lx)", 360 va, mva); 361 } 362 /* The mappings may have changed, be paranoid. */ 363 continue; 364 } 365 /* 366 * Actually, we can only allocate two pages less at 367 * most (depending on the kernel TSB size). 368 */ 369 if (dtlb_slot >= dtlb_slot_max) 370 panic("mmu_mapin: out of dtlb_slots"); 371 if (itlb_slot >= itlb_slot_max) 372 panic("mmu_mapin: out of itlb_slots"); 373 data = TD_V | TD_4M | TD_PA(pa) | TD_L | TD_CP | 374 TD_CV | TD_P | TD_W; 375 dtlb_store[dtlb_slot].te_pa = pa; 376 dtlb_store[dtlb_slot].te_va = va; 377 itlb_store[itlb_slot].te_pa = pa; 378 itlb_store[itlb_slot].te_va = va; 379 dtlb_slot++; 380 itlb_slot++; 381 dtlb_enter(va, data); 382 itlb_enter(va, data); 383 pa = (vm_offset_t)-1; 384 } 385 len -= len > PAGE_SIZE_4M ? PAGE_SIZE_4M : len; 386 va += PAGE_SIZE_4M; 387 } 388 if (pa != (vm_offset_t)-1) 389 OF_release_phys(pa, PAGE_SIZE_4M); 390 391 return 0; 392} 393 394static int 395mmu_mapin_sun4v(vm_offset_t va, vm_size_t len) 396{ 397 398 vm_offset_t pa, mva; 399 u_long data; 400 int ret; 401 402 if (va + len > curkva) 403 curkva = va + len; 404 405 pa = (vm_offset_t)-1; 406 len += va & PAGE_MASK_4M; 407 va &= ~PAGE_MASK_4M; 408 while (len) { 409 if ((va >> 22) > SUN4V_TLB_SLOT_MAX) 410 panic("trying to map more than 4GB"); 411 if (tlb_store[va >> 22].te_pa == -1) { 412 /* Allocate a physical page, claim the virtual area */ 413 if (pa == (vm_offset_t)-1) { 414 pa = (vm_offset_t)OF_alloc_phys(PAGE_SIZE_4M, 415 PAGE_SIZE_4M); 416 if (pa == (vm_offset_t)-1) 417 panic("out of memory"); 418 mva = (vm_offset_t)OF_claim_virt(va, 419 PAGE_SIZE_4M, 0); 420 if (mva != va) { 421 panic("can't claim virtual page " 422 "(wanted %#lx, got %#lx)", 423 va, mva); 424 } 425 } 426 427 tlb_store[va >> 22].te_pa = pa; 428 if ((ret = OF_map_phys(-1, PAGE_SIZE_4M, va, pa)) != 0) 429 printf("OF_map_phys failed: %d\n", ret); 430 pa = (vm_offset_t)-1; 431 } 432 len -= len > PAGE_SIZE_4M ? PAGE_SIZE_4M : len; 433 va += PAGE_SIZE_4M; 434 } 435 if (pa != (vm_offset_t)-1) 436 OF_release_phys(pa, PAGE_SIZE_4M); 437 return 0; 438} 439 440static vm_offset_t 441init_heap(void) 442{ 443 if ((pmemh = OF_finddevice("/memory")) == (phandle_t)-1) 444 OF_exit(); 445 if (OF_getprop(pmemh, "available", memslices, sizeof(memslices)) <= 0) 446 OF_exit(); 447 448 /* There is no need for continuous physical heap memory. */ 449 heapva = (vm_offset_t)OF_claim((void *)HEAPVA, HEAPSZ, 32); 450 return heapva; 451} 452 453static void 454tlb_init_sun4u(void) 455{ 456 phandle_t child; 457 phandle_t root; 458 char buf[128]; 459 u_int bootcpu; 460 u_int cpu; 461 462 bootcpu = UPA_CR_GET_MID(ldxa(0, ASI_UPA_CONFIG_REG)); 463 if ((root = OF_peer(0)) == -1) 464 panic("main: OF_peer"); 465 for (child = OF_child(root); child != 0; child = OF_peer(child)) { 466 if (child == -1) 467 panic("main: OF_child"); 468 if (OF_getprop(child, "device_type", buf, sizeof(buf)) > 0 && 469 strcmp(buf, "cpu") == 0) { 470 if (OF_getprop(child, "upa-portid", &cpu, 471 sizeof(cpu)) == -1 && OF_getprop(child, "portid", 472 &cpu, sizeof(cpu)) == -1) 473 panic("main: OF_getprop"); 474 if (cpu == bootcpu) 475 break; 476 } 477 } 478 if (cpu != bootcpu) 479 panic("init_tlb: no node for bootcpu?!?!"); 480 if (OF_getprop(child, "#dtlb-entries", &dtlb_slot_max, 481 sizeof(dtlb_slot_max)) == -1 || 482 OF_getprop(child, "#itlb-entries", &itlb_slot_max, 483 sizeof(itlb_slot_max)) == -1) 484 panic("init_tlb: OF_getprop"); 485 dtlb_store = malloc(dtlb_slot_max * sizeof(*dtlb_store)); 486 itlb_store = malloc(itlb_slot_max * sizeof(*itlb_store)); 487 if (dtlb_store == NULL || itlb_store == NULL) 488 panic("init_tlb: malloc"); 489} 490 491static void 492tlb_init_sun4v(void) 493{ 494 tlb_store = malloc(SUN4V_TLB_SLOT_MAX * sizeof(*tlb_store)); 495 memset(tlb_store, 0xFF, SUN4V_TLB_SLOT_MAX * sizeof(*tlb_store)); 496} 497 498int 499main(int (*openfirm)(void *)) 500{ 501 char bootpath[64]; 502 char compatible[32]; 503 struct devsw **dp; 504 phandle_t rooth; 505 phandle_t chosenh; 506 507 /* 508 * Tell the Open Firmware functions where they find the ofw gate. 509 */ 510 OF_init(openfirm); 511 512 archsw.arch_getdev = ofw_getdev; 513 archsw.arch_copyin = sparc64_copyin; 514 archsw.arch_copyout = ofw_copyout; 515 archsw.arch_readin = sparc64_readin; 516 archsw.arch_autoload = sparc64_autoload; 517 archsw.arch_maphint = sparc64_maphint; 518 519 init_heap(); 520 setheap((void *)heapva, (void *)(heapva + HEAPSZ)); 521 /* 522 * Probe for a console. 523 */ 524 cons_probe(); 525 526 rooth = OF_peer(0); 527 OF_getprop(rooth, "compatible", compatible, sizeof(compatible)); 528 if (!strcmp(compatible, "sun4v")) { 529 printf("\nBooting with sun4v support.\n"); 530 mmu_ops = &mmu_ops_sun4v; 531 is_sun4v = 1; 532 } else { 533 printf("\nBooting with sun4u support.\n"); 534 mmu_ops = &mmu_ops_sun4u; 535 } 536 537 mmu_ops->tlb_init(); 538 539 /* 540 * Initialize devices. 541 */ 542 for (dp = devsw; *dp != 0; dp++) { 543 if ((*dp)->dv_init != 0) 544 (*dp)->dv_init(); 545 } 546 547 /* 548 * Set up the current device. 549 */ 550 chosenh = OF_finddevice("/chosen"); 551 OF_getprop(chosenh, "bootpath", bootpath, sizeof(bootpath)); 552 553 /* 554 * Sun compatible bootable CD-ROMs have a disk label placed 555 * before the cd9660 data, with the actual filesystem being 556 * in the first partition, while the other partitions contain 557 * pseudo disk labels with embedded boot blocks for different 558 * architectures, which may be followed by UFS filesystems. 559 * The firmware will set the boot path to the partition it 560 * boots from ('f' in the sun4u case), but we want the kernel 561 * to be loaded from the cd9660 fs ('a'), so the boot path 562 * needs to be altered. 563 */ 564 if (bootpath[strlen(bootpath) - 2] == ':' && 565 bootpath[strlen(bootpath) - 1] == 'f') { 566 bootpath[strlen(bootpath) - 1] = 'a'; 567 printf("Boot path set to %s\n", bootpath); 568 } 569 570 env_setenv("currdev", EV_VOLATILE, bootpath, 571 ofw_setcurrdev, env_nounset); 572 env_setenv("loaddev", EV_VOLATILE, bootpath, 573 env_noset, env_nounset); 574 575 printf("\n"); 576 printf("%s, Revision %s\n", bootprog_name, bootprog_rev); 577 printf("(%s, %s)\n", bootprog_maker, bootprog_date); 578 printf("bootpath=\"%s\"\n", bootpath); 579 580 /* Give control to the machine independent loader code. */ 581 interact(); 582 return 1; 583} 584 585COMMAND_SET(reboot, "reboot", "reboot the system", command_reboot); 586 587static int 588command_reboot(int argc, char *argv[]) 589{ 590 int i; 591 592 for (i = 0; devsw[i] != NULL; ++i) 593 if (devsw[i]->dv_cleanup != NULL) 594 (devsw[i]->dv_cleanup)(); 595 596 printf("Rebooting...\n"); 597 OF_exit(); 598} 599 600/* provide this for panic, as it's not in the startup code */ 601void 602exit(int code) 603{ 604 OF_exit(); 605} 606 607#ifdef LOADER_DEBUG 608typedef u_int64_t tte_t; 609 610const char *page_sizes[] = { 611 " 8k", " 64k", "512k", " 4m" 612}; 613 614static void 615pmap_print_tte(tte_t tag, tte_t tte) 616{ 617 printf("%s %s ", 618 page_sizes[(tte & TD_SIZE_MASK) >> TD_SIZE_SHIFT], 619 tag & TD_G ? "G" : " "); 620 printf(tte & TD_W ? "W " : " "); 621 printf(tte & TD_P ? "\e[33mP\e[0m " : " "); 622 printf(tte & TD_E ? "E " : " "); 623 printf(tte & TD_CV ? "CV " : " "); 624 printf(tte & TD_CP ? "CP " : " "); 625 printf(tte & TD_L ? "\e[32mL\e[0m " : " "); 626 printf(tte & TD_IE ? "IE " : " "); 627 printf(tte & TD_NFO ? "NFO " : " "); 628 printf("tag=0x%lx pa=0x%lx va=0x%lx ctx=%ld\n", tag, TD_PA(tte), 629 TT_VA(tag), TT_CTX(tag)); 630} 631void 632pmap_print_tlb(char which) 633{ 634 int i; 635 tte_t tte, tag; 636 637 for (i = 0; i < 64*8; i += 8) { 638 if (which == 'i') { 639 __asm__ __volatile__("ldxa [%1] %2, %0\n" : 640 "=r" (tag) : "r" (i), 641 "i" (ASI_ITLB_TAG_READ_REG)); 642 __asm__ __volatile__("ldxa [%1] %2, %0\n" : 643 "=r" (tte) : "r" (i), 644 "i" (ASI_ITLB_DATA_ACCESS_REG)); 645 } 646 else { 647 __asm__ __volatile__("ldxa [%1] %2, %0\n" : 648 "=r" (tag) : "r" (i), 649 "i" (ASI_DTLB_TAG_READ_REG)); 650 __asm__ __volatile__("ldxa [%1] %2, %0\n" : 651 "=r" (tte) : "r" (i), 652 "i" (ASI_DTLB_DATA_ACCESS_REG)); 653 } 654 if (!(tte & TD_V)) 655 continue; 656 printf("%cTLB-%2u: ", which, i>>3); 657 pmap_print_tte(tag, tte); 658 } 659} 660#endif 661