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> 46*4191Sjosephb #include <vm/hat_i86.h> 473446Smrj 483446Smrj extern void real_mode_start(void); 493446Smrj extern void real_mode_end(void); 503446Smrj 513446Smrj /* 523446Smrj * Fill up the real mode platter to make it easy for real mode code to 533446Smrj * kick it off. This area should really be one passed by boot to kernel 543446Smrj * and guaranteed to be below 1MB and aligned to 16 bytes. Should also 553446Smrj * have identical physical and virtual address in paged mode. 563446Smrj */ 573446Smrj static ushort_t *warm_reset_vector = NULL; 583446Smrj 593446Smrj int 603446Smrj mach_cpucontext_init(void) 613446Smrj { 623446Smrj ushort_t *vec; 633446Smrj 643446Smrj if (!(vec = (ushort_t *)psm_map_phys(WARM_RESET_VECTOR, 653446Smrj sizeof (vec), PROT_READ | PROT_WRITE))) 663446Smrj return (-1); 673446Smrj /* 683446Smrj * setup secondary cpu bios boot up vector 693446Smrj */ 703446Smrj *vec = (ushort_t)((caddr_t) 713446Smrj ((struct rm_platter *)rm_platter_va)->rm_code - rm_platter_va 723446Smrj + ((ulong_t)rm_platter_va & 0xf)); 733446Smrj vec[1] = (ushort_t)(rm_platter_pa >> 4); 743446Smrj warm_reset_vector = vec; 753446Smrj 763446Smrj bcopy((caddr_t)real_mode_start, 773446Smrj (caddr_t)((rm_platter_t *)rm_platter_va)->rm_code, 783446Smrj (size_t)real_mode_end - (size_t)real_mode_start); 793446Smrj 803446Smrj return (0); 813446Smrj } 823446Smrj 833446Smrj void 843446Smrj mach_cpucontext_fini(void) 853446Smrj { 863446Smrj if (warm_reset_vector) 873446Smrj psm_unmap_phys((caddr_t)warm_reset_vector, 883446Smrj sizeof (warm_reset_vector)); 893446Smrj hat_unload(kas.a_hat, (caddr_t)(uintptr_t)rm_platter_pa, MMU_PAGESIZE, 903446Smrj HAT_UNLOAD); 913446Smrj } 923446Smrj 933446Smrj #if defined(__amd64) 943446Smrj extern void *long_mode_64(void); 953446Smrj #endif /* __amd64 */ 963446Smrj 973446Smrj void * 983446Smrj mach_cpucontext_alloc(struct cpu *cp) 993446Smrj { 1003446Smrj rm_platter_t *rm = (rm_platter_t *)rm_platter_va; 1013446Smrj struct cpu_tables *ct; 1023446Smrj struct tss *ntss; 1033446Smrj 1043446Smrj /* 1053446Smrj * Allocate space for page directory, stack, tss, gdt and idt. 1063446Smrj * The page directory has to be page aligned 1073446Smrj */ 1083446Smrj ct = kmem_zalloc(sizeof (*ct), KM_SLEEP); 1093446Smrj if ((uintptr_t)ct & ~MMU_STD_PAGEMASK) 1103446Smrj panic("mp_startup_init: cpu%d misaligned tables", cp->cpu_id); 1113446Smrj 1123446Smrj ntss = cp->cpu_tss = &ct->ct_tss; 1133446Smrj 1143446Smrj #if defined(__amd64) 1153446Smrj 1163446Smrj /* 1173446Smrj * #DF (double fault). 1183446Smrj */ 1193446Smrj ntss->tss_ist1 = (uint64_t)&ct->ct_stack[sizeof (ct->ct_stack)]; 1203446Smrj 1213446Smrj #elif defined(__i386) 1223446Smrj 1233446Smrj ntss->tss_esp0 = ntss->tss_esp1 = ntss->tss_esp2 = ntss->tss_esp = 1243446Smrj (uint32_t)&ct->ct_stack[sizeof (ct->ct_stack)]; 1253446Smrj 1263446Smrj ntss->tss_ss0 = ntss->tss_ss1 = ntss->tss_ss2 = ntss->tss_ss = KDS_SEL; 1273446Smrj 1283446Smrj ntss->tss_eip = (uint32_t)cp->cpu_thread->t_pc; 1293446Smrj 1303446Smrj ntss->tss_cs = KCS_SEL; 1313446Smrj ntss->tss_ds = ntss->tss_es = KDS_SEL; 1323446Smrj ntss->tss_fs = KFS_SEL; 1333446Smrj ntss->tss_gs = KGS_SEL; 1343446Smrj 1353446Smrj #endif /* __i386 */ 1363446Smrj 1373446Smrj /* 1383446Smrj * Set I/O bit map offset equal to size of TSS segment limit 1393446Smrj * for no I/O permission map. This will cause all user I/O 1403446Smrj * instructions to generate #gp fault. 1413446Smrj */ 1423446Smrj ntss->tss_bitmapbase = sizeof (*ntss); 1433446Smrj 1443446Smrj /* 1453446Smrj * Setup kernel tss. 1463446Smrj */ 1473446Smrj set_syssegd((system_desc_t *)&cp->cpu_gdt[GDT_KTSS], cp->cpu_tss, 1483446Smrj sizeof (*cp->cpu_tss) -1, SDT_SYSTSS, SEL_KPL); 1493446Smrj 1503446Smrj /* 1513446Smrj * Now copy all that we've set up onto the real mode platter 1523446Smrj * for the real mode code to digest as part of starting the cpu. 1533446Smrj */ 1543446Smrj 1553446Smrj rm->rm_idt_base = cp->cpu_idt; 1563446Smrj rm->rm_idt_lim = sizeof (idt0) - 1; 1573446Smrj rm->rm_gdt_base = cp->cpu_gdt; 1583446Smrj rm->rm_gdt_lim = ((sizeof (*cp->cpu_gdt) * NGDT)) -1; 1593446Smrj 1603446Smrj rm->rm_pdbr = getcr3(); 1613446Smrj rm->rm_cpu = cp->cpu_id; 1623446Smrj rm->rm_x86feature = x86_feature; 1633446Smrj rm->rm_cr4 = getcr4(); 1643446Smrj 1653446Smrj #if defined(__amd64) 1663446Smrj 1673446Smrj if (getcr3() > 0xffffffffUL) 1683446Smrj panic("Cannot initialize CPUs; kernel's 64-bit page tables\n" 1693446Smrj "located above 4G in physical memory (@ 0x%lx)", getcr3()); 1703446Smrj 1713446Smrj /* 1723446Smrj * Setup pseudo-descriptors for temporary GDT and IDT for use ONLY 1733446Smrj * by code in real_mode_start(): 1743446Smrj * 1753446Smrj * GDT[0]: NULL selector 1763446Smrj * GDT[1]: 64-bit CS: Long = 1, Present = 1, bits 12, 11 = 1 1773446Smrj * 1783446Smrj * Clear the IDT as interrupts will be off and a limit of 0 will cause 1793446Smrj * the CPU to triple fault and reset on an NMI, seemingly as reasonable 1803446Smrj * a course of action as any other, though it may cause the entire 1813446Smrj * platform to reset in some cases... 1823446Smrj */ 1833446Smrj rm->rm_temp_gdt[0] = 0; 1843446Smrj rm->rm_temp_gdt[TEMPGDT_KCODE64] = 0x20980000000000ULL; 1853446Smrj 1863446Smrj rm->rm_temp_gdt_lim = (ushort_t)(sizeof (rm->rm_temp_gdt) - 1); 1873446Smrj rm->rm_temp_gdt_base = rm_platter_pa + 1883446Smrj (uint32_t)offsetof(rm_platter_t, rm_temp_gdt); 1893446Smrj rm->rm_temp_idt_lim = 0; 1903446Smrj rm->rm_temp_idt_base = 0; 1913446Smrj 1923446Smrj /* 1933446Smrj * Since the CPU needs to jump to protected mode using an identity 1943446Smrj * mapped address, we need to calculate it here. 1953446Smrj */ 1963446Smrj rm->rm_longmode64_addr = rm_platter_pa + 1973446Smrj ((uint32_t)long_mode_64 - (uint32_t)real_mode_start); 1983446Smrj #endif /* __amd64 */ 1993446Smrj 2003446Smrj return (ct); 2013446Smrj } 2023446Smrj 2033446Smrj /*ARGSUSED*/ 2043446Smrj void 2053446Smrj mach_cpucontext_free(struct cpu *cp, void *arg, int err) 2063446Smrj { 2073446Smrj struct cpu_tables *ct = arg; 2083446Smrj 2093446Smrj ASSERT(&ct->ct_tss == cp->cpu_tss); 2103446Smrj 2113446Smrj switch (err) { 2123446Smrj case 0: 2133446Smrj break; 2143446Smrj case ETIMEDOUT: 2153446Smrj /* 2163446Smrj * The processor was poked, but failed to start before 2173446Smrj * we gave up waiting for it. In case it starts later, 2183446Smrj * don't free anything. 2193446Smrj */ 2203446Smrj break; 2213446Smrj default: 2223446Smrj /* 2233446Smrj * Some other, passive, error occurred. 2243446Smrj */ 2253446Smrj kmem_free(ct, sizeof (*ct)); 2263446Smrj cp->cpu_tss = NULL; 2273446Smrj break; 2283446Smrj } 2293446Smrj } 2303446Smrj 2313446Smrj /* 2323446Smrj * "Enter monitor." Called via cross-call from stop_other_cpus(). 2333446Smrj */ 2343446Smrj void 2353446Smrj mach_cpu_halt(char *msg) 2363446Smrj { 2373446Smrj if (msg) 2383446Smrj prom_printf("%s\n", msg); 2393446Smrj 2403446Smrj /*CONSTANTCONDITION*/ 2413446Smrj while (1) 2423446Smrj ; 2433446Smrj } 2443446Smrj 2453446Smrj void 2463446Smrj mach_cpu_idle(void) 2473446Smrj { 248*4191Sjosephb tlb_going_idle(); 2493446Smrj i86_halt(); 250*4191Sjosephb tlb_service(); 2513446Smrj } 2523446Smrj 2533446Smrj void 2543446Smrj mach_cpu_pause(volatile char *safe) 2553446Smrj { 2563446Smrj /* 2573446Smrj * This cpu is now safe. 2583446Smrj */ 2593446Smrj *safe = PAUSE_WAIT; 2603446Smrj membar_enter(); /* make sure stores are flushed */ 2613446Smrj 2623446Smrj /* 2633446Smrj * Now we wait. When we are allowed to continue, safe 2643446Smrj * will be set to PAUSE_IDLE. 2653446Smrj */ 2663446Smrj while (*safe != PAUSE_IDLE) 2673446Smrj SMT_PAUSE(); 2683446Smrj } 2693446Smrj 2703446Smrj /* 2713446Smrj * Power on CPU. 2723446Smrj */ 2733446Smrj /*ARGSUSED*/ 2743446Smrj int 2753446Smrj mp_cpu_poweron(struct cpu *cp) 2763446Smrj { 2773446Smrj ASSERT(MUTEX_HELD(&cpu_lock)); 2783446Smrj return (ENOTSUP); /* not supported */ 2793446Smrj } 2803446Smrj 2813446Smrj /* 2823446Smrj * Power off CPU. 2833446Smrj */ 2843446Smrj /*ARGSUSED*/ 2853446Smrj int 2863446Smrj mp_cpu_poweroff(struct cpu *cp) 2873446Smrj { 2883446Smrj ASSERT(MUTEX_HELD(&cpu_lock)); 2893446Smrj return (ENOTSUP); /* not supported */ 2903446Smrj } 291