10Sstevel@tonic-gate /* 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 /* 23*8679SSeth.Goldberg@Sun.COM * Copyright 2009 Sun Microsystems, Inc. All rights reserved. 240Sstevel@tonic-gate * Use is subject to license terms. 250Sstevel@tonic-gate */ 260Sstevel@tonic-gate 270Sstevel@tonic-gate /* 280Sstevel@tonic-gate * Copyright (c) 1992 Terrence R. Lambert. 290Sstevel@tonic-gate * Copyright (c) 1990 The Regents of the University of California. 300Sstevel@tonic-gate * All rights reserved. 310Sstevel@tonic-gate * 320Sstevel@tonic-gate * This code is derived from software contributed to Berkeley by 330Sstevel@tonic-gate * William Jolitz. 340Sstevel@tonic-gate * 350Sstevel@tonic-gate * Redistribution and use in source and binary forms, with or without 360Sstevel@tonic-gate * modification, are permitted provided that the following conditions 370Sstevel@tonic-gate * are met: 380Sstevel@tonic-gate * 1. Redistributions of source code must retain the above copyright 390Sstevel@tonic-gate * notice, this list of conditions and the following disclaimer. 400Sstevel@tonic-gate * 2. Redistributions in binary form must reproduce the above copyright 410Sstevel@tonic-gate * notice, this list of conditions and the following disclaimer in the 420Sstevel@tonic-gate * documentation and/or other materials provided with the distribution. 430Sstevel@tonic-gate * 3. All advertising materials mentioning features or use of this software 440Sstevel@tonic-gate * must display the following acknowledgement: 450Sstevel@tonic-gate * This product includes software developed by the University of 460Sstevel@tonic-gate * California, Berkeley and its contributors. 470Sstevel@tonic-gate * 4. Neither the name of the University nor the names of its contributors 480Sstevel@tonic-gate * may be used to endorse or promote products derived from this software 490Sstevel@tonic-gate * without specific prior written permission. 500Sstevel@tonic-gate * 510Sstevel@tonic-gate * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 520Sstevel@tonic-gate * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 530Sstevel@tonic-gate * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 540Sstevel@tonic-gate * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 550Sstevel@tonic-gate * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 560Sstevel@tonic-gate * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 570Sstevel@tonic-gate * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 580Sstevel@tonic-gate * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 590Sstevel@tonic-gate * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 600Sstevel@tonic-gate * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 610Sstevel@tonic-gate * SUCH DAMAGE. 620Sstevel@tonic-gate * 630Sstevel@tonic-gate * from: @(#)machdep.c 7.4 (Berkeley) 6/3/91 640Sstevel@tonic-gate */ 650Sstevel@tonic-gate 660Sstevel@tonic-gate #include <sys/types.h> 673446Smrj #include <sys/sysmacros.h> 680Sstevel@tonic-gate #include <sys/tss.h> 690Sstevel@tonic-gate #include <sys/segments.h> 700Sstevel@tonic-gate #include <sys/trap.h> 710Sstevel@tonic-gate #include <sys/cpuvar.h> 723446Smrj #include <sys/bootconf.h> 730Sstevel@tonic-gate #include <sys/x86_archext.h> 743446Smrj #include <sys/controlregs.h> 750Sstevel@tonic-gate #include <sys/archsystm.h> 760Sstevel@tonic-gate #include <sys/machsystm.h> 770Sstevel@tonic-gate #include <sys/kobj.h> 780Sstevel@tonic-gate #include <sys/cmn_err.h> 790Sstevel@tonic-gate #include <sys/reboot.h> 800Sstevel@tonic-gate #include <sys/kdi.h> 813446Smrj #include <sys/mach_mmu.h> 821217Srab #include <sys/systm.h> 835084Sjohnlev 845084Sjohnlev #ifdef __xpv 855084Sjohnlev #include <sys/hypervisor.h> 865084Sjohnlev #include <vm/as.h> 875084Sjohnlev #endif 885084Sjohnlev 893446Smrj #include <sys/promif.h> 903446Smrj #include <sys/bootinfo.h> 913446Smrj #include <vm/kboot_mmu.h> 925084Sjohnlev #include <vm/hat_pte.h> 930Sstevel@tonic-gate 940Sstevel@tonic-gate /* 950Sstevel@tonic-gate * cpu0 and default tables and structures. 960Sstevel@tonic-gate */ 973446Smrj user_desc_t *gdt0; 985084Sjohnlev #if !defined(__xpv) 990Sstevel@tonic-gate desctbr_t gdt0_default_r; 1005084Sjohnlev #endif 1010Sstevel@tonic-gate 1025460Sjosephb gate_desc_t *idt0; /* interrupt descriptor table */ 1033446Smrj #if defined(__i386) 1040Sstevel@tonic-gate desctbr_t idt0_default_r; /* describes idt0 in IDTR format */ 1053446Smrj #endif 1060Sstevel@tonic-gate 1075460Sjosephb struct tss *ktss0; /* kernel task state structure */ 1080Sstevel@tonic-gate 1090Sstevel@tonic-gate #if defined(__i386) 1105460Sjosephb struct tss *dftss0; /* #DF double-fault exception */ 1110Sstevel@tonic-gate #endif /* __i386 */ 1120Sstevel@tonic-gate 1130Sstevel@tonic-gate user_desc_t zero_udesc; /* base zero user desc native procs */ 1145084Sjohnlev user_desc_t null_udesc; /* null user descriptor */ 1155084Sjohnlev system_desc_t null_sdesc; /* null system descriptor */ 1160Sstevel@tonic-gate 1170Sstevel@tonic-gate #if defined(__amd64) 1180Sstevel@tonic-gate user_desc_t zero_u32desc; /* 32-bit compatibility procs */ 1190Sstevel@tonic-gate #endif /* __amd64 */ 1200Sstevel@tonic-gate 1215084Sjohnlev #if defined(__amd64) 1225084Sjohnlev user_desc_t ucs_on; 1235084Sjohnlev user_desc_t ucs_off; 1245084Sjohnlev user_desc_t ucs32_on; 1255084Sjohnlev user_desc_t ucs32_off; 1265084Sjohnlev #endif /* __amd64 */ 1275084Sjohnlev 1280Sstevel@tonic-gate #pragma align 16(dblfault_stack0) 1290Sstevel@tonic-gate char dblfault_stack0[DEFAULTSTKSZ]; 1300Sstevel@tonic-gate 1310Sstevel@tonic-gate extern void fast_null(void); 1320Sstevel@tonic-gate extern hrtime_t get_hrtime(void); 1330Sstevel@tonic-gate extern hrtime_t gethrvtime(void); 1340Sstevel@tonic-gate extern hrtime_t get_hrestime(void); 1350Sstevel@tonic-gate extern uint64_t getlgrp(void); 1360Sstevel@tonic-gate 1370Sstevel@tonic-gate void (*(fasttable[]))(void) = { 1380Sstevel@tonic-gate fast_null, /* T_FNULL routine */ 1390Sstevel@tonic-gate fast_null, /* T_FGETFP routine (initially null) */ 1400Sstevel@tonic-gate fast_null, /* T_FSETFP routine (initially null) */ 1410Sstevel@tonic-gate (void (*)())get_hrtime, /* T_GETHRTIME */ 1420Sstevel@tonic-gate (void (*)())gethrvtime, /* T_GETHRVTIME */ 1430Sstevel@tonic-gate (void (*)())get_hrestime, /* T_GETHRESTIME */ 1440Sstevel@tonic-gate (void (*)())getlgrp /* T_GETLGRP */ 1450Sstevel@tonic-gate }; 1460Sstevel@tonic-gate 1470Sstevel@tonic-gate /* 1482712Snn35248 * Structure containing pre-computed descriptors to allow us to temporarily 1492712Snn35248 * interpose on a standard handler. 1502712Snn35248 */ 1512712Snn35248 struct interposing_handler { 1522712Snn35248 int ih_inum; 1532712Snn35248 gate_desc_t ih_interp_desc; 1542712Snn35248 gate_desc_t ih_default_desc; 1552712Snn35248 }; 1562712Snn35248 1572712Snn35248 /* 1582712Snn35248 * The brand infrastructure interposes on two handlers, and we use one as a 1592712Snn35248 * NULL signpost. 1602712Snn35248 */ 1612712Snn35248 static struct interposing_handler brand_tbl[3]; 1622712Snn35248 1632712Snn35248 /* 1640Sstevel@tonic-gate * software prototypes for default local descriptor table 1650Sstevel@tonic-gate */ 1660Sstevel@tonic-gate 1670Sstevel@tonic-gate /* 1680Sstevel@tonic-gate * Routines for loading segment descriptors in format the hardware 1690Sstevel@tonic-gate * can understand. 1700Sstevel@tonic-gate */ 1710Sstevel@tonic-gate 1720Sstevel@tonic-gate #if defined(__amd64) 1730Sstevel@tonic-gate 1740Sstevel@tonic-gate /* 1750Sstevel@tonic-gate * In long mode we have the new L or long mode attribute bit 1760Sstevel@tonic-gate * for code segments. Only the conforming bit in type is used along 1770Sstevel@tonic-gate * with descriptor priority and present bits. Default operand size must 1780Sstevel@tonic-gate * be zero when in long mode. In 32-bit compatibility mode all fields 1790Sstevel@tonic-gate * are treated as in legacy mode. For data segments while in long mode 1800Sstevel@tonic-gate * only the present bit is loaded. 1810Sstevel@tonic-gate */ 1820Sstevel@tonic-gate void 1830Sstevel@tonic-gate set_usegd(user_desc_t *dp, uint_t lmode, void *base, size_t size, 1840Sstevel@tonic-gate uint_t type, uint_t dpl, uint_t gran, uint_t defopsz) 1850Sstevel@tonic-gate { 1860Sstevel@tonic-gate ASSERT(lmode == SDP_SHORT || lmode == SDP_LONG); 1870Sstevel@tonic-gate 1880Sstevel@tonic-gate /* 1890Sstevel@tonic-gate * 64-bit long mode. 1900Sstevel@tonic-gate */ 1910Sstevel@tonic-gate if (lmode == SDP_LONG) 1920Sstevel@tonic-gate dp->usd_def32 = 0; /* 32-bit operands only */ 1930Sstevel@tonic-gate else 1940Sstevel@tonic-gate /* 1950Sstevel@tonic-gate * 32-bit compatibility mode. 1960Sstevel@tonic-gate */ 1970Sstevel@tonic-gate dp->usd_def32 = defopsz; /* 0 = 16, 1 = 32-bit ops */ 1980Sstevel@tonic-gate 1990Sstevel@tonic-gate dp->usd_long = lmode; /* 64-bit mode */ 2000Sstevel@tonic-gate dp->usd_type = type; 2010Sstevel@tonic-gate dp->usd_dpl = dpl; 2020Sstevel@tonic-gate dp->usd_p = 1; 2030Sstevel@tonic-gate dp->usd_gran = gran; /* 0 = bytes, 1 = pages */ 2040Sstevel@tonic-gate 2050Sstevel@tonic-gate dp->usd_lobase = (uintptr_t)base; 2060Sstevel@tonic-gate dp->usd_midbase = (uintptr_t)base >> 16; 2070Sstevel@tonic-gate dp->usd_hibase = (uintptr_t)base >> (16 + 8); 2080Sstevel@tonic-gate dp->usd_lolimit = size; 2090Sstevel@tonic-gate dp->usd_hilimit = (uintptr_t)size >> 16; 2100Sstevel@tonic-gate } 2110Sstevel@tonic-gate 2120Sstevel@tonic-gate #elif defined(__i386) 2130Sstevel@tonic-gate 2140Sstevel@tonic-gate /* 2150Sstevel@tonic-gate * Install user segment descriptor for code and data. 2160Sstevel@tonic-gate */ 2170Sstevel@tonic-gate void 2180Sstevel@tonic-gate set_usegd(user_desc_t *dp, void *base, size_t size, uint_t type, 2190Sstevel@tonic-gate uint_t dpl, uint_t gran, uint_t defopsz) 2200Sstevel@tonic-gate { 2210Sstevel@tonic-gate dp->usd_lolimit = size; 2220Sstevel@tonic-gate dp->usd_hilimit = (uintptr_t)size >> 16; 2230Sstevel@tonic-gate 2240Sstevel@tonic-gate dp->usd_lobase = (uintptr_t)base; 2250Sstevel@tonic-gate dp->usd_midbase = (uintptr_t)base >> 16; 2260Sstevel@tonic-gate dp->usd_hibase = (uintptr_t)base >> (16 + 8); 2270Sstevel@tonic-gate 2280Sstevel@tonic-gate dp->usd_type = type; 2290Sstevel@tonic-gate dp->usd_dpl = dpl; 2300Sstevel@tonic-gate dp->usd_p = 1; 2310Sstevel@tonic-gate dp->usd_def32 = defopsz; /* 0 = 16, 1 = 32 bit operands */ 2320Sstevel@tonic-gate dp->usd_gran = gran; /* 0 = bytes, 1 = pages */ 2330Sstevel@tonic-gate } 2340Sstevel@tonic-gate 2350Sstevel@tonic-gate #endif /* __i386 */ 2360Sstevel@tonic-gate 2370Sstevel@tonic-gate /* 2380Sstevel@tonic-gate * Install system segment descriptor for LDT and TSS segments. 2390Sstevel@tonic-gate */ 2400Sstevel@tonic-gate 2410Sstevel@tonic-gate #if defined(__amd64) 2420Sstevel@tonic-gate 2430Sstevel@tonic-gate void 2440Sstevel@tonic-gate set_syssegd(system_desc_t *dp, void *base, size_t size, uint_t type, 2450Sstevel@tonic-gate uint_t dpl) 2460Sstevel@tonic-gate { 2470Sstevel@tonic-gate dp->ssd_lolimit = size; 2480Sstevel@tonic-gate dp->ssd_hilimit = (uintptr_t)size >> 16; 2490Sstevel@tonic-gate 2500Sstevel@tonic-gate dp->ssd_lobase = (uintptr_t)base; 2510Sstevel@tonic-gate dp->ssd_midbase = (uintptr_t)base >> 16; 2520Sstevel@tonic-gate dp->ssd_hibase = (uintptr_t)base >> (16 + 8); 2530Sstevel@tonic-gate dp->ssd_hi64base = (uintptr_t)base >> (16 + 8 + 8); 2540Sstevel@tonic-gate 2550Sstevel@tonic-gate dp->ssd_type = type; 2560Sstevel@tonic-gate dp->ssd_zero1 = 0; /* must be zero */ 2570Sstevel@tonic-gate dp->ssd_zero2 = 0; 2580Sstevel@tonic-gate dp->ssd_dpl = dpl; 2590Sstevel@tonic-gate dp->ssd_p = 1; 2600Sstevel@tonic-gate dp->ssd_gran = 0; /* force byte units */ 2610Sstevel@tonic-gate } 2620Sstevel@tonic-gate 2635084Sjohnlev void * 2645084Sjohnlev get_ssd_base(system_desc_t *dp) 2655084Sjohnlev { 2665084Sjohnlev uintptr_t base; 2675084Sjohnlev 2685084Sjohnlev base = (uintptr_t)dp->ssd_lobase | 2695084Sjohnlev (uintptr_t)dp->ssd_midbase << 16 | 2705084Sjohnlev (uintptr_t)dp->ssd_hibase << (16 + 8) | 2715084Sjohnlev (uintptr_t)dp->ssd_hi64base << (16 + 8 + 8); 2725084Sjohnlev return ((void *)base); 2735084Sjohnlev } 2745084Sjohnlev 2750Sstevel@tonic-gate #elif defined(__i386) 2760Sstevel@tonic-gate 2770Sstevel@tonic-gate void 2780Sstevel@tonic-gate set_syssegd(system_desc_t *dp, void *base, size_t size, uint_t type, 2790Sstevel@tonic-gate uint_t dpl) 2800Sstevel@tonic-gate { 2810Sstevel@tonic-gate dp->ssd_lolimit = size; 2820Sstevel@tonic-gate dp->ssd_hilimit = (uintptr_t)size >> 16; 2830Sstevel@tonic-gate 2840Sstevel@tonic-gate dp->ssd_lobase = (uintptr_t)base; 2850Sstevel@tonic-gate dp->ssd_midbase = (uintptr_t)base >> 16; 2860Sstevel@tonic-gate dp->ssd_hibase = (uintptr_t)base >> (16 + 8); 2870Sstevel@tonic-gate 2880Sstevel@tonic-gate dp->ssd_type = type; 2890Sstevel@tonic-gate dp->ssd_zero = 0; /* must be zero */ 2900Sstevel@tonic-gate dp->ssd_dpl = dpl; 2910Sstevel@tonic-gate dp->ssd_p = 1; 2920Sstevel@tonic-gate dp->ssd_gran = 0; /* force byte units */ 2930Sstevel@tonic-gate } 2940Sstevel@tonic-gate 2955084Sjohnlev void * 2965084Sjohnlev get_ssd_base(system_desc_t *dp) 2975084Sjohnlev { 2985084Sjohnlev uintptr_t base; 2995084Sjohnlev 3005084Sjohnlev base = (uintptr_t)dp->ssd_lobase | 3015084Sjohnlev (uintptr_t)dp->ssd_midbase << 16 | 3025084Sjohnlev (uintptr_t)dp->ssd_hibase << (16 + 8); 3035084Sjohnlev return ((void *)base); 3045084Sjohnlev } 3055084Sjohnlev 3060Sstevel@tonic-gate #endif /* __i386 */ 3070Sstevel@tonic-gate 3080Sstevel@tonic-gate /* 3090Sstevel@tonic-gate * Install gate segment descriptor for interrupt, trap, call and task gates. 3100Sstevel@tonic-gate */ 3110Sstevel@tonic-gate 3120Sstevel@tonic-gate #if defined(__amd64) 3130Sstevel@tonic-gate 314*8679SSeth.Goldberg@Sun.COM /*ARGSUSED*/ 3150Sstevel@tonic-gate void 3163446Smrj set_gatesegd(gate_desc_t *dp, void (*func)(void), selector_t sel, 317*8679SSeth.Goldberg@Sun.COM uint_t type, uint_t dpl, uint_t vector) 3180Sstevel@tonic-gate { 3190Sstevel@tonic-gate dp->sgd_looffset = (uintptr_t)func; 3200Sstevel@tonic-gate dp->sgd_hioffset = (uintptr_t)func >> 16; 3210Sstevel@tonic-gate dp->sgd_hi64offset = (uintptr_t)func >> (16 + 16); 3220Sstevel@tonic-gate 3230Sstevel@tonic-gate dp->sgd_selector = (uint16_t)sel; 3243446Smrj 3253446Smrj /* 3263446Smrj * For 64 bit native we use the IST stack mechanism 3273446Smrj * for double faults. All other traps use the CPL = 0 3283446Smrj * (tss_rsp0) stack. 3293446Smrj */ 3305084Sjohnlev #if !defined(__xpv) 331*8679SSeth.Goldberg@Sun.COM if (vector == T_DBLFLT) 3323446Smrj dp->sgd_ist = 1; 3333446Smrj else 3345084Sjohnlev #endif 3353446Smrj dp->sgd_ist = 0; 3363446Smrj 3370Sstevel@tonic-gate dp->sgd_type = type; 3380Sstevel@tonic-gate dp->sgd_dpl = dpl; 3390Sstevel@tonic-gate dp->sgd_p = 1; 3400Sstevel@tonic-gate } 3410Sstevel@tonic-gate 3420Sstevel@tonic-gate #elif defined(__i386) 3430Sstevel@tonic-gate 344*8679SSeth.Goldberg@Sun.COM /*ARGSUSED*/ 3450Sstevel@tonic-gate void 3460Sstevel@tonic-gate set_gatesegd(gate_desc_t *dp, void (*func)(void), selector_t sel, 347*8679SSeth.Goldberg@Sun.COM uint_t type, uint_t dpl, uint_t unused) 3480Sstevel@tonic-gate { 3490Sstevel@tonic-gate dp->sgd_looffset = (uintptr_t)func; 3500Sstevel@tonic-gate dp->sgd_hioffset = (uintptr_t)func >> 16; 3510Sstevel@tonic-gate 3520Sstevel@tonic-gate dp->sgd_selector = (uint16_t)sel; 3533446Smrj dp->sgd_stkcpy = 0; /* always zero bytes */ 3540Sstevel@tonic-gate dp->sgd_type = type; 3550Sstevel@tonic-gate dp->sgd_dpl = dpl; 3560Sstevel@tonic-gate dp->sgd_p = 1; 3570Sstevel@tonic-gate } 3580Sstevel@tonic-gate 3593446Smrj #endif /* __i386 */ 3603446Smrj 3615084Sjohnlev /* 3625084Sjohnlev * Updates a single user descriptor in the the GDT of the current cpu. 3635084Sjohnlev * Caller is responsible for preventing cpu migration. 3645084Sjohnlev */ 3655084Sjohnlev 3665084Sjohnlev void 3675084Sjohnlev gdt_update_usegd(uint_t sidx, user_desc_t *udp) 3685084Sjohnlev { 3695084Sjohnlev #if defined(__xpv) 3705084Sjohnlev 3715084Sjohnlev uint64_t dpa = CPU->cpu_m.mcpu_gdtpa + sizeof (*udp) * sidx; 3725084Sjohnlev 3735084Sjohnlev if (HYPERVISOR_update_descriptor(pa_to_ma(dpa), *(uint64_t *)udp)) 3745084Sjohnlev panic("gdt_update_usegd: HYPERVISOR_update_descriptor"); 3755084Sjohnlev 3765084Sjohnlev #else /* __xpv */ 3775084Sjohnlev 3785084Sjohnlev CPU->cpu_gdt[sidx] = *udp; 3795084Sjohnlev 3805084Sjohnlev #endif /* __xpv */ 3815084Sjohnlev } 3825084Sjohnlev 3835084Sjohnlev /* 3845084Sjohnlev * Writes single descriptor pointed to by udp into a processes 3855084Sjohnlev * LDT entry pointed to by ldp. 3865084Sjohnlev */ 3875084Sjohnlev int 3885084Sjohnlev ldt_update_segd(user_desc_t *ldp, user_desc_t *udp) 3895084Sjohnlev { 3905084Sjohnlev #if defined(__xpv) 3915084Sjohnlev 3925084Sjohnlev uint64_t dpa; 3935084Sjohnlev 3945084Sjohnlev dpa = mmu_ptob(hat_getpfnum(kas.a_hat, (caddr_t)ldp)) | 3955084Sjohnlev ((uintptr_t)ldp & PAGEOFFSET); 3965084Sjohnlev 3975084Sjohnlev /* 3985084Sjohnlev * The hypervisor is a little more restrictive about what it 3995084Sjohnlev * supports in the LDT. 4005084Sjohnlev */ 4015084Sjohnlev if (HYPERVISOR_update_descriptor(pa_to_ma(dpa), *(uint64_t *)udp) != 0) 4025084Sjohnlev return (EINVAL); 4035084Sjohnlev 4045084Sjohnlev #else /* __xpv */ 4055084Sjohnlev 4065084Sjohnlev *ldp = *udp; 4075084Sjohnlev 4085084Sjohnlev #endif /* __xpv */ 4095084Sjohnlev return (0); 4105084Sjohnlev } 4115084Sjohnlev 4125084Sjohnlev #if defined(__xpv) 4135084Sjohnlev 4145084Sjohnlev /* 4155084Sjohnlev * Converts hw format gate descriptor into pseudo-IDT format for the hypervisor. 4165084Sjohnlev * Returns true if a valid entry was written. 4175084Sjohnlev */ 4185084Sjohnlev int 4195084Sjohnlev xen_idt_to_trap_info(uint_t vec, gate_desc_t *sgd, void *ti_arg) 4205084Sjohnlev { 4215084Sjohnlev trap_info_t *ti = ti_arg; /* XXPV Aargh - segments.h comment */ 4225084Sjohnlev 4235084Sjohnlev /* 4245084Sjohnlev * skip holes in the IDT 4255084Sjohnlev */ 4265084Sjohnlev if (GATESEG_GETOFFSET(sgd) == 0) 4275084Sjohnlev return (0); 4285084Sjohnlev 4295084Sjohnlev ASSERT(sgd->sgd_type == SDT_SYSIGT); 4305084Sjohnlev ti->vector = vec; 4315084Sjohnlev TI_SET_DPL(ti, sgd->sgd_dpl); 4325084Sjohnlev 4335084Sjohnlev /* 4345084Sjohnlev * Is this an interrupt gate? 4355084Sjohnlev */ 4365084Sjohnlev if (sgd->sgd_type == SDT_SYSIGT) { 4375084Sjohnlev /* LINTED */ 4385084Sjohnlev TI_SET_IF(ti, 1); 4395084Sjohnlev } 4405084Sjohnlev ti->cs = sgd->sgd_selector; 4415084Sjohnlev #if defined(__amd64) 4425084Sjohnlev ti->cs |= SEL_KPL; /* force into ring 3. see KCS_SEL */ 4435084Sjohnlev #endif 4445084Sjohnlev ti->address = GATESEG_GETOFFSET(sgd); 4455084Sjohnlev return (1); 4465084Sjohnlev } 4475084Sjohnlev 4485084Sjohnlev /* 4495084Sjohnlev * Convert a single hw format gate descriptor and write it into our virtual IDT. 4505084Sjohnlev */ 4515084Sjohnlev void 4525084Sjohnlev xen_idt_write(gate_desc_t *sgd, uint_t vec) 4535084Sjohnlev { 4545084Sjohnlev trap_info_t trapinfo[2]; 4555084Sjohnlev 4565084Sjohnlev bzero(trapinfo, sizeof (trapinfo)); 4575084Sjohnlev if (xen_idt_to_trap_info(vec, sgd, &trapinfo[0]) == 0) 4585084Sjohnlev return; 4595084Sjohnlev if (xen_set_trap_table(trapinfo) != 0) 4605084Sjohnlev panic("xen_idt_write: xen_set_trap_table() failed"); 4615084Sjohnlev } 4625084Sjohnlev 4635084Sjohnlev #endif /* __xpv */ 4645084Sjohnlev 4653446Smrj #if defined(__amd64) 4660Sstevel@tonic-gate 4670Sstevel@tonic-gate /* 4680Sstevel@tonic-gate * Build kernel GDT. 4690Sstevel@tonic-gate */ 4700Sstevel@tonic-gate 4710Sstevel@tonic-gate static void 4723446Smrj init_gdt_common(user_desc_t *gdt) 4730Sstevel@tonic-gate { 4743446Smrj int i; 4750Sstevel@tonic-gate 4760Sstevel@tonic-gate /* 4770Sstevel@tonic-gate * 64-bit kernel code segment. 4780Sstevel@tonic-gate */ 4793446Smrj set_usegd(&gdt[GDT_KCODE], SDP_LONG, NULL, 0, SDT_MEMERA, SEL_KPL, 4800Sstevel@tonic-gate SDP_PAGES, SDP_OP32); 4810Sstevel@tonic-gate 4820Sstevel@tonic-gate /* 4830Sstevel@tonic-gate * 64-bit kernel data segment. The limit attribute is ignored in 64-bit 4840Sstevel@tonic-gate * mode, but we set it here to 0xFFFF so that we can use the SYSRET 4850Sstevel@tonic-gate * instruction to return from system calls back to 32-bit applications. 4860Sstevel@tonic-gate * SYSRET doesn't update the base, limit, or attributes of %ss or %ds 4870Sstevel@tonic-gate * descriptors. We therefore must ensure that the kernel uses something, 4880Sstevel@tonic-gate * though it will be ignored by hardware, that is compatible with 32-bit 4890Sstevel@tonic-gate * apps. For the same reason we must set the default op size of this 4900Sstevel@tonic-gate * descriptor to 32-bit operands. 4910Sstevel@tonic-gate */ 4923446Smrj set_usegd(&gdt[GDT_KDATA], SDP_LONG, NULL, -1, SDT_MEMRWA, 4930Sstevel@tonic-gate SEL_KPL, SDP_PAGES, SDP_OP32); 4943446Smrj gdt[GDT_KDATA].usd_def32 = 1; 4950Sstevel@tonic-gate 4960Sstevel@tonic-gate /* 4970Sstevel@tonic-gate * 64-bit user code segment. 4980Sstevel@tonic-gate */ 4993446Smrj set_usegd(&gdt[GDT_UCODE], SDP_LONG, NULL, 0, SDT_MEMERA, SEL_UPL, 5000Sstevel@tonic-gate SDP_PAGES, SDP_OP32); 5010Sstevel@tonic-gate 5020Sstevel@tonic-gate /* 5030Sstevel@tonic-gate * 32-bit user code segment. 5040Sstevel@tonic-gate */ 5053446Smrj set_usegd(&gdt[GDT_U32CODE], SDP_SHORT, NULL, -1, SDT_MEMERA, 5060Sstevel@tonic-gate SEL_UPL, SDP_PAGES, SDP_OP32); 5070Sstevel@tonic-gate 5080Sstevel@tonic-gate /* 5095084Sjohnlev * See gdt_ucode32() and gdt_ucode_native(). 5105084Sjohnlev */ 5115084Sjohnlev ucs_on = ucs_off = gdt[GDT_UCODE]; 5125084Sjohnlev ucs_off.usd_p = 0; /* forces #np fault */ 5135084Sjohnlev 5145084Sjohnlev ucs32_on = ucs32_off = gdt[GDT_U32CODE]; 5155084Sjohnlev ucs32_off.usd_p = 0; /* forces #np fault */ 5165084Sjohnlev 5175084Sjohnlev /* 5180Sstevel@tonic-gate * 32 and 64 bit data segments can actually share the same descriptor. 5190Sstevel@tonic-gate * In long mode only the present bit is checked but all other fields 5200Sstevel@tonic-gate * are loaded. But in compatibility mode all fields are interpreted 5210Sstevel@tonic-gate * as in legacy mode so they must be set correctly for a 32-bit data 5220Sstevel@tonic-gate * segment. 5230Sstevel@tonic-gate */ 5243446Smrj set_usegd(&gdt[GDT_UDATA], SDP_SHORT, NULL, -1, SDT_MEMRWA, SEL_UPL, 5250Sstevel@tonic-gate SDP_PAGES, SDP_OP32); 5260Sstevel@tonic-gate 5275084Sjohnlev #if !defined(__xpv) 5285084Sjohnlev 5290Sstevel@tonic-gate /* 5301217Srab * The 64-bit kernel has no default LDT. By default, the LDT descriptor 5311217Srab * in the GDT is 0. 5320Sstevel@tonic-gate */ 5330Sstevel@tonic-gate 5340Sstevel@tonic-gate /* 5350Sstevel@tonic-gate * Kernel TSS 5360Sstevel@tonic-gate */ 5375460Sjosephb set_syssegd((system_desc_t *)&gdt[GDT_KTSS], ktss0, 5385460Sjosephb sizeof (*ktss0) - 1, SDT_SYSTSS, SEL_KPL); 5390Sstevel@tonic-gate 5405084Sjohnlev #endif /* !__xpv */ 5415084Sjohnlev 5420Sstevel@tonic-gate /* 5430Sstevel@tonic-gate * Initialize fs and gs descriptors for 32 bit processes. 5440Sstevel@tonic-gate * Only attributes and limits are initialized, the effective 5450Sstevel@tonic-gate * base address is programmed via fsbase/gsbase. 5460Sstevel@tonic-gate */ 5473446Smrj set_usegd(&gdt[GDT_LWPFS], SDP_SHORT, NULL, -1, SDT_MEMRWA, 5480Sstevel@tonic-gate SEL_UPL, SDP_PAGES, SDP_OP32); 5493446Smrj set_usegd(&gdt[GDT_LWPGS], SDP_SHORT, NULL, -1, SDT_MEMRWA, 5500Sstevel@tonic-gate SEL_UPL, SDP_PAGES, SDP_OP32); 5510Sstevel@tonic-gate 5520Sstevel@tonic-gate /* 5532712Snn35248 * Initialize the descriptors set aside for brand usage. 5542712Snn35248 * Only attributes and limits are initialized. 5552712Snn35248 */ 5562712Snn35248 for (i = GDT_BRANDMIN; i <= GDT_BRANDMAX; i++) 5573446Smrj set_usegd(&gdt0[i], SDP_SHORT, NULL, -1, SDT_MEMRWA, 5582712Snn35248 SEL_UPL, SDP_PAGES, SDP_OP32); 5592712Snn35248 5602712Snn35248 /* 5610Sstevel@tonic-gate * Initialize convenient zero base user descriptors for clearing 5620Sstevel@tonic-gate * lwp private %fs and %gs descriptors in GDT. See setregs() for 5630Sstevel@tonic-gate * an example. 5640Sstevel@tonic-gate */ 5650Sstevel@tonic-gate set_usegd(&zero_udesc, SDP_LONG, 0, 0, SDT_MEMRWA, SEL_UPL, 5660Sstevel@tonic-gate SDP_BYTES, SDP_OP32); 5670Sstevel@tonic-gate set_usegd(&zero_u32desc, SDP_SHORT, 0, -1, SDT_MEMRWA, SEL_UPL, 5680Sstevel@tonic-gate SDP_PAGES, SDP_OP32); 5690Sstevel@tonic-gate } 5700Sstevel@tonic-gate 5715084Sjohnlev #if defined(__xpv) 5725084Sjohnlev 5735084Sjohnlev static user_desc_t * 5745084Sjohnlev init_gdt(void) 5755084Sjohnlev { 5765084Sjohnlev uint64_t gdtpa; 5775084Sjohnlev ulong_t ma[1]; /* XXPV should be a memory_t */ 5785084Sjohnlev ulong_t addr; 5795084Sjohnlev 5805084Sjohnlev #if !defined(__lint) 5815084Sjohnlev /* 5825084Sjohnlev * Our gdt is never larger than a single page. 5835084Sjohnlev */ 5845084Sjohnlev ASSERT((sizeof (*gdt0) * NGDT) <= PAGESIZE); 5855084Sjohnlev #endif 5865084Sjohnlev gdt0 = (user_desc_t *)BOP_ALLOC(bootops, (caddr_t)GDT_VA, 5875084Sjohnlev PAGESIZE, PAGESIZE); 5885084Sjohnlev bzero(gdt0, PAGESIZE); 5895084Sjohnlev 5905084Sjohnlev init_gdt_common(gdt0); 5915084Sjohnlev 5925084Sjohnlev /* 5935084Sjohnlev * XXX Since we never invoke kmdb until after the kernel takes 5945084Sjohnlev * over the descriptor tables why not have it use the kernel's 5955084Sjohnlev * selectors? 5965084Sjohnlev */ 5975084Sjohnlev if (boothowto & RB_DEBUG) { 5985084Sjohnlev set_usegd(&gdt0[GDT_B32DATA], SDP_LONG, NULL, -1, SDT_MEMRWA, 5995084Sjohnlev SEL_KPL, SDP_PAGES, SDP_OP32); 6005084Sjohnlev set_usegd(&gdt0[GDT_B64CODE], SDP_LONG, NULL, -1, SDT_MEMERA, 6015084Sjohnlev SEL_KPL, SDP_PAGES, SDP_OP32); 6025084Sjohnlev } 6035084Sjohnlev 6045084Sjohnlev /* 6055084Sjohnlev * Clear write permission for page containing the gdt and install it. 6065084Sjohnlev */ 6075084Sjohnlev gdtpa = pfn_to_pa(va_to_pfn(gdt0)); 6085084Sjohnlev ma[0] = (ulong_t)(pa_to_ma(gdtpa) >> PAGESHIFT); 6095084Sjohnlev kbm_read_only((uintptr_t)gdt0, gdtpa); 6105084Sjohnlev xen_set_gdt(ma, NGDT); 6115084Sjohnlev 6125084Sjohnlev /* 6135084Sjohnlev * Reload the segment registers to use the new GDT. 6145084Sjohnlev * On 64-bit, fixup KCS_SEL to be in ring 3. 6155084Sjohnlev * See KCS_SEL in segments.h. 6165084Sjohnlev */ 6175084Sjohnlev load_segment_registers((KCS_SEL | SEL_KPL), KFS_SEL, KGS_SEL, KDS_SEL); 6185084Sjohnlev 6195084Sjohnlev /* 6205084Sjohnlev * setup %gs for kernel 6215084Sjohnlev */ 6225084Sjohnlev xen_set_segment_base(SEGBASE_GS_KERNEL, (ulong_t)&cpus[0]); 6235084Sjohnlev 6245084Sjohnlev /* 6255084Sjohnlev * XX64 We should never dereference off "other gsbase" or 6265084Sjohnlev * "fsbase". So, we should arrange to point FSBASE and 6275084Sjohnlev * KGSBASE somewhere truly awful e.g. point it at the last 6285084Sjohnlev * valid address below the hole so that any attempts to index 6295084Sjohnlev * off them cause an exception. 6305084Sjohnlev * 6315084Sjohnlev * For now, point it at 8G -- at least it should be unmapped 6325084Sjohnlev * until some 64-bit processes run. 6335084Sjohnlev */ 6345084Sjohnlev addr = 0x200000000ul; 6355084Sjohnlev xen_set_segment_base(SEGBASE_FS, addr); 6365084Sjohnlev xen_set_segment_base(SEGBASE_GS_USER, addr); 6375084Sjohnlev xen_set_segment_base(SEGBASE_GS_USER_SEL, 0); 6385084Sjohnlev 6395084Sjohnlev return (gdt0); 6405084Sjohnlev } 6415084Sjohnlev 6425084Sjohnlev #else /* __xpv */ 6435084Sjohnlev 6443446Smrj static user_desc_t * 6450Sstevel@tonic-gate init_gdt(void) 6460Sstevel@tonic-gate { 6470Sstevel@tonic-gate desctbr_t r_bgdt, r_gdt; 6480Sstevel@tonic-gate user_desc_t *bgdt; 6493446Smrj 6503446Smrj #if !defined(__lint) 6513446Smrj /* 6523446Smrj * Our gdt is never larger than a single page. 6533446Smrj */ 6543446Smrj ASSERT((sizeof (*gdt0) * NGDT) <= PAGESIZE); 6553446Smrj #endif 6563446Smrj gdt0 = (user_desc_t *)BOP_ALLOC(bootops, (caddr_t)GDT_VA, 6573446Smrj PAGESIZE, PAGESIZE); 6583446Smrj bzero(gdt0, PAGESIZE); 6593446Smrj 6603446Smrj init_gdt_common(gdt0); 6610Sstevel@tonic-gate 6620Sstevel@tonic-gate /* 6633446Smrj * Copy in from boot's gdt to our gdt. 6643446Smrj * Entry 0 is the null descriptor by definition. 6650Sstevel@tonic-gate */ 6660Sstevel@tonic-gate rd_gdtr(&r_bgdt); 6670Sstevel@tonic-gate bgdt = (user_desc_t *)r_bgdt.dtr_base; 6680Sstevel@tonic-gate if (bgdt == NULL) 6690Sstevel@tonic-gate panic("null boot gdt"); 6700Sstevel@tonic-gate 6713446Smrj gdt0[GDT_B32DATA] = bgdt[GDT_B32DATA]; 6723446Smrj gdt0[GDT_B32CODE] = bgdt[GDT_B32CODE]; 6733446Smrj gdt0[GDT_B16CODE] = bgdt[GDT_B16CODE]; 6743446Smrj gdt0[GDT_B16DATA] = bgdt[GDT_B16DATA]; 6753446Smrj gdt0[GDT_B64CODE] = bgdt[GDT_B64CODE]; 6763446Smrj 6773446Smrj /* 6783446Smrj * Install our new GDT 6793446Smrj */ 6803446Smrj r_gdt.dtr_limit = (sizeof (*gdt0) * NGDT) - 1; 6813446Smrj r_gdt.dtr_base = (uintptr_t)gdt0; 6823446Smrj wr_gdtr(&r_gdt); 6833446Smrj 6843446Smrj /* 6853446Smrj * Reload the segment registers to use the new GDT 6863446Smrj */ 6873446Smrj load_segment_registers(KCS_SEL, KFS_SEL, KGS_SEL, KDS_SEL); 6883446Smrj 6893446Smrj /* 6903446Smrj * setup %gs for kernel 6913446Smrj */ 6923446Smrj wrmsr(MSR_AMD_GSBASE, (uint64_t)&cpus[0]); 6933446Smrj 6943446Smrj /* 6953446Smrj * XX64 We should never dereference off "other gsbase" or 6963446Smrj * "fsbase". So, we should arrange to point FSBASE and 6973446Smrj * KGSBASE somewhere truly awful e.g. point it at the last 6983446Smrj * valid address below the hole so that any attempts to index 6993446Smrj * off them cause an exception. 7003446Smrj * 7013446Smrj * For now, point it at 8G -- at least it should be unmapped 7023446Smrj * until some 64-bit processes run. 7033446Smrj */ 7043446Smrj wrmsr(MSR_AMD_FSBASE, 0x200000000ul); 7053446Smrj wrmsr(MSR_AMD_KGSBASE, 0x200000000ul); 7063446Smrj return (gdt0); 7073446Smrj } 7083446Smrj 7095084Sjohnlev #endif /* __xpv */ 7105084Sjohnlev 7113446Smrj #elif defined(__i386) 7123446Smrj 7133446Smrj static void 7143446Smrj init_gdt_common(user_desc_t *gdt) 7153446Smrj { 7163446Smrj int i; 7170Sstevel@tonic-gate 7180Sstevel@tonic-gate /* 7190Sstevel@tonic-gate * Text and data for both kernel and user span entire 32 bit 7200Sstevel@tonic-gate * address space. 7210Sstevel@tonic-gate */ 7220Sstevel@tonic-gate 7230Sstevel@tonic-gate /* 7240Sstevel@tonic-gate * kernel code segment. 7250Sstevel@tonic-gate */ 7263446Smrj set_usegd(&gdt[GDT_KCODE], NULL, -1, SDT_MEMERA, SEL_KPL, SDP_PAGES, 7270Sstevel@tonic-gate SDP_OP32); 7280Sstevel@tonic-gate 7290Sstevel@tonic-gate /* 7300Sstevel@tonic-gate * kernel data segment. 7310Sstevel@tonic-gate */ 7323446Smrj set_usegd(&gdt[GDT_KDATA], NULL, -1, SDT_MEMRWA, SEL_KPL, SDP_PAGES, 7330Sstevel@tonic-gate SDP_OP32); 7340Sstevel@tonic-gate 7350Sstevel@tonic-gate /* 7360Sstevel@tonic-gate * user code segment. 7370Sstevel@tonic-gate */ 7383446Smrj set_usegd(&gdt[GDT_UCODE], NULL, -1, SDT_MEMERA, SEL_UPL, SDP_PAGES, 7390Sstevel@tonic-gate SDP_OP32); 7400Sstevel@tonic-gate 7410Sstevel@tonic-gate /* 7420Sstevel@tonic-gate * user data segment. 7430Sstevel@tonic-gate */ 7443446Smrj set_usegd(&gdt[GDT_UDATA], NULL, -1, SDT_MEMRWA, SEL_UPL, SDP_PAGES, 7450Sstevel@tonic-gate SDP_OP32); 7460Sstevel@tonic-gate 7475084Sjohnlev #if !defined(__xpv) 7485084Sjohnlev 7490Sstevel@tonic-gate /* 7500Sstevel@tonic-gate * TSS for T_DBLFLT (double fault) handler 7510Sstevel@tonic-gate */ 7525460Sjosephb set_syssegd((system_desc_t *)&gdt[GDT_DBFLT], dftss0, 7535460Sjosephb sizeof (*dftss0) - 1, SDT_SYSTSS, SEL_KPL); 7540Sstevel@tonic-gate 7550Sstevel@tonic-gate /* 7560Sstevel@tonic-gate * TSS for kernel 7570Sstevel@tonic-gate */ 7585460Sjosephb set_syssegd((system_desc_t *)&gdt[GDT_KTSS], ktss0, 7595460Sjosephb sizeof (*ktss0) - 1, SDT_SYSTSS, SEL_KPL); 7600Sstevel@tonic-gate 7615084Sjohnlev #endif /* !__xpv */ 7625084Sjohnlev 7630Sstevel@tonic-gate /* 7640Sstevel@tonic-gate * %gs selector for kernel 7650Sstevel@tonic-gate */ 7663446Smrj set_usegd(&gdt[GDT_GS], &cpus[0], sizeof (struct cpu) -1, SDT_MEMRWA, 7670Sstevel@tonic-gate SEL_KPL, SDP_BYTES, SDP_OP32); 7680Sstevel@tonic-gate 7690Sstevel@tonic-gate /* 7700Sstevel@tonic-gate * Initialize lwp private descriptors. 7710Sstevel@tonic-gate * Only attributes and limits are initialized, the effective 7720Sstevel@tonic-gate * base address is programmed via fsbase/gsbase. 7730Sstevel@tonic-gate */ 7743446Smrj set_usegd(&gdt[GDT_LWPFS], NULL, (size_t)-1, SDT_MEMRWA, SEL_UPL, 7750Sstevel@tonic-gate SDP_PAGES, SDP_OP32); 7763446Smrj set_usegd(&gdt[GDT_LWPGS], NULL, (size_t)-1, SDT_MEMRWA, SEL_UPL, 7770Sstevel@tonic-gate SDP_PAGES, SDP_OP32); 7780Sstevel@tonic-gate 7790Sstevel@tonic-gate /* 7802712Snn35248 * Initialize the descriptors set aside for brand usage. 7812712Snn35248 * Only attributes and limits are initialized. 7822712Snn35248 */ 7832712Snn35248 for (i = GDT_BRANDMIN; i <= GDT_BRANDMAX; i++) 7842712Snn35248 set_usegd(&gdt0[i], NULL, (size_t)-1, SDT_MEMRWA, SEL_UPL, 7852712Snn35248 SDP_PAGES, SDP_OP32); 7863446Smrj /* 7873446Smrj * Initialize convenient zero base user descriptor for clearing 7883446Smrj * lwp private %fs and %gs descriptors in GDT. See setregs() for 7893446Smrj * an example. 7903446Smrj */ 7913446Smrj set_usegd(&zero_udesc, NULL, -1, SDT_MEMRWA, SEL_UPL, 7923446Smrj SDP_BYTES, SDP_OP32); 7933446Smrj } 7943446Smrj 7955084Sjohnlev #if defined(__xpv) 7965084Sjohnlev 7975084Sjohnlev static user_desc_t * 7985084Sjohnlev init_gdt(void) 7995084Sjohnlev { 8005084Sjohnlev uint64_t gdtpa; 8015084Sjohnlev ulong_t ma[1]; /* XXPV should be a memory_t */ 8025084Sjohnlev 8035084Sjohnlev #if !defined(__lint) 8045084Sjohnlev /* 8055084Sjohnlev * Our gdt is never larger than a single page. 8065084Sjohnlev */ 8075084Sjohnlev ASSERT((sizeof (*gdt0) * NGDT) <= PAGESIZE); 8085084Sjohnlev #endif 8095084Sjohnlev gdt0 = (user_desc_t *)BOP_ALLOC(bootops, (caddr_t)GDT_VA, 8105084Sjohnlev PAGESIZE, PAGESIZE); 8115084Sjohnlev bzero(gdt0, PAGESIZE); 8125084Sjohnlev 8135084Sjohnlev init_gdt_common(gdt0); 8145084Sjohnlev gdtpa = pfn_to_pa(va_to_pfn(gdt0)); 8155084Sjohnlev 8165084Sjohnlev /* 8175084Sjohnlev * XXX Since we never invoke kmdb until after the kernel takes 8185084Sjohnlev * over the descriptor tables why not have it use the kernel's 8195084Sjohnlev * selectors? 8205084Sjohnlev */ 8215084Sjohnlev if (boothowto & RB_DEBUG) { 8225084Sjohnlev set_usegd(&gdt0[GDT_B32DATA], NULL, -1, SDT_MEMRWA, SEL_KPL, 8235084Sjohnlev SDP_PAGES, SDP_OP32); 8245084Sjohnlev set_usegd(&gdt0[GDT_B32CODE], NULL, -1, SDT_MEMERA, SEL_KPL, 8255084Sjohnlev SDP_PAGES, SDP_OP32); 8265084Sjohnlev } 8275084Sjohnlev 8285084Sjohnlev /* 8295084Sjohnlev * Clear write permission for page containing the gdt and install it. 8305084Sjohnlev */ 8315084Sjohnlev ma[0] = (ulong_t)(pa_to_ma(gdtpa) >> PAGESHIFT); 8325084Sjohnlev kbm_read_only((uintptr_t)gdt0, gdtpa); 8335084Sjohnlev xen_set_gdt(ma, NGDT); 8345084Sjohnlev 8355084Sjohnlev /* 8365084Sjohnlev * Reload the segment registers to use the new GDT 8375084Sjohnlev */ 8385084Sjohnlev load_segment_registers( 8395084Sjohnlev KCS_SEL, KDS_SEL, KDS_SEL, KFS_SEL, KGS_SEL, KDS_SEL); 8405084Sjohnlev 8415084Sjohnlev return (gdt0); 8425084Sjohnlev } 8435084Sjohnlev 8445084Sjohnlev #else /* __xpv */ 8455084Sjohnlev 8463446Smrj static user_desc_t * 8473446Smrj init_gdt(void) 8483446Smrj { 8493446Smrj desctbr_t r_bgdt, r_gdt; 8503446Smrj user_desc_t *bgdt; 8513446Smrj 8523446Smrj #if !defined(__lint) 8533446Smrj /* 8543446Smrj * Our gdt is never larger than a single page. 8553446Smrj */ 8563446Smrj ASSERT((sizeof (*gdt0) * NGDT) <= PAGESIZE); 8573446Smrj #endif 8583446Smrj /* 8593446Smrj * XXX this allocation belongs in our caller, not here. 8603446Smrj */ 8613446Smrj gdt0 = (user_desc_t *)BOP_ALLOC(bootops, (caddr_t)GDT_VA, 8623446Smrj PAGESIZE, PAGESIZE); 8633446Smrj bzero(gdt0, PAGESIZE); 8643446Smrj 8653446Smrj init_gdt_common(gdt0); 8663446Smrj 8673446Smrj /* 8683446Smrj * Copy in from boot's gdt to our gdt entries. 8693446Smrj * Entry 0 is null descriptor by definition. 8703446Smrj */ 8713446Smrj rd_gdtr(&r_bgdt); 8723446Smrj bgdt = (user_desc_t *)r_bgdt.dtr_base; 8733446Smrj if (bgdt == NULL) 8743446Smrj panic("null boot gdt"); 8753446Smrj 8763446Smrj gdt0[GDT_B32DATA] = bgdt[GDT_B32DATA]; 8773446Smrj gdt0[GDT_B32CODE] = bgdt[GDT_B32CODE]; 8783446Smrj gdt0[GDT_B16CODE] = bgdt[GDT_B16CODE]; 8793446Smrj gdt0[GDT_B16DATA] = bgdt[GDT_B16DATA]; 8802712Snn35248 8812712Snn35248 /* 8820Sstevel@tonic-gate * Install our new GDT 8830Sstevel@tonic-gate */ 8843446Smrj r_gdt.dtr_limit = (sizeof (*gdt0) * NGDT) - 1; 8850Sstevel@tonic-gate r_gdt.dtr_base = (uintptr_t)gdt0; 8860Sstevel@tonic-gate wr_gdtr(&r_gdt); 8870Sstevel@tonic-gate 8880Sstevel@tonic-gate /* 8893446Smrj * Reload the segment registers to use the new GDT 8900Sstevel@tonic-gate */ 8913446Smrj load_segment_registers( 8923446Smrj KCS_SEL, KDS_SEL, KDS_SEL, KFS_SEL, KGS_SEL, KDS_SEL); 8933446Smrj 8943446Smrj return (gdt0); 8950Sstevel@tonic-gate } 8960Sstevel@tonic-gate 8975084Sjohnlev #endif /* __xpv */ 8980Sstevel@tonic-gate #endif /* __i386 */ 8990Sstevel@tonic-gate 9000Sstevel@tonic-gate /* 9010Sstevel@tonic-gate * Build kernel IDT. 9020Sstevel@tonic-gate * 9033446Smrj * Note that for amd64 we pretty much require every gate to be an interrupt 9043446Smrj * gate which blocks interrupts atomically on entry; that's because of our 9053446Smrj * dependency on using 'swapgs' every time we come into the kernel to find 9063446Smrj * the cpu structure. If we get interrupted just before doing that, %cs could 9073446Smrj * be in kernel mode (so that the trap prolog doesn't do a swapgs), but 9083446Smrj * %gsbase is really still pointing at something in userland. Bad things will 9093446Smrj * ensue. We also use interrupt gates for i386 as well even though this is not 9103446Smrj * required for some traps. 9110Sstevel@tonic-gate * 9120Sstevel@tonic-gate * Perhaps they should have invented a trap gate that does an atomic swapgs? 9130Sstevel@tonic-gate */ 9140Sstevel@tonic-gate static void 9153446Smrj init_idt_common(gate_desc_t *idt) 9163446Smrj { 917*8679SSeth.Goldberg@Sun.COM set_gatesegd(&idt[T_ZERODIV], &div0trap, KCS_SEL, SDT_SYSIGT, TRP_KPL, 918*8679SSeth.Goldberg@Sun.COM 0); 919*8679SSeth.Goldberg@Sun.COM set_gatesegd(&idt[T_SGLSTP], &dbgtrap, KCS_SEL, SDT_SYSIGT, TRP_KPL, 920*8679SSeth.Goldberg@Sun.COM 0); 921*8679SSeth.Goldberg@Sun.COM set_gatesegd(&idt[T_NMIFLT], &nmiint, KCS_SEL, SDT_SYSIGT, TRP_KPL, 922*8679SSeth.Goldberg@Sun.COM 0); 923*8679SSeth.Goldberg@Sun.COM set_gatesegd(&idt[T_BPTFLT], &brktrap, KCS_SEL, SDT_SYSIGT, TRP_UPL, 924*8679SSeth.Goldberg@Sun.COM 0); 925*8679SSeth.Goldberg@Sun.COM set_gatesegd(&idt[T_OVFLW], &ovflotrap, KCS_SEL, SDT_SYSIGT, TRP_UPL, 926*8679SSeth.Goldberg@Sun.COM 0); 9273446Smrj set_gatesegd(&idt[T_BOUNDFLT], &boundstrap, KCS_SEL, SDT_SYSIGT, 928*8679SSeth.Goldberg@Sun.COM TRP_KPL, 0); 929*8679SSeth.Goldberg@Sun.COM set_gatesegd(&idt[T_ILLINST], &invoptrap, KCS_SEL, SDT_SYSIGT, TRP_KPL, 930*8679SSeth.Goldberg@Sun.COM 0); 931*8679SSeth.Goldberg@Sun.COM set_gatesegd(&idt[T_NOEXTFLT], &ndptrap, KCS_SEL, SDT_SYSIGT, TRP_KPL, 932*8679SSeth.Goldberg@Sun.COM 0); 9333446Smrj 9343446Smrj /* 9353446Smrj * double fault handler. 9365084Sjohnlev * 9375084Sjohnlev * Note that on the hypervisor a guest does not receive #df faults. 9385084Sjohnlev * Instead a failsafe event is injected into the guest if its selectors 9395084Sjohnlev * and/or stack is in a broken state. See xen_failsafe_callback. 9403446Smrj */ 9415084Sjohnlev #if !defined(__xpv) 9423446Smrj #if defined(__amd64) 9435084Sjohnlev 944*8679SSeth.Goldberg@Sun.COM set_gatesegd(&idt[T_DBLFLT], &syserrtrap, KCS_SEL, SDT_SYSIGT, TRP_KPL, 945*8679SSeth.Goldberg@Sun.COM T_DBLFLT); 9465084Sjohnlev 9473446Smrj #elif defined(__i386) 9485084Sjohnlev 9493446Smrj /* 9503446Smrj * task gate required. 9513446Smrj */ 952*8679SSeth.Goldberg@Sun.COM set_gatesegd(&idt[T_DBLFLT], NULL, DFTSS_SEL, SDT_SYSTASKGT, TRP_KPL, 953*8679SSeth.Goldberg@Sun.COM 0); 9543446Smrj 9553446Smrj #endif /* __i386 */ 9565084Sjohnlev #endif /* !__xpv */ 9573446Smrj 9583446Smrj /* 9593446Smrj * T_EXTOVRFLT coprocessor-segment-overrun not supported. 9603446Smrj */ 9613446Smrj 962*8679SSeth.Goldberg@Sun.COM set_gatesegd(&idt[T_TSSFLT], &invtsstrap, KCS_SEL, SDT_SYSIGT, TRP_KPL, 963*8679SSeth.Goldberg@Sun.COM 0); 964*8679SSeth.Goldberg@Sun.COM set_gatesegd(&idt[T_SEGFLT], &segnptrap, KCS_SEL, SDT_SYSIGT, TRP_KPL, 965*8679SSeth.Goldberg@Sun.COM 0); 966*8679SSeth.Goldberg@Sun.COM set_gatesegd(&idt[T_STKFLT], &stktrap, KCS_SEL, SDT_SYSIGT, TRP_KPL, 0); 967*8679SSeth.Goldberg@Sun.COM set_gatesegd(&idt[T_GPFLT], &gptrap, KCS_SEL, SDT_SYSIGT, TRP_KPL, 0); 968*8679SSeth.Goldberg@Sun.COM set_gatesegd(&idt[T_PGFLT], &pftrap, KCS_SEL, SDT_SYSIGT, TRP_KPL, 0); 969*8679SSeth.Goldberg@Sun.COM set_gatesegd(&idt[T_EXTERRFLT], &ndperr, KCS_SEL, SDT_SYSIGT, TRP_KPL, 970*8679SSeth.Goldberg@Sun.COM 0); 9713446Smrj set_gatesegd(&idt[T_ALIGNMENT], &achktrap, KCS_SEL, SDT_SYSIGT, 972*8679SSeth.Goldberg@Sun.COM TRP_KPL, 0); 973*8679SSeth.Goldberg@Sun.COM set_gatesegd(&idt[T_MCE], &mcetrap, KCS_SEL, SDT_SYSIGT, TRP_KPL, 0); 974*8679SSeth.Goldberg@Sun.COM set_gatesegd(&idt[T_SIMDFPE], &xmtrap, KCS_SEL, SDT_SYSIGT, TRP_KPL, 0); 9753446Smrj 9763446Smrj /* 9773446Smrj * install "int80" handler at, well, 0x80. 9783446Smrj */ 979*8679SSeth.Goldberg@Sun.COM set_gatesegd(&idt0[T_INT80], &sys_int80, KCS_SEL, SDT_SYSIGT, TRP_UPL, 980*8679SSeth.Goldberg@Sun.COM 0); 9813446Smrj 9823446Smrj /* 9833446Smrj * install fast trap handler at 210. 9843446Smrj */ 985*8679SSeth.Goldberg@Sun.COM set_gatesegd(&idt[T_FASTTRAP], &fasttrap, KCS_SEL, SDT_SYSIGT, TRP_UPL, 986*8679SSeth.Goldberg@Sun.COM 0); 9873446Smrj 9883446Smrj /* 9893446Smrj * System call handler. 9903446Smrj */ 9913446Smrj #if defined(__amd64) 9923446Smrj set_gatesegd(&idt[T_SYSCALLINT], &sys_syscall_int, KCS_SEL, SDT_SYSIGT, 993*8679SSeth.Goldberg@Sun.COM TRP_UPL, 0); 9943446Smrj 9953446Smrj #elif defined(__i386) 9963446Smrj set_gatesegd(&idt[T_SYSCALLINT], &sys_call, KCS_SEL, SDT_SYSIGT, 997*8679SSeth.Goldberg@Sun.COM TRP_UPL, 0); 9983446Smrj #endif /* __i386 */ 9993446Smrj 10003446Smrj /* 10013446Smrj * Install the DTrace interrupt handler for the pid provider. 10023446Smrj */ 10033446Smrj set_gatesegd(&idt[T_DTRACE_RET], &dtrace_ret, KCS_SEL, 1004*8679SSeth.Goldberg@Sun.COM SDT_SYSIGT, TRP_UPL, 0); 10053446Smrj 10063446Smrj /* 10073446Smrj * Prepare interposing descriptors for the branded "int80" 10083446Smrj * and syscall handlers and cache copies of the default 10093446Smrj * descriptors. 10103446Smrj */ 10113446Smrj brand_tbl[0].ih_inum = T_INT80; 10123446Smrj brand_tbl[0].ih_default_desc = idt0[T_INT80]; 10133446Smrj set_gatesegd(&(brand_tbl[0].ih_interp_desc), &brand_sys_int80, KCS_SEL, 1014*8679SSeth.Goldberg@Sun.COM SDT_SYSIGT, TRP_UPL, 0); 10153446Smrj 10163446Smrj brand_tbl[1].ih_inum = T_SYSCALLINT; 10173446Smrj brand_tbl[1].ih_default_desc = idt0[T_SYSCALLINT]; 10183446Smrj 10193446Smrj #if defined(__amd64) 10203446Smrj set_gatesegd(&(brand_tbl[1].ih_interp_desc), &brand_sys_syscall_int, 1021*8679SSeth.Goldberg@Sun.COM KCS_SEL, SDT_SYSIGT, TRP_UPL, 0); 10223446Smrj #elif defined(__i386) 10233446Smrj set_gatesegd(&(brand_tbl[1].ih_interp_desc), &brand_sys_call, 1024*8679SSeth.Goldberg@Sun.COM KCS_SEL, SDT_SYSIGT, TRP_UPL, 0); 10253446Smrj #endif /* __i386 */ 10263446Smrj 10273446Smrj brand_tbl[2].ih_inum = 0; 10283446Smrj } 10293446Smrj 10305084Sjohnlev #if defined(__xpv) 10315084Sjohnlev 10325084Sjohnlev static void 10335084Sjohnlev init_idt(gate_desc_t *idt) 10345084Sjohnlev { 10355084Sjohnlev init_idt_common(idt); 10365084Sjohnlev } 10375084Sjohnlev 10385084Sjohnlev #else /* __xpv */ 10395084Sjohnlev 10403446Smrj static void 10413446Smrj init_idt(gate_desc_t *idt) 10420Sstevel@tonic-gate { 10430Sstevel@tonic-gate char ivctname[80]; 10440Sstevel@tonic-gate void (*ivctptr)(void); 10450Sstevel@tonic-gate int i; 10460Sstevel@tonic-gate 10470Sstevel@tonic-gate /* 10480Sstevel@tonic-gate * Initialize entire table with 'reserved' trap and then overwrite 10490Sstevel@tonic-gate * specific entries. T_EXTOVRFLT (9) is unsupported and reserved 10500Sstevel@tonic-gate * since it can only be generated on a 386 processor. 15 is also 10510Sstevel@tonic-gate * unsupported and reserved. 10520Sstevel@tonic-gate */ 10530Sstevel@tonic-gate for (i = 0; i < NIDT; i++) 1054*8679SSeth.Goldberg@Sun.COM set_gatesegd(&idt[i], &resvtrap, KCS_SEL, SDT_SYSIGT, TRP_KPL, 1055*8679SSeth.Goldberg@Sun.COM 0); 10560Sstevel@tonic-gate 10570Sstevel@tonic-gate /* 10580Sstevel@tonic-gate * 20-31 reserved 10590Sstevel@tonic-gate */ 10600Sstevel@tonic-gate for (i = 20; i < 32; i++) 1061*8679SSeth.Goldberg@Sun.COM set_gatesegd(&idt[i], &invaltrap, KCS_SEL, SDT_SYSIGT, TRP_KPL, 1062*8679SSeth.Goldberg@Sun.COM 0); 10630Sstevel@tonic-gate 10640Sstevel@tonic-gate /* 10650Sstevel@tonic-gate * interrupts 32 - 255 10660Sstevel@tonic-gate */ 10670Sstevel@tonic-gate for (i = 32; i < 256; i++) { 10680Sstevel@tonic-gate (void) snprintf(ivctname, sizeof (ivctname), "ivct%d", i); 10690Sstevel@tonic-gate ivctptr = (void (*)(void))kobj_getsymvalue(ivctname, 0); 10700Sstevel@tonic-gate if (ivctptr == NULL) 10710Sstevel@tonic-gate panic("kobj_getsymvalue(%s) failed", ivctname); 10720Sstevel@tonic-gate 1073*8679SSeth.Goldberg@Sun.COM set_gatesegd(&idt[i], ivctptr, KCS_SEL, SDT_SYSIGT, TRP_KPL, 0); 10740Sstevel@tonic-gate } 10750Sstevel@tonic-gate 10760Sstevel@tonic-gate /* 10773446Smrj * Now install the common ones. Note that it will overlay some 10783446Smrj * entries installed above like T_SYSCALLINT, T_FASTTRAP etc. 10790Sstevel@tonic-gate */ 10803446Smrj init_idt_common(idt); 10810Sstevel@tonic-gate } 10820Sstevel@tonic-gate 10835084Sjohnlev #endif /* __xpv */ 10845084Sjohnlev 10850Sstevel@tonic-gate /* 10861217Srab * The kernel does not deal with LDTs unless a user explicitly creates 10871217Srab * one. Under normal circumstances, the LDTR contains 0. Any process attempting 10881217Srab * to reference the LDT will therefore cause a #gp. System calls made via the 10891217Srab * obsolete lcall mechanism are emulated by the #gp fault handler. 10900Sstevel@tonic-gate */ 10910Sstevel@tonic-gate static void 10920Sstevel@tonic-gate init_ldt(void) 10930Sstevel@tonic-gate { 10945084Sjohnlev #if defined(__xpv) 10955084Sjohnlev xen_set_ldt(NULL, 0); 10965084Sjohnlev #else 10971217Srab wr_ldtr(0); 10985084Sjohnlev #endif 10990Sstevel@tonic-gate } 11000Sstevel@tonic-gate 11015084Sjohnlev #if !defined(__xpv) 11020Sstevel@tonic-gate #if defined(__amd64) 11030Sstevel@tonic-gate 11040Sstevel@tonic-gate static void 11050Sstevel@tonic-gate init_tss(void) 11060Sstevel@tonic-gate { 11070Sstevel@tonic-gate /* 11080Sstevel@tonic-gate * tss_rsp0 is dynamically filled in by resume() on each context switch. 11090Sstevel@tonic-gate * All exceptions but #DF will run on the thread stack. 11100Sstevel@tonic-gate * Set up the double fault stack here. 11110Sstevel@tonic-gate */ 11125460Sjosephb ktss0->tss_ist1 = 11130Sstevel@tonic-gate (uint64_t)&dblfault_stack0[sizeof (dblfault_stack0)]; 11140Sstevel@tonic-gate 11150Sstevel@tonic-gate /* 11160Sstevel@tonic-gate * Set I/O bit map offset equal to size of TSS segment limit 11170Sstevel@tonic-gate * for no I/O permission map. This will force all user I/O 11180Sstevel@tonic-gate * instructions to generate #gp fault. 11190Sstevel@tonic-gate */ 11205460Sjosephb ktss0->tss_bitmapbase = sizeof (*ktss0); 11210Sstevel@tonic-gate 11220Sstevel@tonic-gate /* 11230Sstevel@tonic-gate * Point %tr to descriptor for ktss0 in gdt. 11240Sstevel@tonic-gate */ 11250Sstevel@tonic-gate wr_tsr(KTSS_SEL); 11260Sstevel@tonic-gate } 11270Sstevel@tonic-gate 11280Sstevel@tonic-gate #elif defined(__i386) 11290Sstevel@tonic-gate 11300Sstevel@tonic-gate static void 11310Sstevel@tonic-gate init_tss(void) 11320Sstevel@tonic-gate { 11330Sstevel@tonic-gate /* 11345460Sjosephb * ktss0->tss_esp dynamically filled in by resume() on each 11350Sstevel@tonic-gate * context switch. 11360Sstevel@tonic-gate */ 11375460Sjosephb ktss0->tss_ss0 = KDS_SEL; 11385460Sjosephb ktss0->tss_eip = (uint32_t)_start; 11395460Sjosephb ktss0->tss_ds = ktss0->tss_es = ktss0->tss_ss = KDS_SEL; 11405460Sjosephb ktss0->tss_cs = KCS_SEL; 11415460Sjosephb ktss0->tss_fs = KFS_SEL; 11425460Sjosephb ktss0->tss_gs = KGS_SEL; 11435460Sjosephb ktss0->tss_ldt = ULDT_SEL; 11440Sstevel@tonic-gate 11450Sstevel@tonic-gate /* 11460Sstevel@tonic-gate * Initialize double fault tss. 11470Sstevel@tonic-gate */ 11485460Sjosephb dftss0->tss_esp0 = (uint32_t)&dblfault_stack0[sizeof (dblfault_stack0)]; 11495460Sjosephb dftss0->tss_ss0 = KDS_SEL; 11500Sstevel@tonic-gate 11510Sstevel@tonic-gate /* 11520Sstevel@tonic-gate * tss_cr3 will get initialized in hat_kern_setup() once our page 11530Sstevel@tonic-gate * tables have been setup. 11540Sstevel@tonic-gate */ 11555460Sjosephb dftss0->tss_eip = (uint32_t)syserrtrap; 11565460Sjosephb dftss0->tss_esp = (uint32_t)&dblfault_stack0[sizeof (dblfault_stack0)]; 11575460Sjosephb dftss0->tss_cs = KCS_SEL; 11585460Sjosephb dftss0->tss_ds = KDS_SEL; 11595460Sjosephb dftss0->tss_es = KDS_SEL; 11605460Sjosephb dftss0->tss_ss = KDS_SEL; 11615460Sjosephb dftss0->tss_fs = KFS_SEL; 11625460Sjosephb dftss0->tss_gs = KGS_SEL; 11630Sstevel@tonic-gate 11640Sstevel@tonic-gate /* 11650Sstevel@tonic-gate * Set I/O bit map offset equal to size of TSS segment limit 11660Sstevel@tonic-gate * for no I/O permission map. This will force all user I/O 11670Sstevel@tonic-gate * instructions to generate #gp fault. 11680Sstevel@tonic-gate */ 11695460Sjosephb ktss0->tss_bitmapbase = sizeof (*ktss0); 11700Sstevel@tonic-gate 11710Sstevel@tonic-gate /* 11720Sstevel@tonic-gate * Point %tr to descriptor for ktss0 in gdt. 11730Sstevel@tonic-gate */ 11740Sstevel@tonic-gate wr_tsr(KTSS_SEL); 11750Sstevel@tonic-gate } 11760Sstevel@tonic-gate 11770Sstevel@tonic-gate #endif /* __i386 */ 11785084Sjohnlev #endif /* !__xpv */ 11795084Sjohnlev 11805084Sjohnlev #if defined(__xpv) 11815084Sjohnlev 11825084Sjohnlev void 11835084Sjohnlev init_desctbls(void) 11845084Sjohnlev { 11855084Sjohnlev uint_t vec; 11865084Sjohnlev user_desc_t *gdt; 11875084Sjohnlev 11885084Sjohnlev /* 11895084Sjohnlev * Setup and install our GDT. 11905084Sjohnlev */ 11915084Sjohnlev gdt = init_gdt(); 11925084Sjohnlev 11935084Sjohnlev /* 11945084Sjohnlev * Store static pa of gdt to speed up pa_to_ma() translations 11955084Sjohnlev * on lwp context switches. 11965084Sjohnlev */ 11975084Sjohnlev ASSERT(IS_P2ALIGNED((uintptr_t)gdt, PAGESIZE)); 11985460Sjosephb CPU->cpu_gdt = gdt; 11995084Sjohnlev CPU->cpu_m.mcpu_gdtpa = pfn_to_pa(va_to_pfn(gdt)); 12005084Sjohnlev 12015084Sjohnlev /* 12025084Sjohnlev * Setup and install our IDT. 12035084Sjohnlev */ 12045460Sjosephb #if !defined(__lint) 12055460Sjosephb ASSERT(NIDT * sizeof (*idt0) <= PAGESIZE); 12065460Sjosephb #endif 12075460Sjosephb idt0 = (gate_desc_t *)BOP_ALLOC(bootops, (caddr_t)IDT_VA, 12085460Sjosephb PAGESIZE, PAGESIZE); 1209*8679SSeth.Goldberg@Sun.COM bzero(idt0, PAGESIZE); 12105460Sjosephb init_idt(idt0); 12115084Sjohnlev for (vec = 0; vec < NIDT; vec++) 12125084Sjohnlev xen_idt_write(&idt0[vec], vec); 12135084Sjohnlev 12145460Sjosephb CPU->cpu_idt = idt0; 12155084Sjohnlev 12165084Sjohnlev /* 12175084Sjohnlev * set default kernel stack 12185084Sjohnlev */ 12195084Sjohnlev xen_stack_switch(KDS_SEL, 12205084Sjohnlev (ulong_t)&dblfault_stack0[sizeof (dblfault_stack0)]); 12215084Sjohnlev 12225084Sjohnlev xen_init_callbacks(); 12235084Sjohnlev 12245084Sjohnlev init_ldt(); 12255084Sjohnlev } 12265084Sjohnlev 12275084Sjohnlev #else /* __xpv */ 12280Sstevel@tonic-gate 12290Sstevel@tonic-gate void 12303446Smrj init_desctbls(void) 12310Sstevel@tonic-gate { 12323446Smrj user_desc_t *gdt; 12333446Smrj desctbr_t idtr; 12343446Smrj 12353446Smrj /* 12365460Sjosephb * Allocate IDT and TSS structures on unique pages for better 12375460Sjosephb * performance in virtual machines. 12385460Sjosephb */ 12395460Sjosephb #if !defined(__lint) 12405460Sjosephb ASSERT(NIDT * sizeof (*idt0) <= PAGESIZE); 12415460Sjosephb #endif 12425460Sjosephb idt0 = (gate_desc_t *)BOP_ALLOC(bootops, (caddr_t)IDT_VA, 12435460Sjosephb PAGESIZE, PAGESIZE); 1244*8679SSeth.Goldberg@Sun.COM bzero(idt0, PAGESIZE); 12455460Sjosephb #if !defined(__lint) 12465460Sjosephb ASSERT(sizeof (*ktss0) <= PAGESIZE); 12475460Sjosephb #endif 12485460Sjosephb ktss0 = (struct tss *)BOP_ALLOC(bootops, (caddr_t)KTSS_VA, 12495460Sjosephb PAGESIZE, PAGESIZE); 1250*8679SSeth.Goldberg@Sun.COM bzero(ktss0, PAGESIZE); 12515460Sjosephb 12525460Sjosephb #if defined(__i386) 12535460Sjosephb #if !defined(__lint) 12545460Sjosephb ASSERT(sizeof (*dftss0) <= PAGESIZE); 12555460Sjosephb #endif 12565460Sjosephb dftss0 = (struct tss *)BOP_ALLOC(bootops, (caddr_t)DFTSS_VA, 12575460Sjosephb PAGESIZE, PAGESIZE); 1258*8679SSeth.Goldberg@Sun.COM bzero(dftss0, PAGESIZE); 12595460Sjosephb #endif 12605460Sjosephb 12615460Sjosephb /* 12623446Smrj * Setup and install our GDT. 12633446Smrj */ 12643446Smrj gdt = init_gdt(); 12653446Smrj ASSERT(IS_P2ALIGNED((uintptr_t)gdt, PAGESIZE)); 12665460Sjosephb CPU->cpu_gdt = gdt; 12673446Smrj 12683446Smrj /* 12693446Smrj * Setup and install our IDT. 12703446Smrj */ 12715460Sjosephb init_idt(idt0); 12723446Smrj 12733446Smrj idtr.dtr_base = (uintptr_t)idt0; 12745460Sjosephb idtr.dtr_limit = (NIDT * sizeof (*idt0)) - 1; 12753446Smrj wr_idtr(&idtr); 12765460Sjosephb CPU->cpu_idt = idt0; 12773446Smrj 12783446Smrj #if defined(__i386) 12793446Smrj /* 12803446Smrj * We maintain a description of idt0 in convenient IDTR format 12813446Smrj * for #pf's on some older pentium processors. See pentium_pftrap(). 12823446Smrj */ 12833446Smrj idt0_default_r = idtr; 12843446Smrj #endif /* __i386 */ 12853446Smrj 12860Sstevel@tonic-gate init_tss(); 12875460Sjosephb CPU->cpu_tss = ktss0; 12880Sstevel@tonic-gate init_ldt(); 12890Sstevel@tonic-gate } 12902712Snn35248 12915084Sjohnlev #endif /* __xpv */ 12925084Sjohnlev 12932712Snn35248 /* 12943446Smrj * In the early kernel, we need to set up a simple GDT to run on. 12955084Sjohnlev * 12965084Sjohnlev * XXPV Can dboot use this too? See dboot_gdt.s 12973446Smrj */ 12983446Smrj void 12993446Smrj init_boot_gdt(user_desc_t *bgdt) 13003446Smrj { 13013446Smrj #if defined(__amd64) 13023446Smrj set_usegd(&bgdt[GDT_B32DATA], SDP_LONG, NULL, -1, SDT_MEMRWA, SEL_KPL, 13033446Smrj SDP_PAGES, SDP_OP32); 13043446Smrj set_usegd(&bgdt[GDT_B64CODE], SDP_LONG, NULL, -1, SDT_MEMERA, SEL_KPL, 13053446Smrj SDP_PAGES, SDP_OP32); 13063446Smrj #elif defined(__i386) 13073446Smrj set_usegd(&bgdt[GDT_B32DATA], NULL, -1, SDT_MEMRWA, SEL_KPL, 13083446Smrj SDP_PAGES, SDP_OP32); 13093446Smrj set_usegd(&bgdt[GDT_B32CODE], NULL, -1, SDT_MEMERA, SEL_KPL, 13103446Smrj SDP_PAGES, SDP_OP32); 13113446Smrj #endif /* __i386 */ 13123446Smrj } 13133446Smrj 13143446Smrj /* 13152712Snn35248 * Enable interpositioning on the system call path by rewriting the 13162712Snn35248 * sys{call|enter} MSRs and the syscall-related entries in the IDT to use 13172712Snn35248 * the branded entry points. 13182712Snn35248 */ 13192712Snn35248 void 13202712Snn35248 brand_interpositioning_enable(void) 13212712Snn35248 { 13225084Sjohnlev gate_desc_t *idt = CPU->cpu_idt; 13235084Sjohnlev int i; 13245084Sjohnlev 13255084Sjohnlev ASSERT(curthread->t_preempt != 0 || getpil() >= DISP_LEVEL); 13262712Snn35248 13275084Sjohnlev for (i = 0; brand_tbl[i].ih_inum; i++) { 13285084Sjohnlev idt[brand_tbl[i].ih_inum] = brand_tbl[i].ih_interp_desc; 13295084Sjohnlev #if defined(__xpv) 13305084Sjohnlev xen_idt_write(&idt[brand_tbl[i].ih_inum], 13315084Sjohnlev brand_tbl[i].ih_inum); 13325084Sjohnlev #endif 13335084Sjohnlev } 13342712Snn35248 13352712Snn35248 #if defined(__amd64) 13365084Sjohnlev #if defined(__xpv) 13375084Sjohnlev 13385084Sjohnlev /* 13395084Sjohnlev * Currently the hypervisor only supports 64-bit syscalls via 13405084Sjohnlev * syscall instruction. The 32-bit syscalls are handled by 13415084Sjohnlev * interrupt gate above. 13425084Sjohnlev */ 13435084Sjohnlev xen_set_callback(brand_sys_syscall, CALLBACKTYPE_syscall, 13445084Sjohnlev CALLBACKF_mask_events); 13455084Sjohnlev 13465084Sjohnlev #else 13475084Sjohnlev 13485084Sjohnlev if (x86_feature & X86_ASYSC) { 13495084Sjohnlev wrmsr(MSR_AMD_LSTAR, (uintptr_t)brand_sys_syscall); 13505084Sjohnlev wrmsr(MSR_AMD_CSTAR, (uintptr_t)brand_sys_syscall32); 13515084Sjohnlev } 13525084Sjohnlev 13532712Snn35248 #endif 13545084Sjohnlev #endif /* __amd64 */ 13552712Snn35248 13562712Snn35248 if (x86_feature & X86_SEP) 13572712Snn35248 wrmsr(MSR_INTC_SEP_EIP, (uintptr_t)brand_sys_sysenter); 13582712Snn35248 } 13592712Snn35248 13602712Snn35248 /* 13612712Snn35248 * Disable interpositioning on the system call path by rewriting the 13622712Snn35248 * sys{call|enter} MSRs and the syscall-related entries in the IDT to use 13632712Snn35248 * the standard entry points, which bypass the interpositioning hooks. 13642712Snn35248 */ 13652712Snn35248 void 13662712Snn35248 brand_interpositioning_disable(void) 13672712Snn35248 { 13685084Sjohnlev gate_desc_t *idt = CPU->cpu_idt; 13692712Snn35248 int i; 13702712Snn35248 13715084Sjohnlev ASSERT(curthread->t_preempt != 0 || getpil() >= DISP_LEVEL); 13725084Sjohnlev 13735084Sjohnlev for (i = 0; brand_tbl[i].ih_inum; i++) { 13745084Sjohnlev idt[brand_tbl[i].ih_inum] = brand_tbl[i].ih_default_desc; 13755084Sjohnlev #if defined(__xpv) 13765084Sjohnlev xen_idt_write(&idt[brand_tbl[i].ih_inum], 13775084Sjohnlev brand_tbl[i].ih_inum); 13785084Sjohnlev #endif 13795084Sjohnlev } 13802712Snn35248 13812712Snn35248 #if defined(__amd64) 13825084Sjohnlev #if defined(__xpv) 13835084Sjohnlev 13845084Sjohnlev /* 13855084Sjohnlev * See comment above in brand_interpositioning_enable. 13865084Sjohnlev */ 13875084Sjohnlev xen_set_callback(sys_syscall, CALLBACKTYPE_syscall, 13885084Sjohnlev CALLBACKF_mask_events); 13895084Sjohnlev 13905084Sjohnlev #else 13915084Sjohnlev 13925084Sjohnlev if (x86_feature & X86_ASYSC) { 13935084Sjohnlev wrmsr(MSR_AMD_LSTAR, (uintptr_t)sys_syscall); 13945084Sjohnlev wrmsr(MSR_AMD_CSTAR, (uintptr_t)sys_syscall32); 13955084Sjohnlev } 13965084Sjohnlev 13972712Snn35248 #endif 13985084Sjohnlev #endif /* __amd64 */ 13992712Snn35248 14002712Snn35248 if (x86_feature & X86_SEP) 14012712Snn35248 wrmsr(MSR_INTC_SEP_EIP, (uintptr_t)sys_sysenter); 14022712Snn35248 } 1403