1 /* 2 * Copyright (c) 2014,2019 The DragonFly Project. All rights reserved. 3 * 4 * This code is derived from software contributed to The DragonFly Project 5 * by Matthew Dillon <dillon@backplane.com> 6 * 7 * Redistribution and use in source and binary forms, with or without 8 * modification, are permitted provided that the following conditions 9 * are met: 10 * 11 * 1. Redistributions of source code must retain the above copyright 12 * notice, this list of conditions and the following disclaimer. 13 * 2. Redistributions in binary form must reproduce the above copyright 14 * notice, this list of conditions and the following disclaimer in 15 * the documentation and/or other materials provided with the 16 * distribution. 17 * 3. Neither the name of The DragonFly Project nor the names of its 18 * contributors may be used to endorse or promote products derived 19 * from this software without specific, prior written permission. 20 * 21 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 22 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 23 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS 24 * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE 25 * COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, 26 * INCIDENTAL, SPECIAL, EXEMPLARY OR CONSEQUENTIAL DAMAGES (INCLUDING, 27 * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 28 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED 29 * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 30 * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT 31 * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 32 * SUCH DAMAGE. 33 */ 34 35 #include "namespace.h" 36 #include <sys/cdefs.h> 37 #include <sys/types.h> 38 #include <sys/syscall.h> 39 #include <sys/upmap.h> 40 #include <sys/time.h> 41 #include <sys/mman.h> 42 #include <sys/fcntl.h> 43 #include <errno.h> 44 #include <stdio.h> 45 #include <unistd.h> 46 #include <time.h> 47 #include <pthread.h> 48 #include "un-namespace.h" 49 #include "libc_private.h" 50 #include "upmap.h" 51 52 /* 53 * kpmap - Global user/kernel shared map (RO) 54 * upmap - Per-process user/kernel shared map (RW) 55 * lpmap - Per-thread user/kernel shared map (RW) 56 */ 57 static pthread_mutex_t ukpmap_lock; 58 static ukpheader_t *__kpmap_headers; 59 static ukpheader_t *__upmap_headers; 60 __thread ukpheader_t *__lpmap_headers TLS_ATTRIBUTE; 61 __thread uint32_t *__lpmap_blockallsigs TLS_ATTRIBUTE; 62 63 static __thread int lpmap_ok; 64 static int kpmap_ok; 65 static int upmap_ok; 66 static pthread_once_t upmap_once = PTHREAD_ONCE_INIT; 67 68 69 /* 70 * Map the requested data item from the user-kernel global shared mmap 71 * 72 * *state is set to -1 on failure, else it is left alone. 73 * *datap is set to a pointer to the item on success, else it is left alone. 74 * If type == 0 this function finalizes state, setting it to 1 if it is 0. 75 */ 76 void 77 __kpmap_map(void *datap, int *state, uint16_t type) 78 { 79 ukpheader_t *head; 80 81 if (__isthreaded) 82 _pthread_mutex_lock(&ukpmap_lock); 83 84 if (kpmap_ok <= 0) { 85 int fd; 86 87 if (kpmap_ok < 0) 88 goto failed; 89 fd = _open("/dev/kpmap", O_RDONLY); 90 if (fd < 0) { 91 kpmap_ok = -1; 92 goto failed; 93 } 94 __kpmap_headers = mmap(NULL, KPMAP_MAPSIZE, 95 PROT_READ, MAP_SHARED | MAP_FILE, 96 fd, 0); 97 _close(fd); 98 if ((void *)__kpmap_headers == MAP_FAILED) { 99 kpmap_ok = -1; 100 goto failed; 101 } 102 kpmap_ok = 1; 103 } 104 105 /* 106 * Special case to finalize state 107 */ 108 if (type == 0) { 109 if (*state == 0) 110 *state = 1; 111 if (__isthreaded) 112 _pthread_mutex_unlock(&ukpmap_lock); 113 return; 114 } 115 116 /* 117 * Look for type. 118 */ 119 for (head = __kpmap_headers; head->type; ++head) { 120 if (head->type == type) { 121 *(void **)datap = (char *)__kpmap_headers + 122 head->offset; 123 if (__isthreaded) 124 _pthread_mutex_unlock(&ukpmap_lock); 125 return; 126 } 127 } 128 failed: 129 *state = -1; 130 if (__isthreaded) 131 _pthread_mutex_unlock(&ukpmap_lock); 132 } 133 134 /* 135 * Map the requested data item from the user-kernel per-process shared mmap 136 * 137 * *state is set to -1 on failure, else it is left alone. 138 * *datap is set to a pointer to the item on success, else it is left alone. 139 * If type == 0 this function finalizes state, setting it to 1 if it is 0. 140 */ 141 void 142 __upmap_map(void *datap, int *state, uint16_t type) 143 { 144 ukpheader_t *head; 145 146 if (__isthreaded) 147 _pthread_mutex_lock(&ukpmap_lock); 148 149 if (upmap_ok <= 0) { 150 int fd; 151 152 if (upmap_ok < 0) 153 goto failed; 154 fd = _open("/dev/upmap", O_RDWR); 155 if (fd < 0) { 156 upmap_ok = -1; 157 goto failed; 158 } 159 __upmap_headers = mmap(NULL, UPMAP_MAPSIZE, 160 PROT_READ | PROT_WRITE, 161 MAP_SHARED | MAP_FILE, 162 fd, 0); 163 _close(fd); 164 if ((void *)__upmap_headers == MAP_FAILED) { 165 upmap_ok = -1; 166 goto failed; 167 } 168 upmap_ok = 1; 169 } 170 171 /* 172 * Special case to finalize state 173 */ 174 if (type == 0) { 175 if (*state == 0) 176 *state = 1; 177 if (__isthreaded) 178 _pthread_mutex_unlock(&ukpmap_lock); 179 return; 180 } 181 182 /* 183 * Look for type. 184 */ 185 for (head = __upmap_headers; head->type; ++head) { 186 if (head->type == type) { 187 *(void **)datap = (char *)__upmap_headers + 188 head->offset; 189 if (__isthreaded) 190 _pthread_mutex_unlock(&ukpmap_lock); 191 return; 192 } 193 } 194 failed: 195 *state = -1; 196 if (__isthreaded) 197 _pthread_mutex_unlock(&ukpmap_lock); 198 } 199 200 /* 201 * Map the requested data item from the user-kernel per-thread shared mmap 202 * 203 * *state is set to -1 on failure, else it is left alone. 204 * *datap is set to a pointer to the item on success, else it is left alone. 205 * If type == 0 this function finalizes state, setting it to 1 if it is 0. 206 * 207 * WARNING! This code is used all over pthreads and must NOT make any 208 * reentrant pthreads calls until after the mapping has been 209 * set up. 210 */ 211 static pthread_key_t lpmap_key; 212 213 static void lpmap_unmap(void **datap); 214 215 void 216 __lpmap_map(void *datap, int *state, uint16_t type) 217 { 218 ukpheader_t *head; 219 220 if (lpmap_ok <= 0) { 221 int fd; 222 223 if (lpmap_ok < 0) 224 goto failed; 225 fd = _open("/dev/lpmap", O_RDWR); 226 if (fd < 0) { 227 lpmap_ok = -1; 228 goto failed; 229 } 230 __lpmap_headers = mmap(NULL, LPMAP_MAPSIZE, 231 PROT_READ | PROT_WRITE, 232 MAP_SHARED | MAP_FILE, 233 fd, 0); 234 _close(fd); 235 if ((void *)__lpmap_headers == MAP_FAILED) { 236 lpmap_ok = -1; 237 goto failed; 238 } 239 lpmap_ok = 1; 240 _pthread_setspecific(lpmap_key, &__lpmap_headers); 241 } 242 243 /* 244 * Special case to finalize state 245 */ 246 if (type == 0) { 247 if (*state == 0) 248 *state = 1; 249 return; 250 } 251 252 /* 253 * Look for type. 254 */ 255 for (head = __lpmap_headers; head->type; ++head) { 256 if (head->type == type) { 257 *(void **)datap = (char *)__lpmap_headers + 258 head->offset; 259 return; 260 } 261 } 262 failed: 263 *state = -1; 264 } 265 266 /* 267 * Cleanup thread state 268 */ 269 static void 270 lpmap_unmap(void **datap) 271 { 272 ukpheader_t *lpmap = *datap; 273 274 lpmap_ok = -1; 275 if (lpmap) { 276 __lpmap_blockallsigs = NULL; 277 *datap = NULL; 278 munmap(lpmap, LPMAP_MAPSIZE); 279 } 280 } 281 282 /* 283 * upmap initialization code, _upmap_thr_init() is called for the initial 284 * main thread by libc or pthreads, and on every thread create. We need 285 * the __lpmap_blockallsigs pointer ASAP because it is used everywhere in 286 * pthreads. 287 * 288 * If pthreads is not linked in, _pthread_once() still runs via a stub in 289 * libc, and _pthread_key_create() is a NOP. 290 * 291 * NOTE: These pthreads calls are stubs when pthreads is not linked in. 292 * The once routine will still be run once regardless. 293 */ 294 static 295 void 296 _upmap_init_once(void) 297 { 298 _pthread_key_create(&lpmap_key, (void (*)(void *))lpmap_unmap); 299 } 300 301 void 302 _upmap_thr_init(void) 303 { 304 int dummy_state = 0; 305 306 _pthread_once(&upmap_once, _upmap_init_once); 307 __lpmap_map(&__lpmap_blockallsigs, &dummy_state, LPTYPE_BLOCKALLSIGS); 308 } 309