]> git.saurik.com Git - apple/xnu.git/blob - osfmk/i386/mp_desc.c
xnu-792.13.8.tar.gz
[apple/xnu.git] / osfmk / i386 / mp_desc.c
1 /*
2 * Copyright (c) 2000 Apple Computer, Inc. All rights reserved.
3 *
4 * @APPLE_LICENSE_OSREFERENCE_HEADER_START@
5 *
6 * This file contains Original Code and/or Modifications of Original Code
7 * as defined in and that are subject to the Apple Public Source License
8 * Version 2.0 (the 'License'). You may not use this file except in
9 * compliance with the License. The rights granted to you under the
10 * License may not be used to create, or enable the creation or
11 * redistribution of, unlawful or unlicensed copies of an Apple operating
12 * system, or to circumvent, violate, or enable the circumvention or
13 * violation of, any terms of an Apple operating system software license
14 * agreement.
15 *
16 * Please obtain a copy of the License at
17 * http://www.opensource.apple.com/apsl/ and read it before using this
18 * file.
19 *
20 * The Original Code and all software distributed under the License are
21 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
22 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
23 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
24 * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
25 * Please see the License for the specific language governing rights and
26 * limitations under the License.
27 *
28 * @APPLE_LICENSE_OSREFERENCE_HEADER_END@
29 */
30 /*
31 * @OSF_COPYRIGHT@
32 */
33 /*
34 * Mach Operating System
35 * Copyright (c) 1991,1990 Carnegie Mellon University
36 * All Rights Reserved.
37 *
38 * Permission to use, copy, modify and distribute this software and its
39 * documentation is hereby granted, provided that both the copyright
40 * notice and this permission notice appear in all copies of the
41 * software, derivative works or modified versions, and any portions
42 * thereof, and that both notices appear in supporting documentation.
43 *
44 * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS "AS IS"
45 * CONDITION. CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND FOR
46 * ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE.
47 *
48 * Carnegie Mellon requests users of this software to return to
49 *
50 * Software Distribution Coordinator or Software.Distribution@CS.CMU.EDU
51 * School of Computer Science
52 * Carnegie Mellon University
53 * Pittsburgh PA 15213-3890
54 *
55 * any improvements or extensions that they make and grant Carnegie Mellon
56 * the rights to redistribute these changes.
57 */
58
59 /*
60 */
61
62
63 #include <kern/cpu_number.h>
64 #include <kern/kalloc.h>
65 #include <kern/cpu_data.h>
66 #include <mach/mach_types.h>
67 #include <mach/machine.h>
68 #include <mach/vm_map.h>
69 #include <vm/vm_kern.h>
70 #include <vm/vm_map.h>
71
72 #include <i386/mp_desc.h>
73 #include <i386/lock.h>
74 #include <i386/misc_protos.h>
75 #include <i386/mp.h>
76 #include <i386/pmap.h>
77 #include <i386/cpu_threads.h>
78
79 #include <kern/misc_protos.h>
80
81 #include <mach_kdb.h>
82
83 /*
84 * The i386 needs an interrupt stack to keep the PCB stack from being
85 * overrun by interrupts. All interrupt stacks MUST lie at lower addresses
86 * than any thread`s kernel stack.
87 */
88
89 /*
90 * First cpu`s interrupt stack.
91 */
92 extern uint32_t low_intstack[]; /* bottom */
93 extern uint32_t low_eintstack[]; /* top */
94
95 /*
96 * Per-cpu data area pointers.
97 * The master cpu (cpu 0) has its data area statically allocated;
98 * others are allocated dynamically and this array is updated at runtime.
99 */
100 cpu_data_t cpu_data_master;
101 cpu_data_t *cpu_data_ptr[MAX_CPUS] = { [0] &cpu_data_master };
102
103 decl_simple_lock_data(,cpu_lock); /* protects real_ncpus */
104 unsigned int real_ncpus = 1;
105 unsigned int max_ncpus = MAX_CPUS;
106
107 extern void *hi_remap_text;
108 #define HI_TEXT(lo_text) \
109 (((uint32_t)&lo_text - (uint32_t)&hi_remap_text) + HIGH_MEM_BASE)
110
111 extern void hi_sysenter(void);
112 extern void hi64_sysenter(void);
113 extern void hi64_syscall(void);
114
115
116 /*
117 * Multiprocessor i386/i486 systems use a separate copy of the
118 * GDT, IDT, LDT, and kernel TSS per processor. The first three
119 * are separate to avoid lock contention: the i386 uses locked
120 * memory cycles to access the descriptor tables. The TSS is
121 * separate since each processor needs its own kernel stack,
122 * and since using a TSS marks it busy.
123 */
124
125 /*
126 * Allocate and initialize the per-processor descriptor tables.
127 */
128
129 struct fake_descriptor ldt_desc_pattern = {
130 (unsigned int) 0,
131 LDTSZ_MIN * sizeof(struct fake_descriptor) - 1,
132 0,
133 ACC_P|ACC_PL_K|ACC_LDT
134 };
135
136 struct fake_descriptor tss_desc_pattern = {
137 (unsigned int) 0,
138 sizeof(struct i386_tss) - 1,
139 0,
140 ACC_P|ACC_PL_K|ACC_TSS
141 };
142
143 struct fake_descriptor cpudata_desc_pattern = {
144 (unsigned int) 0,
145 sizeof(cpu_data_t)-1,
146 SZ_32,
147 ACC_P|ACC_PL_K|ACC_DATA_W
148 };
149
150 struct fake_descriptor userwindow_desc_pattern = {
151 (unsigned int) 0,
152 ((NBPDE * NCOPY_WINDOWS) / PAGE_SIZE) - 1,
153 SZ_32 | SZ_G,
154 ACC_P|ACC_PL_U|ACC_DATA_W
155 };
156
157 struct fake_descriptor physwindow_desc_pattern = {
158 (unsigned int) 0,
159 PAGE_SIZE - 1,
160 SZ_32,
161 ACC_P|ACC_PL_K|ACC_DATA_W
162 };
163
164 /*
165 * This is the expanded, 64-bit variant of the kernel LDT descriptor.
166 * When switching to 64-bit mode this replaces KERNEL_LDT entry
167 * and the following empty slot. This enables the LDT to be referenced
168 * in the uber-space remapping window on the kernel.
169 */
170 struct fake_descriptor64 kernel_ldt_desc64 = {
171 FAKE_UBER64(&master_ldt),
172 LDTSZ_MIN*sizeof(struct fake_descriptor)-1,
173 0,
174 ACC_P|ACC_PL_K|ACC_LDT,
175 0
176 };
177
178 /*
179 * This is the expanded, 64-bit variant of the kernel TSS descriptor.
180 * It is follows pattern of the KERNEL_LDT.
181 */
182 struct fake_descriptor64 kernel_tss_desc64 = {
183 FAKE_UBER64(&master_ktss64),
184 sizeof(struct x86_64_tss)-1,
185 0,
186 ACC_P|ACC_PL_K|ACC_TSS,
187 0
188 };
189
190 void
191 cpu_desc_init(
192 cpu_data_t *cdp,
193 boolean_t is_boot_cpu)
194 {
195 cpu_desc_table_t *cdt = cdp->cpu_desc_tablep;
196 cpu_desc_index_t *cdi = &cdp->cpu_desc_index;
197
198 if (is_boot_cpu) {
199 /*
200 * Master CPU uses the tables built at boot time.
201 * Just set the index pointers to the high shared-mapping space.
202 * Note that the sysenter stack uses empty space above the ktss
203 * in the HIGH_FIXED_KTSS page. In this case we don't map the
204 * the real master_sstk in low memory.
205 */
206 cdi->cdi_ktss = (struct i386_tss *)
207 pmap_index_to_virt(HIGH_FIXED_KTSS) ;
208 cdi->cdi_sstk = (vm_offset_t) (cdi->cdi_ktss + 1) +
209 (vm_offset_t) &master_sstk.top -
210 (vm_offset_t) &master_sstk;
211 #if MACH_KDB
212 cdi->cdi_dbtss = (struct i386_tss *)
213 pmap_index_to_virt(HIGH_FIXED_DBTSS);
214 #endif /* MACH_KDB */
215 cdi->cdi_gdt = (struct fake_descriptor *)
216 pmap_index_to_virt(HIGH_FIXED_GDT);
217 cdi->cdi_idt = (struct fake_descriptor *)
218 pmap_index_to_virt(HIGH_FIXED_IDT);
219 cdi->cdi_ldt = (struct fake_descriptor *)
220 pmap_index_to_virt(HIGH_FIXED_LDT_BEGIN);
221
222 } else {
223
224 vm_offset_t cpu_hi_desc;
225
226 cpu_hi_desc = pmap_cpu_high_shared_remap(cdp->cpu_number,
227 HIGH_CPU_DESC,
228 (vm_offset_t) cdt, 1);
229
230 /*
231 * Per-cpu GDT, IDT, LDT, KTSS descriptors are allocated in one
232 * block (cpu_desc_table) and double-mapped into high shared space
233 * in one page window.
234 * Also, a transient stack for the fast sysenter path. The top of
235 * which is set at context switch time to point to the PCB using
236 * the high address.
237 */
238 cdi->cdi_gdt = (struct fake_descriptor *) (cpu_hi_desc +
239 offsetof(cpu_desc_table_t, gdt[0]));
240 cdi->cdi_idt = (struct fake_descriptor *) (cpu_hi_desc +
241 offsetof(cpu_desc_table_t, idt[0]));
242 cdi->cdi_ktss = (struct i386_tss *) (cpu_hi_desc +
243 offsetof(cpu_desc_table_t, ktss));
244 cdi->cdi_sstk = cpu_hi_desc +
245 offsetof(cpu_desc_table_t, sstk.top);
246
247 /*
248 * LDT descriptors are mapped into a seperate area.
249 */
250 cdi->cdi_ldt = (struct fake_descriptor *)
251 pmap_cpu_high_shared_remap(
252 cdp->cpu_number,
253 HIGH_CPU_LDT_BEGIN,
254 (vm_offset_t) cdp->cpu_ldtp,
255 HIGH_CPU_LDT_END - HIGH_CPU_LDT_BEGIN + 1);
256
257 /*
258 * Copy the tables
259 */
260 bcopy((char *)master_idt,
261 (char *)cdt->idt,
262 sizeof(master_idt));
263 bcopy((char *)master_gdt,
264 (char *)cdt->gdt,
265 sizeof(master_gdt));
266 bcopy((char *)master_ldt,
267 (char *)cdp->cpu_ldtp,
268 sizeof(master_ldt));
269 bzero((char *)&cdt->ktss,
270 sizeof(struct i386_tss));
271
272 #if MACH_KDB
273 cdi->cdi_dbtss = (struct i386_tss *) (cpu_hi_desc +
274 offsetof(cpu_desc_table_t, dbtss));
275 bcopy((char *)&master_dbtss,
276 (char *)&cdt->dbtss,
277 sizeof(struct i386_tss));
278 #endif /* MACH_KDB */
279
280 /*
281 * Fix up the entries in the GDT to point to
282 * this LDT and this TSS.
283 */
284 cdt->gdt[sel_idx(KERNEL_LDT)] = ldt_desc_pattern;
285 cdt->gdt[sel_idx(KERNEL_LDT)].offset = (vm_offset_t) cdi->cdi_ldt;
286 fix_desc(&cdt->gdt[sel_idx(KERNEL_LDT)], 1);
287
288 cdt->gdt[sel_idx(USER_LDT)] = ldt_desc_pattern;
289 cdt->gdt[sel_idx(USER_LDT)].offset = (vm_offset_t) cdi->cdi_ldt;
290 fix_desc(&cdt->gdt[sel_idx(USER_LDT)], 1);
291
292 cdt->gdt[sel_idx(KERNEL_TSS)] = tss_desc_pattern;
293 cdt->gdt[sel_idx(KERNEL_TSS)].offset = (vm_offset_t) cdi->cdi_ktss;
294 fix_desc(&cdt->gdt[sel_idx(KERNEL_TSS)], 1);
295
296 cdt->gdt[sel_idx(CPU_DATA_GS)] = cpudata_desc_pattern;
297 cdt->gdt[sel_idx(CPU_DATA_GS)].offset = (vm_offset_t) cdp;
298 fix_desc(&cdt->gdt[sel_idx(CPU_DATA_GS)], 1);
299
300 #if MACH_KDB
301 cdt->gdt[sel_idx(DEBUG_TSS)] = tss_desc_pattern;
302 cdt->gdt[sel_idx(DEBUG_TSS)].offset = (vm_offset_t) cdi->cdi_dbtss;
303 fix_desc(&cdt->gdt[sel_idx(DEBUG_TSS)], 1);
304
305 cdt->dbtss.esp0 = (int)(db_task_stack_store +
306 (INTSTACK_SIZE * (cdp->cpu_number)) - sizeof (natural_t));
307 cdt->dbtss.esp = cdt->dbtss.esp0;
308 cdt->dbtss.eip = (int)&db_task_start;
309 #endif /* MACH_KDB */
310
311 cdt->ktss.ss0 = KERNEL_DS;
312 cdt->ktss.io_bit_map_offset = 0x0FFF; /* no IO bitmap */
313
314 cpu_window_init(cdp->cpu_number);
315
316 }
317
318 }
319
320 void
321 cpu_desc_init64(
322 cpu_data_t *cdp,
323 boolean_t is_boot_cpu)
324 {
325 cpu_desc_table64_t *cdt = (cpu_desc_table64_t *)
326 cdp->cpu_desc_tablep;
327 cpu_desc_index_t *cdi = &cdp->cpu_desc_index;
328
329 if (is_boot_cpu) {
330 /*
331 * Master CPU uses the tables built at boot time.
332 * Just set the index pointers to the low memory space.
333 * Note that in 64-bit mode these are addressed in the
334 * double-mapped window (uber-space).
335 */
336 cdi->cdi_ktss = (struct i386_tss *) &master_ktss64;
337 cdi->cdi_sstk = (vm_offset_t) &master_sstk.top;
338 cdi->cdi_gdt = master_gdt;
339 cdi->cdi_idt = (struct fake_descriptor *) &master_idt64;
340 cdi->cdi_ldt = (struct fake_descriptor *) &master_ldt;
341
342 /* Replace the expanded LDT and TSS slots in the GDT: */
343 *(struct fake_descriptor64 *) &master_gdt[sel_idx(KERNEL_LDT)] =
344 kernel_ldt_desc64;
345 *(struct fake_descriptor64 *) &master_gdt[sel_idx(KERNEL_TSS)] =
346 kernel_tss_desc64;
347
348 /*
349 * Fix up the expanded descriptors for 64-bit.
350 */
351 fix_desc64((void *) &master_idt64, IDTSZ);
352 fix_desc64((void *) &master_gdt[sel_idx(KERNEL_LDT)], 1);
353 fix_desc64((void *) &master_gdt[sel_idx(KERNEL_TSS)], 1);
354
355 /*
356 * Set the double-fault stack as IST1 in the 64-bit TSS
357 */
358 master_ktss64.ist1 = UBER64(df_task_stack_end);
359
360 } else {
361 /*
362 * Per-cpu GDT, IDT, KTSS descriptors are allocated in kernel
363 * heap (cpu_desc_table) and double-mapped in uber-space (over 4GB).
364 * LDT descriptors are mapped into a separate area.
365 */
366 cdi->cdi_gdt = cdt->gdt;
367 cdi->cdi_idt = (struct fake_descriptor *) cdt->idt;
368 cdi->cdi_ktss = (struct i386_tss *) &cdt->ktss;
369 cdi->cdi_sstk = (vm_offset_t) &cdt->sstk.top;
370 cdi->cdi_ldt = cdp->cpu_ldtp;
371
372 /*
373 * Copy the tables
374 */
375 bcopy((char *)master_idt64,
376 (char *)cdt->idt,
377 sizeof(master_idt64));
378 bcopy((char *)master_gdt,
379 (char *)cdt->gdt,
380 sizeof(master_gdt));
381 bcopy((char *)master_ldt,
382 (char *)cdp->cpu_ldtp,
383 sizeof(master_ldt));
384 bcopy((char *)&master_ktss64,
385 (char *)&cdt->ktss,
386 sizeof(struct x86_64_tss));
387
388 /*
389 * Fix up the entries in the GDT to point to
390 * this LDT and this TSS.
391 */
392 kernel_ldt_desc64.offset[0] = (vm_offset_t) cdi->cdi_ldt;
393 *(struct fake_descriptor64 *) &cdt->gdt[sel_idx(KERNEL_LDT)] =
394 kernel_ldt_desc64;
395 fix_desc64(&cdt->gdt[sel_idx(KERNEL_LDT)], 1);
396
397 kernel_ldt_desc64.offset[0] = (vm_offset_t) cdi->cdi_ldt;
398 *(struct fake_descriptor64 *) &cdt->gdt[sel_idx(USER_LDT)] =
399 kernel_ldt_desc64;
400 fix_desc64(&cdt->gdt[sel_idx(USER_LDT)], 1);
401
402 kernel_tss_desc64.offset[0] = (vm_offset_t) cdi->cdi_ktss;
403 *(struct fake_descriptor64 *) &cdt->gdt[sel_idx(KERNEL_TSS)] =
404 kernel_tss_desc64;
405 fix_desc64(&cdt->gdt[sel_idx(KERNEL_TSS)], 1);
406
407 cdt->gdt[sel_idx(CPU_DATA_GS)] = cpudata_desc_pattern;
408 cdt->gdt[sel_idx(CPU_DATA_GS)].offset = (vm_offset_t) cdp;
409 fix_desc(&cdt->gdt[sel_idx(CPU_DATA_GS)], 1);
410
411 /* Set double-fault stack as IST1 */
412 cdt->ktss.ist1 = UBER64(cdt->dfstk + sizeof(cdt->dfstk));
413
414 /*
415 * Allocate copyio windows.
416 */
417 cpu_window_init(cdp->cpu_number);
418
419 }
420
421 /* Require that the top of the sysenter stack is 16-byte aligned */
422 if ((cdi->cdi_sstk % 16) != 0)
423 panic("cpu_desc_init64() sysenter stack not 16-byte aligned");
424 }
425
426 /*
427 * Set MSRs for sysenter/sysexit for 64-bit.
428 */
429 void
430 fast_syscall_init64(void)
431 {
432 wrmsr64(MSR_IA32_SYSENTER_CS, SYSENTER_CS);
433 wrmsr64(MSR_IA32_SYSENTER_EIP, UBER64(hi64_sysenter));
434 wrmsr64(MSR_IA32_SYSENTER_ESP, UBER64(current_sstk()));
435
436 /* Enable syscall/sysret */
437 wrmsr64(MSR_IA32_EFER, rdmsr64(MSR_IA32_EFER) | MSR_IA32_EFER_SCE);
438
439 /*
440 * MSRs for 64-bit syscall/sysret
441 * Note USER_CS because sysret uses this + 16 when returning to
442 * 64-bit code.
443 */
444 wrmsr64(MSR_IA32_LSTAR, UBER64(hi64_syscall));
445 wrmsr64(MSR_IA32_STAR, (((uint64_t)USER_CS) << 48) |
446 (((uint64_t)KERNEL64_CS) << 32));
447 /*
448 * Emulate eflags cleared by sysenter but note that
449 * we also clear the trace trap to avoid the complications
450 * of single-stepping into a syscall. We also clear
451 * the nested task bit to avoid a spurious "task switch"
452 * on IRET.
453 */
454 wrmsr64(MSR_IA32_FMASK, EFL_DF|EFL_IF|EFL_TF|EFL_NT);
455
456 /*
457 * Set the Kermel GS base MSR to point to per-cpu data in uber-space.
458 * The uber-space handler (hi64_syscall) uses the swapgs instruction.
459 */
460 wrmsr64(MSR_IA32_KERNEL_GS_BASE, UBER64(current_cpu_datap()));
461 kprintf("fast_syscall_init64() KERNEL_GS_BASE=0x%016llx\n",
462 rdmsr64(MSR_IA32_KERNEL_GS_BASE));
463 }
464
465 /*
466 * Set MSRs for sysenter/sysexit
467 */
468 void
469 fast_syscall_init(void)
470 {
471 wrmsr(MSR_IA32_SYSENTER_CS, SYSENTER_CS, 0);
472 wrmsr(MSR_IA32_SYSENTER_EIP, HI_TEXT(hi_sysenter), 0);
473 wrmsr(MSR_IA32_SYSENTER_ESP, current_sstk(), 0);
474 }
475
476 cpu_data_t *
477 cpu_data_alloc(boolean_t is_boot_cpu)
478 {
479 int ret;
480 cpu_data_t *cdp;
481
482 if (is_boot_cpu) {
483 assert(real_ncpus == 1);
484 simple_lock_init(&cpu_lock, 0);
485 cdp = &cpu_data_master;
486 if (cdp->cpu_processor == NULL) {
487 cdp->cpu_processor = cpu_processor_alloc(TRUE);
488 cdp->cpu_pmap = pmap_cpu_alloc(TRUE);
489 cdp->cpu_this = cdp;
490 cdp->cpu_is64bit = FALSE;
491 cdp->cpu_int_stack_top = (vm_offset_t) low_eintstack;
492 cpu_desc_init(cdp, TRUE);
493 fast_syscall_init();
494 }
495 return cdp;
496 }
497
498 /* Check count before making allocations */
499 if (real_ncpus >= max_ncpus)
500 return NULL;
501
502 /*
503 * Allocate per-cpu data:
504 */
505 ret = kmem_alloc(kernel_map,
506 (vm_offset_t *) &cdp, sizeof(cpu_data_t));
507 if (ret != KERN_SUCCESS) {
508 printf("cpu_data_alloc() failed, ret=%d\n", ret);
509 goto abort;
510 }
511 bzero((void*) cdp, sizeof(cpu_data_t));
512 cdp->cpu_this = cdp;
513
514 /* Propagate mode */
515 cdp->cpu_is64bit = cpu_mode_is64bit();
516
517 /*
518 * Allocate interrupt stack:
519 */
520 ret = kmem_alloc(kernel_map,
521 (vm_offset_t *) &cdp->cpu_int_stack_top,
522 INTSTACK_SIZE);
523 if (ret != KERN_SUCCESS) {
524 printf("cpu_data_alloc() int stack failed, ret=%d\n", ret);
525 goto abort;
526 }
527 bzero((void*) cdp->cpu_int_stack_top, INTSTACK_SIZE);
528 cdp->cpu_int_stack_top += INTSTACK_SIZE;
529
530 /*
531 * Allocate descriptor table:
532 * Size depends on cpu mode.
533 */
534 ret = kmem_alloc(kernel_map,
535 (vm_offset_t *) &cdp->cpu_desc_tablep,
536 cdp->cpu_is64bit ? sizeof(cpu_desc_table64_t)
537 : sizeof(cpu_desc_table_t));
538 if (ret != KERN_SUCCESS) {
539 printf("cpu_data_alloc() desc_table failed, ret=%d\n", ret);
540 goto abort;
541 }
542
543 /*
544 * Allocate LDT
545 */
546 ret = kmem_alloc(kernel_map,
547 (vm_offset_t *) &cdp->cpu_ldtp,
548 sizeof(struct real_descriptor) * LDTSZ);
549 if (ret != KERN_SUCCESS) {
550 printf("cpu_data_alloc() ldt failed, ret=%d\n", ret);
551 goto abort;
552 }
553
554 simple_lock(&cpu_lock);
555 if (real_ncpus >= max_ncpus) {
556 simple_unlock(&cpu_lock);
557 goto abort;
558 }
559 cpu_data_ptr[real_ncpus] = cdp;
560 cdp->cpu_number = real_ncpus;
561 real_ncpus++;
562 simple_unlock(&cpu_lock);
563
564 kprintf("cpu_data_alloc(%d) 0x%x desc_table: 0x%x "
565 "ldt: 0x%x "
566 "int_stack: 0x%x-0x%x\n",
567 cdp->cpu_number, cdp, cdp->cpu_desc_tablep, cdp->cpu_ldtp,
568 cdp->cpu_int_stack_top - INTSTACK_SIZE, cdp->cpu_int_stack_top);
569
570 return cdp;
571
572 abort:
573 if (cdp) {
574 if (cdp->cpu_desc_tablep)
575 kfree((void *) cdp->cpu_desc_tablep,
576 sizeof(*cdp->cpu_desc_tablep));
577 if (cdp->cpu_int_stack_top)
578 kfree((void *) (cdp->cpu_int_stack_top - INTSTACK_SIZE),
579 INTSTACK_SIZE);
580 kfree((void *) cdp, sizeof(*cdp));
581 }
582 return NULL;
583 }
584
585 boolean_t
586 valid_user_segment_selectors(uint16_t cs,
587 uint16_t ss,
588 uint16_t ds,
589 uint16_t es,
590 uint16_t fs,
591 uint16_t gs)
592 {
593 return valid_user_code_selector(cs) &&
594 valid_user_stack_selector(ss) &&
595 valid_user_data_selector(ds) &&
596 valid_user_data_selector(es) &&
597 valid_user_data_selector(fs) &&
598 valid_user_data_selector(gs);
599 }
600
601
602 static vm_offset_t user_window_base = 0;
603 static vm_offset_t phys_window_base = 0;
604
605 void
606 cpu_window_init(int cpu)
607 {
608 cpu_data_t *cdp = cpu_data_ptr[cpu];
609 cpu_desc_index_t *cdi;
610 vm_offset_t user_window;
611 vm_offset_t phys_window;
612 vm_offset_t vaddr;
613 int num_cpus;
614
615 num_cpus = ml_get_max_cpus();
616
617 if (cpu >= num_cpus)
618 panic("copy_window_init: cpu > num_cpus");
619
620 if (user_window_base == 0) {
621
622 if (vm_allocate(kernel_map, &vaddr,
623 (NBPDE * NCOPY_WINDOWS * num_cpus) + NBPDE,
624 VM_FLAGS_ANYWHERE) != KERN_SUCCESS)
625 panic("copy_window_init: "
626 "couldn't allocate user map window");
627
628 /*
629 * window must start on a page table boundary
630 * in the virtual address space
631 */
632 user_window_base = (vaddr + (NBPDE - 1)) & ~(NBPDE - 1);
633
634 /*
635 * get rid of any allocation leading up to our
636 * starting boundary
637 */
638 vm_deallocate(kernel_map, vaddr, user_window_base - vaddr);
639
640 /*
641 * get rid of tail that we don't need
642 */
643 user_window = user_window_base +
644 (NBPDE * NCOPY_WINDOWS * num_cpus);
645
646 vm_deallocate(kernel_map, user_window,
647 (vaddr +
648 ((NBPDE * NCOPY_WINDOWS * num_cpus) + NBPDE)) -
649 user_window);
650
651 if (vm_allocate(kernel_map, &phys_window_base,
652 PAGE_SIZE * num_cpus, VM_FLAGS_ANYWHERE)
653 != KERN_SUCCESS)
654 panic("copy_window_init: "
655 "couldn't allocate phys map window");
656 }
657
658 user_window = user_window_base + (cpu * NCOPY_WINDOWS * NBPDE);
659 phys_window = phys_window_base + (cpu * PAGE_SIZE);
660
661 cdi = &cdp->cpu_desc_index;
662
663 cdp->cpu_copywindow_base = user_window;
664 cdp->cpu_copywindow_pdp = pmap_pde(kernel_pmap, user_window);
665
666 cdi->cdi_gdt[sel_idx(USER_WINDOW_SEL)] = userwindow_desc_pattern;
667 cdi->cdi_gdt[sel_idx(USER_WINDOW_SEL)].offset = user_window;
668
669 fix_desc(&cdi->cdi_gdt[sel_idx(USER_WINDOW_SEL)], 1);
670
671 cdp->cpu_physwindow_base = phys_window;
672
673 /*
674 * make sure the page that encompasses the
675 * pte pointer we're interested in actually
676 * exists in the page table
677 */
678 pmap_expand(kernel_pmap, phys_window);
679
680 cdp->cpu_physwindow_ptep = vtopte(phys_window);
681
682 cdi->cdi_gdt[sel_idx(PHYS_WINDOW_SEL)] = physwindow_desc_pattern;
683 cdi->cdi_gdt[sel_idx(PHYS_WINDOW_SEL)].offset = phys_window;
684
685 fix_desc(&cdi->cdi_gdt[sel_idx(PHYS_WINDOW_SEL)], 1);
686 }
687
688
689 typedef struct {
690 uint16_t length;
691 uint32_t offset[2];
692 } __attribute__((__packed__)) table_descriptor64_t;
693
694 extern table_descriptor64_t gdtptr64;
695 extern table_descriptor64_t idtptr64;
696 /*
697 * Load the segment descriptor tables for the current processor.
698 */
699 void
700 cpu_desc_load64(cpu_data_t *cdp)
701 {
702 cpu_desc_index_t *cdi = &cdp->cpu_desc_index;
703
704 /*
705 * Load up the new descriptors etc
706 * ml_load_desc64() expects these global pseudo-descriptors:
707 * gdtptr64 -> master_gdt
708 * idtptr64 -> master_idt64
709 * These are 10-byte descriptors with 64-bit addresses into
710 * uber-space.
711 */
712 gdtptr64.length = sizeof(master_gdt) - 1;
713 gdtptr64.offset[0] = (uint32_t) cdi->cdi_gdt;
714 gdtptr64.offset[1] = KERNEL_UBER_BASE_HI32;
715 idtptr64.length = sizeof(master_idt64) - 1;
716 idtptr64.offset[0] = (uint32_t) cdi->cdi_idt;
717 idtptr64.offset[1] = KERNEL_UBER_BASE_HI32;
718
719 /* Make sure busy bit is cleared in the TSS */
720 gdt_desc_p(KERNEL_TSS)->access &= ~ACC_TSS_BUSY;
721
722 ml_load_desc64();
723
724 kprintf("64-bit descriptor tables loaded\n");
725 }