1 /* 2 * CDDL HEADER START 3 * 4 * The contents of this file are subject to the terms of the 5 * Common Development and Distribution License (the "License"). 6 * You may not use this file except in compliance with the License. 7 * 8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 9 * or http://www.opensolaris.org/os/licensing. 10 * See the License for the specific language governing permissions 11 * and limitations under the License. 12 * 13 * When distributing Covered Code, include this CDDL HEADER in each 14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 15 * If applicable, add the following below this CDDL HEADER, with the 16 * fields enclosed by brackets "[]" replaced with your own identifying 17 * information: Portions Copyright [yyyy] [name of copyright owner] 18 * 19 * CDDL HEADER END 20 */ 21 /* 22 * Copyright 2008 Sun Microsystems, Inc. All rights reserved. 23 * Use is subject to license terms. 24 */ 25 26 #pragma ident "%Z%%M% %I% %E% SMI" 27 28 #include <sys/types.h> 29 #include <sys/systm.h> 30 #include <sys/archsystm.h> 31 #include <sys/machsystm.h> 32 #include <sys/disp.h> 33 #include <sys/autoconf.h> 34 #include <sys/promif.h> 35 #include <sys/prom_plat.h> 36 #include <sys/promimpl.h> 37 #include <sys/platform_module.h> 38 #include <sys/clock.h> 39 #include <sys/pte.h> 40 #include <sys/scb.h> 41 #include <sys/cpu.h> 42 #include <sys/stack.h> 43 #include <sys/intreg.h> 44 #include <sys/ivintr.h> 45 #include <vm/as.h> 46 #include <vm/hat_sfmmu.h> 47 #include <sys/reboot.h> 48 #include <sys/sysmacros.h> 49 #include <sys/vtrace.h> 50 #include <sys/trap.h> 51 #include <sys/machtrap.h> 52 #include <sys/privregs.h> 53 #include <sys/machpcb.h> 54 #include <sys/proc.h> 55 #include <sys/cpupart.h> 56 #include <sys/pset.h> 57 #include <sys/cpu_module.h> 58 #include <sys/copyops.h> 59 #include <sys/panic.h> 60 #include <sys/bootconf.h> /* for bootops */ 61 #include <sys/pg.h> 62 #include <sys/kdi.h> 63 #include <sys/fpras.h> 64 65 #include <sys/prom_debug.h> 66 #include <sys/debug.h> 67 68 #include <sys/sunddi.h> 69 #include <sys/lgrp.h> 70 #include <sys/traptrace.h> 71 72 #include <sys/kobj_impl.h> 73 #include <sys/kdi_machimpl.h> 74 75 /* 76 * External Routines: 77 */ 78 extern void map_wellknown_devices(void); 79 extern void hsvc_setup(void); 80 extern void mach_descrip_startup_init(void); 81 extern void mach_soft_state_init(void); 82 83 int dcache_size; 84 int dcache_linesize; 85 int icache_size; 86 int icache_linesize; 87 int ecache_size; 88 int ecache_alignsize; 89 int ecache_associativity; 90 int ecache_setsize; /* max possible e$ setsize */ 91 int cpu_setsize; /* max e$ setsize of configured cpus */ 92 int dcache_line_mask; /* spitfire only */ 93 int vac_size; /* cache size in bytes */ 94 uint_t vac_mask; /* VAC alignment consistency mask */ 95 int vac_shift; /* log2(vac_size) for ppmapout() */ 96 int vac = 0; /* virtual address cache type (none == 0) */ 97 98 /* 99 * fpRAS. An individual sun4* machine class (or perhaps subclass, 100 * eg sun4u/cheetah) must set fpras_implemented to indicate that it implements 101 * the fpRAS feature. The feature can be suppressed by setting fpras_disable 102 * or the mechanism can be disabled for individual copy operations with 103 * fpras_disableids. All these are checked in post_startup() code so 104 * fpras_disable and fpras_disableids can be set in /etc/system. 105 * If/when fpRAS is implemented on non-sun4 architectures these 106 * definitions will need to move up to the common level. 107 */ 108 int fpras_implemented; 109 int fpras_disable; 110 int fpras_disableids; 111 112 /* 113 * Static Routines: 114 */ 115 static void kern_splr_preprom(void); 116 static void kern_splx_postprom(void); 117 118 /* 119 * Setup routine called right before main(). Interposing this function 120 * before main() allows us to call it in a machine-independent fashion. 121 */ 122 123 void 124 mlsetup(struct regs *rp, kfpu_t *fp) 125 { 126 struct machpcb *mpcb; 127 128 extern char t0stack[]; 129 extern struct classfuncs sys_classfuncs; 130 extern disp_t cpu0_disp; 131 unsigned long long pa; 132 133 #ifdef TRAPTRACE 134 TRAP_TRACE_CTL *ctlp; 135 #endif /* TRAPTRACE */ 136 137 /* drop into kmdb on boot -d */ 138 if (boothowto & RB_DEBUGENTER) 139 kmdb_enter(); 140 141 /* 142 * initialize cpu_self 143 */ 144 cpu0.cpu_self = &cpu0; 145 146 /* 147 * initialize t0 148 */ 149 t0.t_stk = (caddr_t)rp - REGOFF; 150 /* Can't use va_to_pa here - wait until prom_ initialized */ 151 t0.t_stkbase = t0stack; 152 t0.t_pri = maxclsyspri - 3; 153 t0.t_schedflag = TS_LOAD | TS_DONT_SWAP; 154 t0.t_procp = &p0; 155 t0.t_plockp = &p0lock.pl_lock; 156 t0.t_lwp = &lwp0; 157 t0.t_forw = &t0; 158 t0.t_back = &t0; 159 t0.t_next = &t0; 160 t0.t_prev = &t0; 161 t0.t_cpu = &cpu0; /* loaded by _start */ 162 t0.t_disp_queue = &cpu0_disp; 163 t0.t_bind_cpu = PBIND_NONE; 164 t0.t_bind_pset = PS_NONE; 165 t0.t_bindflag = (uchar_t)default_binding_mode; 166 t0.t_cpupart = &cp_default; 167 t0.t_clfuncs = &sys_classfuncs.thread; 168 t0.t_copyops = NULL; 169 THREAD_ONPROC(&t0, CPU); 170 171 lwp0.lwp_thread = &t0; 172 lwp0.lwp_procp = &p0; 173 lwp0.lwp_regs = (void *)rp; 174 t0.t_tid = p0.p_lwpcnt = p0.p_lwprcnt = p0.p_lwpid = 1; 175 176 mpcb = lwptompcb(&lwp0); 177 mpcb->mpcb_fpu = fp; 178 mpcb->mpcb_fpu->fpu_q = mpcb->mpcb_fpu_q; 179 mpcb->mpcb_thread = &t0; 180 lwp0.lwp_fpu = (void *)mpcb->mpcb_fpu; 181 182 p0.p_exec = NULL; 183 p0.p_stat = SRUN; 184 p0.p_flag = SSYS; 185 p0.p_tlist = &t0; 186 p0.p_stksize = 2*PAGESIZE; 187 p0.p_stkpageszc = 0; 188 p0.p_as = &kas; 189 p0.p_lockp = &p0lock; 190 p0.p_utraps = NULL; 191 p0.p_brkpageszc = 0; 192 p0.p_t1_lgrpid = LGRP_NONE; 193 p0.p_tr_lgrpid = LGRP_NONE; 194 sigorset(&p0.p_ignore, &ignoredefault); 195 196 CPU->cpu_thread = &t0; 197 CPU->cpu_dispthread = &t0; 198 bzero(&cpu0_disp, sizeof (disp_t)); 199 CPU->cpu_disp = &cpu0_disp; 200 CPU->cpu_disp->disp_cpu = CPU; 201 CPU->cpu_idle_thread = &t0; 202 CPU->cpu_flags = CPU_RUNNING; 203 CPU->cpu_id = getprocessorid(); 204 CPU->cpu_dispatch_pri = t0.t_pri; 205 206 /* 207 * Initialize thread/cpu microstate accounting 208 */ 209 init_mstate(&t0, LMS_SYSTEM); 210 init_cpu_mstate(CPU, CMS_SYSTEM); 211 212 /* 213 * Initialize lists of available and active CPUs. 214 */ 215 cpu_list_init(CPU); 216 217 cpu_vm_data_init(CPU); 218 219 (void) prom_set_preprom(kern_splr_preprom); 220 (void) prom_set_postprom(kern_splx_postprom); 221 PRM_INFO("mlsetup: now ok to call prom_printf"); 222 223 mpcb->mpcb_pa = va_to_pa(t0.t_stk); 224 225 /* 226 * Claim the physical and virtual resources used by panicbuf, 227 * then map panicbuf. This operation removes the phys and 228 * virtual addresses from the free lists. 229 */ 230 if (prom_claim_virt(PANICBUFSIZE, panicbuf) != panicbuf) 231 prom_panic("Can't claim panicbuf virtual address"); 232 233 if (prom_retain("panicbuf", PANICBUFSIZE, MMU_PAGESIZE, &pa) != 0) 234 prom_panic("Can't allocate retained panicbuf physical address"); 235 236 if (prom_map_phys(-1, PANICBUFSIZE, panicbuf, pa) != 0) 237 prom_panic("Can't map panicbuf"); 238 239 PRM_DEBUG(panicbuf); 240 PRM_DEBUG(pa); 241 242 /* 243 * Negotiate hypervisor services, if any 244 */ 245 hsvc_setup(); 246 mach_soft_state_init(); 247 248 #ifdef TRAPTRACE 249 /* 250 * initialize the trap trace buffer for the boot cpu 251 * XXX todo, dynamically allocate this buffer too 252 */ 253 ctlp = &trap_trace_ctl[CPU->cpu_id]; 254 ctlp->d.vaddr_base = trap_tr0; 255 ctlp->d.offset = ctlp->d.last_offset = 0; 256 ctlp->d.limit = TRAP_TSIZE; /* XXX dynamic someday */ 257 ctlp->d.paddr_base = va_to_pa(trap_tr0); 258 #endif /* TRAPTRACE */ 259 260 /* 261 * Initialize the Machine Description kernel framework 262 */ 263 264 mach_descrip_startup_init(); 265 266 /* 267 * initialize HV trap trace buffer for the boot cpu 268 */ 269 mach_htraptrace_setup(CPU->cpu_id); 270 mach_htraptrace_configure(CPU->cpu_id); 271 272 /* 273 * lgroup framework initialization. This must be done prior 274 * to devices being mapped. 275 */ 276 lgrp_init(); 277 278 cpu_setup(); 279 280 if (boothowto & RB_HALT) { 281 prom_printf("unix: kernel halted by -h flag\n"); 282 prom_enter_mon(); 283 } 284 285 setcputype(); 286 map_wellknown_devices(); 287 setcpudelay(); 288 } 289 290 /* 291 * These routines are called immediately before and 292 * immediately after calling into the firmware. The 293 * firmware is significantly confused by preemption - 294 * particularly on MP machines - but also on UP's too. 295 */ 296 297 static int saved_spl; 298 299 static void 300 kern_splr_preprom(void) 301 { 302 saved_spl = spl7(); 303 } 304 305 static void 306 kern_splx_postprom(void) 307 { 308 splx(saved_spl); 309 } 310 311 312 /* 313 * WARNING 314 * The code fom here to the end of mlsetup.c runs before krtld has 315 * knitted unix and genunix together. It can call routines in unix, 316 * but calls into genunix will fail spectacularly. More specifically, 317 * calls to prom_*, bop_* and str* will work, everything else is 318 * caveat emptor. 319 * 320 * Also note that while #ifdef sun4u is generally a bad idea, they 321 * exist here to concentrate the dangerous code into a single file. 322 */ 323 324 static char * 325 getcpulist(void) 326 { 327 pnode_t node; 328 /* big enough for OBP_NAME and for a reasonably sized OBP_COMPATIBLE. */ 329 static char cpubuf[5 * OBP_MAXDRVNAME]; 330 int nlen, clen, i; 331 #ifdef sun4u 332 char dname[OBP_MAXDRVNAME]; 333 #endif 334 335 node = prom_findnode_bydevtype(prom_rootnode(), OBP_CPU); 336 if (node != OBP_NONODE && node != OBP_BADNODE) { 337 if ((nlen = prom_getproplen(node, OBP_NAME)) <= 0 || 338 nlen > sizeof (cpubuf) || 339 prom_getprop(node, OBP_NAME, cpubuf) <= 0) 340 prom_panic("no name in cpu node"); 341 342 /* nlen includes the terminating null character */ 343 #ifdef sun4v 344 if ((clen = prom_getproplen(node, OBP_COMPATIBLE)) > 0) { 345 #else /* sun4u */ 346 /* 347 * For the CMT case, need check the parent "core" 348 * node for the compatible property. 349 */ 350 if ((clen = prom_getproplen(node, OBP_COMPATIBLE)) > 0 || 351 ((node = prom_parentnode(node)) != OBP_NONODE && 352 node != OBP_BADNODE && 353 (clen = prom_getproplen(node, OBP_COMPATIBLE)) > 0 && 354 prom_getprop(node, OBP_DEVICETYPE, dname) > 0 && 355 strcmp(dname, "core") == 0)) { 356 #endif 357 if ((clen + nlen) > sizeof (cpubuf)) 358 prom_panic("cpu node \"compatible\" too long"); 359 /* read in compatible, leaving space for ':' */ 360 if (prom_getprop(node, OBP_COMPATIBLE, 361 &cpubuf[nlen]) != clen) 362 prom_panic("cpu node \"compatible\" error"); 363 clen += nlen; /* total length */ 364 /* convert all null characters to ':' */ 365 clen--; /* except the final one... */ 366 for (i = 0; i < clen; i++) 367 if (cpubuf[i] == '\0') 368 cpubuf[i] = ':'; 369 } 370 #ifdef sun4u 371 /* 372 * Some PROMs return SUNW,UltraSPARC when they actually have 373 * SUNW,UltraSPARC-II cpus. SInce we're now filtering out all 374 * SUNW,UltraSPARC systems during the boot phase, we can safely 375 * point the auxv CPU value at SUNW,UltraSPARC-II. 376 */ 377 if (strcmp("SUNW,UltraSPARC", cpubuf) == 0) 378 (void) strcpy(cpubuf, "SUNW,UltraSPARC-II"); 379 #endif 380 return (cpubuf); 381 } else 382 return (NULL); 383 } 384 385 /* 386 * called immediately from _start to stich the 387 * primary modules together 388 */ 389 void 390 kobj_start(void *cif) 391 { 392 Ehdr *ehdr; 393 Phdr *phdr; 394 uint32_t eadr, padr; 395 val_t bootaux[BA_NUM]; 396 int i; 397 398 prom_init("kernel", cif); 399 bop_init(); 400 #ifdef DEBUG 401 if (bop_getproplen("stop-me") != -1) 402 prom_enter_mon(); 403 #endif 404 405 if (bop_getprop("elfheader-address", (caddr_t)&eadr) == -1) 406 prom_panic("no ELF image"); 407 ehdr = (Ehdr *)(uintptr_t)eadr; 408 for (i = 0; i < BA_NUM; i++) 409 bootaux[i].ba_val = NULL; 410 bootaux[BA_PHNUM].ba_val = ehdr->e_phnum; 411 bootaux[BA_PHENT].ba_val = ehdr->e_phentsize; 412 bootaux[BA_LDNAME].ba_ptr = NULL; 413 414 padr = eadr + ehdr->e_phoff; 415 bootaux[BA_PHDR].ba_ptr = (void *)(uintptr_t)padr; 416 for (i = 0; i < ehdr->e_phnum; i++) { 417 phdr = (Phdr *)((uintptr_t)padr + i * ehdr->e_phentsize); 418 if (phdr->p_type == PT_DYNAMIC) { 419 bootaux[BA_DYNAMIC].ba_ptr = (void *)phdr->p_vaddr; 420 break; 421 } 422 } 423 424 bootaux[BA_LPAGESZ].ba_val = MMU_PAGESIZE4M; 425 bootaux[BA_PAGESZ].ba_val = MMU_PAGESIZE; 426 bootaux[BA_IFLUSH].ba_val = 1; 427 bootaux[BA_CPU].ba_ptr = getcpulist(); 428 bootaux[BA_MMU].ba_ptr = NULL; 429 430 kobj_init(cif, NULL, bootops, bootaux); 431 432 /* kernel stitched together; we can now test #pragma's */ 433 if (&plat_setprop_enter != NULL) { 434 prom_setprop_enter = &plat_setprop_enter; 435 prom_setprop_exit = &plat_setprop_exit; 436 ASSERT(prom_setprop_exit != NULL); 437 } 438 439 } 440 441 /* 442 * Create modpath from kernel name. 443 * If we booted: 444 * /platform/`uname -i`/kernel/sparcv9/unix 445 * or 446 * /platform/`uname -m`/kernel/sparcv9/unix 447 * 448 * then make the modpath: 449 * /platform/`uname -i`/kernel /platform/`uname -m`/kernel 450 * 451 * otherwise, make the modpath the dir the kernel was 452 * loaded from, minus any sparcv9 extension 453 * 454 * note the sparcv9 dir is optional since a unix -> sparcv9/unix 455 * symlink is available as a shortcut. 456 */ 457 void 458 mach_modpath(char *path, const char *fname) 459 { 460 char *p; 461 int len, compat; 462 const char prefix[] = "/platform/"; 463 char platname[MAXPATHLEN]; 464 #ifdef sun4u 465 char defname[] = "sun4u"; 466 #else 467 char defname[] = "sun4v"; 468 #endif 469 const char suffix[] = "/kernel"; 470 const char isastr[] = "/sparcv9"; 471 472 /* 473 * check for /platform 474 */ 475 p = (char *)fname; 476 if (strncmp(p, prefix, sizeof (prefix) - 1) != 0) 477 goto nopath; 478 p += sizeof (prefix) - 1; 479 480 /* 481 * check for the default name or the platform name. 482 * also see if we used the 'compatible' name 483 * (platname == default) 484 */ 485 (void) bop_getprop("impl-arch-name", platname); 486 compat = strcmp(platname, defname) == 0; 487 len = strlen(platname); 488 if (strncmp(p, platname, len) == 0) 489 p += len; 490 else if (strncmp(p, defname, sizeof (defname) - 1) == 0) 491 p += sizeof (defname) - 1; 492 else 493 goto nopath; 494 495 /* 496 * check for /kernel/sparcv9 or just /kernel 497 */ 498 if (strncmp(p, suffix, sizeof (suffix) - 1) != 0) 499 goto nopath; 500 p += sizeof (suffix) - 1; 501 if (strncmp(p, isastr, sizeof (isastr) - 1) == 0) 502 p += sizeof (isastr) - 1; 503 504 /* 505 * check we're at the last component 506 */ 507 if (p != strrchr(fname, '/')) 508 goto nopath; 509 510 /* 511 * everything is kosher; setup modpath 512 */ 513 (void) strcpy(path, "/platform/"); 514 (void) strcat(path, platname); 515 (void) strcat(path, "/kernel "); 516 if (!compat) { 517 (void) strcat(path, "/platform/"); 518 (void) strcat(path, defname); 519 (void) strcat(path, "/kernel "); 520 } 521 return; 522 523 nopath: 524 /* 525 * Construct the directory path from the filename. 526 */ 527 if ((p = strrchr(fname, '/')) == NULL) 528 return; 529 530 while (p > fname && *(p - 1) == '/') 531 p--; /* remove trailing '/' characters */ 532 if (p == fname) 533 p++; /* so "/" -is- the modpath in this case */ 534 535 /* 536 * Remove optional isa-dependent directory name - the module 537 * subsystem will put this back again (!) 538 */ 539 len = p - fname; 540 if (len > sizeof (isastr) - 1 && 541 strncmp(&fname[len - (sizeof (isastr) - 1)], isastr, 542 sizeof (isastr) - 1) == 0) 543 p -= sizeof (isastr) - 1; 544 (void) strncpy(path, fname, p - fname); 545 } 546