--- old/usr/src/uts/Makefile.uts	Wed Oct  9 03:12:25 2019
+++ new/usr/src/uts/Makefile.uts	Wed Oct  9 03:12:25 2019
@@ -249,6 +249,16 @@
 CFLAGS_uts_i386 += -_gcc8=-fno-shrink-wrap
 CFLAGS_uts_i386 += -_gcc9=-fno-shrink-wrap
 
+#
+# retpoline support
+#
+CFLAGS_uts_i386 += -_gcc7=-mindirect-branch=thunk-extern
+CFLAGS_uts_i386 += -_gcc7=-mindirect-branch-register
+CFLAGS_uts_i386 += -_gcc8=-mindirect-branch=thunk-extern
+CFLAGS_uts_i386 += -_gcc8=-mindirect-branch-register
+CFLAGS_uts_i386 += -_gcc9=-mindirect-branch=thunk-extern
+CFLAGS_uts_i386 += -_gcc9=-mindirect-branch-register
+
 CSTD = $(CSTD_GNU99)
 
 CFLAGS_uts		=
--- old/usr/src/uts/common/mapfiles/ddi.mapfile	Wed Oct  9 03:12:25 2019
+++ new/usr/src/uts/common/mapfiles/ddi.mapfile	Wed Oct  9 03:12:25 2019
@@ -40,6 +40,22 @@
 	__divdi3			{ FLAGS = EXTERN };
 	__stack_chk_fail		{ FLAGS = EXTERN };
 	__stack_chk_guard		{ FLAGS = EXTERN };
+	__x86_indirect_thunk		{ FLAGS = EXTERN };
+	__x86_indirect_thunk_r10	{ FLAGS = EXTERN };
+	__x86_indirect_thunk_r11	{ FLAGS = EXTERN };
+	__x86_indirect_thunk_r12	{ FLAGS = EXTERN };
+	__x86_indirect_thunk_r13	{ FLAGS = EXTERN };
+	__x86_indirect_thunk_r14	{ FLAGS = EXTERN };
+	__x86_indirect_thunk_r15	{ FLAGS = EXTERN };
+	__x86_indirect_thunk_r8		{ FLAGS = EXTERN };
+	__x86_indirect_thunk_r9		{ FLAGS = EXTERN };
+	__x86_indirect_thunk_rax	{ FLAGS = EXTERN };
+	__x86_indirect_thunk_rbp	{ FLAGS = EXTERN };
+	__x86_indirect_thunk_rbx	{ FLAGS = EXTERN };
+	__x86_indirect_thunk_rcx	{ FLAGS = EXTERN };
+	__x86_indirect_thunk_rdi	{ FLAGS = EXTERN };
+	__x86_indirect_thunk_rdx	{ FLAGS = EXTERN };
+	__x86_indirect_thunk_rsi	{ FLAGS = EXTERN };
 	allocb				{ FLAGS = EXTERN };
 	assfail				{ FLAGS = EXTERN };
 	assfail3			{ FLAGS = EXTERN };
--- old/usr/src/uts/i86pc/ml/cpr_wakecode.s	Wed Oct  9 03:12:26 2019
+++ new/usr/src/uts/i86pc/ml/cpr_wakecode.s	Wed Oct  9 03:12:26 2019
@@ -20,8 +20,9 @@
  */
 /*
  * Copyright (c) 2007, 2010, Oracle and/or its affiliates. All rights reserved.
+ * Copyright 2019 Joyent, Inc.
  */
-	
+
 #include <sys/asm_linkage.h>
 #include <sys/asm_misc.h>
 #include <sys/regset.h>
@@ -339,7 +340,7 @@
 #endif
 
 	/*
- 	 * Add any initial cr4 bits
+	 * Add any initial cr4 bits
 	 */
 	movl		%cr4, %eax
 	A16 D16 orl	CR4OFF, %eax
@@ -434,7 +435,7 @@
 
 
 	/*
- 	 * Do a far transfer to 64-bit mode.  Set the CS selector to a 64-bit
+	 * Do a far transfer to 64-bit mode.  Set the CS selector to a 64-bit
 	 * long mode selector (CS.L=1) in the temporary 32-bit GDT and jump
 	 * to the real mode platter address of wc_long_mode_64 as until the
 	 * 64-bit CS is in place we don't have access to 64-bit instructions
@@ -453,7 +454,7 @@
 	outb    (%dx)
 #endif
 
-	D16 	pushl 	$TEMP_CS64_SEL
+	D16	pushl	$TEMP_CS64_SEL
 	A16 D16 pushl	LM64OFF
 
 	D16 lret
@@ -476,7 +477,7 @@
  */
 cominit:
 	/ init COM1 & COM2
-	
+
 #if     DEBUG
 /*
  * on debug kernels we need to initialize COM1 & COM2 here, so that
@@ -678,7 +679,7 @@
 	addq	WC_GDT+2(%rbx), %rax
 	andl	$0xfffffdff, 4(%rax)
 	movq	4(%rax), %rcx
-	ltr	WC_TR(%rbx)		
+	ltr	WC_TR(%rbx)
 
 #if     LED
 	movw        $WC_LED, %dx
@@ -701,7 +702,7 @@
 	movl    WC_FSBASE(%rbx), %eax
 	movl    WC_FSBASE+4(%rbx), %edx
 	wrmsr
-	
+
 	movq    WC_GS(%rbx), %rcx	/ restore gs register
 	movw    %cx, %gs
 
@@ -760,10 +761,12 @@
 	 */
 	cmpq	$0, ap_mlsetup
 	je	3f
-	call	*ap_mlsetup
+	leaq	ap_mlsetup, %rax
+	INDIRECT_CALL_REG(rax)
 3:
 
-	call    *cpr_start_cpu_func
+	leaq	cpr_start_cpu_func, %rax
+	INDIRECT_CALL_REG(rax)
 
 / restore %rbx to the value it ahd before we called the functions above
 	movq    rm_platter_va, %rbx
@@ -1058,7 +1061,7 @@
 	/ At this point we are with kernel's cs and proper eip.
 	/ We will be executing not from the copy in real mode platter,
 	/ but from the original code where boot loaded us.
-	/ By this time GDT and IDT are loaded as is cr0, cr3 and cr4. 
+	/ By this time GDT and IDT are loaded as is cr0, cr3 and cr4.
 	/ %ebx is wc_cpu
 	/ %dx is our ds
 
@@ -1106,7 +1109,7 @@
 
 	/*
 	 * set the stack pointer to point into the identity mapped page
-	 * temporarily, so we can make function calls 
+	 * temporarily, so we can make function calls
 	 */
 	.globl  rm_platter_va
 	movl    rm_platter_va, %eax
@@ -1142,7 +1145,7 @@
 	call	*ap_mlsetup
 3:
 
-	call    *cpr_start_cpu_func
+	call	*cpr_start_cpu_func
 
 	pushl	WC_EFLAGS(%ebx)		/ restore flags
 	popfl
--- old/usr/src/uts/i86pc/ml/fast_trap_asm.s	Wed Oct  9 03:12:26 2019
+++ new/usr/src/uts/i86pc/ml/fast_trap_asm.s	Wed Oct  9 03:12:26 2019
@@ -21,10 +21,9 @@
 /*
  * Copyright 2007 Sun Microsystems, Inc.  All rights reserved.
  * Use is subject to license terms.
+ * Copyright 2019 Joyent, Inc.
  */
 
-#pragma ident	"%Z%%M%	%I%	%E% SMI"
-
 #include <sys/asm_linkage.h>
 #include <sys/asm_misc.h>
 #include <sys/regset.h>
@@ -101,7 +100,8 @@
 	.globl	gethrtimef
 	ENTRY_NP(get_hrtime)
 	FAST_INTR_PUSH
-	call	*gethrtimef(%rip)
+	movq	gethrtimef(%rip), %rax
+	INDIRECT_CALL_REG(rax)
 	movq	%rax, %rdx
 	shrq	$32, %rdx			/* high 32-bit in %edx */
 	FAST_INTR_POP
@@ -127,7 +127,8 @@
 	FAST_INTR_PUSH
 	subq	$TIMESPEC_SIZE, %rsp
 	movq	%rsp, %rdi
-	call	*gethrestimef(%rip)
+	movq	gethrestimef(%rip), %rax
+	INDIRECT_CALL_REG(rax)
 	movl	(%rsp), %eax
 	movl	CLONGSIZE(%rsp), %edx
 	addq	$TIMESPEC_SIZE, %rsp
--- old/usr/src/uts/i86pc/ml/interrupt.s	Wed Oct  9 03:12:26 2019
+++ new/usr/src/uts/i86pc/ml/interrupt.s	Wed Oct  9 03:12:26 2019
@@ -20,6 +20,7 @@
  */
 /*
  * Copyright (c) 2004, 2010, Oracle and/or its affiliates. All rights reserved.
+ * Copyright 2019 Joyent, Inc.
  */
 
 /*	Copyright (c) 1990, 1991 UNIX System Laboratories, Inc.	*/
@@ -99,7 +100,8 @@
 #endif
 
 	movq	%rsp, %rdi		/* pass struct regs pointer */
-	call	*do_interrupt_common
+	movq	do_interrupt_common, %rax
+	INDIRECT_CALL_REG(rax)
 
 	jmp	_sys_rtt_ints_disabled
 	/*NOTREACHED*/
--- old/usr/src/uts/i86pc/ml/locore.s	Wed Oct  9 03:12:27 2019
+++ new/usr/src/uts/i86pc/ml/locore.s	Wed Oct  9 03:12:27 2019
@@ -1191,7 +1191,7 @@
 	addq	%rax, %r12
 	movq	%r12, REGOFF_RIP(%rbp)
 	INTR_POP
-	call	*x86_md_clear
+	call	x86_md_clear
 	jmp	tr_iret_auto
 	/*NOTREACHED*/
 3:
@@ -1597,7 +1597,7 @@
 	 */
 	ALTENTRY(sys_rtt_syscall32)
 	USER32_POP
-	call	*x86_md_clear
+	call	x86_md_clear
 	jmp	tr_iret_user
 	/*NOTREACHED*/
 
@@ -1607,7 +1607,7 @@
 	 */
 	USER_POP
 	ALTENTRY(nopop_sys_rtt_syscall)
-	call	*x86_md_clear
+	call	x86_md_clear
 	jmp	tr_iret_user
 	/*NOTREACHED*/
 	SET_SIZE(nopop_sys_rtt_syscall)
--- old/usr/src/uts/i86pc/ml/md_clear.s	Wed Oct  9 03:12:27 2019
+++ new/usr/src/uts/i86pc/ml/md_clear.s	Wed Oct  9 03:12:27 2019
@@ -42,15 +42,17 @@
  *    this are either going to change privilege levels or halt, which makes
  *    these operations safer.
  */
-	ENTRY_NP(x86_md_clear_noop)
-	ret
-	SET_SIZE(x86_md_clear_noop)
 
 	/*
-	 * This uses the microcode based means of flushing state. VERW will
-	 * clobber flags.
+	 * By default, x86_md_clear is disabled until the system determines that
+	 * it both needs MDS related mitigations and we have microcode that
+	 * provides the needed functionality.
+	 *
+	 * The VERW instruction clobbers flags which is why it's important that
+	 * we save and restore them here.
 	 */
-	ENTRY_NP(x86_md_clear_verw)
+	ENTRY_NP(x86_md_clear)
+	ret
 	pushfq
 	subq	$8, %rsp
 	mov	%ds, (%rsp)
@@ -58,4 +60,4 @@
 	addq	$8, %rsp
 	popfq
 	ret
-	SET_SIZE(x86_md_clear_verw)
+	SET_SIZE(x86_md_clear)
--- old/usr/src/uts/i86pc/ml/mpcore.s	Wed Oct  9 03:12:28 2019
+++ new/usr/src/uts/i86pc/ml/mpcore.s	Wed Oct  9 03:12:28 2019
@@ -25,9 +25,9 @@
  * Copyright (c) 2010, Intel Corporation.
  * All rights reserved.
  *
- * Copyright 2018 Joyent, Inc.
+ * Copyright 2019 Joyent, Inc.
  */
-	
+
 #include <sys/asm_linkage.h>
 #include <sys/asm_misc.h>
 #include <sys/regset.h>
@@ -87,7 +87,7 @@
 	 *	  prefixes need not be used on instructions EXCEPT in the case
 	 *	  of address prefixes for code for which the reference is not
 	 *	  automatically of the default operand size.
-	 */      
+	 */
 	.code16
 	cli
 	movw		%cs, %ax
@@ -116,7 +116,7 @@
 
 pestart:
 	/*
- 	 * 16-bit protected mode is now active, so prepare to turn on long
+	 * 16-bit protected mode is now active, so prepare to turn on long
 	 * mode.
 	 *
 	 * Note that we currently assume that if we're attempting to run a
@@ -135,7 +135,7 @@
 	cpuid
 	cmpl		$0x80000000, %eax	/* check if > 0x80000000 */
 	jbe		no_long_mode		/* nope, no long mode */
-	movl		$0x80000001, %eax	
+	movl		$0x80000001, %eax
 	cpuid					/* get extended feature flags */
 	btl		$29, %edx		/* check for long mode */
 	jnc		no_long_mode		/* long mode not supported */
@@ -142,7 +142,7 @@
 #endif
 
 	/*
- 	 * Add any initial cr4 bits
+	 * Add any initial cr4 bits
 	 */
 	movl		%cr4, %eax
 	addr32 orl	CR4OFF, %eax
@@ -198,13 +198,13 @@
 	addr32 lidtl	TEMPIDTOFF	/* load temporary IDT */
 
 	/*
- 	 * Do a far transfer to 64-bit mode.  Set the CS selector to a 64-bit
+	 * Do a far transfer to 64-bit mode.  Set the CS selector to a 64-bit
 	 * long mode selector (CS.L=1) in the temporary 32-bit GDT and jump
 	 * to the real mode platter address of long_mode 64 as until the 64-bit
 	 * CS is in place we don't have access to 64-bit instructions and thus
 	 * can't reference a 64-bit %rip.
 	 */
-	pushl 		$TEMP_CS64_SEL
+	pushl		$TEMP_CS64_SEL
 	addr32 pushl	LM64OFF
 	lretl
 
@@ -313,7 +313,7 @@
 	movq    %rax, %cr0		/* set machine status word */
 
 	/*
-	 * Before going any further, enable usage of page table NX bit if 
+	 * Before going any further, enable usage of page table NX bit if
 	 * that's how our page tables are set up.
 	 */
 	bt	$X86FSET_NX, x86_featureset(%rip)
@@ -328,7 +328,8 @@
 	 * Complete the rest of the setup and call mp_startup().
 	 */
 	movq	%gs:CPU_THREAD, %rax	/* get thread ptr */
-	call	*T_PC(%rax)		/* call mp_startup_boot */
+	movq	T_PC(%rax), %rax
+	INDIRECT_CALL_REG(rax)		/* call mp_startup_boot */
 	/* not reached */
 	int	$20			/* whoops, returned somehow! */
 
@@ -352,8 +353,8 @@
 	 */
 	D16 movl	$0xffc, %esp
 
- 	D16 A16 lgdt	%cs:GDTROFF
- 	D16 A16 lidt	%cs:IDTROFF
+	D16 A16 lgdt	%cs:GDTROFF
+	D16 A16 lidt	%cs:IDTROFF
 	D16 A16 movl	%cs:CR4OFF, %eax	/* set up CR4, if desired */
 	D16 andl	%eax, %eax
 	D16 A16 je	no_cr4
@@ -412,7 +413,7 @@
 	movl    %edx,%cr0		  /* set machine status word */
 
 	/*
-	 * Before going any further, enable usage of page table NX bit if 
+	 * Before going any further, enable usage of page table NX bit if
 	 * that's how our page tables are set up.
 	 */
 	bt	$X86FSET_NX, x86_featureset
@@ -503,7 +504,7 @@
 	mov	%edx, %cr0		/* set machine status word */
 
 	/*
-	 * Before going any farther, enable usage of page table NX bit if 
+	 * Before going any farther, enable usage of page table NX bit if
 	 * that's how our page tables are set up.  (PCIDE is enabled later on).
 	 */
 	bt	$X86FSET_NX, x86_featureset
@@ -558,7 +559,7 @@
 	 *	  prefixes need not be used on instructions EXCEPT in the case
 	 *	  of address prefixes for code for which the reference is not
 	 *	  automatically of the default operand size.
-	 */      
+	 */
 	.code16
 	cli
 	movw		%cs, %ax
@@ -607,6 +608,12 @@
 	 * Jump to the stage 2 code in the rm_platter_va->rm_cpu_halt_code
 	 */
 	movw		$CPUHALTCODEOFF, %ax
+	/*
+	 * The following indirect call is executed as part of starting up a CPU.
+	 * As such nothing else should be running on it or executing in the
+	 * system such that it is a viable Spectre v2 branch target injection
+	 * location. At least, in theory.
+	 */
 	jmp		*%ax
 
 #endif	/* !__GNUC_AS__ */
--- old/usr/src/uts/i86pc/ml/syscall_asm_amd64.s	Wed Oct  9 03:12:28 2019
+++ new/usr/src/uts/i86pc/ml/syscall_asm_amd64.s	Wed Oct  9 03:12:28 2019
@@ -199,7 +199,8 @@
 	je	1f							   ;\
 	movq	%r15, 16(%rsp)		/* save the callback pointer	*/ ;\
 	push_userland_ret		/* push the return address	*/ ;\
-	call	*24(%rsp)		/* call callback		*/ ;\
+	movq	24(%rsp), %r15		/* load callback pointer	*/ ;\
+	INDIRECT_CALL_REG(r15)		/* call callback		*/ ;\
 1:	movq	%gs:CPU_RTMP_R15, %r15	/* restore %r15			*/ ;\
 	movq	%gs:CPU_RTMP_RSP, %rsp	/* restore the stack pointer	*/
 
@@ -575,7 +576,8 @@
 	shll	$SYSENT_SIZE_SHIFT, %eax
 	leaq	sysent(%rax), %rbx
 
-	call	*SY_CALLC(%rbx)
+	movq	SY_CALLC(%rbx), %rax
+	INDIRECT_CALL_REG(rax)
 
 	movq	%rax, %r12
 	movq	%rdx, %r13
@@ -651,7 +653,7 @@
 	 * potentially the addresses where we stored them. Given the constraints
 	 * of sysret, that's how it has to be.
 	 */
-	call	*x86_md_clear
+	call	x86_md_clear
 
 	/*
 	 * To get back to userland, we need the return %rip in %rcx and
@@ -902,7 +904,8 @@
 	movl	0x20(%rsp), %r8d
 	movl	0x28(%rsp), %r9d
 
-	call	*SY_CALLC(%rbx)
+	movq	SY_CALLC(%rbx), %rax
+	INDIRECT_CALL_REG(rax)
 
 	movq	%rbp, %rsp	/* pop the args */
 
@@ -949,7 +952,7 @@
 	 * potentially the addresses where we stored them. Given the constraints
 	 * of sysret, that's how it has to be.
 	 */
-	call	*x86_md_clear
+	call	x86_md_clear
 
 	/*
 	 * To get back to userland, we need to put the return %rip in %rcx and
@@ -1189,7 +1192,8 @@
 	movl	0x20(%rsp), %r8d
 	movl	0x28(%rsp), %r9d
 
-	call	*SY_CALLC(%rbx)
+	movq	SY_CALLC(%rbx), %rax
+	INDIRECT_CALL_REG(rax)
 
 	movq	%rbp, %rsp	/* pop the args */
 
@@ -1257,7 +1261,7 @@
 	popfq
 	movl	REGOFF_RSP(%rsp), %ecx	/* sysexit: %ecx -> %esp */
         ALTENTRY(sys_sysenter_swapgs_sysexit)
-	call	*x86_md_clear
+	call	x86_md_clear
 	jmp	tr_sysexit
 	SET_SIZE(sys_sysenter_swapgs_sysexit)
 	SET_SIZE(sys_sysenter)
@@ -1314,7 +1318,7 @@
 	 * tr_iret_user are done on the user gsbase.
 	 */
 	ALTENTRY(sys_sysint_swapgs_iret)
-	call	*x86_md_clear
+	call	x86_md_clear
 	SWAPGS
 	jmp	tr_iret_user
 	/*NOTREACHED*/
--- old/usr/src/uts/i86pc/os/cpuid.c	Wed Oct  9 03:12:29 2019
+++ new/usr/src/uts/i86pc/os/cpuid.c	Wed Oct  9 03:12:29 2019
@@ -897,6 +897,281 @@
  * microcode, and performance monitoring. These functions all ASSERT that the
  * CPU they're being called on has reached a certain cpuid pass. If the passes
  * are rearranged, then this needs to be adjusted.
+ *
+ * -----------------------------------------------
+ * Speculative Execution CPU Side Channel Security
+ * -----------------------------------------------
+ *
+ * With the advent of the Spectre and Meltdown attacks which exploit speculative
+ * execution in the CPU to create side channels there have been a number of
+ * different attacks and corresponding issues that the operating system needs to
+ * mitigate against. The following list is some of the common, but not
+ * exhaustive, set of issues that we know about and have done some or need to do
+ * more work in the system to mitigate against:
+ *
+ *   - Spectre v1
+ *   - Spectre v2
+ *   - Meltdown (Spectre v3)
+ *   - Rogue Register Read (Spectre v3a)
+ *   - Speculative Store Bypass (Spectre v4)
+ *   - ret2spec, SpectreRSB
+ *   - L1 Terminal Fault (L1TF)
+ *   - Microarchitectural Data Sampling (MDS)
+ *
+ * Each of these requires different sets of mitigations and has different attack
+ * surfaces. For the most part, this discussion is about protecting the kernel
+ * from non-kernel executing environments such as user processes and hardware
+ * virtual machines. Unfortunately, there are a number of user vs. user
+ * scenarios that exist with these. The rest of this section will describe the
+ * overall approach that the system has taken to address these as well as their
+ * shortcomings. Unfortunately, not all of the above have been handled today.
+ *
+ * SPECTRE FAMILY (Spectre v2, ret2spec, SpectreRSB)
+ *
+ * The second variant of the spectre attack focuses on performing branch target
+ * injection. This generally impacts indirect call instructions in the system.
+ * There are three different ways to mitigate this issue that are commonly
+ * described today:
+ *
+ *  1. Using Indirect Branch Restricted Speculation (IBRS).
+ *  2. Using Retpolines and RSB Stuffing
+ *  3. Using Enhanced Indirect Branch Restricted Speculation (EIBRS)
+ *
+ * IBRS uses a feature added to microcode to restrict speculation, among other
+ * things. This form of mitigation has not been used as it has been generally
+ * seen as too expensive and requires reactivation upon various transitions in
+ * the system.
+ *
+ * As a less impactful alternative to IBRS, retpolines were developed by
+ * Google. These basically require one to replace indirect calls with a specific
+ * trampoline that will cause speculation to fail and break the attack.
+ * Retpolines require compiler support. We always build with retpolines in the
+ * external thunk mode. This means that a traditional indirect call is replaced
+ * with a call to one of the __x86_indirect_thunk_<reg> functions. A side effect
+ * of this is that all indirect function calls are performed through a register.
+ *
+ * We have to use a common external location of the thunk and not inline it into
+ * the callsite so that way we can have a single place to patch these functions.
+ * As it turns out, we actually have three different forms of retpolines that
+ * exist in the system:
+ *
+ *  1. A full retpoline
+ *  2. An AMD-specific optimized retpoline
+ *  3. A no-op version
+ *
+ * The first one is used in the general case. The second one is used if we can
+ * determine that we're on an AMD system and we can successfully toggle the
+ * lfence serializing MSR that exists on the platform. Basically with this
+ * present, an lfence is sufficient and we don't need to do anywhere near as
+ * complicated a dance to successfully use retpolines.
+ *
+ * The third form described above is the most curious. It turns out that the way
+ * that retpolines are implemented is that they rely on how speculation is
+ * performed on a 'ret' instruction. Intel has continued to optimize this
+ * process (which is partly why we need to have return stack buffer stuffing,
+ * but more on that in a bit) and in processors starting with Cascade Lake
+ * on the server side, it's dangerous to rely on retpolines. Instead, a new
+ * mechanism has been introduced called Enhanced IBRS (EIBRS).
+ *
+ * Unlike IBRS, EIBRS is designed to be enabled once at boot and left on each
+ * physical core. However, if this is the case, we don't want to use retpolines
+ * any more. Therefore if EIBRS is present, we end up turning each retpoline
+ * function (called a thunk) into a jmp instruction. This means that we're still
+ * paying the cost of an extra jump to the external thunk, but it gives us
+ * flexibility and the ability to have a single kernel image that works across a
+ * wide variety of systems and hardware features.
+ *
+ * Unfortunately, this alone is insufficient. First, Skylake systems have
+ * additional speculation for the Return Stack Buffer (RSB) which is used to
+ * return from call instructions which retpolines take advantage of. However,
+ * this problem is not just limited to Skylake and is actually more pernicious.
+ * The SpectreRSB paper introduces several more problems that can arise with
+ * dealing with this. The RSB can be poisoned just like the indirect branch
+ * predictor. This means that one needs to clear the RSB when transitioning
+ * between two different privilege domains. Some examples include:
+ *
+ *  - Switching between two different user processes
+ *  - Going between user land and the kernel
+ *  - Returning to the kernel from a hardware virtual machine
+ *
+ * Mitigating this involves combining a couple of different things. The first is
+ * SMEP (supervisor mode execution protection) which was introduced in Ivy
+ * Bridge. When an RSB entry refers to a user address and we're executing in the
+ * kernel, speculation through it will be stopped when SMEP is enabled. This
+ * protects against a number of the different cases that we would normally be
+ * worried about such as when we enter the kernel from user land.
+ *
+ * To prevent against additional manipulation of the RSB from other contexts
+ * such as a non-root VMX context attacking the kernel we first look to enhanced
+ * IBRS. When EIBRS is present and enabled, then there is nothing else that we
+ * need to do to protect the kernel at this time.
+ *
+ * On CPUs without EIBRS we need to manually overwrite the contents of the
+ * return stack buffer. We do this through the x86_rsb_stuff() function.
+ * Currently this is employed on context switch. The x86_rsb_stuff() function is
+ * disabled when enhanced IBRS is present because Intel claims on such systems
+ * it will be ineffective. Stuffing the RSB in context switch helps prevent user
+ * to user attacks via the RSB.
+ *
+ * If SMEP is not present, then we would have to stuff the RSB every time we
+ * transitioned from user mode to the kernel, which isn't very practical right
+ * now.
+ *
+ * To fully protect user to user and vmx to vmx attacks from these classes of
+ * issues, we would also need to allow them to opt into performing an Indirect
+ * Branch Prediction Barrier (IBPB) on switch. This is not currently wired up.
+ *
+ * By default, the system will enable RSB stuffing and the required variant of
+ * retpolines and store that information in the x86_spectrev2_mitigation value.
+ * This will be evaluated after a microcode update as well, though it is
+ * expected that microcode updates will not take away features. This may mean
+ * that a late loaded microcode may not end up in the optimal configuration
+ * (though this should be rare).
+ *
+ * Currently we do not build kmdb with retpolines or perform any additional side
+ * channel security mitigations for it. One complication with kmdb is that it
+ * requires its own retpoline thunks and it would need to adjust itself based on
+ * what the kernel does. The threat model of kmdb is more limited and therefore
+ * it may make more sense to investigate using prediction barriers as the whole
+ * system is only executing a single instruction at a time while in kmdb.
+ *
+ * SPECTRE FAMILY (v1, v4)
+ *
+ * The v1 and v4 variants of spectre are not currently mitigated in the
+ * system and require other classes of changes to occur in the code.
+ *
+ * MELTDOWN
+ *
+ * Meltdown, or spectre v3, allowed a user process to read any data in their
+ * address space regardless of whether or not the page tables in question
+ * allowed the user to have the ability to read them. The solution to meltdown
+ * is kernel page table isolation. In this world, there are two page tables that
+ * are used for a process, one in user land and one in the kernel. To implement
+ * this we use per-CPU page tables and switch between the user and kernel
+ * variants when entering and exiting the kernel.  For more information about
+ * this process and how the trampolines work, please see the big theory
+ * statements and additional comments in:
+ *
+ *  - uts/i86pc/ml/kpti_trampolines.s
+ *  - uts/i86pc/vm/hat_i86.c
+ *
+ * While Meltdown only impacted Intel systems and there are also Intel systems
+ * that have Meltdown fixed (called Rogue Data Cache Load), we always have
+ * kernel page table isolation enabled. While this may at first seem weird, an
+ * important thing to remember is that you can't speculatively read an address
+ * if it's never in your page table at all. Having user processes without kernel
+ * pages present provides us with an important layer of defense in the kernel
+ * against any other side channel attacks that exist and have yet to be
+ * discovered. As such, kernel page table isolation (KPTI) is always enabled by
+ * default, no matter the x86 system.
+ *
+ * L1 TERMINAL FAULT
+ *
+ * L1 Terminal Fault (L1TF) takes advantage of an issue in how speculative
+ * execution uses page table entries. Effectively, it is two different problems.
+ * The first is that it ignores the not present bit in the page table entries
+ * when performing speculative execution. This means that something can
+ * speculatively read the listed physical address if it's present in the L1
+ * cache under certain conditions (see Intel's documentation for the full set of
+ * conditions). Secondly, this can be used to bypass hardware virtualization
+ * extended page tables (EPT) that are part of Intel's hardware virtual machine
+ * instructions.
+ *
+ * For the non-hardware virtualized case, this is relatively easy to deal with.
+ * We must make sure that all unmapped pages have an address of zero. This means
+ * that they could read the first 4k of physical memory; however, we never use
+ * that first page in the operating system and always skip putting it in our
+ * memory map, even if firmware tells us we can use it in our memory map. While
+ * other systems try to put extra metadata in the address and reserved bits,
+ * which led to this being problematic in those cases, we do not.
+ *
+ * For hardware virtual machines things are more complicated. Because they can
+ * construct their own page tables, it isn't hard for them to perform this
+ * attack against any physical address. The one wrinkle is that this physical
+ * address must be in the L1 data cache. Thus Intel added an MSR that we can use
+ * to flush the L1 data cache. We wrap this up in the function
+ * spec_uarch_flush(). This function is also used in the mitigation of
+ * microarchitectural data sampling (MDS) discussed later on. Kernel based
+ * hypervisors such as KVM or bhyve are responsible for performing this before
+ * entering the guest.
+ *
+ * Because this attack takes place in the L1 cache, there's another wrinkle
+ * here. The L1 cache is shared between all logical CPUs in a core in most Intel
+ * designs. This means that when a thread enters a hardware virtualized context
+ * and flushes the L1 data cache, the other thread on the processor may then go
+ * ahead and put new data in it that can be potentially attacked. While one
+ * solution is to disable SMT on the system, another option that is available is
+ * to use a feature for hardware virtualization called 'SMT exclusion'. This
+ * goes through and makes sure that if a HVM is being scheduled on one thread,
+ * then the thing on the other thread is from the same hardware virtual machine.
+ * If an interrupt comes in or the guest exits to the broader system, then the
+ * other SMT thread will be kicked out.
+ *
+ * L1TF can be fully mitigated by hardware. If the RDCL_NO feature is set in the
+ * architecture capabilities MSR (MSR_IA32_ARCH_CAPABILITIES), then we will not
+ * perform L1TF related mitigations.
+ *
+ * MICROARCHITECTURAL DATA SAMPLING
+ *
+ * Microarchitectural data sampling (MDS) is a combination of four discrete
+ * vulnerabilities that are similar issues affecting various parts of the CPU's
+ * microarchitectural implementation around load, store, and fill buffers.
+ * Specifically it is made up of the following subcomponents:
+ *
+ *  1. Microarchitectural Store Buffer Data Sampling (MSBDS)
+ *  2. Microarchitectural Fill Buffer Data Sampling (MFBDS)
+ *  3. Microarchitectural Load Port Data Sampling (MLPDS)
+ *  4. Microarchitectural Data Sampling Uncacheable Memory (MDSUM)
+ *
+ * To begin addressing these, Intel has introduced another feature in microcode
+ * called MD_CLEAR. This changes the verw instruction to operate in a different
+ * way. This allows us to execute the verw instruction in a particular way to
+ * flush the state of the affected parts. The L1TF L1D flush mechanism is also
+ * updated when this microcode is present to flush this state.
+ *
+ * Primarily we need to flush this state whenever we transition from the kernel
+ * to a less privileged context such as user mode or an HVM guest. MSBDS is a
+ * little bit different. Here the structures are statically sized when a logical
+ * CPU is in use and resized when it goes to sleep. Therefore, we also need to
+ * flush the microarchitectural state before the CPU goes idles by calling hlt,
+ * mwait, or another ACPI method. To perform these flushes, we call
+ * x86_md_clear() at all of these transition points.
+ *
+ * If hardware enumerates RDCL_NO, indicating that it is not vulnerable to L1TF,
+ * then we change the spec_uarch_flush() function to point to x86_md_clear(). If
+ * MDS_NO has been set, then this is fully mitigated and x86_md_clear() becomes
+ * a no-op.
+ *
+ * Unfortunately, with this issue hyperthreading rears its ugly head. In
+ * particular, everything we've discussed above is only valid for a single
+ * thread executing on a core. In the case where you have hyper-threading
+ * present, this attack can be performed between threads. The theoretical fix
+ * for this is to ensure that both threads are always in the same security
+ * domain. This means that they are executing in the same ring and mutually
+ * trust each other. Practically speaking, this would mean that a system call
+ * would have to issue an inter-processor interrupt (IPI) to the other thread.
+ * Rather than implement this, we recommend that one disables hyper-threading
+ * through the use of psradm -aS.
+ *
+ * SUMMARY
+ *
+ * The following table attempts to summarize the mitigations for various issues
+ * and what's done in various places:
+ *
+ *  - Spectre v1: Not currently mitigated
+ *  - Spectre v2: Retpolines/RSB Stuffing or EIBRS if HW support
+ *  - Meltdown: Kernel Page Table Isolation
+ *  - Spectre v3a: Updated CPU microcode
+ *  - Spectre v4: Not currently mitigated
+ *  - SpectreRSB: SMEP and RSB Stuffing
+ *  - L1TF: spec_uarch_flush, smt exclusion, requires microcode
+ *  - MDS: x86_md_clear, requires microcode, disabling hyper threading
+ *
+ * The following table indicates the x86 feature set bits that indicate that a
+ * given problem has been solved or a notable feature is present:
+ *
+ *  - RDCL_NO: Meltdown, L1TF, MSBDS subset of MDS
+ *  - MDS_NO: All forms of MDS
  */
 
 #include <sys/types.h>
@@ -921,6 +1196,8 @@
 #include <sys/mach_mmu.h>
 #include <sys/ucode.h>
 #include <sys/tsc.h>
+#include <sys/kobj.h>
+#include <sys/asm_misc.h>
 
 #ifdef __xpv
 #include <sys/hypervisor.h>
@@ -940,6 +1217,17 @@
 int x86_use_invpcid = -1;
 #endif
 
+typedef enum {
+	X86_SPECTREV2_RETPOLINE,
+	X86_SPECTREV2_RETPOLINE_AMD,
+	X86_SPECTREV2_ENHANCED_IBRS,
+	X86_SPECTREV2_DISABLED
+} x86_spectrev2_mitigation_t;
+
+uint_t x86_disable_spectrev2 = 0;
+static x86_spectrev2_mitigation_t x86_spectrev2_mitigation =
+    X86_SPECTREV2_RETPOLINE;
+
 uint_t pentiumpro_bug4046376;
 
 uchar_t x86_featureset[BT_SIZEOFMAP(NUM_X86_FEATURES)];
@@ -2170,8 +2458,6 @@
  */
 void (*spec_uarch_flush)(void) = spec_uarch_flush_noop;
 
-void (*x86_md_clear)(void) = x86_md_clear_noop;
-
 static void
 cpuid_update_md_clear(cpu_t *cpu, uchar_t *featureset)
 {
@@ -2185,13 +2471,14 @@
 	 */
 	if (cpi->cpi_vendor != X86_VENDOR_Intel ||
 	    is_x86_feature(featureset, X86FSET_MDS_NO)) {
-		x86_md_clear = x86_md_clear_noop;
-		membar_producer();
 		return;
 	}
 
 	if (is_x86_feature(featureset, X86FSET_MD_CLEAR)) {
-		x86_md_clear = x86_md_clear_verw;
+		const uint8_t nop = NOP_INSTR;
+		uint8_t *md = (uint8_t *)x86_md_clear;
+
+		*md = nop;
 	}
 
 	membar_producer();
@@ -2255,10 +2542,137 @@
 	membar_producer();
 }
 
+/*
+ * We default to enabling RSB mitigations.
+ */
 static void
+cpuid_patch_rsb(x86_spectrev2_mitigation_t mit)
+{
+	const uint8_t ret = RET_INSTR;
+	uint8_t *stuff = (uint8_t *)x86_rsb_stuff;
+
+	switch (mit) {
+	case X86_SPECTREV2_ENHANCED_IBRS:
+	case X86_SPECTREV2_DISABLED:
+		*stuff = ret;
+		break;
+	default:
+		break;
+	}
+}
+
+static void
+cpuid_patch_retpolines(x86_spectrev2_mitigation_t mit)
+{
+	const char *thunks[] = { "_rax", "_rbx", "_rcx", "_rdx", "_rdi",
+	    "_rsi", "_rbp", "_r8", "_r9", "_r10", "_r11", "_r12", "_r13",
+	    "_r14", "_r15" };
+	const uint_t nthunks = ARRAY_SIZE(thunks);
+	const char *type;
+	uint_t i;
+
+	if (mit == x86_spectrev2_mitigation)
+		return;
+
+	switch (mit) {
+	case X86_SPECTREV2_RETPOLINE:
+		type = "gen";
+		break;
+	case X86_SPECTREV2_RETPOLINE_AMD:
+		type = "amd";
+		break;
+	case X86_SPECTREV2_ENHANCED_IBRS:
+	case X86_SPECTREV2_DISABLED:
+		type = "jmp";
+		break;
+	default:
+		panic("asked to updated retpoline state with unknown state!");
+	}
+
+	for (i = 0; i < nthunks; i++) {
+		uintptr_t source, dest;
+		int ssize, dsize;
+		char sourcebuf[64], destbuf[64];
+		size_t len;
+
+		(void) snprintf(destbuf, sizeof (destbuf),
+		    "__x86_indirect_thunk%s", thunks[i]);
+		(void) snprintf(sourcebuf, sizeof (sourcebuf),
+		    "__x86_indirect_thunk_%s%s", type, thunks[i]);
+
+		source = kobj_getelfsym(sourcebuf, NULL, &ssize);
+		dest = kobj_getelfsym(destbuf, NULL, &dsize);
+		VERIFY3U(source, !=, 0);
+		VERIFY3U(dest, !=, 0);
+		VERIFY3S(dsize, >=, ssize);
+		bcopy((void *)source, (void *)dest, ssize);
+	}
+}
+
+static void
+cpuid_enable_enhanced_ibrs(void)
+{
+	uint64_t val;
+
+	val = rdmsr(MSR_IA32_SPEC_CTRL);
+	val |= IA32_SPEC_CTRL_IBRS;
+	wrmsr(MSR_IA32_SPEC_CTRL, val);
+}
+
+#ifndef __xpv
+/*
+ * Determine whether or not we can use the AMD optimized retpoline
+ * functionality. We use this when we know we're on an AMD system and we can
+ * successfully verify that lfence is dispatch serializing.
+ */
+static boolean_t
+cpuid_use_amd_retpoline(struct cpuid_info *cpi)
+{
+	uint64_t val;
+	on_trap_data_t otd;
+
+	if (cpi->cpi_vendor != X86_VENDOR_AMD)
+		return (B_FALSE);
+
+	/*
+	 * We need to determine whether or not lfence is serializing. It always
+	 * is on families 0xf and 0x11. On others, it's controlled by
+	 * MSR_AMD_DECODE_CONFIG (MSRC001_1029). If some hypervisor gives us a
+	 * crazy old family, don't try and do anything.
+	 */
+	if (cpi->cpi_family < 0xf)
+		return (B_FALSE);
+	if (cpi->cpi_family == 0xf || cpi->cpi_family == 0x11)
+		return (B_TRUE);
+
+	/*
+	 * While it may be tempting to use get_hwenv(), there are no promises
+	 * that a hypervisor will actually declare themselves to be so in a
+	 * friendly way. As such, try to read and set the MSR. If we can then
+	 * read back the value we set (it wasn't just set to zero), then we go
+	 * for it.
+	 */
+	if (!on_trap(&otd, OT_DATA_ACCESS)) {
+		val = rdmsr(MSR_AMD_DECODE_CONFIG);
+		val |= AMD_DECODE_CONFIG_LFENCE_DISPATCH;
+		wrmsr(MSR_AMD_DECODE_CONFIG, val);
+		val = rdmsr(MSR_AMD_DECODE_CONFIG);
+	} else {
+		val = 0;
+	}
+	no_trap();
+
+	if ((val & AMD_DECODE_CONFIG_LFENCE_DISPATCH) != 0)
+		return (B_TRUE);
+	return (B_FALSE);
+}
+#endif	/* !__xpv */
+
+static void
 cpuid_scan_security(cpu_t *cpu, uchar_t *featureset)
 {
 	struct cpuid_info *cpi = cpu->cpu_m.mcpu_cpi;
+	x86_spectrev2_mitigation_t v2mit;
 
 	if (cpi->cpi_vendor == X86_VENDOR_AMD &&
 	    cpi->cpi_xmaxeax >= CPUID_LEAF_EXT_8) {
@@ -2268,12 +2682,8 @@
 			add_x86_feature(featureset, X86FSET_IBRS);
 		if (cpi->cpi_extd[8].cp_ebx & CPUID_AMD_EBX_STIBP)
 			add_x86_feature(featureset, X86FSET_STIBP);
-		if (cpi->cpi_extd[8].cp_ebx & CPUID_AMD_EBX_IBRS_ALL)
-			add_x86_feature(featureset, X86FSET_IBRS_ALL);
 		if (cpi->cpi_extd[8].cp_ebx & CPUID_AMD_EBX_STIBP_ALL)
 			add_x86_feature(featureset, X86FSET_STIBP_ALL);
-		if (cpi->cpi_extd[8].cp_ebx & CPUID_AMD_EBX_PREFER_IBRS)
-			add_x86_feature(featureset, X86FSET_RSBA);
 		if (cpi->cpi_extd[8].cp_ebx & CPUID_AMD_EBX_SSBD)
 			add_x86_feature(featureset, X86FSET_SSBD);
 		if (cpi->cpi_extd[8].cp_ebx & CPUID_AMD_EBX_VIRT_SSBD)
@@ -2280,6 +2690,16 @@
 			add_x86_feature(featureset, X86FSET_SSBD_VIRT);
 		if (cpi->cpi_extd[8].cp_ebx & CPUID_AMD_EBX_SSB_NO)
 			add_x86_feature(featureset, X86FSET_SSB_NO);
+		/*
+		 * Don't enable enhanced IBRS unless we're told that we should
+		 * prefer it and it has the same semantics as Intel. This is
+		 * split into two bits rather than a single one.
+		 */
+		if ((cpi->cpi_extd[8].cp_ebx & CPUID_AMD_EBX_PREFER_IBRS) &&
+		    (cpi->cpi_extd[8].cp_ebx & CPUID_AMD_EBX_IBRS_ALL)) {
+			add_x86_feature(featureset, X86FSET_IBRS_ALL);
+		}
+
 	} else if (cpi->cpi_vendor == X86_VENDOR_Intel &&
 	    cpi->cpi_maxeax >= 7) {
 		struct cpuid_regs *ecp;
@@ -2349,10 +2769,42 @@
 			add_x86_feature(featureset, X86FSET_FLUSH_CMD);
 	}
 
-	if (cpu->cpu_id != 0)
+	if (cpu->cpu_id != 0) {
+		if (x86_spectrev2_mitigation == X86_SPECTREV2_ENHANCED_IBRS) {
+			cpuid_enable_enhanced_ibrs();
+		}
 		return;
+	}
 
 	/*
+	 * Go through and initialize various security mechanisms that we should
+	 * only do on a single CPU. This includes Spectre V2, L1TF, and MDS.
+	 */
+
+	/*
+	 * By default we've come in with retpolines enabled. Check whether we
+	 * should disable them or enable enhanced IBRS. RSB stuffing is enabled
+	 * by default, but disabled if we are using enhanced IBRS.
+	 */
+	if (x86_disable_spectrev2 != 0) {
+		v2mit = X86_SPECTREV2_DISABLED;
+	} else if (is_x86_feature(featureset, X86FSET_IBRS_ALL)) {
+		cpuid_enable_enhanced_ibrs();
+		v2mit = X86_SPECTREV2_ENHANCED_IBRS;
+#ifndef __xpv
+	} else if (cpuid_use_amd_retpoline(cpi)) {
+		v2mit = X86_SPECTREV2_RETPOLINE_AMD;
+#endif	/* !__xpv */
+	} else {
+		v2mit = X86_SPECTREV2_RETPOLINE;
+	}
+
+	cpuid_patch_retpolines(v2mit);
+	cpuid_patch_rsb(v2mit);
+	x86_spectrev2_mitigation = v2mit;
+	membar_producer();
+
+	/*
 	 * We need to determine what changes are required for mitigating L1TF
 	 * and MDS. If the CPU suffers from either of them, then SMT exclusion
 	 * is required.
@@ -6774,8 +7226,13 @@
 cpuid_post_ucodeadm_xc(xc_arg_t arg0, xc_arg_t arg1, xc_arg_t arg2)
 {
 	uchar_t *fset;
+	boolean_t first_pass = (boolean_t)arg1;
 
 	fset = (uchar_t *)(arg0 + sizeof (x86_featureset) * CPU->cpu_id);
+	if (first_pass && CPU->cpu_id != 0)
+		return (0);
+	if (!first_pass && CPU->cpu_id == 0)
+		return (0);
 	cpuid_pass_ucode(CPU, fset);
 
 	return (0);
@@ -6818,9 +7275,18 @@
 		CPUSET_ADD(cpuset, i);
 	}
 
+	/*
+	 * We do the cross calls in two passes. The first pass is only for the
+	 * boot CPU. The second pass is for all of the other CPUs. This allows
+	 * the boot CPU to go through and change behavior related to patching or
+	 * whether or not Enhanced IBRS needs to be enabled and then allow all
+	 * other CPUs to follow suit.
+	 */
 	kpreempt_disable();
-	xc_sync((xc_arg_t)argdata, 0, 0, CPUSET2BV(cpuset),
+	xc_sync((xc_arg_t)argdata, B_TRUE, 0, CPUSET2BV(cpuset),
 	    cpuid_post_ucodeadm_xc);
+	xc_sync((xc_arg_t)argdata, B_FALSE, 0, CPUSET2BV(cpuset),
+	    cpuid_post_ucodeadm_xc);
 	kpreempt_enable();
 
 	/*
--- old/usr/src/uts/i86pc/sys/asm_misc.h	Wed Oct  9 03:12:30 2019
+++ new/usr/src/uts/i86pc/sys/asm_misc.h	Wed Oct  9 03:12:30 2019
@@ -21,7 +21,7 @@
 /*
  * Copyright 2008 Sun Microsystems, Inc.  All rights reserved.
  * Use is subject to license terms.
- * Copyright 2017 Joyent, Inc.
+ * Copyright 2019 Joyent, Inc.
  */
 
 #ifndef _SYS_ASM_MISC_H
@@ -31,6 +31,11 @@
 extern "C" {
 #endif
 
+#define	RET_INSTR	0xc3
+#define	NOP_INSTR	0x90
+#define	STI_INSTR	0xfb
+#define	JMP_INSTR	0x00eb
+
 #ifdef _ASM	/* The remainder of this file is only for assembly files */
 
 /* Load reg with pointer to per-CPU structure */
@@ -42,12 +47,6 @@
 	movl	%gs:CPU_SELF, reg;
 #endif
 
-#define	RET_INSTR	0xc3
-#define	NOP_INSTR	0x90
-#define	STI_INSTR	0xfb
-#define	JMP_INSTR	0x00eb
-
-
 #if defined(__i386)
 
 #define	_HOT_PATCH_PROLOG			\
--- old/usr/src/uts/i86pc/sys/machprivregs.h	Wed Oct  9 03:12:30 2019
+++ new/usr/src/uts/i86pc/sys/machprivregs.h	Wed Oct  9 03:12:30 2019
@@ -129,7 +129,7 @@
 	movq	REGOFF_RDI(%rsp), %rdi;	\
 	addq	$REGOFF_RIP, %rsp
 
-#define	FAST_INTR_RETURN	call *x86_md_clear; jmp tr_iret_user
+#define	FAST_INTR_RETURN	call x86_md_clear; jmp tr_iret_user
 
 #elif defined(__i386)
 
--- old/usr/src/uts/intel/Makefile.files	Wed Oct  9 03:12:30 2019
+++ new/usr/src/uts/intel/Makefile.files	Wed Oct  9 03:12:30 2019
@@ -53,11 +53,15 @@
 	lock_prim.o	\
 	ovbcopy.o	\
 	polled_io.o	\
+	retpoline.o	\
 	sseblk.o	\
 	sundep.o	\
 	swtch.o		\
 	sysi86.o
 
+DBOOT_OBJS +=		\
+	retpoline.o
+
 #
 # 64-bit multiply/divide compiler helper routines
 # used only for ia32
--- old/usr/src/uts/intel/Makefile.rules	Wed Oct  9 03:12:31 2019
+++ new/usr/src/uts/intel/Makefile.rules	Wed Oct  9 03:12:31 2019
@@ -294,6 +294,10 @@
 #
 $(OBJS_DIR)/kobj.o		:= CPPFLAGS += -D_DBOOT
 
+$(DBOOT_OBJS_DIR)/%.o:		$(UTSBASE)/intel/ia32/ml/%.s
+	$(DBOOT_AS) -P -D_ASM $(DBOOT_DEFS) $(DBOOT_AS_INCL) -o $@ $<
+
+
 $(OBJS_DIR)/%.o:	$(UTSBASE)/intel/$(SUBARCH_DIR)/krtld/%.s
 	$(COMPILE.s) $(KRTLD_INC_PATH) $(KRTLD_CPPFLAGS) -o $@ $<
 
--- old/usr/src/uts/intel/amd64/krtld/kobj_crt.s	Wed Oct  9 03:12:31 2019
+++ new/usr/src/uts/intel/amd64/krtld/kobj_crt.s	Wed Oct  9 03:12:31 2019
@@ -21,10 +21,9 @@
 /*
  * Copyright 2007 Sun Microsystems, Inc.  All rights reserved.
  * Use is subject to license terms.
+ * Copyright 2019 Joyent, Inc.
  */
 
-#pragma ident	"%Z%%M%	%I%	%E% SMI"
-
 /*
  * exit routine from linker/loader to kernel
  */
@@ -64,7 +63,7 @@
 	movq    (%rax), %rdx
 
 	/ Call destination
-	call   *%r11
+	INDIRECT_CALL_REG(r11)
 
 	SET_SIZE(exitto)
 
--- old/usr/src/uts/intel/brand/common/brand_solaris.s	Wed Oct  9 03:12:31 2019
+++ new/usr/src/uts/intel/brand/common/brand_solaris.s	Wed Oct  9 03:12:31 2019
@@ -30,7 +30,7 @@
  * no easy place to save the extra parameters that would be required, so
  * each brand module needs its own copy of this code.  We #include this and
  * use brand-specific #defines to replace the XXX_brand_... definitions.
- */ 
+ */
 
 #ifdef lint
 
@@ -89,7 +89,7 @@
 	mov	%rcx, SYSCALL_REG; /* save orig return addr in syscall_reg */
 	mov	SCR_REG, %rcx;	/* place new return addr in %rcx */
 	mov	%gs:CPU_RTMP_R15, SCR_REG; /* restore scratch register */
-	call	*x86_md_clear		/* Flush micro-arch state */
+	call	x86_md_clear		/* Flush micro-arch state */
 	mov	V_SSP(SP_REG), SP_REG	/* restore user stack pointer */
 	jmp	nopop_sys_syscall32_swapgs_sysretl
 9:
@@ -109,7 +109,7 @@
 	mov	%rcx, SYSCALL_REG; /* save orig return addr in syscall_reg */
 	mov	SCR_REG, %rcx;	/* place new return addr in %rcx */
 	mov	%gs:CPU_RTMP_R15, SCR_REG; /* restore scratch register */
-	call	*x86_md_clear		/* Flush micro-arch state */
+	call	x86_md_clear		/* Flush micro-arch state */
 	mov	V_SSP(SP_REG), SP_REG	/* restore user stack pointer */
 	jmp	nopop_sys_syscall_swapgs_sysretq
 9:
--- old/usr/src/uts/intel/ia32/ml/copy.s	Wed Oct  9 03:12:32 2019
+++ new/usr/src/uts/intel/ia32/ml/copy.s	Wed Oct  9 03:12:32 2019
@@ -36,7 +36,7 @@
 /*         All Rights Reserved						*/
 
 /*
- * Copyright (c) 2018 Joyent, Inc.
+ * Copyright 2019 Joyent, Inc.
  */
 
 #include <sys/errno.h>
@@ -128,7 +128,7 @@
  * bcopy/kcopy/bzero/kzero operate on small buffers. For best performance for
  * these small sizes unrolled code is used. For medium sizes loops writing
  * 64-bytes per loop are used. Transition points were determined experimentally.
- */ 
+ */
 #define BZERO_USE_REP	(1024)
 #define BCOPY_DFLT_REP	(128)
 #define	BCOPY_NHM_REP	(768)
@@ -179,7 +179,7 @@
 	pushq	%rbp
 	movq	%rsp, %rbp
 #ifdef DEBUG
-	cmpq	postbootkernelbase(%rip), %rdi 		/* %rdi = from */
+	cmpq	postbootkernelbase(%rip), %rdi		/* %rdi = from */
 	jb	0f
 	cmpq	postbootkernelbase(%rip), %rsi		/* %rsi = to */
 	jnb	1f
@@ -231,7 +231,7 @@
 1:	popl	%ebp
 #endif
 	lea	_kcopy_copyerr, %eax	/* lofault value */
-	movl	%gs:CPU_THREAD, %edx	
+	movl	%gs:CPU_THREAD, %edx
 
 do_copy_fault:
 	pushl	%ebp
@@ -310,7 +310,7 @@
 	pushq	%rbp
 	movq	%rsp, %rbp
 #ifdef DEBUG
-	cmpq	postbootkernelbase(%rip), %rdi 		/* %rdi = from */
+	cmpq	postbootkernelbase(%rip), %rdi		/* %rdi = from */
 	jb	0f
 	cmpq	postbootkernelbase(%rip), %rsi		/* %rsi = to */
 	jnb	1f
@@ -406,7 +406,7 @@
 	pushl	%esi
 	pushl	%edi
 
-	movl	%gs:CPU_THREAD, %edx	
+	movl	%gs:CPU_THREAD, %edx
 	movl	T_LOFAULT(%edx), %edi
 	pushl	%edi			/* save the current lofault */
 	movl	%eax, T_LOFAULT(%edx)	/* new lofault */
@@ -455,7 +455,7 @@
 	jz	1f
 	cmpq	postbootkernelbase(%rip), %rdi		/* %rdi = from */
 	jb	0f
-	cmpq	postbootkernelbase(%rip), %rsi		/* %rsi = to */		
+	cmpq	postbootkernelbase(%rip), %rsi		/* %rsi = to */
 	jnb	1f
 0:	leaq	.bcopy_panic_msg(%rip), %rdi
 	jmp	call_panic		/* setup stack and call panic */
@@ -482,7 +482,7 @@
 	addq	%rdx, %rsi
 	movslq	(%r10,%rdx,4), %rcx
 	leaq	(%rcx,%r10,1), %r10
-	jmpq	*%r10
+	INDIRECT_JMP_REG(r10)
 
 	.p2align 4
 L(fwdPxQx):
@@ -493,7 +493,7 @@
 	.int       L(P4Q0)-L(fwdPxQx)
 	.int       L(P5Q0)-L(fwdPxQx)
 	.int       L(P6Q0)-L(fwdPxQx)
-	.int       L(P7Q0)-L(fwdPxQx) 
+	.int       L(P7Q0)-L(fwdPxQx)
 
 	.int       L(P0Q1)-L(fwdPxQx)	/* 8 */
 	.int       L(P1Q1)-L(fwdPxQx)
@@ -502,7 +502,7 @@
 	.int       L(P4Q1)-L(fwdPxQx)
 	.int       L(P5Q1)-L(fwdPxQx)
 	.int       L(P6Q1)-L(fwdPxQx)
-	.int       L(P7Q1)-L(fwdPxQx) 
+	.int       L(P7Q1)-L(fwdPxQx)
 
 	.int       L(P0Q2)-L(fwdPxQx)	/* 16 */
 	.int       L(P1Q2)-L(fwdPxQx)
@@ -511,7 +511,7 @@
 	.int       L(P4Q2)-L(fwdPxQx)
 	.int       L(P5Q2)-L(fwdPxQx)
 	.int       L(P6Q2)-L(fwdPxQx)
-	.int       L(P7Q2)-L(fwdPxQx) 
+	.int       L(P7Q2)-L(fwdPxQx)
 
 	.int       L(P0Q3)-L(fwdPxQx)	/* 24 */
 	.int       L(P1Q3)-L(fwdPxQx)
@@ -520,7 +520,7 @@
 	.int       L(P4Q3)-L(fwdPxQx)
 	.int       L(P5Q3)-L(fwdPxQx)
 	.int       L(P6Q3)-L(fwdPxQx)
-	.int       L(P7Q3)-L(fwdPxQx) 
+	.int       L(P7Q3)-L(fwdPxQx)
 
 	.int       L(P0Q4)-L(fwdPxQx)	/* 32 */
 	.int       L(P1Q4)-L(fwdPxQx)
@@ -529,7 +529,7 @@
 	.int       L(P4Q4)-L(fwdPxQx)
 	.int       L(P5Q4)-L(fwdPxQx)
 	.int       L(P6Q4)-L(fwdPxQx)
-	.int       L(P7Q4)-L(fwdPxQx) 
+	.int       L(P7Q4)-L(fwdPxQx)
 
 	.int       L(P0Q5)-L(fwdPxQx)	/* 40 */
 	.int       L(P1Q5)-L(fwdPxQx)
@@ -538,7 +538,7 @@
 	.int       L(P4Q5)-L(fwdPxQx)
 	.int       L(P5Q5)-L(fwdPxQx)
 	.int       L(P6Q5)-L(fwdPxQx)
-	.int       L(P7Q5)-L(fwdPxQx) 
+	.int       L(P7Q5)-L(fwdPxQx)
 
 	.int       L(P0Q6)-L(fwdPxQx)	/* 48 */
 	.int       L(P1Q6)-L(fwdPxQx)
@@ -547,7 +547,7 @@
 	.int       L(P4Q6)-L(fwdPxQx)
 	.int       L(P5Q6)-L(fwdPxQx)
 	.int       L(P6Q6)-L(fwdPxQx)
-	.int       L(P7Q6)-L(fwdPxQx) 
+	.int       L(P7Q6)-L(fwdPxQx)
 
 	.int       L(P0Q7)-L(fwdPxQx)	/* 56 */
 	.int       L(P1Q7)-L(fwdPxQx)
@@ -556,7 +556,7 @@
 	.int       L(P4Q7)-L(fwdPxQx)
 	.int       L(P5Q7)-L(fwdPxQx)
 	.int       L(P6Q7)-L(fwdPxQx)
-	.int       L(P7Q7)-L(fwdPxQx) 
+	.int       L(P7Q7)-L(fwdPxQx)
 
 	.int       L(P0Q8)-L(fwdPxQx)	/* 64 */
 	.int       L(P1Q8)-L(fwdPxQx)
@@ -604,8 +604,8 @@
 L(P0Q1):
 	mov    -0x8(%rdi), %r8
 	mov    %r8, -0x8(%rsi)
-L(P0Q0):                                   
-	ret   
+L(P0Q0):
+	ret
 
 	.p2align 4
 L(P1Q9):
@@ -638,7 +638,7 @@
 L(P1Q0):
 	movzbq -0x1(%rdi), %r8
 	mov    %r8b, -0x1(%rsi)
-	ret   
+	ret
 
 	.p2align 4
 L(P2Q9):
@@ -671,7 +671,7 @@
 L(P2Q0):
 	movzwq -0x2(%rdi), %r8
 	mov    %r8w, -0x2(%rsi)
-	ret   
+	ret
 
 	.p2align 4
 L(P3Q9):
@@ -702,7 +702,7 @@
 	mov    -0xb(%rdi), %r10
 	mov    %r10, -0xb(%rsi)
 	/*
-	 * These trailing loads/stores have to do all their loads 1st, 
+	 * These trailing loads/stores have to do all their loads 1st,
 	 * then do the stores.
 	 */
 L(P3Q0):
@@ -710,7 +710,7 @@
 	movzbq -0x1(%rdi), %r10
 	mov    %r8w, -0x3(%rsi)
 	mov    %r10b, -0x1(%rsi)
-	ret   
+	ret
 
 	.p2align 4
 L(P4Q9):
@@ -743,7 +743,7 @@
 L(P4Q0):
 	mov    -0x4(%rdi), %r8d
 	mov    %r8d, -0x4(%rsi)
-	ret   
+	ret
 
 	.p2align 4
 L(P5Q9):
@@ -778,7 +778,7 @@
 	movzbq -0x1(%rdi), %r10
 	mov    %r8d, -0x5(%rsi)
 	mov    %r10b, -0x1(%rsi)
-	ret   
+	ret
 
 	.p2align 4
 L(P6Q9):
@@ -813,7 +813,7 @@
 	movzwq -0x2(%rdi), %r10
 	mov    %r8d, -0x6(%rsi)
 	mov    %r10w, -0x2(%rsi)
-	ret   
+	ret
 
 	.p2align 4
 L(P7Q9):
@@ -850,7 +850,7 @@
 	mov    %r8d, -0x7(%rsi)
 	mov    %r10w, -0x3(%rsi)
 	mov    %cl, -0x1(%rsi)
-	ret   
+	ret
 
 	/*
 	 * For large sizes rep smovq is fastest.
@@ -938,7 +938,7 @@
 	addq	%rdx, %rsi
 	movslq	(%r10,%rdx,4), %rcx
 	leaq	(%rcx,%r10,1), %r10
-	jmpq	*%r10
+	INDIRECT_JMP_REG(r10)
 
 	/*
 	 * Use rep smovq. Clear remainder via unrolled code
@@ -1052,7 +1052,7 @@
 0:
 #endif
 	/*
-	 * pass lofault value as 3rd argument for fault return 
+	 * pass lofault value as 3rd argument for fault return
 	 */
 	leaq	_kzeroerr(%rip), %rdx
 
@@ -1095,7 +1095,7 @@
 	movl	%esp, %ebp		/* set new stack base */
 	pushl	%edi			/* save %edi */
 
-	mov	%gs:CPU_THREAD, %edx	
+	mov	%gs:CPU_THREAD, %edx
 	movl	T_LOFAULT(%edx), %edi
 	pushl	%edi			/* save the current lofault */
 	movl	%eax, T_LOFAULT(%edx)	/* new lofault */
@@ -1170,7 +1170,7 @@
 	addq	%rsi, %rdi
 	movslq	(%r10,%rsi,4), %rcx
 	leaq	(%rcx,%r10,1), %r10
-	jmpq	*%r10
+	INDIRECT_JMP_REG(r10)
 
 	.p2align 4
 L(setPxQx):
@@ -1181,7 +1181,7 @@
 	.int       L(P4Q0)-L(setPxQx)
 	.int       L(P5Q0)-L(setPxQx)
 	.int       L(P6Q0)-L(setPxQx)
-	.int       L(P7Q0)-L(setPxQx) 
+	.int       L(P7Q0)-L(setPxQx)
 
 	.int       L(P0Q1)-L(setPxQx)	/* 8 */
 	.int       L(P1Q1)-L(setPxQx)
@@ -1190,7 +1190,7 @@
 	.int       L(P4Q1)-L(setPxQx)
 	.int       L(P5Q1)-L(setPxQx)
 	.int       L(P6Q1)-L(setPxQx)
-	.int       L(P7Q1)-L(setPxQx) 
+	.int       L(P7Q1)-L(setPxQx)
 
 	.int       L(P0Q2)-L(setPxQx)	/* 16 */
 	.int       L(P1Q2)-L(setPxQx)
@@ -1199,7 +1199,7 @@
 	.int       L(P4Q2)-L(setPxQx)
 	.int       L(P5Q2)-L(setPxQx)
 	.int       L(P6Q2)-L(setPxQx)
-	.int       L(P7Q2)-L(setPxQx) 
+	.int       L(P7Q2)-L(setPxQx)
 
 	.int       L(P0Q3)-L(setPxQx)	/* 24 */
 	.int       L(P1Q3)-L(setPxQx)
@@ -1208,7 +1208,7 @@
 	.int       L(P4Q3)-L(setPxQx)
 	.int       L(P5Q3)-L(setPxQx)
 	.int       L(P6Q3)-L(setPxQx)
-	.int       L(P7Q3)-L(setPxQx) 
+	.int       L(P7Q3)-L(setPxQx)
 
 	.int       L(P0Q4)-L(setPxQx)	/* 32 */
 	.int       L(P1Q4)-L(setPxQx)
@@ -1217,7 +1217,7 @@
 	.int       L(P4Q4)-L(setPxQx)
 	.int       L(P5Q4)-L(setPxQx)
 	.int       L(P6Q4)-L(setPxQx)
-	.int       L(P7Q4)-L(setPxQx) 
+	.int       L(P7Q4)-L(setPxQx)
 
 	.int       L(P0Q5)-L(setPxQx)	/* 40 */
 	.int       L(P1Q5)-L(setPxQx)
@@ -1226,7 +1226,7 @@
 	.int       L(P4Q5)-L(setPxQx)
 	.int       L(P5Q5)-L(setPxQx)
 	.int       L(P6Q5)-L(setPxQx)
-	.int       L(P7Q5)-L(setPxQx) 
+	.int       L(P7Q5)-L(setPxQx)
 
 	.int       L(P0Q6)-L(setPxQx)	/* 48 */
 	.int       L(P1Q6)-L(setPxQx)
@@ -1235,7 +1235,7 @@
 	.int       L(P4Q6)-L(setPxQx)
 	.int       L(P5Q6)-L(setPxQx)
 	.int       L(P6Q6)-L(setPxQx)
-	.int       L(P7Q6)-L(setPxQx) 
+	.int       L(P7Q6)-L(setPxQx)
 
 	.int       L(P0Q7)-L(setPxQx)	/* 56 */
 	.int       L(P1Q7)-L(setPxQx)
@@ -1244,7 +1244,7 @@
 	.int       L(P4Q7)-L(setPxQx)
 	.int       L(P5Q7)-L(setPxQx)
 	.int       L(P6Q7)-L(setPxQx)
-	.int       L(P7Q7)-L(setPxQx) 
+	.int       L(P7Q7)-L(setPxQx)
 
 	.int       L(P0Q8)-L(setPxQx)	/* 64 */
 	.int       L(P1Q8)-L(setPxQx)
@@ -1274,7 +1274,7 @@
 L(P0Q3): mov    %rax, -0x18(%rdi)
 L(P0Q2): mov    %rax, -0x10(%rdi)
 L(P0Q1): mov    %rax, -0x8(%rdi)
-L(P0Q0): 
+L(P0Q0):
 	 ret
 
 	.p2align 4
@@ -1422,14 +1422,14 @@
 L(bzero_loop):
 	leaq	-0x40(%rsi), %rsi
 	cmpq	$0x40, %rsi
-	movq	%rax, (%rdi) 
-	movq	%rax, 0x8(%rdi) 
-	movq	%rax, 0x10(%rdi) 
-	movq	%rax, 0x18(%rdi) 
-	movq	%rax, 0x20(%rdi) 
-	movq	%rax, 0x28(%rdi) 
-	movq	%rax, 0x30(%rdi) 
-	movq	%rax, 0x38(%rdi) 
+	movq	%rax, (%rdi)
+	movq	%rax, 0x8(%rdi)
+	movq	%rax, 0x10(%rdi)
+	movq	%rax, 0x18(%rdi)
+	movq	%rax, 0x20(%rdi)
+	movq	%rax, 0x28(%rdi)
+	movq	%rax, 0x30(%rdi)
+	movq	%rax, 0x38(%rdi)
 	leaq	0x40(%rdi), %rdi
 	jae	L(bzero_loop)
 
@@ -1441,7 +1441,7 @@
 	addq	%rsi, %rdi
 	movslq	(%r10,%rsi,4), %rcx
 	leaq	(%rcx,%r10,1), %r10
-	jmpq	*%r10
+	INDIRECT_JMP_REG(r10)
 
 	/*
 	 * Use rep sstoq. Clear any remainder via unrolled code
@@ -1564,7 +1564,7 @@
 
 _copyin_err:
 	SMAP_ENABLE_INSTR(2)
-	movq	%r11, T_LOFAULT(%r9)	/* restore original lofault */	
+	movq	%r11, T_LOFAULT(%r9)	/* restore original lofault */
 	addq	$8, %rsp		/* pop bcopy_altentry call ret addr */
 3:
 	movq	T_COPYOPS(%r9), %rax
@@ -1577,9 +1577,10 @@
 	movq	0x8(%rsp), %rsi
 	movq	0x10(%rsp), %rdx
 	leave
-	jmp	*CP_COPYIN(%rax)
+	movq	CP_COPYIN(%rax), %rax
+	INDIRECT_JMP_REG(rax)
 
-2:	movl	$-1, %eax	
+2:	movl	$-1, %eax
 	leave
 	ret
 	SET_SIZE(copyin)
@@ -1680,7 +1681,7 @@
 6:
 	SMAP_DISABLE_INSTR(1)
 	jmp	do_copy_fault
-	
+
 	/*
 	 * Make sure src and dst are NTA_ALIGN_SIZE aligned,
 	 * count is COUNT_ALIGN_SIZE aligned.
@@ -1691,11 +1692,11 @@
 	andq	$NTA_ALIGN_MASK, %r10
 	orq	%rdx, %r10
 	andq	$COUNT_ALIGN_MASK, %r10
-	jnz	6b	
+	jnz	6b
 	leaq	_xcopyin_nta_err(%rip), %rcx	/* doesn't set rflags */
 	SMAP_DISABLE_INSTR(2)
 	jmp	do_copy_fault_nta	/* use non-temporal access */
-	
+
 4:
 	movl	$EFAULT, %eax
 	jmp	3f
@@ -1722,7 +1723,8 @@
 	movq	0x8(%rsp), %rsi
 	movq	0x10(%rsp), %rdx
 	leave
-	jmp	*CP_XCOPYIN(%r8)
+	movq	CP_XCOPYIN(%r8), %r8
+	INDIRECT_JMP_REG(r8)
 
 2:	leave
 	ret
@@ -1755,7 +1757,7 @@
 	 */
 	cmpl	$XCOPY_MIN_SIZE, ARG_COUNT(%esp)
 	jb	do_copy_fault
-	
+
 	/*
 	 * Make sure src and dst are NTA_ALIGN_SIZE aligned,
 	 * count is COUNT_ALIGN_SIZE aligned.
@@ -1790,7 +1792,7 @@
 	movl	T_COPYOPS(%edx), %eax
 	jmp	*CP_XCOPYIN(%eax)
 
-2:	rep; 	ret	/* use 2 byte return instruction when branch target */
+2:	rep;	ret	/* use 2 byte return instruction when branch target */
 			/* AMD Software Optimization Guide - Section 6.2 */
 	SET_SIZE(xcopyin_nta)
 
@@ -1865,7 +1867,8 @@
 	movq	0x8(%rsp), %rsi
 	movq	0x10(%rsp), %rdx
 	leave
-	jmp	*CP_COPYOUT(%rax)
+	movq	CP_COPYOUT(%rax), %rax
+	INDIRECT_JMP_REG(rax)
 
 2:	movl	$-1, %eax
 	leave
@@ -1893,7 +1896,7 @@
 	cmpl	%ecx, ARG_UADDR(%esp)	/* test uaddr < kernelbase */
 	jb	do_copy_fault
 	jmp	3f
-	
+
 _copyout_err:
 	popl	%ecx
 	popl	%edi
@@ -1966,7 +1969,7 @@
 6:
 	SMAP_DISABLE_INSTR(4)
 	jmp	do_copy_fault
-	
+
 	/*
 	 * Make sure src and dst are NTA_ALIGN_SIZE aligned,
 	 * count is COUNT_ALIGN_SIZE aligned.
@@ -1977,7 +1980,7 @@
 	andq	$NTA_ALIGN_MASK, %r10
 	orq	%rdx, %r10
 	andq	$COUNT_ALIGN_MASK, %r10
-	jnz	6b	
+	jnz	6b
 	leaq	_xcopyout_nta_err(%rip), %rcx
 	SMAP_DISABLE_INSTR(5)
 	call	do_copy_fault_nta
@@ -2010,7 +2013,8 @@
 	movq	0x8(%rsp), %rsi
 	movq	0x10(%rsp), %rdx
 	leave
-	jmp	*CP_XCOPYOUT(%r8)
+	movq	CP_XCOPYOUT(%r8), %r8
+	INDIRECT_JMP_REG(r8)
 
 2:	leave
 	ret
@@ -2041,7 +2045,7 @@
 	 */
 	cmpl	$XCOPY_MIN_SIZE, %edx
 	jb	do_copy_fault
-	
+
 	/*
 	 * Make sure src and dst are NTA_ALIGN_SIZE aligned,
 	 * count is COUNT_ALIGN_SIZE aligned.
@@ -2197,7 +2201,7 @@
 	pushl	%ebx			/* save registers */
 	pushl	%edi
 
-	movl	%gs:CPU_THREAD, %ebx	
+	movl	%gs:CPU_THREAD, %ebx
 	movl	T_LOFAULT(%ebx), %edi
 	pushl	%edi			/* save the current lofault */
 	movl	%eax, T_LOFAULT(%ebx)	/* new lofault */
@@ -2212,7 +2216,7 @@
 copystr_loop:
 	decl	%ecx
 	movb	(%ebx), %al
-	incl	%ebx	
+	incl	%ebx
 	movb	%al, (%edx)
 	incl	%edx
 	cmpb	$0, %al
@@ -2237,13 +2241,13 @@
 
 copystr_done:
 	popl	%edi
-	movl	%gs:CPU_THREAD, %ebx	
+	movl	%gs:CPU_THREAD, %ebx
 	movl	%edi, T_LOFAULT(%ebx)	/* restore the original lofault */
 
 	popl	%edi
 	popl	%ebx
 	popl	%ebp
-	ret	
+	ret
 	SET_SIZE(copystr)
 
 #undef	ARG_FROM
@@ -2324,8 +2328,9 @@
 	movq	0x10(%rsp), %rdx
 	movq	0x18(%rsp), %rcx
 	leave
-	jmp	*CP_COPYINSTR(%rax)
-	
+	movq	CP_COPYINSTR(%rax), %rax
+	INDIRECT_JMP_REG(rax)
+
 2:	movl	$EFAULT, %eax		/* return EFAULT */
 	leave
 	ret
@@ -2355,7 +2360,7 @@
 
 _copyinstr_error:
 	popl	%edi
-	movl	%gs:CPU_THREAD, %edx	
+	movl	%gs:CPU_THREAD, %edx
 	movl	%edi, T_LOFAULT(%edx)	/* original lofault */
 
 	popl	%edi
@@ -2366,7 +2371,7 @@
 	cmpl	$0, %eax
 	jz	2f
 	jmp	*CP_COPYINSTR(%eax)
-	
+
 2:	movl	$EFAULT, %eax		/* return EFAULT */
 	ret
 	SET_SIZE(copyinstr)
@@ -2446,13 +2451,14 @@
 	movq	0x10(%rsp), %rdx
 	movq	0x18(%rsp), %rcx
 	leave
-	jmp	*CP_COPYOUTSTR(%rax)
-	
+	movq	CP_COPYOUTSTR(%rax), %rax
+	INDIRECT_JMP_REG(rax)
+
 2:	movl	$EFAULT, %eax		/* return EFAULT */
 	leave
 	ret
-	SET_SIZE(copyoutstr)	
-	
+	SET_SIZE(copyoutstr)
+
 #elif defined(__i386)
 
 #define	ARG_KADDR	4
@@ -2477,7 +2483,7 @@
 
 _copyoutstr_error:
 	popl	%edi
-	movl	%gs:CPU_THREAD, %edx	
+	movl	%gs:CPU_THREAD, %edx
 	movl	%edi, T_LOFAULT(%edx)	/* restore the original lofault */
 
 	popl	%edi
@@ -2492,7 +2498,7 @@
 2:	movl	$EFAULT, %eax		/* return EFAULT */
 	ret
 	SET_SIZE(copyoutstr)
-	
+
 #undef	ARG_KADDR
 #undef	ARG_UADDR
 
@@ -2503,7 +2509,7 @@
  * Since all of the fuword() variants are so similar, we have a macro to spit
  * them out.  This allows us to create DTrace-unobservable functions easily.
  */
-	
+
 #if defined(__lint)
 
 #if defined(__amd64)
@@ -2562,12 +2568,13 @@
 	movq	T_COPYOPS(%r9), %rax;		\
 	cmpq	$0, %rax;			\
 	jz	2f;				\
-	jmp	*COPYOP(%rax);			\
+	movq	COPYOP(%rax), %rax;		\
+	INDIRECT_JMP_REG(rax);			\
 2:						\
 	movl	$-1, %eax;			\
 	ret;					\
 	SET_SIZE(NAME)
-	
+
 	FUWORD(fuword64, movq, %rax, CP_FUWORD64,8,10,11)
 	FUWORD(fuword32, movl, %eax, CP_FUWORD32,9,12,13)
 	FUWORD(fuword16, movw, %ax, CP_FUWORD16,10,14,15)
@@ -2671,7 +2678,8 @@
 	movq	T_COPYOPS(%r9), %rax;		\
 	cmpq	$0, %rax;			\
 	jz	3f;				\
-	jmp	*COPYOP(%rax);			\
+	movq	COPYOP(%rax), %rax;		\
+	INDIRECT_JMP_REG(rax);			\
 3:						\
 	movl	$-1, %eax;			\
 	ret;					\
@@ -3183,7 +3191,7 @@
 #ifndef __lint
 
 .data
-.align 	4
+.align	4
 .globl	_smap_enable_patch_count
 .type	_smap_enable_patch_count,@object
 .size	_smap_enable_patch_count, 4
--- old/usr/src/uts/intel/ia32/ml/ddi_i86_asm.s	Wed Oct  9 03:12:33 2019
+++ new/usr/src/uts/intel/ia32/ml/ddi_i86_asm.s	Wed Oct  9 03:12:33 2019
@@ -24,7 +24,9 @@
  * Use is subject to license terms.
  */
 
-#pragma ident	"%Z%%M%	%I%	%E% SMI"
+/*
+ * Copyright 2019 Joyent, Inc.
+ */
 
 #if defined(lint) || defined(__lint)
 #include <sys/types.h>
@@ -267,7 +269,7 @@
 
 #else	/* lint */
 
-	
+
 #if defined(__amd64)
 
 	ENTRY(ddi_get8)
@@ -289,7 +291,8 @@
 	movzbq	(%rsi), %rax
 	ret
 2:
-	jmp	*ACC_GETB(%rdi)
+	movq	ACC_GETB(%rdi), %rax
+	INDIRECT_JMP_REG(rax)
 	SET_SIZE(ddi_get8)
 	SET_SIZE(ddi_getb)
 	SET_SIZE(ddi_mem_getb)
@@ -351,7 +354,8 @@
 	movzwq	(%rsi), %rax
 	ret
 4:
-	jmp	*ACC_GETW(%rdi)
+	movq	ACC_GETW(%rdi), %rax
+	INDIRECT_JMP_REG(rax)
 	SET_SIZE(ddi_get16)
 	SET_SIZE(ddi_getw)
 	SET_SIZE(ddi_mem_getw)
@@ -412,7 +416,8 @@
 	movl	(%rsi), %eax
 	ret
 6:
-	jmp	*ACC_GETL(%rdi)
+	movq	ACC_GETL(%rdi), %rax
+	INDIRECT_JMP_REG(rax)
 	SET_SIZE(ddi_get32)
 	SET_SIZE(ddi_getl)
 	SET_SIZE(ddi_mem_getl)
@@ -458,7 +463,8 @@
 	ALTENTRY(ddi_getll)
 	ALTENTRY(ddi_mem_getll)
 	ALTENTRY(ddi_mem_get64)
-	jmp	*ACC_GETLL(%rdi)
+	movq	ACC_GETLL(%rdi), %rax
+	INDIRECT_JMP_REG(rax)
 	SET_SIZE(ddi_get64)
 	SET_SIZE(ddi_getll)
 	SET_SIZE(ddi_mem_getll)
@@ -500,7 +506,8 @@
 	movb	%dl, (%rsi)
 	ret
 8:
-	jmp	*ACC_PUTB(%rdi)
+	movq	ACC_PUTB(%rdi), %rax
+	INDIRECT_JMP_REG(rax)
 	SET_SIZE(ddi_put8)
 	SET_SIZE(ddi_putb)
 	SET_SIZE(ddi_mem_putb)
@@ -563,7 +570,8 @@
 	movw	%dx, (%rsi)
 	ret
 9:
-	jmp	*ACC_PUTW(%rdi)
+	movq	ACC_PUTW(%rdi), %rax
+	INDIRECT_JMP_REG(rax)
 	SET_SIZE(ddi_put16)
 	SET_SIZE(ddi_putw)
 	SET_SIZE(ddi_mem_putw)
@@ -626,7 +634,8 @@
 	movl	%edx, (%rsi)
 	ret
 9:
-	jmp	*ACC_PUTL(%rdi)
+	movq	ACC_PUTL(%rdi), %rax
+	INDIRECT_JMP_REG(rax)
 	SET_SIZE(ddi_put32)
 	SET_SIZE(ddi_putl)
 	SET_SIZE(ddi_mem_putl)
@@ -674,7 +683,8 @@
 	ALTENTRY(ddi_putll)
 	ALTENTRY(ddi_mem_putll)
 	ALTENTRY(ddi_mem_put64)
-	jmp	*ACC_PUTLL(%rdi)
+	movq	ACC_PUTLL(%rdi), %rax
+	INDIRECT_JMP_REG(rax)
 	SET_SIZE(ddi_put64)
 	SET_SIZE(ddi_putll)
 	SET_SIZE(ddi_mem_putll)
@@ -701,7 +711,8 @@
 	ALTENTRY(ddi_rep_getb)
 	ALTENTRY(ddi_mem_rep_getb)
 	ALTENTRY(ddi_mem_rep_get8)
-	jmp	*ACC_REP_GETB(%rdi)
+	movq	ACC_REP_GETB(%rdi), %rax
+	INDIRECT_JMP_REG(rax)
 	SET_SIZE(ddi_rep_get8)
 	SET_SIZE(ddi_rep_getb)
 	SET_SIZE(ddi_mem_rep_getb)
@@ -728,7 +739,8 @@
 	ALTENTRY(ddi_rep_getw)
 	ALTENTRY(ddi_mem_rep_getw)
 	ALTENTRY(ddi_mem_rep_get16)
-	jmp	*ACC_REP_GETW(%rdi)
+	movq	ACC_REP_GETW(%rdi), %rax
+	INDIRECT_JMP_REG(rax)
 	SET_SIZE(ddi_rep_get16)
 	SET_SIZE(ddi_rep_getw)
 	SET_SIZE(ddi_mem_rep_getw)
@@ -755,7 +767,8 @@
 	ALTENTRY(ddi_rep_getl)
 	ALTENTRY(ddi_mem_rep_getl)
 	ALTENTRY(ddi_mem_rep_get32)
-	jmp	*ACC_REP_GETL(%rdi)
+	movq	ACC_REP_GETL(%rdi), %rax
+	INDIRECT_JMP_REG(rax)
 	SET_SIZE(ddi_rep_get32)
 	SET_SIZE(ddi_rep_getl)
 	SET_SIZE(ddi_mem_rep_getl)
@@ -782,7 +795,8 @@
 	ALTENTRY(ddi_rep_getll)
 	ALTENTRY(ddi_mem_rep_getll)
 	ALTENTRY(ddi_mem_rep_get64)
-	jmp	*ACC_REP_GETLL(%rdi)
+	movq	ACC_REP_GETLL(%rdi), %rax
+	INDIRECT_JMP_REG(rax)
 	SET_SIZE(ddi_rep_get64)
 	SET_SIZE(ddi_rep_getll)
 	SET_SIZE(ddi_mem_rep_getll)
@@ -809,7 +823,8 @@
 	ALTENTRY(ddi_rep_putb)
 	ALTENTRY(ddi_mem_rep_putb)
 	ALTENTRY(ddi_mem_rep_put8)
-	jmp	*ACC_REP_PUTB(%rdi)
+	movq	ACC_REP_PUTB(%rdi), %rax
+	INDIRECT_JMP_REG(rax)
 	SET_SIZE(ddi_rep_put8)
 	SET_SIZE(ddi_rep_putb)
 	SET_SIZE(ddi_mem_rep_putb)
@@ -836,7 +851,8 @@
 	ALTENTRY(ddi_rep_putw)
 	ALTENTRY(ddi_mem_rep_putw)
 	ALTENTRY(ddi_mem_rep_put16)
-	jmp	*ACC_REP_PUTW(%rdi)
+	movq	ACC_REP_PUTW(%rdi), %rax
+	INDIRECT_JMP_REG(rax)
 	SET_SIZE(ddi_rep_put16)
 	SET_SIZE(ddi_rep_putw)
 	SET_SIZE(ddi_mem_rep_putw)
@@ -863,7 +879,8 @@
 	ALTENTRY(ddi_rep_putl)
 	ALTENTRY(ddi_mem_rep_putl)
 	ALTENTRY(ddi_mem_rep_put32)
-	jmp	*ACC_REP_PUTL(%rdi)
+	movq	ACC_REP_PUTL(%rdi), %rax
+	INDIRECT_JMP_REG(rax)
 	SET_SIZE(ddi_rep_put32)
 	SET_SIZE(ddi_rep_putl)
 	SET_SIZE(ddi_mem_rep_putl)
@@ -890,7 +907,8 @@
 	ALTENTRY(ddi_rep_putll)
 	ALTENTRY(ddi_mem_rep_putll)
 	ALTENTRY(ddi_mem_rep_put64)
-	jmp	*ACC_REP_PUTLL(%rdi)
+	movq	ACC_REP_PUTLL(%rdi), %rax
+	INDIRECT_JMP_REG(rax)
 	SET_SIZE(ddi_rep_put64)
 	SET_SIZE(ddi_rep_putll)
 	SET_SIZE(ddi_mem_rep_putll)
@@ -1336,7 +1354,7 @@
 	ret
 
 gb_ioadv:
-	andq	%rcx, %rcx		
+	andq	%rcx, %rcx
 	jz	gb_ioadv_done
 gb_ioadv2:
 	inb	(%dx)
@@ -1363,7 +1381,7 @@
 	cmpl	$DDI_DEV_AUTOINCR, 24(%esp)
 	je	gb_ioadv
 
-	rep	
+	rep
 	insb
 	popl	%edi
 	ret
@@ -1395,7 +1413,7 @@
 	je	gw_ioadv
 
 	movq	%rsi, %rdi
-	rep	
+	rep
 	insw
 	ret
 
@@ -1426,7 +1444,7 @@
 	cmpl	$DDI_DEV_AUTOINCR, 24(%esp)
 	je	gw_ioadv
 
-	rep	
+	rep
 	insw
 	popl	%edi
 	ret
@@ -1457,7 +1475,7 @@
 	je	gl_ioadv
 
 	movq	%rsi, %rdi
-	rep	
+	rep
 	insl
 	ret
 
@@ -1490,7 +1508,7 @@
 	cmpl	$DDI_DEV_AUTOINCR, 24(%esp)
 	je	gl_ioadv
 
-	rep	
+	rep
 	insl
 	popl	%edi
 	ret
@@ -1557,7 +1575,7 @@
 	je	pb_ioadv
 
 	movq	%rsi, %rdi
-	rep	
+	rep
 	outsb
 	ret
 
@@ -1588,7 +1606,7 @@
 	cmpl	$DDI_DEV_AUTOINCR, 24(%esp)
 	je	pb_ioadv
 
-	rep	
+	rep
 	outsb
 	popl	%esi
 	ret
@@ -1619,7 +1637,7 @@
 	je	pw_ioadv
 
 	movq	%rsi, %rdi
-	rep	
+	rep
 	outsw
 	ret
 
@@ -1650,7 +1668,7 @@
 	cmpl	$DDI_DEV_AUTOINCR, 24(%esp)
 	je	pw_ioadv
 
-	rep	
+	rep
 	outsw
 	popl	%esi
 	ret
@@ -1681,7 +1699,7 @@
 	je	pl_ioadv
 
 	movq	%rsi, %rdi
-	rep	
+	rep
 	outsl
 	ret
 
@@ -1712,7 +1730,7 @@
 	cmpl	$DDI_DEV_AUTOINCR, 24(%esp)
 	je	pl_ioadv
 
-	rep	
+	rep
 	outsl
 	popl	%esi
 	ret
--- old/usr/src/uts/intel/ia32/ml/exception.s	Wed Oct  9 03:12:33 2019
+++ new/usr/src/uts/intel/ia32/ml/exception.s	Wed Oct  9 03:12:33 2019
@@ -153,7 +153,7 @@
 	/*
 	 * At this point the stack looks like this:
 	 *
-	 * (high address) 	r_ss
+	 * (high address)	r_ss
 	 *			r_rsp
 	 *			r_rfl
 	 *			r_cs
@@ -308,7 +308,7 @@
 	call	av_dispatch_nmivect
 
 	INTR_POP
-	call	*x86_md_clear
+	call	x86_md_clear
 	jmp	tr_iret_auto
 	/*NOTREACHED*/
 	SET_SIZE(nmiint)
@@ -1026,7 +1026,8 @@
 	orl	%eax, %eax	/* (zero extend top 32-bits) */
 	leaq	fasttable(%rip), %r11
 	leaq	(%r11, %rax, CLONGSIZE), %r11
-	jmp	*(%r11)
+	movq	(%r11), %r11
+	INDIRECT_JMP_REG(r11)
 1:
 	/*
 	 * Fast syscall number was illegal.  Make it look
@@ -1086,7 +1087,7 @@
 	ENTRY_NP(fast_null)
 	XPV_TRAP_POP
 	orq	$PS_C, 24(%rsp)	/* set carry bit in user flags */
-	call	*x86_md_clear
+	call	x86_md_clear
 	jmp	tr_iret_auto
 	/*NOTREACHED*/
 	SET_SIZE(fast_null)
--- old/usr/src/uts/intel/ia32/ml/hypersubr.s	Wed Oct  9 03:12:34 2019
+++ new/usr/src/uts/intel/ia32/ml/hypersubr.s	Wed Oct  9 03:12:34 2019
@@ -24,6 +24,10 @@
  * Use is subject to license terms.
  */
 
+/*
+ * Copyright 2019 Joyent, Inc.
+ */
+
 #include <sys/asm_linkage.h>
 #ifndef __xpv
 #include <sys/xpv_support.h>
@@ -34,12 +38,12 @@
  * Hypervisor "system calls"
  *
  * i386
- * 	%eax == call number
- * 	args in registers (%ebx, %ecx, %edx, %esi, %edi)
+ *	%eax == call number
+ *	args in registers (%ebx, %ecx, %edx, %esi, %edi)
  *
  * amd64
- * 	%rax == call number
- * 	args in registers (%rdi, %rsi, %rdx, %r10, %r8, %r9)
+ *	%rax == call number
+ *	args in registers (%rdi, %rsi, %rdx, %r10, %r8, %r9)
  *
  * Note that for amd64 we use %r10 instead of %rcx for passing 4th argument
  * as in C calling convention since the "syscall" instruction clobbers %rcx.
@@ -164,7 +168,7 @@
 #define	TRAP_INSTR			\
 	shll	$5, %eax;		\
 	addq	$hypercall_page, %rax;	\
-	jmp	*%rax
+	INDIRECT_JMP_REG(rax);
 #else
 #define	TRAP_INSTR			\
 	shll	$5, %eax;		\
@@ -182,7 +186,7 @@
 #endif /* !__xpv */
 
 
-#if defined(__amd64) 
+#if defined(__amd64)
 
 	ENTRY_NP(__hypercall0)
 	ALTENTRY(__hypercall0_int)
--- old/usr/src/uts/intel/ia32/ml/i86_subr.s	Wed Oct  9 03:12:34 2019
+++ new/usr/src/uts/intel/ia32/ml/i86_subr.s	Wed Oct  9 03:12:34 2019
@@ -755,7 +755,7 @@
 
 	ENTRY_NP(i86_mwait)
 	pushq	%rbp
-	call	*x86_md_clear
+	call	x86_md_clear
 	movq	%rsp, %rbp
 	movq	%rdi, %rax		/* data */
 	movq	%rsi, %rcx		/* extensions */
@@ -1285,7 +1285,7 @@
 #elif defined(__i386)
 	pop	%ebx
 #endif
-	ret	
+	ret
 	SET_SIZE(wait_500ms)
 
 #define	RESET_METHOD_KBC	1
@@ -1683,16 +1683,16 @@
 #if defined(__amd64)
 
 	ENTRY(repinsb)
-	movl	%edx, %ecx	
+	movl	%edx, %ecx
 	movw	%di, %dx
 	movq	%rsi, %rdi
 	rep
 	  insb
-	ret		
+	ret
 	SET_SIZE(repinsb)
 
 #elif defined(__i386)
-	
+
 	/*
 	 * The arguments and saved registers are on the stack in the
 	 *  following order:
@@ -1737,7 +1737,7 @@
 #else	/* __lint */
 
 #if defined(__amd64)
-	
+
 	ENTRY(repinsd)
 	movl	%edx, %ecx
 	movw	%di, %dx
@@ -1783,7 +1783,7 @@
 	movw	%di, %dx
 	rep
 	  outsb
-	ret	
+	ret
 	SET_SIZE(repoutsb)
 
 #elif defined(__i386)
@@ -1799,7 +1799,7 @@
 	ret
 	SET_SIZE(repoutsb)
 
-#endif	/* __i386 */	
+#endif	/* __i386 */
 #endif	/* __lint */
 
 /*
@@ -1822,7 +1822,7 @@
 	movw	%di, %dx
 	rep
 	  outsl
-	ret	
+	ret
 	SET_SIZE(repoutsd)
 
 #elif defined(__i386)
@@ -2283,7 +2283,7 @@
 	SET_SIZE(dtrace_interrupt_disable)
 
 #elif defined(__i386)
-		
+
 	ENTRY(dtrace_interrupt_disable)
 	pushfl
 	popl	%eax
@@ -2307,7 +2307,7 @@
 	ret
 	SET_SIZE(dtrace_interrupt_disable)
 
-#endif	/* __i386 */	
+#endif	/* __i386 */
 #endif	/* __lint */
 
 #if defined(__lint)
@@ -2341,7 +2341,7 @@
 	SET_SIZE(dtrace_interrupt_enable)
 
 #elif defined(__i386)
-		
+
 	ENTRY(dtrace_interrupt_enable)
 	movl	4(%esp), %eax
 	pushl	%eax
@@ -2362,7 +2362,7 @@
 	ret
 	SET_SIZE(dtrace_interrupt_enable)
 
-#endif	/* __i386 */	
+#endif	/* __i386 */
 #endif	/* __lint */
 
 
@@ -2399,7 +2399,7 @@
 #else	/* __lint */
 
 #if defined(__amd64)
-	
+
 	ENTRY(threadp)
 	movq	%gs:CPU_THREAD, %rax
 	ret
@@ -2427,7 +2427,7 @@
 	ushort_t *address,	/* ptr to 1st message buffer */
 	int halfword_count,	/* length of data */
 	unsigned int sum)	/* partial checksum */
-{ 
+{
 	int		i;
 	unsigned int	psum = 0;	/* partial sum */
 
@@ -2560,7 +2560,8 @@
 	leaq	(%rdi, %rcx, 8), %rdi
 	xorl	%ecx, %ecx
 	clc
-	jmp 	*(%rdi)
+	movq	(%rdi), %rdi
+	INDIRECT_JMP_REG(rdi)
 
 	.align	8
 .ip_ocsum_jmptbl:
@@ -2671,7 +2672,7 @@
 	lea	(%edi, %ecx, 4), %edi
 	xorl	%ecx, %ecx
 	clc
-	jmp 	*(%edi)
+	jmp	*(%edi)
 	SET_SIZE(ip_ocsum)
 
 	.data
@@ -2682,8 +2683,8 @@
 	.long	.only24, .only28, .only32, .only36, .only40, .only44
 	.long	.only48, .only52, .only56, .only60
 
-	
-#endif	/* __i386 */		
+
+#endif	/* __i386 */
 #endif	/* __lint */
 
 /*
@@ -2707,7 +2708,7 @@
 	xorl	%edx, %edx	/* XX64 joe, paranoia? */
 	movl	%edi, %eax
 	mull	%esi
-	shlq	$32, %rdx	
+	shlq	$32, %rdx
 	orq	%rdx, %rax
 	ret
 	SET_SIZE(mul32)
@@ -2854,7 +2855,7 @@
 	ret
 0:
 	xorl	%eax, %eax
-	ret    
+	ret
 	SET_SIZE(highbit)
 
 	ENTRY(highbit64)
@@ -2908,7 +2909,7 @@
 #define	XMSR_ACCESS_VAL		$0x9c5a203a
 
 #if defined(__amd64)
-	
+
 	ENTRY(rdmsr)
 	movl	%edi, %ecx
 	rdmsr
@@ -2981,7 +2982,7 @@
 	ENTRY(wrmsr)
 	movl	4(%esp), %ecx
 	movl	8(%esp), %eax
-	movl	12(%esp), %edx 
+	movl	12(%esp), %edx
 	wrmsr
 	ret
 	SET_SIZE(wrmsr)
@@ -3003,7 +3004,7 @@
 	movl	%esp, %ebp
 	movl	8(%esp), %ecx
 	movl	12(%esp), %eax
-	movl	16(%esp), %edx 
+	movl	16(%esp), %edx
 	pushl	%edi
 	movl	XMSR_ACCESS_VAL, %edi	/* this value is needed to access MSR */
 	wrmsr
@@ -3202,13 +3203,13 @@
 	lock
 	  xchgl	%edx, (%rdi)
 	cmpl	$0, %edx
-	je	0f 
+	je	0f
 	movl	$0, %eax
 	ret
 0:	movl	$1, %eax
 	ret
 	SET_SIZE(panic_trigger)
-	
+
 	ENTRY_NP(dtrace_panic_trigger)
 	xorl	%eax, %eax
 	movl	$0xdefacedd, %edx
@@ -3284,8 +3285,8 @@
 #if defined(__amd64)
 
 	ENTRY_NP(vpanic)			/* Initial stack layout: */
-	
-	pushq	%rbp				/* | %rip | 	0x60	*/
+
+	pushq	%rbp				/* | %rip |	0x60	*/
 	movq	%rsp, %rbp			/* | %rbp |	0x58	*/
 	pushfq					/* | rfl  |	0x50	*/
 	pushq	%r11				/* | %r11 |	0x48	*/
@@ -3385,8 +3386,8 @@
 	movq	%rcx, REGOFF_SS(%rsp)
 
 	/*
-	 * panicsys(format, alist, rp, on_panic_stack) 
-	 */	
+	 * panicsys(format, alist, rp, on_panic_stack)
+	 */
 	movq	REGOFF_RDI(%rsp), %rdi		/* format */
 	movq	REGOFF_RSI(%rsp), %rsi		/* alist */
 	movq	%rsp, %rdx			/* struct regs */
@@ -3410,7 +3411,7 @@
 
 	ENTRY_NP(dtrace_vpanic)			/* Initial stack layout: */
 
-	pushq	%rbp				/* | %rip | 	0x60	*/
+	pushq	%rbp				/* | %rip |	0x60	*/
 	movq	%rsp, %rbp			/* | %rbp |	0x58	*/
 	pushfq					/* | rfl  |	0x50	*/
 	pushq	%r11				/* | %r11 |	0x48	*/
@@ -3466,7 +3467,7 @@
 	/*
 	 * Now that we've got everything set up, store the register values as
 	 * they were when we entered vpanic() to the designated location in
-	 * the regs structure we allocated on the stack. 
+	 * the regs structure we allocated on the stack.
 	 */
 #if !defined(__GNUC_AS__)
 	movw	%gs, %edx
@@ -3610,7 +3611,8 @@
 	 * At worst, performing this now instead of under CLOCK_LOCK may
 	 * introduce some jitter in pc_gethrestime().
 	 */
-	call	*gethrtimef(%rip)
+	movq	gethrtimef(%rip), %rsi
+	INDIRECT_CALL_REG(rsi)
 	movq	%rax, %r8
 
 	leaq	hres_lock(%rip), %rax
@@ -3638,8 +3640,8 @@
 	addq	%r8, hrestime+8(%rip)	/* add interval to hrestime.tv_nsec */
 	/*
 	 * Now that we have CLOCK_LOCK, we can update hres_last_tick
-	 */ 	
-	movq	%r11, (%rax)	
+	 */
+	movq	%r11, (%rax)
 
 	call	__adj_hrestime
 
@@ -3650,7 +3652,7 @@
 	leave
 	ret
 	SET_SIZE(hres_tick)
-	
+
 #elif defined(__i386)
 
 	ENTRY_NP(hres_tick)
@@ -3693,13 +3695,13 @@
 	movl	%ebx, %edx
 	movl	%esi, %ecx
 
-	subl 	(%eax), %edx
-	sbbl 	4(%eax), %ecx
+	subl	(%eax), %edx
+	sbbl	4(%eax), %ecx
 
 	addl	%edx, hrtime_base	/ add interval to hrtime_base
 	adcl	%ecx, hrtime_base+4
 
-	addl 	%edx, hrestime+4	/ add interval to hrestime.tv_nsec
+	addl	%edx, hrestime+4	/ add interval to hrestime.tv_nsec
 
 	/
 	/ Now that we have CLOCK_LOCK, we can update hres_last_tick.
@@ -3933,9 +3935,9 @@
 	movzbl	%dl, %eax
 	ret
 	SET_SIZE(bcmp)
-	
+
 #elif defined(__i386)
-	
+
 #define	ARG_S1		8
 #define	ARG_S2		12
 #define	ARG_LENGTH	16
@@ -4090,7 +4092,7 @@
 	movq	%rdx, %rdi		/* pass func arg 1 */
 	movq	%rsi, %r11		/* save function to call */
 	movq	%rcx, %rsi		/* pass func arg 2 */
-	call	*%r11			/* call function */
+	INDIRECT_CALL_REG(r11)		/* call function */
 	leave				/* restore stack */
 	ret
 	SET_SIZE(switch_sp_and_call)
@@ -4140,7 +4142,7 @@
 	call	intr_restore
 
 	leave
-	ret	
+	ret
 	SET_SIZE(kmdb_enter)
 
 #elif defined(__i386)
@@ -4164,7 +4166,7 @@
 	addl	$4, %esp
 
 	leave
-	ret	
+	ret
 	SET_SIZE(kmdb_enter)
 
 #endif	/* __i386 */
@@ -4261,7 +4263,7 @@
 	SET_SIZE(ftrace_interrupt_disable)
 
 #elif defined(__i386)
-		
+
 	ENTRY(ftrace_interrupt_disable)
 	pushfl
 	popl	%eax
@@ -4269,7 +4271,7 @@
 	ret
 	SET_SIZE(ftrace_interrupt_disable)
 
-#endif	/* __i386 */	
+#endif	/* __i386 */
 #endif	/* __lint */
 
 #if defined(__lint)
@@ -4290,7 +4292,7 @@
 	SET_SIZE(ftrace_interrupt_enable)
 
 #elif defined(__i386)
-		
+
 	ENTRY(ftrace_interrupt_enable)
 	movl	4(%esp), %eax
 	pushl	%eax
@@ -4353,7 +4355,7 @@
  * depending on magic values in certain registers and modifies some registers
  * as a side effect.
  *
- * References: http://kb.vmware.com/kb/1009458 
+ * References: http://kb.vmware.com/kb/1009458
  */
 
 #if defined(__lint)
--- old/usr/src/uts/intel/ia32/ml/lock_prim.s	Wed Oct  9 03:12:35 2019
+++ new/usr/src/uts/intel/ia32/ml/lock_prim.s	Wed Oct  9 03:12:35 2019
@@ -588,7 +588,8 @@
 	pushq	%rbp				/* align stack properly */
 	movq	%rsp, %rbp
 	movl	%eax, %edi
-	call	*lockstat_probe
+	movq	lockstat_probe, %rax
+	INDIRECT_CALL_REG(rax)
 	leave					/* unwind stack */
 1:
 	movq	%gs:CPU_THREAD, %rdx		/* reload thread ptr */
@@ -610,7 +611,8 @@
 	pushq	%rbp				/* align stack properly */
 	movq	%rsp, %rbp
 	movl	%eax, %edi
-	call	*lockstat_probe
+	movq	lockstat_probe, %rax
+	INDIRECT_CALL_REG(rax)
 	leave					/* unwind stack */
 1:
 	movq	%gs:CPU_THREAD, %rdx		/* reload thread ptr */
--- old/usr/src/uts/intel/ia32/ml/modstubs.s	Wed Oct  9 03:12:35 2019
+++ new/usr/src/uts/intel/ia32/ml/modstubs.s	Wed Oct  9 03:12:35 2019
@@ -21,7 +21,7 @@
 
 /*
  * Copyright (c) 1992, 2010, Oracle and/or its affiliates. All rights reserved.
- * Copyright (c) 2017, Joyent, Inc. All rights reserved.
+ * Copyright 2019 Joyent, Inc.
  */
 
 #include <sys/asm_linkage.h>
@@ -64,7 +64,7 @@
 /*
  * This file uses ansi preprocessor features:
  *
- * 1. 	#define mac(a) extra_ ## a     -->   mac(x) expands to extra_a
+ * 1.   #define mac(a) extra_ ## a     -->   mac(x) expands to extra_a
  * The old version of this is
  *      #define mac(a) extra_/.*.*./a
  * but this fails if the argument has spaces "mac ( x )"
@@ -91,8 +91,6 @@
  * This file contains the stubs routines for modules which can be autoloaded.
  */
 
-#if defined(__amd64)
-
 /*
  * See the 'struct mod_modinfo' definition to see what this declaration
  * is trying to achieve here.
@@ -130,7 +128,8 @@
 	je	stubs_common_code;			/* not weak */	\
 	testb	$MODS_INSTALLED, MODS_FLAG(%rax);	/* installed? */ \
 	jne	stubs_common_code;		/* yes, do the mod_hold */ \
-	jmp	*MODS_RETFCN(%rax);		/* no, jump to retfcn */ \
+	movq	MODS_RETFCN(%rax), %rax;	/* no, load retfcn */	\
+	INDIRECT_JMP_REG(rax);			/* no, jump to retfcn */ \
 	SET_SIZE(fcnname);						\
 	.data;								\
 	.align	 CPTRSIZE;						\
@@ -148,10 +147,12 @@
 	leaq	fcnname/**/_info(%rip), %rax;				\
 	testb	$MODS_INSTALLED, MODS_FLAG(%rax); /* installed? */	\
 	je	5f;			/* no */			\
-	jmp	*(%rax);		/* yes, jump to install_fcn */	\
+	movq	MODS_INSTFCN(%rax), %rax; /* yes, load install_fcn */	\
+	INDIRECT_JMP_REG(rax);		/* yes, jump to install_fcn */	\
 5:	testb	$MODS_WEAK, MODS_FLAG(%rax);	/* weak? */		\
 	je	stubs_common_code;	/* no, do mod load */		\
-	jmp	*MODS_RETFCN(%rax);	/* yes, jump to retfcn */	\
+	movq	MODS_RETFCN(%rax), %rax; /* yes, load retfcn */		\
+	INDIRECT_JMP_REG(rax);		/* yes, jump to retfcn */	\
 	SET_SIZE(fcnname);						\
 	.data;								\
 	.align	CPTRSIZE;						\
@@ -190,7 +191,7 @@
 	cmpl	$-1, %eax		/* error? */
 	jne	.L1
 	movq	0x18(%r15), %rax
-	call	*%rax
+	INDIRECT_CALL_REG(rax)
 	addq	$0x30, %rsp
 	jmp	.L2
 .L1:
@@ -219,7 +220,8 @@
 	pushq	(%rsp, %r11, 8)
 	pushq	(%rsp, %r11, 8)
 	pushq	(%rsp, %r11, 8)
-	call	*(%r15)			/* call the stub fn(arg, ..) */
+	movq	(%r15), %rax
+	INDIRECT_CALL_REG(rax)		/* call the stub fn(arg, ..) */
 	addq	$0x20, %rsp		/* pop off last 4 args */
 	pushq	%rax			/* save any return values */
 	pushq	%rdx
@@ -233,134 +235,6 @@
 	ret
 	SET_SIZE(stubs_common_code)
 
-#elif defined(__i386)
-
-/*
- * See the 'struct mod_modinfo' definition to see what this declaration
- * is trying to achieve here.
- */
-#define MODULE(module,namespace)	\
-	.data;				\
-module/**/_modname:			\
-	.string	"namespace/module";	\
-	SET_SIZE(module/**/_modname);	\
-	.align	CPTRSIZE;		\
-	.globl	module/**/_modinfo;	\
-	.type	module/**/_modinfo, @object;	\
-module/**/_modinfo:			\
-	.long	module/**/_modname;	\
-	.long	0	/* storage for modctl pointer */
-
-	/* then mod_stub_info structures follow until a mods_func_adr is 0 */
-
-/* this puts a 0 where the next mods_func_adr would be */
-#define END_MODULE(module)		\
-	.data;				\
-	.align	CPTRSIZE;		\
-	.long 0;			\
-	SET_SIZE(module/**/_modinfo)
-
-/*
- * The data section in the stub_common macro is the
- * mod_stub_info structure for the stub function
- */
-
-/*	
- * The flag MODS_INSTALLED is stored in the stub data and is used to
- * indicate if a module is installed and initialized.  This flag is used
- * instead of the mod_stub_info->mods_modinfo->mod_installed flag
- * to minimize the number of pointer de-references for each function
- * call (and also to avoid possible TLB misses which could be induced
- * by dereferencing these pointers.)
- */	
-
-#define STUB_COMMON(module, fcnname, install_fcn, retfcn, weak)		\
-	ENTRY(fcnname);							\
-	leal	fcnname/**/_info, %eax;					\
-	cmpl	$0, MODS_FLAG(%eax);	/* weak? */			\
-	je	stubs_common_code;	/* not weak */			\
-	testb	$MODS_INSTALLED, MODS_FLAG(%eax); /* installed? */	\
-	jne	stubs_common_code;	/* yes, do the mod_hold */	\
-	jmp	*MODS_RETFCN(%eax);	/* no, just jump to retfcn */	\
-	SET_SIZE(fcnname);						\
-	.data;								\
-	.align	 CPTRSIZE;						\
-	.type	fcnname/**/_info, @object;				\
-fcnname/**/_info:							\
-	.long	install_fcn;						\
-	.long	module/**/_modinfo;					\
-	.long	fcnname;						\
-	.long	retfcn;							\
-	.long   weak;							\
-	SET_SIZE(fcnname/**/_info)
-	
-#define STUB_NO_UNLOADABLE(module, fcnname, install_fcn, retfcn, weak)	\
-	ENTRY(fcnname);							\
-	leal	fcnname/**/_info, %eax;					\
-	testb	$MODS_INSTALLED, MODS_FLAG(%eax); /* installed? */	\
-	je	5f;		/* no */				\
-	jmp	*(%eax);	/* yes, just jump to install_fcn */	\
-5:	testb	$MODS_WEAK, MODS_FLAG(%eax);	/* weak? */		\
-	je	stubs_common_code;	/* no, do mod load */		\
-	jmp	*MODS_RETFCN(%eax);	/* yes, just jump to retfcn */ 	\
-	SET_SIZE(fcnname);						\
-	.data;								\
-	.align	CPTRSIZE;						\
-	.type	fcnname/**/_info, @object;				\
-fcnname/**/_info:							\
-	.long	install_fcn;		/* 0 */				\
-	.long	module/**/_modinfo;	/* 0x4 */			\
-	.long	fcnname;		/* 0x8 */			\
-	.long	retfcn;			/* 0xc */			\
-	.long   weak;			/* 0x10 */			\
-	SET_SIZE(fcnname/**/_info)
-
-/*
- * We branch here with the fcnname_info pointer in %eax
- */
-	ENTRY_NP(stubs_common_code)
-	.globl	mod_hold_stub
-	.globl	mod_release_stub
-	pushl	%esi
-	movl	%eax, %esi		/ save the info pointer
-	pushl	%eax
-	call	mod_hold_stub		/ mod_hold_stub(mod_stub_info *)
-	popl	%ecx
-	cmpl	$-1, %eax		/ error?
-	jne	.L1
-	movl	MODS_RETFCN(%esi), %eax
-	call    *%eax	
-	popl	%esi			/ yes, return error (panic?)
-	ret
-.L1:
-	movl	$MAXNARG+1, %ecx
-	/ copy incoming arguments
-	pushl	(%esp, %ecx, 4)		/ push MAXNARG times
-	pushl	(%esp, %ecx, 4)
-	pushl	(%esp, %ecx, 4)
-	pushl	(%esp, %ecx, 4)
-	pushl	(%esp, %ecx, 4)
-	pushl	(%esp, %ecx, 4)
-	pushl	(%esp, %ecx, 4)
-	pushl	(%esp, %ecx, 4)
-	pushl	(%esp, %ecx, 4)
-	pushl	(%esp, %ecx, 4)
-	call	*(%esi)			/ call the stub function(arg1,arg2, ...)
-	add	$_MUL(MAXNARG, 4), %esp	/ pop off MAXNARG arguments
-	pushl	%eax			/ save any return values from the stub
-	pushl	%edx
-	pushl	%esi
-	call	mod_release_stub	/ release hold on module
-	addl	$4, %esp
-	popl	%edx			/ restore return values
-	popl	%eax
-.L2:
-	popl	%esi
-	ret
-	SET_SIZE(stubs_common_code)
-
-#endif	/* __i386 */
-
 #define STUB(module, fcnname, retfcn)	\
     STUB_COMMON(module, fcnname, mod_hold_stub, retfcn, 0)
 
@@ -393,11 +267,11 @@
 
 /*
  * WARNING WARNING WARNING!!!!!!
- * 
+ *
  * On the MODULE macro you MUST NOT use any spaces!!! They are
  * significant to the preprocessor.  With ansi c there is a way around this
  * but for some reason (yet to be investigated) ansi didn't work for other
- * reasons!  
+ * reasons!
  *
  * When zero is used as the return function, the system will call
  * panic if the stub can't be resolved.
@@ -439,15 +313,15 @@
 	MODULE(specfs,fs);
 	NO_UNLOAD_STUB(specfs, common_specvp,		nomod_zero);
 	NO_UNLOAD_STUB(specfs, makectty,		nomod_zero);
-	NO_UNLOAD_STUB(specfs, makespecvp,     		nomod_zero);
-	NO_UNLOAD_STUB(specfs, smark,          		nomod_zero);
-	NO_UNLOAD_STUB(specfs, spec_segmap,    		nomod_einval);
-	NO_UNLOAD_STUB(specfs, specfind,       		nomod_zero);
-	NO_UNLOAD_STUB(specfs, specvp,         		nomod_zero);
+	NO_UNLOAD_STUB(specfs, makespecvp,		nomod_zero);
+	NO_UNLOAD_STUB(specfs, smark,			nomod_zero);
+	NO_UNLOAD_STUB(specfs, spec_segmap,		nomod_einval);
+	NO_UNLOAD_STUB(specfs, specfind,		nomod_zero);
+	NO_UNLOAD_STUB(specfs, specvp,			nomod_zero);
 	NO_UNLOAD_STUB(specfs, devi_stillreferenced,	nomod_zero);
 	NO_UNLOAD_STUB(specfs, spec_getvnodeops,	nomod_zero);
 	NO_UNLOAD_STUB(specfs, spec_char_map,		nomod_zero);
-	NO_UNLOAD_STUB(specfs, specvp_devfs,  		nomod_zero);
+	NO_UNLOAD_STUB(specfs, specvp_devfs,		nomod_zero);
 	NO_UNLOAD_STUB(specfs, spec_assoc_vp_with_devi,	nomod_void);
 	NO_UNLOAD_STUB(specfs, spec_hold_devi_by_vp,	nomod_zero);
 	NO_UNLOAD_STUB(specfs, spec_snode_walk,		nomod_void);
@@ -465,19 +339,19 @@
  */
 #ifndef SOCK_MODULE
 	MODULE(sockfs,fs);
-	NO_UNLOAD_STUB(sockfs, so_socket,  	nomod_zero);
+	NO_UNLOAD_STUB(sockfs, so_socket,	nomod_zero);
 	NO_UNLOAD_STUB(sockfs, so_socketpair,	nomod_zero);
-	NO_UNLOAD_STUB(sockfs, bind,  		nomod_zero);
-	NO_UNLOAD_STUB(sockfs, listen,  	nomod_zero);
-	NO_UNLOAD_STUB(sockfs, accept,  	nomod_zero);
-	NO_UNLOAD_STUB(sockfs, connect,  	nomod_zero);
-	NO_UNLOAD_STUB(sockfs, shutdown,  	nomod_zero);
-	NO_UNLOAD_STUB(sockfs, recv,  		nomod_zero);
-	NO_UNLOAD_STUB(sockfs, recvfrom,  	nomod_zero);
-	NO_UNLOAD_STUB(sockfs, recvmsg,  	nomod_zero);
-	NO_UNLOAD_STUB(sockfs, send,  		nomod_zero);
-	NO_UNLOAD_STUB(sockfs, sendmsg,  	nomod_zero);
-	NO_UNLOAD_STUB(sockfs, sendto,  	nomod_zero);
+	NO_UNLOAD_STUB(sockfs, bind,		nomod_zero);
+	NO_UNLOAD_STUB(sockfs, listen,		nomod_zero);
+	NO_UNLOAD_STUB(sockfs, accept,		nomod_zero);
+	NO_UNLOAD_STUB(sockfs, connect,		nomod_zero);
+	NO_UNLOAD_STUB(sockfs, shutdown,	nomod_zero);
+	NO_UNLOAD_STUB(sockfs, recv,		nomod_zero);
+	NO_UNLOAD_STUB(sockfs, recvfrom,	nomod_zero);
+	NO_UNLOAD_STUB(sockfs, recvmsg,		nomod_zero);
+	NO_UNLOAD_STUB(sockfs, send,		nomod_zero);
+	NO_UNLOAD_STUB(sockfs, sendmsg,		nomod_zero);
+	NO_UNLOAD_STUB(sockfs, sendto,		nomod_zero);
 #ifdef _SYSCALL32_IMPL
 	NO_UNLOAD_STUB(sockfs, recv32,		nomod_zero);
 	NO_UNLOAD_STUB(sockfs, recvfrom32,	nomod_zero);
@@ -484,19 +358,19 @@
 	NO_UNLOAD_STUB(sockfs, send32,		nomod_zero);
 	NO_UNLOAD_STUB(sockfs, sendto32,	nomod_zero);
 #endif	/* _SYSCALL32_IMPL */
-	NO_UNLOAD_STUB(sockfs, getpeername,  	nomod_zero);
-	NO_UNLOAD_STUB(sockfs, getsockname,  	nomod_zero);
-	NO_UNLOAD_STUB(sockfs, getsockopt,  	nomod_zero);
-	NO_UNLOAD_STUB(sockfs, setsockopt,  	nomod_zero);
-	NO_UNLOAD_STUB(sockfs, sockconfig,  	nomod_zero);
-	NO_UNLOAD_STUB(sockfs, sock_getmsg,  	nomod_zero);
-	NO_UNLOAD_STUB(sockfs, sock_putmsg,  	nomod_zero);
-	NO_UNLOAD_STUB(sockfs, sosendfile64,  	nomod_zero);
-	NO_UNLOAD_STUB(sockfs, snf_segmap,  	nomod_einval);
-	NO_UNLOAD_STUB(sockfs, sock_getfasync,  nomod_zero);
-	NO_UNLOAD_STUB(sockfs, nl7c_sendfilev,  nomod_zero);
-	NO_UNLOAD_STUB(sockfs, sotpi_sototpi,  nomod_zero);
-	NO_UNLOAD_STUB(sockfs, socket_sendmblk,  nomod_zero);
+	NO_UNLOAD_STUB(sockfs, getpeername,	nomod_zero);
+	NO_UNLOAD_STUB(sockfs, getsockname,	nomod_zero);
+	NO_UNLOAD_STUB(sockfs, getsockopt,	nomod_zero);
+	NO_UNLOAD_STUB(sockfs, setsockopt,	nomod_zero);
+	NO_UNLOAD_STUB(sockfs, sockconfig,	nomod_zero);
+	NO_UNLOAD_STUB(sockfs, sock_getmsg,	nomod_zero);
+	NO_UNLOAD_STUB(sockfs, sock_putmsg,	nomod_zero);
+	NO_UNLOAD_STUB(sockfs, sosendfile64,	nomod_zero);
+	NO_UNLOAD_STUB(sockfs, snf_segmap,	nomod_einval);
+	NO_UNLOAD_STUB(sockfs, sock_getfasync,	nomod_zero);
+	NO_UNLOAD_STUB(sockfs, nl7c_sendfilev,	nomod_zero);
+	NO_UNLOAD_STUB(sockfs, sotpi_sototpi,	nomod_zero);
+	NO_UNLOAD_STUB(sockfs, socket_sendmblk,	nomod_zero);
 	NO_UNLOAD_STUB(sockfs, socket_setsockopt,  nomod_zero);
 	END_MODULE(sockfs);
 #endif
@@ -594,7 +468,7 @@
 	NO_UNLOAD_STUB(klmmod, lm_shutdown,	nomod_zero);
 	NO_UNLOAD_STUB(klmmod, lm_unexport,	nomod_zero);
 	NO_UNLOAD_STUB(klmmod, lm_cprresume,	nomod_zero);
-	NO_UNLOAD_STUB(klmmod, lm_cprsuspend,	nomod_zero); 
+	NO_UNLOAD_STUB(klmmod, lm_cprsuspend,	nomod_zero);
 	NO_UNLOAD_STUB(klmmod, lm_safelock, nomod_zero);
 	NO_UNLOAD_STUB(klmmod, lm_safemap, nomod_zero);
 	NO_UNLOAD_STUB(klmmod, lm_has_sleep, nomod_zero);
@@ -602,8 +476,8 @@
 	NO_UNLOAD_STUB(klmmod, lm_vp_active, nomod_zero);
 	NO_UNLOAD_STUB(klmmod, lm_get_sysid, nomod_zero);
 	NO_UNLOAD_STUB(klmmod, lm_rel_sysid, nomod_zero);
-	NO_UNLOAD_STUB(klmmod, lm_alloc_sysidt, nomod_minus_one); 
-	NO_UNLOAD_STUB(klmmod, lm_free_sysidt, nomod_zero); 
+	NO_UNLOAD_STUB(klmmod, lm_alloc_sysidt, nomod_minus_one);
+	NO_UNLOAD_STUB(klmmod, lm_free_sysidt, nomod_zero);
 	NO_UNLOAD_STUB(klmmod, lm_sysidt, nomod_minus_one);
 	END_MODULE(klmmod);
 #endif
@@ -663,8 +537,8 @@
  */
 #ifndef DES_MODULE
 	MODULE(des,misc);
-	STUB(des, cbc_crypt, 	 	nomod_zero);
-	STUB(des, ecb_crypt, 		nomod_zero);
+	STUB(des, cbc_crypt,		nomod_zero);
+	STUB(des, ecb_crypt,		nomod_zero);
 	STUB(des, _des_crypt,		nomod_zero);
 	END_MODULE(des);
 #endif
@@ -683,7 +557,7 @@
 	NO_UNLOAD_STUB(procfs, prgetcred,	nomod_zero);
 	NO_UNLOAD_STUB(procfs, prgetpriv,	nomod_zero);
 	NO_UNLOAD_STUB(procfs, prgetprivsize,	nomod_zero);
-       	NO_UNLOAD_STUB(procfs, prgetsecflags,	nomod_zero);
+	NO_UNLOAD_STUB(procfs, prgetsecflags,	nomod_zero);
 	NO_UNLOAD_STUB(procfs, prgetstatus,	nomod_zero);
 	NO_UNLOAD_STUB(procfs, prgetlwpstatus,	nomod_zero);
 	NO_UNLOAD_STUB(procfs, prgetpsinfo,	nomod_zero);
@@ -721,7 +595,7 @@
  */
 #ifndef FIFO_MODULE
 	MODULE(fifofs,fs);
-	NO_UNLOAD_STUB(fifofs, fifovp,      	nomod_zero);
+	NO_UNLOAD_STUB(fifofs, fifovp,		nomod_zero);
 	NO_UNLOAD_STUB(fifofs, fifo_getinfo,	nomod_zero);
 	NO_UNLOAD_STUB(fifofs, fifo_vfastoff,	nomod_zero);
 	END_MODULE(fifofs);
@@ -764,7 +638,7 @@
  */
 #ifndef NAMEFS_MODULE
 	MODULE(namefs,fs);
-	STUB(namefs, nm_unmountall, 	0);
+	STUB(namefs, nm_unmountall,	0);
 	END_MODULE(namefs);
 #endif
 
@@ -864,13 +738,13 @@
 	END_MODULE(consconfig);
 #endif
 
-/* 
+/*
  * Stubs for accounting.
  */
 #ifndef SYSACCT_MODULE
 	MODULE(sysacct,sys);
-	NO_UNLOAD_WSTUB(sysacct, acct,  		nomod_zero);
-	NO_UNLOAD_WSTUB(sysacct, acct_fs_in_use, 	nomod_zero);
+	NO_UNLOAD_WSTUB(sysacct, acct,			nomod_zero);
+	NO_UNLOAD_WSTUB(sysacct, acct_fs_in_use,	nomod_zero);
 	END_MODULE(sysacct);
 #endif
 
@@ -957,7 +831,7 @@
 #ifndef C2AUDIT_MODULE
 	MODULE(c2audit,sys);
 	NO_UNLOAD_STUB(c2audit, audit_init_module,	nomod_zero);
-	NO_UNLOAD_STUB(c2audit, audit_start, 		nomod_zero);
+	NO_UNLOAD_STUB(c2audit, audit_start,		nomod_zero);
 	NO_UNLOAD_STUB(c2audit, audit_finish,		nomod_zero);
 	NO_UNLOAD_STUB(c2audit, audit,			nomod_zero);
 	NO_UNLOAD_STUB(c2audit, auditdoor,		nomod_zero);
@@ -1009,7 +883,7 @@
 	NO_UNLOAD_STUB(rpcsec, sec_svc_control,		nomod_zero);
 	END_MODULE(rpcsec);
 #endif
- 
+
 /*
  * Stubs for rpc RPCSEC_GSS security service module
  */
@@ -1106,7 +980,7 @@
 
 /*
  * Clustering: stubs for cluster infrastructure.
- */	
+ */
 #ifndef CL_COMM_MODULE
 	MODULE(cl_comm,misc);
 	NO_UNLOAD_STUB(cl_comm, cladmin, nomod_minus_one);
@@ -1408,12 +1282,10 @@
  */
 #ifndef ELFEXEC_MODULE
 	MODULE(elfexec,exec);
-	STUB(elfexec, elfexec,      	nomod_einval);
+	STUB(elfexec, elfexec,		nomod_einval);
 	STUB(elfexec, mapexec_brand,	nomod_einval);
-#if defined(__amd64)
 	STUB(elfexec, elf32exec,	nomod_einval);
 	STUB(elfexec, mapexec32_brand,	nomod_einval);
-#endif
 	END_MODULE(elfexec);
 #endif
 
@@ -1426,7 +1298,9 @@
 	END_MODULE(apix);
 #endif
 
-/ this is just a marker for the area of text that contains stubs 
+/*
+ * this is just a marker for the area of text that contains stubs
+ */
 
 	ENTRY_NP(stubs_end)
 	nop
--- /dev/null	Wed Oct  9 03:12:35 2019
+++ new/usr/src/uts/intel/ia32/ml/retpoline.s	Wed Oct  9 03:12:35 2019
@@ -0,0 +1,211 @@
+/*
+ * This file and its contents are supplied under the terms of the
+ * Common Development and Distribution License ("CDDL"), version 1.0.
+ * You may only use this file in accordance with the terms of version
+ * 1.0 of the CDDL.
+ *
+ * A full copy of the text of the CDDL should have accompanied this
+ * source.  A copy of the CDDL is also available via the Internet at
+ * http://www.illumos.org/license/CDDL.
+ */
+
+/*
+ * Copyright 2019 Joyent, Inc.
+ */
+
+	.file	"retpoline.s"
+
+/*
+ * This file implements the various hooks that are needed for retpolines and
+ * return stack buffer (RSB) stuffing. For more information, please see the
+ * 'Speculative Execution CPU Side Channel Security' section of the
+ * uts/i86pc/os/cpuid.c big theory statement.
+ */
+
+#include <sys/asm_linkage.h>
+#include <sys/x86_archext.h>
+
+#if defined(__amd64)
+
+/*
+ * This macro generates the default retpoline entry point that the compiler
+ * expects. It implements the expected retpoline form.
+ */
+#define	RETPOLINE_MKTHUNK(reg) \
+	ENTRY(__x86_indirect_thunk_/**/reg)	\
+	call	2f;				\
+1:						\
+	pause;					\
+	lfence;					\
+	jmp	1b;				\
+2:						\
+	movq	%/**/reg, (%rsp);		\
+	ret;					\
+	SET_SIZE(__x86_indirect_thunk_/**/reg)
+
+/*
+ * This macro generates the default retpoline form. It exists in addition to the
+ * thunk so if we need to restore the default retpoline behavior to the thunk
+ * we can.
+ */
+#define	RETPOLINE_MKGENERIC(reg) \
+	ENTRY(__x86_indirect_thunk_gen_/**/reg)	\
+	call	2f;				\
+1:						\
+	pause;					\
+	lfence;					\
+	jmp	1b;				\
+2:						\
+	movq	%/**/reg, (%rsp);		\
+	ret;					\
+	SET_SIZE(__x86_indirect_thunk_gen_/**/reg)
+
+/*
+ * This macro generates the AMD optimized form of a retpoline which will be used
+ * on systems where the lfence dispatch serializing behavior has been changed.
+ */
+#define	RETPOLINE_MKLFENCE(reg)			\
+	ENTRY(__x86_indirect_thunk_amd_/**/reg)	\
+	lfence;					\
+	jmp	*%/**/reg;			\
+	SET_SIZE(__x86_indirect_thunk_amd_/**/reg)
+
+
+/*
+ * This macro generates the no-op form of the retpoline which will be used if we
+ * either need to disable retpolines because we have enhanced IBRS or because we
+ * have been asked to disable mitigations.
+ */
+#define	RETPOLINE_MKJUMP(reg)			\
+	ENTRY(__x86_indirect_thunk_jmp_/**/reg)	\
+	jmp	*%/**/reg;			\
+	SET_SIZE(__x86_indirect_thunk_jmp_/**/reg)
+
+	RETPOLINE_MKTHUNK(rax)
+	RETPOLINE_MKTHUNK(rbx)
+	RETPOLINE_MKTHUNK(rcx)
+	RETPOLINE_MKTHUNK(rdx)
+	RETPOLINE_MKTHUNK(rdi)
+	RETPOLINE_MKTHUNK(rsi)
+	RETPOLINE_MKTHUNK(rbp)
+	RETPOLINE_MKTHUNK(r8)
+	RETPOLINE_MKTHUNK(r9)
+	RETPOLINE_MKTHUNK(r10)
+	RETPOLINE_MKTHUNK(r11)
+	RETPOLINE_MKTHUNK(r12)
+	RETPOLINE_MKTHUNK(r13)
+	RETPOLINE_MKTHUNK(r14)
+	RETPOLINE_MKTHUNK(r15)
+
+	RETPOLINE_MKGENERIC(rax)
+	RETPOLINE_MKGENERIC(rbx)
+	RETPOLINE_MKGENERIC(rcx)
+	RETPOLINE_MKGENERIC(rdx)
+	RETPOLINE_MKGENERIC(rdi)
+	RETPOLINE_MKGENERIC(rsi)
+	RETPOLINE_MKGENERIC(rbp)
+	RETPOLINE_MKGENERIC(r8)
+	RETPOLINE_MKGENERIC(r9)
+	RETPOLINE_MKGENERIC(r10)
+	RETPOLINE_MKGENERIC(r11)
+	RETPOLINE_MKGENERIC(r12)
+	RETPOLINE_MKGENERIC(r13)
+	RETPOLINE_MKGENERIC(r14)
+	RETPOLINE_MKGENERIC(r15)
+
+	RETPOLINE_MKLFENCE(rax)
+	RETPOLINE_MKLFENCE(rbx)
+	RETPOLINE_MKLFENCE(rcx)
+	RETPOLINE_MKLFENCE(rdx)
+	RETPOLINE_MKLFENCE(rdi)
+	RETPOLINE_MKLFENCE(rsi)
+	RETPOLINE_MKLFENCE(rbp)
+	RETPOLINE_MKLFENCE(r8)
+	RETPOLINE_MKLFENCE(r9)
+	RETPOLINE_MKLFENCE(r10)
+	RETPOLINE_MKLFENCE(r11)
+	RETPOLINE_MKLFENCE(r12)
+	RETPOLINE_MKLFENCE(r13)
+	RETPOLINE_MKLFENCE(r14)
+	RETPOLINE_MKLFENCE(r15)
+
+	RETPOLINE_MKJUMP(rax)
+	RETPOLINE_MKJUMP(rbx)
+	RETPOLINE_MKJUMP(rcx)
+	RETPOLINE_MKJUMP(rdx)
+	RETPOLINE_MKJUMP(rdi)
+	RETPOLINE_MKJUMP(rsi)
+	RETPOLINE_MKJUMP(rbp)
+	RETPOLINE_MKJUMP(r8)
+	RETPOLINE_MKJUMP(r9)
+	RETPOLINE_MKJUMP(r10)
+	RETPOLINE_MKJUMP(r11)
+	RETPOLINE_MKJUMP(r12)
+	RETPOLINE_MKJUMP(r13)
+	RETPOLINE_MKJUMP(r14)
+	RETPOLINE_MKJUMP(r15)
+
+	/*
+	 * The x86_rsb_stuff function is called from pretty arbitrary
+	 * contexts. It's much easier for us to save and restore all the
+	 * registers we touch rather than clobber them for callers. You must
+	 * preserve this property or the system will panic at best.
+	 */
+	ENTRY(x86_rsb_stuff)
+	/*
+	 * These nops are present so we can patch a ret instruction if we need
+	 * to disable RSB stuffing because enhanced IBRS is present or we're
+	 * disabling mitigations.
+	 */
+	nop
+	nop
+	pushq	%rdi
+	pushq	%rax
+	movl	$16, %edi
+	movq	%rsp, %rax
+rsb_loop:
+	call	2f
+1:
+	pause
+	call	1b
+2:
+	call	2f
+1:
+	pause
+	call	1b
+2:
+	subl	$1, %edi
+	jnz	rsb_loop
+	movq	%rax, %rsp
+	popq	%rax
+	popq	%rdi
+	ret
+	SET_SIZE(x86_rsb_stuff)
+
+#elif defined(__i386)
+
+/*
+ * While the kernel is 64-bit only, dboot is still 32-bit, so there are a
+ * limited number of variants that are used for 32-bit. However as dboot is
+ * short lived and uses them sparingly, we only do the full variant and do not
+ * have an AMD specific version.
+ */
+
+#define	RETPOLINE_MKTHUNK(reg) \
+	ENTRY(__x86_indirect_thunk_/**/reg)	\
+	call	2f;				\
+1:						\
+	pause;					\
+	lfence;					\
+	jmp	1b;				\
+2:						\
+	movl	%/**/reg, (%esp);		\
+	ret;					\
+	SET_SIZE(__x86_indirect_thunk_/**/reg)
+
+	RETPOLINE_MKTHUNK(edi)
+	RETPOLINE_MKTHUNK(eax)
+
+#else
+#error	"Your architecture is in another castle."
+#endif
--- old/usr/src/uts/intel/ia32/ml/swtch.s	Wed Oct  9 03:12:36 2019
+++ new/usr/src/uts/intel/ia32/ml/swtch.s	Wed Oct  9 03:12:36 2019
@@ -171,6 +171,14 @@
 	call	smap_enable
 
 	/*
+	 * Take a moment to potentially clear the RSB buffer. This is done to
+	 * prevent various Spectre variant 2 and SpectreRSB attacks. This may
+	 * not be sufficient. Please see uts/intel/ia32/ml/retpoline.s for more
+	 * information about this.
+	 */
+	call	x86_rsb_stuff
+
+	/*
 	 * Save non-volatile registers, and set return address for current
 	 * thread to resume_return.
 	 *
@@ -211,7 +219,7 @@
 	/*
 	 * Temporarily switch to the idle thread's stack
 	 */
-	movq	CPU_IDLE_THREAD(%r15), %rax 	/* idle thread pointer */
+	movq	CPU_IDLE_THREAD(%r15), %rax	/* idle thread pointer */
 
 	/*
 	 * Set the idle thread as the current thread
@@ -246,7 +254,7 @@
 	 */
 .lock_thread_mutex:
 	lock
-	btsl	$0, T_LOCK(%r12) 	/* attempt to lock new thread's mutex */
+	btsl	$0, T_LOCK(%r12)	/* attempt to lock new thread's mutex */
 	jnc	.thread_mutex_locked	/* got it */
 
 .spin_thread_mutex:
@@ -302,8 +310,8 @@
 	movq	%r12, CPU_THREAD(%r13)	/* set CPU's thread pointer */
 	mfence				/* synchronize with mutex_exit() */
 	xorl	%ebp, %ebp		/* make $<threadlist behave better */
-	movq	T_LWP(%r12), %rax 	/* set associated lwp to  */
-	movq	%rax, CPU_LWP(%r13) 	/* CPU's lwp ptr */
+	movq	T_LWP(%r12), %rax	/* set associated lwp to  */
+	movq	%rax, CPU_LWP(%r13)	/* CPU's lwp ptr */
 
 	movq	T_SP(%r12), %rsp	/* switch to outgoing thread's stack */
 	movq	T_PC(%r12), %r13	/* saved return addr */
@@ -481,7 +489,7 @@
 	/*
 	 * Remove stack frame created in SAVE_REGS()
 	 */
-	addq 	$CLONGSIZE, %rsp
+	addq	$CLONGSIZE, %rsp
 	ret
 	SET_SIZE(resume_from_intr)
 
@@ -490,7 +498,7 @@
 	popq	%rdi		/* arg */
 	popq	%rsi		/* len */
 	movq	%rsp, %rbp
-	call	*%rax
+	INDIRECT_CALL_REG(rax)
 	call	thread_exit	/* destroy thread if it returns. */
 	/*NOTREACHED*/
 	SET_SIZE(thread_start)
--- old/usr/src/uts/intel/ia32/sys/asm_linkage.h	Wed Oct  9 03:12:36 2019
+++ new/usr/src/uts/intel/ia32/sys/asm_linkage.h	Wed Oct  9 03:12:36 2019
@@ -24,11 +24,13 @@
  * Use is subject to license terms.
  */
 
+/*
+ * Copyright 2019 Joyent, Inc.
+ */
+
 #ifndef _IA32_SYS_ASM_LINKAGE_H
 #define	_IA32_SYS_ASM_LINKAGE_H
 
-#pragma ident	"%Z%%M%	%I%	%E% SMI"
-
 #include <sys/stack.h>
 #include <sys/trap.h>
 
@@ -300,6 +302,46 @@
 
 #endif  /* __i386 */
 
+/*
+ * These macros should be used when making indirect calls in the kernel. They
+ * will perform a jump or call to the corresponding register in a way that knows
+ * about retpolines and handles whether such mitigations are enabled or not.
+ *
+ * INDIRECT_JMP_REG will jump to named register. INDIRECT_CALL_REG will instead
+ * do a call. These macros cannot be used to dereference a register. For
+ * example, if you need to do something that looks like the following:
+ *
+ *	call	*24(%rdi)
+ *	jmp	*(%r15)
+ *
+ * You must instead first do a movq into the corresponding location. You need to
+ * be careful to make sure that the register that its loaded into is safe to
+ * use. Often that register may be saved or used elsewhere so it may not be safe
+ * to clobber the value. Usually, loading into %rax would be safe. These would
+ * turn into something like:
+ *
+ *	movq 24(%rdi), %rdi; INDIRECT_CALL_REG(rdi)
+ *	movq (%r15), %r15; INDIRECT_JMP_REG(r15)
+ *
+ * If you are trying to call a global function, then use the following pattern
+ * (substituting the register in question):
+ *
+ *	leaq	my_favorite_function(%rip), %rax
+ *	INDIRECT_CALL_REG(rax)
+ *
+ * If you instead have a function pointer (say gethrtimef for example), then you
+ * need to do:
+ *
+ *	movq	my_favorite_function_pointer(%rip), %rax
+ *	INDIRECT_CALL_REG(rax)
+ */
+
+/* CSTYLED */
+#define	INDIRECT_JMP_REG(reg)	jmp	__x86_indirect_thunk_/**/reg;
+
+/* CSTYLED */
+#define	INDIRECT_CALL_REG(reg)	call	__x86_indirect_thunk_/**/reg;
+
 #endif /* _ASM */
 
 #ifdef	__cplusplus
--- old/usr/src/uts/intel/sys/x86_archext.h	Wed Oct  9 03:12:36 2019
+++ new/usr/src/uts/intel/sys/x86_archext.h	Wed Oct  9 03:12:36 2019
@@ -547,6 +547,14 @@
 #define	IA32_PKG_THERM_INTERRUPT_TR2_IE		0x00800000
 #define	IA32_PKG_THERM_INTERRUPT_PL_NE		0x01000000
 
+/*
+ * This MSR exists on families, 10h, 12h+ for AMD. This controls instruction
+ * decoding. Most notably, for the AMD variant of retpolines, we must improve
+ * the serializability of lfence for the lfence based method to work.
+ */
+#define	MSR_AMD_DECODE_CONFIG			0xc0011029
+#define	AMD_DECODE_CONFIG_LFENCE_DISPATCH	0x02
+
 #define	MCI_CTL_VALUE		0xffffffff
 
 #define	MTRR_TYPE_UC		0
@@ -978,7 +986,7 @@
 #define	INTC_MODEL_BROADWELL_XEON	0x4f
 #define	INTC_MODEL_BROADWELL_XEON_D	0x56
 
-#define	INCC_MODEL_SKYLAKE_MOBILE	0x4e
+#define	INTC_MODEL_SKYLAKE_MOBILE	0x4e
 #define	INTC_MODEL_SKYLAKE_XEON		0x55
 #define	INTC_MODEL_SKYLAKE_DESKTOP	0x5e
 
@@ -1055,7 +1063,13 @@
 
 extern const char CyrixInstead[];
 
+/*
+ * These functions are all used to perform various side-channel mitigations.
+ * Please see uts/i86pc/os/cpuid.c for more information.
+ */
 extern void (*spec_uarch_flush)(void);
+extern void x86_rsb_stuff(void);
+extern void x86_md_clear(void);
 
 #endif
 
@@ -1062,15 +1076,6 @@
 #if defined(_KERNEL)
 
 /*
- * x86_md_clear is the main entry point that should be called to deal with
- * clearing u-arch buffers. Implementations are below because they're
- * implemented in ASM. They shouldn't be used.
- */
-extern void (*x86_md_clear)(void);
-extern void x86_md_clear_noop(void);
-extern void x86_md_clear_verw(void);
-
-/*
  * This structure is used to pass arguments and get return values back
  * from the CPUID instruction in __cpuid_insn() routine.
  */
