Skip to content

Commit f980f9c

Browse files
joergroedelsuryasaimadhu
authored andcommitted
x86/sev-es: Compile early handler code into kernel image
Setup sev-es.c and include the code from the pre-decompression stage to also build it into the image of the running kernel. Temporarily add __maybe_unused annotations to avoid build warnings until the functions get used. [ bp: Use the non-tracing rd/wrmsr variants because: vmlinux.o: warning: objtool: __sev_es_nmi_complete()+0x11f: \ call to do_trace_write_msr() leaves .noinstr.text section as __sev_es_nmi_complete() is noinstr due to being called from the NMI handler exc_nmi(). ] Signed-off-by: Joerg Roedel <[email protected]> Signed-off-by: Borislav Petkov <[email protected]> Link: https://lkml.kernel.org/r/[email protected]
1 parent c685eb0 commit f980f9c

File tree

3 files changed

+175
-10
lines changed

3 files changed

+175
-10
lines changed

arch/x86/kernel/Makefile

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -145,6 +145,7 @@ obj-$(CONFIG_UNWINDER_ORC) += unwind_orc.o
145145
obj-$(CONFIG_UNWINDER_FRAME_POINTER) += unwind_frame.o
146146
obj-$(CONFIG_UNWINDER_GUESS) += unwind_guess.o
147147

148+
obj-$(CONFIG_AMD_MEM_ENCRYPT) += sev-es.o
148149
###
149150
# 64 bit specific files
150151
ifeq ($(CONFIG_X86_64),y)

arch/x86/kernel/sev-es-shared.c

Lines changed: 11 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@
99
* and is included directly into both code-bases.
1010
*/
1111

12-
static void sev_es_terminate(unsigned int reason)
12+
static void __maybe_unused sev_es_terminate(unsigned int reason)
1313
{
1414
u64 val = GHCB_SEV_TERMINATE;
1515

@@ -27,7 +27,7 @@ static void sev_es_terminate(unsigned int reason)
2727
asm volatile("hlt\n" : : : "memory");
2828
}
2929

30-
static bool sev_es_negotiate_protocol(void)
30+
static bool __maybe_unused sev_es_negotiate_protocol(void)
3131
{
3232
u64 val;
3333

@@ -46,7 +46,7 @@ static bool sev_es_negotiate_protocol(void)
4646
return true;
4747
}
4848

49-
static void vc_ghcb_invalidate(struct ghcb *ghcb)
49+
static void __maybe_unused vc_ghcb_invalidate(struct ghcb *ghcb)
5050
{
5151
memset(ghcb->save.valid_bitmap, 0, sizeof(ghcb->save.valid_bitmap));
5252
}
@@ -58,9 +58,9 @@ static bool vc_decoding_needed(unsigned long exit_code)
5858
exit_code <= SVM_EXIT_LAST_EXCP);
5959
}
6060

61-
static enum es_result vc_init_em_ctxt(struct es_em_ctxt *ctxt,
62-
struct pt_regs *regs,
63-
unsigned long exit_code)
61+
static enum es_result __maybe_unused vc_init_em_ctxt(struct es_em_ctxt *ctxt,
62+
struct pt_regs *regs,
63+
unsigned long exit_code)
6464
{
6565
enum es_result ret = ES_OK;
6666

@@ -73,7 +73,7 @@ static enum es_result vc_init_em_ctxt(struct es_em_ctxt *ctxt,
7373
return ret;
7474
}
7575

76-
static void vc_finish_insn(struct es_em_ctxt *ctxt)
76+
static void __maybe_unused vc_finish_insn(struct es_em_ctxt *ctxt)
7777
{
7878
ctxt->regs->ip += ctxt->insn.length;
7979
}
@@ -325,7 +325,8 @@ static enum es_result vc_ioio_exitinfo(struct es_em_ctxt *ctxt, u64 *exitinfo)
325325
return ES_OK;
326326
}
327327

328-
static enum es_result vc_handle_ioio(struct ghcb *ghcb, struct es_em_ctxt *ctxt)
328+
static enum es_result __maybe_unused
329+
vc_handle_ioio(struct ghcb *ghcb, struct es_em_ctxt *ctxt)
329330
{
330331
struct pt_regs *regs = ctxt->regs;
331332
u64 exit_info_1, exit_info_2;
@@ -433,8 +434,8 @@ static enum es_result vc_handle_ioio(struct ghcb *ghcb, struct es_em_ctxt *ctxt)
433434
return ret;
434435
}
435436

436-
static enum es_result vc_handle_cpuid(struct ghcb *ghcb,
437-
struct es_em_ctxt *ctxt)
437+
static enum es_result __maybe_unused vc_handle_cpuid(struct ghcb *ghcb,
438+
struct es_em_ctxt *ctxt)
438439
{
439440
struct pt_regs *regs = ctxt->regs;
440441
u32 cr4 = native_read_cr4();

arch/x86/kernel/sev-es.c

Lines changed: 163 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,163 @@
1+
// SPDX-License-Identifier: GPL-2.0-only
2+
/*
3+
* AMD Memory Encryption Support
4+
*
5+
* Copyright (C) 2019 SUSE
6+
*
7+
* Author: Joerg Roedel <[email protected]>
8+
*/
9+
10+
#include <linux/kernel.h>
11+
#include <linux/mm.h>
12+
13+
#include <asm/sev-es.h>
14+
#include <asm/insn-eval.h>
15+
#include <asm/fpu/internal.h>
16+
#include <asm/processor.h>
17+
#include <asm/trap_pf.h>
18+
#include <asm/trapnr.h>
19+
#include <asm/svm.h>
20+
21+
static inline u64 sev_es_rd_ghcb_msr(void)
22+
{
23+
return __rdmsr(MSR_AMD64_SEV_ES_GHCB);
24+
}
25+
26+
static inline void sev_es_wr_ghcb_msr(u64 val)
27+
{
28+
u32 low, high;
29+
30+
low = (u32)(val);
31+
high = (u32)(val >> 32);
32+
33+
native_wrmsr(MSR_AMD64_SEV_ES_GHCB, low, high);
34+
}
35+
36+
static int vc_fetch_insn_kernel(struct es_em_ctxt *ctxt,
37+
unsigned char *buffer)
38+
{
39+
return copy_from_kernel_nofault(buffer, (unsigned char *)ctxt->regs->ip, MAX_INSN_SIZE);
40+
}
41+
42+
static enum es_result vc_decode_insn(struct es_em_ctxt *ctxt)
43+
{
44+
char buffer[MAX_INSN_SIZE];
45+
enum es_result ret;
46+
int res;
47+
48+
res = vc_fetch_insn_kernel(ctxt, buffer);
49+
if (unlikely(res == -EFAULT)) {
50+
ctxt->fi.vector = X86_TRAP_PF;
51+
ctxt->fi.error_code = 0;
52+
ctxt->fi.cr2 = ctxt->regs->ip;
53+
return ES_EXCEPTION;
54+
}
55+
56+
insn_init(&ctxt->insn, buffer, MAX_INSN_SIZE - res, 1);
57+
insn_get_length(&ctxt->insn);
58+
59+
ret = ctxt->insn.immediate.got ? ES_OK : ES_DECODE_FAILED;
60+
61+
return ret;
62+
}
63+
64+
static enum es_result vc_write_mem(struct es_em_ctxt *ctxt,
65+
char *dst, char *buf, size_t size)
66+
{
67+
unsigned long error_code = X86_PF_PROT | X86_PF_WRITE;
68+
char __user *target = (char __user *)dst;
69+
u64 d8;
70+
u32 d4;
71+
u16 d2;
72+
u8 d1;
73+
74+
switch (size) {
75+
case 1:
76+
memcpy(&d1, buf, 1);
77+
if (put_user(d1, target))
78+
goto fault;
79+
break;
80+
case 2:
81+
memcpy(&d2, buf, 2);
82+
if (put_user(d2, target))
83+
goto fault;
84+
break;
85+
case 4:
86+
memcpy(&d4, buf, 4);
87+
if (put_user(d4, target))
88+
goto fault;
89+
break;
90+
case 8:
91+
memcpy(&d8, buf, 8);
92+
if (put_user(d8, target))
93+
goto fault;
94+
break;
95+
default:
96+
WARN_ONCE(1, "%s: Invalid size: %zu\n", __func__, size);
97+
return ES_UNSUPPORTED;
98+
}
99+
100+
return ES_OK;
101+
102+
fault:
103+
if (user_mode(ctxt->regs))
104+
error_code |= X86_PF_USER;
105+
106+
ctxt->fi.vector = X86_TRAP_PF;
107+
ctxt->fi.error_code = error_code;
108+
ctxt->fi.cr2 = (unsigned long)dst;
109+
110+
return ES_EXCEPTION;
111+
}
112+
113+
static enum es_result vc_read_mem(struct es_em_ctxt *ctxt,
114+
char *src, char *buf, size_t size)
115+
{
116+
unsigned long error_code = X86_PF_PROT;
117+
char __user *s = (char __user *)src;
118+
u64 d8;
119+
u32 d4;
120+
u16 d2;
121+
u8 d1;
122+
123+
switch (size) {
124+
case 1:
125+
if (get_user(d1, s))
126+
goto fault;
127+
memcpy(buf, &d1, 1);
128+
break;
129+
case 2:
130+
if (get_user(d2, s))
131+
goto fault;
132+
memcpy(buf, &d2, 2);
133+
break;
134+
case 4:
135+
if (get_user(d4, s))
136+
goto fault;
137+
memcpy(buf, &d4, 4);
138+
break;
139+
case 8:
140+
if (get_user(d8, s))
141+
goto fault;
142+
memcpy(buf, &d8, 8);
143+
break;
144+
default:
145+
WARN_ONCE(1, "%s: Invalid size: %zu\n", __func__, size);
146+
return ES_UNSUPPORTED;
147+
}
148+
149+
return ES_OK;
150+
151+
fault:
152+
if (user_mode(ctxt->regs))
153+
error_code |= X86_PF_USER;
154+
155+
ctxt->fi.vector = X86_TRAP_PF;
156+
ctxt->fi.error_code = error_code;
157+
ctxt->fi.cr2 = (unsigned long)src;
158+
159+
return ES_EXCEPTION;
160+
}
161+
162+
/* Include code shared with pre-decompression boot stage */
163+
#include "sev-es-shared.c"

0 commit comments

Comments
 (0)