mirror of
https://github.com/linux-msm/laptops-kernel.git
synced 2026-08-13 14:19:53 -07:00
Merge tag 'x86_core_for_v6.18_rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/tip/tip
Pull more x86 updates from Borislav Petkov: - Remove a bunch of asm implementing condition flags testing in KVM's emulator in favor of int3_emulate_jcc() which is written in C - Replace KVM fastops with C-based stubs which avoids problems with the fastop infra related to latter not adhering to the C ABI due to their special calling convention and, more importantly, bypassing compiler control-flow integrity checking because they're written in asm - Remove wrongly used static branches and other ugliness accumulated over time in hyperv's hypercall implementation with a proper static function call to the correct hypervisor call variant - Add some fixes and modifications to allow running FRED-enabled kernels in KVM even on non-FRED hardware - Add kCFI improvements like validating indirect calls and prepare for enabling kCFI with GCC. Add cmdline params documentation and other code cleanups - Use the single-byte 0xd6 insn as the official #UD single-byte undefined opcode instruction as agreed upon by both x86 vendors - Other smaller cleanups and touchups all over the place * tag 'x86_core_for_v6.18_rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/tip/tip: (24 commits) x86,retpoline: Optimize patch_retpoline() x86,ibt: Use UDB instead of 0xEA x86/cfi: Remove __noinitretpoline and __noretpoline x86/cfi: Add "debug" option to "cfi=" bootparam x86/cfi: Standardize on common "CFI:" prefix for CFI reports x86/cfi: Document the "cfi=" bootparam options x86/traps: Clarify KCFI instruction layout compiler_types.h: Move __nocfi out of compiler-specific header objtool: Validate kCFI calls x86/fred: KVM: VMX: Always use FRED for IRQs when CONFIG_X86_FRED=y x86/fred: Play nice with invoking asm_fred_entry_from_kvm() on non-FRED hardware x86/fred: Install system vector handlers even if FRED isn't fully enabled x86/hyperv: Use direct call to hypercall-page x86/hyperv: Clean up hv_do_hypercall() KVM: x86: Remove fastops KVM: x86: Convert em_salc() to C KVM: x86: Introduce EM_ASM_3WCL KVM: x86: Introduce EM_ASM_1SRC2 KVM: x86: Introduce EM_ASM_2CL KVM: x86: Introduce EM_ASM_2W ...
This commit is contained in:
@@ -608,6 +608,24 @@
|
||||
ccw_timeout_log [S390]
|
||||
See Documentation/arch/s390/common_io.rst for details.
|
||||
|
||||
cfi= [X86-64] Set Control Flow Integrity checking features
|
||||
when CONFIG_FINEIBT is enabled.
|
||||
Format: feature[,feature...]
|
||||
Default: auto
|
||||
|
||||
auto: Use FineIBT if IBT available, otherwise kCFI.
|
||||
Under FineIBT, enable "paranoid" mode when
|
||||
FRED is not available.
|
||||
off: Turn off CFI checking.
|
||||
kcfi: Use kCFI (disable FineIBT).
|
||||
fineibt: Use FineIBT (even if IBT not available).
|
||||
norand: Do not re-randomize CFI hashes.
|
||||
paranoid: Add caller hash checking under FineIBT.
|
||||
bhi: Enable register poisoning to stop speculation
|
||||
across FineIBT. (Disabled by default.)
|
||||
warn: Do not enforce CFI checking: warn only.
|
||||
debug: Report CFI initialization details.
|
||||
|
||||
cgroup_disable= [KNL] Disable a particular controller or optional feature
|
||||
Format: {name of the controller(s) or feature(s) to disable}
|
||||
The effects of cgroup_disable=foo are:
|
||||
|
||||
@@ -99,7 +99,7 @@ For 32-bit we have the following conventions - kernel is built with
|
||||
.endif
|
||||
.endm
|
||||
|
||||
.macro CLEAR_REGS clear_bp=1
|
||||
.macro CLEAR_REGS clear_callee=1
|
||||
/*
|
||||
* Sanitize registers of values that a speculation attack might
|
||||
* otherwise want to exploit. The lower registers are likely clobbered
|
||||
@@ -113,20 +113,19 @@ For 32-bit we have the following conventions - kernel is built with
|
||||
xorl %r9d, %r9d /* nospec r9 */
|
||||
xorl %r10d, %r10d /* nospec r10 */
|
||||
xorl %r11d, %r11d /* nospec r11 */
|
||||
.if \clear_callee
|
||||
xorl %ebx, %ebx /* nospec rbx */
|
||||
.if \clear_bp
|
||||
xorl %ebp, %ebp /* nospec rbp */
|
||||
.endif
|
||||
xorl %r12d, %r12d /* nospec r12 */
|
||||
xorl %r13d, %r13d /* nospec r13 */
|
||||
xorl %r14d, %r14d /* nospec r14 */
|
||||
xorl %r15d, %r15d /* nospec r15 */
|
||||
|
||||
.endif
|
||||
.endm
|
||||
|
||||
.macro PUSH_AND_CLEAR_REGS rdx=%rdx rcx=%rcx rax=%rax save_ret=0 clear_bp=1 unwind_hint=1
|
||||
.macro PUSH_AND_CLEAR_REGS rdx=%rdx rcx=%rcx rax=%rax save_ret=0 clear_callee=1 unwind_hint=1
|
||||
PUSH_REGS rdx=\rdx, rcx=\rcx, rax=\rax, save_ret=\save_ret unwind_hint=\unwind_hint
|
||||
CLEAR_REGS clear_bp=\clear_bp
|
||||
CLEAR_REGS clear_callee=\clear_callee
|
||||
.endm
|
||||
|
||||
.macro POP_REGS pop_rdi=1
|
||||
|
||||
@@ -111,18 +111,37 @@ SYM_FUNC_START(asm_fred_entry_from_kvm)
|
||||
push %rax /* Return RIP */
|
||||
push $0 /* Error code, 0 for IRQ/NMI */
|
||||
|
||||
PUSH_AND_CLEAR_REGS clear_bp=0 unwind_hint=0
|
||||
PUSH_AND_CLEAR_REGS clear_callee=0 unwind_hint=0
|
||||
|
||||
movq %rsp, %rdi /* %rdi -> pt_regs */
|
||||
call __fred_entry_from_kvm /* Call the C entry point */
|
||||
POP_REGS
|
||||
ERETS
|
||||
1:
|
||||
/*
|
||||
* Objtool doesn't understand what ERETS does, this hint tells it that
|
||||
* yes, we'll reach here and with what stack state. A save/restore pair
|
||||
* isn't strictly needed, but it's the simplest form.
|
||||
* At this point: {rdi, rsi, rdx, rcx, r8, r9}, {r10, r11}, {rax, rdx}
|
||||
* are clobbered, which corresponds to: arguments, extra caller-saved
|
||||
* and return. All registers a C function is allowed to clobber.
|
||||
*
|
||||
* Notably, the callee-saved registers: {rbx, r12, r13, r14, r15}
|
||||
* are untouched, with the exception of rbp, which carries the stack
|
||||
* frame and will be restored before exit.
|
||||
*
|
||||
* Further calling another C function will not alter this state.
|
||||
*/
|
||||
call __fred_entry_from_kvm /* Call the C entry point */
|
||||
|
||||
/*
|
||||
* When FRED, use ERETS to potentially clear NMIs, otherwise simply
|
||||
* restore the stack pointer.
|
||||
*/
|
||||
ALTERNATIVE "nop; nop; mov %rbp, %rsp", \
|
||||
__stringify(add $C_PTREGS_SIZE, %rsp; ERETS), \
|
||||
X86_FEATURE_FRED
|
||||
|
||||
1: /*
|
||||
* Objtool doesn't understand ERETS, and the cfi register state is
|
||||
* different from initial_func_cfi due to PUSH_REGS. Tell it the state
|
||||
* is similar to where UNWIND_HINT_SAVE is.
|
||||
*/
|
||||
UNWIND_HINT_RESTORE
|
||||
|
||||
pop %rbp
|
||||
RET
|
||||
|
||||
|
||||
+44
-25
@@ -17,7 +17,6 @@
|
||||
#include <asm/desc.h>
|
||||
#include <asm/e820/api.h>
|
||||
#include <asm/sev.h>
|
||||
#include <asm/ibt.h>
|
||||
#include <asm/hypervisor.h>
|
||||
#include <hyperv/hvhdk.h>
|
||||
#include <asm/mshyperv.h>
|
||||
@@ -37,7 +36,45 @@
|
||||
#include <linux/export.h>
|
||||
|
||||
void *hv_hypercall_pg;
|
||||
|
||||
#ifdef CONFIG_X86_64
|
||||
static u64 __hv_hyperfail(u64 control, u64 param1, u64 param2)
|
||||
{
|
||||
return U64_MAX;
|
||||
}
|
||||
|
||||
DEFINE_STATIC_CALL(__hv_hypercall, __hv_hyperfail);
|
||||
|
||||
u64 hv_std_hypercall(u64 control, u64 param1, u64 param2)
|
||||
{
|
||||
u64 hv_status;
|
||||
|
||||
register u64 __r8 asm("r8") = param2;
|
||||
asm volatile ("call " STATIC_CALL_TRAMP_STR(__hv_hypercall)
|
||||
: "=a" (hv_status), ASM_CALL_CONSTRAINT,
|
||||
"+c" (control), "+d" (param1), "+r" (__r8)
|
||||
: : "cc", "memory", "r9", "r10", "r11");
|
||||
|
||||
return hv_status;
|
||||
}
|
||||
|
||||
typedef u64 (*hv_hypercall_f)(u64 control, u64 param1, u64 param2);
|
||||
|
||||
static inline void hv_set_hypercall_pg(void *ptr)
|
||||
{
|
||||
hv_hypercall_pg = ptr;
|
||||
|
||||
if (!ptr)
|
||||
ptr = &__hv_hyperfail;
|
||||
static_call_update(__hv_hypercall, (hv_hypercall_f)ptr);
|
||||
}
|
||||
#else
|
||||
static inline void hv_set_hypercall_pg(void *ptr)
|
||||
{
|
||||
hv_hypercall_pg = ptr;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(hv_hypercall_pg);
|
||||
#endif
|
||||
|
||||
union hv_ghcb * __percpu *hv_ghcb_pg;
|
||||
|
||||
@@ -330,7 +367,7 @@ static int hv_suspend(void)
|
||||
* pointer is restored on resume.
|
||||
*/
|
||||
hv_hypercall_pg_saved = hv_hypercall_pg;
|
||||
hv_hypercall_pg = NULL;
|
||||
hv_set_hypercall_pg(NULL);
|
||||
|
||||
/* Disable the hypercall page in the hypervisor */
|
||||
rdmsrq(HV_X64_MSR_HYPERCALL, hypercall_msr.as_uint64);
|
||||
@@ -356,7 +393,7 @@ static void hv_resume(void)
|
||||
vmalloc_to_pfn(hv_hypercall_pg_saved);
|
||||
wrmsrq(HV_X64_MSR_HYPERCALL, hypercall_msr.as_uint64);
|
||||
|
||||
hv_hypercall_pg = hv_hypercall_pg_saved;
|
||||
hv_set_hypercall_pg(hv_hypercall_pg_saved);
|
||||
hv_hypercall_pg_saved = NULL;
|
||||
|
||||
/*
|
||||
@@ -476,8 +513,8 @@ void __init hyperv_init(void)
|
||||
if (hv_isolation_type_tdx() && !ms_hyperv.paravisor_present)
|
||||
goto skip_hypercall_pg_init;
|
||||
|
||||
hv_hypercall_pg = __vmalloc_node_range(PAGE_SIZE, 1, VMALLOC_START,
|
||||
VMALLOC_END, GFP_KERNEL, PAGE_KERNEL_ROX,
|
||||
hv_hypercall_pg = __vmalloc_node_range(PAGE_SIZE, 1, MODULES_VADDR,
|
||||
MODULES_END, GFP_KERNEL, PAGE_KERNEL_ROX,
|
||||
VM_FLUSH_RESET_PERMS, NUMA_NO_NODE,
|
||||
__builtin_return_address(0));
|
||||
if (hv_hypercall_pg == NULL)
|
||||
@@ -515,27 +552,9 @@ void __init hyperv_init(void)
|
||||
wrmsrq(HV_X64_MSR_HYPERCALL, hypercall_msr.as_uint64);
|
||||
}
|
||||
|
||||
skip_hypercall_pg_init:
|
||||
/*
|
||||
* Some versions of Hyper-V that provide IBT in guest VMs have a bug
|
||||
* in that there's no ENDBR64 instruction at the entry to the
|
||||
* hypercall page. Because hypercalls are invoked via an indirect call
|
||||
* to the hypercall page, all hypercall attempts fail when IBT is
|
||||
* enabled, and Linux panics. For such buggy versions, disable IBT.
|
||||
*
|
||||
* Fixed versions of Hyper-V always provide ENDBR64 on the hypercall
|
||||
* page, so if future Linux kernel versions enable IBT for 32-bit
|
||||
* builds, additional hypercall page hackery will be required here
|
||||
* to provide an ENDBR32.
|
||||
*/
|
||||
#ifdef CONFIG_X86_KERNEL_IBT
|
||||
if (cpu_feature_enabled(X86_FEATURE_IBT) &&
|
||||
*(u32 *)hv_hypercall_pg != gen_endbr()) {
|
||||
setup_clear_cpu_cap(X86_FEATURE_IBT);
|
||||
pr_warn("Disabling IBT because of Hyper-V bug\n");
|
||||
}
|
||||
#endif
|
||||
hv_set_hypercall_pg(hv_hypercall_pg);
|
||||
|
||||
skip_hypercall_pg_init:
|
||||
/*
|
||||
* hyperv_init() is called before LAPIC is initialized: see
|
||||
* apic_intr_mode_init() -> x86_platform.apic_post_init() and
|
||||
|
||||
@@ -385,9 +385,23 @@ int hv_snp_boot_ap(u32 apic_id, unsigned long start_ip, unsigned int cpu)
|
||||
return ret;
|
||||
}
|
||||
|
||||
u64 hv_snp_hypercall(u64 control, u64 param1, u64 param2)
|
||||
{
|
||||
u64 hv_status;
|
||||
|
||||
register u64 __r8 asm("r8") = param2;
|
||||
asm volatile("vmmcall"
|
||||
: "=a" (hv_status), ASM_CALL_CONSTRAINT,
|
||||
"+c" (control), "+d" (param1), "+r" (__r8)
|
||||
: : "cc", "memory", "r9", "r10", "r11");
|
||||
|
||||
return hv_status;
|
||||
}
|
||||
|
||||
#else
|
||||
static inline void hv_ghcb_msr_write(u64 msr, u64 value) {}
|
||||
static inline void hv_ghcb_msr_read(u64 msr, u64 *value) {}
|
||||
u64 hv_snp_hypercall(u64 control, u64 param1, u64 param2) { return U64_MAX; }
|
||||
#endif /* CONFIG_AMD_MEM_ENCRYPT */
|
||||
|
||||
#ifdef CONFIG_INTEL_TDX_GUEST
|
||||
@@ -437,6 +451,7 @@ u64 hv_tdx_hypercall(u64 control, u64 param1, u64 param2)
|
||||
#else
|
||||
static inline void hv_tdx_msr_write(u64 msr, u64 value) {}
|
||||
static inline void hv_tdx_msr_read(u64 msr, u64 *value) {}
|
||||
u64 hv_tdx_hypercall(u64 control, u64 param1, u64 param2) { return U64_MAX; }
|
||||
#endif /* CONFIG_INTEL_TDX_GUEST */
|
||||
|
||||
#if defined(CONFIG_AMD_MEM_ENCRYPT) || defined(CONFIG_INTEL_TDX_GUEST)
|
||||
|
||||
@@ -5,14 +5,19 @@
|
||||
#include <linux/stringify.h>
|
||||
#include <linux/instrumentation.h>
|
||||
#include <linux/objtool.h>
|
||||
#include <asm/asm.h>
|
||||
|
||||
/*
|
||||
* Despite that some emulators terminate on UD2, we use it for WARN().
|
||||
*/
|
||||
#define ASM_UD2 ".byte 0x0f, 0x0b"
|
||||
#define ASM_UD2 _ASM_BYTES(0x0f, 0x0b)
|
||||
#define INSN_UD2 0x0b0f
|
||||
#define LEN_UD2 2
|
||||
|
||||
#define ASM_UDB _ASM_BYTES(0xd6)
|
||||
#define INSN_UDB 0xd6
|
||||
#define LEN_UDB 1
|
||||
|
||||
/*
|
||||
* In clang we have UD1s reporting UBSAN failures on X86, 64 and 32bit.
|
||||
*/
|
||||
@@ -26,7 +31,7 @@
|
||||
#define BUG_UD2 0xfffe
|
||||
#define BUG_UD1 0xfffd
|
||||
#define BUG_UD1_UBSAN 0xfffc
|
||||
#define BUG_EA 0xffea
|
||||
#define BUG_UDB 0xffd6
|
||||
#define BUG_LOCK 0xfff0
|
||||
|
||||
#ifdef CONFIG_GENERIC_BUG
|
||||
|
||||
@@ -71,12 +71,10 @@
|
||||
*
|
||||
* __cfi_foo:
|
||||
* endbr64
|
||||
* subl 0x12345678, %r10d
|
||||
* jz foo
|
||||
* ud2
|
||||
* nop
|
||||
* subl 0x12345678, %eax
|
||||
* jne.32,pn foo+3
|
||||
* foo:
|
||||
* osp nop3 # was endbr64
|
||||
* nopl -42(%rax) # was endbr64
|
||||
* ... code here ...
|
||||
* ret
|
||||
*
|
||||
@@ -86,9 +84,9 @@
|
||||
* indirect caller:
|
||||
* lea foo(%rip), %r11
|
||||
* ...
|
||||
* movl $0x12345678, %r10d
|
||||
* subl $16, %r11
|
||||
* nop4
|
||||
* movl $0x12345678, %eax
|
||||
* lea -0x10(%r11), %r11
|
||||
* nop5
|
||||
* call *%r11
|
||||
*
|
||||
*/
|
||||
|
||||
@@ -59,10 +59,10 @@ static __always_inline __attribute_const__ u32 gen_endbr(void)
|
||||
static __always_inline __attribute_const__ u32 gen_endbr_poison(void)
|
||||
{
|
||||
/*
|
||||
* 4 byte NOP that isn't NOP4 (in fact it is OSP NOP3), such that it
|
||||
* will be unique to (former) ENDBR sites.
|
||||
* 4 byte NOP that isn't NOP4, such that it will be unique to (former)
|
||||
* ENDBR sites. Additionally it carries UDB as immediate.
|
||||
*/
|
||||
return 0x001f0f66; /* osp nopl (%rax) */
|
||||
return 0xd6401f0f; /* nopl -42(%rax) */
|
||||
}
|
||||
|
||||
static inline bool __is_endbr(u32 val)
|
||||
@@ -70,10 +70,6 @@ static inline bool __is_endbr(u32 val)
|
||||
if (val == gen_endbr_poison())
|
||||
return true;
|
||||
|
||||
/* See cfi_fineibt_bhi_preamble() */
|
||||
if (IS_ENABLED(CONFIG_FINEIBT_BHI) && val == 0x001f0ff5)
|
||||
return true;
|
||||
|
||||
val &= ~0x01000000U; /* ENDBR32 -> ENDBR64 */
|
||||
return val == gen_endbr();
|
||||
}
|
||||
|
||||
@@ -460,17 +460,12 @@ __visible noinstr void func(struct pt_regs *regs, \
|
||||
#endif
|
||||
|
||||
void idt_install_sysvec(unsigned int n, const void *function);
|
||||
|
||||
#ifdef CONFIG_X86_FRED
|
||||
void fred_install_sysvec(unsigned int vector, const idtentry_t function);
|
||||
#else
|
||||
static inline void fred_install_sysvec(unsigned int vector, const idtentry_t function) { }
|
||||
#endif
|
||||
|
||||
#define sysvec_install(vector, function) { \
|
||||
if (cpu_feature_enabled(X86_FEATURE_FRED)) \
|
||||
if (IS_ENABLED(CONFIG_X86_FRED)) \
|
||||
fred_install_sysvec(vector, function); \
|
||||
else \
|
||||
if (!cpu_feature_enabled(X86_FEATURE_FRED)) \
|
||||
idt_install_sysvec(vector, asm_##function); \
|
||||
}
|
||||
|
||||
|
||||
@@ -6,6 +6,7 @@
|
||||
#include <linux/nmi.h>
|
||||
#include <linux/msi.h>
|
||||
#include <linux/io.h>
|
||||
#include <linux/static_call.h>
|
||||
#include <asm/nospec-branch.h>
|
||||
#include <asm/paravirt.h>
|
||||
#include <asm/msr.h>
|
||||
@@ -39,16 +40,21 @@ static inline unsigned char hv_get_nmi_reason(void)
|
||||
return 0;
|
||||
}
|
||||
|
||||
#if IS_ENABLED(CONFIG_HYPERV)
|
||||
extern bool hyperv_paravisor_present;
|
||||
extern u64 hv_tdx_hypercall(u64 control, u64 param1, u64 param2);
|
||||
extern u64 hv_snp_hypercall(u64 control, u64 param1, u64 param2);
|
||||
extern u64 hv_std_hypercall(u64 control, u64 param1, u64 param2);
|
||||
|
||||
#if IS_ENABLED(CONFIG_HYPERV)
|
||||
extern void *hv_hypercall_pg;
|
||||
|
||||
extern union hv_ghcb * __percpu *hv_ghcb_pg;
|
||||
|
||||
bool hv_isolation_type_snp(void);
|
||||
bool hv_isolation_type_tdx(void);
|
||||
u64 hv_tdx_hypercall(u64 control, u64 param1, u64 param2);
|
||||
|
||||
#ifdef CONFIG_X86_64
|
||||
DECLARE_STATIC_CALL(hv_hypercall, hv_std_hypercall);
|
||||
#endif
|
||||
|
||||
/*
|
||||
* DEFAULT INIT GPAT and SEGMENT LIMIT value in struct VMSA
|
||||
@@ -65,37 +71,15 @@ static inline u64 hv_do_hypercall(u64 control, void *input, void *output)
|
||||
{
|
||||
u64 input_address = input ? virt_to_phys(input) : 0;
|
||||
u64 output_address = output ? virt_to_phys(output) : 0;
|
||||
u64 hv_status;
|
||||
|
||||
#ifdef CONFIG_X86_64
|
||||
if (hv_isolation_type_tdx() && !hyperv_paravisor_present)
|
||||
return hv_tdx_hypercall(control, input_address, output_address);
|
||||
|
||||
if (hv_isolation_type_snp() && !hyperv_paravisor_present) {
|
||||
__asm__ __volatile__("mov %[output_address], %%r8\n"
|
||||
"vmmcall"
|
||||
: "=a" (hv_status), ASM_CALL_CONSTRAINT,
|
||||
"+c" (control), "+d" (input_address)
|
||||
: [output_address] "r" (output_address)
|
||||
: "cc", "memory", "r8", "r9", "r10", "r11");
|
||||
return hv_status;
|
||||
}
|
||||
|
||||
if (!hv_hypercall_pg)
|
||||
return U64_MAX;
|
||||
|
||||
__asm__ __volatile__("mov %[output_address], %%r8\n"
|
||||
CALL_NOSPEC
|
||||
: "=a" (hv_status), ASM_CALL_CONSTRAINT,
|
||||
"+c" (control), "+d" (input_address)
|
||||
: [output_address] "r" (output_address),
|
||||
THUNK_TARGET(hv_hypercall_pg)
|
||||
: "cc", "memory", "r8", "r9", "r10", "r11");
|
||||
return static_call_mod(hv_hypercall)(control, input_address, output_address);
|
||||
#else
|
||||
u32 input_address_hi = upper_32_bits(input_address);
|
||||
u32 input_address_lo = lower_32_bits(input_address);
|
||||
u32 output_address_hi = upper_32_bits(output_address);
|
||||
u32 output_address_lo = lower_32_bits(output_address);
|
||||
u64 hv_status;
|
||||
|
||||
if (!hv_hypercall_pg)
|
||||
return U64_MAX;
|
||||
@@ -108,48 +92,30 @@ static inline u64 hv_do_hypercall(u64 control, void *input, void *output)
|
||||
"D"(output_address_hi), "S"(output_address_lo),
|
||||
THUNK_TARGET(hv_hypercall_pg)
|
||||
: "cc", "memory");
|
||||
#endif /* !x86_64 */
|
||||
return hv_status;
|
||||
#endif /* !x86_64 */
|
||||
}
|
||||
|
||||
/* Fast hypercall with 8 bytes of input and no output */
|
||||
static inline u64 _hv_do_fast_hypercall8(u64 control, u64 input1)
|
||||
{
|
||||
#ifdef CONFIG_X86_64
|
||||
return static_call_mod(hv_hypercall)(control, input1, 0);
|
||||
#else
|
||||
u32 input1_hi = upper_32_bits(input1);
|
||||
u32 input1_lo = lower_32_bits(input1);
|
||||
u64 hv_status;
|
||||
|
||||
#ifdef CONFIG_X86_64
|
||||
if (hv_isolation_type_tdx() && !hyperv_paravisor_present)
|
||||
return hv_tdx_hypercall(control, input1, 0);
|
||||
|
||||
if (hv_isolation_type_snp() && !hyperv_paravisor_present) {
|
||||
__asm__ __volatile__(
|
||||
"vmmcall"
|
||||
: "=a" (hv_status), ASM_CALL_CONSTRAINT,
|
||||
"+c" (control), "+d" (input1)
|
||||
:: "cc", "r8", "r9", "r10", "r11");
|
||||
} else {
|
||||
__asm__ __volatile__(CALL_NOSPEC
|
||||
: "=a" (hv_status), ASM_CALL_CONSTRAINT,
|
||||
"+c" (control), "+d" (input1)
|
||||
: THUNK_TARGET(hv_hypercall_pg)
|
||||
: "cc", "r8", "r9", "r10", "r11");
|
||||
}
|
||||
#else
|
||||
{
|
||||
u32 input1_hi = upper_32_bits(input1);
|
||||
u32 input1_lo = lower_32_bits(input1);
|
||||
|
||||
__asm__ __volatile__ (CALL_NOSPEC
|
||||
: "=A"(hv_status),
|
||||
"+c"(input1_lo),
|
||||
ASM_CALL_CONSTRAINT
|
||||
: "A" (control),
|
||||
"b" (input1_hi),
|
||||
THUNK_TARGET(hv_hypercall_pg)
|
||||
: "cc", "edi", "esi");
|
||||
}
|
||||
#endif
|
||||
__asm__ __volatile__ (CALL_NOSPEC
|
||||
: "=A"(hv_status),
|
||||
"+c"(input1_lo),
|
||||
ASM_CALL_CONSTRAINT
|
||||
: "A" (control),
|
||||
"b" (input1_hi),
|
||||
THUNK_TARGET(hv_hypercall_pg)
|
||||
: "cc", "edi", "esi");
|
||||
return hv_status;
|
||||
#endif
|
||||
}
|
||||
|
||||
static inline u64 hv_do_fast_hypercall8(u16 code, u64 input1)
|
||||
@@ -162,45 +128,24 @@ static inline u64 hv_do_fast_hypercall8(u16 code, u64 input1)
|
||||
/* Fast hypercall with 16 bytes of input */
|
||||
static inline u64 _hv_do_fast_hypercall16(u64 control, u64 input1, u64 input2)
|
||||
{
|
||||
#ifdef CONFIG_X86_64
|
||||
return static_call_mod(hv_hypercall)(control, input1, input2);
|
||||
#else
|
||||
u32 input1_hi = upper_32_bits(input1);
|
||||
u32 input1_lo = lower_32_bits(input1);
|
||||
u32 input2_hi = upper_32_bits(input2);
|
||||
u32 input2_lo = lower_32_bits(input2);
|
||||
u64 hv_status;
|
||||
|
||||
#ifdef CONFIG_X86_64
|
||||
if (hv_isolation_type_tdx() && !hyperv_paravisor_present)
|
||||
return hv_tdx_hypercall(control, input1, input2);
|
||||
|
||||
if (hv_isolation_type_snp() && !hyperv_paravisor_present) {
|
||||
__asm__ __volatile__("mov %[input2], %%r8\n"
|
||||
"vmmcall"
|
||||
: "=a" (hv_status), ASM_CALL_CONSTRAINT,
|
||||
"+c" (control), "+d" (input1)
|
||||
: [input2] "r" (input2)
|
||||
: "cc", "r8", "r9", "r10", "r11");
|
||||
} else {
|
||||
__asm__ __volatile__("mov %[input2], %%r8\n"
|
||||
CALL_NOSPEC
|
||||
: "=a" (hv_status), ASM_CALL_CONSTRAINT,
|
||||
"+c" (control), "+d" (input1)
|
||||
: [input2] "r" (input2),
|
||||
THUNK_TARGET(hv_hypercall_pg)
|
||||
: "cc", "r8", "r9", "r10", "r11");
|
||||
}
|
||||
#else
|
||||
{
|
||||
u32 input1_hi = upper_32_bits(input1);
|
||||
u32 input1_lo = lower_32_bits(input1);
|
||||
u32 input2_hi = upper_32_bits(input2);
|
||||
u32 input2_lo = lower_32_bits(input2);
|
||||
|
||||
__asm__ __volatile__ (CALL_NOSPEC
|
||||
: "=A"(hv_status),
|
||||
"+c"(input1_lo), ASM_CALL_CONSTRAINT
|
||||
: "A" (control), "b" (input1_hi),
|
||||
"D"(input2_hi), "S"(input2_lo),
|
||||
THUNK_TARGET(hv_hypercall_pg)
|
||||
: "cc");
|
||||
}
|
||||
#endif
|
||||
__asm__ __volatile__ (CALL_NOSPEC
|
||||
: "=A"(hv_status),
|
||||
"+c"(input1_lo), ASM_CALL_CONSTRAINT
|
||||
: "A" (control), "b" (input1_hi),
|
||||
"D"(input2_hi), "S"(input2_lo),
|
||||
THUNK_TARGET(hv_hypercall_pg)
|
||||
: "cc");
|
||||
return hv_status;
|
||||
#endif
|
||||
}
|
||||
|
||||
static inline u64 hv_do_fast_hypercall16(u16 code, u64 input1, u64 input2)
|
||||
|
||||
@@ -178,9 +178,9 @@ void int3_emulate_ret(struct pt_regs *regs)
|
||||
}
|
||||
|
||||
static __always_inline
|
||||
void int3_emulate_jcc(struct pt_regs *regs, u8 cc, unsigned long ip, unsigned long disp)
|
||||
bool __emulate_cc(unsigned long flags, u8 cc)
|
||||
{
|
||||
static const unsigned long jcc_mask[6] = {
|
||||
static const unsigned long cc_mask[6] = {
|
||||
[0] = X86_EFLAGS_OF,
|
||||
[1] = X86_EFLAGS_CF,
|
||||
[2] = X86_EFLAGS_ZF,
|
||||
@@ -193,15 +193,21 @@ void int3_emulate_jcc(struct pt_regs *regs, u8 cc, unsigned long ip, unsigned lo
|
||||
bool match;
|
||||
|
||||
if (cc < 0xc) {
|
||||
match = regs->flags & jcc_mask[cc >> 1];
|
||||
match = flags & cc_mask[cc >> 1];
|
||||
} else {
|
||||
match = ((regs->flags & X86_EFLAGS_SF) >> X86_EFLAGS_SF_BIT) ^
|
||||
((regs->flags & X86_EFLAGS_OF) >> X86_EFLAGS_OF_BIT);
|
||||
match = ((flags & X86_EFLAGS_SF) >> X86_EFLAGS_SF_BIT) ^
|
||||
((flags & X86_EFLAGS_OF) >> X86_EFLAGS_OF_BIT);
|
||||
if (cc >= 0xe)
|
||||
match = match || (regs->flags & X86_EFLAGS_ZF);
|
||||
match = match || (flags & X86_EFLAGS_ZF);
|
||||
}
|
||||
|
||||
if ((match && !invert) || (!match && invert))
|
||||
return (match && !invert) || (!match && invert);
|
||||
}
|
||||
|
||||
static __always_inline
|
||||
void int3_emulate_jcc(struct pt_regs *regs, u8 cc, unsigned long ip, unsigned long disp)
|
||||
{
|
||||
if (__emulate_cc(regs->flags, cc))
|
||||
ip += disp;
|
||||
|
||||
int3_emulate_jmp(regs, ip);
|
||||
|
||||
+176
-116
File diff suppressed because it is too large
Load Diff
@@ -102,6 +102,7 @@ static void __used common(void)
|
||||
|
||||
BLANK();
|
||||
DEFINE(PTREGS_SIZE, sizeof(struct pt_regs));
|
||||
OFFSET(C_PTREGS_SIZE, pt_regs, orig_ax);
|
||||
|
||||
/* TLB state for the entry code */
|
||||
OFFSET(TLB_STATE_user_pcid_flush_mask, tlb_state, user_pcid_flush_mask);
|
||||
|
||||
@@ -27,7 +27,7 @@ static bool decode_cfi_insn(struct pt_regs *regs, unsigned long *target,
|
||||
* for indirect call checks:
|
||||
*
|
||||
* movl -<id>, %r10d ; 6 bytes
|
||||
* addl -4(%reg), %r10d ; 4 bytes
|
||||
* addl -<pos>(%reg), %r10d; 4 bytes
|
||||
* je .Ltmp1 ; 2 bytes
|
||||
* ud2 ; <- regs->ip
|
||||
* .Ltmp1:
|
||||
|
||||
@@ -38,10 +38,6 @@
|
||||
bool hv_nested;
|
||||
struct ms_hyperv_info ms_hyperv;
|
||||
|
||||
/* Used in modules via hv_do_hypercall(): see arch/x86/include/asm/mshyperv.h */
|
||||
bool hyperv_paravisor_present __ro_after_init;
|
||||
EXPORT_SYMBOL_GPL(hyperv_paravisor_present);
|
||||
|
||||
#if IS_ENABLED(CONFIG_HYPERV)
|
||||
static inline unsigned int hv_get_nested_msr(unsigned int reg)
|
||||
{
|
||||
@@ -288,8 +284,18 @@ static void __init x86_setup_ops_for_tsc_pg_clock(void)
|
||||
old_restore_sched_clock_state = x86_platform.restore_sched_clock_state;
|
||||
x86_platform.restore_sched_clock_state = hv_restore_sched_clock_state;
|
||||
}
|
||||
|
||||
#ifdef CONFIG_X86_64
|
||||
DEFINE_STATIC_CALL(hv_hypercall, hv_std_hypercall);
|
||||
EXPORT_STATIC_CALL_TRAMP_GPL(hv_hypercall);
|
||||
#define hypercall_update(hc) static_call_update(hv_hypercall, hc)
|
||||
#endif
|
||||
#endif /* CONFIG_HYPERV */
|
||||
|
||||
#ifndef hypercall_update
|
||||
#define hypercall_update(hc) (void)hc
|
||||
#endif
|
||||
|
||||
static uint32_t __init ms_hyperv_platform(void)
|
||||
{
|
||||
u32 eax;
|
||||
@@ -484,14 +490,14 @@ static void __init ms_hyperv_init_platform(void)
|
||||
ms_hyperv.shared_gpa_boundary =
|
||||
BIT_ULL(ms_hyperv.shared_gpa_boundary_bits);
|
||||
|
||||
hyperv_paravisor_present = !!ms_hyperv.paravisor_present;
|
||||
|
||||
pr_info("Hyper-V: Isolation Config: Group A 0x%x, Group B 0x%x\n",
|
||||
ms_hyperv.isolation_config_a, ms_hyperv.isolation_config_b);
|
||||
|
||||
|
||||
if (hv_get_isolation_type() == HV_ISOLATION_TYPE_SNP) {
|
||||
static_branch_enable(&isolation_type_snp);
|
||||
if (!ms_hyperv.paravisor_present)
|
||||
hypercall_update(hv_snp_hypercall);
|
||||
} else if (hv_get_isolation_type() == HV_ISOLATION_TYPE_TDX) {
|
||||
static_branch_enable(&isolation_type_tdx);
|
||||
|
||||
@@ -499,6 +505,7 @@ static void __init ms_hyperv_init_platform(void)
|
||||
ms_hyperv.hints &= ~HV_X64_APIC_ACCESS_RECOMMENDED;
|
||||
|
||||
if (!ms_hyperv.paravisor_present) {
|
||||
hypercall_update(hv_tdx_hypercall);
|
||||
/*
|
||||
* Mark the Hyper-V TSC page feature as disabled
|
||||
* in a TDX VM without paravisor so that the
|
||||
|
||||
@@ -97,9 +97,11 @@ void __init native_init_IRQ(void)
|
||||
/* Execute any quirks before the call gates are initialised: */
|
||||
x86_init.irqs.pre_vector_init();
|
||||
|
||||
if (cpu_feature_enabled(X86_FEATURE_FRED))
|
||||
/* FRED's IRQ path may be used even if FRED isn't fully enabled. */
|
||||
if (IS_ENABLED(CONFIG_X86_FRED))
|
||||
fred_complete_exception_setup();
|
||||
else
|
||||
|
||||
if (!cpu_feature_enabled(X86_FEATURE_FRED))
|
||||
idt_setup_apic_and_irq_gates();
|
||||
|
||||
lapic_assign_system_vectors();
|
||||
|
||||
@@ -479,6 +479,10 @@ void __nocfi machine_kexec(struct kimage *image)
|
||||
|
||||
__ftrace_enabled_restore(save_ftrace_enabled);
|
||||
}
|
||||
/*
|
||||
* Handover to the next kernel, no CFI concern.
|
||||
*/
|
||||
ANNOTATE_NOCFI_SYM(machine_kexec);
|
||||
|
||||
/* arch-dependent functionality related to kexec file-based syscall */
|
||||
|
||||
|
||||
@@ -97,7 +97,7 @@ __always_inline int is_valid_bugaddr(unsigned long addr)
|
||||
* Check for UD1 or UD2, accounting for Address Size Override Prefixes.
|
||||
* If it's a UD1, further decode to determine its use:
|
||||
*
|
||||
* FineIBT: ea (bad)
|
||||
* FineIBT: d6 udb
|
||||
* FineIBT: f0 75 f9 lock jne . - 6
|
||||
* UBSan{0}: 67 0f b9 00 ud1 (%eax),%eax
|
||||
* UBSan{10}: 67 0f b9 40 10 ud1 0x10(%eax),%eax
|
||||
@@ -130,9 +130,9 @@ __always_inline int decode_bug(unsigned long addr, s32 *imm, int *len)
|
||||
WARN_ON_ONCE(!lock);
|
||||
return BUG_LOCK;
|
||||
|
||||
case 0xea:
|
||||
case 0xd6:
|
||||
*len = addr - start;
|
||||
return BUG_EA;
|
||||
return BUG_UDB;
|
||||
|
||||
case OPCODE_ESCAPE:
|
||||
break;
|
||||
@@ -341,7 +341,7 @@ static noinstr bool handle_bug(struct pt_regs *regs)
|
||||
}
|
||||
fallthrough;
|
||||
|
||||
case BUG_EA:
|
||||
case BUG_UDB:
|
||||
case BUG_LOCK:
|
||||
if (handle_cfi_failure(regs) == BUG_TRAP_TYPE_WARN) {
|
||||
handled = true;
|
||||
|
||||
@@ -96,6 +96,7 @@ config KVM_SW_PROTECTED_VM
|
||||
config KVM_INTEL
|
||||
tristate "KVM for Intel (and compatible) processors support"
|
||||
depends on KVM && IA32_FEAT_CTL
|
||||
select X86_FRED if X86_64
|
||||
help
|
||||
Provides support for KVM on processors equipped with Intel's VT
|
||||
extensions, a.k.a. Virtual Machine Extensions (VMX).
|
||||
|
||||
+210
-296
File diff suppressed because it is too large
Load Diff
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user