Clean up RCS ids
[projects/cmucl/cmucl.git] / src / lisp / solaris-os.c
CommitLineData
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 56long os_vm_page_size = (-1);
57static long os_real_page_size = (-1);
f4ef6a57 58
9a8c1c2f 59static int zero_fd = (-1);
f4ef6a57 60
9a8c1c2f 61static os_vm_size_t real_page_size_difference = 0;
f4ef6a57 62
84551d3e 63static void
9a8c1c2f 64os_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 73void
dafb9e03 74os_init0(const char *argv[], const char *envp[])
75{}
76
77void
0f0aed07 78os_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 105os_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
122void
123os_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
129os_vm_address_t
130os_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 142void
143os_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
169void
170os_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 176static boolean
177in_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 186boolean 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 212void
213segv_handle_now(HANDLER_ARGS)
8cbbd24d 214{
9a8c1c2f 215 interrupt_handle_now(signal, code, context);
8cbbd24d 216}
217
6438e048 218void real_segv_handler(HANDLER_ARGS)
219{
220 segv_handle_now(signal, code, context);
221}
222
9a8c1c2f 223void
224segv_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 282void
283segv_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 303void
b8d0dfaf 304os_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 313int *
314solaris_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 337int
338sigblock(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 350int
351sigsetmask(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 364int
365openpty(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 403os_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 413static 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
425static 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 437void
438make_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 485void *
486os_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
512unsigned long *
513os_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
539unsigned long *
540os_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
549unsigned char *
550os_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
580unsigned int
581os_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
617boolean
618os_support_sse2()
619{
620 return TRUE;
621}
6438e048 622#endif