13446Smrj /* 23446Smrj * CDDL HEADER START 33446Smrj * 43446Smrj * The contents of this file are subject to the terms of the 53446Smrj * Common Development and Distribution License (the "License"). 63446Smrj * You may not use this file except in compliance with the License. 73446Smrj * 83446Smrj * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 93446Smrj * or http://www.opensolaris.org/os/licensing. 103446Smrj * See the License for the specific language governing permissions 113446Smrj * and limitations under the License. 123446Smrj * 133446Smrj * When distributing Covered Code, include this CDDL HEADER in each 143446Smrj * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 153446Smrj * If applicable, add the following below this CDDL HEADER, with the 163446Smrj * fields enclosed by brackets "[]" replaced with your own identifying 173446Smrj * information: Portions Copyright [yyyy] [name of copyright owner] 183446Smrj * 193446Smrj * CDDL HEADER END 203446Smrj */ 213446Smrj /* 22*9637SRandy.Fishel@Sun.COM * Copyright 2009 Sun Microsystems, Inc. All rights reserved. 233446Smrj * Use is subject to license terms. 243446Smrj */ 253446Smrj 263446Smrj /* 273446Smrj * Welcome to the world of the "real mode platter". 283446Smrj * See also startup.c, mpcore.s and apic.c for related routines. 293446Smrj */ 303446Smrj 313446Smrj #include <sys/types.h> 323446Smrj #include <sys/systm.h> 333446Smrj #include <sys/cpuvar.h> 343446Smrj #include <sys/kmem.h> 353446Smrj #include <sys/archsystm.h> 363446Smrj #include <sys/machsystm.h> 373446Smrj #include <sys/controlregs.h> 383446Smrj #include <sys/x86_archext.h> 393446Smrj #include <sys/smp_impldefs.h> 403446Smrj #include <sys/sysmacros.h> 413446Smrj #include <sys/mach_mmu.h> 423446Smrj #include <sys/promif.h> 433446Smrj #include <sys/cpu.h> 444191Sjosephb #include <vm/hat_i86.h> 453446Smrj 463446Smrj extern void real_mode_start(void); 473446Smrj extern void real_mode_end(void); 485295Srandyf extern void *(*cpu_pause_func)(void *); 495295Srandyf 505295Srandyf void rmp_gdt_init(rm_platter_t *); 513446Smrj 523446Smrj /* 533446Smrj * Fill up the real mode platter to make it easy for real mode code to 543446Smrj * kick it off. This area should really be one passed by boot to kernel 553446Smrj * and guaranteed to be below 1MB and aligned to 16 bytes. Should also 563446Smrj * have identical physical and virtual address in paged mode. 573446Smrj */ 583446Smrj static ushort_t *warm_reset_vector = NULL; 593446Smrj 603446Smrj int 613446Smrj mach_cpucontext_init(void) 623446Smrj { 633446Smrj ushort_t *vec; 643446Smrj 653446Smrj if (!(vec = (ushort_t *)psm_map_phys(WARM_RESET_VECTOR, 663446Smrj sizeof (vec), PROT_READ | PROT_WRITE))) 673446Smrj return (-1); 683446Smrj /* 693446Smrj * setup secondary cpu bios boot up vector 703446Smrj */ 713446Smrj *vec = (ushort_t)((caddr_t) 725295Srandyf ((struct rm_platter *)rm_platter_va)->rm_code - rm_platter_va 735295Srandyf + ((ulong_t)rm_platter_va & 0xf)); 743446Smrj vec[1] = (ushort_t)(rm_platter_pa >> 4); 753446Smrj warm_reset_vector = vec; 763446Smrj 773446Smrj bcopy((caddr_t)real_mode_start, 783446Smrj (caddr_t)((rm_platter_t *)rm_platter_va)->rm_code, 793446Smrj (size_t)real_mode_end - (size_t)real_mode_start); 803446Smrj 813446Smrj return (0); 823446Smrj } 833446Smrj 843446Smrj void 853446Smrj mach_cpucontext_fini(void) 863446Smrj { 873446Smrj if (warm_reset_vector) 883446Smrj psm_unmap_phys((caddr_t)warm_reset_vector, 893446Smrj sizeof (warm_reset_vector)); 903446Smrj hat_unload(kas.a_hat, (caddr_t)(uintptr_t)rm_platter_pa, MMU_PAGESIZE, 913446Smrj HAT_UNLOAD); 923446Smrj } 933446Smrj 943446Smrj #if defined(__amd64) 953446Smrj extern void *long_mode_64(void); 963446Smrj #endif /* __amd64 */ 973446Smrj 983446Smrj void * 993446Smrj mach_cpucontext_alloc(struct cpu *cp) 1003446Smrj { 1013446Smrj rm_platter_t *rm = (rm_platter_t *)rm_platter_va; 1023446Smrj struct cpu_tables *ct; 1033446Smrj struct tss *ntss; 1043446Smrj 1053446Smrj /* 1065460Sjosephb * Allocate space for stack, tss, gdt and idt. We round the size 107*9637SRandy.Fishel@Sun.COM * allotted for cpu_tables up, so that the TSS is on a unique page. 1085460Sjosephb * This is more efficient when running in virtual machines. 1093446Smrj */ 1105460Sjosephb ct = kmem_zalloc(P2ROUNDUP(sizeof (*ct), PAGESIZE), KM_SLEEP); 1115460Sjosephb if ((uintptr_t)ct & PAGEOFFSET) 1123446Smrj panic("mp_startup_init: cpu%d misaligned tables", cp->cpu_id); 1133446Smrj 1143446Smrj ntss = cp->cpu_tss = &ct->ct_tss; 1153446Smrj 1163446Smrj #if defined(__amd64) 1173446Smrj 1183446Smrj /* 1193446Smrj * #DF (double fault). 1203446Smrj */ 1213446Smrj ntss->tss_ist1 = (uint64_t)&ct->ct_stack[sizeof (ct->ct_stack)]; 1223446Smrj 1233446Smrj #elif defined(__i386) 1243446Smrj 1253446Smrj ntss->tss_esp0 = ntss->tss_esp1 = ntss->tss_esp2 = ntss->tss_esp = 1263446Smrj (uint32_t)&ct->ct_stack[sizeof (ct->ct_stack)]; 1273446Smrj 1283446Smrj ntss->tss_ss0 = ntss->tss_ss1 = ntss->tss_ss2 = ntss->tss_ss = KDS_SEL; 1293446Smrj 1303446Smrj ntss->tss_eip = (uint32_t)cp->cpu_thread->t_pc; 1313446Smrj 1323446Smrj ntss->tss_cs = KCS_SEL; 1333446Smrj ntss->tss_ds = ntss->tss_es = KDS_SEL; 1343446Smrj ntss->tss_fs = KFS_SEL; 1353446Smrj ntss->tss_gs = KGS_SEL; 1363446Smrj 1373446Smrj #endif /* __i386 */ 1383446Smrj 1393446Smrj /* 1403446Smrj * Set I/O bit map offset equal to size of TSS segment limit 1413446Smrj * for no I/O permission map. This will cause all user I/O 1423446Smrj * instructions to generate #gp fault. 1433446Smrj */ 1443446Smrj ntss->tss_bitmapbase = sizeof (*ntss); 1453446Smrj 1463446Smrj /* 1473446Smrj * Setup kernel tss. 1483446Smrj */ 1493446Smrj set_syssegd((system_desc_t *)&cp->cpu_gdt[GDT_KTSS], cp->cpu_tss, 1505460Sjosephb sizeof (*cp->cpu_tss) - 1, SDT_SYSTSS, SEL_KPL); 1513446Smrj 1523446Smrj /* 1533446Smrj * Now copy all that we've set up onto the real mode platter 1543446Smrj * for the real mode code to digest as part of starting the cpu. 1553446Smrj */ 1563446Smrj 1573446Smrj rm->rm_idt_base = cp->cpu_idt; 1585460Sjosephb rm->rm_idt_lim = sizeof (*cp->cpu_idt) * NIDT - 1; 1593446Smrj rm->rm_gdt_base = cp->cpu_gdt; 1605460Sjosephb rm->rm_gdt_lim = sizeof (*cp->cpu_gdt) * NGDT - 1; 1613446Smrj 1623446Smrj rm->rm_pdbr = getcr3(); 1633446Smrj rm->rm_cpu = cp->cpu_id; 1643446Smrj rm->rm_x86feature = x86_feature; 1653446Smrj rm->rm_cr4 = getcr4(); 1663446Smrj 1675295Srandyf rmp_gdt_init(rm); 1685295Srandyf 1695295Srandyf return (ct); 1705295Srandyf } 1715295Srandyf 1725295Srandyf /*ARGSUSED*/ 1735295Srandyf void 1745295Srandyf rmp_gdt_init(rm_platter_t *rm) 1755295Srandyf { 1765295Srandyf 1773446Smrj #if defined(__amd64) 1783446Smrj 1793446Smrj if (getcr3() > 0xffffffffUL) 1803446Smrj panic("Cannot initialize CPUs; kernel's 64-bit page tables\n" 1813446Smrj "located above 4G in physical memory (@ 0x%lx)", getcr3()); 1823446Smrj 1833446Smrj /* 1843446Smrj * Setup pseudo-descriptors for temporary GDT and IDT for use ONLY 1853446Smrj * by code in real_mode_start(): 1863446Smrj * 1873446Smrj * GDT[0]: NULL selector 1883446Smrj * GDT[1]: 64-bit CS: Long = 1, Present = 1, bits 12, 11 = 1 1893446Smrj * 1903446Smrj * Clear the IDT as interrupts will be off and a limit of 0 will cause 1913446Smrj * the CPU to triple fault and reset on an NMI, seemingly as reasonable 1923446Smrj * a course of action as any other, though it may cause the entire 1933446Smrj * platform to reset in some cases... 1943446Smrj */ 1953446Smrj rm->rm_temp_gdt[0] = 0; 1963446Smrj rm->rm_temp_gdt[TEMPGDT_KCODE64] = 0x20980000000000ULL; 1973446Smrj 1983446Smrj rm->rm_temp_gdt_lim = (ushort_t)(sizeof (rm->rm_temp_gdt) - 1); 1993446Smrj rm->rm_temp_gdt_base = rm_platter_pa + 2003446Smrj (uint32_t)offsetof(rm_platter_t, rm_temp_gdt); 2013446Smrj rm->rm_temp_idt_lim = 0; 2023446Smrj rm->rm_temp_idt_base = 0; 2033446Smrj 2043446Smrj /* 2053446Smrj * Since the CPU needs to jump to protected mode using an identity 2063446Smrj * mapped address, we need to calculate it here. 2073446Smrj */ 2083446Smrj rm->rm_longmode64_addr = rm_platter_pa + 2093446Smrj ((uint32_t)long_mode_64 - (uint32_t)real_mode_start); 2103446Smrj #endif /* __amd64 */ 2113446Smrj } 2123446Smrj 2133446Smrj /*ARGSUSED*/ 2143446Smrj void 2153446Smrj mach_cpucontext_free(struct cpu *cp, void *arg, int err) 2163446Smrj { 2173446Smrj struct cpu_tables *ct = arg; 2183446Smrj 2193446Smrj ASSERT(&ct->ct_tss == cp->cpu_tss); 2203446Smrj 2213446Smrj switch (err) { 2223446Smrj case 0: 2233446Smrj break; 2243446Smrj case ETIMEDOUT: 2253446Smrj /* 2263446Smrj * The processor was poked, but failed to start before 2273446Smrj * we gave up waiting for it. In case it starts later, 2283446Smrj * don't free anything. 2293446Smrj */ 2303446Smrj break; 2313446Smrj default: 2323446Smrj /* 2333446Smrj * Some other, passive, error occurred. 2343446Smrj */ 2355460Sjosephb kmem_free(ct, P2ROUNDUP(sizeof (*ct), PAGESIZE)); 2363446Smrj cp->cpu_tss = NULL; 2373446Smrj break; 2383446Smrj } 2393446Smrj } 2403446Smrj 2413446Smrj /* 2423446Smrj * "Enter monitor." Called via cross-call from stop_other_cpus(). 2433446Smrj */ 2443446Smrj void 2453446Smrj mach_cpu_halt(char *msg) 2463446Smrj { 2473446Smrj if (msg) 2483446Smrj prom_printf("%s\n", msg); 2493446Smrj 2503446Smrj /*CONSTANTCONDITION*/ 2513446Smrj while (1) 2523446Smrj ; 2533446Smrj } 2543446Smrj 2553446Smrj void 2563446Smrj mach_cpu_idle(void) 2573446Smrj { 2583446Smrj i86_halt(); 2593446Smrj } 2603446Smrj 2613446Smrj void 2623446Smrj mach_cpu_pause(volatile char *safe) 2633446Smrj { 2643446Smrj /* 2653446Smrj * This cpu is now safe. 2663446Smrj */ 2673446Smrj *safe = PAUSE_WAIT; 2683446Smrj membar_enter(); /* make sure stores are flushed */ 2693446Smrj 2703446Smrj /* 2713446Smrj * Now we wait. When we are allowed to continue, safe 2723446Smrj * will be set to PAUSE_IDLE. 2733446Smrj */ 2743446Smrj while (*safe != PAUSE_IDLE) 2753446Smrj SMT_PAUSE(); 2763446Smrj } 2773446Smrj 2783446Smrj /* 2793446Smrj * Power on CPU. 2803446Smrj */ 2813446Smrj /*ARGSUSED*/ 2823446Smrj int 2833446Smrj mp_cpu_poweron(struct cpu *cp) 2843446Smrj { 2853446Smrj ASSERT(MUTEX_HELD(&cpu_lock)); 2863446Smrj return (ENOTSUP); /* not supported */ 2873446Smrj } 2883446Smrj 2893446Smrj /* 2903446Smrj * Power off CPU. 2913446Smrj */ 2923446Smrj /*ARGSUSED*/ 2933446Smrj int 2943446Smrj mp_cpu_poweroff(struct cpu *cp) 2953446Smrj { 2963446Smrj ASSERT(MUTEX_HELD(&cpu_lock)); 2973446Smrj return (ENOTSUP); /* not supported */ 2983446Smrj } 2995529Ssmaybe 3005529Ssmaybe /* 3015529Ssmaybe * Return vcpu state, since this could be a virtual environment that we 3025529Ssmaybe * are unaware of, return "unknown". 3035529Ssmaybe */ 3045529Ssmaybe /* ARGSUSED */ 3055529Ssmaybe int 3065529Ssmaybe vcpu_on_pcpu(processorid_t cpu) 3075529Ssmaybe { 3085529Ssmaybe return (VCPU_STATE_UNKNOWN); 3095529Ssmaybe } 310