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