Changeset View
Changeset View
Standalone View
Standalone View
sys/sys/vps.h
- This file was added.
/*- | |||||
* SPDX-License-Identifier: BSD-2-Clause-FreeBSD | |||||
* | |||||
* Copyright (c) 2006-2009 University of Zagreb | |||||
* Copyright (c) 2006-2009 FreeBSD Foundation | |||||
* Copyright (c) 2018 iXsystems, Inc. | |||||
* All rights reserved. | |||||
* | |||||
* This software was developed by the University of Zagreb and the | |||||
* FreeBSD Foundation under sponsorship by the Stichting NLnet and the | |||||
* FreeBSD Foundation. | |||||
* | |||||
* Portions of this software were developed by Bjoern Zeeb | |||||
* under sponsorship from iXsystems, Inc. | |||||
* | |||||
* Copyright (c) 2009 Jeffrey Roberson <jeff@freebsd.org> | |||||
* Copyright (c) 2009 Robert N. M. Watson | |||||
* All rights reserved. | |||||
* | |||||
* Redistribution and use in source and binary forms, with or without | |||||
* modification, are permitted provided that the following conditions | |||||
* are met: | |||||
* 1. Redistributions of source code must retain the above copyright | |||||
* notice, this list of conditions and the following disclaimer. | |||||
* 2. Redistributions in binary form must reproduce the above copyright | |||||
* notice, this list of conditions and the following disclaimer in the | |||||
* documentation and/or other materials provided with the distribution. | |||||
* | |||||
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND | |||||
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE | |||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE | |||||
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE | |||||
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL | |||||
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS | |||||
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) | |||||
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT | |||||
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY | |||||
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF | |||||
* SUCH DAMAGE. | |||||
* | |||||
* $FreeBSD$ | |||||
*/ | |||||
/*- | |||||
* This header file defines several sets of interfaces supporting virtualized | |||||
* process space: | |||||
* | |||||
* - Definition of 'struct vps' and functions and macros to allocate/free/ | |||||
* manipulate it. | |||||
* | |||||
* - A virtual process stack memory allocator, which provides support for | |||||
* virtualized global variables via a special linker set, set_vps. | |||||
* | |||||
* - Virtualized sysinits/sysuninits, which allow constructors and | |||||
* destructors to be run for each process space as virtual | |||||
* instances are created and destroyed. | |||||
* | |||||
* If VIMAGE isn't compiled into the kernel, virtualized global variables | |||||
* compile to normal global variables, and virtualized sysinits to regular | |||||
* sysinits. | |||||
*/ | |||||
#ifndef _SYS_VPS_H_ | |||||
#define _SYS_VPS_H_ | |||||
/* | |||||
* struct vps describes a virtualized process space, and is primarily a | |||||
* pointer to storage for virtualized global variables. Expose to userspace | |||||
* as required for libkvm. | |||||
*/ | |||||
#if defined(_KERNEL) || defined(_WANT_VPS) | |||||
#include <sys/queue.h> | |||||
struct vps { | |||||
LIST_ENTRY(vps) vps_le; /* all vps list */ | |||||
u_int vps_magic_n; | |||||
u_int vps_state; /* SI_SUB_* */ | |||||
void *vps_data_mem; | |||||
uintptr_t vps_data_base; | |||||
struct prison *vps_pr; /* Put init on this if set. */ | |||||
}; | |||||
#define VPS_MAGIC_N 0x0f0307e2 | |||||
/* | |||||
* These two virtual process space allocator definitions are also required | |||||
* for libkvm so that it can evaluate virtualized global variables. | |||||
*/ | |||||
#define VPS_SETNAME "set_vps" | |||||
#define VPS_SYMPREFIX "vps_entry_" | |||||
#endif | |||||
#ifdef _KERNEL | |||||
#ifdef VIMAGE | |||||
#include <sys/lock.h> | |||||
#include <sys/proc.h> /* for struct thread */ | |||||
#include <sys/rwlock.h> | |||||
#include <sys/sx.h> | |||||
/* | |||||
* Location of the kernel's 'set_vps' linker set. | |||||
*/ | |||||
extern uintptr_t *__start_set_vps; | |||||
__GLOBL(__start_set_vps); | |||||
extern uintptr_t *__stop_set_vps; | |||||
__GLOBL(__stop_set_vps); | |||||
#define VPS_START (uintptr_t)&__start_set_vps | |||||
#define VPS_STOP (uintptr_t)&__stop_set_vps | |||||
/* | |||||
* Functions to allocate and destroy virtual process spaces. | |||||
*/ | |||||
struct vps *vps_alloc(struct prison *); | |||||
void vps_destroy(struct vps *); | |||||
/* | |||||
* The current virtual process space -- we may wish to move this to struct | |||||
* pcpu in the future. | |||||
*/ | |||||
#define curvps curthread->td_vps | |||||
/* | |||||
* Various macros -- get and set the current process space, but also | |||||
* assertions. | |||||
*/ | |||||
#if defined(INVARIANTS) || defined(VPS_DEBUG) | |||||
#define VPS_ASSERT(exp, msg) do { \ | |||||
if (!(exp)) \ | |||||
panic msg; \ | |||||
} while (0) | |||||
#else | |||||
#define VPS_ASSERT(exp, msg) do { \ | |||||
} while (0) | |||||
#endif | |||||
#ifdef VPS_DEBUG | |||||
void vps_log_recursion(struct vps *, const char *, int); | |||||
#define CURVPS_SET_QUIET(arg) \ | |||||
VPS_ASSERT((arg) != NULL && (arg)->vps_magic_n == VPS_MAGIC_N, \ | |||||
("CURVPS_SET at %s:%d %s() curvps=%p vps=%p", \ | |||||
__FILE__, __LINE__, __func__, curvps, (arg))); \ | |||||
struct vps *saved_vps = curvps; \ | |||||
const char *saved_vps_lpush = curthread->td_vps_lpush; \ | |||||
curvps = arg; \ | |||||
curthread->td_vps_lpush = __func__; | |||||
#define CURVPS_SET_VERBOSE(arg) \ | |||||
CURVPS_SET_QUIET(arg) \ | |||||
if (saved_vps) \ | |||||
vps_log_recursion(saved_vps, saved_vps_lpush, __LINE__); | |||||
#define CURVPS_SET(arg) CURVPS_SET_VERBOSE(arg) | |||||
#define CURVPS_RESTORE() \ | |||||
VPS_ASSERT(curvps != NULL && (saved_vps == NULL || \ | |||||
saved_vps->vps_magic_n == VPS_MAGIC_N), \ | |||||
("CURVPS_RESTORE at %s:%d %s() curvps=%p saved_vps=%p", \ | |||||
__FILE__, __LINE__, __func__, curvps, saved_vps)); \ | |||||
curvps = saved_vps; \ | |||||
curthread->td_vps_lpush = saved_vps_lpush; | |||||
#else /* !VPS_DEBUG */ | |||||
#define CURVPS_SET_QUIET(arg) \ | |||||
VPS_ASSERT((arg) != NULL && (arg)->vps_magic_n == VPS_MAGIC_N, \ | |||||
("CURVPS_SET at %s:%d %s() curvps=%p vps=%p", \ | |||||
__FILE__, __LINE__, __func__, curvps, (arg))); \ | |||||
struct vps *saved_vps = curvps; \ | |||||
curvps = arg; | |||||
#define CURVPS_SET_VERBOSE(arg) \ | |||||
CURVPS_SET_QUIET(arg) | |||||
#define CURVPS_SET(arg) CURVPS_SET_VERBOSE(arg) | |||||
#define CURVPS_RESTORE() \ | |||||
VPS_ASSERT(curvps != NULL && (saved_vps == NULL || \ | |||||
saved_vps->vps_magic_n == VPS_MAGIC_N), \ | |||||
("CURVPS_RESTORE at %s:%d %s() curvps=%p saved_vps=%p", \ | |||||
__FILE__, __LINE__, __func__, curvps, saved_vps)); \ | |||||
curvps = saved_vps; | |||||
#endif /* VPS_DEBUG */ | |||||
extern struct vps *vps0; | |||||
#define IS_DEFAULT_VPS(arg) ((arg) == vps0) | |||||
#define CRED_TO_VPS(cr) (cr)->cr_prison->pr_vps | |||||
#define TD_TO_VPS(td) CRED_TO_VPS((td)->td_ucred) | |||||
#define P_TO_VPS(p) CRED_TO_VPS((p)->p_ucred) | |||||
/* | |||||
* Global linked list of all virtual process spaces, along with read locks to | |||||
* access it. If a caller may sleep while accessing the list, it must use | |||||
* the sleepable lock macros. | |||||
*/ | |||||
LIST_HEAD(vps_list_head, vps); | |||||
extern struct vps_list_head vps_head; | |||||
extern struct rwlock vps_rwlock; | |||||
extern struct sx vps_sxlock; | |||||
#define VPS_LIST_RLOCK() sx_slock(&vps_sxlock) | |||||
#define VPS_LIST_RLOCK_NOSLEEP() rw_rlock(&vps_rwlock) | |||||
#define VPS_LIST_RUNLOCK() sx_sunlock(&vps_sxlock) | |||||
#define VPS_LIST_RUNLOCK_NOSLEEP() rw_runlock(&vps_rwlock) | |||||
/* | |||||
* Iteration macros to walk the global list of virtual process spaces. | |||||
*/ | |||||
#define VPS_ITERATOR_DECL(arg) struct vps *arg | |||||
#define VPS_FOREACH(arg) LIST_FOREACH((arg), &vps_head, vps_le) | |||||
/* | |||||
* Virtual process space memory allocator, which allows global variables to | |||||
* be automatically instantiated for each process space instance. | |||||
*/ | |||||
#define VPS_NAME(n) vps_entry_##n | |||||
#define VPS_DECLARE(t, n) extern t VPS_NAME(n) | |||||
#define VPS_DEFINE(t, n) t VPS_NAME(n) __section(VPS_SETNAME) __used | |||||
#define _VPS_PTR(b, n) (__typeof(VPS_NAME(n))*) \ | |||||
((b) + (uintptr_t)&VPS_NAME(n)) | |||||
#define _VPS(b, n) (*_VPS_PTR(b, n)) | |||||
/* | |||||
* Virtualized global variable accessor macros. | |||||
*/ | |||||
#define VPS_VPS_PTR(vps, n) _VPS_PTR((vps)->vps_data_base, n) | |||||
#define VPS_VPS(vps, n) (*VPS_VPS_PTR((vps), n)) | |||||
#define VPS_PTR(n) VPS_VPS_PTR(curvps, n) | |||||
#define VPS(n) VPS_VPS(curvps, n) | |||||
/* | |||||
* Virtual process space allocator interfaces from the kernel linker. | |||||
*/ | |||||
void *vps_data_alloc(int size); | |||||
void vps_data_copy(void *start, int size); | |||||
void vps_data_free(void *start_arg, int size); | |||||
/* | |||||
* Virtual sysinit mechanism, allowing process space components to declare | |||||
* startup and shutdown methods to be run when virtual process space | |||||
* instances are created and destroyed. | |||||
*/ | |||||
#include <sys/kernel.h> | |||||
/* | |||||
* SYSINIT/SYSUNINIT variants that provide per-vps constructors and | |||||
* destructors. | |||||
*/ | |||||
struct vps_sysinit { | |||||
enum sysinit_sub_id subsystem; | |||||
enum sysinit_elem_order order; | |||||
sysinit_cfunc_t func; | |||||
const void *arg; | |||||
TAILQ_ENTRY(vps_sysinit) link; | |||||
}; | |||||
#define VPS_SYSINIT(ident, subsystem, order, func, arg) \ | |||||
static struct vps_sysinit ident ## _vps_init = { \ | |||||
subsystem, \ | |||||
order, \ | |||||
(sysinit_cfunc_t)(sysinit_nfunc_t)func, \ | |||||
(arg) \ | |||||
}; \ | |||||
SYSINIT(vps_init_ ## ident, subsystem, order, \ | |||||
vps_register_sysinit, &ident ## _vps_init); \ | |||||
SYSUNINIT(vps_init_ ## ident, subsystem, order, \ | |||||
vps_deregister_sysinit, &ident ## _vps_init) | |||||
#define VPS_SYSUNINIT(ident, subsystem, order, func, arg) \ | |||||
static struct vps_sysinit ident ## _vps_uninit = { \ | |||||
subsystem, \ | |||||
order, \ | |||||
(sysinit_cfunc_t)(sysinit_nfunc_t)func, \ | |||||
(arg) \ | |||||
}; \ | |||||
SYSINIT(vps_uninit_ ## ident, subsystem, order, \ | |||||
vps_register_sysuninit, &ident ## _vps_uninit); \ | |||||
SYSUNINIT(vps_uninit_ ## ident, subsystem, order, \ | |||||
vps_deregister_sysuninit, &ident ## _vps_uninit) | |||||
/* | |||||
* Run per-vps sysinits or sysuninits during vps creation/destruction. | |||||
*/ | |||||
void vps_sysinit(void); | |||||
void vps_sysuninit(void); | |||||
/* | |||||
* Interfaces for managing per-vps constructors and destructors. | |||||
*/ | |||||
void vps_register_sysinit(void *arg); | |||||
void vps_register_sysuninit(void *arg); | |||||
void vps_deregister_sysinit(void *arg); | |||||
void vps_deregister_sysuninit(void *arg); | |||||
/* | |||||
* EVENTHANDLER(9) extensions. | |||||
*/ | |||||
#include <sys/eventhandler.h> | |||||
void vps_global_eventhandler_iterator_func(void *, ...); | |||||
#define VPS_GLOBAL_EVENTHANDLER_REGISTER_TAG(tag, name, func, arg, priority) \ | |||||
do { \ | |||||
if (IS_DEFAULT_VPS(curvps)) { \ | |||||
(tag) = vimage_eventhandler_register(NULL, #name, func, \ | |||||
arg, priority, \ | |||||
vps_global_eventhandler_iterator_func); \ | |||||
} \ | |||||
} while(0) | |||||
#define VPS_GLOBAL_EVENTHANDLER_REGISTER(name, func, arg, priority) \ | |||||
do { \ | |||||
if (IS_DEFAULT_VPS(curvps)) { \ | |||||
vimage_eventhandler_register(NULL, #name, func, \ | |||||
arg, priority, \ | |||||
vps_global_eventhandler_iterator_func); \ | |||||
} \ | |||||
} while(0) | |||||
#else /* !VIMAGE */ | |||||
/* | |||||
* Various virtual process space macros compile to no-ops without VIMAGE. | |||||
*/ | |||||
#define curvps NULL | |||||
#define VPS_ASSERT(exp, msg) | |||||
#define CURVPS_SET(arg) | |||||
#define CURVPS_SET_QUIET(arg) | |||||
#define CURVPS_RESTORE() | |||||
#define VPS_LIST_RLOCK() | |||||
#define VPS_LIST_RLOCK_NOSLEEP() | |||||
#define VPS_LIST_RUNLOCK() | |||||
#define VPS_LIST_RUNLOCK_NOSLEEP() | |||||
#define VPS_ITERATOR_DECL(arg) | |||||
#define VPS_FOREACH(arg) | |||||
#define IS_DEFAULT_VPS(arg) 1 | |||||
#define CRED_TO_VPS(cr) NULL | |||||
#define TD_TO_VPS(td) NULL | |||||
#define P_TO_VPS(p) NULL | |||||
/* | |||||
* Versions of the vps macros that compile to normal global variables and | |||||
* standard sysctl definitions. | |||||
*/ | |||||
#define VPS_NAME(n) n | |||||
#define VPS_DECLARE(t, n) extern t n | |||||
#define VPS_DEFINE(t, n) t n | |||||
#define _VPS_PTR(b, n) &VPS_NAME(n) | |||||
/* | |||||
* Virtualized global variable accessor macros. | |||||
*/ | |||||
#define VPS_VPS_PTR(vps, n) (&(n)) | |||||
#define VPS_VPS(vps, n) (n) | |||||
#define VPS_PTR(n) (&(n)) | |||||
#define VPS(n) (n) | |||||
/* | |||||
* When VIMAGE isn't compiled into the kernel, VPS_SYSINIT/VPS_SYSUNINIT | |||||
* map into normal sysinits, which have the same ordering properties. | |||||
*/ | |||||
#define VPS_SYSINIT(ident, subsystem, order, func, arg) \ | |||||
SYSINIT(ident, subsystem, order, func, arg) | |||||
#define VPS_SYSUNINIT(ident, subsystem, order, func, arg) \ | |||||
SYSUNINIT(ident, subsystem, order, func, arg) | |||||
/* | |||||
* Without VIMAGE revert to the default implementation. | |||||
*/ | |||||
#define VPS_GLOBAL_EVENTHANDLER_REGISTER_TAG(tag, name, func, arg, priority) \ | |||||
(tag) = eventhandler_register(NULL, #name, func, arg, priority) | |||||
#define VPS_GLOBAL_EVENTHANDLER_REGISTER(name, func, arg, priority) \ | |||||
eventhandler_register(NULL, #name, func, arg, priority) | |||||
#endif /* VIMAGE */ | |||||
#endif /* _KERNEL */ | |||||
#endif /* !_SYS_VPS_H_ */ |