xref: /onnv-gate/usr/src/uts/i86pc/os/mp_pc.c (revision 3446:5903aece022d)
1*3446Smrj /*
2*3446Smrj  * CDDL HEADER START
3*3446Smrj  *
4*3446Smrj  * The contents of this file are subject to the terms of the
5*3446Smrj  * Common Development and Distribution License (the "License").
6*3446Smrj  * You may not use this file except in compliance with the License.
7*3446Smrj  *
8*3446Smrj  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9*3446Smrj  * or http://www.opensolaris.org/os/licensing.
10*3446Smrj  * See the License for the specific language governing permissions
11*3446Smrj  * and limitations under the License.
12*3446Smrj  *
13*3446Smrj  * When distributing Covered Code, include this CDDL HEADER in each
14*3446Smrj  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15*3446Smrj  * If applicable, add the following below this CDDL HEADER, with the
16*3446Smrj  * fields enclosed by brackets "[]" replaced with your own identifying
17*3446Smrj  * information: Portions Copyright [yyyy] [name of copyright owner]
18*3446Smrj  *
19*3446Smrj  * CDDL HEADER END
20*3446Smrj  */
21*3446Smrj /*
22*3446Smrj  * Copyright 2007 Sun Microsystems, Inc.  All rights reserved.
23*3446Smrj  * Use is subject to license terms.
24*3446Smrj  */
25*3446Smrj 
26*3446Smrj #pragma ident	"%Z%%M%	%I%	%E% SMI"
27*3446Smrj 
28*3446Smrj /*
29*3446Smrj  * Welcome to the world of the "real mode platter".
30*3446Smrj  * See also startup.c, mpcore.s and apic.c for related routines.
31*3446Smrj  */
32*3446Smrj 
33*3446Smrj #include <sys/types.h>
34*3446Smrj #include <sys/systm.h>
35*3446Smrj #include <sys/cpuvar.h>
36*3446Smrj #include <sys/kmem.h>
37*3446Smrj #include <sys/archsystm.h>
38*3446Smrj #include <sys/machsystm.h>
39*3446Smrj #include <sys/controlregs.h>
40*3446Smrj #include <sys/x86_archext.h>
41*3446Smrj #include <sys/smp_impldefs.h>
42*3446Smrj #include <sys/sysmacros.h>
43*3446Smrj #include <sys/mach_mmu.h>
44*3446Smrj #include <sys/promif.h>
45*3446Smrj #include <sys/cpu.h>
46*3446Smrj 
47*3446Smrj extern void real_mode_start(void);
48*3446Smrj extern void real_mode_end(void);
49*3446Smrj 
50*3446Smrj /*
51*3446Smrj  * Fill up the real mode platter to make it easy for real mode code to
52*3446Smrj  * kick it off. This area should really be one passed by boot to kernel
53*3446Smrj  * and guaranteed to be below 1MB and aligned to 16 bytes. Should also
54*3446Smrj  * have identical physical and virtual address in paged mode.
55*3446Smrj  */
56*3446Smrj static ushort_t *warm_reset_vector = NULL;
57*3446Smrj 
58*3446Smrj int
59*3446Smrj mach_cpucontext_init(void)
60*3446Smrj {
61*3446Smrj 	ushort_t *vec;
62*3446Smrj 
63*3446Smrj 	if (!(vec = (ushort_t *)psm_map_phys(WARM_RESET_VECTOR,
64*3446Smrj 	    sizeof (vec), PROT_READ | PROT_WRITE)))
65*3446Smrj 		return (-1);
66*3446Smrj 	/*
67*3446Smrj 	 * setup secondary cpu bios boot up vector
68*3446Smrj 	 */
69*3446Smrj 	*vec = (ushort_t)((caddr_t)
70*3446Smrj 		((struct rm_platter *)rm_platter_va)->rm_code - rm_platter_va
71*3446Smrj 		+ ((ulong_t)rm_platter_va & 0xf));
72*3446Smrj 	vec[1] = (ushort_t)(rm_platter_pa >> 4);
73*3446Smrj 	warm_reset_vector = vec;
74*3446Smrj 
75*3446Smrj 	bcopy((caddr_t)real_mode_start,
76*3446Smrj 	    (caddr_t)((rm_platter_t *)rm_platter_va)->rm_code,
77*3446Smrj 	    (size_t)real_mode_end - (size_t)real_mode_start);
78*3446Smrj 
79*3446Smrj 	return (0);
80*3446Smrj }
81*3446Smrj 
82*3446Smrj void
83*3446Smrj mach_cpucontext_fini(void)
84*3446Smrj {
85*3446Smrj 	if (warm_reset_vector)
86*3446Smrj 		psm_unmap_phys((caddr_t)warm_reset_vector,
87*3446Smrj 		    sizeof (warm_reset_vector));
88*3446Smrj 	hat_unload(kas.a_hat, (caddr_t)(uintptr_t)rm_platter_pa, MMU_PAGESIZE,
89*3446Smrj 	    HAT_UNLOAD);
90*3446Smrj }
91*3446Smrj 
92*3446Smrj #if defined(__amd64)
93*3446Smrj extern void *long_mode_64(void);
94*3446Smrj #endif	/* __amd64 */
95*3446Smrj 
96*3446Smrj void *
97*3446Smrj mach_cpucontext_alloc(struct cpu *cp)
98*3446Smrj {
99*3446Smrj 	rm_platter_t *rm = (rm_platter_t *)rm_platter_va;
100*3446Smrj 	struct cpu_tables *ct;
101*3446Smrj 	struct tss *ntss;
102*3446Smrj 
103*3446Smrj 	/*
104*3446Smrj 	 * Allocate space for page directory, stack, tss, gdt and idt.
105*3446Smrj 	 * The page directory has to be page aligned
106*3446Smrj 	 */
107*3446Smrj 	ct = kmem_zalloc(sizeof (*ct), KM_SLEEP);
108*3446Smrj 	if ((uintptr_t)ct & ~MMU_STD_PAGEMASK)
109*3446Smrj 		panic("mp_startup_init: cpu%d misaligned tables", cp->cpu_id);
110*3446Smrj 
111*3446Smrj 	ntss = cp->cpu_tss = &ct->ct_tss;
112*3446Smrj 
113*3446Smrj #if defined(__amd64)
114*3446Smrj 
115*3446Smrj 	/*
116*3446Smrj 	 * #DF (double fault).
117*3446Smrj 	 */
118*3446Smrj 	ntss->tss_ist1 = (uint64_t)&ct->ct_stack[sizeof (ct->ct_stack)];
119*3446Smrj 
120*3446Smrj #elif defined(__i386)
121*3446Smrj 
122*3446Smrj 	ntss->tss_esp0 = ntss->tss_esp1 = ntss->tss_esp2 = ntss->tss_esp =
123*3446Smrj 	    (uint32_t)&ct->ct_stack[sizeof (ct->ct_stack)];
124*3446Smrj 
125*3446Smrj 	ntss->tss_ss0 = ntss->tss_ss1 = ntss->tss_ss2 = ntss->tss_ss = KDS_SEL;
126*3446Smrj 
127*3446Smrj 	ntss->tss_eip = (uint32_t)cp->cpu_thread->t_pc;
128*3446Smrj 
129*3446Smrj 	ntss->tss_cs = KCS_SEL;
130*3446Smrj 	ntss->tss_ds = ntss->tss_es = KDS_SEL;
131*3446Smrj 	ntss->tss_fs = KFS_SEL;
132*3446Smrj 	ntss->tss_gs = KGS_SEL;
133*3446Smrj 
134*3446Smrj #endif	/* __i386 */
135*3446Smrj 
136*3446Smrj 	/*
137*3446Smrj 	 * Set I/O bit map offset equal to size of TSS segment limit
138*3446Smrj 	 * for no I/O permission map. This will cause all user I/O
139*3446Smrj 	 * instructions to generate #gp fault.
140*3446Smrj 	 */
141*3446Smrj 	ntss->tss_bitmapbase = sizeof (*ntss);
142*3446Smrj 
143*3446Smrj 	/*
144*3446Smrj 	 * Setup kernel tss.
145*3446Smrj 	 */
146*3446Smrj 	set_syssegd((system_desc_t *)&cp->cpu_gdt[GDT_KTSS], cp->cpu_tss,
147*3446Smrj 	    sizeof (*cp->cpu_tss) -1, SDT_SYSTSS, SEL_KPL);
148*3446Smrj 
149*3446Smrj 	/*
150*3446Smrj 	 * Now copy all that we've set up onto the real mode platter
151*3446Smrj 	 * for the real mode code to digest as part of starting the cpu.
152*3446Smrj 	 */
153*3446Smrj 
154*3446Smrj 	rm->rm_idt_base = cp->cpu_idt;
155*3446Smrj 	rm->rm_idt_lim = sizeof (idt0) - 1;
156*3446Smrj 	rm->rm_gdt_base = cp->cpu_gdt;
157*3446Smrj 	rm->rm_gdt_lim = ((sizeof (*cp->cpu_gdt) * NGDT)) -1;
158*3446Smrj 
159*3446Smrj 	rm->rm_pdbr = getcr3();
160*3446Smrj 	rm->rm_cpu = cp->cpu_id;
161*3446Smrj 	rm->rm_x86feature = x86_feature;
162*3446Smrj 	rm->rm_cr4 = getcr4();
163*3446Smrj 
164*3446Smrj #if defined(__amd64)
165*3446Smrj 
166*3446Smrj 	if (getcr3() > 0xffffffffUL)
167*3446Smrj 		panic("Cannot initialize CPUs; kernel's 64-bit page tables\n"
168*3446Smrj 		    "located above 4G in physical memory (@ 0x%lx)", getcr3());
169*3446Smrj 
170*3446Smrj 	/*
171*3446Smrj 	 * Setup pseudo-descriptors for temporary GDT and IDT for use ONLY
172*3446Smrj 	 * by code in real_mode_start():
173*3446Smrj 	 *
174*3446Smrj 	 * GDT[0]:  NULL selector
175*3446Smrj 	 * GDT[1]:  64-bit CS: Long = 1, Present = 1, bits 12, 11 = 1
176*3446Smrj 	 *
177*3446Smrj 	 * Clear the IDT as interrupts will be off and a limit of 0 will cause
178*3446Smrj 	 * the CPU to triple fault and reset on an NMI, seemingly as reasonable
179*3446Smrj 	 * a course of action as any other, though it may cause the entire
180*3446Smrj 	 * platform to reset in some cases...
181*3446Smrj 	 */
182*3446Smrj 	rm->rm_temp_gdt[0] = 0;
183*3446Smrj 	rm->rm_temp_gdt[TEMPGDT_KCODE64] = 0x20980000000000ULL;
184*3446Smrj 
185*3446Smrj 	rm->rm_temp_gdt_lim = (ushort_t)(sizeof (rm->rm_temp_gdt) - 1);
186*3446Smrj 	rm->rm_temp_gdt_base = rm_platter_pa +
187*3446Smrj 	    (uint32_t)offsetof(rm_platter_t, rm_temp_gdt);
188*3446Smrj 	rm->rm_temp_idt_lim = 0;
189*3446Smrj 	rm->rm_temp_idt_base = 0;
190*3446Smrj 
191*3446Smrj 	/*
192*3446Smrj 	 * Since the CPU needs to jump to protected mode using an identity
193*3446Smrj 	 * mapped address, we need to calculate it here.
194*3446Smrj 	 */
195*3446Smrj 	rm->rm_longmode64_addr = rm_platter_pa +
196*3446Smrj 	    ((uint32_t)long_mode_64 - (uint32_t)real_mode_start);
197*3446Smrj #endif	/* __amd64 */
198*3446Smrj 
199*3446Smrj 	return (ct);
200*3446Smrj }
201*3446Smrj 
202*3446Smrj /*ARGSUSED*/
203*3446Smrj void
204*3446Smrj mach_cpucontext_free(struct cpu *cp, void *arg, int err)
205*3446Smrj {
206*3446Smrj 	struct cpu_tables *ct = arg;
207*3446Smrj 
208*3446Smrj 	ASSERT(&ct->ct_tss == cp->cpu_tss);
209*3446Smrj 
210*3446Smrj 	switch (err) {
211*3446Smrj 	case 0:
212*3446Smrj 		break;
213*3446Smrj 	case ETIMEDOUT:
214*3446Smrj 		/*
215*3446Smrj 		 * The processor was poked, but failed to start before
216*3446Smrj 		 * we gave up waiting for it.  In case it starts later,
217*3446Smrj 		 * don't free anything.
218*3446Smrj 		 */
219*3446Smrj 		break;
220*3446Smrj 	default:
221*3446Smrj 		/*
222*3446Smrj 		 * Some other, passive, error occurred.
223*3446Smrj 		 */
224*3446Smrj 		kmem_free(ct, sizeof (*ct));
225*3446Smrj 		cp->cpu_tss = NULL;
226*3446Smrj 		break;
227*3446Smrj 	}
228*3446Smrj }
229*3446Smrj 
230*3446Smrj /*
231*3446Smrj  * "Enter monitor."  Called via cross-call from stop_other_cpus().
232*3446Smrj  */
233*3446Smrj void
234*3446Smrj mach_cpu_halt(char *msg)
235*3446Smrj {
236*3446Smrj 	if (msg)
237*3446Smrj 		prom_printf("%s\n", msg);
238*3446Smrj 
239*3446Smrj 	/*CONSTANTCONDITION*/
240*3446Smrj 	while (1)
241*3446Smrj 		;
242*3446Smrj }
243*3446Smrj 
244*3446Smrj void
245*3446Smrj mach_cpu_idle(void)
246*3446Smrj {
247*3446Smrj 	i86_halt();
248*3446Smrj }
249*3446Smrj 
250*3446Smrj void
251*3446Smrj mach_cpu_pause(volatile char *safe)
252*3446Smrj {
253*3446Smrj 	/*
254*3446Smrj 	 * This cpu is now safe.
255*3446Smrj 	 */
256*3446Smrj 	*safe = PAUSE_WAIT;
257*3446Smrj 	membar_enter(); /* make sure stores are flushed */
258*3446Smrj 
259*3446Smrj 	/*
260*3446Smrj 	 * Now we wait.  When we are allowed to continue, safe
261*3446Smrj 	 * will be set to PAUSE_IDLE.
262*3446Smrj 	 */
263*3446Smrj 	while (*safe != PAUSE_IDLE)
264*3446Smrj 		SMT_PAUSE();
265*3446Smrj }
266*3446Smrj 
267*3446Smrj /*
268*3446Smrj  * Power on CPU.
269*3446Smrj  */
270*3446Smrj /*ARGSUSED*/
271*3446Smrj int
272*3446Smrj mp_cpu_poweron(struct cpu *cp)
273*3446Smrj {
274*3446Smrj 	ASSERT(MUTEX_HELD(&cpu_lock));
275*3446Smrj 	return (ENOTSUP);		/* not supported */
276*3446Smrj }
277*3446Smrj 
278*3446Smrj /*
279*3446Smrj  * Power off CPU.
280*3446Smrj  */
281*3446Smrj /*ARGSUSED*/
282*3446Smrj int
283*3446Smrj mp_cpu_poweroff(struct cpu *cp)
284*3446Smrj {
285*3446Smrj 	ASSERT(MUTEX_HELD(&cpu_lock));
286*3446Smrj 	return (ENOTSUP);		/* not supported */
287*3446Smrj }
288