[PATCH] x86/mm: Print the encryption features correctly when a paravisor is present

From: Dexuan Cui
Date: Thu Oct 19 2023 - 02:21:47 EST


Hyper-V provides two modes for running a TDX/SNP VM:

1) In TD Partitioning mode (TDX) or vTOM mode (SNP) with a paravisor;
2) In "fully enlightened" mode with the normal TDX shared bit or SNP C-bit
control over page encryption, and no paravisor.

In the first mode (i.e. paravisor mode), the native TDX/SNP CPUID
capability is hidden from the VM, but cc_platform_has(CC_ATTR_MEM_ENCRYPT)
and cc_platform_has(CC_ATTR_GUEST_MEM_ENCRYPT) are true; as a result,
mem_encrypt_init() incorrectly prints the below message when an Intel TDX
VM with a paravisor runs on Hyper-V:
"Memory Encryption Features active: AMD SEV".

Introduce x86_platform.print_mem_enc_feature_info and allow hv_vtom_init()
to override the function pointer so that the correct message is printed.

BTW, when a VBS (Virtualization-based Security) VM running on Hyper-V
(the physical CPU can be an AMD CPU or an Intel CPU), the VM's memory is
not encrypted, but mem_encrypt_init() also prints the same incorrect
message. The introduction of x86_platform.print_mem_enc_feature_info can
also fix the issue.

Signed-off-by: Dexuan Cui <decui@xxxxxxxxxxxxx>
---

Some open questions:

1. Should we refactor the existing print_memory_encrypt_feature_info()
into a TDX-specific function and an SEV-specific function? The
function pointer in x86_platform_ops would be initialized to a no-op
function, and then early_tdx_init(), sme_enable() and hv_vtom_init()
would fill it in accordingly.

2. Should we rename "print_mem_enc_feature_info()" to
"print_coco_feature_info()"? CC_ATTR_GUEST_STATE_ENCRYPT (and
CC_ATTR_GUEST_SEV_SNP?) may not look like *memory* encryption to me?

arch/x86/hyperv/ivm.c | 11 +++++++++++
arch/x86/include/asm/mem_encrypt.h | 1 +
arch/x86/include/asm/x86_init.h | 2 ++
arch/x86/kernel/x86_init.c | 1 +
arch/x86/mm/mem_encrypt.c | 4 ++--
5 files changed, 17 insertions(+), 2 deletions(-)

diff --git a/arch/x86/hyperv/ivm.c b/arch/x86/hyperv/ivm.c
index e68051eba25a..fdc2fab0415e 100644
--- a/arch/x86/hyperv/ivm.c
+++ b/arch/x86/hyperv/ivm.c
@@ -450,6 +450,16 @@ static bool hv_is_private_mmio(u64 addr)
return false;
}

+static void hv_print_mem_enc_feature_info(void)
+{
+ enum hv_isolation_type type = hv_get_isolation_type();
+
+ if (type == HV_ISOLATION_TYPE_SNP)
+ pr_info("Memory Encryption Features active: AMD SEV\n");
+ else if (type == HV_ISOLATION_TYPE_TDX)
+ pr_info("Memory Encryption Features active: Intel TDX\n");
+}
+
void __init hv_vtom_init(void)
{
enum hv_isolation_type type = hv_get_isolation_type();
@@ -479,6 +489,7 @@ void __init hv_vtom_init(void)
cc_set_mask(ms_hyperv.shared_gpa_boundary);
physical_mask &= ms_hyperv.shared_gpa_boundary - 1;

+ x86_platform.print_mem_enc_feature_info = hv_print_mem_enc_feature_info;
x86_platform.hyper.is_private_mmio = hv_is_private_mmio;
x86_platform.guest.enc_cache_flush_required = hv_vtom_cache_flush_required;
x86_platform.guest.enc_tlb_flush_required = hv_vtom_tlb_flush_required;
diff --git a/arch/x86/include/asm/mem_encrypt.h b/arch/x86/include/asm/mem_encrypt.h
index 7f97a8a97e24..6e8050a9138e 100644
--- a/arch/x86/include/asm/mem_encrypt.h
+++ b/arch/x86/include/asm/mem_encrypt.h
@@ -19,6 +19,7 @@

#ifdef CONFIG_X86_MEM_ENCRYPT
void __init mem_encrypt_init(void);
+void print_mem_encrypt_feature_info(void);
#else
static inline void mem_encrypt_init(void) { }
#endif
diff --git a/arch/x86/include/asm/x86_init.h b/arch/x86/include/asm/x86_init.h
index 14b0562c1d8b..7798174d4b8d 100644
--- a/arch/x86/include/asm/x86_init.h
+++ b/arch/x86/include/asm/x86_init.h
@@ -291,6 +291,7 @@ struct x86_hyper_runtime {
* semantics.
* @realmode_reserve: reserve memory for realmode trampoline
* @realmode_init: initialize realmode trampoline
+ * @print_mem_enc_feature_info: print the supported memory encryption features
* @hyper: x86 hypervisor specific runtime callbacks
*/
struct x86_platform_ops {
@@ -309,6 +310,7 @@ struct x86_platform_ops {
void (*set_legacy_features)(void);
void (*realmode_reserve)(void);
void (*realmode_init)(void);
+ void (*print_mem_enc_feature_info)(void);
struct x86_hyper_runtime hyper;
struct x86_guest guest;
};
diff --git a/arch/x86/kernel/x86_init.c b/arch/x86/kernel/x86_init.c
index 6117662ae4e6..ccb53db1b51e 100644
--- a/arch/x86/kernel/x86_init.c
+++ b/arch/x86/kernel/x86_init.c
@@ -149,6 +149,7 @@ struct x86_platform_ops x86_platform __ro_after_init = {
.restore_sched_clock_state = tsc_restore_sched_clock_state,
.realmode_reserve = reserve_real_mode,
.realmode_init = init_real_mode,
+ .print_mem_enc_feature_info = print_mem_encrypt_feature_info,
.hyper.pin_vcpu = x86_op_int_noop,
.hyper.is_private_mmio = is_private_mmio_noop,

diff --git a/arch/x86/mm/mem_encrypt.c b/arch/x86/mm/mem_encrypt.c
index 9f27e14e185f..8d37048bc1df 100644
--- a/arch/x86/mm/mem_encrypt.c
+++ b/arch/x86/mm/mem_encrypt.c
@@ -39,7 +39,7 @@ bool force_dma_unencrypted(struct device *dev)
return false;
}

-static void print_mem_encrypt_feature_info(void)
+void print_mem_encrypt_feature_info(void)
{
pr_info("Memory Encryption Features active:");

@@ -84,5 +84,5 @@ void __init mem_encrypt_init(void)
/* Call into SWIOTLB to update the SWIOTLB DMA buffers */
swiotlb_update_mem_attributes();

- print_mem_encrypt_feature_info();
+ x86_platform.print_mem_enc_feature_info();
}
--
2.25.1