xref: /illumos-gate/usr/src/uts/i86pc/os/mlsetup.c (revision cd2135d041662c75017487e2d4b9b69b7e0b8349)
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/sysmacros.h>
28 #include <sys/disp.h>
29 #include <sys/promif.h>
30 #include <sys/clock.h>
31 #include <sys/cpuvar.h>
32 #include <sys/stack.h>
33 #include <vm/as.h>
34 #include <vm/hat.h>
35 #include <sys/reboot.h>
36 #include <sys/avintr.h>
37 #include <sys/vtrace.h>
38 #include <sys/proc.h>
39 #include <sys/thread.h>
40 #include <sys/cpupart.h>
41 #include <sys/pset.h>
42 #include <sys/copyops.h>
43 #include <sys/pg.h>
44 #include <sys/disp.h>
45 #include <sys/debug.h>
46 #include <sys/sunddi.h>
47 #include <sys/x86_archext.h>
48 #include <sys/privregs.h>
49 #include <sys/machsystm.h>
50 #include <sys/ontrap.h>
51 #include <sys/bootconf.h>
52 #include <sys/boot_console.h>
53 #include <sys/kdi_machimpl.h>
54 #include <sys/archsystm.h>
55 #include <sys/promif.h>
56 #include <sys/pci_cfgspace.h>
57 #ifdef __xpv
58 #include <sys/hypervisor.h>
59 #else
60 #include <sys/xpv_support.h>
61 #endif
62 
63 /*
64  * some globals for patching the result of cpuid
65  * to solve problems w/ creative cpu vendors
66  */
67 
68 extern uint32_t cpuid_feature_ecx_include;
69 extern uint32_t cpuid_feature_ecx_exclude;
70 extern uint32_t cpuid_feature_edx_include;
71 extern uint32_t cpuid_feature_edx_exclude;
72 
73 /*
74  * Dummy spl priority masks
75  */
76 static unsigned char dummy_cpu_pri[MAXIPL + 1] = {
77 	0xf, 0xf, 0xf, 0xf, 0xf, 0xf, 0xf, 0xf,
78 	0xf, 0xf, 0xf, 0xf, 0xf, 0xf, 0xf, 0xf, 0xf
79 };
80 
81 /*
82  * Set console mode
83  */
84 static void
85 set_console_mode(uint8_t val)
86 {
87 	struct bop_regs rp = {0};
88 
89 	rp.eax.byte.ah = 0x0;
90 	rp.eax.byte.al = val;
91 	rp.ebx.word.bx = 0x0;
92 
93 	BOP_DOINT(bootops, 0x10, &rp);
94 }
95 
96 
97 /*
98  * Setup routine called right before main(). Interposing this function
99  * before main() allows us to call it in a machine-independent fashion.
100  */
101 void
102 mlsetup(struct regs *rp)
103 {
104 	u_longlong_t prop_value;
105 	extern struct classfuncs sys_classfuncs;
106 	extern disp_t cpu0_disp;
107 	extern char t0stack[];
108 	extern int post_fastreboot;
109 	extern int console;
110 
111 	ASSERT_STACK_ALIGNED();
112 
113 	/*
114 	 * initialize cpu_self
115 	 */
116 	cpu[0]->cpu_self = cpu[0];
117 
118 #if defined(__xpv)
119 	/*
120 	 * Point at the hypervisor's virtual cpu structure
121 	 */
122 	cpu[0]->cpu_m.mcpu_vcpu_info = &HYPERVISOR_shared_info->vcpu_info[0];
123 #endif
124 
125 	/*
126 	 * Set up dummy cpu_pri_data values till psm spl code is
127 	 * installed.  This allows splx() to work on amd64.
128 	 */
129 
130 	cpu[0]->cpu_pri_data = dummy_cpu_pri;
131 
132 	/*
133 	 * check if we've got special bits to clear or set
134 	 * when checking cpu features
135 	 */
136 
137 	if (bootprop_getval("cpuid_feature_ecx_include", &prop_value) != 0)
138 		cpuid_feature_ecx_include = 0;
139 	else
140 		cpuid_feature_ecx_include = (uint32_t)prop_value;
141 
142 	if (bootprop_getval("cpuid_feature_ecx_exclude", &prop_value) != 0)
143 		cpuid_feature_ecx_exclude = 0;
144 	else
145 		cpuid_feature_ecx_exclude = (uint32_t)prop_value;
146 
147 	if (bootprop_getval("cpuid_feature_edx_include", &prop_value) != 0)
148 		cpuid_feature_edx_include = 0;
149 	else
150 		cpuid_feature_edx_include = (uint32_t)prop_value;
151 
152 	if (bootprop_getval("cpuid_feature_edx_exclude", &prop_value) != 0)
153 		cpuid_feature_edx_exclude = 0;
154 	else
155 		cpuid_feature_edx_exclude = (uint32_t)prop_value;
156 
157 	/*
158 	 * The first lightweight pass (pass0) through the cpuid data
159 	 * was done in locore before mlsetup was called.  Do the next
160 	 * pass in C code.
161 	 *
162 	 * The x86_feature bits are set here on the basis of the capabilities
163 	 * of the boot CPU.  Note that if we choose to support CPUs that have
164 	 * different feature sets (at which point we would almost certainly
165 	 * want to set the feature bits to correspond to the feature
166 	 * minimum) this value may be altered.
167 	 */
168 	x86_feature = cpuid_pass1(cpu[0]);
169 
170 	/*
171 	 * Initialize idt0, gdt0, ldt0_default, ktss0 and dftss.
172 	 */
173 	init_desctbls();
174 
175 #if !defined(__xpv)
176 
177 	if (get_hwenv() == HW_XEN_HVM)
178 		xen_hvm_init();
179 
180 	/*
181 	 * Patch the tsc_read routine with appropriate set of instructions,
182 	 * depending on the processor family and architecure, to read the
183 	 * time-stamp counter while ensuring no out-of-order execution.
184 	 * Patch it while the kernel text is still writable.
185 	 *
186 	 * Note: tsc_read is not patched for intel processors whose family
187 	 * is >6 and for amd whose family >f (in case they don't support rdtscp
188 	 * instruction, unlikely). By default tsc_read will use cpuid for
189 	 * serialization in such cases. The following code needs to be
190 	 * revisited if intel processors of family >= f retains the
191 	 * instruction serialization nature of mfence instruction.
192 	 * Note: tsc_read is not patched for x86 processors which do
193 	 * not support "mfence". By default tsc_read will use cpuid for
194 	 * serialization in such cases.
195 	 *
196 	 * The Xen hypervisor does not correctly report whether rdtscp is
197 	 * supported or not, so we must assume that it is not.
198 	 */
199 	if (get_hwenv() != HW_XEN_HVM && (x86_feature & X86_TSCP))
200 		patch_tsc_read(X86_HAVE_TSCP);
201 	else if (cpuid_getvendor(CPU) == X86_VENDOR_AMD &&
202 	    cpuid_getfamily(CPU) <= 0xf && (x86_feature & X86_SSE2) != 0)
203 		patch_tsc_read(X86_TSC_MFENCE);
204 	else if (cpuid_getvendor(CPU) == X86_VENDOR_Intel &&
205 	    cpuid_getfamily(CPU) <= 6 && (x86_feature & X86_SSE2) != 0)
206 		patch_tsc_read(X86_TSC_LFENCE);
207 
208 #endif	/* !__xpv */
209 
210 #if defined(__i386) && !defined(__xpv)
211 	/*
212 	 * Some i386 processors do not implement the rdtsc instruction,
213 	 * or at least they do not implement it correctly. Patch them to
214 	 * return 0.
215 	 */
216 	if ((x86_feature & X86_TSC) == 0)
217 		patch_tsc_read(X86_NO_TSC);
218 #endif	/* __i386 && !__xpv */
219 
220 #if defined(__amd64) && !defined(__xpv)
221 	patch_memops(cpuid_getvendor(CPU));
222 #endif	/* __amd64 && !__xpv */
223 
224 #if !defined(__xpv)
225 	/* XXPV	what, if anything, should be dorked with here under xen? */
226 
227 	/*
228 	 * While we're thinking about the TSC, let's set up %cr4 so that
229 	 * userland can issue rdtsc, and initialize the TSC_AUX value
230 	 * (the cpuid) for the rdtscp instruction on appropriately
231 	 * capable hardware.
232 	 */
233 	if (x86_feature & X86_TSC)
234 		setcr4(getcr4() & ~CR4_TSD);
235 
236 	if (x86_feature & X86_TSCP)
237 		(void) wrmsr(MSR_AMD_TSCAUX, 0);
238 
239 	if (x86_feature & X86_DE)
240 		setcr4(getcr4() | CR4_DE);
241 #endif /* __xpv */
242 
243 	/*
244 	 * initialize t0
245 	 */
246 	t0.t_stk = (caddr_t)rp - MINFRAME;
247 	t0.t_stkbase = t0stack;
248 	t0.t_pri = maxclsyspri - 3;
249 	t0.t_schedflag = TS_LOAD | TS_DONT_SWAP;
250 	t0.t_procp = &p0;
251 	t0.t_plockp = &p0lock.pl_lock;
252 	t0.t_lwp = &lwp0;
253 	t0.t_forw = &t0;
254 	t0.t_back = &t0;
255 	t0.t_next = &t0;
256 	t0.t_prev = &t0;
257 	t0.t_cpu = cpu[0];
258 	t0.t_disp_queue = &cpu0_disp;
259 	t0.t_bind_cpu = PBIND_NONE;
260 	t0.t_bind_pset = PS_NONE;
261 	t0.t_bindflag = (uchar_t)default_binding_mode;
262 	t0.t_cpupart = &cp_default;
263 	t0.t_clfuncs = &sys_classfuncs.thread;
264 	t0.t_copyops = NULL;
265 	THREAD_ONPROC(&t0, CPU);
266 
267 	lwp0.lwp_thread = &t0;
268 	lwp0.lwp_regs = (void *)rp;
269 	lwp0.lwp_procp = &p0;
270 	t0.t_tid = p0.p_lwpcnt = p0.p_lwprcnt = p0.p_lwpid = 1;
271 
272 	p0.p_exec = NULL;
273 	p0.p_stat = SRUN;
274 	p0.p_flag = SSYS;
275 	p0.p_tlist = &t0;
276 	p0.p_stksize = 2*PAGESIZE;
277 	p0.p_stkpageszc = 0;
278 	p0.p_as = &kas;
279 	p0.p_lockp = &p0lock;
280 	p0.p_brkpageszc = 0;
281 	p0.p_t1_lgrpid = LGRP_NONE;
282 	p0.p_tr_lgrpid = LGRP_NONE;
283 	sigorset(&p0.p_ignore, &ignoredefault);
284 
285 	CPU->cpu_thread = &t0;
286 	bzero(&cpu0_disp, sizeof (disp_t));
287 	CPU->cpu_disp = &cpu0_disp;
288 	CPU->cpu_disp->disp_cpu = CPU;
289 	CPU->cpu_dispthread = &t0;
290 	CPU->cpu_idle_thread = &t0;
291 	CPU->cpu_flags = CPU_READY | CPU_RUNNING | CPU_EXISTS | CPU_ENABLE;
292 	CPU->cpu_dispatch_pri = t0.t_pri;
293 
294 	CPU->cpu_id = 0;
295 
296 	CPU->cpu_pri = 12;		/* initial PIL for the boot CPU */
297 
298 	/*
299 	 * The kernel doesn't use LDTs unless a process explicitly requests one.
300 	 */
301 	p0.p_ldt_desc = null_sdesc;
302 
303 	/*
304 	 * Initialize thread/cpu microstate accounting
305 	 */
306 	init_mstate(&t0, LMS_SYSTEM);
307 	init_cpu_mstate(CPU, CMS_SYSTEM);
308 
309 	/*
310 	 * Initialize lists of available and active CPUs.
311 	 */
312 	cpu_list_init(CPU);
313 
314 	pg_cpu_bootstrap(CPU);
315 
316 	/*
317 	 * Now that we have taken over the GDT, IDT and have initialized
318 	 * active CPU list it's time to inform kmdb if present.
319 	 */
320 	if (boothowto & RB_DEBUG)
321 		kdi_idt_sync();
322 
323 	/*
324 	 * Explicitly set console to text mode (0x3) if this is a boot
325 	 * post Fast Reboot, and the console is set to CONS_SCREEN_TEXT.
326 	 */
327 	if (post_fastreboot && console == CONS_SCREEN_TEXT)
328 		set_console_mode(0x3);
329 
330 	/*
331 	 * If requested (boot -d) drop into kmdb.
332 	 *
333 	 * This must be done after cpu_list_init() on the 64-bit kernel
334 	 * since taking a trap requires that we re-compute gsbase based
335 	 * on the cpu list.
336 	 */
337 	if (boothowto & RB_DEBUGENTER)
338 		kmdb_enter();
339 
340 	cpu_vm_data_init(CPU);
341 
342 	/* lgrp_init() needs PCI config space access */
343 #if defined(__xpv)
344 	if (DOMAIN_IS_INITDOMAIN(xen_info))
345 		pci_cfgspace_init();
346 #else
347 	pci_cfgspace_init();
348 #endif
349 
350 	rp->r_fp = 0;	/* terminate kernel stack traces! */
351 
352 	prom_init("kernel", (void *)NULL);
353 
354 	if (bootprop_getval("boot-ncpus", &prop_value) != 0)
355 		boot_ncpus = NCPU;
356 	else {
357 		boot_ncpus = (int)prop_value;
358 		if (boot_ncpus <= 0 || boot_ncpus > NCPU)
359 			boot_ncpus = NCPU;
360 	}
361 
362 	max_ncpus = boot_max_ncpus = boot_ncpus;
363 
364 	/*
365 	 * Initialize the lgrp framework
366 	 */
367 	lgrp_init();
368 
369 	if (boothowto & RB_HALT) {
370 		prom_printf("unix: kernel halted by -h flag\n");
371 		prom_enter_mon();
372 	}
373 
374 	ASSERT_STACK_ALIGNED();
375 
376 	/*
377 	 * Fill out cpu_ucode_info.  Update microcode if necessary.
378 	 */
379 	ucode_check(CPU);
380 
381 	if (workaround_errata(CPU) != 0)
382 		panic("critical workaround(s) missing for boot cpu");
383 }
384 
385 
386 void
387 mach_modpath(char *path, const char *filename)
388 {
389 	/*
390 	 * Construct the directory path from the filename.
391 	 */
392 
393 	int len;
394 	char *p;
395 	const char isastr[] = "/amd64";
396 	size_t isalen = strlen(isastr);
397 
398 	if ((p = strrchr(filename, '/')) == NULL)
399 		return;
400 
401 	while (p > filename && *(p - 1) == '/')
402 		p--;	/* remove trailing '/' characters */
403 	if (p == filename)
404 		p++;	/* so "/" -is- the modpath in this case */
405 
406 	/*
407 	 * Remove optional isa-dependent directory name - the module
408 	 * subsystem will put this back again (!)
409 	 */
410 	len = p - filename;
411 	if (len > isalen &&
412 	    strncmp(&filename[len - isalen], isastr, isalen) == 0)
413 		p -= isalen;
414 
415 	/*
416 	 * "/platform/mumblefrotz" + " " + MOD_DEFPATH
417 	 */
418 	len += (p - filename) + 1 + strlen(MOD_DEFPATH) + 1;
419 	(void) strncpy(path, filename, p - filename);
420 }
421