| 1 | /* SPDX-License-Identifier: GPL-2.0 */ |
| 2 | |
| 3 | #define DR7_RESET_VALUE 0x400 |
| 4 | |
| 5 | extern u64 sev_hv_features; |
| 6 | extern u64 sev_secrets_pa; |
| 7 | |
| 8 | /* #VC handler runtime per-CPU data */ |
| 9 | struct sev_es_runtime_data { |
| 10 | struct ghcb ghcb_page; |
| 11 | |
| 12 | /* |
| 13 | * Reserve one page per CPU as backup storage for the unencrypted GHCB. |
| 14 | * It is needed when an NMI happens while the #VC handler uses the real |
| 15 | * GHCB, and the NMI handler itself is causing another #VC exception. In |
| 16 | * that case the GHCB content of the first handler needs to be backed up |
| 17 | * and restored. |
| 18 | */ |
| 19 | struct ghcb backup_ghcb; |
| 20 | |
| 21 | /* |
| 22 | * Mark the per-cpu GHCBs as in-use to detect nested #VC exceptions. |
| 23 | * There is no need for it to be atomic, because nothing is written to |
| 24 | * the GHCB between the read and the write of ghcb_active. So it is safe |
| 25 | * to use it when a nested #VC exception happens before the write. |
| 26 | * |
| 27 | * This is necessary for example in the #VC->NMI->#VC case when the NMI |
| 28 | * happens while the first #VC handler uses the GHCB. When the NMI code |
| 29 | * raises a second #VC handler it might overwrite the contents of the |
| 30 | * GHCB written by the first handler. To avoid this the content of the |
| 31 | * GHCB is saved and restored when the GHCB is detected to be in use |
| 32 | * already. |
| 33 | */ |
| 34 | bool ghcb_active; |
| 35 | bool backup_ghcb_active; |
| 36 | |
| 37 | /* |
| 38 | * Cached DR7 value - write it on DR7 writes and return it on reads. |
| 39 | * That value will never make it to the real hardware DR7 as debugging |
| 40 | * is currently unsupported in SEV-ES guests. |
| 41 | */ |
| 42 | unsigned long dr7; |
| 43 | }; |
| 44 | |
| 45 | struct ghcb_state { |
| 46 | struct ghcb *ghcb; |
| 47 | }; |
| 48 | |
| 49 | extern struct svsm_ca boot_svsm_ca_page; |
| 50 | |
| 51 | struct ghcb *__sev_get_ghcb(struct ghcb_state *state); |
| 52 | void __sev_put_ghcb(struct ghcb_state *state); |
| 53 | |
| 54 | DECLARE_PER_CPU(struct sev_es_runtime_data*, runtime_data); |
| 55 | DECLARE_PER_CPU(struct sev_es_save_area *, sev_vmsa); |
| 56 | |
| 57 | void early_set_pages_state(unsigned long vaddr, unsigned long paddr, |
| 58 | unsigned long npages, const struct psc_desc *desc); |
| 59 | |
| 60 | DECLARE_PER_CPU(struct svsm_ca *, svsm_caa); |
| 61 | DECLARE_PER_CPU(u64, svsm_caa_pa); |
| 62 | |
| 63 | extern u64 boot_svsm_caa_pa; |
| 64 | |
| 65 | enum es_result verify_exception_info(struct ghcb *ghcb, struct es_em_ctxt *ctxt); |
| 66 | void vc_forward_exception(struct es_em_ctxt *ctxt); |
| 67 | |
| 68 | static inline u64 sev_es_rd_ghcb_msr(void) |
| 69 | { |
| 70 | return native_rdmsrq(MSR_AMD64_SEV_ES_GHCB); |
| 71 | } |
| 72 | |
| 73 | static __always_inline void sev_es_wr_ghcb_msr(u64 val) |
| 74 | { |
| 75 | u32 low, high; |
| 76 | |
| 77 | low = (u32)(val); |
| 78 | high = (u32)(val >> 32); |
| 79 | |
| 80 | native_wrmsr(MSR_AMD64_SEV_ES_GHCB, low, high); |
| 81 | } |
| 82 | |
| 83 | enum es_result sev_es_ghcb_handle_msr(struct ghcb *ghcb, struct es_em_ctxt *ctxt, bool write); |
| 84 | |
| 85 | u64 get_hv_features(void); |
| 86 | |
| 87 | const struct snp_cpuid_table *snp_cpuid_get_table(void); |
| 88 | |