diff options
author | kib <kib@FreeBSD.org> | 2015-11-23 07:09:35 +0000 |
---|---|---|
committer | kib <kib@FreeBSD.org> | 2015-11-23 07:09:35 +0000 |
commit | e0c4faece4ce54570904909a5ede55c60f35fe5f (patch) | |
tree | 86f12545db0b9e76efce54eb215d79ed458d2be6 /sys/kern | |
parent | d427e0a9ba651eeab98ce6516fef233ea7041714 (diff) | |
download | FreeBSD-src-e0c4faece4ce54570904909a5ede55c60f35fe5f.zip FreeBSD-src-e0c4faece4ce54570904909a5ede55c60f35fe5f.tar.gz |
Split kerne timekeep ABI structure vdso_sv_tk out of the struct
sysentvec. This allows the timekeep data to be shared between similar
ABIs which cannot share sysentvec.
Make the timekeep_push_vdso() tick callback to the timekeep structures
instead of sysentvecs. If several sysentvec share the vdso_sv_tk
structure, we would update the userspace data several times on each
tick, without the change.
Only allocate vdso_sv_tk in the exec_sysvec_init() sysinit when
sysentvec is marked with the new SV_TIMEKEEP flag. This saves
allocation and update of unneeded vdso_sv_tk for ABIs which do not
provide userspace gettimeofday yet, which are PowerPCs arches right
now.
Make vdso_sv_tk allocator public, namely split out and export
alloc_sv_tk() and alloc_sv_tk_compat32(). ABIs which share timekeep
data now can allocate it manually and share as appropriate.
Requested by: nwhitehorn
Tested by: nwhitehorn, pho
Sponsored by: The FreeBSD Foundation
MFC after: 2 weeks
Diffstat (limited to 'sys/kern')
-rw-r--r-- | sys/kern/kern_sharedpage.c | 125 |
1 files changed, 79 insertions, 46 deletions
diff --git a/sys/kern/kern_sharedpage.c b/sys/kern/kern_sharedpage.c index 6ad2ed8..7501472 100644 --- a/sys/kern/kern_sharedpage.c +++ b/sys/kern/kern_sharedpage.c @@ -1,7 +1,11 @@ /*- * Copyright (c) 2010, 2012 Konstantin Belousov <kib@FreeBSD.org> + * Copyright (c) 2015 The FreeBSD Foundation * All rights reserved. * + * Portions of this software were developed by Konstantin Belousov + * under sponsorship from the FreeBSD Foundation. + * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: @@ -34,6 +38,7 @@ __FBSDID("$FreeBSD$"); #include <sys/systm.h> #include <sys/kernel.h> #include <sys/lock.h> +#include <sys/malloc.h> #include <sys/rwlock.h> #include <sys/sysent.h> #include <sys/sysctl.h> @@ -127,7 +132,7 @@ SYSINIT(shp, SI_SUB_EXEC, SI_ORDER_FIRST, (sysinit_cfunc_t)shared_page_init, * calls us after the timehands are updated). */ static void -timehands_update(struct sysentvec *sv) +timehands_update(struct vdso_sv_tk *svtk) { struct vdso_timehands th; struct vdso_timekeep *tk; @@ -135,20 +140,20 @@ timehands_update(struct sysentvec *sv) enabled = tc_fill_vdso_timehands(&th); th.th_gen = 0; - idx = sv->sv_timekeep_curr; + idx = svtk->sv_timekeep_curr; if (++idx >= VDSO_TH_NUM) idx = 0; - sv->sv_timekeep_curr = idx; - if (++sv->sv_timekeep_gen == 0) - sv->sv_timekeep_gen = 1; + svtk->sv_timekeep_curr = idx; + if (++svtk->sv_timekeep_gen == 0) + svtk->sv_timekeep_gen = 1; tk = (struct vdso_timekeep *)(shared_page_mapping + - sv->sv_timekeep_off); + svtk->sv_timekeep_off); tk->tk_th[idx].th_gen = 0; atomic_thread_fence_rel(); if (enabled) tk->tk_th[idx] = th; - atomic_store_rel_32(&tk->tk_th[idx].th_gen, sv->sv_timekeep_gen); + atomic_store_rel_32(&tk->tk_th[idx].th_gen, svtk->sv_timekeep_gen); atomic_store_rel_32(&tk->tk_current, idx); /* @@ -160,7 +165,7 @@ timehands_update(struct sysentvec *sv) #ifdef COMPAT_FREEBSD32 static void -timehands_update32(struct sysentvec *sv) +timehands_update32(struct vdso_sv_tk *svtk) { struct vdso_timehands32 th; struct vdso_timekeep32 *tk; @@ -168,20 +173,20 @@ timehands_update32(struct sysentvec *sv) enabled = tc_fill_vdso_timehands32(&th); th.th_gen = 0; - idx = sv->sv_timekeep_curr; + idx = svtk->sv_timekeep_curr; if (++idx >= VDSO_TH_NUM) idx = 0; - sv->sv_timekeep_curr = idx; - if (++sv->sv_timekeep_gen == 0) - sv->sv_timekeep_gen = 1; + svtk->sv_timekeep_curr = idx; + if (++svtk->sv_timekeep_gen == 0) + svtk->sv_timekeep_gen = 1; tk = (struct vdso_timekeep32 *)(shared_page_mapping + - sv->sv_timekeep_off); + svtk->sv_timekeep_off); tk->tk_th[idx].th_gen = 0; atomic_thread_fence_rel(); if (enabled) tk->tk_th[idx] = th; - atomic_store_rel_32(&tk->tk_th[idx].th_gen, sv->sv_timekeep_gen); + atomic_store_rel_32(&tk->tk_th[idx].th_gen, svtk->sv_timekeep_gen); atomic_store_rel_32(&tk->tk_current, idx); tk->tk_enabled = enabled; } @@ -192,33 +197,69 @@ timehands_update32(struct sysentvec *sv) * that needs to be iterated over from the hardclock interrupt * context. */ -static struct sysentvec *host_sysentvec; +static struct vdso_sv_tk *host_svtk; #ifdef COMPAT_FREEBSD32 -static struct sysentvec *compat32_sysentvec; +static struct vdso_sv_tk *compat32_svtk; #endif void timekeep_push_vdso(void) { - if (host_sysentvec != NULL && host_sysentvec->sv_timekeep_base != 0) - timehands_update(host_sysentvec); + if (host_svtk != NULL) + timehands_update(host_svtk); #ifdef COMPAT_FREEBSD32 - if (compat32_sysentvec != NULL && - compat32_sysentvec->sv_timekeep_base != 0) - timehands_update32(compat32_sysentvec); + if (compat32_svtk != NULL) + timehands_update32(compat32_svtk); #endif } +struct vdso_sv_tk * +alloc_sv_tk(void) +{ + struct vdso_sv_tk *svtk; + int tk_base; + uint32_t tk_ver; + + tk_ver = VDSO_TK_VER_CURR; + svtk = malloc(sizeof(struct vdso_sv_tk), M_TEMP, M_WAITOK | M_ZERO); + tk_base = shared_page_alloc(sizeof(struct vdso_timekeep) + + sizeof(struct vdso_timehands) * VDSO_TH_NUM, 16); + KASSERT(tk_base != -1, ("tk_base -1 for native")); + shared_page_write(tk_base + offsetof(struct vdso_timekeep, tk_ver), + sizeof(uint32_t), &tk_ver); + svtk->sv_timekeep_off = tk_base; + timekeep_push_vdso(); + return (svtk); +} + +#ifdef COMPAT_FREEBSD32 +struct vdso_sv_tk * +alloc_sv_tk_compat32(void) +{ + struct vdso_sv_tk *svtk; + int tk_base; + uint32_t tk_ver; + + svtk = malloc(sizeof(struct vdso_sv_tk), M_TEMP, M_WAITOK | M_ZERO); + tk_ver = VDSO_TK_VER_CURR; + tk_base = shared_page_alloc(sizeof(struct vdso_timekeep32) + + sizeof(struct vdso_timehands32) * VDSO_TH_NUM, 16); + KASSERT(tk_base != -1, ("tk_base -1 for 32bit")); + shared_page_write(tk_base + offsetof(struct vdso_timekeep32, + tk_ver), sizeof(uint32_t), &tk_ver); + svtk->sv_timekeep_off = tk_base; + timekeep_push_vdso(); + return (svtk); +} +#endif + void exec_sysvec_init(void *param) { struct sysentvec *sv; - int tk_base; - uint32_t tk_ver; sv = (struct sysentvec *)param; - if ((sv->sv_flags & SV_SHP) == 0) return; sv->sv_shared_page_obj = shared_page_obj; @@ -226,30 +267,22 @@ exec_sysvec_init(void *param) shared_page_fill(*(sv->sv_szsigcode), 16, sv->sv_sigcode); if ((sv->sv_flags & SV_ABI_MASK) != SV_ABI_FREEBSD) return; - tk_ver = VDSO_TK_VER_CURR; + if ((sv->sv_flags & SV_TIMEKEEP) != 0) { #ifdef COMPAT_FREEBSD32 - if ((sv->sv_flags & SV_ILP32) != 0) { - tk_base = shared_page_alloc(sizeof(struct vdso_timekeep32) + - sizeof(struct vdso_timehands32) * VDSO_TH_NUM, 16); - KASSERT(tk_base != -1, ("tk_base -1 for 32bit")); - shared_page_write(tk_base + offsetof(struct vdso_timekeep32, - tk_ver), sizeof(uint32_t), &tk_ver); - KASSERT(compat32_sysentvec == 0, - ("Native compat32 already registered")); - compat32_sysentvec = sv; - } else { + if ((sv->sv_flags & SV_ILP32) != 0) { + KASSERT(compat32_svtk == NULL, + ("Compat32 already registered")); + compat32_svtk = alloc_sv_tk_compat32(); + sv->sv_timekeep_base = sv->sv_shared_page_base + + compat32_svtk->sv_timekeep_off; + } else { #endif - tk_base = shared_page_alloc(sizeof(struct vdso_timekeep) + - sizeof(struct vdso_timehands) * VDSO_TH_NUM, 16); - KASSERT(tk_base != -1, ("tk_base -1 for native")); - shared_page_write(tk_base + offsetof(struct vdso_timekeep, - tk_ver), sizeof(uint32_t), &tk_ver); - KASSERT(host_sysentvec == 0, ("Native already registered")); - host_sysentvec = sv; + KASSERT(host_svtk == NULL, ("Host already registered")); + host_svtk = alloc_sv_tk(); + sv->sv_timekeep_base = sv->sv_shared_page_base + + host_svtk->sv_timekeep_off; #ifdef COMPAT_FREEBSD32 - } + } #endif - sv->sv_timekeep_base = sv->sv_shared_page_base + tk_base; - sv->sv_timekeep_off = tk_base; - timekeep_push_vdso(); + } } |