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