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 /* 223446Smrj * Copyright 2007 Sun Microsystems, Inc. All rights reserved. 233446Smrj * Use is subject to license terms. 243446Smrj */ 253446Smrj 263446Smrj #pragma ident "%Z%%M% %I% %E% SMI" 273446Smrj 283446Smrj /* 293446Smrj * Welcome to the world of the "real mode platter". 303446Smrj * See also startup.c, mpcore.s and apic.c for related routines. 313446Smrj */ 323446Smrj 333446Smrj #include <sys/types.h> 343446Smrj #include <sys/systm.h> 353446Smrj #include <sys/cpuvar.h> 363446Smrj #include <sys/kmem.h> 373446Smrj #include <sys/archsystm.h> 383446Smrj #include <sys/machsystm.h> 393446Smrj #include <sys/controlregs.h> 403446Smrj #include <sys/x86_archext.h> 413446Smrj #include <sys/smp_impldefs.h> 423446Smrj #include <sys/sysmacros.h> 433446Smrj #include <sys/mach_mmu.h> 443446Smrj #include <sys/promif.h> 453446Smrj #include <sys/cpu.h> 464191Sjosephb #include <vm/hat_i86.h> 473446Smrj 483446Smrj extern void real_mode_start(void); 493446Smrj extern void real_mode_end(void); 505295Srandyf extern void *(*cpu_pause_func)(void *); 515295Srandyf 525295Srandyf void rmp_gdt_init(rm_platter_t *); 533446Smrj 543446Smrj /* 553446Smrj * Fill up the real mode platter to make it easy for real mode code to 563446Smrj * kick it off. This area should really be one passed by boot to kernel 573446Smrj * and guaranteed to be below 1MB and aligned to 16 bytes. Should also 583446Smrj * have identical physical and virtual address in paged mode. 593446Smrj */ 603446Smrj static ushort_t *warm_reset_vector = NULL; 613446Smrj 623446Smrj int 633446Smrj mach_cpucontext_init(void) 643446Smrj { 653446Smrj ushort_t *vec; 663446Smrj 673446Smrj if (!(vec = (ushort_t *)psm_map_phys(WARM_RESET_VECTOR, 683446Smrj sizeof (vec), PROT_READ | PROT_WRITE))) 693446Smrj return (-1); 703446Smrj /* 713446Smrj * setup secondary cpu bios boot up vector 723446Smrj */ 733446Smrj *vec = (ushort_t)((caddr_t) 745295Srandyf ((struct rm_platter *)rm_platter_va)->rm_code - rm_platter_va 755295Srandyf + ((ulong_t)rm_platter_va & 0xf)); 763446Smrj vec[1] = (ushort_t)(rm_platter_pa >> 4); 773446Smrj warm_reset_vector = vec; 783446Smrj 793446Smrj bcopy((caddr_t)real_mode_start, 803446Smrj (caddr_t)((rm_platter_t *)rm_platter_va)->rm_code, 813446Smrj (size_t)real_mode_end - (size_t)real_mode_start); 823446Smrj 833446Smrj return (0); 843446Smrj } 853446Smrj 863446Smrj void 873446Smrj mach_cpucontext_fini(void) 883446Smrj { 893446Smrj if (warm_reset_vector) 903446Smrj psm_unmap_phys((caddr_t)warm_reset_vector, 913446Smrj sizeof (warm_reset_vector)); 923446Smrj hat_unload(kas.a_hat, (caddr_t)(uintptr_t)rm_platter_pa, MMU_PAGESIZE, 933446Smrj HAT_UNLOAD); 943446Smrj } 953446Smrj 963446Smrj #if defined(__amd64) 973446Smrj extern void *long_mode_64(void); 983446Smrj #endif /* __amd64 */ 993446Smrj 1003446Smrj void * 1013446Smrj mach_cpucontext_alloc(struct cpu *cp) 1023446Smrj { 1033446Smrj rm_platter_t *rm = (rm_platter_t *)rm_platter_va; 1043446Smrj struct cpu_tables *ct; 1053446Smrj struct tss *ntss; 1063446Smrj 1073446Smrj /* 108*5460Sjosephb * Allocate space for stack, tss, gdt and idt. We round the size 109*5460Sjosephb * alloated for cpu_tables up, so that the TSS is on a unique page. 110*5460Sjosephb * This is more efficient when running in virtual machines. 1113446Smrj */ 112*5460Sjosephb ct = kmem_zalloc(P2ROUNDUP(sizeof (*ct), PAGESIZE), KM_SLEEP); 113*5460Sjosephb if ((uintptr_t)ct & PAGEOFFSET) 1143446Smrj panic("mp_startup_init: cpu%d misaligned tables", cp->cpu_id); 1153446Smrj 1163446Smrj ntss = cp->cpu_tss = &ct->ct_tss; 1173446Smrj 1183446Smrj #if defined(__amd64) 1193446Smrj 1203446Smrj /* 1213446Smrj * #DF (double fault). 1223446Smrj */ 1233446Smrj ntss->tss_ist1 = (uint64_t)&ct->ct_stack[sizeof (ct->ct_stack)]; 1243446Smrj 1253446Smrj #elif defined(__i386) 1263446Smrj 1273446Smrj ntss->tss_esp0 = ntss->tss_esp1 = ntss->tss_esp2 = ntss->tss_esp = 1283446Smrj (uint32_t)&ct->ct_stack[sizeof (ct->ct_stack)]; 1293446Smrj 1303446Smrj ntss->tss_ss0 = ntss->tss_ss1 = ntss->tss_ss2 = ntss->tss_ss = KDS_SEL; 1313446Smrj 1323446Smrj ntss->tss_eip = (uint32_t)cp->cpu_thread->t_pc; 1333446Smrj 1343446Smrj ntss->tss_cs = KCS_SEL; 1353446Smrj ntss->tss_ds = ntss->tss_es = KDS_SEL; 1363446Smrj ntss->tss_fs = KFS_SEL; 1373446Smrj ntss->tss_gs = KGS_SEL; 1383446Smrj 1393446Smrj #endif /* __i386 */ 1403446Smrj 1413446Smrj /* 1423446Smrj * Set I/O bit map offset equal to size of TSS segment limit 1433446Smrj * for no I/O permission map. This will cause all user I/O 1443446Smrj * instructions to generate #gp fault. 1453446Smrj */ 1463446Smrj ntss->tss_bitmapbase = sizeof (*ntss); 1473446Smrj 1483446Smrj /* 1493446Smrj * Setup kernel tss. 1503446Smrj */ 1513446Smrj set_syssegd((system_desc_t *)&cp->cpu_gdt[GDT_KTSS], cp->cpu_tss, 152*5460Sjosephb sizeof (*cp->cpu_tss) - 1, SDT_SYSTSS, SEL_KPL); 1533446Smrj 1543446Smrj /* 1553446Smrj * Now copy all that we've set up onto the real mode platter 1563446Smrj * for the real mode code to digest as part of starting the cpu. 1573446Smrj */ 1583446Smrj 1593446Smrj rm->rm_idt_base = cp->cpu_idt; 160*5460Sjosephb rm->rm_idt_lim = sizeof (*cp->cpu_idt) * NIDT - 1; 1613446Smrj rm->rm_gdt_base = cp->cpu_gdt; 162*5460Sjosephb rm->rm_gdt_lim = sizeof (*cp->cpu_gdt) * NGDT - 1; 1633446Smrj 1643446Smrj rm->rm_pdbr = getcr3(); 1653446Smrj rm->rm_cpu = cp->cpu_id; 1663446Smrj rm->rm_x86feature = x86_feature; 1673446Smrj rm->rm_cr4 = getcr4(); 1683446Smrj 1695295Srandyf rmp_gdt_init(rm); 1705295Srandyf 1715295Srandyf return (ct); 1725295Srandyf } 1735295Srandyf 1745295Srandyf /*ARGSUSED*/ 1755295Srandyf void 1765295Srandyf rmp_gdt_init(rm_platter_t *rm) 1775295Srandyf { 1785295Srandyf 1793446Smrj #if defined(__amd64) 1803446Smrj 1813446Smrj if (getcr3() > 0xffffffffUL) 1823446Smrj panic("Cannot initialize CPUs; kernel's 64-bit page tables\n" 1833446Smrj "located above 4G in physical memory (@ 0x%lx)", getcr3()); 1843446Smrj 1853446Smrj /* 1863446Smrj * Setup pseudo-descriptors for temporary GDT and IDT for use ONLY 1873446Smrj * by code in real_mode_start(): 1883446Smrj * 1893446Smrj * GDT[0]: NULL selector 1903446Smrj * GDT[1]: 64-bit CS: Long = 1, Present = 1, bits 12, 11 = 1 1913446Smrj * 1923446Smrj * Clear the IDT as interrupts will be off and a limit of 0 will cause 1933446Smrj * the CPU to triple fault and reset on an NMI, seemingly as reasonable 1943446Smrj * a course of action as any other, though it may cause the entire 1953446Smrj * platform to reset in some cases... 1963446Smrj */ 1973446Smrj rm->rm_temp_gdt[0] = 0; 1983446Smrj rm->rm_temp_gdt[TEMPGDT_KCODE64] = 0x20980000000000ULL; 1993446Smrj 2003446Smrj rm->rm_temp_gdt_lim = (ushort_t)(sizeof (rm->rm_temp_gdt) - 1); 2013446Smrj rm->rm_temp_gdt_base = rm_platter_pa + 2023446Smrj (uint32_t)offsetof(rm_platter_t, rm_temp_gdt); 2033446Smrj rm->rm_temp_idt_lim = 0; 2043446Smrj rm->rm_temp_idt_base = 0; 2053446Smrj 2063446Smrj /* 2073446Smrj * Since the CPU needs to jump to protected mode using an identity 2083446Smrj * mapped address, we need to calculate it here. 2093446Smrj */ 2103446Smrj rm->rm_longmode64_addr = rm_platter_pa + 2113446Smrj ((uint32_t)long_mode_64 - (uint32_t)real_mode_start); 2123446Smrj #endif /* __amd64 */ 2133446Smrj } 2143446Smrj 2153446Smrj /*ARGSUSED*/ 2163446Smrj void 2173446Smrj mach_cpucontext_free(struct cpu *cp, void *arg, int err) 2183446Smrj { 2193446Smrj struct cpu_tables *ct = arg; 2203446Smrj 2213446Smrj ASSERT(&ct->ct_tss == cp->cpu_tss); 2223446Smrj 2233446Smrj switch (err) { 2243446Smrj case 0: 2253446Smrj break; 2263446Smrj case ETIMEDOUT: 2273446Smrj /* 2283446Smrj * The processor was poked, but failed to start before 2293446Smrj * we gave up waiting for it. In case it starts later, 2303446Smrj * don't free anything. 2313446Smrj */ 2323446Smrj break; 2333446Smrj default: 2343446Smrj /* 2353446Smrj * Some other, passive, error occurred. 2363446Smrj */ 237*5460Sjosephb kmem_free(ct, P2ROUNDUP(sizeof (*ct), PAGESIZE)); 2383446Smrj cp->cpu_tss = NULL; 2393446Smrj break; 2403446Smrj } 2413446Smrj } 2423446Smrj 2433446Smrj /* 2443446Smrj * "Enter monitor." Called via cross-call from stop_other_cpus(). 2453446Smrj */ 2463446Smrj void 2473446Smrj mach_cpu_halt(char *msg) 2483446Smrj { 2493446Smrj if (msg) 2503446Smrj prom_printf("%s\n", msg); 2513446Smrj 2523446Smrj /*CONSTANTCONDITION*/ 2533446Smrj while (1) 2543446Smrj ; 2553446Smrj } 2563446Smrj 2573446Smrj void 2583446Smrj mach_cpu_idle(void) 2593446Smrj { 2604191Sjosephb tlb_going_idle(); 2613446Smrj i86_halt(); 2624191Sjosephb tlb_service(); 2633446Smrj } 2643446Smrj 2653446Smrj void 2663446Smrj mach_cpu_pause(volatile char *safe) 2673446Smrj { 2683446Smrj /* 2693446Smrj * This cpu is now safe. 2703446Smrj */ 2713446Smrj *safe = PAUSE_WAIT; 2723446Smrj membar_enter(); /* make sure stores are flushed */ 2733446Smrj 2743446Smrj /* 2753446Smrj * Now we wait. When we are allowed to continue, safe 2763446Smrj * will be set to PAUSE_IDLE. 2773446Smrj */ 2783446Smrj while (*safe != PAUSE_IDLE) 2793446Smrj SMT_PAUSE(); 2803446Smrj } 2813446Smrj 2823446Smrj /* 2833446Smrj * Power on CPU. 2843446Smrj */ 2853446Smrj /*ARGSUSED*/ 2863446Smrj int 2873446Smrj mp_cpu_poweron(struct cpu *cp) 2883446Smrj { 2893446Smrj ASSERT(MUTEX_HELD(&cpu_lock)); 2903446Smrj return (ENOTSUP); /* not supported */ 2913446Smrj } 2923446Smrj 2933446Smrj /* 2943446Smrj * Power off CPU. 2953446Smrj */ 2963446Smrj /*ARGSUSED*/ 2973446Smrj int 2983446Smrj mp_cpu_poweroff(struct cpu *cp) 2993446Smrj { 3003446Smrj ASSERT(MUTEX_HELD(&cpu_lock)); 3013446Smrj return (ENOTSUP); /* not supported */ 3023446Smrj } 303