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.
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.
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]
22 * Copyright 2009 Sun Microsystems, Inc. All rights reserved.
23 * Use is subject to license terms.
26 #include <sys/types.h>
27 #include <sys/systm.h>
28 #include <sys/archsystm.h>
29 #include <sys/machsystm.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>
40 #include <sys/stack.h>
41 #include <sys/intreg.h>
42 #include <sys/ivintr.h>
44 #include <vm/hat_sfmmu.h>
45 #include <sys/reboot.h>
46 #include <sys/sysmacros.h>
47 #include <sys/vtrace.h>
49 #include <sys/machtrap.h>
50 #include <sys/privregs.h>
51 #include <sys/machpcb.h>
53 #include <sys/cpupart.h>
55 #include <sys/cpu_module.h>
56 #include <sys/copyops.h>
57 #include <sys/panic.h>
58 #include <sys/bootconf.h> /* for bootops */
61 #include <sys/fpras.h>
63 #include <sys/prom_debug.h>
64 #include <sys/debug.h>
66 #include <sys/sunddi.h>
68 #include <sys/traptrace.h>
70 #include <sys/kobj_impl.h>
71 #include <sys/kdi_machimpl.h>
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);
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) */
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.
106 int fpras_implemented
;
108 int fpras_disableids
;
113 static void kern_splr_preprom(void);
114 static void kern_splx_postprom(void);
117 * Setup routine called right before main(). Interposing this function
118 * before main() allows us to call it in a machine-independent fashion.
122 mlsetup(struct regs
*rp
, kfpu_t
*fp
)
124 struct machpcb
*mpcb
;
126 extern char t0stack
[];
127 extern struct classfuncs sys_classfuncs
;
128 extern disp_t cpu0_disp
;
129 unsigned long long pa
;
132 TRAP_TRACE_CTL
*ctlp
;
133 #endif /* TRAPTRACE */
135 /* drop into kmdb on boot -d */
136 if (boothowto
& RB_DEBUGENTER
)
140 * initialize cpu_self
142 cpu0
.cpu_self
= &cpu0
;
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
;
153 t0
.t_plockp
= &p0lock
.pl_lock
;
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
;
167 THREAD_ONPROC(&t0
, CPU
);
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;
174 mpcb
= lwptompcb(&lwp0
);
176 mpcb
->mpcb_fpu
->fpu_q
= mpcb
->mpcb_fpu_q
;
177 mpcb
->mpcb_thread
= &t0
;
178 lwp0
.lwp_fpu
= (void *)mpcb
->mpcb_fpu
;
184 p0
.p_stksize
= 2*PAGESIZE
;
187 p0
.p_lockp
= &p0lock
;
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
);
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
;
207 * Initialize thread/cpu microstate accounting
209 init_mstate(&t0
, LMS_SYSTEM
);
210 init_cpu_mstate(CPU
, CMS_SYSTEM
);
213 * Initialize lists of available and active CPUs.
217 cpu_vm_data_init(CPU
);
219 pg_cpu_bootstrap(CPU
);
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");
225 mpcb
->mpcb_pa
= va_to_pa(t0
.t_stk
);
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.
232 if (prom_claim_virt(PANICBUFSIZE
, panicbuf
) != panicbuf
)
233 prom_panic("Can't claim panicbuf virtual address");
235 if (prom_retain("panicbuf", PANICBUFSIZE
, MMU_PAGESIZE
, &pa
) != 0)
236 prom_panic("Can't allocate retained panicbuf physical address");
238 if (prom_map_phys(-1, PANICBUFSIZE
, panicbuf
, pa
) != 0)
239 prom_panic("Can't map panicbuf");
245 * Negotiate hypervisor services, if any
248 mach_soft_state_init();
252 * initialize the trap trace buffer for the boot cpu
253 * XXX todo, dynamically allocate this buffer too
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 */
263 * Initialize the Machine Description kernel framework
266 mach_descrip_startup_init();
269 * initialize HV trap trace buffer for the boot cpu
271 mach_htraptrace_setup(CPU
->cpu_id
);
272 mach_htraptrace_configure(CPU
->cpu_id
);
275 * lgroup framework initialization. This must be done prior
276 * to devices being mapped.
278 lgrp_init(LGRP_INIT_STAGE1
);
282 if (boothowto
& RB_HALT
) {
283 prom_printf("unix: kernel halted by -h flag\n");
288 map_wellknown_devices();
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.
299 static int saved_spl
;
302 kern_splr_preprom(void)
308 kern_splx_postprom(void)
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
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.
330 /* big enough for OBP_NAME and for a reasonably sized OBP_COMPATIBLE. */
331 static char cpubuf
[5 * OBP_MAXDRVNAME
];
334 char dname
[OBP_MAXDRVNAME
];
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");
344 /* nlen includes the terminating null character */
346 if ((clen
= prom_getproplen(node
, OBP_COMPATIBLE
)) > 0) {
349 * For the CMT case, need check the parent "core"
350 * node for the compatible property.
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)) {
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')
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.
379 if (strcmp("SUNW,UltraSPARC", cpubuf
) == 0)
380 (void) strcpy(cpubuf
, "SUNW,UltraSPARC-II");
388 * called immediately from _start to stich the
389 * primary modules together
392 kobj_start(void *cif
)
397 val_t bootaux
[BA_NUM
];
400 prom_init("kernel", cif
);
403 if (bop_getproplen("stop-me") != -1)
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
;
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
;
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
;
432 kobj_init(cif
, NULL
, bootops
, bootaux
);
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
);
444 * Create modpath from kernel name.
446 * /platform/`uname -i`/kernel/sparcv9/unix
448 * /platform/`uname -m`/kernel/sparcv9/unix
450 * then make the modpath:
451 * /platform/`uname -i`/kernel /platform/`uname -m`/kernel
453 * otherwise, make the modpath the dir the kernel was
454 * loaded from, minus any sparcv9 extension
456 * note the sparcv9 dir is optional since a unix -> sparcv9/unix
457 * symlink is available as a shortcut.
460 mach_modpath(char *path
, const char *fname
)
464 const char prefix
[] = "/platform/";
465 char platname
[MAXPATHLEN
];
467 char defname
[] = "sun4u";
469 char defname
[] = "sun4v";
471 const char suffix
[] = "/kernel";
472 const char isastr
[] = "/sparcv9";
475 * check for /platform
478 if (strncmp(p
, prefix
, sizeof (prefix
) - 1) != 0)
480 p
+= sizeof (prefix
) - 1;
483 * check for the default name or the platform name.
484 * also see if we used the 'compatible' name
485 * (platname == default)
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)
492 else if (strncmp(p
, defname
, sizeof (defname
) - 1) == 0)
493 p
+= sizeof (defname
) - 1;
498 * check for /kernel/sparcv9 or just /kernel
500 if (strncmp(p
, suffix
, sizeof (suffix
) - 1) != 0)
502 p
+= sizeof (suffix
) - 1;
503 if (strncmp(p
, isastr
, sizeof (isastr
) - 1) == 0)
504 p
+= sizeof (isastr
) - 1;
507 * check we're at the last component
509 if (p
!= strrchr(fname
, '/'))
513 * everything is kosher; setup modpath
515 (void) strcpy(path
, "/platform/");
516 (void) strcat(path
, platname
);
517 (void) strcat(path
, "/kernel");
519 (void) strcat(path
, " /platform/");
520 (void) strcat(path
, defname
);
521 (void) strcat(path
, "/kernel");
527 * Construct the directory path from the filename.
529 if ((p
= strrchr(fname
, '/')) == NULL
)
532 while (p
> fname
&& *(p
- 1) == '/')
533 p
--; /* remove trailing '/' characters */
535 p
++; /* so "/" -is- the modpath in this case */
538 * Remove optional isa-dependent directory name - the module
539 * subsystem will put this back again (!)
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
);