case FIX_KMAP_BEGIN ... FIX_KMAP_END:
# endif
#elif defined(CONFIG_X86_VSYSCALL_EMULATION)
+ case PVCLOCK_FIXMAP_BEGIN ... PVCLOCK_FIXMAP_END:
case VSYSCALL_PAGE:
#endif
case FIX_TEXT_POKE0:
#ifdef CONFIG_X86_VSYSCALL_EMULATION
/* Replicate changes to map the vsyscall page into the user
pagetable vsyscall mapping. */
- if (idx == VSYSCALL_PAGE) {
+ if (idx == VSYSCALL_PAGE ||
+ (idx >= PVCLOCK_FIXMAP_BEGIN && idx <= PVCLOCK_FIXMAP_END)) {
unsigned long vaddr = __fix_to_virt(idx);
set_pte_vaddr_pud(level3_user_vsyscall, vaddr, pte);
}
#include <linux/slab.h>
#include <linux/pvclock_gtod.h>
#include <linux/timekeeper_internal.h>
+#include <linux/mm.h>
#include <asm/pvclock.h>
#include <asm/xen/hypervisor.h>
.steal_clock = xen_steal_clock,
};
+static struct pvclock_vsyscall_time_info *xen_clock __read_mostly;
+
+void xen_setup_vcpu_vsyscall_time_info(int cpu)
+{
+ struct vcpu_register_time_memory_area t;
+ int ret;
+
+ if (!xen_clock)
+ return;
+
+ t.addr.v = &xen_clock[cpu].pvti;
+
+ ret = HYPERVISOR_vcpu_op(VCPUOP_register_vcpu_time_memory_area,
+ cpu, &t);
+
+ /*
+ * We don't disable VCLOCK_PVCLOCK entirely if one of the vCPUS fails
+ * to register the secondary time info with Xen. If it does fail worse
+ * it can happen is process seeing a zeroed out pvti. Though userspace
+ * checks the PVCLOCK_TSC_STABLE_BIT and if 0, it discards the data
+ * in pvti and fallbacks to a system call for a reliable timestamp.
+ */
+ WARN_ONCE(ret != 0,
+ "CPU%d: Cannot register secondary vcpu_time_info", cpu);
+}
+
+static __init void xen_setup_vsyscall_time_info(void)
+{
+ struct vcpu_register_time_memory_area t;
+ struct pvclock_vsyscall_time_info *ti;
+ struct pvclock_vcpu_time_info *pvti;
+ int cpu = smp_processor_id();
+ unsigned long size;
+ int ret;
+
+ pvti = &__this_cpu_read(xen_vcpu)->time;
+
+ /*
+ * We check ahead on the primary time info if this
+ * bit is supported hence speeding up Xen clocksource.
+ */
+ if (!(pvti->flags & PVCLOCK_TSC_STABLE_BIT))
+ return;
+
+ pvclock_set_flags(PVCLOCK_TSC_STABLE_BIT);
+
+ size = PAGE_ALIGN(sizeof(struct pvclock_vsyscall_time_info) * NR_CPUS);
+ ti = (struct pvclock_vsyscall_time_info *)
+ alloc_pages_exact(size, GFP_KERNEL | __GFP_ZERO);
+ if (!ti)
+ return;
+
+ t.addr.v = &ti->pvti;
+
+ ret = HYPERVISOR_vcpu_op(VCPUOP_register_vcpu_time_memory_area,
+ cpu, &t);
+ if (ret) {
+ pr_debug("xen: Cannot register secondary time_info err %d\n",
+ ret);
+ free_pages_exact(ti, get_order(size));
+ return;
+ }
+
+ /* If the check above succedded this one most likely too since it's the
+ * same data on both primary and secondary time infos just different
+ * memory regions. But we still check in case hypervisor is buggy.
+ */
+ pvti = &ti->pvti;
+ if (!(pvti->flags & PVCLOCK_TSC_STABLE_BIT)) {
+ t.addr.v = NULL;
+ if (!HYPERVISOR_vcpu_op(VCPUOP_register_vcpu_time_memory_area,
+ cpu, &t))
+ free_pages_exact(ti, get_order(size));
+
+ pr_debug("xen: VCLOCK_PVCLOCK not supported\n");
+ return;
+ }
+
+ xen_clock = ti;
+ pvclock_init_vsyscall(xen_clock, size);
+
+ xen_clocksource.archdata.vclock_mode = VCLOCK_PVCLOCK;
+}
+
static void __init xen_time_init(void)
{
int cpu = smp_processor_id();
xen_setup_cpu_clockevents();
xen_time_setup_guest();
+ xen_setup_vsyscall_time_info();
if (xen_initial_domain())
pvclock_gtod_register_notifier(&xen_pvclock_gtod_notifier);
/* Send an NMI to the specified VCPU. @extra_arg == NULL. */
#define VCPUOP_send_nmi 11
+
+/*
+ * Register a memory location to get a secondary copy of the vcpu time
+ * parameters. The master copy still exists as part of the vcpu shared
+ * memory area, and this secondary copy is updated whenever the master copy
+ * is updated (and using the same versioning scheme for synchronisation).
+ *
+ * The intent is that this copy may be mapped (RO) into userspace so
+ * that usermode can compute system time using the time info and the
+ * tsc. Usermode will see an array of vcpu_time_info structures, one
+ * for each vcpu, and choose the right one by an existing mechanism
+ * which allows it to get the current vcpu number (such as via a
+ * segment limit). It can then apply the normal algorithm to compute
+ * system time from the tsc.
+ *
+ * @extra_arg == pointer to vcpu_register_time_info_memory_area structure.
+ */
+#define VCPUOP_register_vcpu_time_memory_area 13
+DEFINE_GUEST_HANDLE_STRUCT(vcpu_time_info_t);
+struct vcpu_register_time_memory_area {
+ union {
+ GUEST_HANDLE(vcpu_time_info_t) h;
+ struct pvclock_vcpu_time_info *v;
+ uint64_t p;
+ } addr;
+};
+DEFINE_GUEST_HANDLE_STRUCT(vcpu_register_time_memory_area_t);
+
#endif /* __XEN_PUBLIC_VCPU_H__ */