| Commit | Line | Data |
|---|---|---|
| f4ef6a57 | 1 | /* |
| f4ef6a57 | 2 | * OS-dependent routines. This file (along with os.h) exports an |
| 3 | * OS-independent interface to the operating system VM facilities. | |
| 4 | * Suprisingly, this interface looks a lot like the Mach interface | |
| 5 | * (but simpler in some places). For some operating systems, a subset | |
| 6 | * of these functions will have to be emulated. | |
| 7 | * | |
| 8 | * This is an experimental Solaris version based on sunos-os.c but | |
| 9 | * without the VM hack of unmapped pages for the GC trigger which | |
| 10 | * caused trouble when system calls were passed unmapped pages. | |
| 11 | * | |
| 12 | */ | |
| 13 | ||
| f4ef6a57 | 14 | |
| 15 | #include <stdio.h> | |
| 34b793ce | 16 | #include <stdlib.h> |
| f4ef6a57 | 17 | #include <signal.h> |
| 34b793ce | 18 | #include <fcntl.h> |
| f4ef6a57 | 19 | #include <sys/file.h> |
| 20 | ||
| 8946c553 | 21 | #include <stropts.h> |
| 22 | #include <termios.h> | |
| f4ef6a57 | 23 | #include <unistd.h> |
| 24 | #include <errno.h> | |
| 25 | #include <sys/param.h> | |
| 49fdb025 | 26 | |
| 27 | #include <dlfcn.h> | |
| 28 | ||
| 2bf5d5f4 | 29 | #include <sys/resource.h> |
| 30 | ||
| af867264 | 31 | #if defined(GENCGC) |
| 32 | #include "lisp.h" | |
| 6438e048 | 33 | /* Need struct code defined to get rid of warning from gencgc.h */ |
| 34 | #include "internals.h" | |
| af867264 | 35 | #include "gencgc.h" |
| 36 | #endif | |
| 37 | ||
| f4ef6a57 | 38 | #include "os.h" |
| 39 | ||
| 015a25b6 | 40 | #include "interrupt.h" |
| 41 | ||
| b34e1730 | 42 | /* To get dynamic_0_space and friends */ |
| 43 | #include "globals.h" | |
| 44 | /* To get memory map */ | |
| 45 | #include "sparc-validate.h" | |
| 46 | ||
| 49fdb025 | 47 | /* For type_ListPointer and NIL */ |
| 48 | #include "internals.h" | |
| 49 | ||
| f4ef6a57 | 50 | #define EMPTYFILE "/tmp/empty" |
| 51 | #define ZEROFILE "/dev/zero" | |
| 52 | ||
| f4ef6a57 | 53 | /* ---------------------------------------------------------------- */ |
| 54 | ||
| f4ef6a57 | 55 | |
| 9a8c1c2f | 56 | long os_vm_page_size = (-1); |
| 57 | static long os_real_page_size = (-1); | |
| f4ef6a57 | 58 | |
| 9a8c1c2f | 59 | static int zero_fd = (-1); |
| f4ef6a57 | 60 | |
| 9a8c1c2f | 61 | static os_vm_size_t real_page_size_difference = 0; |
| f4ef6a57 | 62 | |
| 84551d3e | 63 | static void |
| 9a8c1c2f | 64 | os_init_bailout(char *arg) |
| f4ef6a57 | 65 | { |
| 66 | char buf[500]; | |
| 9a8c1c2f | 67 | |
| 68 | sprintf(buf, "os_init: %s", arg); | |
| f4ef6a57 | 69 | perror(buf); |
| 70 | exit(1); | |
| 71 | } | |
| 72 | ||
| 84551d3e | 73 | void |
| dafb9e03 | 74 | os_init0(const char *argv[], const char *envp[]) |
| 75 | {} | |
| 76 | ||
| 77 | void | |
| 0f0aed07 | 78 | os_init(const char *argv[], const char *envp[]) |
| f4ef6a57 | 79 | { |
| 9a8c1c2f | 80 | zero_fd = open(ZEROFILE, O_RDONLY); |
| 81 | if (zero_fd < 0) | |
| f4ef6a57 | 82 | os_init_bailout(ZEROFILE); |
| 83 | ||
| 84 | os_vm_page_size = os_real_page_size = sysconf(_SC_PAGESIZE); | |
| 85 | ||
| 9a8c1c2f | 86 | if (os_vm_page_size > OS_VM_DEFAULT_PAGESIZE) { |
| 87 | fprintf(stderr, "os_init: Pagesize too large (%ld > %d)\n", | |
| 88 | os_vm_page_size, OS_VM_DEFAULT_PAGESIZE); | |
| f4ef6a57 | 89 | exit(1); |
| 9a8c1c2f | 90 | } else { |
| f4ef6a57 | 91 | /* |
| 92 | * we do this because there are apparently dependencies on | |
| 93 | * the pagesize being OS_VM_DEFAULT_PAGESIZE somewhere... | |
| 94 | * but since the OS doesn't know we're using this restriction, | |
| 95 | * we have to grovel around a bit to enforce it, thus anything | |
| 96 | * that uses real_page_size_difference. | |
| 97 | */ | |
| 9a8c1c2f | 98 | real_page_size_difference = OS_VM_DEFAULT_PAGESIZE - os_vm_page_size; |
| 99 | os_vm_page_size = OS_VM_DEFAULT_PAGESIZE; | |
| f4ef6a57 | 100 | } |
| 101 | } | |
| 102 | ||
| 103 | /* ---------------------------------------------------------------- */ | |
| 104 | ||
| 9a8c1c2f | 105 | os_vm_address_t os_validate(os_vm_address_t addr, os_vm_size_t len) |
| f4ef6a57 | 106 | { |
| 9a8c1c2f | 107 | int flags = MAP_PRIVATE | MAP_NORESERVE; |
| f4ef6a57 | 108 | |
| 9a8c1c2f | 109 | if (addr) |
| 110 | flags |= MAP_FIXED; | |
| f4ef6a57 | 111 | |
| 972fe2bf | 112 | addr = (os_vm_address_t) mmap((void *) addr, len, OS_VM_PROT_ALL, flags, zero_fd, 0); |
| 113 | ||
| 114 | if (addr == (os_vm_address_t) - 1) { | |
| 9a8c1c2f | 115 | perror("mmap"); |
| 972fe2bf | 116 | addr = NULL; |
| 117 | } | |
| f4ef6a57 | 118 | |
| 9a8c1c2f | 119 | return addr; |
| f4ef6a57 | 120 | } |
| 121 | ||
| 122 | void | |
| 123 | os_invalidate(os_vm_address_t addr, os_vm_size_t len) | |
| 124 | { | |
| 9a8c1c2f | 125 | if (munmap((void *) addr, len) == -1) |
| 126 | perror("munmap"); | |
| f4ef6a57 | 127 | } |
| 128 | ||
| 129 | os_vm_address_t | |
| 130 | os_map(int fd, int offset, os_vm_address_t addr, os_vm_size_t len) | |
| 131 | { | |
| 9a8c1c2f | 132 | if ( |
| 133 | (addr = | |
| 134 | (os_vm_address_t) mmap((void *) addr, len, OS_VM_PROT_ALL, | |
| 135 | MAP_PRIVATE | MAP_FIXED, fd, | |
| 136 | (off_t) offset)) == (os_vm_address_t) - 1) | |
| 137 | perror("mmap"); | |
| 138 | ||
| 139 | return addr; | |
| f4ef6a57 | 140 | } |
| 141 | ||
| 84551d3e | 142 | void |
| 143 | os_flush_icache(os_vm_address_t address, os_vm_size_t length) | |
| f4ef6a57 | 144 | { |
| 6438e048 | 145 | #ifndef i386 |
| 9a8c1c2f | 146 | static int flushit = -1; |
| 147 | ||
| 148 | /* | |
| 149 | * On some systems, iflush needs to be emulated in the kernel | |
| 150 | * On those systems, it isn't necessary | |
| 151 | * Call getenv() only once. | |
| 152 | */ | |
| 153 | if (flushit == -1) | |
| 154 | flushit = getenv("CMUCL_NO_SPARC_IFLUSH") == 0; | |
| 155 | ||
| 156 | if (flushit) { | |
| 157 | static int traceit = -1; | |
| 158 | ||
| 159 | if (traceit == -1) | |
| 160 | traceit = getenv("CMUCL_TRACE_SPARC_IFLUSH") != 0; | |
| 161 | ||
| 162 | if (traceit) | |
| 163 | fprintf(stderr, ";;;iflush %p - %lx\n", (void *) address, length); | |
| 164 | flush_icache((unsigned int *) address, length); | |
| 165 | } | |
| 6438e048 | 166 | #endif |
| f4ef6a57 | 167 | } |
| 168 | ||
| 169 | void | |
| 170 | os_protect(os_vm_address_t address, os_vm_size_t length, os_vm_prot_t prot) | |
| 171 | { | |
| 9a8c1c2f | 172 | if (mprotect((void *) address, length, prot) == -1) |
| 173 | perror("mprotect"); | |
| f4ef6a57 | 174 | } |
| 175 | ||
| 84551d3e | 176 | static boolean |
| 177 | in_range_p(os_vm_address_t a, lispobj sbeg, size_t slen) | |
| f4ef6a57 | 178 | { |
| 9a8c1c2f | 179 | char *beg = (char *) sbeg; |
| 180 | char *end = (char *) sbeg + slen; | |
| 181 | char *adr = (char *) a; | |
| 182 | ||
| 183 | return (adr >= beg && adr < end); | |
| 84551d3e | 184 | } |
| 185 | ||
| 9a8c1c2f | 186 | boolean valid_addr(os_vm_address_t addr) |
| 84551d3e | 187 | { |
| 9a8c1c2f | 188 | /* Stolen from Linux-os.c */ |
| 189 | os_vm_address_t newaddr; | |
| 190 | ||
| 191 | newaddr = os_trunc_to_page(addr); | |
| 192 | ||
| 193 | /* Just assume address is valid if it lies within one of the known | |
| 194 | spaces. (Unlike sunos-os which keeps track of every valid page.) */ | |
| 44a8f0c7 RT |
195 | return (in_range_p(addr, READ_ONLY_SPACE_START, read_only_space_size) |
| 196 | || in_range_p(addr, STATIC_SPACE_START, static_space_size) | |
| 9a8c1c2f | 197 | || in_range_p(addr, DYNAMIC_0_SPACE_START, dynamic_space_size) |
| 32786b6c | 198 | #ifndef GENCGC |
| 9a8c1c2f | 199 | || in_range_p(addr, DYNAMIC_1_SPACE_START, dynamic_space_size) |
| 32786b6c | 200 | #endif |
| 44a8f0c7 RT |
201 | || in_range_p(addr, CONTROL_STACK_START, control_stack_size) |
| 202 | || in_range_p(addr, BINDING_STACK_START, binding_stack_size)); | |
| f4ef6a57 | 203 | } |
| 204 | ||
| 205 | /* ---------------------------------------------------------------- */ | |
| 206 | ||
| f4ef6a57 | 207 | /* |
| d9db6d61 | 208 | * Running into the gc trigger page will end up here... |
| f4ef6a57 | 209 | */ |
| af867264 | 210 | #if defined(GENCGC) |
| 8cbbd24d | 211 | |
| 9a8c1c2f | 212 | void |
| 213 | segv_handle_now(HANDLER_ARGS) | |
| 8cbbd24d | 214 | { |
| 9a8c1c2f | 215 | interrupt_handle_now(signal, code, context); |
| 8cbbd24d | 216 | } |
| 217 | ||
| 6438e048 | 218 | void real_segv_handler(HANDLER_ARGS) |
| 219 | { | |
| 220 | segv_handle_now(signal, code, context); | |
| 221 | } | |
| 222 | ||
| 9a8c1c2f | 223 | void |
| 224 | segv_handler(HANDLER_ARGS) | |
| af867264 | 225 | { |
| cba6f60b RT |
226 | os_context_t *os_context = (os_context_t *) context; |
| 227 | ||
| 9a8c1c2f | 228 | caddr_t addr = code->si_addr; |
| af867264 | 229 | |
| 9a8c1c2f | 230 | SAVE_CONTEXT(); |
| 231 | ||
| af867264 | 232 | #ifdef RED_ZONE_HIT |
| 9a8c1c2f | 233 | if (os_control_stack_overflow(addr, context)) |
| 234 | return; | |
| af867264 | 235 | #endif |
| 236 | ||
| 97083c55 | 237 | if (gc_write_barrier(code->si_addr)) |
| 238 | return; | |
| af867264 | 239 | |
| 9a8c1c2f | 240 | /* |
| 241 | * Could be a C stack overflow. Let's check | |
| 242 | */ | |
| 243 | ||
| 244 | { | |
| 245 | struct rlimit rlimit; | |
| 246 | ||
| 247 | if (getrlimit(RLIMIT_STACK, &rlimit) == 0) { | |
| 248 | /* The stack top here is based on the notes in sparc-validate.h */ | |
| 249 | char *stack_top = (char *) 0xffbf0000; | |
| 250 | char *stack_bottom; | |
| 251 | ||
| 252 | stack_bottom = stack_top - rlimit.rlim_cur; | |
| 253 | ||
| 254 | /* | |
| 255 | * Add a fudge factor. Don't know why, but we get the signal | |
| 256 | * sometime after the bottom of the stack, as computed above, | |
| 257 | * has been reached. (It seems to be 8K, so we use something | |
| 258 | * larger.) | |
| 259 | */ | |
| 260 | ||
| 261 | stack_bottom -= 16384; | |
| 262 | ||
| 263 | if ((stack_bottom <= addr) && (addr <= stack_top)) { | |
| 264 | fprintf(stderr, | |
| 265 | "\nsegv_handler: C stack overflow. Try increasing stack limit (%ld).\n", | |
| 266 | rlimit.rlim_cur); | |
| 267 | ||
| a9045c5e | 268 | segv_handle_now(signal, code, context); |
| 9a8c1c2f | 269 | } |
| 270 | } else { | |
| 271 | perror("getrlimit"); | |
| 272 | } | |
| 273 | } | |
| 274 | ||
| 275 | /* a *real* protection fault */ | |
| f025b1f0 | 276 | fprintf(stderr, "segv_handler: Real protection violation: %p, PC = %p\n", |
| 277 | addr, | |
| cba6f60b | 278 | os_context->uc_mcontext.gregs[1]); |
| 6438e048 | 279 | real_segv_handler(signal, code, context); |
| af867264 | 280 | } |
| 281 | #else | |
| 84551d3e | 282 | void |
| 283 | segv_handler(HANDLER_ARGS) | |
| f4ef6a57 | 284 | { |
| 9a8c1c2f | 285 | caddr_t addr = code->si_addr; |
| d9db6d61 | 286 | |
| 9a8c1c2f | 287 | SAVE_CONTEXT(); |
| 72f0aa1e | 288 | |
| 289 | #ifdef RED_ZONE_HIT | |
| 9a8c1c2f | 290 | if (os_control_stack_overflow(addr, context)) |
| 291 | return; | |
| 72f0aa1e | 292 | #endif |
| 293 | ||
| 9a8c1c2f | 294 | if (!interrupt_maybe_gc(signal, code, context)) { |
| 295 | /* a *real* protection fault */ | |
| 296 | fprintf(stderr, "segv_handler: Real protection violation: 0x%08x\n", | |
| 297 | addr); | |
| 298 | interrupt_handle_now(signal, code, context); | |
| 299 | } | |
| f4ef6a57 | 300 | } |
| af867264 | 301 | #endif |
| f4ef6a57 | 302 | |
| 84551d3e | 303 | void |
| b8d0dfaf | 304 | os_install_interrupt_handlers(void) |
| f4ef6a57 | 305 | { |
| 9a8c1c2f | 306 | interrupt_install_low_level_handler(SIGSEGV, segv_handler); |
| f4ef6a57 | 307 | } |
| 308 | ||
| 309 | ||
| 84551d3e | 310 | /* function definitions for register lvalues */ |
| f4ef6a57 | 311 | |
| 6438e048 | 312 | #ifndef i386 |
| 84551d3e | 313 | int * |
| 314 | solaris_register_address(struct ucontext *context, int reg) | |
| f4ef6a57 | 315 | { |
| 316 | if (reg == 0) { | |
| 317 | static int zero; | |
| 318 | ||
| 319 | zero = 0; | |
| 320 | ||
| 321 | return &zero; | |
| 322 | } else if (reg < 16) { | |
| 9a8c1c2f | 323 | return &context->uc_mcontext.gregs[reg + 3]; |
| f4ef6a57 | 324 | } else if (reg < 32) { |
| 9a8c1c2f | 325 | int *sp = (int *) context->uc_mcontext.gregs[REG_SP]; |
| 326 | ||
| 327 | return &sp[reg - 16]; | |
| f4ef6a57 | 328 | } else |
| 329 | return 0; | |
| 330 | } | |
| 6438e048 | 331 | #endif |
| 9a8c1c2f | 332 | |
| f4ef6a57 | 333 | /* function defintions for backward compatibilty and static linking */ |
| 334 | ||
| 335 | /* For now we put in some porting functions */ | |
| 336 | ||
| f4ef6a57 | 337 | int |
| 338 | sigblock(int mask) | |
| 339 | { | |
| 340 | sigset_t old, new; | |
| 341 | ||
| 342 | sigemptyset(&new); | |
| 343 | new.__sigbits[0] = mask; | |
| 344 | ||
| 345 | sigprocmask(SIG_BLOCK, &new, &old); | |
| 346 | ||
| 347 | return old.__sigbits[0]; | |
| 348 | } | |
| 349 | ||
| f4ef6a57 | 350 | int |
| 351 | sigsetmask(int mask) | |
| 352 | { | |
| 353 | sigset_t old, new; | |
| 354 | ||
| 355 | sigemptyset(&new); | |
| 356 | new.__sigbits[0] = mask; | |
| 357 | ||
| 358 | sigprocmask(SIG_SETMASK, &new, &old); | |
| 359 | ||
| 360 | return old.__sigbits[0]; | |
| 361 | ||
| 362 | } | |
| b34e1730 | 363 | |
| 8946c553 | 364 | int |
| 365 | openpty(int *amaster, int *aslave, char *name, struct termios *termp, | |
| 366 | struct winsize *winp) | |
| 367 | { | |
| 368 | char *slavename; | |
| 369 | int masterfd, slavefd; | |
| 370 | ||
| 371 | if ((masterfd = open("/dev/ptmx", O_RDWR)) == -1) | |
| 372 | return -1; | |
| 373 | if (grantpt(masterfd) == -1) { | |
| 374 | close(masterfd); | |
| 375 | return -1; | |
| 376 | } | |
| 377 | if (unlockpt(masterfd) == -1) { | |
| 378 | close(masterfd); | |
| 379 | return -1; | |
| 380 | } | |
| 381 | if ((slavename = ptsname(masterfd)) == NULL) { | |
| 382 | close(masterfd); | |
| 383 | return -1; | |
| 384 | } | |
| 385 | if ((slavefd = open(slavename, O_RDWR | O_NOCTTY)) == -1) { | |
| 386 | close(masterfd); | |
| 387 | return -1; | |
| 388 | } | |
| 389 | *amaster = masterfd; | |
| 390 | *aslave = slavefd; | |
| 391 | ioctl(*aslave, I_PUSH, "ptem"); | |
| 392 | ioctl(*aslave, I_PUSH, "ldterm"); | |
| 393 | ioctl(*aslave, I_PUSH, "ttcompat"); | |
| 394 | if (name) | |
| 395 | strcpy(name, slavename); | |
| 396 | if (termp) | |
| 397 | tcsetattr(slavefd, TCSAFLUSH, termp); | |
| 398 | if (winp) | |
| 399 | ioctl(slavefd, TIOCSWINSZ, (char *) winp); | |
| 400 | return 0; | |
| 401 | } | |
| 402 | ||
| 9a8c1c2f | 403 | os_vm_address_t round_up_sparse_size(os_vm_address_t addr) |
| b34e1730 | 404 | { |
| 9a8c1c2f | 405 | return (addr + SPARSE_BLOCK_SIZE - 1) & ~SPARSE_SIZE_MASK; |
| b34e1730 | 406 | } |
| 407 | ||
| 408 | /* | |
| 409 | * An array of the start of the spaces which should have holes placed | |
| 410 | * after them. Must not include the dynamic spaces because the size | |
| 411 | * of the dynamic space can be controlled from the command line. | |
| 412 | */ | |
| 9a8c1c2f | 413 | static os_vm_address_t spaces[] = { |
| 414 | READ_ONLY_SPACE_START, STATIC_SPACE_START, | |
| 415 | BINDING_STACK_START, CONTROL_STACK_START | |
| b34e1730 | 416 | }; |
| 417 | ||
| 418 | /* | |
| 419 | ||
| 420 | * The corresponding array for the size of each space. Be sure that | |
| 421 | * the spaces and holes don't overlap! The sizes MUST be on | |
| 422 | * SPARSE_BLOCK_SIZE boundaries. | |
| 423 | ||
| 424 | */ | |
| 44a8f0c7 RT |
425 | static unsigned long *space_size[] = { |
| 426 | &read_only_space_size, &static_space_size, | |
| 427 | &binding_stack_size, &control_stack_size | |
| b34e1730 | 428 | }; |
| 429 | ||
| 430 | /* | |
| 431 | * The size of the hole to make. It should be strictly smaller than | |
| 432 | * SPARSE_BLOCK_SIZE. | |
| 433 | */ | |
| 434 | ||
| 435 | #define HOLE_SIZE 0x2000 | |
| 436 | ||
| 9a8c1c2f | 437 | void |
| 438 | make_holes(void) | |
| b34e1730 | 439 | { |
| 9a8c1c2f | 440 | int k; |
| 441 | os_vm_address_t hole; | |
| 442 | ||
| 443 | /* Make holes of the appropriate size for desired spaces */ | |
| 444 | ||
| 445 | for (k = 0; k < sizeof(spaces) / sizeof(spaces[0]); ++k) { | |
| b34e1730 | 446 | |
| 44a8f0c7 | 447 | hole = spaces[k] + *space_size[k]; |
| 9a8c1c2f | 448 | |
| 449 | if (os_validate(hole, HOLE_SIZE) == NULL) { | |
| 450 | fprintf(stderr, | |
| 451 | "ensure_space: Failed to validate hole of %d bytes at 0x%08lX\n", | |
| 452 | HOLE_SIZE, (unsigned long) hole); | |
| 453 | exit(1); | |
| 454 | } | |
| 455 | /* Make it inaccessible */ | |
| 456 | os_protect(hole, HOLE_SIZE, 0); | |
| b34e1730 | 457 | } |
| 458 | ||
| 9a8c1c2f | 459 | /* Round up the dynamic_space_size to the nearest SPARSE_BLOCK_SIZE */ |
| 460 | dynamic_space_size = round_up_sparse_size(dynamic_space_size); | |
| 461 | ||
| 462 | /* Now make a hole for the dynamic spaces */ | |
| 463 | hole = dynamic_space_size + (os_vm_address_t) dynamic_0_space; | |
| 464 | ||
| 465 | if (os_validate(hole, HOLE_SIZE) == NULL) { | |
| 466 | fprintf(stderr, | |
| 467 | "ensure_space: Failed to validate hold of %d bytes at 0x%08lX\n", | |
| 468 | HOLE_SIZE, (unsigned long) hole); | |
| 469 | exit(1); | |
| b34e1730 | 470 | } |
| 9a8c1c2f | 471 | os_protect(hole, HOLE_SIZE, 0); |
| b34e1730 | 472 | |
| a4484236 | 473 | #ifndef GENCGC |
| 9a8c1c2f | 474 | hole = dynamic_space_size + (os_vm_address_t) dynamic_1_space; |
| 475 | if (os_validate(hole, HOLE_SIZE) == NULL) { | |
| 476 | fprintf(stderr, | |
| 477 | "ensure_space: Failed to validate hole of %ld bytes at 0x%08X\n", | |
| 478 | HOLE_SIZE, (unsigned long) hole); | |
| 479 | exit(1); | |
| b34e1730 | 480 | } |
| 9a8c1c2f | 481 | os_protect(hole, HOLE_SIZE, 0); |
| a4484236 | 482 | #endif |
| b34e1730 | 483 | } |
| 484 | ||
| 9a8c1c2f | 485 | void * |
| 486 | os_dlsym(const char *sym_name, lispobj lib_list) | |
| 49fdb025 | 487 | { |
| 488 | static void *program_handle; | |
| 489 | void *sym_addr = 0; | |
| 490 | ||
| 491 | if (!program_handle) | |
| 9a8c1c2f | 492 | program_handle = dlopen((void *) 0, RTLD_LAZY | RTLD_GLOBAL); |
| 49fdb025 | 493 | if (lib_list != NIL) { |
| 494 | lispobj lib_list_head; | |
| 495 | ||
| 496 | for (lib_list_head = lib_list; | |
| 9a8c1c2f | 497 | lib_list_head != NIL; lib_list_head = (CONS(lib_list_head))->cdr) { |
| 49fdb025 | 498 | struct cons *lib_cons = CONS(CONS(lib_list_head)->car); |
| 9a8c1c2f | 499 | struct sap *dlhandle = (struct sap *) PTR(lib_cons->car); |
| 49fdb025 | 500 | |
| 9a8c1c2f | 501 | sym_addr = dlsym((void *) dlhandle->pointer, sym_name); |
| 49fdb025 | 502 | if (sym_addr) |
| 503 | return sym_addr; | |
| 504 | } | |
| 505 | } | |
| 506 | sym_addr = dlsym(program_handle, sym_name); | |
| 98a1dd67 | 507 | |
| 508 | return sym_addr; | |
| 49fdb025 | 509 | } |
| 6438e048 | 510 | |
| 511 | #ifdef i386 | |
| 512 | unsigned long * | |
| 513 | os_sigcontext_reg(ucontext_t *scp, int index) | |
| 514 | { | |
| 515 | #if 0 | |
| 516 | fprintf(stderr, "os_sigcontext_reg index = %d\n", index); | |
| 517 | #endif | |
| 518 | switch (index) { | |
| 519 | case 0: | |
| 520 | return (unsigned long *) &scp->uc_mcontext.gregs[EAX]; | |
| 521 | case 2: | |
| 522 | return (unsigned long *) &scp->uc_mcontext.gregs[ECX]; | |
| 523 | case 4: | |
| 524 | return (unsigned long *) &scp->uc_mcontext.gregs[EDX]; | |
| 525 | case 6: | |
| 526 | return (unsigned long *) &scp->uc_mcontext.gregs[EBX]; | |
| 527 | case 8: | |
| 528 | return (unsigned long *) &scp->uc_mcontext.gregs[ESP]; | |
| 529 | case 10: | |
| 530 | return (unsigned long *) &scp->uc_mcontext.gregs[EBP]; | |
| 531 | case 12: | |
| 532 | return (unsigned long *) &scp->uc_mcontext.gregs[ESI]; | |
| 533 | case 14: | |
| 534 | return (unsigned long *) &scp->uc_mcontext.gregs[EDI]; | |
| 535 | } | |
| 536 | return NULL; | |
| 537 | } | |
| 538 | ||
| 539 | unsigned long * | |
| 540 | os_sigcontext_pc(ucontext_t *scp) | |
| 541 | { | |
| 542 | #if 0 | |
| 543 | fprintf(stderr, "os_sigcontext_pc = %p\n", scp->uc_mcontext.gregs[EIP]); | |
| 544 | #endif | |
| 545 | return (unsigned long *) &scp->uc_mcontext.gregs[EIP]; | |
| 546 | } | |
| 547 | ||
| 548 | ||
| 549 | unsigned char * | |
| 550 | os_sigcontext_fpu_reg(ucontext_t *scp, int offset) | |
| 551 | { | |
| 552 | fpregset_t *fpregs = &scp->uc_mcontext.fpregs; | |
| 553 | unsigned char *reg = NULL; | |
| 554 | ||
| 555 | if (offset < 8) { | |
| 556 | unsigned char *fpustate; | |
| 557 | unsigned char *stregs; | |
| 558 | ||
| 559 | /* | |
| 560 | * Not sure this is right. There is no structure defined for | |
| 561 | * the x87 fpu state in /usr/include/sys/regset.h | |
| 562 | */ | |
| 563 | ||
| 564 | /* Point to the fpchip_state */ | |
| 565 | fpustate = (unsigned char*) &fpregs->fp_reg_set.fpchip_state.state[0]; | |
| 566 | /* Skip to where the x87 fp registers are */ | |
| 2c8d7bae | 567 | stregs = fpustate + 28; |
| 6438e048 | 568 | |
| 2c8d7bae | 569 | reg = stregs + 10*offset; |
| 6438e048 | 570 | } |
| 571 | #ifdef FEATURE_SSE2 | |
| 572 | else { | |
| 573 | reg = (unsigned char*) &fpregs->fp_reg_set.fpchip_state.xmm[offset - 8]; | |
| 574 | } | |
| 575 | #endif | |
| 576 | ||
| 577 | return reg; | |
| 578 | } | |
| 579 | ||
| 580 | unsigned int | |
| 581 | os_sigcontext_fpu_modes(ucontext_t *scp) | |
| 582 | { | |
| 583 | unsigned int modes; | |
| 584 | unsigned short cw, sw; | |
| 585 | fpregset_t *fpr; | |
| 586 | unsigned int state; | |
| 587 | ||
| 588 | fpr = &scp->uc_mcontext.fpregs; | |
| 589 | ||
| 590 | cw = fpr->fp_reg_set.fpchip_state.state[0] & 0xffff; | |
| 591 | sw = fpr->fp_reg_set.fpchip_state.state[1] & 0xffff; | |
| 592 | ||
| 593 | modes = ((cw & 0x3f) << 7) | (sw & 0x3f); | |
| 594 | ||
| 595 | DPRINTF(0, (stderr, "cw = 0x%04x\n", cw)); | |
| 596 | DPRINTF(0, (stderr, "sw = 0x%04x\n", sw)); | |
| 597 | DPRINTF(0, (stderr, "modes = 0x%08x\n", modes)); | |
| 598 | ||
| 599 | #ifdef FEATURE_SSE2 | |
| 600 | /* | |
| 601 | * Add in the SSE2 part, if we're running the sse2 core. | |
| 602 | */ | |
| 603 | if (fpu_mode == SSE2) { | |
| 604 | unsigned long mxcsr; | |
| 605 | ||
| 606 | mxcsr = fpr->fp_reg_set.fpchip_state.mxcsr; | |
| 607 | DPRINTF(0, (stderr, "SSE2 modes = %08lx\n", mxcsr)); | |
| 608 | ||
| 609 | modes |= mxcsr; | |
| 610 | } | |
| 611 | #endif | |
| 612 | ||
| 613 | modes ^= (0x3f << 7); | |
| 614 | return modes; | |
| 615 | } | |
| aa9c2237 | 616 | |
| 617 | boolean | |
| 618 | os_support_sse2() | |
| 619 | { | |
| 620 | return TRUE; | |
| 621 | } | |
| 6438e048 | 622 | #endif |