When a TDX guest runs on Hyper-V, the hv_netvsc driver's netvsc_init_buf() allocates buffers using vzalloc(), and needs to share the buffers with the host OS by calling set_memory_decrypted(), which is not working for vmalloc() yet. Add the support by handling the pages one by one. Signed-off-by: Dexuan Cui <decui@xxxxxxxxxxxxx> --- arch/x86/coco/tdx/tdx.c | 45 ++++++++++++++++++++++++++++++++++++++++- 1 file changed, 44 insertions(+), 1 deletion(-) diff --git a/arch/x86/coco/tdx/tdx.c b/arch/x86/coco/tdx/tdx.c index 46971cc7d006..8bccae962b6d 100644 --- a/arch/x86/coco/tdx/tdx.c +++ b/arch/x86/coco/tdx/tdx.c @@ -5,6 +5,7 @@ #define pr_fmt(fmt) "tdx: " fmt #include <linux/cpufeature.h> +#include <linux/mm.h> #include <asm/coco.h> #include <asm/tdx.h> #include <asm/vmx.h> @@ -754,7 +755,8 @@ static bool tdx_map_gpa(phys_addr_t start, phys_addr_t end, bool enc) * the VMM or private to the guest. The VMM is expected to change its mapping * of the page in response. */ -static bool tdx_enc_status_changed(unsigned long vaddr, int numpages, bool enc) +static bool tdx_enc_status_changed_for_contiguous_pages(unsigned long vaddr, + int numpages, bool enc) { phys_addr_t start = __pa(vaddr); phys_addr_t end = __pa(vaddr + numpages * PAGE_SIZE); @@ -798,6 +800,47 @@ static bool tdx_enc_status_changed(unsigned long vaddr, int numpages, bool enc) return true; } +static bool tdx_enc_status_changed_for_vmalloc(unsigned long vaddr, + int numpages, bool enc) +{ + void *start_va = (void *)vaddr; + void *end_va = start_va + numpages * PAGE_SIZE; + phys_addr_t pa; + + if (offset_in_page(vaddr) != 0) + return false; + + while (start_va < end_va) { + pa = slow_virt_to_phys(start_va); + if (!enc) + pa |= cc_mkdec(0); + + if (!tdx_map_gpa(pa, pa + PAGE_SIZE, enc)) + return false; + + /* + * private->shared conversion requires only MapGPA call. + * + * For shared->private conversion, accept the page using + * TDX_ACCEPT_PAGE TDX module call. + */ + if (enc && !try_accept_one(&pa, PAGE_SIZE, PG_LEVEL_4K)) + return false; + + start_va += PAGE_SIZE; + } + + return true; +} + +static bool tdx_enc_status_changed(unsigned long vaddr, int numpages, bool enc) +{ + if (is_vmalloc_addr((void *)vaddr)) + return tdx_enc_status_changed_for_vmalloc(vaddr, numpages, enc); + + return tdx_enc_status_changed_for_contiguous_pages(vaddr, numpages, enc); +} + void __init tdx_early_init(void) { u64 cc_mask; -- 2.25.1