main.c revision 97445
121330Sdavidn/* 221330Sdavidn * Initial implementation: 321330Sdavidn * Copyright (c) 2001 Robert Drehmel 421330Sdavidn * All rights reserved. 521330Sdavidn * 621330Sdavidn * As long as the above copyright statement and this notice remain 721330Sdavidn * unchanged, you can do what ever you want with this file. 821330Sdavidn * 921330Sdavidn * $FreeBSD: head/sys/boot/sparc64/loader/main.c 97445 2002-05-29 05:49:59Z jake $ 1021330Sdavidn */ 1121330Sdavidn/* 1221330Sdavidn * FreeBSD/sparc64 kernel loader - machine dependent part 1321330Sdavidn * 1421330Sdavidn * - implements copyin and readin functions that map kernel 1521330Sdavidn * pages on demand. The machine independent code does not 1621330Sdavidn * know the size of the kernel early enough to pre-enter 1721330Sdavidn * TTEs and install just one 4MB mapping seemed to limiting 1821330Sdavidn * to me. 1921330Sdavidn */ 2021330Sdavidn 2121330Sdavidn#include <stand.h> 2221330Sdavidn#include <sys/exec.h> 2321330Sdavidn#include <sys/param.h> 2421330Sdavidn#include <sys/linker.h> 2521330Sdavidn#include <sys/pcpu.h> 2621330Sdavidn 2730259Scharnier#include <machine/asi.h> 2830259Scharnier#include <machine/atomic.h> 2950479Speter#include <machine/cpufunc.h> 3030259Scharnier#include <machine/elf.h> 3130259Scharnier#include <machine/lsu.h> 3221330Sdavidn#include <machine/metadata.h> 33287084Sbapt#include <machine/smp.h> 34242349Sbapt#include <machine/tte.h> 35242349Sbapt#include <machine/upa.h> 36242349Sbapt 37308814Sasomers#include "bootstrap.h" 3821330Sdavidn#include "libofw.h" 3921330Sdavidn#include "dev_net.h" 4021330Sdavidn 4121330Sdavidnenum { 42242349Sbapt HEAPVA = 0x800000, 4321330Sdavidn HEAPSZ = 0x1000000, 44242349Sbapt LOADSZ = 0x1000000 /* for kernel and modules */ 45242349Sbapt}; 46242349Sbapt 4721330Sdavidnstruct memory_slice { 48287084Sbapt vm_offset_t pstart; 49242349Sbapt vm_offset_t size; 50242349Sbapt}; 51242349Sbapt 52242349Sbapttypedef void kernel_entry_t(vm_offset_t mdp, u_long o1, u_long o2, u_long o3, 53242349Sbapt void *openfirmware); 54242349Sbapt 55242349Sbaptextern void itlb_enter(u_long vpn, u_long data); 56242349Sbaptextern void dtlb_enter(u_long vpn, u_long data); 57242349Sbaptextern vm_offset_t itlb_va_to_pa(vm_offset_t); 58242349Sbaptextern vm_offset_t dtlb_va_to_pa(vm_offset_t); 59242349Sbaptextern vm_offset_t md_load(char *, vm_offset_t *); 60242349Sbaptstatic int elf_exec(struct preloaded_file *); 61242349Sbaptstatic int sparc64_autoload(void); 62242349Sbaptstatic int mmu_mapin(vm_offset_t, vm_size_t); 63242349Sbapt 64242349Sbaptchar __progname[] = "FreeBSD/sparc64 loader"; 65242349Sbapt 66242349Sbaptstruct tlb_entry *dtlb_store; 67308814Sasomersstruct tlb_entry *itlb_store; 68242349Sbapt 69242349Sbaptint dtlb_slot; 70310173Sasomersint itlb_slot; 71308814Sasomersint dtlb_slot_max; 72243335Sbaptint itlb_slot_max; 73243335Sbapt 74242349Sbaptvm_offset_t curkva = 0; 75242349Sbaptvm_offset_t heapva; 76242349Sbaptphandle_t pmemh; /* OFW memory handle */ 77242349Sbapt 78242349Sbaptstruct memory_slice memslices[18]; 79242349Sbaptstruct ofw_devdesc bootdev; 80242349Sbapt 8121330Sdavidn/* 8221330Sdavidn * Machine dependent structures that the machine independent 8321330Sdavidn * loader part uses. 8421330Sdavidn */ 8521330Sdavidnstruct devsw *devsw[] = { 86242349Sbapt#ifdef LOADER_DISK_SUPPORT 8721330Sdavidn &ofwdisk, 8821330Sdavidn#endif 8921330Sdavidn#ifdef LOADER_NET_SUPPORT 9021330Sdavidn &netdev, 9121330Sdavidn#endif 92242349Sbapt 0 9321330Sdavidn}; 9421330Sdavidnstruct arch_switch archsw; 9521330Sdavidn 9621330Sdavidnstruct file_format sparc64_elf = { 9721330Sdavidn elf_loadfile, 98242349Sbapt elf_exec 9921330Sdavidn}; 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_NET_SUPPORT 112 &nfs_fsops, 113#endif 114#ifdef LOADER_TFTP_SUPPORT 115 &tftp_fsops, 116#endif 117 0 118}; 119struct netif_driver *netif_drivers[] = { 120#ifdef LOADER_NET_SUPPORT 121 &ofwnet, 122#endif 123 0 124}; 125 126extern struct console ofwconsole; 127struct console *consoles[] = { 128 &ofwconsole, 129 0 130}; 131 132#ifdef LOADER_DEBUG 133static int 134watch_phys_set_mask(vm_offset_t pa, u_long mask) 135{ 136 u_long lsucr; 137 138 stxa(AA_DMMU_PWPR, ASI_DMMU, pa & (((2UL << 38) - 1) << 3)); 139 lsucr = ldxa(0, ASI_LSU_CTL_REG); 140 lsucr = ((lsucr | LSU_PW) & ~LSU_PM_MASK) | 141 (mask << LSU_PM_SHIFT); 142 stxa(0, ASI_LSU_CTL_REG, lsucr); 143 return (0); 144} 145 146static int 147watch_phys_set(vm_offset_t pa, int sz) 148{ 149 u_long off; 150 151 off = (u_long)pa & 7; 152 /* Test for misaligned watch points. */ 153 if (off + sz > 8) 154 return (-1); 155 return (watch_phys_set_mask(pa, ((1 << sz) - 1) << off)); 156} 157 158 159static int 160watch_virt_set_mask(vm_offset_t va, u_long mask) 161{ 162 u_long lsucr; 163 164 stxa(AA_DMMU_VWPR, ASI_DMMU, va & (((2UL << 41) - 1) << 3)); 165 lsucr = ldxa(0, ASI_LSU_CTL_REG); 166 lsucr = ((lsucr | LSU_VW) & ~LSU_VM_MASK) | 167 (mask << LSU_VM_SHIFT); 168 stxa(0, ASI_LSU_CTL_REG, lsucr); 169 return (0); 170} 171 172static int 173watch_virt_set(vm_offset_t va, int sz) 174{ 175 u_long off; 176 177 off = (u_long)va & 7; 178 /* Test for misaligned watch points. */ 179 if (off + sz > 8) 180 return (-1); 181 return (watch_virt_set_mask(va, ((1 << sz) - 1) << off)); 182} 183#endif 184 185/* 186 * archsw functions 187 */ 188static int 189sparc64_autoload(void) 190{ 191 printf("nothing to autoload yet.\n"); 192 return 0; 193} 194 195static ssize_t 196sparc64_readin(const int fd, vm_offset_t va, const size_t len) 197{ 198 mmu_mapin(va, len); 199 return read(fd, (void *)va, len); 200} 201 202static ssize_t 203sparc64_copyin(const void *src, vm_offset_t dest, size_t len) 204{ 205 mmu_mapin(dest, len); 206 memcpy((void *)dest, src, len); 207 return len; 208} 209 210/* 211 * other MD functions 212 */ 213static int 214elf_exec(struct preloaded_file *fp) 215{ 216 struct file_metadata *fmp; 217 vm_offset_t mdp; 218 Elf_Ehdr *e; 219 int error; 220 221 if ((fmp = file_findmetadata(fp, MODINFOMD_ELFHDR)) == 0) { 222 return EFTYPE; 223 } 224 e = (Elf_Ehdr *)&fmp->md_data; 225 226 if ((error = md_load(fp->f_args, &mdp)) != 0) 227 return error; 228 229 printf("jumping to kernel entry at %#lx.\n", e->e_entry); 230#if 0 231 pmap_print_tlb('i'); 232 pmap_print_tlb('d'); 233#endif 234 ((kernel_entry_t *)e->e_entry)(mdp, 0, 0, 0, openfirmware); 235 236 panic("exec returned"); 237} 238 239static int 240mmu_mapin(vm_offset_t va, vm_size_t len) 241{ 242 vm_offset_t pa, mva; 243 u_long data; 244 245 if (va + len > curkva) 246 curkva = va + len; 247 248 pa = (vm_offset_t)-1; 249 len += va & PAGE_MASK_4M; 250 va &= ~PAGE_MASK_4M; 251 while (len) { 252 if (dtlb_va_to_pa(va) == (vm_offset_t)-1 || 253 itlb_va_to_pa(va) == (vm_offset_t)-1) { 254 /* Allocate a physical page, claim the virtual area */ 255 if (pa == (vm_offset_t)-1) { 256 pa = (vm_offset_t)OF_alloc_phys(PAGE_SIZE_4M, 257 PAGE_SIZE_4M); 258 if (pa == (vm_offset_t)-1) 259 panic("out of memory"); 260 mva = (vm_offset_t)OF_claim_virt(va, 261 PAGE_SIZE_4M, 0); 262 if (mva != va) { 263 panic("can't claim virtual page " 264 "(wanted %#lx, got %#lx)", 265 va, mva); 266 } 267 /* The mappings may have changed, be paranoid. */ 268 continue; 269 } 270 /* 271 * Actually, we can only allocate two pages less at 272 * most (depending on the kernel TSB size). 273 */ 274 if (dtlb_slot >= dtlb_slot_max) 275 panic("mmu_mapin: out of dtlb_slots"); 276 if (itlb_slot >= itlb_slot_max) 277 panic("mmu_mapin: out of itlb_slots"); 278 data = TD_V | TD_4M | TD_PA(pa) | TD_L | TD_CP | 279 TD_CV | TD_P | TD_W; 280 dtlb_store[dtlb_slot].te_pa = pa; 281 dtlb_store[dtlb_slot].te_va = va; 282 itlb_store[itlb_slot].te_pa = pa; 283 itlb_store[itlb_slot].te_va = va; 284 dtlb_slot++; 285 itlb_slot++; 286 dtlb_enter(va, data); 287 itlb_enter(va, data); 288 pa = (vm_offset_t)-1; 289 } 290 len -= len > PAGE_SIZE_4M ? PAGE_SIZE_4M : len; 291 va += PAGE_SIZE_4M; 292 } 293 if (pa != (vm_offset_t)-1) 294 OF_release_phys(pa, PAGE_SIZE_4M); 295 return 0; 296} 297 298static vm_offset_t 299init_heap(void) 300{ 301 if ((pmemh = OF_finddevice("/memory")) == (phandle_t)-1) 302 OF_exit(); 303 if (OF_getprop(pmemh, "available", memslices, sizeof(memslices)) <= 0) 304 OF_exit(); 305 306 /* There is no need for continuous physical heap memory. */ 307 heapva = (vm_offset_t)OF_claim((void *)HEAPVA, HEAPSZ, 32); 308 return heapva; 309} 310 311static void 312tlb_init(void) 313{ 314 phandle_t child; 315 phandle_t root; 316 char buf[128]; 317 u_int bootcpu; 318 u_int cpu; 319 320 bootcpu = UPA_CR_GET_MID(ldxa(0, ASI_UPA_CONFIG_REG)); 321 if ((root = OF_peer(0)) == -1) 322 panic("main: OF_peer"); 323 for (child = OF_child(root); child != 0; child = OF_peer(child)) { 324 if (child == -1) 325 panic("main: OF_child"); 326 if (OF_getprop(child, "device_type", buf, sizeof(buf)) > 0 && 327 strcmp(buf, "cpu") == 0) { 328 if (OF_getprop(child, "upa-portid", &cpu, 329 sizeof(cpu)) == -1 && OF_getprop(child, "portid", 330 &cpu, sizeof(cpu)) == -1) 331 panic("main: OF_getprop"); 332 if (cpu == bootcpu) 333 break; 334 } 335 } 336 if (cpu != bootcpu) 337 panic("init_tlb: no node for bootcpu?!?!"); 338 if (OF_getprop(child, "#dtlb-entries", &dtlb_slot_max, 339 sizeof(dtlb_slot_max)) == -1 || 340 OF_getprop(child, "#itlb-entries", &itlb_slot_max, 341 sizeof(itlb_slot_max)) == -1) 342 panic("init_tlb: OF_getprop"); 343 dtlb_store = malloc(dtlb_slot_max * sizeof(*dtlb_store)); 344 itlb_store = malloc(itlb_slot_max * sizeof(*itlb_store)); 345 if (dtlb_store == NULL || itlb_store == NULL) 346 panic("init_tlb: malloc"); 347} 348 349int 350main(int (*openfirm)(void *)) 351{ 352 char bootpath[64]; 353 struct devsw **dp; 354 phandle_t chosenh; 355 356 /* 357 * Tell the OpenFirmware functions where they find the ofw gate. 358 */ 359 OF_init(openfirm); 360 361 archsw.arch_getdev = ofw_getdev; 362 archsw.arch_copyin = sparc64_copyin; 363 archsw.arch_copyout = ofw_copyout; 364 archsw.arch_readin = sparc64_readin; 365 archsw.arch_autoload = sparc64_autoload; 366#ifdef ELF_CRC32 367 archsw.arch_crc32 = sparc64_crc32; 368#endif 369 370 init_heap(); 371 setheap((void *)heapva, (void *)(heapva + HEAPSZ)); 372 373 /* 374 * Probe for a console. 375 */ 376 cons_probe(); 377 378 tlb_init(); 379 380 bcache_init(32, 512); 381 382 /* 383 * Initialize devices. 384 */ 385 for (dp = devsw; *dp != 0; dp++) { 386 if ((*dp)->dv_init != 0) 387 (*dp)->dv_init(); 388 } 389 390 /* 391 * Set up the current device. 392 */ 393 chosenh = OF_finddevice("/chosen"); 394 OF_getprop(chosenh, "bootpath", bootpath, sizeof(bootpath)); 395 396 bootdev.d_type = ofw_devicetype(bootpath); 397 switch (bootdev.d_type) { 398 case DEVT_DISK: 399 bootdev.d_dev = &ofwdisk; 400 /* 401 * Sun compatible bootable CD-ROMs have a disk label placed 402 * before the cd9660 data, with the actual filesystem being 403 * in the first partition, while the other partitions contain 404 * pseudo disk labels with embedded boot blocks for different 405 * architectures, which may be followed by UFS filesystems. 406 * The firmware will set the boot path to the partition it 407 * boots from ('f' in the sun4u case), but we want the kernel 408 * to be loaded from the cd9660 fs ('a'), so the boot path 409 * needs to be altered. 410 */ 411 if (strstr(bootpath, "cdrom") != NULL && 412 bootpath[strlen(bootpath) - 2] == ':') { 413 bootpath[strlen(bootpath) - 1] = 'a'; 414 printf("Boot path set to %s\n", bootpath); 415 } 416 strncpy(bootdev.d_kind.ofwdisk.path, bootpath, 64); 417 ofw_parseofwdev(&bootdev, bootpath); 418 break; 419 case DEVT_NET: 420 bootdev.d_dev = &netdev; 421 strncpy(bootdev.d_kind.netif.path, bootpath, 64); 422 bootdev.d_kind.netif.unit = 0; 423 break; 424 } 425 426 env_setenv("currdev", EV_VOLATILE, ofw_fmtdev(&bootdev), 427 ofw_setcurrdev, env_nounset); 428 env_setenv("loaddev", EV_VOLATILE, ofw_fmtdev(&bootdev), 429 env_noset, env_nounset); 430 431 printf("%s\n", __progname); 432 printf("bootpath=\"%s\"\n", bootpath); 433 printf("loaddev=%s\n", getenv("loaddev")); 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