Message ID | 20231016132819.1002933-13-michael.roth@amd.com (mailing list archive) |
---|---|
State | New, archived |
Headers | show |
Series | Add AMD Secure Nested Paging (SEV-SNP) Hypervisor Support | expand |
On Mon, Oct 16, 2023 at 08:27:41AM -0500, Michael Roth wrote: > From: Brijesh Singh <brijesh.singh@amd.com> > > The integrity guarantee of SEV-SNP is enforced through the RMP table. > The RMP is used with standard x86 and IOMMU page tables to enforce > memory restrictions and page access rights. The RMP check is enforced as > soon as SEV-SNP is enabled globally in the system. When hardware > encounters an RMP-check failure, it raises a page-fault exception. > > The rmp_make_private() and rmp_make_shared() helpers are used to add > or remove the pages from the RMP table. Improve the rmp_make_private() > to invalidate state so that pages cannot be used in the direct-map after > they are added the RMP table, and restored to their default valid > permission after the pages are removed from the RMP table. Brijesh's SOB comes <--- here, then Ashish's two tags. Please audit your whole set for such inconsistencies. > @@ -404,6 +440,21 @@ static int rmpupdate(u64 pfn, struct rmp_state *val) > if (!cpu_feature_enabled(X86_FEATURE_SEV_SNP)) > return -ENXIO; > > + level = RMP_TO_X86_PG_LEVEL(val->pagesize); > + npages = page_level_size(level) / PAGE_SIZE; > + > + /* > + * If page is getting assigned in the RMP table then unmap it from the > + * direct map. Here I'm missing the explanation *why* the pages need to be unmapped from the direct map. What happens if not? > + */ > + if (val->assigned) { > + if (invalidate_direct_map(pfn, npages)) { > + pr_err("Failed to unmap %d pages at pfn 0x%llx from the direct_map\n", > + npages, pfn); invalidate_direct_map() already dumps an error message - no need to do that here too. > + return -EFAULT; > + } > + } > + > do { > /* Binutils version 2.36 supports the RMPUPDATE mnemonic. */ > asm volatile(".byte 0xF2, 0x0F, 0x01, 0xFE" > @@ -422,6 +473,17 @@ static int rmpupdate(u64 pfn, struct rmp_state *val) > return -EFAULT; > } > > + /* > + * Restore the direct map after the page is removed from the RMP table. > + */ > + if (!val->assigned) { > + if (restore_direct_map(pfn, npages)) { > + pr_err("Failed to map %d pages at pfn 0x%llx into the direct_map\n", > + npages, pfn); Ditto.
diff --git a/arch/x86/virt/svm/sev.c b/arch/x86/virt/svm/sev.c index 24a695af13a5..bf9b97046e05 100644 --- a/arch/x86/virt/svm/sev.c +++ b/arch/x86/virt/svm/sev.c @@ -395,6 +395,42 @@ int psmash(u64 pfn) } EXPORT_SYMBOL_GPL(psmash); +static int restore_direct_map(u64 pfn, int npages) +{ + int i, ret = 0; + + for (i = 0; i < npages; i++) { + ret = set_direct_map_default_noflush(pfn_to_page(pfn + i)); + if (ret) + break; + } + + if (ret) + pr_warn("Failed to restore direct map for pfn 0x%llx, ret: %d\n", + pfn + i, ret); + + return ret; +} + +static int invalidate_direct_map(u64 pfn, int npages) +{ + int i, ret = 0; + + for (i = 0; i < npages; i++) { + ret = set_direct_map_invalid_noflush(pfn_to_page(pfn + i)); + if (ret) + break; + } + + if (ret) { + pr_warn("Failed to invalidate direct map for pfn 0x%llx, ret: %d\n", + pfn + i, ret); + restore_direct_map(pfn, i); + } + + return ret; +} + static int rmpupdate(u64 pfn, struct rmp_state *val) { unsigned long paddr = pfn << PAGE_SHIFT; @@ -404,6 +440,21 @@ static int rmpupdate(u64 pfn, struct rmp_state *val) if (!cpu_feature_enabled(X86_FEATURE_SEV_SNP)) return -ENXIO; + level = RMP_TO_X86_PG_LEVEL(val->pagesize); + npages = page_level_size(level) / PAGE_SIZE; + + /* + * If page is getting assigned in the RMP table then unmap it from the + * direct map. + */ + if (val->assigned) { + if (invalidate_direct_map(pfn, npages)) { + pr_err("Failed to unmap %d pages at pfn 0x%llx from the direct_map\n", + npages, pfn); + return -EFAULT; + } + } + do { /* Binutils version 2.36 supports the RMPUPDATE mnemonic. */ asm volatile(".byte 0xF2, 0x0F, 0x01, 0xFE" @@ -422,6 +473,17 @@ static int rmpupdate(u64 pfn, struct rmp_state *val) return -EFAULT; } + /* + * Restore the direct map after the page is removed from the RMP table. + */ + if (!val->assigned) { + if (restore_direct_map(pfn, npages)) { + pr_err("Failed to map %d pages at pfn 0x%llx into the direct_map\n", + npages, pfn); + return -EFAULT; + } + } + return 0; }