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