diff --git a/arch/x86/coco/sev/core.c b/arch/x86/coco/sev/core.c index 14ef5908fb2735..aba75d2aa4fc68 100644 --- a/arch/x86/coco/sev/core.c +++ b/arch/x86/coco/sev/core.c @@ -1425,6 +1425,34 @@ int snp_issue_svsm_attest_req(u64 call_id, struct svsm_call *call, } EXPORT_SYMBOL_GPL(snp_issue_svsm_attest_req); +void snp_issue_svsm_reboot_req(void) +{ + struct svsm_call call; + unsigned long flags; + + if (!snp_vmpl) + return; + + local_irq_save(flags); + + /* + * Set input registers for the request and set RDX and R8 to known + * values in order to detect length values being returned in them. + */ + call.caa = svsm_get_caa(); + call.rax = SVSM_REBOOT_CALL(SVSM_REBOOT_EXECUTE); + call.rcx = 0; + svsm_perform_call_protocol(&call); + /* + * If SVSM_REBOOT_EXECUTE is supported in the underlying SVSM, + * it will NOT return here. If it is not supported, return to + * the caller to try other reboot schemes. + */ + + local_irq_restore(flags); +} +EXPORT_SYMBOL_GPL(snp_issue_svsm_reboot_req); + static int snp_issue_guest_request(struct snp_guest_req *req) { struct snp_req_data *input = &req->input; diff --git a/arch/x86/include/asm/sev.h b/arch/x86/include/asm/sev.h index 465b19fd1a2db8..92d11056391c22 100644 --- a/arch/x86/include/asm/sev.h +++ b/arch/x86/include/asm/sev.h @@ -435,6 +435,9 @@ struct svsm_call { #define SVSM_VTPM_QUERY 0 #define SVSM_VTPM_CMD 1 +#define SVSM_REBOOT_CALL(x) ((5ULL << 32) | (x)) +#define SVSM_REBOOT_EXECUTE 0 + #ifdef CONFIG_AMD_MEM_ENCRYPT extern u8 snp_vmpl; @@ -523,6 +526,7 @@ int prepare_pte_enc(struct pte_enc_desc *d); void set_pte_enc_mask(pte_t *kpte, unsigned long pfn, pgprot_t new_prot); void snp_kexec_finish(void); void snp_kexec_begin(void); +void snp_issue_svsm_reboot_req(void); int snp_msg_init(struct snp_msg_desc *mdesc, int vmpck_id); struct snp_msg_desc *snp_msg_alloc(void); @@ -615,6 +619,7 @@ static inline int prepare_pte_enc(struct pte_enc_desc *d) { return 0; } static inline void set_pte_enc_mask(pte_t *kpte, unsigned long pfn, pgprot_t new_prot) { } static inline void snp_kexec_finish(void) { } static inline void snp_kexec_begin(void) { } +static inline void snp_issue_svsm_reboot_req(void) { } static inline int snp_msg_init(struct snp_msg_desc *mdesc, int vmpck_id) { return -1; } static inline struct snp_msg_desc *snp_msg_alloc(void) { return NULL; } static inline void snp_msg_free(struct snp_msg_desc *mdesc) { } diff --git a/arch/x86/kernel/reboot.c b/arch/x86/kernel/reboot.c index 964f6b0a3d68c3..8b106673b29e9c 100644 --- a/arch/x86/kernel/reboot.c +++ b/arch/x86/kernel/reboot.c @@ -26,6 +26,7 @@ #include #include #include +#include #include #include @@ -650,6 +651,15 @@ static void native_machine_emergency_restart(void) reboot_type = BOOT_EFI; } + /* + * If we're running under SVSM, try to reboot using SVSM. + */ + if (snp_vmpl) { + pr_emerg("Trying SVSM Reboot\n"); + snp_issue_svsm_reboot_req(); + pr_emerg("SVSM Reboot returned.\n"); + } + for (;;) { /* Could also try the reset bit in the Hammer NB */ switch (reboot_type) {