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