summaryrefslogtreecommitdiff
path: root/drivers/ptp/ptp_kvm_x86.c
diff options
context:
space:
mode:
authorJeremi Piotrowski <jpiotrowski@linux.microsoft.com>2023-03-08 18:05:31 +0300
committerJakub Kicinski <kuba@kernel.org>2023-03-18 07:57:52 +0300
commit6365ba64b4dbe8b59ddaeaa724b281f3787715d5 (patch)
tree22b37a8da0da4dcbb9ef3d98511d60c9f9ab3bcf /drivers/ptp/ptp_kvm_x86.c
parent1118aa4c70a6978afb0c4391ad29826c14b842b3 (diff)
downloadlinux-6365ba64b4dbe8b59ddaeaa724b281f3787715d5.tar.xz
ptp: kvm: Use decrypted memory in confidential guest on x86
KVM_HC_CLOCK_PAIRING currently fails inside SEV-SNP guests because the guest passes an address to static data to the host. In confidential computing the host can't access arbitrary guest memory so handling the hypercall runs into an "rmpfault". To make the hypercall work, the guest needs to explicitly mark the memory as decrypted. Do that in kvm_arch_ptp_init(), but retain the previous behavior for non-confidential guests to save us from having to allocate memory. Add a new arch-specific function (kvm_arch_ptp_exit()) to free the allocation and mark the memory as encrypted again. Signed-off-by: Jeremi Piotrowski <jpiotrowski@linux.microsoft.com> Link: https://lore.kernel.org/r/20230308150531.477741-1-jpiotrowski@linux.microsoft.com Signed-off-by: Jakub Kicinski <kuba@kernel.org>
Diffstat (limited to 'drivers/ptp/ptp_kvm_x86.c')
-rw-r--r--drivers/ptp/ptp_kvm_x86.c59
1 files changed, 48 insertions, 11 deletions
diff --git a/drivers/ptp/ptp_kvm_x86.c b/drivers/ptp/ptp_kvm_x86.c
index 4991054a2135..902844cc1a17 100644
--- a/drivers/ptp/ptp_kvm_x86.c
+++ b/drivers/ptp/ptp_kvm_x86.c
@@ -14,27 +14,64 @@
#include <uapi/linux/kvm_para.h>
#include <linux/ptp_clock_kernel.h>
#include <linux/ptp_kvm.h>
+#include <linux/set_memory.h>
static phys_addr_t clock_pair_gpa;
-static struct kvm_clock_pairing clock_pair;
+static struct kvm_clock_pairing clock_pair_glbl;
+static struct kvm_clock_pairing *clock_pair;
int kvm_arch_ptp_init(void)
{
+ struct page *p;
long ret;
if (!kvm_para_available())
return -ENODEV;
- clock_pair_gpa = slow_virt_to_phys(&clock_pair);
- if (!pvclock_get_pvti_cpu0_va())
- return -ENODEV;
+ if (cc_platform_has(CC_ATTR_GUEST_MEM_ENCRYPT)) {
+ p = alloc_page(GFP_KERNEL | __GFP_ZERO);
+ if (!p)
+ return -ENOMEM;
+
+ clock_pair = page_address(p);
+ ret = set_memory_decrypted((unsigned long)clock_pair, 1);
+ if (ret) {
+ __free_page(p);
+ clock_pair = NULL;
+ goto nofree;
+ }
+ } else {
+ clock_pair = &clock_pair_glbl;
+ }
+
+ clock_pair_gpa = slow_virt_to_phys(clock_pair);
+ if (!pvclock_get_pvti_cpu0_va()) {
+ ret = -ENODEV;
+ goto err;
+ }
ret = kvm_hypercall2(KVM_HC_CLOCK_PAIRING, clock_pair_gpa,
KVM_CLOCK_PAIRING_WALLCLOCK);
- if (ret == -KVM_ENOSYS)
- return -ENODEV;
+ if (ret == -KVM_ENOSYS) {
+ ret = -ENODEV;
+ goto err;
+ }
return ret;
+
+err:
+ kvm_arch_ptp_exit();
+nofree:
+ return ret;
+}
+
+void kvm_arch_ptp_exit(void)
+{
+ if (cc_platform_has(CC_ATTR_GUEST_MEM_ENCRYPT)) {
+ WARN_ON(set_memory_encrypted((unsigned long)clock_pair, 1));
+ free_page((unsigned long)clock_pair);
+ clock_pair = NULL;
+ }
}
int kvm_arch_ptp_get_clock(struct timespec64 *ts)
@@ -49,8 +86,8 @@ int kvm_arch_ptp_get_clock(struct timespec64 *ts)
return -EOPNOTSUPP;
}
- ts->tv_sec = clock_pair.sec;
- ts->tv_nsec = clock_pair.nsec;
+ ts->tv_sec = clock_pair->sec;
+ ts->tv_nsec = clock_pair->nsec;
return 0;
}
@@ -81,9 +118,9 @@ int kvm_arch_ptp_get_crosststamp(u64 *cycle, struct timespec64 *tspec,
pr_err_ratelimited("clock pairing hypercall ret %lu\n", ret);
return -EOPNOTSUPP;
}
- tspec->tv_sec = clock_pair.sec;
- tspec->tv_nsec = clock_pair.nsec;
- *cycle = __pvclock_read_cycles(src, clock_pair.tsc);
+ tspec->tv_sec = clock_pair->sec;
+ tspec->tv_nsec = clock_pair->nsec;
+ *cycle = __pvclock_read_cycles(src, clock_pair->tsc);
} while (pvclock_read_retry(src, version));
*cs = &kvm_clock;