| Commit | Line | Data |
|---|---|---|
| 5ced0fdf | 1 | /* |
| 2 | * FreeBSD-os.c. Maybe could be just BSD-os.c | |
| 3 | * From osf1-os.c,v 1.1 94/03/27 15:30:51 hallgren Exp $ | |
| 4 | * | |
| 5 | * OS-dependent routines. This file (along with os.h) exports an | |
| 6 | * OS-independent interface to the operating system VM facilities. | |
| 7 | * Suprisingly, this interface looks a lot like the Mach interface | |
| 8 | * (but simpler in some places). For some operating systems, a subset | |
| 9 | * of these functions will have to be emulated. | |
| 10 | * | |
| 11 | * This is the OSF1 version. By Sean Hallgren. | |
| 12 | * Much hacked by Paul Werkowski | |
| 0c41e522 | 13 | * GENCGC support by Douglas Crosher, 1996, 1997. |
| 14 | * | |
| 5ced0fdf | 15 | */ |
| 16 | ||
| 0bba8011 | 17 | #include "os.h" |
| 5ced0fdf | 18 | #include <sys/file.h> |
| 9495c516 | 19 | #include <machine/npx.h> |
| 5ced0fdf | 20 | #include <errno.h> |
| 5ced0fdf | 21 | #include "arch.h" |
| 22 | #include "globals.h" | |
| 23 | #include "interrupt.h" | |
| 24 | #include "lispregs.h" | |
| 25 | #include "internals.h" | |
| 26 | ||
| 0c41e522 | 27 | #include <signal.h> |
| bf84be07 | 28 | #include <dlfcn.h> |
| 182365bc | 29 | #include "validate.h" |
| 86957330 | 30 | #include <stdio.h> |
| 31 | #include <unistd.h> | |
| 0c41e522 | 32 | |
| 33 | #if defined GENCGC | |
| 34 | #include "gencgc.h" | |
| 35 | #endif | |
| 36 | ||
| 670d643f | 37 | vm_size_t os_vm_page_size; |
| 9a8c1c2f | 38 | |
| 670d643f | 39 | void |
| dafb9e03 | 40 | os_init0(const char *argv[], const char *envp[]) |
| 41 | {} | |
| 42 | ||
| 43 | void | |
| 0f0aed07 | 44 | os_init(const char *argv[], const char *envp[]) |
| 5ced0fdf | 45 | { |
| 9a8c1c2f | 46 | os_vm_page_size = getpagesize(); |
| 5ced0fdf | 47 | } |
| 48 | ||
| 9495c516 | 49 | unsigned long * |
| 50 | os_sigcontext_reg(ucontext_t *scp, int index) | |
| 51 | { | |
| 0faa382f | 52 | __register_t *rv; |
| 00353423 | 53 | |
| 9495c516 | 54 | switch (index) { |
| 00353423 | 55 | case 0: |
| 68ac9a3e | 56 | rv = &scp->uc_mcontext.mc_eax; |
| 57 | break; | |
| 00353423 | 58 | case 2: |
| 68ac9a3e | 59 | rv = &scp->uc_mcontext.mc_ecx; |
| 60 | break; | |
| 00353423 | 61 | case 4: |
| 68ac9a3e | 62 | rv = &scp->uc_mcontext.mc_edx; |
| 63 | break; | |
| 00353423 | 64 | case 6: |
| 68ac9a3e | 65 | rv = &scp->uc_mcontext.mc_ebx; |
| 66 | break; | |
| 00353423 | 67 | case 8: |
| 68ac9a3e | 68 | rv = &scp->uc_mcontext.mc_esp; |
| 69 | break; | |
| 00353423 | 70 | case 10: |
| 68ac9a3e | 71 | rv = &scp->uc_mcontext.mc_ebp; |
| 72 | break; | |
| 00353423 | 73 | case 12: |
| 68ac9a3e | 74 | rv = &scp->uc_mcontext.mc_esi; |
| 75 | break; | |
| 00353423 | 76 | case 14: |
| 68ac9a3e | 77 | rv = &scp->uc_mcontext.mc_edi; |
| 78 | break; | |
| 00353423 | 79 | default: |
| 68ac9a3e | 80 | rv = NULL; |
| 9495c516 | 81 | } |
| 68ac9a3e | 82 | |
| 0faa382f | 83 | /* Pre-cast to (void *), to avoid the compiler warning: |
| 00353423 | 84 | * dereferencing type-punned pointer will break strict-aliasing rules |
| 0faa382f | 85 | */ |
| 00353423 | 86 | return (unsigned long *) (void *) rv; |
| 9495c516 | 87 | } |
| 88 | ||
| 89 | unsigned long * | |
| 90 | os_sigcontext_pc(ucontext_t *scp) | |
| 91 | { | |
| 0faa382f | 92 | return (unsigned long *) (void *) &scp->uc_mcontext.mc_eip; |
| 9495c516 | 93 | } |
| 94 | ||
| 95 | unsigned char * | |
| 96 | os_sigcontext_fpu_reg(ucontext_t *scp, int index) | |
| 97 | { | |
| 98 | union savefpu *sv = (union savefpu *) scp->uc_mcontext.mc_fpstate; | |
| 99 | int fpformat = scp->uc_mcontext.mc_fpformat; | |
| 100 | unsigned char *reg = NULL; | |
| 101 | ||
| 102 | switch (fpformat) { | |
| 00353423 | 103 | case _MC_FPFMT_XMM: |
| b9c7bd10 | 104 | if (index < 8) { |
| 105 | reg = sv->sv_xmm.sv_fp[index].fp_acc.fp_bytes; | |
| 106 | } else { | |
| 107 | reg = sv->sv_xmm.sv_xmm[index - 8].xmm_bytes; | |
| 108 | } | |
| 00353423 | 109 | break; |
| 110 | case _MC_FPFMT_387: | |
| 111 | reg = sv->sv_87.sv_ac[index].fp_bytes; | |
| 112 | break; | |
| 113 | case _MC_FPFMT_NODEV: | |
| 114 | reg = NULL; | |
| 115 | break; | |
| 5ced0fdf | 116 | } |
| 9495c516 | 117 | return reg; |
| 118 | } | |
| 9a8c1c2f | 119 | |
| b17a70c7 | 120 | unsigned int |
| 9495c516 | 121 | os_sigcontext_fpu_modes(ucontext_t *scp) |
| 122 | { | |
| b17a70c7 | 123 | unsigned int modes; |
| 00353423 | 124 | |
| 249dadb0 | 125 | union savefpu *sv = (union savefpu *) scp->uc_mcontext.mc_fpstate; |
| 9495c516 | 126 | int fpformat = scp->uc_mcontext.mc_fpformat; |
| 249dadb0 | 127 | struct env87 *env_87 = &sv->sv_87.sv_env; |
| 128 | struct envxmm *env_xmm = &sv->sv_xmm.sv_env; | |
| 129 | u_int16_t cw; | |
| 130 | u_int16_t sw; | |
| 9495c516 | 131 | |
| 132 | if (fpformat == _MC_FPFMT_XMM) { | |
| 249dadb0 | 133 | cw = env_xmm->en_cw; |
| 134 | sw = env_xmm->en_sw; | |
| 9495c516 | 135 | } else if (fpformat == _MC_FPFMT_387) { |
| 249dadb0 | 136 | cw = env_87->en_cw & 0xffff; |
| 137 | sw = env_87->en_sw & 0xffff; | |
| 00353423 | 138 | } else { /* _MC_FPFMT_NODEV */ |
| 9495c516 | 139 | cw = 0; |
| 140 | sw = 0x3f; | |
| 141 | } | |
| 249dadb0 | 142 | |
| 143 | modes = ((cw & 0x3f) << 7) | (sw & 0x3f); | |
| 144 | ||
| 145 | #ifdef FEATURE_SSE2 | |
| c2323072 | 146 | if (fpu_mode == SSE2) { |
| 00353423 | 147 | u_int32_t mxcsr = env_xmm->en_mxcsr; |
| 148 | ||
| 149 | DPRINTF(0, (stderr, "SSE2 modes = %08x\n", (int)mxcsr)); | |
| 249dadb0 | 150 | modes |= mxcsr; |
| 151 | } | |
| 152 | #endif | |
| 153 | modes ^= (0x3f << 7); | |
| 9495c516 | 154 | return modes; |
| 5ced0fdf | 155 | } |
| a18df860 | 156 | |
| 00353423 | 157 | os_vm_address_t |
| 158 | os_validate(os_vm_address_t addr, os_vm_size_t len) | |
| 5ced0fdf | 159 | { |
| 1e078503 | 160 | int flags = MAP_PRIVATE | MAP_ANON; |
| a18df860 | 161 | |
| 9a8c1c2f | 162 | if (addr) |
| 163 | flags |= MAP_FIXED; | |
| 5ced0fdf | 164 | |
| 9a8c1c2f | 165 | addr = mmap(addr, len, OS_VM_PROT_ALL, flags, -1, 0); |
| a18df860 | 166 | |
| 9a8c1c2f | 167 | if (addr == (os_vm_address_t) - 1) { |
| 168 | perror("mmap"); | |
| 169 | return NULL; | |
| 5ced0fdf | 170 | } |
| a18df860 | 171 | |
| 9a8c1c2f | 172 | return addr; |
| 5ced0fdf | 173 | } |
| 174 | ||
| 670d643f | 175 | void |
| 9a8c1c2f | 176 | os_invalidate(os_vm_address_t addr, os_vm_size_t len) |
| 5ced0fdf | 177 | { |
| 9a8c1c2f | 178 | if (munmap(addr, len) == -1) |
| 179 | perror("munmap"); | |
| 5ced0fdf | 180 | } |
| 181 | ||
| 670d643f | 182 | os_vm_address_t |
| 9a8c1c2f | 183 | os_map(int fd, int offset, os_vm_address_t addr, os_vm_size_t len) |
| 5ced0fdf | 184 | { |
| 9a8c1c2f | 185 | addr = mmap(addr, len, OS_VM_PROT_ALL, |
| 186 | MAP_PRIVATE | MAP_FILE | MAP_FIXED, fd, (off_t) offset); | |
| a18df860 | 187 | |
| 9a8c1c2f | 188 | if (addr == (os_vm_address_t) - 1) |
| 189 | perror("mmap"); | |
| a18df860 | 190 | |
| 9a8c1c2f | 191 | return addr; |
| 5ced0fdf | 192 | } |
| 193 | ||
| 670d643f | 194 | void |
| 9a8c1c2f | 195 | os_flush_icache(os_vm_address_t address, os_vm_size_t length) |
| 5ced0fdf | 196 | { |
| 197 | } | |
| 198 | ||
| 670d643f | 199 | void |
| 9a8c1c2f | 200 | os_protect(os_vm_address_t address, os_vm_size_t length, os_vm_prot_t prot) |
| 5ced0fdf | 201 | { |
| 9a8c1c2f | 202 | if (mprotect(address, length, prot) == -1) |
| 203 | perror("mprotect"); | |
| 5ced0fdf | 204 | } |
| 205 | \f | |
| a18df860 | 206 | |
| 9a8c1c2f | 207 | |
| 670d643f | 208 | static boolean |
| 9a8c1c2f | 209 | in_range_p(os_vm_address_t a, lispobj sbeg, size_t slen) |
| 5ced0fdf | 210 | { |
| 9a8c1c2f | 211 | char *beg = (char *) sbeg; |
| 212 | char *end = (char *) sbeg + slen; | |
| 213 | char *adr = (char *) a; | |
| 214 | ||
| 215 | return adr >= beg && adr < end; | |
| 5ced0fdf | 216 | } |
| a18df860 | 217 | |
| 00353423 | 218 | boolean |
| 219 | valid_addr(os_vm_address_t addr) | |
| 5ced0fdf | 220 | { |
| 9a8c1c2f | 221 | os_vm_address_t newaddr; |
| 222 | ||
| 223 | newaddr = os_trunc_to_page(addr); | |
| 670d643f | 224 | |
| 44a8f0c7 RT |
225 | if (in_range_p(addr, READ_ONLY_SPACE_START, read_only_space_size) |
| 226 | || in_range_p(addr, STATIC_SPACE_START, static_space_size) | |
| 9a8c1c2f | 227 | || in_range_p(addr, DYNAMIC_0_SPACE_START, dynamic_space_size) |
| 670d643f | 228 | #ifndef GENCGC |
| 9a8c1c2f | 229 | || in_range_p(addr, DYNAMIC_1_SPACE_START, dynamic_space_size) |
| 670d643f | 230 | #endif |
| 44a8f0c7 RT |
231 | || in_range_p(addr, CONTROL_STACK_START, control_stack_size) |
| 232 | || in_range_p(addr, BINDING_STACK_START, binding_stack_size)) | |
| 9a8c1c2f | 233 | return TRUE; |
| 234 | return FALSE; | |
| 5ced0fdf | 235 | } |
| 5ced0fdf | 236 | \f |
| 9a8c1c2f | 237 | |
| 670d643f | 238 | static void |
| 00353423 | 239 | protection_violation_handler(HANDLER_ARGS) |
| 5ced0fdf | 240 | { |
| 670d643f | 241 | #ifdef RED_ZONE_HIT |
| 00353423 | 242 | if (os_control_stack_overflow(code->si_addr, context)) |
| 9a8c1c2f | 243 | return; |
| 5ced0fdf | 244 | #endif |
| 9a8c1c2f | 245 | |
| 670d643f | 246 | #if defined GENCGC |
| 00353423 | 247 | if (code->si_code == PROTECTION_VIOLATION_CODE) { |
| 248 | if (gc_write_barrier(code->si_addr)) { | |
| f3e5780e | 249 | return; |
| 250 | } | |
| 0c41e522 | 251 | } |
| 00353423 | 252 | #endif |
| 0c41e522 | 253 | |
| 00353423 | 254 | interrupt_handle_now(signal, code, context); |
| 5ced0fdf | 255 | } |
| a18df860 | 256 | |
| 9495c516 | 257 | /* |
| 258 | * Restore the exception flags cleared by the kernel. These bits must | |
| 259 | * be set for Lisp to determine which exception caused the signal. At | |
| 260 | * present, there is no way to distinguish underflow exceptions from | |
| 261 | * denormalized operand exceptions. An underflow exception is assumed | |
| 262 | * if the subcode is FPE_FLTUND. | |
| 263 | */ | |
| 264 | static void | |
| 00353423 | 265 | sigfpe_handler(HANDLER_ARGS) |
| 9495c516 | 266 | { |
| 00353423 | 267 | ucontext_t *ucontext = (ucontext_t *) context; |
| 268 | union savefpu *sv = (union savefpu *) ucontext->uc_mcontext.mc_fpstate; | |
| 269 | int fpformat = ucontext->uc_mcontext.mc_fpformat; | |
| 270 | unsigned char trap = 0; | |
| 9495c516 | 271 | |
| 00353423 | 272 | switch (code->si_code) { |
| 273 | case FPE_FLTDIV: /* ZE */ | |
| 9495c516 | 274 | trap = 0x04; |
| 275 | break; | |
| 00353423 | 276 | case FPE_FLTOVF: /* OE */ |
| 9495c516 | 277 | trap = 0x08; |
| 278 | break; | |
| 00353423 | 279 | case FPE_FLTUND: /* DE or UE */ |
| 9495c516 | 280 | trap = 0x10; |
| 281 | break; | |
| 00353423 | 282 | case FPE_FLTRES: /* PE */ |
| 9495c516 | 283 | trap = 0x20; |
| 284 | break; | |
| 00353423 | 285 | case FPE_FLTINV: /* IE */ |
| 9495c516 | 286 | trap = 0x01; |
| 287 | break; | |
| 00353423 | 288 | } |
| 289 | ||
| 290 | switch (fpformat) { | |
| 291 | case _MC_FPFMT_XMM: | |
| 9495c516 | 292 | sv->sv_xmm.sv_env.en_sw |= trap; |
| 293 | break; | |
| 00353423 | 294 | case _MC_FPFMT_387: |
| 9495c516 | 295 | sv->sv_87.sv_env.en_sw |= trap; |
| 296 | break; | |
| 00353423 | 297 | } |
| 298 | interrupt_handle_now(signal, code, context); | |
| 9495c516 | 299 | } |
| 300 | ||
| 670d643f | 301 | void |
| 9a8c1c2f | 302 | os_install_interrupt_handlers(void) |
| 5ced0fdf | 303 | { |
| 00353423 | 304 | interrupt_install_low_level_handler(PROTECTION_VIOLATION_SIGNAL, |
| 305 | protection_violation_handler); | |
| 9495c516 | 306 | interrupt_install_low_level_handler(SIGFPE, sigfpe_handler); |
| 5ced0fdf | 307 | } |
| bf84be07 | 308 | |
| 670d643f | 309 | void * |
| 9a8c1c2f | 310 | os_dlsym(const char *sym_name, lispobj lib_list) |
| bf84be07 | 311 | { |
| b45fb97e | 312 | static void *program_handle; |
| b45fb97e | 313 | |
| 314 | if (!program_handle) | |
| 315 | program_handle = dlopen((void *) 0, RTLD_LAZY | RTLD_GLOBAL); | |
| 316 | ||
| 9a8c1c2f | 317 | if (lib_list != NIL) { |
| 318 | lispobj lib_list_head; | |
| 319 | ||
| 320 | for (lib_list_head = lib_list; | |
| 321 | lib_list_head != NIL; lib_list_head = CONS(lib_list_head)->cdr) { | |
| 322 | struct cons *lib_cons = CONS(CONS(lib_list_head)->car); | |
| 00353423 | 323 | struct sap *dlhandle = (struct sap *)PTR(lib_cons->car); |
| 324 | void *sym_addr = dlsym((void *)dlhandle->pointer, sym_name); | |
| 9a8c1c2f | 325 | |
| 326 | if (sym_addr) | |
| 327 | return sym_addr; | |
| bf84be07 | 328 | } |
| 329 | } | |
| b45fb97e | 330 | return dlsym(program_handle, sym_name); |
| bf84be07 | 331 | } |
| 9495c516 | 332 | |
| 333 | void | |
| 334 | restore_fpu(ucontext_t *scp) | |
| 335 | { | |
| 336 | union savefpu *sv = (union savefpu *) scp->uc_mcontext.mc_fpstate; | |
| 337 | int fpformat = scp->uc_mcontext.mc_fpformat; | |
| 249dadb0 | 338 | struct env87 *env_87 = &sv->sv_87.sv_env; |
| 339 | struct envxmm *env_xmm = &sv->sv_xmm.sv_env; | |
| 340 | u_int16_t cw; | |
| 9495c516 | 341 | |
| 342 | if (fpformat == _MC_FPFMT_XMM) { | |
| 249dadb0 | 343 | cw = env_xmm->en_cw; |
| 9495c516 | 344 | } else if (fpformat == _MC_FPFMT_387) { |
| 249dadb0 | 345 | cw = env_87->en_cw & 0xffff; |
| 00353423 | 346 | } else { /* _MC_FPFMT_NODEV */ |
| 9495c516 | 347 | return; |
| 348 | } | |
| 00353423 | 349 | DPRINTF(0, (stderr, "restore_fpu: cw = %08x\n", (int)cw)); |
| 350 | __asm__ __volatile__ ("fldcw %0"::"m"(*&cw)); | |
| 351 | ||
| 249dadb0 | 352 | #ifdef FEATURE_SSE2 |
| 03f8a6a6 | 353 | if (fpu_mode == SSE2) { |
| 00353423 | 354 | u_int32_t mxcsr = env_xmm->en_mxcsr; |
| 355 | ||
| 356 | DPRINTF(0, (stderr, "restore_fpu: mxcsr (raw) = %04x\n", mxcsr)); | |
| 357 | __asm__ __volatile__ ("ldmxcsr %0"::"m"(*&mxcsr)); | |
| 249dadb0 | 358 | } |
| 359 | #endif | |
| 9495c516 | 360 | } |
| aa9c2237 | 361 | |
| 362 | #ifdef i386 | |
| 363 | boolean | |
| 364 | os_support_sse2() | |
| 365 | { | |
| 366 | return TRUE; | |
| 367 | } | |
| 368 | #endif | |
| 369 |