/*
* CDDL HEADER START
*
* The contents of this file are subject to the terms of the
* Common Development and Distribution License (the "License").
* You may not use this file except in compliance with the License.
*
* You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
* See the License for the specific language governing permissions
* and limitations under the License.
*
* When distributing Covered Code, include this CDDL HEADER in each
* file and include the License file at usr/src/OPENSOLARIS.LICENSE.
* If applicable, add the following below this CDDL HEADER, with the
* fields enclosed by brackets "[]" replaced with your own identifying
* information: Portions Copyright [yyyy] [name of copyright owner]
*
* CDDL HEADER END
*/
/*
*/
/*
* Copyright 2011 Joyent, Inc. All rights reserved.
*/
/*
* Copyright (c) 1992 Terrence R. Lambert.
* Copyright (c) 1990 The Regents of the University of California.
* All rights reserved.
*
* This code is derived from software contributed to Berkeley by
* William Jolitz.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* 3. All advertising materials mentioning features or use of this software
* must display the following acknowledgement:
* This product includes software developed by the University of
* California, Berkeley and its contributors.
* 4. Neither the name of the University nor the names of its contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*
* from: @(#)machdep.c 7.4 (Berkeley) 6/3/91
*/
#include <sys/sysmacros.h>
#include <sys/segments.h>
#include <sys/bootconf.h>
#include <sys/x86_archext.h>
#include <sys/controlregs.h>
#include <sys/archsystm.h>
#include <sys/machsystm.h>
#include <sys/mach_mmu.h>
#ifdef __xpv
#include <sys/hypervisor.h>
#endif
#include <sys/bootinfo.h>
#include <vm/kboot_mmu.h>
/*
* cpu0 and default tables and structures.
*/
#if !defined(__xpv)
#endif
#if defined(__i386)
#endif
#if defined(__i386)
#endif /* __i386 */
#if defined(__amd64)
#endif /* __amd64 */
#if defined(__amd64)
#endif /* __amd64 */
extern void fast_null(void);
extern hrtime_t get_hrtime(void);
extern hrtime_t gethrvtime(void);
extern hrtime_t get_hrestime(void);
void (*(fasttable[]))(void) = {
fast_null, /* T_FNULL routine */
fast_null, /* T_FGETFP routine (initially null) */
fast_null, /* T_FSETFP routine (initially null) */
(void (*)())get_hrtime, /* T_GETHRTIME */
(void (*)())gethrvtime, /* T_GETHRVTIME */
(void (*)())get_hrestime, /* T_GETHRESTIME */
(void (*)())getlgrp /* T_GETLGRP */
};
/*
* Structure containing pre-computed descriptors to allow us to temporarily
* interpose on a standard handler.
*/
struct interposing_handler {
int ih_inum;
};
/*
* The brand infrastructure interposes on two handlers, and we use one as a
* NULL signpost.
*/
/*
* software prototypes for default local descriptor table
*/
/*
* Routines for loading segment descriptors in format the hardware
* can understand.
*/
#if defined(__amd64)
/*
* In long mode we have the new L or long mode attribute bit
* for code segments. Only the conforming bit in type is used along
* with descriptor priority and present bits. Default operand size must
* be zero when in long mode. In 32-bit compatibility mode all fields
* are treated as in legacy mode. For data segments while in long mode
* only the present bit is loaded.
*/
void
{
/*
* 64-bit long mode.
*/
else
/*
* 32-bit compatibility mode.
*/
}
/*
* Install user segment descriptor for code and data.
*/
void
{
}
#endif /* __i386 */
/*
* Install system segment descriptor for LDT and TSS segments.
*/
#if defined(__amd64)
void
{
}
void *
{
return ((void *)base);
}
void
{
}
void *
{
return ((void *)base);
}
#endif /* __i386 */
/*
* Install gate segment descriptor for interrupt, trap, call and task gates.
*/
#if defined(__amd64)
/*ARGSUSED*/
void
{
/*
* For 64 bit native we use the IST stack mechanism
* for double faults. All other traps use the CPL = 0
* (tss_rsp0) stack.
*/
#if !defined(__xpv)
else
#endif
}
/*ARGSUSED*/
void
{
}
#endif /* __i386 */
/*
* Updates a single user descriptor in the the GDT of the current cpu.
* Caller is responsible for preventing cpu migration.
*/
void
{
#if defined(__xpv)
panic("gdt_update_usegd: HYPERVISOR_update_descriptor");
#else /* __xpv */
#endif /* __xpv */
}
/*
* Writes single descriptor pointed to by udp into a processes
* LDT entry pointed to by ldp.
*/
int
{
#if defined(__xpv)
/*
* The hypervisor is a little more restrictive about what it
* supports in the LDT.
*/
return (EINVAL);
#else /* __xpv */
#endif /* __xpv */
return (0);
}
#if defined(__xpv)
/*
* Converts hw format gate descriptor into pseudo-IDT format for the hypervisor.
* Returns true if a valid entry was written.
*/
int
{
/*
* skip holes in the IDT
*/
if (GATESEG_GETOFFSET(sgd) == 0)
return (0);
/*
* Is this an interrupt gate?
*/
/* LINTED */
}
#if defined(__amd64)
#endif
return (1);
}
/*
* Convert a single hw format gate descriptor and write it into our virtual IDT.
*/
void
{
return;
if (xen_set_trap_table(trapinfo) != 0)
panic("xen_idt_write: xen_set_trap_table() failed");
}
#endif /* __xpv */
#if defined(__amd64)
/*
* Build kernel GDT.
*/
static void
{
int i;
/*
* 64-bit kernel code segment.
*/
/*
* 64-bit kernel data segment. The limit attribute is ignored in 64-bit
* mode, but we set it here to 0xFFFF so that we can use the SYSRET
* instruction to return from system calls back to 32-bit applications.
* SYSRET doesn't update the base, limit, or attributes of %ss or %ds
* descriptors. We therefore must ensure that the kernel uses something,
* though it will be ignored by hardware, that is compatible with 32-bit
* apps. For the same reason we must set the default op size of this
* descriptor to 32-bit operands.
*/
/*
* 64-bit user code segment.
*/
/*
* 32-bit user code segment.
*/
/*
* See gdt_ucode32() and gdt_ucode_native().
*/
/*
* 32 and 64 bit data segments can actually share the same descriptor.
* In long mode only the present bit is checked but all other fields
* are loaded. But in compatibility mode all fields are interpreted
* as in legacy mode so they must be set correctly for a 32-bit data
* segment.
*/
#if !defined(__xpv)
/*
* The 64-bit kernel has no default LDT. By default, the LDT descriptor
* in the GDT is 0.
*/
/*
* Kernel TSS
*/
#endif /* !__xpv */
/*
* Initialize fs and gs descriptors for 32 bit processes.
* Only attributes and limits are initialized, the effective
*/
/*
* Initialize the descriptors set aside for brand usage.
* Only attributes and limits are initialized.
*/
for (i = GDT_BRANDMIN; i <= GDT_BRANDMAX; i++)
/*
* Initialize convenient zero base user descriptors for clearing
* lwp private %fs and %gs descriptors in GDT. See setregs() for
* an example.
*/
}
#if defined(__xpv)
static user_desc_t *
init_gdt(void)
{
#if !defined(__lint)
/*
* Our gdt is never larger than a single page.
*/
#endif
/*
* XXX Since we never invoke kmdb until after the kernel takes
* over the descriptor tables why not have it use the kernel's
* selectors?
*/
}
/*
* Clear write permission for page containing the gdt and install it.
*/
/*
* Reload the segment registers to use the new GDT.
* On 64-bit, fixup KCS_SEL to be in ring 3.
* See KCS_SEL in segments.h.
*/
/*
* setup %gs for kernel
*/
/*
* XX64 We should never dereference off "other gsbase" or
* "fsbase". So, we should arrange to point FSBASE and
* KGSBASE somewhere truly awful e.g. point it at the last
* valid address below the hole so that any attempts to index
* off them cause an exception.
*
* For now, point it at 8G -- at least it should be unmapped
* until some 64-bit processes run.
*/
addr = 0x200000000ul;
return (gdt0);
}
#else /* __xpv */
static user_desc_t *
init_gdt(void)
{
#if !defined(__lint)
/*
* Our gdt is never larger than a single page.
*/
#endif
/*
* Copy in from boot's gdt to our gdt.
* Entry 0 is the null descriptor by definition.
*/
panic("null boot gdt");
/*
* Install our new GDT
*/
/*
* Reload the segment registers to use the new GDT
*/
/*
* setup %gs for kernel
*/
/*
* XX64 We should never dereference off "other gsbase" or
* "fsbase". So, we should arrange to point FSBASE and
* KGSBASE somewhere truly awful e.g. point it at the last
* valid address below the hole so that any attempts to index
* off them cause an exception.
*
* For now, point it at 8G -- at least it should be unmapped
* until some 64-bit processes run.
*/
return (gdt0);
}
#endif /* __xpv */
static void
{
int i;
/*
* Text and data for both kernel and user span entire 32 bit
* address space.
*/
/*
* kernel code segment.
*/
SDP_OP32);
/*
* kernel data segment.
*/
SDP_OP32);
/*
* user code segment.
*/
SDP_OP32);
/*
* user data segment.
*/
SDP_OP32);
#if !defined(__xpv)
/*
* TSS for T_DBLFLT (double fault) handler
*/
/*
* TSS for kernel
*/
#endif /* !__xpv */
/*
* %gs selector for kernel
*/
/*
* Initialize lwp private descriptors.
* Only attributes and limits are initialized, the effective
*/
/*
* Initialize the descriptors set aside for brand usage.
* Only attributes and limits are initialized.
*/
for (i = GDT_BRANDMIN; i <= GDT_BRANDMAX; i++)
/*
* Initialize convenient zero base user descriptor for clearing
* lwp private %fs and %gs descriptors in GDT. See setregs() for
* an example.
*/
}
#if defined(__xpv)
static user_desc_t *
init_gdt(void)
{
#if !defined(__lint)
/*
* Our gdt is never larger than a single page.
*/
#endif
/*
* XXX Since we never invoke kmdb until after the kernel takes
* over the descriptor tables why not have it use the kernel's
* selectors?
*/
}
/*
* Clear write permission for page containing the gdt and install it.
*/
/*
* Reload the segment registers to use the new GDT
*/
return (gdt0);
}
#else /* __xpv */
static user_desc_t *
init_gdt(void)
{
#if !defined(__lint)
/*
* Our gdt is never larger than a single page.
*/
#endif
/*
* XXX this allocation belongs in our caller, not here.
*/
/*
* Copy in from boot's gdt to our gdt entries.
* Entry 0 is null descriptor by definition.
*/
panic("null boot gdt");
/*
* Install our new GDT
*/
/*
* Reload the segment registers to use the new GDT
*/
return (gdt0);
}
#endif /* __xpv */
#endif /* __i386 */
/*
* Build kernel IDT.
*
* Note that for amd64 we pretty much require every gate to be an interrupt
* gate which blocks interrupts atomically on entry; that's because of our
* dependency on using 'swapgs' every time we come into the kernel to find
* the cpu structure. If we get interrupted just before doing that, %cs could
* be in kernel mode (so that the trap prolog doesn't do a swapgs), but
* %gsbase is really still pointing at something in userland. Bad things will
* ensue. We also use interrupt gates for i386 as well even though this is not
* required for some traps.
*
* Perhaps they should have invented a trap gate that does an atomic swapgs?
*/
static void
{
0);
0);
0);
0);
0);
TRP_KPL, 0);
0);
0);
/*
* double fault handler.
*
* Note that on the hypervisor a guest does not receive #df faults.
* Instead a failsafe event is injected into the guest if its selectors
*/
#if !defined(__xpv)
#if defined(__amd64)
T_DBLFLT);
/*
* task gate required.
*/
0);
#endif /* __i386 */
#endif /* !__xpv */
/*
* T_EXTOVRFLT coprocessor-segment-overrun not supported.
*/
0);
0);
0);
TRP_KPL, 0);
/*
* install fast trap handler at 210.
*/
0);
/*
* System call handler.
*/
#if defined(__amd64)
TRP_UPL, 0);
TRP_UPL, 0);
#endif /* __i386 */
/*
* Install the DTrace interrupt handler for the pid provider.
*/
SDT_SYSIGT, TRP_UPL, 0);
/*
* Prepare interposing descriptor for the syscall handler
* and cache copy of the default descriptor.
*/
#if defined(__amd64)
#endif /* __i386 */
}
#if defined(__xpv)
static void
{
}
#else /* __xpv */
static void
{
void (*ivctptr)(void);
int i;
/*
* Initialize entire table with 'reserved' trap and then overwrite
* specific entries. T_EXTOVRFLT (9) is unsupported and reserved
* since it can only be generated on a 386 processor. 15 is also
* unsupported and reserved.
*/
for (i = 0; i < NIDT; i++)
0);
/*
* 20-31 reserved
*/
for (i = 20; i < 32; i++)
0);
/*
* interrupts 32 - 255
*/
for (i = 32; i < 256; i++) {
}
/*
* Now install the common ones. Note that it will overlay some
* entries installed above like T_SYSCALLINT, T_FASTTRAP etc.
*/
}
#endif /* __xpv */
/*
* The kernel does not deal with LDTs unless a user explicitly creates
* one. Under normal circumstances, the LDTR contains 0. Any process attempting
* to reference the LDT will therefore cause a #gp. System calls made via the
* obsolete lcall mechanism are emulated by the #gp fault handler.
*/
static void
init_ldt(void)
{
#if defined(__xpv)
xen_set_ldt(NULL, 0);
#else
wr_ldtr(0);
#endif
}
#if !defined(__xpv)
#if defined(__amd64)
static void
init_tss(void)
{
/*
* tss_rsp0 is dynamically filled in by resume() on each context switch.
* All exceptions but #DF will run on the thread stack.
* Set up the double fault stack here.
*/
/*
* Set I/O bit map offset equal to size of TSS segment limit
* for no I/O permission map. This will force all user I/O
* instructions to generate #gp fault.
*/
/*
* Point %tr to descriptor for ktss0 in gdt.
*/
}
static void
init_tss(void)
{
/*
* ktss0->tss_esp dynamically filled in by resume() on each
* context switch.
*/
/*
* Initialize double fault tss.
*/
/*
* tss_cr3 will get initialized in hat_kern_setup() once our page
* tables have been setup.
*/
/*
* Set I/O bit map offset equal to size of TSS segment limit
* for no I/O permission map. This will force all user I/O
* instructions to generate #gp fault.
*/
/*
* Point %tr to descriptor for ktss0 in gdt.
*/
}
#endif /* __i386 */
#endif /* !__xpv */
#if defined(__xpv)
void
init_desctbls(void)
{
/*
* Setup and install our GDT.
*/
/*
* Store static pa of gdt to speed up pa_to_ma() translations
* on lwp context switches.
*/
/*
* Setup and install our IDT.
*/
#if !defined(__lint)
#endif
/*
* set default kernel stack
*/
init_ldt();
}
#else /* __xpv */
void
init_desctbls(void)
{
/*
* Allocate IDT and TSS structures on unique pages for better
* performance in virtual machines.
*/
#if !defined(__lint)
#endif
#if !defined(__lint)
#endif
#if defined(__i386)
#if !defined(__lint)
#endif
#endif
/*
* Setup and install our GDT.
*/
/*
* Setup and install our IDT.
*/
#if defined(__i386)
/*
* We maintain a description of idt0 in convenient IDTR format
* for #pf's on some older pentium processors. See pentium_pftrap().
*/
#endif /* __i386 */
init_tss();
init_ldt();
}
#endif /* __xpv */
/*
* In the early kernel, we need to set up a simple GDT to run on.
*
* XXPV Can dboot use this too? See dboot_gdt.s
*/
void
{
#if defined(__amd64)
#endif /* __i386 */
}
/*
* Enable interpositioning on the system call path by rewriting the
* sys{call|enter} MSRs and the syscall-related entries in the IDT to use
* the branded entry points.
*/
void
{
int i;
#if defined(__xpv)
#endif
}
#if defined(__amd64)
#if defined(__xpv)
/*
* Currently the hypervisor only supports 64-bit syscalls via
* syscall instruction. The 32-bit syscalls are handled by
* interrupt gate above.
*/
#else
}
#endif
#endif /* __amd64 */
}
/*
* Disable interpositioning on the system call path by rewriting the
* sys{call|enter} MSRs and the syscall-related entries in the IDT to use
* the standard entry points, which bypass the interpositioning hooks.
*/
void
{
int i;
#if defined(__xpv)
#endif
}
#if defined(__amd64)
#if defined(__xpv)
/*
* See comment above in brand_interpositioning_enable.
*/
#else
}
#endif
#endif /* __amd64 */
}