1 /* 2 * Copyright (C) 2015 Imagination Technologies 3 * Author: Alex Smith <alex.smith@imgtec.com> 4 * 5 * This program is free software; you can redistribute it and/or modify it 6 * under the terms of the GNU General Public License as published by the 7 * Free Software Foundation; either version 2 of the License, or (at your 8 * option) any later version. 9 */ 10 11 #ifndef __ASM_VDSO_H 12 #define __ASM_VDSO_H 13 14 #include <linux/mm_types.h> 15 16 #include <asm/barrier.h> 17 18 /** 19 * struct mips_vdso_image - Details of a VDSO image. 20 * @data: Pointer to VDSO image data (page-aligned). 21 * @size: Size of the VDSO image data (page-aligned). 22 * @off_sigreturn: Offset of the sigreturn() trampoline. 23 * @off_rt_sigreturn: Offset of the rt_sigreturn() trampoline. 24 * @mapping: Special mapping structure. 25 * 26 * This structure contains details of a VDSO image, including the image data 27 * and offsets of certain symbols required by the kernel. It is generated as 28 * part of the VDSO build process, aside from the mapping page array, which is 29 * populated at runtime. 30 */ 31 struct mips_vdso_image { 32 void *data; 33 unsigned long size; 34 35 unsigned long off_sigreturn; 36 unsigned long off_rt_sigreturn; 37 38 struct vm_special_mapping mapping; 39 }; 40 41 /* 42 * The following structures are auto-generated as part of the build for each 43 * ABI by genvdso, see arch/mips/vdso/Makefile. 44 */ 45 46 extern struct mips_vdso_image vdso_image; 47 48 #ifdef CONFIG_MIPS32_O32 49 extern struct mips_vdso_image vdso_image_o32; 50 #endif 51 52 #ifdef CONFIG_MIPS32_N32 53 extern struct mips_vdso_image vdso_image_n32; 54 #endif 55 56 /** 57 * union mips_vdso_data - Data provided by the kernel for the VDSO. 58 * @xtime_sec: Current real time (seconds part). 59 * @xtime_nsec: Current real time (nanoseconds part, shifted). 60 * @wall_to_mono_sec: Wall-to-monotonic offset (seconds part). 61 * @wall_to_mono_nsec: Wall-to-monotonic offset (nanoseconds part). 62 * @seq_count: Counter to synchronise updates (odd = updating). 63 * @cs_shift: Clocksource shift value. 64 * @clock_mode: Clocksource to use for time functions. 65 * @cs_mult: Clocksource multiplier value. 66 * @cs_cycle_last: Clock cycle value at last update. 67 * @cs_mask: Clocksource mask value. 68 * @tz_minuteswest: Minutes west of Greenwich (from timezone). 69 * @tz_dsttime: Type of DST correction (from timezone). 70 * 71 * This structure contains data needed by functions within the VDSO. It is 72 * populated by the kernel and mapped read-only into user memory. The time 73 * fields are mirrors of internal data from the timekeeping infrastructure. 74 * 75 * Note: Care should be taken when modifying as the layout must remain the same 76 * for both 64- and 32-bit (for 32-bit userland on 64-bit kernel). 77 */ 78 union mips_vdso_data { 79 struct { 80 u64 xtime_sec; 81 u64 xtime_nsec; 82 u64 wall_to_mono_sec; 83 u64 wall_to_mono_nsec; 84 u32 seq_count; 85 u32 cs_shift; 86 u8 clock_mode; 87 u32 cs_mult; 88 u64 cs_cycle_last; 89 u64 cs_mask; 90 s32 tz_minuteswest; 91 s32 tz_dsttime; 92 }; 93 94 u8 page[PAGE_SIZE]; 95 }; 96 vdso_data_read_begin(const union mips_vdso_data * data)97static inline u32 vdso_data_read_begin(const union mips_vdso_data *data) 98 { 99 u32 seq; 100 101 while (true) { 102 seq = ACCESS_ONCE(data->seq_count); 103 if (likely(!(seq & 1))) { 104 /* Paired with smp_wmb() in vdso_data_write_*(). */ 105 smp_rmb(); 106 return seq; 107 } 108 109 cpu_relax(); 110 } 111 } 112 vdso_data_read_retry(const union mips_vdso_data * data,u32 start_seq)113static inline bool vdso_data_read_retry(const union mips_vdso_data *data, 114 u32 start_seq) 115 { 116 /* Paired with smp_wmb() in vdso_data_write_*(). */ 117 smp_rmb(); 118 return unlikely(data->seq_count != start_seq); 119 } 120 vdso_data_write_begin(union mips_vdso_data * data)121static inline void vdso_data_write_begin(union mips_vdso_data *data) 122 { 123 ++data->seq_count; 124 125 /* Ensure sequence update is written before other data page values. */ 126 smp_wmb(); 127 } 128 vdso_data_write_end(union mips_vdso_data * data)129static inline void vdso_data_write_end(union mips_vdso_data *data) 130 { 131 /* Ensure data values are written before updating sequence again. */ 132 smp_wmb(); 133 ++data->seq_count; 134 } 135 136 #endif /* __ASM_VDSO_H */ 137