mirror of
https://git.proxmox.com/git/mirror_ubuntu-kernels.git
synced 2025-11-15 22:43:55 +00:00
Hyper-V guests on AMD SEV-SNP hardware have the option of using the "virtual Top Of Memory" (vTOM) feature specified by the SEV-SNP architecture. With vTOM, shared vs. private memory accesses are controlled by splitting the guest physical address space into two halves. vTOM is the dividing line where the uppermost bit of the physical address space is set; e.g., with 47 bits of guest physical address space, vTOM is 0x400000000000 (bit 46 is set). Guest physical memory is accessible at two parallel physical addresses -- one below vTOM and one above vTOM. Accesses below vTOM are private (encrypted) while accesses above vTOM are shared (decrypted). In this sense, vTOM is like the GPA.SHARED bit in Intel TDX. Support for Hyper-V guests using vTOM was added to the Linux kernel in two patch sets[1][2]. This support treats the vTOM bit as part of the physical address. For accessing shared (decrypted) memory, these patch sets create a second kernel virtual mapping that maps to physical addresses above vTOM. A better approach is to treat the vTOM bit as a protection flag, not as part of the physical address. This new approach is like the approach for the GPA.SHARED bit in Intel TDX. Rather than creating a second kernel virtual mapping, the existing mapping is updated using recently added coco mechanisms. When memory is changed between private and shared using set_memory_decrypted() and set_memory_encrypted(), the PTEs for the existing kernel mapping are changed to add or remove the vTOM bit in the guest physical address, just as with TDX. The hypercalls to change the memory status on the host side are made using the existing callback mechanism. Everything just works, with a minor tweak to map the IO-APIC to use private accesses. To accomplish the switch in approach, the following must be done: * Update Hyper-V initialization to set the cc_mask based on vTOM and do other coco initialization. * Update physical_mask so the vTOM bit is no longer treated as part of the physical address * Remove CC_VENDOR_HYPERV and merge the associated vTOM functionality under CC_VENDOR_AMD. Update cc_mkenc() and cc_mkdec() to set/clear the vTOM bit as a protection flag. * Code already exists to make hypercalls to inform Hyper-V about pages changing between shared and private. Update this code to run as a callback from __set_memory_enc_pgtable(). * Remove the Hyper-V special case from __set_memory_enc_dec() * Remove the Hyper-V specific call to swiotlb_update_mem_attributes() since mem_encrypt_init() will now do it. * Add a Hyper-V specific implementation of the is_private_mmio() callback that returns true for the IO-APIC and vTPM MMIO addresses [1] https://lore.kernel.org/all/20211025122116.264793-1-ltykernel@gmail.com/ [2] https://lore.kernel.org/all/20211213071407.314309-1-ltykernel@gmail.com/ [ bp: Touchups. ] Signed-off-by: Michael Kelley <mikelley@microsoft.com> Signed-off-by: Borislav Petkov (AMD) <bp@alien8.de> Link: https://lore.kernel.org/r/1679838727-87310-7-git-send-email-mikelley@microsoft.com
114 lines
3.3 KiB
C
114 lines
3.3 KiB
C
/* SPDX-License-Identifier: GPL-2.0-only */
|
|
/*
|
|
* AMD Memory Encryption Support
|
|
*
|
|
* Copyright (C) 2016 Advanced Micro Devices, Inc.
|
|
*
|
|
* Author: Tom Lendacky <thomas.lendacky@amd.com>
|
|
*/
|
|
|
|
#ifndef __X86_MEM_ENCRYPT_H__
|
|
#define __X86_MEM_ENCRYPT_H__
|
|
|
|
#ifndef __ASSEMBLY__
|
|
|
|
#include <linux/init.h>
|
|
#include <linux/cc_platform.h>
|
|
|
|
#include <asm/bootparam.h>
|
|
|
|
#ifdef CONFIG_AMD_MEM_ENCRYPT
|
|
|
|
extern u64 sme_me_mask;
|
|
extern u64 sev_status;
|
|
|
|
void sme_encrypt_execute(unsigned long encrypted_kernel_vaddr,
|
|
unsigned long decrypted_kernel_vaddr,
|
|
unsigned long kernel_len,
|
|
unsigned long encryption_wa,
|
|
unsigned long encryption_pgd);
|
|
|
|
void __init sme_early_encrypt(resource_size_t paddr,
|
|
unsigned long size);
|
|
void __init sme_early_decrypt(resource_size_t paddr,
|
|
unsigned long size);
|
|
|
|
void __init sme_map_bootdata(char *real_mode_data);
|
|
void __init sme_unmap_bootdata(char *real_mode_data);
|
|
|
|
void __init sme_early_init(void);
|
|
void __init sev_setup_arch(void);
|
|
|
|
void __init sme_encrypt_kernel(struct boot_params *bp);
|
|
void __init sme_enable(struct boot_params *bp);
|
|
|
|
int __init early_set_memory_decrypted(unsigned long vaddr, unsigned long size);
|
|
int __init early_set_memory_encrypted(unsigned long vaddr, unsigned long size);
|
|
void __init early_set_mem_enc_dec_hypercall(unsigned long vaddr, int npages,
|
|
bool enc);
|
|
|
|
void __init mem_encrypt_free_decrypted_mem(void);
|
|
|
|
void __init sev_es_init_vc_handling(void);
|
|
|
|
#define __bss_decrypted __section(".bss..decrypted")
|
|
|
|
#else /* !CONFIG_AMD_MEM_ENCRYPT */
|
|
|
|
#define sme_me_mask 0ULL
|
|
#define sev_status 0ULL
|
|
|
|
static inline void __init sme_early_encrypt(resource_size_t paddr,
|
|
unsigned long size) { }
|
|
static inline void __init sme_early_decrypt(resource_size_t paddr,
|
|
unsigned long size) { }
|
|
|
|
static inline void __init sme_map_bootdata(char *real_mode_data) { }
|
|
static inline void __init sme_unmap_bootdata(char *real_mode_data) { }
|
|
|
|
static inline void __init sme_early_init(void) { }
|
|
static inline void __init sev_setup_arch(void) { }
|
|
|
|
static inline void __init sme_encrypt_kernel(struct boot_params *bp) { }
|
|
static inline void __init sme_enable(struct boot_params *bp) { }
|
|
|
|
static inline void sev_es_init_vc_handling(void) { }
|
|
|
|
static inline int __init
|
|
early_set_memory_decrypted(unsigned long vaddr, unsigned long size) { return 0; }
|
|
static inline int __init
|
|
early_set_memory_encrypted(unsigned long vaddr, unsigned long size) { return 0; }
|
|
static inline void __init
|
|
early_set_mem_enc_dec_hypercall(unsigned long vaddr, int npages, bool enc) {}
|
|
|
|
static inline void mem_encrypt_free_decrypted_mem(void) { }
|
|
|
|
#define __bss_decrypted
|
|
|
|
#endif /* CONFIG_AMD_MEM_ENCRYPT */
|
|
|
|
/* Architecture __weak replacement functions */
|
|
void __init mem_encrypt_init(void);
|
|
|
|
void add_encrypt_protection_map(void);
|
|
|
|
/*
|
|
* The __sme_pa() and __sme_pa_nodebug() macros are meant for use when
|
|
* writing to or comparing values from the cr3 register. Having the
|
|
* encryption mask set in cr3 enables the PGD entry to be encrypted and
|
|
* avoid special case handling of PGD allocations.
|
|
*/
|
|
#define __sme_pa(x) (__pa(x) | sme_me_mask)
|
|
#define __sme_pa_nodebug(x) (__pa_nodebug(x) | sme_me_mask)
|
|
|
|
extern char __start_bss_decrypted[], __end_bss_decrypted[], __start_bss_decrypted_unused[];
|
|
|
|
static inline u64 sme_get_me_mask(void)
|
|
{
|
|
return sme_me_mask;
|
|
}
|
|
|
|
#endif /* __ASSEMBLY__ */
|
|
|
|
#endif /* __X86_MEM_ENCRYPT_H__ */
|