Commit 6365ba64 authored by Jeremi Piotrowski's avatar Jeremi Piotrowski Committed by Jakub Kicinski

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: default avatarJeremi Piotrowski <jpiotrowski@linux.microsoft.com>
Link: https://lore.kernel.org/r/20230308150531.477741-1-jpiotrowski@linux.microsoft.comSigned-off-by: default avatarJakub Kicinski <kuba@kernel.org>
parent 1118aa4c
...@@ -22,6 +22,10 @@ int kvm_arch_ptp_init(void) ...@@ -22,6 +22,10 @@ int kvm_arch_ptp_init(void)
return 0; return 0;
} }
void kvm_arch_ptp_exit(void)
{
}
int kvm_arch_ptp_get_clock(struct timespec64 *ts) int kvm_arch_ptp_get_clock(struct timespec64 *ts)
{ {
return kvm_arch_ptp_get_crosststamp(NULL, ts, NULL); return kvm_arch_ptp_get_crosststamp(NULL, ts, NULL);
......
...@@ -130,6 +130,7 @@ static struct kvm_ptp_clock kvm_ptp_clock; ...@@ -130,6 +130,7 @@ static struct kvm_ptp_clock kvm_ptp_clock;
static void __exit ptp_kvm_exit(void) static void __exit ptp_kvm_exit(void)
{ {
ptp_clock_unregister(kvm_ptp_clock.ptp_clock); ptp_clock_unregister(kvm_ptp_clock.ptp_clock);
kvm_arch_ptp_exit();
} }
static int __init ptp_kvm_init(void) static int __init ptp_kvm_init(void)
......
...@@ -14,27 +14,64 @@ ...@@ -14,27 +14,64 @@
#include <uapi/linux/kvm_para.h> #include <uapi/linux/kvm_para.h>
#include <linux/ptp_clock_kernel.h> #include <linux/ptp_clock_kernel.h>
#include <linux/ptp_kvm.h> #include <linux/ptp_kvm.h>
#include <linux/set_memory.h>
static phys_addr_t clock_pair_gpa; 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) int kvm_arch_ptp_init(void)
{ {
struct page *p;
long ret; long ret;
if (!kvm_para_available()) if (!kvm_para_available())
return -ENODEV; return -ENODEV;
clock_pair_gpa = slow_virt_to_phys(&clock_pair); if (cc_platform_has(CC_ATTR_GUEST_MEM_ENCRYPT)) {
if (!pvclock_get_pvti_cpu0_va()) p = alloc_page(GFP_KERNEL | __GFP_ZERO);
return -ENODEV; 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, ret = kvm_hypercall2(KVM_HC_CLOCK_PAIRING, clock_pair_gpa,
KVM_CLOCK_PAIRING_WALLCLOCK); KVM_CLOCK_PAIRING_WALLCLOCK);
if (ret == -KVM_ENOSYS) if (ret == -KVM_ENOSYS) {
return -ENODEV; ret = -ENODEV;
goto err;
}
return ret; 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) int kvm_arch_ptp_get_clock(struct timespec64 *ts)
...@@ -49,8 +86,8 @@ int kvm_arch_ptp_get_clock(struct timespec64 *ts) ...@@ -49,8 +86,8 @@ int kvm_arch_ptp_get_clock(struct timespec64 *ts)
return -EOPNOTSUPP; return -EOPNOTSUPP;
} }
ts->tv_sec = clock_pair.sec; ts->tv_sec = clock_pair->sec;
ts->tv_nsec = clock_pair.nsec; ts->tv_nsec = clock_pair->nsec;
return 0; return 0;
} }
...@@ -81,9 +118,9 @@ int kvm_arch_ptp_get_crosststamp(u64 *cycle, struct timespec64 *tspec, ...@@ -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); pr_err_ratelimited("clock pairing hypercall ret %lu\n", ret);
return -EOPNOTSUPP; return -EOPNOTSUPP;
} }
tspec->tv_sec = clock_pair.sec; tspec->tv_sec = clock_pair->sec;
tspec->tv_nsec = clock_pair.nsec; tspec->tv_nsec = clock_pair->nsec;
*cycle = __pvclock_read_cycles(src, clock_pair.tsc); *cycle = __pvclock_read_cycles(src, clock_pair->tsc);
} while (pvclock_read_retry(src, version)); } while (pvclock_read_retry(src, version));
*cs = &kvm_clock; *cs = &kvm_clock;
......
...@@ -14,6 +14,7 @@ struct timespec64; ...@@ -14,6 +14,7 @@ struct timespec64;
struct clocksource; struct clocksource;
int kvm_arch_ptp_init(void); int kvm_arch_ptp_init(void);
void kvm_arch_ptp_exit(void);
int kvm_arch_ptp_get_clock(struct timespec64 *ts); int kvm_arch_ptp_get_clock(struct timespec64 *ts);
int kvm_arch_ptp_get_crosststamp(u64 *cycle, int kvm_arch_ptp_get_crosststamp(u64 *cycle,
struct timespec64 *tspec, struct clocksource **cs); struct timespec64 *tspec, struct clocksource **cs);
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment