Commit d04f7de0 authored by Linus Torvalds's avatar Linus Torvalds

Merge tag 'x86_sev_for_v5.14_rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/tip/tip

Pull x86 SEV updates from Borislav Petkov:

 - Differentiate the type of exception the #VC handler raises depending
   on code executed in the guest and handle the case where failure to
   get the RIP would result in a #GP, as it should, instead of in a #PF

 - Disable interrupts while the per-CPU GHCB is held

 - Split the #VC handler depending on where the #VC exception has
   happened and therefore provide for precise context tracking like the
   rest of the exception handlers deal with noinstr regions now

 - Add defines for the GHCB version 2 protocol so that further shared
   development with KVM can happen without merge conflicts

 - The usual small cleanups

* tag 'x86_sev_for_v5.14_rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/tip/tip:
  x86/sev: Use "SEV: " prefix for messages from sev.c
  x86/sev: Add defines for GHCB version 2 MSR protocol requests
  x86/sev: Split up runtime #VC handler for correct state tracking
  x86/sev: Make sure IRQs are disabled while GHCB is active
  x86/sev: Propagate #GP if getting linear instruction address failed
  x86/insn: Extend error reporting from insn_fetch_from_user[_inatomic]()
  x86/insn-eval: Make 0 a valid RIP for insn_get_effective_ip()
  x86/sev: Fix error message in runtime #VC handler
parents 2594b713 8d9d46bb
...@@ -506,7 +506,7 @@ SYM_CODE_START(\asmsym) ...@@ -506,7 +506,7 @@ SYM_CODE_START(\asmsym)
movq %rsp, %rdi /* pt_regs pointer */ movq %rsp, %rdi /* pt_regs pointer */
call \cfunc call kernel_\cfunc
/* /*
* No need to switch back to the IST stack. The current stack is either * No need to switch back to the IST stack. The current stack is either
...@@ -517,7 +517,7 @@ SYM_CODE_START(\asmsym) ...@@ -517,7 +517,7 @@ SYM_CODE_START(\asmsym)
/* Switch to the regular task stack */ /* Switch to the regular task stack */
.Lfrom_usermode_switch_stack_\@: .Lfrom_usermode_switch_stack_\@:
idtentry_body safe_stack_\cfunc, has_error_code=1 idtentry_body user_\cfunc, has_error_code=1
_ASM_NOKPROBE(\asmsym) _ASM_NOKPROBE(\asmsym)
SYM_CODE_END(\asmsym) SYM_CODE_END(\asmsym)
......
...@@ -312,8 +312,8 @@ static __always_inline void __##func(struct pt_regs *regs) ...@@ -312,8 +312,8 @@ static __always_inline void __##func(struct pt_regs *regs)
*/ */
#define DECLARE_IDTENTRY_VC(vector, func) \ #define DECLARE_IDTENTRY_VC(vector, func) \
DECLARE_IDTENTRY_RAW_ERRORCODE(vector, func); \ DECLARE_IDTENTRY_RAW_ERRORCODE(vector, func); \
__visible noinstr void ist_##func(struct pt_regs *regs, unsigned long error_code); \ __visible noinstr void kernel_##func(struct pt_regs *regs, unsigned long error_code); \
__visible noinstr void safe_stack_##func(struct pt_regs *regs, unsigned long error_code) __visible noinstr void user_##func(struct pt_regs *regs, unsigned long error_code)
/** /**
* DEFINE_IDTENTRY_IST - Emit code for IST entry points * DEFINE_IDTENTRY_IST - Emit code for IST entry points
...@@ -355,33 +355,24 @@ static __always_inline void __##func(struct pt_regs *regs) ...@@ -355,33 +355,24 @@ static __always_inline void __##func(struct pt_regs *regs)
DEFINE_IDTENTRY_RAW_ERRORCODE(func) DEFINE_IDTENTRY_RAW_ERRORCODE(func)
/** /**
* DEFINE_IDTENTRY_VC_SAFE_STACK - Emit code for VMM communication handler * DEFINE_IDTENTRY_VC_KERNEL - Emit code for VMM communication handler
which runs on a safe stack. when raised from kernel mode
* @func: Function name of the entry point * @func: Function name of the entry point
* *
* Maps to DEFINE_IDTENTRY_RAW_ERRORCODE * Maps to DEFINE_IDTENTRY_RAW_ERRORCODE
*/ */
#define DEFINE_IDTENTRY_VC_SAFE_STACK(func) \ #define DEFINE_IDTENTRY_VC_KERNEL(func) \
DEFINE_IDTENTRY_RAW_ERRORCODE(safe_stack_##func) DEFINE_IDTENTRY_RAW_ERRORCODE(kernel_##func)
/** /**
* DEFINE_IDTENTRY_VC_IST - Emit code for VMM communication handler * DEFINE_IDTENTRY_VC_USER - Emit code for VMM communication handler
which runs on the VC fall-back stack when raised from user mode
* @func: Function name of the entry point * @func: Function name of the entry point
* *
* Maps to DEFINE_IDTENTRY_RAW_ERRORCODE * Maps to DEFINE_IDTENTRY_RAW_ERRORCODE
*/ */
#define DEFINE_IDTENTRY_VC_IST(func) \ #define DEFINE_IDTENTRY_VC_USER(func) \
DEFINE_IDTENTRY_RAW_ERRORCODE(ist_##func) DEFINE_IDTENTRY_RAW_ERRORCODE(user_##func)
/**
* DEFINE_IDTENTRY_VC - Emit code for VMM communication handler
* @func: Function name of the entry point
*
* Maps to DEFINE_IDTENTRY_RAW_ERRORCODE
*/
#define DEFINE_IDTENTRY_VC(func) \
DEFINE_IDTENTRY_RAW_ERRORCODE(func)
#else /* CONFIG_X86_64 */ #else /* CONFIG_X86_64 */
......
...@@ -9,8 +9,13 @@ ...@@ -9,8 +9,13 @@
#define __ASM_X86_SEV_COMMON_H #define __ASM_X86_SEV_COMMON_H
#define GHCB_MSR_INFO_POS 0 #define GHCB_MSR_INFO_POS 0
#define GHCB_MSR_INFO_MASK (BIT_ULL(12) - 1) #define GHCB_DATA_LOW 12
#define GHCB_MSR_INFO_MASK (BIT_ULL(GHCB_DATA_LOW) - 1)
#define GHCB_DATA(v) \
(((unsigned long)(v) & ~GHCB_MSR_INFO_MASK) >> GHCB_DATA_LOW)
/* SEV Information Request/Response */
#define GHCB_MSR_SEV_INFO_RESP 0x001 #define GHCB_MSR_SEV_INFO_RESP 0x001
#define GHCB_MSR_SEV_INFO_REQ 0x002 #define GHCB_MSR_SEV_INFO_REQ 0x002
#define GHCB_MSR_VER_MAX_POS 48 #define GHCB_MSR_VER_MAX_POS 48
...@@ -28,6 +33,7 @@ ...@@ -28,6 +33,7 @@
#define GHCB_MSR_PROTO_MAX(v) (((v) >> GHCB_MSR_VER_MAX_POS) & GHCB_MSR_VER_MAX_MASK) #define GHCB_MSR_PROTO_MAX(v) (((v) >> GHCB_MSR_VER_MAX_POS) & GHCB_MSR_VER_MAX_MASK)
#define GHCB_MSR_PROTO_MIN(v) (((v) >> GHCB_MSR_VER_MIN_POS) & GHCB_MSR_VER_MIN_MASK) #define GHCB_MSR_PROTO_MIN(v) (((v) >> GHCB_MSR_VER_MIN_POS) & GHCB_MSR_VER_MIN_MASK)
/* CPUID Request/Response */
#define GHCB_MSR_CPUID_REQ 0x004 #define GHCB_MSR_CPUID_REQ 0x004
#define GHCB_MSR_CPUID_RESP 0x005 #define GHCB_MSR_CPUID_RESP 0x005
#define GHCB_MSR_CPUID_FUNC_POS 32 #define GHCB_MSR_CPUID_FUNC_POS 32
...@@ -45,6 +51,14 @@ ...@@ -45,6 +51,14 @@
(((unsigned long)reg & GHCB_MSR_CPUID_REG_MASK) << GHCB_MSR_CPUID_REG_POS) | \ (((unsigned long)reg & GHCB_MSR_CPUID_REG_MASK) << GHCB_MSR_CPUID_REG_POS) | \
(((unsigned long)fn) << GHCB_MSR_CPUID_FUNC_POS)) (((unsigned long)fn) << GHCB_MSR_CPUID_FUNC_POS))
/* AP Reset Hold */
#define GHCB_MSR_AP_RESET_HOLD_REQ 0x006
#define GHCB_MSR_AP_RESET_HOLD_RESP 0x007
/* GHCB Hypervisor Feature Request/Response */
#define GHCB_MSR_HV_FT_REQ 0x080
#define GHCB_MSR_HV_FT_RESP 0x081
#define GHCB_MSR_TERM_REQ 0x100 #define GHCB_MSR_TERM_REQ 0x100
#define GHCB_MSR_TERM_REASON_SET_POS 12 #define GHCB_MSR_TERM_REASON_SET_POS 12
#define GHCB_MSR_TERM_REASON_SET_MASK 0xf #define GHCB_MSR_TERM_REASON_SET_MASK 0xf
......
This diff is collapsed.
...@@ -346,14 +346,12 @@ bool fixup_umip_exception(struct pt_regs *regs) ...@@ -346,14 +346,12 @@ bool fixup_umip_exception(struct pt_regs *regs)
if (!regs) if (!regs)
return false; return false;
nr_copied = insn_fetch_from_user(regs, buf);
/* /*
* The insn_fetch_from_user above could have failed if user code * Give up on emulation if fetching the instruction failed. Should a
* is protected by a memory protection key. Give up on emulation * page fault or a #GP be issued?
* in such a case. Should we issue a page fault?
*/ */
if (!nr_copied) nr_copied = insn_fetch_from_user(regs, buf);
if (nr_copied <= 0)
return false; return false;
if (!insn_decode_from_regs(&insn, regs, buf, nr_copied)) if (!insn_decode_from_regs(&insn, regs, buf, nr_copied))
......
...@@ -1417,7 +1417,7 @@ void __user *insn_get_addr_ref(struct insn *insn, struct pt_regs *regs) ...@@ -1417,7 +1417,7 @@ void __user *insn_get_addr_ref(struct insn *insn, struct pt_regs *regs)
} }
} }
static unsigned long insn_get_effective_ip(struct pt_regs *regs) static int insn_get_effective_ip(struct pt_regs *regs, unsigned long *ip)
{ {
unsigned long seg_base = 0; unsigned long seg_base = 0;
...@@ -1430,10 +1430,12 @@ static unsigned long insn_get_effective_ip(struct pt_regs *regs) ...@@ -1430,10 +1430,12 @@ static unsigned long insn_get_effective_ip(struct pt_regs *regs)
if (!user_64bit_mode(regs)) { if (!user_64bit_mode(regs)) {
seg_base = insn_get_seg_base(regs, INAT_SEG_REG_CS); seg_base = insn_get_seg_base(regs, INAT_SEG_REG_CS);
if (seg_base == -1L) if (seg_base == -1L)
return 0; return -EINVAL;
} }
return seg_base + regs->ip; *ip = seg_base + regs->ip;
return 0;
} }
/** /**
...@@ -1446,18 +1448,17 @@ static unsigned long insn_get_effective_ip(struct pt_regs *regs) ...@@ -1446,18 +1448,17 @@ static unsigned long insn_get_effective_ip(struct pt_regs *regs)
* *
* Returns: * Returns:
* *
* Number of instruction bytes copied. * - number of instruction bytes copied.
* * - 0 if nothing was copied.
* 0 if nothing was copied. * - -EINVAL if the linear address of the instruction could not be calculated
*/ */
int insn_fetch_from_user(struct pt_regs *regs, unsigned char buf[MAX_INSN_SIZE]) int insn_fetch_from_user(struct pt_regs *regs, unsigned char buf[MAX_INSN_SIZE])
{ {
unsigned long ip; unsigned long ip;
int not_copied; int not_copied;
ip = insn_get_effective_ip(regs); if (insn_get_effective_ip(regs, &ip))
if (!ip) return -EINVAL;
return 0;
not_copied = copy_from_user(buf, (void __user *)ip, MAX_INSN_SIZE); not_copied = copy_from_user(buf, (void __user *)ip, MAX_INSN_SIZE);
...@@ -1475,18 +1476,17 @@ int insn_fetch_from_user(struct pt_regs *regs, unsigned char buf[MAX_INSN_SIZE]) ...@@ -1475,18 +1476,17 @@ int insn_fetch_from_user(struct pt_regs *regs, unsigned char buf[MAX_INSN_SIZE])
* *
* Returns: * Returns:
* *
* Number of instruction bytes copied. * - number of instruction bytes copied.
* * - 0 if nothing was copied.
* 0 if nothing was copied. * - -EINVAL if the linear address of the instruction could not be calculated.
*/ */
int insn_fetch_from_user_inatomic(struct pt_regs *regs, unsigned char buf[MAX_INSN_SIZE]) int insn_fetch_from_user_inatomic(struct pt_regs *regs, unsigned char buf[MAX_INSN_SIZE])
{ {
unsigned long ip; unsigned long ip;
int not_copied; int not_copied;
ip = insn_get_effective_ip(regs); if (insn_get_effective_ip(regs, &ip))
if (!ip) return -EINVAL;
return 0;
not_copied = __copy_from_user_inatomic(buf, (void __user *)ip, MAX_INSN_SIZE); not_copied = __copy_from_user_inatomic(buf, (void __user *)ip, MAX_INSN_SIZE);
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment