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         sigorset(&p0.p_ignore, &ignoredefault);
 193 
 194         CPU->cpu_thread = &t0;
 195         CPU->cpu_dispthread = &t0;
 196         bzero(&cpu0_disp, sizeof (disp_t));
 197         CPU->cpu_disp = &cpu0_disp;
 198         CPU->cpu_disp->disp_cpu = CPU;
 199         CPU->cpu_idle_thread = &t0;
 200         CPU->cpu_flags = CPU_RUNNING;
 201         CPU->cpu_id = getprocessorid();
 202         CPU->cpu_dispatch_pri = t0.t_pri;
 203 
 204         /*
 205          * Initialize thread/cpu microstate accounting
 206          */
 207         init_mstate(&t0, LMS_SYSTEM);
 208         init_cpu_mstate(CPU, CMS_SYSTEM);
 209 
 210         /*
 211          * Initialize lists of available and active CPUs.
 212          */
 213         cpu_list_init(CPU);
 214 
 215         cpu_vm_data_init(CPU);
 216 
 217         pg_cpu_bootstrap(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(LGRP_INIT_STAGE1);
 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 }