Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

mm: x86: Invoke hypercall when page encryption status is changed

Invoke a hypercall when a memory region is changed from encrypted ->
decrypted and vice versa. Hypervisor needs to know the page encryption
status during the guest migration.

Cc: Thomas Gleixner <tglx@linutronix.de>
Cc: Ingo Molnar <mingo@redhat.com>
Cc: "H. Peter Anvin" <hpa@zytor.com>
Cc: Paolo Bonzini <pbonzini@redhat.com>
Cc: Joerg Roedel <joro@8bytes.org>
Cc: Borislav Petkov <bp@suse.de>
Cc: Tom Lendacky <thomas.lendacky@amd.com>
Cc: x86@kernel.org
Cc: kvm@vger.kernel.org
Cc: linux-kernel@vger.kernel.org
Reviewed-by: Steve Rutherford <srutherford@google.com>
Reviewed-by: Venu Busireddy <venu.busireddy@oracle.com>
Signed-off-by: Brijesh Singh <brijesh.singh@amd.com>
Signed-off-by: Ashish Kalra <ashish.kalra@amd.com>
Reviewed-by: Borislav Petkov <bp@suse.de>
Message-Id: <0a237d5bb08793916c7790a3e653a2cbe7485761.1629726117.git.ashish.kalra@amd.com>
Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>

authored by

Brijesh Singh and committed by
Paolo Bonzini
064ce6c5 08c2336d

+80 -16
+6
arch/x86/include/asm/paravirt.h
··· 97 97 PVOP_VCALL1(mmu.exit_mmap, mm); 98 98 } 99 99 100 + static inline void notify_page_enc_status_changed(unsigned long pfn, 101 + int npages, bool enc) 102 + { 103 + PVOP_VCALL3(mmu.notify_page_enc_status_changed, pfn, npages, enc); 104 + } 105 + 100 106 #ifdef CONFIG_PARAVIRT_XXL 101 107 static inline void load_sp0(unsigned long sp0) 102 108 {
+1
arch/x86/include/asm/paravirt_types.h
··· 168 168 169 169 /* Hook for intercepting the destruction of an mm_struct. */ 170 170 void (*exit_mmap)(struct mm_struct *mm); 171 + void (*notify_page_enc_status_changed)(unsigned long pfn, int npages, bool enc); 171 172 172 173 #ifdef CONFIG_PARAVIRT_XXL 173 174 struct paravirt_callee_save read_cr2;
+1
arch/x86/include/asm/set_memory.h
··· 83 83 int set_direct_map_invalid_noflush(struct page *page); 84 84 int set_direct_map_default_noflush(struct page *page); 85 85 bool kernel_page_present(struct page *page); 86 + void notify_range_enc_status_changed(unsigned long vaddr, int npages, bool enc); 86 87 87 88 extern int kernel_set_to_readonly; 88 89
+1
arch/x86/kernel/paravirt.c
··· 296 296 (void (*)(struct mmu_gather *, void *))tlb_remove_page, 297 297 298 298 .mmu.exit_mmap = paravirt_nop, 299 + .mmu.notify_page_enc_status_changed = paravirt_nop, 299 300 300 301 #ifdef CONFIG_PARAVIRT_XXL 301 302 .mmu.read_cr2 = __PV_IS_CALLEE_SAVE(native_read_cr2),
+65 -16
arch/x86/mm/mem_encrypt.c
··· 228 228 swiotlb_adjust_size(size); 229 229 } 230 230 231 + static unsigned long pg_level_to_pfn(int level, pte_t *kpte, pgprot_t *ret_prot) 232 + { 233 + unsigned long pfn = 0; 234 + pgprot_t prot; 235 + 236 + switch (level) { 237 + case PG_LEVEL_4K: 238 + pfn = pte_pfn(*kpte); 239 + prot = pte_pgprot(*kpte); 240 + break; 241 + case PG_LEVEL_2M: 242 + pfn = pmd_pfn(*(pmd_t *)kpte); 243 + prot = pmd_pgprot(*(pmd_t *)kpte); 244 + break; 245 + case PG_LEVEL_1G: 246 + pfn = pud_pfn(*(pud_t *)kpte); 247 + prot = pud_pgprot(*(pud_t *)kpte); 248 + break; 249 + default: 250 + WARN_ONCE(1, "Invalid level for kpte\n"); 251 + return 0; 252 + } 253 + 254 + if (ret_prot) 255 + *ret_prot = prot; 256 + 257 + return pfn; 258 + } 259 + 260 + void notify_range_enc_status_changed(unsigned long vaddr, int npages, bool enc) 261 + { 262 + #ifdef CONFIG_PARAVIRT 263 + unsigned long sz = npages << PAGE_SHIFT; 264 + unsigned long vaddr_end = vaddr + sz; 265 + 266 + while (vaddr < vaddr_end) { 267 + int psize, pmask, level; 268 + unsigned long pfn; 269 + pte_t *kpte; 270 + 271 + kpte = lookup_address(vaddr, &level); 272 + if (!kpte || pte_none(*kpte)) { 273 + WARN_ONCE(1, "kpte lookup for vaddr\n"); 274 + return; 275 + } 276 + 277 + pfn = pg_level_to_pfn(level, kpte, NULL); 278 + if (!pfn) 279 + continue; 280 + 281 + psize = page_level_size(level); 282 + pmask = page_level_mask(level); 283 + 284 + notify_page_enc_status_changed(pfn, psize >> PAGE_SHIFT, enc); 285 + 286 + vaddr = (vaddr & pmask) + psize; 287 + } 288 + #endif 289 + } 290 + 231 291 static void __init __set_clr_pte_enc(pte_t *kpte, int level, bool enc) 232 292 { 233 293 pgprot_t old_prot, new_prot; 234 294 unsigned long pfn, pa, size; 235 295 pte_t new_pte; 236 296 237 - switch (level) { 238 - case PG_LEVEL_4K: 239 - pfn = pte_pfn(*kpte); 240 - old_prot = pte_pgprot(*kpte); 241 - break; 242 - case PG_LEVEL_2M: 243 - pfn = pmd_pfn(*(pmd_t *)kpte); 244 - old_prot = pmd_pgprot(*(pmd_t *)kpte); 245 - break; 246 - case PG_LEVEL_1G: 247 - pfn = pud_pfn(*(pud_t *)kpte); 248 - old_prot = pud_pgprot(*(pud_t *)kpte); 249 - break; 250 - default: 297 + pfn = pg_level_to_pfn(level, kpte, &old_prot); 298 + if (!pfn) 251 299 return; 252 - } 253 300 254 301 new_prot = old_prot; 255 302 if (enc) ··· 332 285 static int __init early_set_memory_enc_dec(unsigned long vaddr, 333 286 unsigned long size, bool enc) 334 287 { 335 - unsigned long vaddr_end, vaddr_next; 288 + unsigned long vaddr_end, vaddr_next, start; 336 289 unsigned long psize, pmask; 337 290 int split_page_size_mask; 338 291 int level, ret; 339 292 pte_t *kpte; 340 293 294 + start = vaddr; 341 295 vaddr_next = vaddr; 342 296 vaddr_end = vaddr + size; 343 297 ··· 393 345 394 346 ret = 0; 395 347 348 + notify_range_enc_status_changed(start, PAGE_ALIGN(size) >> PAGE_SHIFT, enc); 396 349 out: 397 350 __flush_tlb_all(); 398 351 return ret;
+6
arch/x86/mm/pat/set_memory.c
··· 2020 2020 */ 2021 2021 cpa_flush(&cpa, 0); 2022 2022 2023 + /* 2024 + * Notify hypervisor that a given memory range is mapped encrypted 2025 + * or decrypted. 2026 + */ 2027 + notify_range_enc_status_changed(addr, numpages, enc); 2028 + 2023 2029 return ret; 2024 2030 } 2025 2031