Clean up RCS ids
[projects/cmucl/cmucl.git] / src / lisp / FreeBSD-os.c
CommitLineData
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 37vm_size_t os_vm_page_size;
9a8c1c2f 38
670d643f 39void
dafb9e03 40os_init0(const char *argv[], const char *envp[])
41{}
42
43void
0f0aed07 44os_init(const char *argv[], const char *envp[])
5ced0fdf 45{
9a8c1c2f 46 os_vm_page_size = getpagesize();
5ced0fdf 47}
48
9495c516 49unsigned long *
50os_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
89unsigned long *
90os_sigcontext_pc(ucontext_t *scp)
91{
0faa382f 92 return (unsigned long *) (void *) &scp->uc_mcontext.mc_eip;
9495c516 93}
94
95unsigned char *
96os_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 120unsigned int
9495c516 121os_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 157os_vm_address_t
158os_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 175void
9a8c1c2f 176os_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 182os_vm_address_t
9a8c1c2f 183os_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 194void
9a8c1c2f 195os_flush_icache(os_vm_address_t address, os_vm_size_t length)
5ced0fdf 196{
197}
198
670d643f 199void
9a8c1c2f 200os_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 208static boolean
9a8c1c2f 209in_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 218boolean
219valid_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 238static void
00353423 239protection_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 */
264static void
00353423 265sigfpe_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 301void
9a8c1c2f 302os_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 309void *
9a8c1c2f 310os_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
333void
334restore_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
363boolean
364os_support_sse2()
365{
366 return TRUE;
367}
368#endif
369