]> git.saurik.com Git - apple/xnu.git/blobdiff - osfmk/i386/mp_desc.c
xnu-3789.51.2.tar.gz
[apple/xnu.git] / osfmk / i386 / mp_desc.c
index b1bc88bf60ea31ae8d1e004f881f3243dddb115b..a3dbca3b107ba8638c748b30415c1747087f87d3 100644 (file)
 #include <vm/vm_kern.h>
 #include <vm/vm_map.h>
 
-#include <i386/lock.h>
+#include <i386/bit_routines.h>
 #include <i386/mp_desc.h>
 #include <i386/misc_protos.h>
 #include <i386/mp.h>
 #include <i386/pmap.h>
-#if defined(__i386__)
+#if defined(__i386__) || defined(__x86_64__)
 #include <i386/pmap_internal.h>
 #endif /* i386 */
 #if CONFIG_MCA
@@ -389,6 +389,26 @@ fix_desc64(void *descp, int count)
        }
 }
 
+static void
+cpu_gdt_alias(vm_map_offset_t gdt, vm_map_offset_t alias)
+{
+       pt_entry_t *pte = NULL;
+
+       /* Require page alignment */
+       assert(page_aligned(gdt));
+       assert(page_aligned(alias));
+
+       pte = pmap_pte(kernel_pmap, alias);
+       pmap_store_pte(pte, kvtophys(gdt) | INTEL_PTE_REF
+                                         | INTEL_PTE_MOD
+                                         | INTEL_PTE_WIRED
+                                         | INTEL_PTE_VALID
+                                         | INTEL_PTE_WRITE
+                                         | INTEL_PTE_NX);
+
+       /* TLB flush unneccessry because target processor isn't running yet */
+}
+
 
 void
 cpu_desc_init64(cpu_data_t *cdp)
@@ -430,19 +450,25 @@ cpu_desc_init64(cpu_data_t *cdp)
                master_ktss64.ist1 = (uintptr_t) low_eintstack
                                        - sizeof(x86_64_intr_stack_frame_t);
 
-       } else {
+       } else if (cdi->cdi_ktss == NULL) {     /* Skipping re-init on wake */
                cpu_desc_table64_t      *cdt = (cpu_desc_table64_t *) cdp->cpu_desc_tablep;
+
                /*
                 * Per-cpu GDT, IDT, KTSS descriptors are allocated in kernel 
                 * heap (cpu_desc_table). 
                 * LDT descriptors are mapped into a separate area.
+                * GDT descriptors are addressed by alias to avoid sgdt leaks to user-space.
                 */
                cdi->cdi_idt.ptr  = (void *)MASTER_IDT_ALIAS;
-               cdi->cdi_gdt.ptr  = (struct fake_descriptor *)cdt->gdt;
+               cdi->cdi_gdt.ptr  = (void *)CPU_GDT_ALIAS(cdp->cpu_number);
                cdi->cdi_ktss = (void *)&cdt->ktss;
                cdi->cdi_sstk = (vm_offset_t)&cdt->sstk.top;
                cdi->cdi_ldt  = cdp->cpu_ldtp;
 
+               /* Make the virtual alias address for the GDT */
+               cpu_gdt_alias((vm_map_offset_t) &cdt->gdt,
+                             (vm_map_offset_t) cdi->cdi_gdt.ptr);
+
                /*
                 * Copy the tables
                 */
@@ -487,6 +513,17 @@ cpu_desc_load64(cpu_data_t *cdp)
 {
        cpu_desc_index_t        *cdi = &cdp->cpu_desc_index;
 
+       /* Stuff the kernel per-cpu data area address into the MSRs */
+       wrmsr64(MSR_IA32_GS_BASE, (uintptr_t) cdp);
+       wrmsr64(MSR_IA32_KERNEL_GS_BASE, (uintptr_t) cdp);
+
+       /*
+        * Ensure the TSS segment's busy bit is clear. This is required
+        * for the case of reloading descriptors at wake to avoid
+        * their complete re-initialization.
+        */
+       gdt_desc_p(KERNEL_TSS)->access &= ~ACC_TSS_BUSY;
+
        /* Load the GDT, LDT, IDT and TSS */
        cdi->cdi_gdt.size = sizeof(struct real_descriptor)*GDTSZ - 1;
        cdi->cdi_idt.size = 0x1000 + cdp->cpu_number;
@@ -495,10 +532,6 @@ cpu_desc_load64(cpu_data_t *cdp)
        lldt(KERNEL_LDT);
        set_tr(KERNEL_TSS);
 
-       /* Stuff the kernel per-cpu data area address into the MSRs */
-       wrmsr64(MSR_IA32_GS_BASE, (uintptr_t) cdp);
-       wrmsr64(MSR_IA32_KERNEL_GS_BASE, (uintptr_t) cdp);
-
 #if GPROF // Hack to enable mcount to work on K64
        __asm__ volatile("mov %0, %%gs" : : "rm" ((unsigned short)(KERNEL_DS)));
 #endif
@@ -559,7 +592,7 @@ cpu_data_alloc(boolean_t is_boot_cpu)
        /*
         * Allocate per-cpu data:
         */
-       ret = kmem_alloc(kernel_map, (vm_offset_t *) &cdp, sizeof(cpu_data_t));
+       ret = kmem_alloc(kernel_map, (vm_offset_t *) &cdp, sizeof(cpu_data_t), VM_KERN_MEMORY_CPU);
        if (ret != KERN_SUCCESS) {
                printf("cpu_data_alloc() failed, ret=%d\n", ret);
                goto abort;
@@ -572,7 +605,7 @@ cpu_data_alloc(boolean_t is_boot_cpu)
         */
        ret = kmem_alloc(kernel_map, 
                         (vm_offset_t *) &cdp->cpu_int_stack_top,
-                        INTSTACK_SIZE);
+                        INTSTACK_SIZE, VM_KERN_MEMORY_CPU);
        if (ret != KERN_SUCCESS) {
                printf("cpu_data_alloc() int stack failed, ret=%d\n", ret);
                goto abort;
@@ -585,7 +618,8 @@ cpu_data_alloc(boolean_t is_boot_cpu)
         */
        ret = kmem_alloc(kernel_map, 
                         (vm_offset_t *) &cdp->cpu_desc_tablep,
-                        sizeof(cpu_desc_table64_t));
+                        sizeof(cpu_desc_table64_t),
+                        VM_KERN_MEMORY_CPU);
        if (ret != KERN_SUCCESS) {
                printf("cpu_data_alloc() desc_table failed, ret=%d\n", ret);
                goto abort;
@@ -596,7 +630,8 @@ cpu_data_alloc(boolean_t is_boot_cpu)
         */
        ret = kmem_alloc(kernel_map, 
                         (vm_offset_t *) &cdp->cpu_ldtp,
-                        sizeof(struct real_descriptor) * LDTSZ);
+                        sizeof(struct real_descriptor) * LDTSZ,
+                        VM_KERN_MEMORY_CPU);
        if (ret != KERN_SUCCESS) {
                printf("cpu_data_alloc() ldt failed, ret=%d\n", ret);
                goto abort;
@@ -614,6 +649,16 @@ cpu_data_alloc(boolean_t is_boot_cpu)
        real_ncpus++;
        simple_unlock(&ncpus_lock);
 
+       /*
+        * Before this cpu has been assigned a real thread context,
+        * we give it a fake, unique, non-zero thread id which the locking
+        * primitives use as their lock value.
+        * Note that this does not apply to the boot processor, cpu 0, which
+        * transitions to a thread context well before other processors are
+        * started.
+        */
+       cdp->cpu_active_thread = (thread_t) (uintptr_t) cdp->cpu_number;
+
        cdp->cpu_nanotime = &pal_rtc_nanotime_info;
 
        kprintf("cpu_data_alloc(%d) %p desc_table: %p "
@@ -732,7 +777,7 @@ cpu_userwindow_init(int cpu)
 
                if (vm_allocate(kernel_map, &vaddr,
                                        (NBPDE * NCOPY_WINDOWS * num_cpus) + NBPDE,
-                                       VM_FLAGS_ANYWHERE) != KERN_SUCCESS)
+                                       VM_FLAGS_ANYWHERE | VM_MAKE_TAG(VM_KERN_MEMORY_CPU)) != KERN_SUCCESS)
                        panic("cpu_userwindow_init: "
                                        "couldn't allocate user map window");
 
@@ -779,7 +824,7 @@ cpu_physwindow_init(int cpu)
 
        if (phys_window == 0) {
                if (vm_allocate(kernel_map, &phys_window,
-                               PAGE_SIZE, VM_FLAGS_ANYWHERE)
+                               PAGE_SIZE, VM_FLAGS_ANYWHERE | VM_MAKE_TAG(VM_KERN_MEMORY_CPU))
                                != KERN_SUCCESS)
                        panic("cpu_physwindow_init: "
                                "couldn't allocate phys map window");
@@ -820,14 +865,14 @@ cpu_data_realloc(void)
        cpu_data_t      *cdp;
        boolean_t       istate;
 
-       ret = kmem_alloc(kernel_map, &istk, INTSTACK_SIZE);
+       ret = kmem_alloc(kernel_map, &istk, INTSTACK_SIZE, VM_KERN_MEMORY_CPU);
        if (ret != KERN_SUCCESS) {
                panic("cpu_data_realloc() stack alloc, ret=%d\n", ret);
        }
        bzero((void*) istk, INTSTACK_SIZE);
        istk += INTSTACK_SIZE;
 
-       ret = kmem_alloc(kernel_map, (vm_offset_t *) &cdp, sizeof(cpu_data_t));
+       ret = kmem_alloc(kernel_map, (vm_offset_t *) &cdp, sizeof(cpu_data_t), VM_KERN_MEMORY_CPU);
        if (ret != KERN_SUCCESS) {
                panic("cpu_data_realloc() cpu data alloc, ret=%d\n", ret);
        }
@@ -840,7 +885,7 @@ cpu_data_realloc(void)
        timer_call_queue_init(&cdp->rtclock_timer.queue);
 
        /* Allocate the separate fault stack */
-       ret = kmem_alloc(kernel_map, &fstk, PAGE_SIZE);
+       ret = kmem_alloc(kernel_map, &fstk, PAGE_SIZE, VM_KERN_MEMORY_CPU);
        if (ret != KERN_SUCCESS) {
                panic("cpu_data_realloc() fault stack alloc, ret=%d\n", ret);
        }