Skip to content

Commit

Permalink
ptp: kvm: Use decrypted memory in confidential guest on x86
Browse files Browse the repository at this point in the history
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
when not needed.

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>
  • Loading branch information
jepio authored and intel-lab-lkp committed Feb 20, 2023
1 parent 92f3e96 commit 0dd1701
Show file tree
Hide file tree
Showing 3 changed files with 53 additions and 11 deletions.
4 changes: 4 additions & 0 deletions drivers/ptp/ptp_kvm_arm.c
Expand Up @@ -22,6 +22,10 @@ int kvm_arch_ptp_init(void)
return 0;
}

void kvm_arch_ptp_exit(void)
{
}

int kvm_arch_ptp_get_clock(struct timespec64 *ts)
{
return kvm_arch_ptp_get_crosststamp(NULL, ts, NULL);
Expand Down
1 change: 1 addition & 0 deletions drivers/ptp/ptp_kvm_common.c
Expand Up @@ -130,6 +130,7 @@ static struct kvm_ptp_clock kvm_ptp_clock;
static void __exit ptp_kvm_exit(void)
{
ptp_clock_unregister(kvm_ptp_clock.ptp_clock);
kvm_arch_ptp_exit();
}

static int __init ptp_kvm_init(void)
Expand Down
59 changes: 48 additions & 11 deletions drivers/ptp/ptp_kvm_x86.c
Expand Up @@ -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)
Expand All @@ -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;
}
Expand Down Expand Up @@ -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;
Expand Down

0 comments on commit 0dd1701

Please sign in to comment.