Skip to content

Commit

Permalink
x86/sev: Perform PVALIDATE using the SVSM when not at VMPL0
Browse files Browse the repository at this point in the history
The PVALIDATE instruction can only be performed at VMPL0. If an SVSM is
present, it will be running at VMPL0 while the guest itself is then
running at VMPL1 or a lower privilege level.

In that case, use the SVSM_CORE_PVALIDATE call to perform memory
validation instead of issuing the PVALIDATE instruction directly.

The validation of a single 4K page is now explicitly identified as such
in the function name, pvalidate_4k_page(). The pvalidate_pages()
function is used for validating 1 or more pages at either 4K or 2M in
size. Each function, however, determines whether it can issue the
PVALIDATE directly or whether the SVSM needs to be invoked.

  [ bp: Touchups. ]
  [ Tom: fold in a fix for Coconut SVSM:
    https://lore.kernel.org/r/234bb23c-d295-76e5-a690-7ea68dc1118b@amd.com  ]

Signed-off-by: Tom Lendacky <thomas.lendacky@amd.com>
Signed-off-by: Borislav Petkov (AMD) <bp@alien8.de>
Link: https://lore.kernel.org/r/4c4017d8b94512d565de9ccb555b1a9f8983c69c.1717600736.git.thomas.lendacky@amd.com
  • Loading branch information
Tom Lendacky authored and Borislav Petkov (AMD) committed Jun 17, 2024
1 parent 34ff659 commit fcd042e
Show file tree
Hide file tree
Showing 4 changed files with 328 additions and 24 deletions.
46 changes: 42 additions & 4 deletions arch/x86/boot/compressed/sev.c
Original file line number Diff line number Diff line change
Expand Up @@ -129,6 +129,34 @@ static bool fault_in_kernel_space(unsigned long address)
/* Include code for early handlers */
#include "../../kernel/sev-shared.c"

static struct svsm_ca *svsm_get_caa(void)
{
return boot_svsm_caa;
}

static u64 svsm_get_caa_pa(void)
{
return boot_svsm_caa_pa;
}

static int svsm_perform_call_protocol(struct svsm_call *call)
{
struct ghcb *ghcb;
int ret;

if (boot_ghcb)
ghcb = boot_ghcb;
else
ghcb = NULL;

do {
ret = ghcb ? svsm_perform_ghcb_protocol(ghcb, call)
: svsm_perform_msr_protocol(call);
} while (ret == -EAGAIN);

return ret;
}

bool sev_snp_enabled(void)
{
return sev_status & MSR_AMD64_SEV_SNP_ENABLED;
Expand All @@ -145,8 +173,8 @@ static void __page_state_change(unsigned long paddr, enum psc_op op)
* If private -> shared then invalidate the page before requesting the
* state change in the RMP table.
*/
if (op == SNP_PAGE_STATE_SHARED && pvalidate(paddr, RMP_PG_SIZE_4K, 0))
sev_es_terminate(SEV_TERM_SET_LINUX, GHCB_TERM_PVALIDATE);
if (op == SNP_PAGE_STATE_SHARED)
pvalidate_4k_page(paddr, paddr, false);

/* Issue VMGEXIT to change the page state in RMP table. */
sev_es_wr_ghcb_msr(GHCB_MSR_PSC_REQ_GFN(paddr >> PAGE_SHIFT, op));
Expand All @@ -161,8 +189,8 @@ static void __page_state_change(unsigned long paddr, enum psc_op op)
* Now that page state is changed in the RMP table, validate it so that it is
* consistent with the RMP entry.
*/
if (op == SNP_PAGE_STATE_PRIVATE && pvalidate(paddr, RMP_PG_SIZE_4K, 1))
sev_es_terminate(SEV_TERM_SET_LINUX, GHCB_TERM_PVALIDATE);
if (op == SNP_PAGE_STATE_PRIVATE)
pvalidate_4k_page(paddr, paddr, true);
}

void snp_set_page_private(unsigned long paddr)
Expand Down Expand Up @@ -255,6 +283,16 @@ void sev_es_shutdown_ghcb(void)
if (!sev_es_check_cpu_features())
error("SEV-ES CPU Features missing.");

/*
* This denotes whether to use the GHCB MSR protocol or the GHCB
* shared page to perform a GHCB request. Since the GHCB page is
* being changed to encrypted, it can't be used to perform GHCB
* requests. Clear the boot_ghcb variable so that the GHCB MSR
* protocol is used to change the GHCB page over to an encrypted
* page.
*/
boot_ghcb = NULL;

/*
* GHCB Page must be flushed from the cache and mapped encrypted again.
* Otherwise the running kernel will see strange cache effects when
Expand Down
26 changes: 26 additions & 0 deletions arch/x86/include/asm/sev.h
Original file line number Diff line number Diff line change
Expand Up @@ -187,6 +187,31 @@ struct svsm_ca {
#define SVSM_ERR_INVALID_PARAMETER 0x80000005
#define SVSM_ERR_INVALID_REQUEST 0x80000006
#define SVSM_ERR_BUSY 0x80000007
#define SVSM_PVALIDATE_FAIL_SIZEMISMATCH 0x80001006

/*
* The SVSM PVALIDATE related structures
*/
struct svsm_pvalidate_entry {
u64 page_size : 2,
action : 1,
ignore_cf : 1,
rsvd : 8,
pfn : 52;
};

struct svsm_pvalidate_call {
u16 num_entries;
u16 cur_index;

u8 rsvd1[4];

struct svsm_pvalidate_entry entry[];
};

#define SVSM_PVALIDATE_MAX_COUNT ((sizeof_field(struct svsm_ca, svsm_buffer) - \
offsetof(struct svsm_pvalidate_call, entry)) / \
sizeof(struct svsm_pvalidate_entry))

/*
* SVSM protocol structure
Expand All @@ -207,6 +232,7 @@ struct svsm_call {

#define SVSM_CORE_CALL(x) ((0ULL << 32) | (x))
#define SVSM_CORE_REMAP_CA 0
#define SVSM_CORE_PVALIDATE 1

#ifdef CONFIG_AMD_MEM_ENCRYPT
extern void __sev_es_ist_enter(struct pt_regs *regs);
Expand Down
Loading

0 comments on commit fcd042e

Please sign in to comment.