summaryrefslogtreecommitdiffstats
path: root/lib
diff options
context:
space:
mode:
authorkib <kib@FreeBSD.org>2017-01-11 11:25:18 +0000
committerkib <kib@FreeBSD.org>2017-01-11 11:25:18 +0000
commitaf3d04b889e60d8f5e852ada7b4260f336867445 (patch)
tree3e6742c778055e1e6f3d9ec8547e842d605a699d /lib
parentf59a0de2f427175c17bcbef91e8b95fad27ffe1d (diff)
downloadFreeBSD-src-af3d04b889e60d8f5e852ada7b4260f336867445.zip
FreeBSD-src-af3d04b889e60d8f5e852ada7b4260f336867445.tar.gz
MFC r311287:
__vdso_gettc(): be extra careful with /dev/hpet mappings, never unmap the mapping which might be accessed by other threads.
Diffstat (limited to 'lib')
-rw-r--r--lib/libc/x86/sys/__vdso_gettc.c54
1 files changed, 35 insertions, 19 deletions
diff --git a/lib/libc/x86/sys/__vdso_gettc.c b/lib/libc/x86/sys/__vdso_gettc.c
index 5097ad5..723db6e 100644
--- a/lib/libc/x86/sys/__vdso_gettc.c
+++ b/lib/libc/x86/sys/__vdso_gettc.c
@@ -1,6 +1,6 @@
/*-
* Copyright (c) 2012 Konstantin Belousov <kib@FreeBSD.org>
- * Copyright (c) 2016 The FreeBSD Foundation
+ * Copyright (c) 2016, 2017 The FreeBSD Foundation
* All rights reserved.
*
* Portions of this software were developed by Konstantin Belousov
@@ -42,11 +42,11 @@ __FBSDID("$FreeBSD$");
#include <string.h>
#include <unistd.h>
#include "un-namespace.h"
+#include <machine/atomic.h>
#include <machine/cpufunc.h>
#include <machine/specialreg.h>
#include <dev/acpica/acpi_hpet.h>
#ifdef __amd64__
-#include <machine/atomic.h>
#include <dev/hyperv/hyperv.h>
#endif
#include "libc_private.h"
@@ -115,37 +115,47 @@ __vdso_rdtsc32(void)
return (rdtsc32());
}
-static char *hpet_dev_map = NULL;
-static uint32_t hpet_idx = 0xffffffff;
+#define HPET_DEV_MAP_MAX 10
+static volatile char *hpet_dev_map[HPET_DEV_MAP_MAX];
static void
__vdso_init_hpet(uint32_t u)
{
static const char devprefix[] = "/dev/hpet";
char devname[64], *c, *c1, t;
+ volatile char *new_map, *old_map;
+ uint32_t u1;
int fd;
c1 = c = stpcpy(devname, devprefix);
- u = hpet_idx;
+ u1 = u;
do {
- *c++ = u % 10 + '0';
- u /= 10;
- } while (u != 0);
+ *c++ = u1 % 10 + '0';
+ u1 /= 10;
+ } while (u1 != 0);
*c = '\0';
for (c--; c1 != c; c1++, c--) {
t = *c1;
*c1 = *c;
*c = t;
}
+
+ old_map = hpet_dev_map[u];
+ if (old_map != NULL)
+ return;
+
fd = _open(devname, O_RDONLY);
if (fd == -1) {
- hpet_dev_map = MAP_FAILED;
+ atomic_cmpset_rel_ptr((volatile uintptr_t *)&hpet_dev_map[u],
+ (uintptr_t)old_map, (uintptr_t)MAP_FAILED);
return;
}
- if (hpet_dev_map != NULL && hpet_dev_map != MAP_FAILED)
- munmap(hpet_dev_map, PAGE_SIZE);
- hpet_dev_map = mmap(NULL, PAGE_SIZE, PROT_READ, MAP_SHARED, fd, 0);
+ new_map = mmap(NULL, PAGE_SIZE, PROT_READ, MAP_SHARED, fd, 0);
_close(fd);
+ if (atomic_cmpset_rel_ptr((volatile uintptr_t *)&hpet_dev_map[u],
+ (uintptr_t)old_map, (uintptr_t)new_map) == 0 &&
+ new_map != MAP_FAILED)
+ munmap((void *)new_map, PAGE_SIZE);
}
#ifdef __amd64__
@@ -213,7 +223,8 @@ __vdso_hyperv_tsc(struct hyperv_reftsc *tsc_ref, u_int *tc)
int
__vdso_gettc(const struct vdso_timehands *th, u_int *tc)
{
- uint32_t tmp;
+ volatile char *map;
+ uint32_t idx;
switch (th->th_algo) {
case VDSO_TH_ALGO_X86_TSC:
@@ -221,14 +232,19 @@ __vdso_gettc(const struct vdso_timehands *th, u_int *tc)
__vdso_rdtsc32();
return (0);
case VDSO_TH_ALGO_X86_HPET:
- tmp = th->th_x86_hpet_idx;
- if (hpet_dev_map == NULL || tmp != hpet_idx) {
- hpet_idx = tmp;
- __vdso_init_hpet(hpet_idx);
+ idx = th->th_x86_hpet_idx;
+ if (idx >= HPET_DEV_MAP_MAX)
+ return (ENOSYS);
+ map = (volatile char *)atomic_load_acq_ptr(
+ (volatile uintptr_t *)&hpet_dev_map[idx]);
+ if (map == NULL) {
+ __vdso_init_hpet(idx);
+ map = (volatile char *)atomic_load_acq_ptr(
+ (volatile uintptr_t *)&hpet_dev_map[idx]);
}
- if (hpet_dev_map == MAP_FAILED)
+ if (map == MAP_FAILED)
return (ENOSYS);
- *tc = *(volatile uint32_t *)(hpet_dev_map + HPET_MAIN_COUNTER);
+ *tc = *(volatile uint32_t *)(map + HPET_MAIN_COUNTER);
return (0);
#ifdef __amd64__
case VDSO_TH_ALGO_X86_HVTSC:
OpenPOWER on IntegriCloud