main.c revision 108100
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 108100 2002-12-19 19:34:59Z 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 elf_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 elf_loadfile, 96 elf_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 221elf_exec(struct preloaded_file *fp) 222{ 223 struct file_metadata *fmp; 224 vm_offset_t mdp; 225 Elf_Ehdr *e; 226 int error; 227 228 if ((fmp = file_findmetadata(fp, MODINFOMD_ELFHDR)) == 0) { 229 return EFTYPE; 230 } 231 e = (Elf_Ehdr *)&fmp->md_data; 232 233 if ((error = md_load(fp->f_args, &mdp)) != 0) 234 return error; 235 236 printf("jumping to kernel entry at %#lx.\n", e->e_entry); 237#if 0 238 pmap_print_tlb('i'); 239 pmap_print_tlb('d'); 240#endif 241 ((kernel_entry_t *)e->e_entry)(mdp, 0, 0, 0, openfirmware); 242 243 panic("exec returned"); 244} 245 246static int 247mmu_mapin(vm_offset_t va, vm_size_t len) 248{ 249 vm_offset_t pa, mva; 250 u_long data; 251 252 if (va + len > curkva) 253 curkva = va + len; 254 255 pa = (vm_offset_t)-1; 256 len += va & PAGE_MASK_4M; 257 va &= ~PAGE_MASK_4M; 258 while (len) { 259 if (dtlb_va_to_pa(va) == (vm_offset_t)-1 || 260 itlb_va_to_pa(va) == (vm_offset_t)-1) { 261 /* Allocate a physical page, claim the virtual area */ 262 if (pa == (vm_offset_t)-1) { 263 pa = (vm_offset_t)OF_alloc_phys(PAGE_SIZE_4M, 264 PAGE_SIZE_4M); 265 if (pa == (vm_offset_t)-1) 266 panic("out of memory"); 267 mva = (vm_offset_t)OF_claim_virt(va, 268 PAGE_SIZE_4M, 0); 269 if (mva != va) { 270 panic("can't claim virtual page " 271 "(wanted %#lx, got %#lx)", 272 va, mva); 273 } 274 /* The mappings may have changed, be paranoid. */ 275 continue; 276 } 277 /* 278 * Actually, we can only allocate two pages less at 279 * most (depending on the kernel TSB size). 280 */ 281 if (dtlb_slot >= dtlb_slot_max) 282 panic("mmu_mapin: out of dtlb_slots"); 283 if (itlb_slot >= itlb_slot_max) 284 panic("mmu_mapin: out of itlb_slots"); 285 data = TD_V | TD_4M | TD_PA(pa) | TD_L | TD_CP | 286 TD_CV | TD_P | TD_W; 287 dtlb_store[dtlb_slot].te_pa = pa; 288 dtlb_store[dtlb_slot].te_va = va; 289 itlb_store[itlb_slot].te_pa = pa; 290 itlb_store[itlb_slot].te_va = va; 291 dtlb_slot++; 292 itlb_slot++; 293 dtlb_enter(va, data); 294 itlb_enter(va, data); 295 pa = (vm_offset_t)-1; 296 } 297 len -= len > PAGE_SIZE_4M ? PAGE_SIZE_4M : len; 298 va += PAGE_SIZE_4M; 299 } 300 if (pa != (vm_offset_t)-1) 301 OF_release_phys(pa, PAGE_SIZE_4M); 302 return 0; 303} 304 305static vm_offset_t 306init_heap(void) 307{ 308 if ((pmemh = OF_finddevice("/memory")) == (phandle_t)-1) 309 OF_exit(); 310 if (OF_getprop(pmemh, "available", memslices, sizeof(memslices)) <= 0) 311 OF_exit(); 312 313 /* There is no need for continuous physical heap memory. */ 314 heapva = (vm_offset_t)OF_claim((void *)HEAPVA, HEAPSZ, 32); 315 return heapva; 316} 317 318static void 319tlb_init(void) 320{ 321 phandle_t child; 322 phandle_t root; 323 char buf[128]; 324 u_int bootcpu; 325 u_int cpu; 326 327 bootcpu = UPA_CR_GET_MID(ldxa(0, ASI_UPA_CONFIG_REG)); 328 if ((root = OF_peer(0)) == -1) 329 panic("main: OF_peer"); 330 for (child = OF_child(root); child != 0; child = OF_peer(child)) { 331 if (child == -1) 332 panic("main: OF_child"); 333 if (OF_getprop(child, "device_type", buf, sizeof(buf)) > 0 && 334 strcmp(buf, "cpu") == 0) { 335 if (OF_getprop(child, "upa-portid", &cpu, 336 sizeof(cpu)) == -1 && OF_getprop(child, "portid", 337 &cpu, sizeof(cpu)) == -1) 338 panic("main: OF_getprop"); 339 if (cpu == bootcpu) 340 break; 341 } 342 } 343 if (cpu != bootcpu) 344 panic("init_tlb: no node for bootcpu?!?!"); 345 if (OF_getprop(child, "#dtlb-entries", &dtlb_slot_max, 346 sizeof(dtlb_slot_max)) == -1 || 347 OF_getprop(child, "#itlb-entries", &itlb_slot_max, 348 sizeof(itlb_slot_max)) == -1) 349 panic("init_tlb: OF_getprop"); 350 dtlb_store = malloc(dtlb_slot_max * sizeof(*dtlb_store)); 351 itlb_store = malloc(itlb_slot_max * sizeof(*itlb_store)); 352 if (dtlb_store == NULL || itlb_store == NULL) 353 panic("init_tlb: malloc"); 354} 355 356int 357main(int (*openfirm)(void *)) 358{ 359 char bootpath[64]; 360 struct devsw **dp; 361 phandle_t chosenh; 362 363 /* 364 * Tell the OpenFirmware functions where they find the ofw gate. 365 */ 366 OF_init(openfirm); 367 368 archsw.arch_getdev = ofw_getdev; 369 archsw.arch_copyin = sparc64_copyin; 370 archsw.arch_copyout = ofw_copyout; 371 archsw.arch_readin = sparc64_readin; 372 archsw.arch_autoload = sparc64_autoload; 373 374 init_heap(); 375 setheap((void *)heapva, (void *)(heapva + HEAPSZ)); 376 377 /* 378 * Probe for a console. 379 */ 380 cons_probe(); 381 382 tlb_init(); 383 384 bcache_init(32, 512); 385 386 /* 387 * Initialize devices. 388 */ 389 for (dp = devsw; *dp != 0; dp++) { 390 if ((*dp)->dv_init != 0) 391 (*dp)->dv_init(); 392 } 393 394 /* 395 * Set up the current device. 396 */ 397 chosenh = OF_finddevice("/chosen"); 398 OF_getprop(chosenh, "bootpath", bootpath, sizeof(bootpath)); 399 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 (bootpath[strlen(bootpath) - 2] == ':' && 412 bootpath[strlen(bootpath) - 1] == 'f') { 413 bootpath[strlen(bootpath) - 1] = 'a'; 414 printf("Boot path set to %s\n", bootpath); 415 } 416 417 env_setenv("currdev", EV_VOLATILE, bootpath, 418 ofw_setcurrdev, env_nounset); 419 env_setenv("loaddev", EV_VOLATILE, bootpath, 420 env_noset, env_nounset); 421 422 printf("\n"); 423 printf("%s, Revision %s\n", bootprog_name, bootprog_rev); 424 printf("(%s, %s)\n", bootprog_maker, bootprog_date); 425 printf("bootpath=\"%s\"\n", bootpath); 426 427 /* Give control to the machine independent loader code. */ 428 interact(); 429 return 1; 430} 431 432COMMAND_SET(reboot, "reboot", "reboot the system", command_reboot); 433 434static int 435command_reboot(int argc, char *argv[]) 436{ 437 int i; 438 439 for (i = 0; devsw[i] != NULL; ++i) 440 if (devsw[i]->dv_cleanup != NULL) 441 (devsw[i]->dv_cleanup)(); 442 443 printf("Rebooting...\n"); 444 OF_exit(); 445} 446 447/* provide this for panic, as it's not in the startup code */ 448void 449exit(int code) 450{ 451 OF_exit(); 452} 453 454#ifdef LOADER_DEBUG 455typedef u_int64_t tte_t; 456 457const char *page_sizes[] = { 458 " 8k", " 64k", "512k", " 4m" 459}; 460 461static void 462pmap_print_tte(tte_t tag, tte_t tte) 463{ 464 printf("%s %s ", 465 page_sizes[(tte & TD_SIZE_MASK) >> TD_SIZE_SHIFT], 466 tag & TD_G ? "G" : " "); 467 printf(tte & TD_W ? "W " : " "); 468 printf(tte & TD_P ? "\e[33mP\e[0m " : " "); 469 printf(tte & TD_E ? "E " : " "); 470 printf(tte & TD_CV ? "CV " : " "); 471 printf(tte & TD_CP ? "CP " : " "); 472 printf(tte & TD_L ? "\e[32mL\e[0m " : " "); 473 printf(tte & TD_IE ? "IE " : " "); 474 printf(tte & TD_NFO ? "NFO " : " "); 475 printf("tag=0x%lx pa=0x%lx va=0x%lx ctx=%ld\n", tag, TD_PA(tte), 476 TT_VA(tag), TT_CTX(tag)); 477} 478void 479pmap_print_tlb(char which) 480{ 481 int i; 482 tte_t tte, tag; 483 484 for (i = 0; i < 64*8; i += 8) { 485 if (which == 'i') { 486 __asm__ __volatile__("ldxa [%1] %2, %0\n" : 487 "=r" (tag) : "r" (i), 488 "i" (ASI_ITLB_TAG_READ_REG)); 489 __asm__ __volatile__("ldxa [%1] %2, %0\n" : 490 "=r" (tte) : "r" (i), 491 "i" (ASI_ITLB_DATA_ACCESS_REG)); 492 } 493 else { 494 __asm__ __volatile__("ldxa [%1] %2, %0\n" : 495 "=r" (tag) : "r" (i), 496 "i" (ASI_DTLB_TAG_READ_REG)); 497 __asm__ __volatile__("ldxa [%1] %2, %0\n" : 498 "=r" (tte) : "r" (i), 499 "i" (ASI_DTLB_DATA_ACCESS_REG)); 500 } 501 if (!(tte & TD_V)) 502 continue; 503 printf("%cTLB-%2u: ", which, i>>3); 504 pmap_print_tte(tag, tte); 505 } 506} 507#endif 508