3 * From OpenBSD-os.c 1.1 2001/12/06 19:15:44 pmai Exp
4 * From FreeBSD-os.c 1.6 2000/10/24 13:32:30 dtc Exp
6 * OS-dependent routines. This file (along with os.h) exports an
7 * OS-independent interface to the operating system VM facilities.
8 * Suprisingly, this interface looks a lot like the Mach interface
9 * (but simpler in some places). For some operating systems, a subset
10 * of these functions will have to be emulated.
12 * This is the OSF1 version. By Sean Hallgren.
13 * Much hacked by Paul Werkowski
14 * GENCGC support by Douglas Crosher, 1996, 1997.
15 * Frobbed for OpenBSD by Pierre R. Mai, 2001.
16 * Frobbed for NetBSD by Pierre R. Mai, 2002.
23 #include <sys/param.h>
29 #include "interrupt.h"
31 #include "internals.h"
33 #include <sys/types.h>
35 /* #include <sys/sysinfo.h> */
38 #include <sys/sysctl.h>
40 size_t os_vm_page_size;
48 os_init0(const char *argv[], const char *envp[])
52 os_init(const char *argv[], const char *envp[])
54 os_vm_page_size = OS_VM_DEFAULT_PAGESIZE;
58 os_sigcontext_reg(ucontext_t *scp, int index)
63 return (unsigned long *) &scp->uc_mcontext.__gregs[_REG_EAX];
65 return (unsigned long *) &scp->uc_mcontext.__gregs[_REG_ECX];
67 return (unsigned long *) &scp->uc_mcontext.__gregs[_REG_EDX];
69 return (unsigned long *) &scp->uc_mcontext.__gregs[_REG_EBX];
71 return (unsigned long *) &scp->uc_mcontext.__gregs[_REG_ESP];
73 return (unsigned long *) &scp->uc_mcontext.__gregs[_REG_EBP];
75 return (unsigned long *) &scp->uc_mcontext.__gregs[_REG_ESI];
77 return (unsigned long *) &scp->uc_mcontext.__gregs[_REG_EDI];
84 os_sigcontext_pc(ucontext_t *scp)
87 return (unsigned long *) &scp->uc_mcontext.__gregs[_REG_EIP];
92 os_sigcontext_fpu_reg(ucontext_t *scp, int index)
94 unsigned char *reg = NULL;
96 DPRINTF(0, (stderr, "fpu reg index = %d\n", index));
98 if (scp->uc_flags & _UC_FPU) {
99 if (scp->uc_flags & _UC_FXSAVE) {
101 * fp_xmm is an array of bytes in the format of the FXSAVE
102 * instruction. The x87 registers are at offset 32 from
103 * the start and each entry takes 16 bytes (only 10
104 * needed). The XMM registers are at offset 160 from the
105 * start of the array, and each XMM register is 16 bytes
109 reg = &scp->uc_mcontext.__fpregs.__fp_reg_set.__fp_xmm_state.__fp_xmm[160 + 16*(index - 8)];
110 DPRINTF(0, (stderr, " sse2 = %g\n", (double) *(double*) reg));
112 reg = &scp->uc_mcontext.__fpregs.__fp_reg_set.__fp_xmm_state.__fp_xmm[32 + 16*index];
113 DPRINTF(0, (stderr, " sse2 x87 = %g\n", (double) *(long double*) reg));
118 * In this case, we have the FNSAVE format. The x87
119 * registers are located at offset 28 and take 10 bytes
122 reg = &scp->uc_mcontext.__fpregs.__fp_reg_set.__fpchip_state.__fp_state[28 + 10*index];
123 DPRINTF(0, (stderr, " x87 = %g\n", (double) *(long double*) reg));
132 os_sigcontext_fpu_modes(ucontext_t *scp)
136 union savefpu *sv = (union savefpu *) &scp->uc_mcontext.__fpregs.__fp_reg_set;
137 struct env87 *env_87 = (struct env87 *) &sv->sv_87.sv_env;
138 struct envxmm *env_xmm = (struct envxmm *) &sv->sv_xmm.sv_env;
142 if (scp->uc_flags & _UC_FPU) {
143 if (scp->uc_flags & _UC_FXSAVE) {
147 cw = env_87->en_cw & 0xffff;
148 sw = env_87->en_sw & 0xffff;
155 modes = ((cw & 0x3f) << 7) | (sw & 0x3f);
158 if (fpu_mode == SSE2) {
159 u_int32_t mxcsr = env_xmm->en_mxcsr;
161 DPRINTF(0, (stderr, "SSE2 modes = %08x\n", (int)mxcsr));
165 modes ^= (0x3f << 7);
170 os_validate(os_vm_address_t addr, os_vm_size_t len)
172 int flags = MAP_PRIVATE | MAP_ANON;
175 * NetBSD 1.5.2 seems to insist on each mmap being less than 128MB.
176 * So we mmap in 64MB steps.
182 DPRINTF(0, (stderr, "os_validate %p %d =>", addr, len));
185 os_vm_address_t curaddr = addr;
188 os_vm_address_t resaddr;
189 int curlen = MIN(64 * 1024 * 1024, len);
191 resaddr = mmap(curaddr, curlen, OS_VM_PROT_ALL, flags, -1, 0);
193 if (resaddr == (os_vm_address_t) - 1) {
196 while (curaddr > addr) {
197 curaddr -= 64 * 1024 * 1024;
198 munmap(curaddr, 64 * 1024 * 1024);
204 DPRINTF(0, (stderr, " %p", resaddr));
210 DPRINTF(0, (stderr, "\n"));
212 addr = mmap(0, len, OS_VM_PROT_ALL, flags, -1, 0);
214 if (addr == (os_vm_address_t) - 1) {
219 DPRINTF(0, (stderr, " %p\n", addr));
226 os_invalidate(os_vm_address_t addr, os_vm_size_t len)
228 DPRINTF(0, (stderr, "os_invalidate %p %d\n", addr, len));
230 if (munmap(addr, len) == -1)
235 os_map(int fd, int offset, os_vm_address_t addr, os_vm_size_t len)
237 addr = mmap(addr, len,
239 MAP_PRIVATE | MAP_FILE | MAP_FIXED, fd, (off_t) offset);
241 if (addr == (os_vm_address_t) - 1)
248 os_flush_icache(os_vm_address_t address, os_vm_size_t length)
253 os_protect(os_vm_address_t address, os_vm_size_t length, os_vm_prot_t prot)
255 if (mprotect(address, length, prot) == -1)
262 in_range_p(os_vm_address_t a, lispobj sbeg, size_t slen)
264 char *beg = (char *) sbeg;
265 char *end = (char *) sbeg + slen;
266 char *adr = (char *) a;
268 return (adr >= beg && adr < end);
272 valid_addr(os_vm_address_t addr)
274 os_vm_address_t newaddr;
276 newaddr = os_trunc_to_page(addr);
278 if (in_range_p(addr, READ_ONLY_SPACE_START, read_only_space_size)
279 || in_range_p(addr, STATIC_SPACE_START, static_space_size)
280 || in_range_p(addr, DYNAMIC_0_SPACE_START, dynamic_space_size)
282 || in_range_p(addr, DYNAMIC_1_SPACE_START, dynamic_space_size)
284 || in_range_p(addr, CONTROL_STACK_START, control_stack_size)
285 || in_range_p(addr, BINDING_STACK_START, binding_stack_size))
292 sigsegv_handler(HANDLER_ARGS)
296 caddr_t fault_addr = code ? code->si_addr : 0;
298 fprintf(stderr, "Signal %d, fault_addr=%p, page_index=%d:\n",
299 signal, fault_addr, page_index);
302 if (gc_write_barrier(code->si_addr))
308 DPRINTF(0, (stderr, "sigsegv:\n"));
309 interrupt_handle_now(signal, code, context);
313 sigbus_handler(HANDLER_ARGS)
317 DPRINTF(0, (stderr, "sigbus:\n"));
318 interrupt_handle_now(signal, code, context);
322 * Restore the exception flags cleared by the kernel. These bits must
323 * be set for Lisp to determine which exception caused the signal. At
324 * present, there is no way to distinguish underflow exceptions from
325 * denormalized operand exceptions. An underflow exception is assumed
326 * if the subcode is FPE_FLTUND.
329 sigfpe_handler(HANDLER_ARGS)
331 ucontext_t *ucontext = (ucontext_t *) context;
332 union savefpu *sv = (union savefpu *) &ucontext->uc_mcontext.__fpregs.__fp_reg_set;
333 unsigned char trap = 0;
335 switch (code->si_code) {
336 case FPE_FLTDIV: /* ZE */
339 case FPE_FLTOVF: /* OE */
342 case FPE_FLTUND: /* DE or UE */
345 case FPE_FLTRES: /* PE */
348 case FPE_FLTINV: /* IE */
353 if (ucontext->uc_flags & _UC_FXSAVE) {
354 sv->sv_xmm.sv_env.en_sw |= trap;
356 sv->sv_87.sv_env.en_sw |= trap;
358 interrupt_handle_now(signal, code, context);
362 os_install_interrupt_handlers(void)
364 interrupt_install_low_level_handler(SIGSEGV, sigsegv_handler);
365 interrupt_install_low_level_handler(SIGBUS, sigbus_handler);
366 interrupt_install_low_level_handler(SIGFPE, sigfpe_handler);
370 os_dlsym(const char *sym_name, lispobj lib_list)
372 if (lib_list != NIL) {
373 lispobj lib_list_head;
375 for (lib_list_head = lib_list;
376 lib_list_head != NIL; lib_list_head = CONS(lib_list_head)->cdr) {
377 struct cons *lib_cons = CONS(CONS(lib_list_head)->car);
378 struct sap *dlhandle = (struct sap *) PTR(lib_cons->car);
379 void *sym_addr = dlsym((void *) dlhandle->pointer, sym_name);
386 return dlsym(RTLD_DEFAULT, sym_name);
390 restore_fpu(ucontext_t *scp)
392 union savefpu *sv = (union savefpu *) &scp->uc_mcontext.__fpregs.__fp_reg_set;
393 struct env87 *env_87 = &sv->sv_87.sv_env;
394 struct envxmm *env_xmm = &sv->sv_xmm.sv_env;
397 if (scp->uc_flags & _UC_FPU) {
398 if (scp->uc_flags & _UC_FXSAVE) {
401 cw = env_87->en_cw & 0xffff;
406 DPRINTF(0, (stderr, "restore_fpu: cw = %08x\n", (int)cw));
407 __asm__ __volatile__ ("fldcw %0"::"m"(*&cw));
409 if (fpu_mode == SSE2) {
410 u_int32_t mxcsr = env_xmm->en_mxcsr;
412 DPRINTF(0, (stderr, "restore_fpu: mxcsr (raw) = %04x\n", mxcsr));
413 __asm__ __volatile__ ("ldmxcsr %0"::"m"(*&mxcsr));
424 if (sysctlbyname("machdep.sse2", &support_sse2, &len,
425 NULL, 0) == 0 && support_sse2 != 0)