Skip to content

Commit 75d090f

Browse files
kirylbp3tk0v
authored andcommitted
x86/tdx: Add unaccepted memory support
Hookup TDX-specific code to accept memory. Accepting the memory is done with ACCEPT_PAGE module call on every page in the range. MAP_GPA hypercall is not required as the unaccepted memory is considered private already. Extract the part of tdx_enc_status_changed() that does memory acceptance in a new helper. Move the helper tdx-shared.c. It is going to be used by both main kernel and decompressor. [ bp: Fix the INTEL_TDX_GUEST=y, KVM_GUEST=n build. ] Signed-off-by: Kirill A. Shutemov <[email protected]> Signed-off-by: Borislav Petkov (AMD) <[email protected]> Link: https://lore.kernel.org/r/[email protected]
1 parent c2b353a commit 75d090f

File tree

12 files changed

+162
-70
lines changed

12 files changed

+162
-70
lines changed

arch/x86/Kconfig

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -884,9 +884,11 @@ config INTEL_TDX_GUEST
884884
bool "Intel TDX (Trust Domain Extensions) - Guest Support"
885885
depends on X86_64 && CPU_SUP_INTEL
886886
depends on X86_X2APIC
887+
depends on EFI_STUB
887888
select ARCH_HAS_CC_PLATFORM
888889
select X86_MEM_ENCRYPT
889890
select X86_MCE
891+
select UNACCEPTED_MEMORY
890892
help
891893
Support running as a guest under Intel TDX. Without this support,
892894
the guest kernel can not boot or run under TDX.

arch/x86/boot/compressed/Makefile

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -106,7 +106,7 @@ ifdef CONFIG_X86_64
106106
endif
107107

108108
vmlinux-objs-$(CONFIG_ACPI) += $(obj)/acpi.o
109-
vmlinux-objs-$(CONFIG_INTEL_TDX_GUEST) += $(obj)/tdx.o $(obj)/tdcall.o
109+
vmlinux-objs-$(CONFIG_INTEL_TDX_GUEST) += $(obj)/tdx.o $(obj)/tdcall.o $(obj)/tdx-shared.o
110110
vmlinux-objs-$(CONFIG_UNACCEPTED_MEMORY) += $(obj)/mem.o
111111

112112
vmlinux-objs-$(CONFIG_EFI) += $(obj)/efi.o

arch/x86/boot/compressed/error.c

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,3 +22,22 @@ void error(char *m)
2222
while (1)
2323
asm("hlt");
2424
}
25+
26+
/* EFI libstub provides vsnprintf() */
27+
#ifdef CONFIG_EFI_STUB
28+
void panic(const char *fmt, ...)
29+
{
30+
static char buf[1024];
31+
va_list args;
32+
int len;
33+
34+
va_start(args, fmt);
35+
len = vsnprintf(buf, sizeof(buf), fmt, args);
36+
va_end(args);
37+
38+
if (len && buf[len - 1] == '\n')
39+
buf[len - 1] = '\0';
40+
41+
error(buf);
42+
}
43+
#endif

arch/x86/boot/compressed/error.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,5 +6,6 @@
66

77
void warn(char *m);
88
void error(char *m) __noreturn;
9+
void panic(const char *fmt, ...) __noreturn __cold;
910

1011
#endif /* BOOT_COMPRESSED_ERROR_H */

arch/x86/boot/compressed/mem.c

Lines changed: 34 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,11 +2,44 @@
22

33
#include "error.h"
44
#include "misc.h"
5+
#include "tdx.h"
6+
#include <asm/shared/tdx.h>
7+
8+
/*
9+
* accept_memory() and process_unaccepted_memory() called from EFI stub which
10+
* runs before decompresser and its early_tdx_detect().
11+
*
12+
* Enumerate TDX directly from the early users.
13+
*/
14+
static bool early_is_tdx_guest(void)
15+
{
16+
static bool once;
17+
static bool is_tdx;
18+
19+
if (!IS_ENABLED(CONFIG_INTEL_TDX_GUEST))
20+
return false;
21+
22+
if (!once) {
23+
u32 eax, sig[3];
24+
25+
cpuid_count(TDX_CPUID_LEAF_ID, 0, &eax,
26+
&sig[0], &sig[2], &sig[1]);
27+
is_tdx = !memcmp(TDX_IDENT, sig, sizeof(sig));
28+
once = true;
29+
}
30+
31+
return is_tdx;
32+
}
533

634
void arch_accept_memory(phys_addr_t start, phys_addr_t end)
735
{
836
/* Platform-specific memory-acceptance call goes here */
9-
error("Cannot accept memory");
37+
if (early_is_tdx_guest()) {
38+
if (!tdx_accept_memory(start, end))
39+
panic("TDX: Failed to accept memory\n");
40+
} else {
41+
error("Cannot accept memory: unknown platform\n");
42+
}
1043
}
1144

1245
bool init_unaccepted_memory(void)

arch/x86/boot/compressed/tdx-shared.c

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
#include "error.h"
2+
#include "../../coco/tdx/tdx-shared.c"

arch/x86/coco/tdx/Makefile

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,3 @@
11
# SPDX-License-Identifier: GPL-2.0
22

3-
obj-y += tdx.o tdcall.o
3+
obj-y += tdx.o tdx-shared.o tdcall.o

arch/x86/coco/tdx/tdx-shared.c

Lines changed: 71 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,71 @@
1+
#include <asm/tdx.h>
2+
#include <asm/pgtable.h>
3+
4+
static unsigned long try_accept_one(phys_addr_t start, unsigned long len,
5+
enum pg_level pg_level)
6+
{
7+
unsigned long accept_size = page_level_size(pg_level);
8+
u64 tdcall_rcx;
9+
u8 page_size;
10+
11+
if (!IS_ALIGNED(start, accept_size))
12+
return 0;
13+
14+
if (len < accept_size)
15+
return 0;
16+
17+
/*
18+
* Pass the page physical address to the TDX module to accept the
19+
* pending, private page.
20+
*
21+
* Bits 2:0 of RCX encode page size: 0 - 4K, 1 - 2M, 2 - 1G.
22+
*/
23+
switch (pg_level) {
24+
case PG_LEVEL_4K:
25+
page_size = 0;
26+
break;
27+
case PG_LEVEL_2M:
28+
page_size = 1;
29+
break;
30+
case PG_LEVEL_1G:
31+
page_size = 2;
32+
break;
33+
default:
34+
return 0;
35+
}
36+
37+
tdcall_rcx = start | page_size;
38+
if (__tdx_module_call(TDX_ACCEPT_PAGE, tdcall_rcx, 0, 0, 0, NULL))
39+
return 0;
40+
41+
return accept_size;
42+
}
43+
44+
bool tdx_accept_memory(phys_addr_t start, phys_addr_t end)
45+
{
46+
/*
47+
* For shared->private conversion, accept the page using
48+
* TDX_ACCEPT_PAGE TDX module call.
49+
*/
50+
while (start < end) {
51+
unsigned long len = end - start;
52+
unsigned long accept_size;
53+
54+
/*
55+
* Try larger accepts first. It gives chance to VMM to keep
56+
* 1G/2M Secure EPT entries where possible and speeds up
57+
* process by cutting number of hypercalls (if successful).
58+
*/
59+
60+
accept_size = try_accept_one(start, len, PG_LEVEL_1G);
61+
if (!accept_size)
62+
accept_size = try_accept_one(start, len, PG_LEVEL_2M);
63+
if (!accept_size)
64+
accept_size = try_accept_one(start, len, PG_LEVEL_4K);
65+
if (!accept_size)
66+
return false;
67+
start += accept_size;
68+
}
69+
70+
return true;
71+
}

arch/x86/coco/tdx/tdx.c

Lines changed: 3 additions & 67 deletions
Original file line numberDiff line numberDiff line change
@@ -713,46 +713,6 @@ static bool tdx_cache_flush_required(void)
713713
return true;
714714
}
715715

716-
static unsigned long try_accept_one(phys_addr_t start, unsigned long len,
717-
enum pg_level pg_level)
718-
{
719-
unsigned long accept_size = page_level_size(pg_level);
720-
u64 tdcall_rcx;
721-
u8 page_size;
722-
723-
if (!IS_ALIGNED(start, accept_size))
724-
return 0;
725-
726-
if (len < accept_size)
727-
return 0;
728-
729-
/*
730-
* Pass the page physical address to the TDX module to accept the
731-
* pending, private page.
732-
*
733-
* Bits 2:0 of RCX encode page size: 0 - 4K, 1 - 2M, 2 - 1G.
734-
*/
735-
switch (pg_level) {
736-
case PG_LEVEL_4K:
737-
page_size = 0;
738-
break;
739-
case PG_LEVEL_2M:
740-
page_size = 1;
741-
break;
742-
case PG_LEVEL_1G:
743-
page_size = 2;
744-
break;
745-
default:
746-
return 0;
747-
}
748-
749-
tdcall_rcx = start | page_size;
750-
if (__tdx_module_call(TDX_ACCEPT_PAGE, tdcall_rcx, 0, 0, 0, NULL))
751-
return 0;
752-
753-
return accept_size;
754-
}
755-
756716
/*
757717
* Inform the VMM of the guest's intent for this physical page: shared with
758718
* the VMM or private to the guest. The VMM is expected to change its mapping
@@ -777,33 +737,9 @@ static bool tdx_enc_status_changed(unsigned long vaddr, int numpages, bool enc)
777737
if (_tdx_hypercall(TDVMCALL_MAP_GPA, start, end - start, 0, 0))
778738
return false;
779739

780-
/* private->shared conversion requires only MapGPA call */
781-
if (!enc)
782-
return true;
783-
784-
/*
785-
* For shared->private conversion, accept the page using
786-
* TDX_ACCEPT_PAGE TDX module call.
787-
*/
788-
while (start < end) {
789-
unsigned long len = end - start;
790-
unsigned long accept_size;
791-
792-
/*
793-
* Try larger accepts first. It gives chance to VMM to keep
794-
* 1G/2M Secure EPT entries where possible and speeds up
795-
* process by cutting number of hypercalls (if successful).
796-
*/
797-
798-
accept_size = try_accept_one(start, len, PG_LEVEL_1G);
799-
if (!accept_size)
800-
accept_size = try_accept_one(start, len, PG_LEVEL_2M);
801-
if (!accept_size)
802-
accept_size = try_accept_one(start, len, PG_LEVEL_4K);
803-
if (!accept_size)
804-
return false;
805-
start += accept_size;
806-
}
740+
/* shared->private conversion requires memory to be accepted before use */
741+
if (enc)
742+
return tdx_accept_memory(start, end);
807743

808744
return true;
809745
}

arch/x86/include/asm/shared/tdx.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -91,5 +91,7 @@ struct tdx_module_output {
9191
u64 __tdx_module_call(u64 fn, u64 rcx, u64 rdx, u64 r8, u64 r9,
9292
struct tdx_module_output *out);
9393

94+
bool tdx_accept_memory(phys_addr_t start, phys_addr_t end);
95+
9496
#endif /* !__ASSEMBLY__ */
9597
#endif /* _ASM_X86_SHARED_TDX_H */

0 commit comments

Comments
 (0)