hyperv: Allow userland to ro-mmap reference TSC page

This paves way to implement VDSO for the enlightened time counter.

Reviewed by:	kib
MFC after:	1 week
Sponsored by:	Microsoft
Differential Revision:	https://reviews.freebsd.org/D8768
This commit is contained in:
Sepherosa Ziehau 2016-12-15 03:32:24 +00:00
parent 1de8c69de7
commit 9622c93ae8
Notes: svn2git 2020-12-20 02:59:44 +00:00
svn path=/head/; revision=310101
4 changed files with 83 additions and 16 deletions

View file

@ -185,6 +185,9 @@ copies: .PHONY .META
${DESTDIR}${INCLUDEDIR}/dev/evdev; \
${INSTALL} -C -o ${BINOWN} -g ${BINGRP} -m 444 uinput.h \
${DESTDIR}${INCLUDEDIR}/dev/evdev
cd ${.CURDIR}/../sys/dev/hyperv/include; \
${INSTALL} -C ${TAG_ARGS} -o ${BINOWN} -g ${BINGRP} -m 444 hyperv.h \
${DESTDIR}${INCLUDEDIR}/dev/hyperv
cd ${.CURDIR}/../sys/dev/hyperv/utilities; \
${INSTALL} -C ${TAG_ARGS} -o ${BINOWN} -g ${BINGRP} -m 444 hv_snapshot.h \
${DESTDIR}${INCLUDEDIR}/dev/hyperv
@ -293,6 +296,11 @@ symlinks: .PHONY .META
ln -fs ../../../../sys/dev/evdev/$$h \
${DESTDIR}${INCLUDEDIR}/dev/evdev; \
done
cd ${.CURDIR}/../sys/dev/hyperv/include; \
for h in hyperv.h; do \
${INSTALL_SYMLINK} ${TAG_ARGS} ../../../../sys/dev/hyperv/include/$$h \
${DESTDIR}${INCLUDEDIR}/dev/hyperv; \
done
cd ${.CURDIR}/../sys/dev/hyperv/utilities; \
for h in hv_snapshot.h; do \
${INSTALL_SYMLINK} ${TAG_ARGS} ../../../../sys/dev/hyperv/utilities/$$h \

View file

@ -31,10 +31,10 @@
#ifndef _HYPERV_H_
#define _HYPERV_H_
#include <sys/param.h>
#ifdef _KERNEL
#include <vm/vm.h>
#include <vm/pmap.h>
#include <sys/param.h>
#include <sys/systm.h>
#define MSR_HV_TIME_REF_COUNT 0x40000020
@ -54,14 +54,35 @@
#define HYPERV_TIMER_NS_FACTOR 100ULL
#define HYPERV_TIMER_FREQ (NANOSEC / HYPERV_TIMER_NS_FACTOR)
#endif /* _KERNEL */
#define HYPERV_REFTSC_DEVNAME "hv_tsc"
/*
* Hyper-V Reference TSC
*/
struct hyperv_reftsc {
volatile uint32_t tsc_seq;
volatile uint32_t tsc_rsvd1;
volatile uint64_t tsc_scale;
volatile int64_t tsc_ofs;
} __packed __aligned(PAGE_SIZE);
#ifdef CTASSERT
CTASSERT(sizeof(struct hyperv_reftsc) == PAGE_SIZE);
#endif
#ifdef _KERNEL
struct hyperv_guid {
uint8_t hv_guid[16];
uint8_t hv_guid[16];
} __packed;
#define HYPERV_GUID_STRLEN 40
#define HYPERV_GUID_STRLEN 40
int hyperv_guid2str(const struct hyperv_guid *, char *, size_t);
extern u_int hyperv_features; /* CPUID_HV_MSR_ */
#endif /* _KERNEL */
#endif /* _HYPERV_H_ */

View file

@ -28,6 +28,8 @@
__FBSDID("$FreeBSD$");
#include <sys/param.h>
#include <sys/conf.h>
#include <sys/fcntl.h>
#include <sys/kernel.h>
#include <sys/systm.h>
#include <sys/timetc.h>
@ -35,6 +37,9 @@ __FBSDID("$FreeBSD$");
#include <machine/cpufunc.h>
#include <machine/cputypes.h>
#include <machine/md_var.h>
#include <machine/specialreg.h>
#include <vm/vm.h>
#include <dev/hyperv/include/hyperv.h>
#include <dev/hyperv/include/hyperv_busdma.h>
@ -47,6 +52,9 @@ struct hyperv_reftsc_ctx {
struct hyperv_dma tsc_ref_dma;
};
static d_open_t hyperv_tsc_open;
static d_mmap_t hyperv_tsc_mmap;
static struct timecounter hyperv_tsc_timecounter = {
.tc_get_timecount = NULL, /* based on CPU vendor. */
.tc_poll_pps = NULL,
@ -58,6 +66,13 @@ static struct timecounter hyperv_tsc_timecounter = {
.tc_priv = NULL
};
static struct cdevsw hyperv_tsc_cdevsw = {
.d_version = D_VERSION,
.d_open = hyperv_tsc_open,
.d_mmap = hyperv_tsc_mmap,
.d_name = HYPERV_REFTSC_DEVNAME
};
static struct hyperv_reftsc_ctx hyperv_ref_tsc;
uint64_t
@ -72,6 +87,36 @@ hypercall_md(volatile void *hc_addr, uint64_t in_val,
return (status);
}
static int
hyperv_tsc_open(struct cdev *dev __unused, int oflags, int devtype __unused,
struct thread *td __unused)
{
if (oflags & FWRITE)
return (EPERM);
return (0);
}
static int
hyperv_tsc_mmap(struct cdev *dev __unused, vm_ooffset_t offset,
vm_paddr_t *paddr, int nprot __unused, vm_memattr_t *memattr __unused)
{
KASSERT(hyperv_ref_tsc.tsc_ref != NULL, ("reftsc has not been setup"));
/*
* NOTE:
* 'nprot' does not contain information interested to us;
* WR-open is blocked by d_open.
*/
if (offset != 0)
return (EOPNOTSUPP);
*paddr = hyperv_ref_tsc.tsc_ref_dma.hv_paddr;
return (0);
}
#define HYPERV_TSC_TIMECOUNT(fence) \
static u_int \
hyperv_tsc_timecount_##fence(struct timecounter *tc) \
@ -150,6 +195,10 @@ hyperv_tsc_tcinit(void *dummy __unused)
/* Register "enlightened" timecounter. */
tc_init(&hyperv_tsc_timecounter);
/* Add device for mmap(2). */
make_dev(&hyperv_tsc_cdevsw, 0, UID_ROOT, GID_WHEEL, 0444,
HYPERV_REFTSC_DEVNAME);
}
SYSINIT(hyperv_tsc_init, SI_SUB_DRIVERS, SI_ORDER_FIRST, hyperv_tsc_tcinit,
NULL);

View file

@ -128,17 +128,6 @@
#define CPUID_LEAF_HV_LIMITS 0x40000005
#define CPUID_LEAF_HV_HWFEATURES 0x40000006
/*
* Hyper-V Reference TSC
*/
struct hyperv_reftsc {
volatile uint32_t tsc_seq;
volatile uint32_t tsc_rsvd1;
volatile uint64_t tsc_scale;
volatile int64_t tsc_ofs;
} __packed __aligned(PAGE_SIZE);
CTASSERT(sizeof(struct hyperv_reftsc) == PAGE_SIZE);
/*
* Hyper-V Monitor Notification Facility
*/