Skip to content

Commit f366a8d

Browse files
ashkalrabp3tk0v
authored andcommitted
iommu/amd: Clean up RMP entries for IOMMU pages during SNP shutdown
Add a new IOMMU API interface amd_iommu_snp_disable() to transition IOMMU pages to Hypervisor state from Reclaim state after SNP_SHUTDOWN_EX command. Invoke this API from the CCP driver after SNP_SHUTDOWN_EX command. Signed-off-by: Ashish Kalra <[email protected]> Signed-off-by: Michael Roth <[email protected]> Signed-off-by: Borislav Petkov (AMD) <[email protected]> Link: https://lore.kernel.org/r/[email protected]
1 parent a867ad6 commit f366a8d

File tree

3 files changed

+105
-0
lines changed

3 files changed

+105
-0
lines changed

drivers/crypto/ccp/sev-dev.c

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,7 @@
2626
#include <linux/fs.h>
2727
#include <linux/fs_struct.h>
2828
#include <linux/psp.h>
29+
#include <linux/amd-iommu.h>
2930

3031
#include <asm/smp.h>
3132
#include <asm/cacheflush.h>
@@ -1655,6 +1656,25 @@ static int __sev_snp_shutdown_locked(int *error)
16551656
return ret;
16561657
}
16571658

1659+
/*
1660+
* SNP_SHUTDOWN_EX with IOMMU_SNP_SHUTDOWN set to 1 disables SNP
1661+
* enforcement by the IOMMU and also transitions all pages
1662+
* associated with the IOMMU to the Reclaim state.
1663+
* Firmware was transitioning the IOMMU pages to Hypervisor state
1664+
* before version 1.53. But, accounting for the number of assigned
1665+
* 4kB pages in a 2M page was done incorrectly by not transitioning
1666+
* to the Reclaim state. This resulted in RMP #PF when later accessing
1667+
* the 2M page containing those pages during kexec boot. Hence, the
1668+
* firmware now transitions these pages to Reclaim state and hypervisor
1669+
* needs to transition these pages to shared state. SNP Firmware
1670+
* version 1.53 and above are needed for kexec boot.
1671+
*/
1672+
ret = amd_iommu_snp_disable();
1673+
if (ret) {
1674+
dev_err(sev->dev, "SNP IOMMU shutdown failed\n");
1675+
return ret;
1676+
}
1677+
16581678
sev->snp_initialized = false;
16591679
dev_dbg(sev->dev, "SEV-SNP firmware shutdown\n");
16601680

drivers/iommu/amd/init.c

Lines changed: 79 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,7 @@
3030
#include <asm/io_apic.h>
3131
#include <asm/irq_remapping.h>
3232
#include <asm/set_memory.h>
33+
#include <asm/sev.h>
3334

3435
#include <linux/crash_dump.h>
3536

@@ -3797,3 +3798,81 @@ int amd_iommu_pc_set_reg(struct amd_iommu *iommu, u8 bank, u8 cntr, u8 fxn, u64
37973798

37983799
return iommu_pc_get_set_reg(iommu, bank, cntr, fxn, value, true);
37993800
}
3801+
3802+
#ifdef CONFIG_KVM_AMD_SEV
3803+
static int iommu_page_make_shared(void *page)
3804+
{
3805+
unsigned long paddr, pfn;
3806+
3807+
paddr = iommu_virt_to_phys(page);
3808+
/* Cbit maybe set in the paddr */
3809+
pfn = __sme_clr(paddr) >> PAGE_SHIFT;
3810+
3811+
if (!(pfn % PTRS_PER_PMD)) {
3812+
int ret, level;
3813+
bool assigned;
3814+
3815+
ret = snp_lookup_rmpentry(pfn, &assigned, &level);
3816+
if (ret)
3817+
pr_warn("IOMMU PFN %lx RMP lookup failed, ret %d\n",
3818+
pfn, ret);
3819+
3820+
if (!assigned)
3821+
pr_warn("IOMMU PFN %lx not assigned in RMP table\n",
3822+
pfn);
3823+
3824+
if (level > PG_LEVEL_4K) {
3825+
ret = psmash(pfn);
3826+
if (ret) {
3827+
pr_warn("IOMMU PFN %lx had a huge RMP entry, but attempted psmash failed, ret: %d, level: %d\n",
3828+
pfn, ret, level);
3829+
}
3830+
}
3831+
}
3832+
3833+
return rmp_make_shared(pfn, PG_LEVEL_4K);
3834+
}
3835+
3836+
static int iommu_make_shared(void *va, size_t size)
3837+
{
3838+
void *page;
3839+
int ret;
3840+
3841+
if (!va)
3842+
return 0;
3843+
3844+
for (page = va; page < (va + size); page += PAGE_SIZE) {
3845+
ret = iommu_page_make_shared(page);
3846+
if (ret)
3847+
return ret;
3848+
}
3849+
3850+
return 0;
3851+
}
3852+
3853+
int amd_iommu_snp_disable(void)
3854+
{
3855+
struct amd_iommu *iommu;
3856+
int ret;
3857+
3858+
if (!amd_iommu_snp_en)
3859+
return 0;
3860+
3861+
for_each_iommu(iommu) {
3862+
ret = iommu_make_shared(iommu->evt_buf, EVT_BUFFER_SIZE);
3863+
if (ret)
3864+
return ret;
3865+
3866+
ret = iommu_make_shared(iommu->ppr_log, PPR_LOG_SIZE);
3867+
if (ret)
3868+
return ret;
3869+
3870+
ret = iommu_make_shared((void *)iommu->cmd_sem, PAGE_SIZE);
3871+
if (ret)
3872+
return ret;
3873+
}
3874+
3875+
return 0;
3876+
}
3877+
EXPORT_SYMBOL_GPL(amd_iommu_snp_disable);
3878+
#endif

include/linux/amd-iommu.h

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -85,4 +85,10 @@ int amd_iommu_pc_get_reg(struct amd_iommu *iommu, u8 bank, u8 cntr, u8 fxn,
8585
u64 *value);
8686
struct amd_iommu *get_amd_iommu(unsigned int idx);
8787

88+
#ifdef CONFIG_KVM_AMD_SEV
89+
int amd_iommu_snp_disable(void);
90+
#else
91+
static inline int amd_iommu_snp_disable(void) { return 0; }
92+
#endif
93+
8894
#endif /* _ASM_X86_AMD_IOMMU_H */

0 commit comments

Comments
 (0)