The snp_lookup_page_in_rmptable() can be used by the host to read the RMP entry for a given page. The RMP entry format is documented in AMD PPR, see https://bugzilla.kernel.org/attachment.cgi?id=296015. Signed-off-by: Brijesh Singh <brijesh.singh@xxxxxxx> --- arch/x86/include/asm/sev.h | 5 +--- arch/x86/kernel/sev.c | 28 ++++++++++++++++++++ include/linux/sev.h | 54 ++++++++++++++++++++++++++++++++++++++ 3 files changed, 83 insertions(+), 4 deletions(-) create mode 100644 include/linux/sev.h diff --git a/arch/x86/include/asm/sev.h b/arch/x86/include/asm/sev.h index 7f4c34dd84e1..a65e78fa3d51 100644 --- a/arch/x86/include/asm/sev.h +++ b/arch/x86/include/asm/sev.h @@ -9,6 +9,7 @@ #define __ASM_ENCRYPTED_STATE_H #include <linux/types.h> +#include <linux/sev.h> #include <asm/insn.h> #include <asm/sev-common.h> @@ -65,10 +66,6 @@ extern bool handle_vc_boot_ghcb(struct pt_regs *regs); #define PVALIDATE_FAIL_SIZEMISMATCH 6 #define PVALIDATE_FAIL_NOUPDATE 255 /* Software defined (when rFlags.CF = 1) */ -/* RMP page size */ -#define RMP_PG_SIZE_2M 1 -#define RMP_PG_SIZE_4K 0 - #ifdef CONFIG_AMD_MEM_ENCRYPT extern struct static_key_false sev_es_enable_key; extern void __sev_es_ist_enter(struct pt_regs *regs); diff --git a/arch/x86/kernel/sev.c b/arch/x86/kernel/sev.c index 126fa441c0f8..dec4f423e232 100644 --- a/arch/x86/kernel/sev.c +++ b/arch/x86/kernel/sev.c @@ -40,6 +40,10 @@ #define DR7_RESET_VALUE 0x400 +#define RMPTABLE_ENTRIES_OFFSET 0x4000 +#define RMPENTRY_SHIFT 8 +#define rmptable_page_offset(x) (RMPTABLE_ENTRIES_OFFSET + (((unsigned long)x) >> RMPENTRY_SHIFT)) + /* For early boot hypervisor communication in SEV-ES enabled guests */ static struct ghcb boot_ghcb_page __bss_decrypted __aligned(PAGE_SIZE); @@ -1873,3 +1877,27 @@ static int __init snp_rmptable_init(void) return 0; } early_initcall(snp_rmptable_init); + +struct rmpentry *snp_lookup_page_in_rmptable(struct page *page, int *level) +{ + unsigned long phys = page_to_pfn(page) << PAGE_SHIFT; + struct rmpentry *entry, *large_entry; + unsigned long vaddr; + + if (!cpu_feature_enabled(X86_FEATURE_SEV_SNP)) + return NULL; + + vaddr = rmptable_start + rmptable_page_offset(phys); + if (unlikely(vaddr > rmptable_end)) + return NULL; + + entry = (struct rmpentry *)vaddr; + + /* Read a large RMP entry to get the correct page level used in RMP entry. */ + vaddr = rmptable_start + rmptable_page_offset(phys & PMD_MASK); + large_entry = (struct rmpentry *)vaddr; + *level = RMP_TO_X86_PG_LEVEL(rmpentry_pagesize(large_entry)); + + return entry; +} +EXPORT_SYMBOL_GPL(snp_lookup_page_in_rmptable); diff --git a/include/linux/sev.h b/include/linux/sev.h new file mode 100644 index 000000000000..ee038d466786 --- /dev/null +++ b/include/linux/sev.h @@ -0,0 +1,54 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* + * AMD Secure Encrypted Virtualization + * + * Author: Brijesh Singh <brijesh.singh@xxxxxxx> + */ + +#ifndef __LINUX_SEV_H +#define __LINUX_SEV_H + +struct __packed rmpentry { + union { + struct { + u64 assigned:1; + u64 pagesize:1; + u64 immutable:1; + u64 rsvd1:9; + u64 gpa:39; + u64 asid:10; + u64 vmsa:1; + u64 validated:1; + u64 rsvd2:1; + } info; + u64 low; + }; + u64 high; +}; + +#define rmpentry_assigned(x) ((x)->info.assigned) +#define rmpentry_pagesize(x) ((x)->info.pagesize) +#define rmpentry_vmsa(x) ((x)->info.vmsa) +#define rmpentry_asid(x) ((x)->info.asid) +#define rmpentry_validated(x) ((x)->info.validated) +#define rmpentry_gpa(x) ((unsigned long)(x)->info.gpa) +#define rmpentry_immutable(x) ((x)->info.immutable) + +/* RMP page size */ +#define RMP_PG_SIZE_2M 1 +#define RMP_PG_SIZE_4K 0 + +/* Macro to convert the x86 page level to the RMP level and vice versa */ +#define X86_TO_RMP_PG_LEVEL(level) (((level) == PG_LEVEL_4K) ? RMP_PG_SIZE_4K : RMP_PG_SIZE_2M) +#define RMP_TO_X86_PG_LEVEL(level) (((level) == RMP_PG_SIZE_4K) ? PG_LEVEL_4K : PG_LEVEL_2M) + +#ifdef CONFIG_AMD_MEM_ENCRYPT +struct rmpentry *snp_lookup_page_in_rmptable(struct page *page, int *level); +#else +static inline struct rmpentry *snp_lookup_page_in_rmptable(struct page *page, int *level) +{ + return NULL; +} + +#endif /* CONFIG_AMD_MEM_ENCRYPT */ +#endif /* __LINUX_SEV_H */ -- 2.17.1