#include <sys/types.h>
#include <sys/sysmacros.h>
#include <sys/tss.h>
#include <sys/segments.h>
#include <sys/trap.h>
#include <sys/cpuvar.h>
#include <sys/bootconf.h>
#include <sys/x86_archext.h>
#include <sys/controlregs.h>
#include <sys/archsystm.h>
#include <sys/machsystm.h>
#include <sys/kobj.h>
#include <sys/cmn_err.h>
#include <sys/reboot.h>
#include <sys/kdi.h>
#include <sys/mach_mmu.h>
#include <sys/systm.h>
#include <sys/note.h>
#ifdef __xpv
#include <sys/hypervisor.h>
#include <vm/as.h>
#endif
#include <sys/promif.h>
#include <sys/bootinfo.h>
#include <vm/kboot_mmu.h>
#include <vm/hat_pte.h>
user_desc_t *gdt0;
#if !defined(__xpv)
desctbr_t gdt0_default_r;
#endif
gate_desc_t *idt0;
tss_t *ktss0;
user_desc_t zero_udesc;
user_desc_t null_udesc;
system_desc_t null_sdesc;
user_desc_t zero_u32desc;
user_desc_t ucs_on;
user_desc_t ucs_off;
user_desc_t ucs32_on;
user_desc_t ucs32_off;
extern char dblfault_stack0[DEFAULTSTKSZ];
extern char nmi_stack0[DEFAULTSTKSZ];
extern char mce_stack0[DEFAULTSTKSZ];
extern void fast_null(void);
extern hrtime_t get_hrtime(void);
extern hrtime_t gethrvtime(void);
extern hrtime_t get_hrestime(void);
extern uint64_t getlgrp(void);
void (*(fasttable[]))(void) = {
fast_null,
fast_null,
fast_null,
(void (*)())(uintptr_t)get_hrtime,
(void (*)())(uintptr_t)gethrvtime,
(void (*)())(uintptr_t)get_hrestime,
(void (*)())(uintptr_t)getlgrp
};
struct interposing_handler {
int ih_inum;
gate_desc_t ih_interp_desc;
gate_desc_t ih_default_desc;
};
static struct interposing_handler brand_tbl[2];
void
set_usegd(user_desc_t *dp, uint_t lmode, void *base, uint32_t size,
uint_t type, uint_t dpl, uint_t gran, uint_t defopsz)
{
ASSERT(lmode == SDP_SHORT || lmode == SDP_LONG);
ASSERT3U(type & SDT_S, !=, 0);
ASSERT3P(dp, !=, NULL);
if (lmode == SDP_LONG)
dp->usd_def32 = 0;
else
dp->usd_def32 = defopsz;
ASSERT3U(type & SDT_A, !=, 0);
dp->usd_long = lmode;
dp->usd_type = type;
dp->usd_dpl = dpl;
dp->usd_p = 1;
dp->usd_gran = gran;
dp->usd_lobase = (uintptr_t)base;
dp->usd_midbase = (uintptr_t)base >> 16;
dp->usd_hibase = (uintptr_t)base >> (16 + 8);
dp->usd_lolimit = size;
dp->usd_hilimit = (uintptr_t)size >> 16;
}
void
set_syssegd(system_desc_t *dp, void *base, size_t size, uint_t type,
uint_t dpl)
{
dp->ssd_lolimit = size;
dp->ssd_hilimit = (uintptr_t)size >> 16;
dp->ssd_lobase = (uintptr_t)base;
dp->ssd_midbase = (uintptr_t)base >> 16;
dp->ssd_hibase = (uintptr_t)base >> (16 + 8);
dp->ssd_hi64base = (uintptr_t)base >> (16 + 8 + 8);
dp->ssd_type = type;
dp->ssd_zero1 = 0;
dp->ssd_zero2 = 0;
dp->ssd_dpl = dpl;
dp->ssd_p = 1;
dp->ssd_gran = 0;
}
void *
get_ssd_base(system_desc_t *dp)
{
uintptr_t base;
base = (uintptr_t)dp->ssd_lobase |
(uintptr_t)dp->ssd_midbase << 16 |
(uintptr_t)dp->ssd_hibase << (16 + 8) |
(uintptr_t)dp->ssd_hi64base << (16 + 8 + 8);
return ((void *)base);
}
uint_t
idt_vector_to_ist(uint_t vector)
{
#if defined(__xpv)
_NOTE(ARGUNUSED(vector));
return (IST_NONE);
#else
switch (vector) {
case T_DBLFLT:
return (IST_DF);
case T_NMIFLT:
return (IST_NMI);
case T_MCE:
return (IST_MCE);
case T_BPTFLT:
case T_SGLSTP:
if (kpti_enable == 1) {
return (IST_DBG);
}
return (IST_NONE);
case T_STKFLT:
case T_GPFLT:
case T_PGFLT:
if (kpti_enable == 1) {
return (IST_NESTABLE);
}
return (IST_NONE);
default:
if (kpti_enable == 1) {
return (IST_DEFAULT);
}
return (IST_NONE);
}
#endif
}
void
set_gatesegd(gate_desc_t *dp, void (*func)(void), selector_t sel,
uint_t type, uint_t dpl, uint_t ist)
{
dp->sgd_looffset = (uintptr_t)func;
dp->sgd_hioffset = (uintptr_t)func >> 16;
dp->sgd_hi64offset = (uintptr_t)func >> (16 + 16);
dp->sgd_selector = (uint16_t)sel;
dp->sgd_ist = ist;
dp->sgd_type = type;
dp->sgd_dpl = dpl;
dp->sgd_p = 1;
}
void
gdt_update_usegd(uint_t sidx, user_desc_t *udp)
{
#if defined(DEBUG)
if (udp->usd_p != 0 || udp->usd_type != 0) {
ASSERT3U(udp->usd_type & SDT_S, !=, 0);
}
if (udp->usd_p != 0 || udp->usd_type != 0) {
ASSERT3U(udp->usd_type & SDT_A, !=, 0);
}
#endif
#if defined(__xpv)
uint64_t dpa = CPU->cpu_m.mcpu_gdtpa + sizeof (*udp) * sidx;
if (HYPERVISOR_update_descriptor(pa_to_ma(dpa), *(uint64_t *)udp))
panic("gdt_update_usegd: HYPERVISOR_update_descriptor");
#else
CPU->cpu_gdt[sidx] = *udp;
#endif
}
int
ldt_update_segd(user_desc_t *ldp, user_desc_t *udp)
{
#if defined(DEBUG)
if (udp->usd_p != 0 || udp->usd_type != 0) {
ASSERT3U(udp->usd_type & SDT_S, !=, 0);
}
if (udp->usd_p != 0 || udp->usd_type != 0) {
ASSERT3U(udp->usd_type & SDT_A, !=, 0);
}
#endif
#if defined(__xpv)
uint64_t dpa;
dpa = mmu_ptob(hat_getpfnum(kas.a_hat, (caddr_t)ldp)) |
((uintptr_t)ldp & PAGEOFFSET);
if (HYPERVISOR_update_descriptor(pa_to_ma(dpa), *(uint64_t *)udp) != 0)
return (EINVAL);
#else
*ldp = *udp;
#endif
return (0);
}
#if defined(__xpv)
int
xen_idt_to_trap_info(uint_t vec, gate_desc_t *sgd, void *ti_arg)
{
trap_info_t *ti = ti_arg;
if (GATESEG_GETOFFSET(sgd) == 0)
return (0);
ASSERT(sgd->sgd_type == SDT_SYSIGT);
ti->vector = vec;
TI_SET_DPL(ti, sgd->sgd_dpl);
if (sgd->sgd_type == SDT_SYSIGT) {
TI_SET_IF(ti, 1);
}
ti->cs = sgd->sgd_selector;
ti->cs |= SEL_KPL;
ti->address = GATESEG_GETOFFSET(sgd);
return (1);
}
void
xen_idt_write(gate_desc_t *sgd, uint_t vec)
{
trap_info_t trapinfo[2];
bzero(trapinfo, sizeof (trapinfo));
if (xen_idt_to_trap_info(vec, sgd, &trapinfo[0]) == 0)
return;
if (xen_set_trap_table(trapinfo) != 0)
panic("xen_idt_write: xen_set_trap_table() failed");
}
#endif
static void
init_gdt_common(user_desc_t *gdt)
{
int i;
ASSERT3P(gdt, !=, NULL);
init_boot_gdt(gdt);
set_usegd(&gdt[GDT_KCODE], SDP_LONG, NULL, 0, SDT_MEMERA, SEL_KPL,
SDP_PAGES, SDP_OP32);
set_usegd(&gdt[GDT_KDATA], SDP_LONG, NULL, SDP_LIMIT_MAX, SDT_MEMRWA,
SEL_KPL, SDP_PAGES, SDP_OP32);
gdt[GDT_KDATA].usd_def32 = 1;
set_usegd(&gdt[GDT_UCODE], SDP_LONG, NULL, 0, SDT_MEMERA, SEL_UPL,
SDP_PAGES, SDP_OP32);
set_usegd(&gdt[GDT_U32CODE], SDP_SHORT, NULL, SDP_LIMIT_MAX, SDT_MEMERA,
SEL_UPL, SDP_PAGES, SDP_OP32);
ucs_on = ucs_off = gdt[GDT_UCODE];
ucs_off.usd_p = 0;
ucs32_on = ucs32_off = gdt[GDT_U32CODE];
ucs32_off.usd_p = 0;
set_usegd(&gdt[GDT_UDATA], SDP_SHORT, NULL, SDP_LIMIT_MAX, SDT_MEMRWA,
SEL_UPL, SDP_PAGES, SDP_OP32);
#if !defined(__xpv)
set_syssegd((system_desc_t *)&gdt[GDT_KTSS], ktss0,
sizeof (*ktss0) - 1, SDT_SYSTSS, SEL_KPL);
#endif
set_usegd(&gdt[GDT_LWPFS], SDP_SHORT, NULL, SDP_LIMIT_MAX, SDT_MEMRWA,
SEL_UPL, SDP_PAGES, SDP_OP32);
set_usegd(&gdt[GDT_LWPGS], SDP_SHORT, NULL, SDP_LIMIT_MAX, SDT_MEMRWA,
SEL_UPL, SDP_PAGES, SDP_OP32);
for (i = GDT_BRANDMIN; i <= GDT_BRANDMAX; i++)
set_usegd(&gdt0[i], SDP_SHORT, NULL, SDP_LIMIT_MAX, SDT_MEMRWA,
SEL_UPL, SDP_PAGES, SDP_OP32);
set_usegd(&zero_udesc, SDP_LONG, 0, 0, SDT_MEMRWA, SEL_UPL,
SDP_BYTES, SDP_OP32);
set_usegd(&zero_u32desc, SDP_SHORT, 0, SDP_LIMIT_MAX, SDT_MEMRWA,
SEL_UPL, SDP_PAGES, SDP_OP32);
}
#if defined(__xpv)
static user_desc_t *
init_gdt(void)
{
uint64_t gdtpa;
ulong_t ma[1];
ulong_t addr;
#if !defined(__lint)
ASSERT((sizeof (*gdt0) * NGDT) <= PAGESIZE);
#endif
gdt0 = (user_desc_t *)BOP_ALLOC(bootops, (caddr_t)GDT_VA,
PAGESIZE, PAGESIZE);
ASSERT3P(gdt0, !=, NULL);
bzero(gdt0, PAGESIZE);
init_gdt_common(gdt0);
if (boothowto & RB_DEBUG) {
set_usegd(&gdt0[GDT_B32DATA], SDP_LONG, NULL, SDP_LIMIT_MAX,
SDT_MEMRWA, SEL_KPL, SDP_PAGES, SDP_OP32);
set_usegd(&gdt0[GDT_B64CODE], SDP_LONG, NULL, SDP_LIMIT_MAX,
SDT_MEMERA, SEL_KPL, SDP_PAGES, SDP_OP32);
}
gdtpa = pfn_to_pa(va_to_pfn(gdt0));
ma[0] = (ulong_t)(pa_to_ma(gdtpa) >> PAGESHIFT);
kbm_read_only((uintptr_t)gdt0, gdtpa);
xen_set_gdt(ma, NGDT);
load_segment_registers((KCS_SEL | SEL_KPL), KFS_SEL, KGS_SEL, KDS_SEL);
xen_set_segment_base(SEGBASE_GS_KERNEL, (ulong_t)&cpus[0]);
addr = 0x200000000ul;
xen_set_segment_base(SEGBASE_FS, addr);
xen_set_segment_base(SEGBASE_GS_USER, addr);
xen_set_segment_base(SEGBASE_GS_USER_SEL, 0);
return (gdt0);
}
#else
static user_desc_t *
init_gdt(void)
{
desctbr_t r_gdt;
#if !defined(__lint)
ASSERT((sizeof (*gdt0) * NGDT) <= PAGESIZE);
#endif
gdt0 = (user_desc_t *)BOP_ALLOC(bootops, (caddr_t)GDT_VA,
PAGESIZE, PAGESIZE);
bzero(gdt0, PAGESIZE);
init_gdt_common(gdt0);
r_gdt.dtr_limit = (sizeof (*gdt0) * NGDT) - 1;
r_gdt.dtr_base = (uintptr_t)gdt0;
wr_gdtr(&r_gdt);
load_segment_registers(KCS_SEL, KFS_SEL, KGS_SEL, KDS_SEL);
wrmsr(MSR_AMD_GSBASE, (uint64_t)&cpus[0]);
wrmsr(MSR_AMD_FSBASE, 0x200000000ul);
wrmsr(MSR_AMD_KGSBASE, 0x200000000ul);
return (gdt0);
}
#endif
static void
init_idt_common(gate_desc_t *idt)
{
set_gatesegd(&idt[T_ZERODIV],
(kpti_enable == 1) ? &tr_div0trap : &div0trap,
KCS_SEL, SDT_SYSIGT, TRP_KPL, idt_vector_to_ist(T_ZERODIV));
set_gatesegd(&idt[T_SGLSTP],
(kpti_enable == 1) ? &tr_dbgtrap : &dbgtrap,
KCS_SEL, SDT_SYSIGT, TRP_KPL, idt_vector_to_ist(T_SGLSTP));
set_gatesegd(&idt[T_NMIFLT],
(kpti_enable == 1) ? &tr_nmiint : &nmiint,
KCS_SEL, SDT_SYSIGT, TRP_KPL, idt_vector_to_ist(T_NMIFLT));
set_gatesegd(&idt[T_BPTFLT],
(kpti_enable == 1) ? &tr_brktrap : &brktrap,
KCS_SEL, SDT_SYSIGT, TRP_UPL, idt_vector_to_ist(T_BPTFLT));
set_gatesegd(&idt[T_OVFLW],
(kpti_enable == 1) ? &tr_ovflotrap : &ovflotrap,
KCS_SEL, SDT_SYSIGT, TRP_UPL, idt_vector_to_ist(T_OVFLW));
set_gatesegd(&idt[T_BOUNDFLT],
(kpti_enable == 1) ? &tr_boundstrap : &boundstrap,
KCS_SEL, SDT_SYSIGT, TRP_KPL, idt_vector_to_ist(T_BOUNDFLT));
set_gatesegd(&idt[T_ILLINST],
(kpti_enable == 1) ? &tr_invoptrap : &invoptrap,
KCS_SEL, SDT_SYSIGT, TRP_KPL, idt_vector_to_ist(T_ILLINST));
set_gatesegd(&idt[T_NOEXTFLT],
(kpti_enable == 1) ? &tr_ndptrap : &ndptrap,
KCS_SEL, SDT_SYSIGT, TRP_KPL, idt_vector_to_ist(T_NOEXTFLT));
#if !defined(__xpv)
set_gatesegd(&idt[T_DBLFLT],
(kpti_enable == 1) ? &tr_syserrtrap : &syserrtrap,
KCS_SEL, SDT_SYSIGT, TRP_KPL, idt_vector_to_ist(T_DBLFLT));
#endif
set_gatesegd(&idt[T_TSSFLT],
(kpti_enable == 1) ? &tr_invtsstrap : &invtsstrap,
KCS_SEL, SDT_SYSIGT, TRP_KPL, idt_vector_to_ist(T_TSSFLT));
set_gatesegd(&idt[T_SEGFLT],
(kpti_enable == 1) ? &tr_segnptrap : &segnptrap,
KCS_SEL, SDT_SYSIGT, TRP_KPL, idt_vector_to_ist(T_SEGFLT));
set_gatesegd(&idt[T_STKFLT],
(kpti_enable == 1) ? &tr_stktrap : &stktrap,
KCS_SEL, SDT_SYSIGT, TRP_KPL, idt_vector_to_ist(T_STKFLT));
set_gatesegd(&idt[T_GPFLT],
(kpti_enable == 1) ? &tr_gptrap : &gptrap,
KCS_SEL, SDT_SYSIGT, TRP_KPL, idt_vector_to_ist(T_GPFLT));
set_gatesegd(&idt[T_PGFLT],
(kpti_enable == 1) ? &tr_pftrap : &pftrap,
KCS_SEL, SDT_SYSIGT, TRP_KPL, idt_vector_to_ist(T_PGFLT));
set_gatesegd(&idt[T_EXTERRFLT],
(kpti_enable == 1) ? &tr_ndperr : &ndperr,
KCS_SEL, SDT_SYSIGT, TRP_KPL, idt_vector_to_ist(T_EXTERRFLT));
set_gatesegd(&idt[T_ALIGNMENT],
(kpti_enable == 1) ? &tr_achktrap : &achktrap,
KCS_SEL, SDT_SYSIGT, TRP_KPL, idt_vector_to_ist(T_ALIGNMENT));
set_gatesegd(&idt[T_MCE],
(kpti_enable == 1) ? &tr_mcetrap : &mcetrap,
KCS_SEL, SDT_SYSIGT, TRP_KPL, idt_vector_to_ist(T_MCE));
set_gatesegd(&idt[T_SIMDFPE],
(kpti_enable == 1) ? &tr_xmtrap : &xmtrap,
KCS_SEL, SDT_SYSIGT, TRP_KPL, idt_vector_to_ist(T_SIMDFPE));
set_gatesegd(&idt[T_FASTTRAP],
(kpti_enable == 1) ? &tr_fasttrap : &fasttrap,
KCS_SEL, SDT_SYSIGT, TRP_UPL, idt_vector_to_ist(T_FASTTRAP));
set_gatesegd(&idt[T_SYSCALLINT],
(kpti_enable == 1) ? &tr_sys_syscall_int : &sys_syscall_int,
KCS_SEL, SDT_SYSIGT, TRP_UPL, idt_vector_to_ist(T_SYSCALLINT));
set_gatesegd(&idt[T_DTRACE_RET],
(kpti_enable == 1) ? &tr_dtrace_ret : &dtrace_ret,
KCS_SEL, SDT_SYSIGT, TRP_UPL, idt_vector_to_ist(T_DTRACE_RET));
brand_tbl[0].ih_inum = T_SYSCALLINT;
brand_tbl[0].ih_default_desc = idt0[T_SYSCALLINT];
set_gatesegd(&(brand_tbl[0].ih_interp_desc),
(kpti_enable == 1) ? &tr_brand_sys_syscall_int :
&brand_sys_syscall_int, KCS_SEL, SDT_SYSIGT, TRP_UPL,
idt_vector_to_ist(T_SYSCALLINT));
brand_tbl[1].ih_inum = 0;
}
#if defined(__xpv)
static void
init_idt(gate_desc_t *idt)
{
init_idt_common(idt);
}
#else
static void
init_idt(gate_desc_t *idt)
{
char ivctname[80];
void (*ivctptr)(void);
int i;
for (i = 0; i < NIDT; i++) {
set_gatesegd(&idt[i],
(kpti_enable == 1) ? &tr_resvtrap : &resvtrap,
KCS_SEL, SDT_SYSIGT, TRP_KPL,
idt_vector_to_ist(T_RESVTRAP));
}
for (i = 20; i < 32; i++) {
set_gatesegd(&idt[i],
(kpti_enable == 1) ? &tr_invaltrap : &invaltrap,
KCS_SEL, SDT_SYSIGT, TRP_KPL,
idt_vector_to_ist(T_INVALTRAP));
}
for (i = 32; i < 256; i++) {
(void) snprintf(ivctname, sizeof (ivctname),
(kpti_enable == 1) ? "tr_ivct%d" : "ivct%d", i);
ivctptr = (void (*)(void))kobj_getsymvalue(ivctname, 0);
if (ivctptr == NULL)
panic("kobj_getsymvalue(%s) failed", ivctname);
set_gatesegd(&idt[i], ivctptr, KCS_SEL, SDT_SYSIGT, TRP_KPL,
idt_vector_to_ist(i));
}
init_idt_common(idt);
}
#endif
static void
init_ldt(void)
{
#if defined(__xpv)
xen_set_ldt(NULL, 0);
#else
wr_ldtr(0);
#endif
}
#if !defined(__xpv)
static void
init_tss(void)
{
extern struct cpu cpus[];
if (kpti_enable == 1) {
ktss0->tss_rsp0 = (uint64_t)&cpus->cpu_m.mcpu_kpti.kf_tr_rsp;
}
ktss0->tss_ist1 = (uintptr_t)&dblfault_stack0[sizeof (dblfault_stack0)];
ktss0->tss_ist2 = (uintptr_t)&nmi_stack0[sizeof (nmi_stack0)];
ktss0->tss_ist3 = (uintptr_t)&mce_stack0[sizeof (mce_stack0)];
ktss0->tss_ist4 = (uint64_t)&cpus->cpu_m.mcpu_kpti_dbg.kf_tr_rsp;
if (kpti_enable == 1) {
ktss0->tss_ist5 =
(uint64_t)&cpus->cpu_m.mcpu_kpti_flt.kf_tr_rsp;
ktss0->tss_ist6 = (uint64_t)&cpus->cpu_m.mcpu_kpti.kf_tr_rsp;
}
ktss0->tss_bitmapbase = sizeof (*ktss0);
wr_tsr(KTSS_SEL);
}
#endif
#if defined(__xpv)
void
init_desctbls(void)
{
uint_t vec;
user_desc_t *gdt;
gdt = init_gdt();
ASSERT(IS_P2ALIGNED((uintptr_t)gdt, PAGESIZE));
CPU->cpu_gdt = gdt;
CPU->cpu_m.mcpu_gdtpa = pfn_to_pa(va_to_pfn(gdt));
#if !defined(__lint)
ASSERT(NIDT * sizeof (*idt0) <= PAGESIZE);
#endif
idt0 = (gate_desc_t *)BOP_ALLOC(bootops, (caddr_t)IDT_VA,
PAGESIZE, PAGESIZE);
bzero(idt0, PAGESIZE);
init_idt(idt0);
for (vec = 0; vec < NIDT; vec++)
xen_idt_write(&idt0[vec], vec);
CPU->cpu_idt = idt0;
xen_stack_switch(KDS_SEL,
(ulong_t)&dblfault_stack0[sizeof (dblfault_stack0)]);
xen_init_callbacks();
init_ldt();
}
#else
void
init_desctbls(void)
{
user_desc_t *gdt;
desctbr_t idtr;
#if !defined(__lint)
ASSERT(NIDT * sizeof (*idt0) <= PAGESIZE);
#endif
idt0 = (gate_desc_t *)BOP_ALLOC(bootops, (caddr_t)IDT_VA,
PAGESIZE, PAGESIZE);
bzero(idt0, PAGESIZE);
#if !defined(__lint)
ASSERT(sizeof (*ktss0) <= PAGESIZE);
#endif
ktss0 = (tss_t *)BOP_ALLOC(bootops, (caddr_t)KTSS_VA,
PAGESIZE, PAGESIZE);
bzero(ktss0, PAGESIZE);
gdt = init_gdt();
ASSERT(IS_P2ALIGNED((uintptr_t)gdt, PAGESIZE));
CPU->cpu_gdt = gdt;
CPU->cpu_m.mcpu_ldt = BOP_ALLOC(bootops, (caddr_t)LDT_VA,
LDT_CPU_SIZE, PAGESIZE);
bzero(CPU->cpu_m.mcpu_ldt, LDT_CPU_SIZE);
CPU->cpu_m.mcpu_ldt_len = 0;
init_idt(idt0);
idtr.dtr_base = (uintptr_t)idt0;
idtr.dtr_limit = (NIDT * sizeof (*idt0)) - 1;
wr_idtr(&idtr);
CPU->cpu_idt = idt0;
init_tss();
CPU->cpu_tss = ktss0;
init_ldt();
kpti_safe_cr3 = (uint64_t)getcr3();
}
#endif
#ifndef __xpv
void
reset_gdtr_limit(void)
{
ulong_t flags = intr_clear();
desctbr_t gdtr;
rd_gdtr(&gdtr);
gdtr.dtr_limit = (sizeof (user_desc_t) * NGDT) - 1;
wr_gdtr(&gdtr);
intr_restore(flags);
}
#endif
void
init_boot_gdt(user_desc_t *bgdt)
{
ASSERT3P(bgdt, !=, NULL);
#ifdef __xpv
set_usegd(&bgdt[GDT_B32DATA], SDP_LONG, NULL, SDP_LIMIT_MAX, SDT_MEMRWA,
SEL_KPL, SDP_PAGES, SDP_OP32);
#else
set_usegd(&bgdt[GDT_B32DATA], SDP_SHORT, NULL, SDP_LIMIT_MAX,
SDT_MEMRWA, SEL_KPL, SDP_PAGES, SDP_OP32);
set_usegd(&bgdt[GDT_B32CODE], SDP_SHORT, NULL, SDP_LIMIT_MAX,
SDT_MEMERA, SEL_KPL, SDP_PAGES, SDP_OP32);
set_usegd(&bgdt[GDT_B16CODE], SDP_SHORT, NULL, SDP_LIMIT_MAX,
SDT_MEMERA, SEL_KPL, 0, 0);
set_usegd(&bgdt[GDT_B16DATA], SDP_SHORT, NULL, SDP_LIMIT_MAX,
SDT_MEMRWA, SEL_KPL, 0, SDP_OP32);
#endif
set_usegd(&bgdt[GDT_B64CODE], SDP_LONG, NULL, SDP_LIMIT_MAX, SDT_MEMERA,
SEL_KPL, SDP_PAGES, SDP_OP32);
}
void
brand_interpositioning_enable(void *arg __unused)
{
gate_desc_t *idt = CPU->cpu_idt;
int i;
ASSERT(curthread->t_preempt != 0 || getpil() >= DISP_LEVEL);
for (i = 0; brand_tbl[i].ih_inum; i++) {
idt[brand_tbl[i].ih_inum] = brand_tbl[i].ih_interp_desc;
#if defined(__xpv)
xen_idt_write(&idt[brand_tbl[i].ih_inum],
brand_tbl[i].ih_inum);
#endif
}
#if defined(__xpv)
xen_set_callback(brand_sys_syscall, CALLBACKTYPE_syscall,
CALLBACKF_mask_events);
#else
if (is_x86_feature(x86_featureset, X86FSET_ASYSC)) {
if (kpti_enable == 1) {
wrmsr(MSR_AMD_LSTAR, (uintptr_t)tr_brand_sys_syscall);
wrmsr(MSR_AMD_CSTAR, (uintptr_t)tr_brand_sys_syscall32);
} else {
wrmsr(MSR_AMD_LSTAR, (uintptr_t)brand_sys_syscall);
wrmsr(MSR_AMD_CSTAR, (uintptr_t)brand_sys_syscall32);
}
}
#endif
if (is_x86_feature(x86_featureset, X86FSET_SEP)) {
if (kpti_enable == 1) {
wrmsr(MSR_INTC_SEP_EIP,
(uintptr_t)tr_brand_sys_sysenter);
} else {
wrmsr(MSR_INTC_SEP_EIP, (uintptr_t)brand_sys_sysenter);
}
}
}
void
brand_interpositioning_disable(void *arg __unused)
{
gate_desc_t *idt = CPU->cpu_idt;
int i;
ASSERT(curthread->t_preempt != 0 || getpil() >= DISP_LEVEL);
for (i = 0; brand_tbl[i].ih_inum; i++) {
idt[brand_tbl[i].ih_inum] = brand_tbl[i].ih_default_desc;
#if defined(__xpv)
xen_idt_write(&idt[brand_tbl[i].ih_inum],
brand_tbl[i].ih_inum);
#endif
}
#if defined(__xpv)
xen_set_callback(sys_syscall, CALLBACKTYPE_syscall,
CALLBACKF_mask_events);
#else
if (is_x86_feature(x86_featureset, X86FSET_ASYSC)) {
if (kpti_enable == 1) {
wrmsr(MSR_AMD_LSTAR, (uintptr_t)tr_sys_syscall);
wrmsr(MSR_AMD_CSTAR, (uintptr_t)tr_sys_syscall32);
} else {
wrmsr(MSR_AMD_LSTAR, (uintptr_t)sys_syscall);
wrmsr(MSR_AMD_CSTAR, (uintptr_t)sys_syscall32);
}
}
#endif
if (is_x86_feature(x86_featureset, X86FSET_SEP)) {
if (kpti_enable == 1) {
wrmsr(MSR_INTC_SEP_EIP, (uintptr_t)tr_sys_sysenter);
} else {
wrmsr(MSR_INTC_SEP_EIP, (uintptr_t)sys_sysenter);
}
}
}