brintos

brintos / linux-shallow public Read only

0
0
Text · 2.7 KiB · 617c8d6 Raw
130 lines · c
1// SPDX-License-Identifier: GPL-2.0-or-later2/*3 * Virtual PTP 1588 clock for use with KVM guests4 *5 * Copyright (C) 2017 Red Hat Inc.6 */7 8#include <linux/device.h>9#include <linux/kernel.h>10#include <asm/pvclock.h>11#include <asm/kvmclock.h>12#include <linux/module.h>13#include <uapi/asm/kvm_para.h>14#include <uapi/linux/kvm_para.h>15#include <linux/ptp_clock_kernel.h>16#include <linux/ptp_kvm.h>17#include <linux/set_memory.h>18 19static phys_addr_t clock_pair_gpa;20static struct kvm_clock_pairing clock_pair_glbl;21static struct kvm_clock_pairing *clock_pair;22 23int kvm_arch_ptp_init(void)24{25	struct page *p;26	long ret;27 28	if (!kvm_para_available())29		return -ENODEV;30 31	if (cc_platform_has(CC_ATTR_GUEST_MEM_ENCRYPT)) {32		p = alloc_page(GFP_KERNEL | __GFP_ZERO);33		if (!p)34			return -ENOMEM;35 36		clock_pair = page_address(p);37		ret = set_memory_decrypted((unsigned long)clock_pair, 1);38		if (ret) {39			__free_page(p);40			clock_pair = NULL;41			goto nofree;42		}43	} else {44		clock_pair = &clock_pair_glbl;45	}46 47	clock_pair_gpa = slow_virt_to_phys(clock_pair);48	if (!pvclock_get_pvti_cpu0_va()) {49		ret = -ENODEV;50		goto err;51	}52 53	ret = kvm_hypercall2(KVM_HC_CLOCK_PAIRING, clock_pair_gpa,54			     KVM_CLOCK_PAIRING_WALLCLOCK);55	if (ret == -KVM_ENOSYS) {56		ret = -ENODEV;57		goto err;58	}59 60	return ret;61 62err:63	kvm_arch_ptp_exit();64nofree:65	return ret;66}67 68void kvm_arch_ptp_exit(void)69{70	if (cc_platform_has(CC_ATTR_GUEST_MEM_ENCRYPT)) {71		WARN_ON(set_memory_encrypted((unsigned long)clock_pair, 1));72		free_page((unsigned long)clock_pair);73		clock_pair = NULL;74	}75}76 77int kvm_arch_ptp_get_clock(struct timespec64 *ts)78{79	long ret;80 81	ret = kvm_hypercall2(KVM_HC_CLOCK_PAIRING,82			     clock_pair_gpa,83			     KVM_CLOCK_PAIRING_WALLCLOCK);84	if (ret != 0) {85		pr_err_ratelimited("clock offset hypercall ret %lu\n", ret);86		return -EOPNOTSUPP;87	}88 89	ts->tv_sec = clock_pair->sec;90	ts->tv_nsec = clock_pair->nsec;91 92	return 0;93}94 95int kvm_arch_ptp_get_crosststamp(u64 *cycle, struct timespec64 *tspec,96			      enum clocksource_ids *cs_id)97{98	struct pvclock_vcpu_time_info *src;99	unsigned int version;100	long ret;101 102	src = this_cpu_pvti();103 104	do {105		/*106		 * We are using a TSC value read in the hosts107		 * kvm_hc_clock_pairing handling.108		 * So any changes to tsc_to_system_mul109		 * and tsc_shift or any other pvclock110		 * data invalidate that measurement.111		 */112		version = pvclock_read_begin(src);113 114		ret = kvm_hypercall2(KVM_HC_CLOCK_PAIRING,115				     clock_pair_gpa,116				     KVM_CLOCK_PAIRING_WALLCLOCK);117		if (ret != 0) {118			pr_err_ratelimited("clock pairing hypercall ret %lu\n", ret);119			return -EOPNOTSUPP;120		}121		tspec->tv_sec = clock_pair->sec;122		tspec->tv_nsec = clock_pair->nsec;123		*cycle = __pvclock_read_cycles(src, clock_pair->tsc);124	} while (pvclock_read_retry(src, version));125 126	*cs_id = CSID_X86_KVM_CLK;127 128	return 0;129}130