1*3446Smrj /* 2*3446Smrj * CDDL HEADER START 3*3446Smrj * 4*3446Smrj * The contents of this file are subject to the terms of the 5*3446Smrj * Common Development and Distribution License (the "License"). 6*3446Smrj * You may not use this file except in compliance with the License. 7*3446Smrj * 8*3446Smrj * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 9*3446Smrj * or http://www.opensolaris.org/os/licensing. 10*3446Smrj * See the License for the specific language governing permissions 11*3446Smrj * and limitations under the License. 12*3446Smrj * 13*3446Smrj * When distributing Covered Code, include this CDDL HEADER in each 14*3446Smrj * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 15*3446Smrj * If applicable, add the following below this CDDL HEADER, with the 16*3446Smrj * fields enclosed by brackets "[]" replaced with your own identifying 17*3446Smrj * information: Portions Copyright [yyyy] [name of copyright owner] 18*3446Smrj * 19*3446Smrj * CDDL HEADER END 20*3446Smrj */ 21*3446Smrj /* 22*3446Smrj * Copyright 2007 Sun Microsystems, Inc. All rights reserved. 23*3446Smrj * Use is subject to license terms. 24*3446Smrj */ 25*3446Smrj 26*3446Smrj #pragma ident "%Z%%M% %I% %E% SMI" 27*3446Smrj 28*3446Smrj /* 29*3446Smrj * Welcome to the world of the "real mode platter". 30*3446Smrj * See also startup.c, mpcore.s and apic.c for related routines. 31*3446Smrj */ 32*3446Smrj 33*3446Smrj #include <sys/types.h> 34*3446Smrj #include <sys/systm.h> 35*3446Smrj #include <sys/cpuvar.h> 36*3446Smrj #include <sys/kmem.h> 37*3446Smrj #include <sys/archsystm.h> 38*3446Smrj #include <sys/machsystm.h> 39*3446Smrj #include <sys/controlregs.h> 40*3446Smrj #include <sys/x86_archext.h> 41*3446Smrj #include <sys/smp_impldefs.h> 42*3446Smrj #include <sys/sysmacros.h> 43*3446Smrj #include <sys/mach_mmu.h> 44*3446Smrj #include <sys/promif.h> 45*3446Smrj #include <sys/cpu.h> 46*3446Smrj 47*3446Smrj extern void real_mode_start(void); 48*3446Smrj extern void real_mode_end(void); 49*3446Smrj 50*3446Smrj /* 51*3446Smrj * Fill up the real mode platter to make it easy for real mode code to 52*3446Smrj * kick it off. This area should really be one passed by boot to kernel 53*3446Smrj * and guaranteed to be below 1MB and aligned to 16 bytes. Should also 54*3446Smrj * have identical physical and virtual address in paged mode. 55*3446Smrj */ 56*3446Smrj static ushort_t *warm_reset_vector = NULL; 57*3446Smrj 58*3446Smrj int 59*3446Smrj mach_cpucontext_init(void) 60*3446Smrj { 61*3446Smrj ushort_t *vec; 62*3446Smrj 63*3446Smrj if (!(vec = (ushort_t *)psm_map_phys(WARM_RESET_VECTOR, 64*3446Smrj sizeof (vec), PROT_READ | PROT_WRITE))) 65*3446Smrj return (-1); 66*3446Smrj /* 67*3446Smrj * setup secondary cpu bios boot up vector 68*3446Smrj */ 69*3446Smrj *vec = (ushort_t)((caddr_t) 70*3446Smrj ((struct rm_platter *)rm_platter_va)->rm_code - rm_platter_va 71*3446Smrj + ((ulong_t)rm_platter_va & 0xf)); 72*3446Smrj vec[1] = (ushort_t)(rm_platter_pa >> 4); 73*3446Smrj warm_reset_vector = vec; 74*3446Smrj 75*3446Smrj bcopy((caddr_t)real_mode_start, 76*3446Smrj (caddr_t)((rm_platter_t *)rm_platter_va)->rm_code, 77*3446Smrj (size_t)real_mode_end - (size_t)real_mode_start); 78*3446Smrj 79*3446Smrj return (0); 80*3446Smrj } 81*3446Smrj 82*3446Smrj void 83*3446Smrj mach_cpucontext_fini(void) 84*3446Smrj { 85*3446Smrj if (warm_reset_vector) 86*3446Smrj psm_unmap_phys((caddr_t)warm_reset_vector, 87*3446Smrj sizeof (warm_reset_vector)); 88*3446Smrj hat_unload(kas.a_hat, (caddr_t)(uintptr_t)rm_platter_pa, MMU_PAGESIZE, 89*3446Smrj HAT_UNLOAD); 90*3446Smrj } 91*3446Smrj 92*3446Smrj #if defined(__amd64) 93*3446Smrj extern void *long_mode_64(void); 94*3446Smrj #endif /* __amd64 */ 95*3446Smrj 96*3446Smrj void * 97*3446Smrj mach_cpucontext_alloc(struct cpu *cp) 98*3446Smrj { 99*3446Smrj rm_platter_t *rm = (rm_platter_t *)rm_platter_va; 100*3446Smrj struct cpu_tables *ct; 101*3446Smrj struct tss *ntss; 102*3446Smrj 103*3446Smrj /* 104*3446Smrj * Allocate space for page directory, stack, tss, gdt and idt. 105*3446Smrj * The page directory has to be page aligned 106*3446Smrj */ 107*3446Smrj ct = kmem_zalloc(sizeof (*ct), KM_SLEEP); 108*3446Smrj if ((uintptr_t)ct & ~MMU_STD_PAGEMASK) 109*3446Smrj panic("mp_startup_init: cpu%d misaligned tables", cp->cpu_id); 110*3446Smrj 111*3446Smrj ntss = cp->cpu_tss = &ct->ct_tss; 112*3446Smrj 113*3446Smrj #if defined(__amd64) 114*3446Smrj 115*3446Smrj /* 116*3446Smrj * #DF (double fault). 117*3446Smrj */ 118*3446Smrj ntss->tss_ist1 = (uint64_t)&ct->ct_stack[sizeof (ct->ct_stack)]; 119*3446Smrj 120*3446Smrj #elif defined(__i386) 121*3446Smrj 122*3446Smrj ntss->tss_esp0 = ntss->tss_esp1 = ntss->tss_esp2 = ntss->tss_esp = 123*3446Smrj (uint32_t)&ct->ct_stack[sizeof (ct->ct_stack)]; 124*3446Smrj 125*3446Smrj ntss->tss_ss0 = ntss->tss_ss1 = ntss->tss_ss2 = ntss->tss_ss = KDS_SEL; 126*3446Smrj 127*3446Smrj ntss->tss_eip = (uint32_t)cp->cpu_thread->t_pc; 128*3446Smrj 129*3446Smrj ntss->tss_cs = KCS_SEL; 130*3446Smrj ntss->tss_ds = ntss->tss_es = KDS_SEL; 131*3446Smrj ntss->tss_fs = KFS_SEL; 132*3446Smrj ntss->tss_gs = KGS_SEL; 133*3446Smrj 134*3446Smrj #endif /* __i386 */ 135*3446Smrj 136*3446Smrj /* 137*3446Smrj * Set I/O bit map offset equal to size of TSS segment limit 138*3446Smrj * for no I/O permission map. This will cause all user I/O 139*3446Smrj * instructions to generate #gp fault. 140*3446Smrj */ 141*3446Smrj ntss->tss_bitmapbase = sizeof (*ntss); 142*3446Smrj 143*3446Smrj /* 144*3446Smrj * Setup kernel tss. 145*3446Smrj */ 146*3446Smrj set_syssegd((system_desc_t *)&cp->cpu_gdt[GDT_KTSS], cp->cpu_tss, 147*3446Smrj sizeof (*cp->cpu_tss) -1, SDT_SYSTSS, SEL_KPL); 148*3446Smrj 149*3446Smrj /* 150*3446Smrj * Now copy all that we've set up onto the real mode platter 151*3446Smrj * for the real mode code to digest as part of starting the cpu. 152*3446Smrj */ 153*3446Smrj 154*3446Smrj rm->rm_idt_base = cp->cpu_idt; 155*3446Smrj rm->rm_idt_lim = sizeof (idt0) - 1; 156*3446Smrj rm->rm_gdt_base = cp->cpu_gdt; 157*3446Smrj rm->rm_gdt_lim = ((sizeof (*cp->cpu_gdt) * NGDT)) -1; 158*3446Smrj 159*3446Smrj rm->rm_pdbr = getcr3(); 160*3446Smrj rm->rm_cpu = cp->cpu_id; 161*3446Smrj rm->rm_x86feature = x86_feature; 162*3446Smrj rm->rm_cr4 = getcr4(); 163*3446Smrj 164*3446Smrj #if defined(__amd64) 165*3446Smrj 166*3446Smrj if (getcr3() > 0xffffffffUL) 167*3446Smrj panic("Cannot initialize CPUs; kernel's 64-bit page tables\n" 168*3446Smrj "located above 4G in physical memory (@ 0x%lx)", getcr3()); 169*3446Smrj 170*3446Smrj /* 171*3446Smrj * Setup pseudo-descriptors for temporary GDT and IDT for use ONLY 172*3446Smrj * by code in real_mode_start(): 173*3446Smrj * 174*3446Smrj * GDT[0]: NULL selector 175*3446Smrj * GDT[1]: 64-bit CS: Long = 1, Present = 1, bits 12, 11 = 1 176*3446Smrj * 177*3446Smrj * Clear the IDT as interrupts will be off and a limit of 0 will cause 178*3446Smrj * the CPU to triple fault and reset on an NMI, seemingly as reasonable 179*3446Smrj * a course of action as any other, though it may cause the entire 180*3446Smrj * platform to reset in some cases... 181*3446Smrj */ 182*3446Smrj rm->rm_temp_gdt[0] = 0; 183*3446Smrj rm->rm_temp_gdt[TEMPGDT_KCODE64] = 0x20980000000000ULL; 184*3446Smrj 185*3446Smrj rm->rm_temp_gdt_lim = (ushort_t)(sizeof (rm->rm_temp_gdt) - 1); 186*3446Smrj rm->rm_temp_gdt_base = rm_platter_pa + 187*3446Smrj (uint32_t)offsetof(rm_platter_t, rm_temp_gdt); 188*3446Smrj rm->rm_temp_idt_lim = 0; 189*3446Smrj rm->rm_temp_idt_base = 0; 190*3446Smrj 191*3446Smrj /* 192*3446Smrj * Since the CPU needs to jump to protected mode using an identity 193*3446Smrj * mapped address, we need to calculate it here. 194*3446Smrj */ 195*3446Smrj rm->rm_longmode64_addr = rm_platter_pa + 196*3446Smrj ((uint32_t)long_mode_64 - (uint32_t)real_mode_start); 197*3446Smrj #endif /* __amd64 */ 198*3446Smrj 199*3446Smrj return (ct); 200*3446Smrj } 201*3446Smrj 202*3446Smrj /*ARGSUSED*/ 203*3446Smrj void 204*3446Smrj mach_cpucontext_free(struct cpu *cp, void *arg, int err) 205*3446Smrj { 206*3446Smrj struct cpu_tables *ct = arg; 207*3446Smrj 208*3446Smrj ASSERT(&ct->ct_tss == cp->cpu_tss); 209*3446Smrj 210*3446Smrj switch (err) { 211*3446Smrj case 0: 212*3446Smrj break; 213*3446Smrj case ETIMEDOUT: 214*3446Smrj /* 215*3446Smrj * The processor was poked, but failed to start before 216*3446Smrj * we gave up waiting for it. In case it starts later, 217*3446Smrj * don't free anything. 218*3446Smrj */ 219*3446Smrj break; 220*3446Smrj default: 221*3446Smrj /* 222*3446Smrj * Some other, passive, error occurred. 223*3446Smrj */ 224*3446Smrj kmem_free(ct, sizeof (*ct)); 225*3446Smrj cp->cpu_tss = NULL; 226*3446Smrj break; 227*3446Smrj } 228*3446Smrj } 229*3446Smrj 230*3446Smrj /* 231*3446Smrj * "Enter monitor." Called via cross-call from stop_other_cpus(). 232*3446Smrj */ 233*3446Smrj void 234*3446Smrj mach_cpu_halt(char *msg) 235*3446Smrj { 236*3446Smrj if (msg) 237*3446Smrj prom_printf("%s\n", msg); 238*3446Smrj 239*3446Smrj /*CONSTANTCONDITION*/ 240*3446Smrj while (1) 241*3446Smrj ; 242*3446Smrj } 243*3446Smrj 244*3446Smrj void 245*3446Smrj mach_cpu_idle(void) 246*3446Smrj { 247*3446Smrj i86_halt(); 248*3446Smrj } 249*3446Smrj 250*3446Smrj void 251*3446Smrj mach_cpu_pause(volatile char *safe) 252*3446Smrj { 253*3446Smrj /* 254*3446Smrj * This cpu is now safe. 255*3446Smrj */ 256*3446Smrj *safe = PAUSE_WAIT; 257*3446Smrj membar_enter(); /* make sure stores are flushed */ 258*3446Smrj 259*3446Smrj /* 260*3446Smrj * Now we wait. When we are allowed to continue, safe 261*3446Smrj * will be set to PAUSE_IDLE. 262*3446Smrj */ 263*3446Smrj while (*safe != PAUSE_IDLE) 264*3446Smrj SMT_PAUSE(); 265*3446Smrj } 266*3446Smrj 267*3446Smrj /* 268*3446Smrj * Power on CPU. 269*3446Smrj */ 270*3446Smrj /*ARGSUSED*/ 271*3446Smrj int 272*3446Smrj mp_cpu_poweron(struct cpu *cp) 273*3446Smrj { 274*3446Smrj ASSERT(MUTEX_HELD(&cpu_lock)); 275*3446Smrj return (ENOTSUP); /* not supported */ 276*3446Smrj } 277*3446Smrj 278*3446Smrj /* 279*3446Smrj * Power off CPU. 280*3446Smrj */ 281*3446Smrj /*ARGSUSED*/ 282*3446Smrj int 283*3446Smrj mp_cpu_poweroff(struct cpu *cp) 284*3446Smrj { 285*3446Smrj ASSERT(MUTEX_HELD(&cpu_lock)); 286*3446Smrj return (ENOTSUP); /* not supported */ 287*3446Smrj } 288