202 lines · 5.9 KB · C
RawDownload
/* SPDX-License-Identifier: GPL-2.0 */#ifndef __VDSO_DATAPAGE_H#define __VDSO_DATAPAGE_H #ifndef __ASSEMBLER__ #include <linux/types.h> #include <uapi/linux/bits.h>#include <uapi/linux/time.h> #include <vdso/align.h>#include <vdso/bits.h>#include <vdso/cache.h>#include <vdso/page.h>#include <vdso/time.h> #ifdef CONFIG_ARCH_HAS_VDSO_TIME_DATA#include <asm/vdso/time_data.h>#elsestruct arch_vdso_time_data {};#endif #if defined(CONFIG_ARCH_HAS_VDSO_ARCH_DATA)#include <asm/vdso/arch_data.h>#elsestruct vdso_arch_data {	/* Needed for the generic code, never actually used at runtime */	char __unused;};#endif #define VDSO_BASES	(CLOCK_TAI + 1)#define VDSO_BASE_AUX	0#define VDSO_HRES	(BIT(CLOCK_REALTIME)		| \			 BIT(CLOCK_MONOTONIC)		| \			 BIT(CLOCK_BOOTTIME)		| \			 BIT(CLOCK_TAI))#define VDSO_COARSE	(BIT(CLOCK_REALTIME_COARSE)	| \			 BIT(CLOCK_MONOTONIC_COARSE))#define VDSO_RAW	(BIT(CLOCK_MONOTONIC_RAW))#define VDSO_AUX	__GENMASK(CLOCK_AUX_LAST, CLOCK_AUX) #define CS_HRES_COARSE	0#define CS_RAW		1#define CS_BASES	(CS_RAW + 1) /** * struct vdso_timestamp - basetime per clock_id * @sec:	seconds * @nsec:	nanoseconds * * There is one vdso_timestamp object in vvar for each vDSO-accelerated * clock_id. For high-resolution clocks, this encodes the time * corresponding to vdso_time_data.cycle_last. For coarse clocks this encodes * the actual time. * * To be noticed that for highres clocks nsec is left-shifted by * vdso_time_data[x].shift. */struct vdso_timestamp {	u64	sec;	u64	nsec;}; /** * struct vdso_clock - vdso per clocksource datapage representation * @seq:		timebase sequence counter * @clock_mode:		clock mode * @cycle_last:		timebase at clocksource init * @max_cycles:		maximum cycles which won't overflow 64bit multiplication * @mask:		clocksource mask * @mult:		clocksource multiplier * @shift:		clocksource shift * @basetime:		basetime per clock_id * @offset:		time namespace offset per clock_id * * See also struct vdso_time_data for basic access and ordering information as * struct vdso_clock is used there. * * @basetime is used to store the base time for the system wide time getter * VVAR page. * * @offset is used by the special time namespace VVAR pages which are * installed instead of the real VVAR page. These namespace pages must set * @seq to 1 and @clock_mode to VDSO_CLOCKMODE_TIMENS to force the code into * the time namespace slow path. The namespace aware functions retrieve the * real system wide VVAR page, read host time and add the per clock offset. * For clocks which are not affected by time namespace adjustment the * offset must be zero. */struct vdso_clock {	u32			seq; 	s32			clock_mode;	u64			cycle_last;#ifdef CONFIG_GENERIC_VDSO_OVERFLOW_PROTECT	u64			max_cycles;#endif	u64			mask;	u32			mult;	u32			shift; 	union {		struct vdso_timestamp	basetime[VDSO_BASES];		struct timens_offset	offset[VDSO_BASES];	};}; /** * struct vdso_time_data - vdso datapage representation * @arch_data:		architecture specific data (optional, defaults *			to an empty struct) * @clock_data:		clocksource related data (array) * @aux_clock_data:	auxiliary clocksource related data (array) * @tz_minuteswest:	minutes west of Greenwich * @tz_dsttime:		type of DST correction * @hrtimer_res:	hrtimer resolution * @__unused:		unused * * vdso_time_data will be accessed by 64 bit and compat code at the same time * so we should be careful before modifying this structure. * * The ordering of the struct members is optimized to have fast acces to the * often required struct members which are related to CLOCK_REALTIME and * CLOCK_MONOTONIC. This information is stored in the first cache lines. */struct vdso_time_data {	struct arch_vdso_time_data	arch_data; 	struct vdso_clock		clock_data[CS_BASES];	struct vdso_clock		aux_clock_data[MAX_AUX_CLOCKS]; 	s32				tz_minuteswest;	s32				tz_dsttime;	u32				hrtimer_res;	u32				__unused;} ____cacheline_aligned; /** * struct vdso_rng_data - vdso RNG state information * @generation:	counter representing the number of RNG reseeds * @is_ready:	boolean signaling whether the RNG is initialized */struct vdso_rng_data {	u64	generation;	u8	is_ready;}; /* * We use the hidden visibility to prevent the compiler from generating a GOT * relocation. Not only is going through a GOT useless (the entry couldn't and * must not be overridden by another library), it does not even work: the linker * cannot generate an absolute address to the data page. * * With the hidden visibility, the compiler simply generates a PC-relative * relocation, and this is what we need. */extern struct vdso_time_data vdso_u_time_data __attribute__((visibility("hidden")));extern struct vdso_rng_data vdso_u_rng_data __attribute__((visibility("hidden")));extern struct vdso_arch_data vdso_u_arch_data __attribute__((visibility("hidden"))); extern struct vdso_time_data *vdso_k_time_data;extern struct vdso_rng_data *vdso_k_rng_data;extern struct vdso_arch_data *vdso_k_arch_data; #define VDSO_ARCH_DATA_SIZE ALIGN(sizeof(struct vdso_arch_data), PAGE_SIZE)#define VDSO_ARCH_DATA_PAGES (VDSO_ARCH_DATA_SIZE >> PAGE_SHIFT) enum vdso_pages {	VDSO_TIME_PAGE_OFFSET,	VDSO_TIMENS_PAGE_OFFSET,	VDSO_RNG_PAGE_OFFSET,	VDSO_ARCH_PAGES_START,	VDSO_ARCH_PAGES_END = VDSO_ARCH_PAGES_START + VDSO_ARCH_DATA_PAGES - 1,	VDSO_NR_PAGES}; #else /* !__ASSEMBLER__ */ #ifdef CONFIG_VDSO_GETRANDOM#define __vdso_u_rng_data	PROVIDE(vdso_u_rng_data = vdso_u_data + 2 * PAGE_SIZE);#else#define __vdso_u_rng_data#endif #ifdef CONFIG_ARCH_HAS_VDSO_ARCH_DATA#define __vdso_u_arch_data	PROVIDE(vdso_u_arch_data = vdso_u_data + 3 * PAGE_SIZE);#else#define __vdso_u_arch_data#endif #define VDSO_VVAR_SYMS						\	PROVIDE(vdso_u_data = . - __VDSO_PAGES * PAGE_SIZE);	\	PROVIDE(vdso_u_time_data = vdso_u_data);		\	__vdso_u_rng_data					\	__vdso_u_arch_data					\  #endif /* !__ASSEMBLER__ */ #endif /* __VDSO_DATAPAGE_H */