/[cmucl]/src/lisp/sunos-os.c
ViewVC logotype

Contents of /src/lisp/sunos-os.c

Parent Directory Parent Directory | Revision Log Revision Log


Revision 1.8 - (show annotations)
Mon Jan 1 11:53:03 2007 UTC (7 years, 3 months ago) by cshapiro
Branch: MAIN
CVS Tags: snapshot-2007-09, snapshot-2007-08, snapshot-2007-05, snapshot-2008-01, snapshot-2008-02, snapshot-2008-03, snapshot-2007-01, snapshot-2007-02, release-19e, snapshot-2007-03, snapshot-2007-04, snapshot-2007-07, snapshot-2007-06, release-19e-pre1, release-19e-pre2, release-19e-base, snapshot-2007-12, snapshot-2007-10, snapshot-2007-11, pre-telent-clx
Branch point for: release-19e-branch
Changes since 1.7: +1 -5 lines
File MIME type: text/plain
Remove old-style signals code and make our POSIX_SIGS behavior the default.
1 /*
2 * $Header: /tiger/var/lib/cvsroots/cmucl/src/lisp/sunos-os.c,v 1.8 2007/01/01 11:53:03 cshapiro Exp $
3 *
4 * OS-dependent routines. This file (along with os.h) exports an
5 * OS-independent interface to the operating system VM facilities.
6 * Suprisingly, this interface looks a lot like the Mach interface
7 * (but simpler in some places). For some operating systems, a subset
8 * of these functions will have to be emulated.
9 *
10 * This is the SunOS version.
11 * March 1991, Miles Bader <miles@cogsci.ed.ack.uk> & ted <ted@edu.NMSU>
12 *
13 */
14
15 /* #define DEBUG */
16
17 #include <stdio.h>
18
19 #include <signal.h>
20 #include <sys/file.h>
21
22 #ifdef SOLARIS
23 #include <unistd.h>
24 #include <errno.h>
25 #include <sys/param.h>
26 #define OS_PROTERR SEGV_ACCERR
27 #define OS_MAPERR SEGV_MAPERR
28 #define OS_HASERRNO(code) ((code)->si_errno != 0)
29 #define OS_ERRNO(code) ((code)->si_errno)
30 #else
31 #define OS_PROTERR SEGV_PROT
32 #define OS_MAPERR SEGV_NOMAP
33 #define OS_HASERRNO(code) (SEGV_CODE(code)==SEGV_OBJERR)
34 #define OS_ERRNO(code) SEGV_ERRNO(code)
35 extern int errno;
36 #endif /* SOLARIS */
37
38 #include "os.h"
39 /* To get dynamic_0_space and friends */
40 #include "globals.h"
41 /* To get memory map */
42 #include "sparc-validate.h"
43
44 /* block size must be larger than the system page size */
45 #define SPARSE_BLOCK_SIZE (1<<15)
46 #define SPARSE_SIZE_MASK (SPARSE_BLOCK_SIZE-1)
47
48 #define PROT_DEFAULT OS_VM_PROT_ALL
49
50 #define OFFSET_NONE ((os_vm_offset_t)(~0))
51
52 #define EMPTYFILE "/tmp/empty"
53 #define ZEROFILE "/dev/zero"
54
55 #define INITIAL_MAX_SEGS 32
56 #define GROW_MAX_SEGS 16
57
58 extern char *getenv();
59
60 /* ---------------------------------------------------------------- */
61
62 #define ADJ_OFFSET(off,adj) (((off)==OFFSET_NONE) ? OFFSET_NONE : ((off)+(adj)))
63
64 long os_vm_page_size = (-1);
65 static long os_real_page_size = (-1);
66
67 static struct segment {
68 os_vm_address_t start; /* note: start & length are expected to be on page */
69 os_vm_size_t length; /* boundaries */
70 long file_offset;
71 short mapped_fd;
72 short protection;
73 } *segments;
74
75 static int n_segments = 0, max_segments = 0;
76
77 static int zero_fd = (-1), empty_fd = (-1);
78
79 static os_vm_address_t last_fault = 0;
80 static os_vm_size_t real_page_size_difference = 0;
81
82 static void
83 os_init_bailout(arg)
84 char *arg;
85 {
86 char buf[500];
87
88 sprintf(buf, "os_init: %s", arg);
89 perror(buf);
90 exit(1);
91 }
92
93 void
94 os_init()
95 {
96 char *empty_file = getenv("CMUCL_EMPTYFILE");
97
98 if (empty_file == NULL)
99 empty_file = EMPTYFILE;
100
101 empty_fd = open(empty_file, O_RDONLY | O_CREAT);
102 if (empty_fd < 0)
103 os_init_bailout(empty_file);
104 unlink(empty_file);
105
106 zero_fd = open(ZEROFILE, O_RDONLY);
107 if (zero_fd < 0)
108 os_init_bailout(ZEROFILE);
109
110
111 #ifdef SOLARIS
112 os_vm_page_size = os_real_page_size = sysconf(_SC_PAGESIZE);
113 #else
114 os_vm_page_size = os_real_page_size = getpagesize();
115 #endif
116
117 max_segments = INITIAL_MAX_SEGS;
118 segments = (struct segment *) malloc(sizeof(struct segment) * max_segments);
119
120 if (segments == NULL) {
121 fprintf(stderr, "os_init: Couldn't allocate %d segment descriptors\n",
122 max_segments);
123 exit(1);
124 }
125
126 if (os_vm_page_size > OS_VM_DEFAULT_PAGESIZE) {
127 fprintf(stderr, "os_init: Pagesize too large (%d > %d)\n",
128 os_vm_page_size, OS_VM_DEFAULT_PAGESIZE);
129 exit(1);
130 } else {
131 /*
132 * we do this because there are apparently dependencies on
133 * the pagesize being OS_VM_DEFAULT_PAGESIZE somewhere...
134 * but since the OS doesn't know we're using this restriction,
135 * we have to grovel around a bit to enforce it, thus anything
136 * that uses real_page_size_difference.
137 */
138 real_page_size_difference = OS_VM_DEFAULT_PAGESIZE - os_vm_page_size;
139 os_vm_page_size = OS_VM_DEFAULT_PAGESIZE;
140 }
141 }
142
143 /* ---------------------------------------------------------------- */
144
145 void
146 seg_force_resident(struct segment *seg, os_vm_address_t addr, os_vm_size_t len)
147 {
148 int prot = seg->protection;
149
150 if (prot != 0) {
151 os_vm_address_t end = addr + len, touch = addr;
152
153 while (touch < end) {
154 int contents = (*(char *) touch);
155
156 if (prot & OS_VM_PROT_WRITE)
157 (*(char *) touch) = contents;
158 touch =
159 (os_vm_address_t) (((long) touch + SPARSE_BLOCK_SIZE) &
160 ~SPARSE_SIZE_MASK);
161 }
162 }
163 }
164
165 static struct segment *
166 seg_create_nomerge(addr, len, protection, mapped_fd, file_offset)
167 os_vm_address_t addr;
168 os_vm_size_t len;
169 int protection;
170 int mapped_fd;
171 {
172 int n;
173 struct segment *seg;
174
175 if (len == 0)
176 return NULL;
177
178 if (n_segments == max_segments) {
179 struct segment *new_segs;
180
181 max_segments += GROW_MAX_SEGS;
182
183 new_segs = (struct segment *)
184 realloc(segments, max_segments * sizeof(struct segment));
185
186 if (new_segs == NULL) {
187 fprintf(stderr,
188 "seg_create_nomerge: Couldn't grow segment descriptor table to %s segments\n",
189 max_segments);
190 max_segments -= GROW_MAX_SEGS;
191 return NULL;
192 }
193
194 segments = new_segs;
195 }
196
197 for (n = n_segments, seg = segments; n > 0; n--, seg++)
198 if (addr < seg->start) {
199 seg = (&segments[n_segments]);
200 while (n-- > 0) {
201 seg[0] = seg[-1];
202 seg--;
203 }
204 break;
205 }
206
207 n_segments++;
208
209 seg->start = addr;
210 seg->length = len;
211 seg->protection = protection;
212 seg->mapped_fd = mapped_fd;
213 seg->file_offset = file_offset;
214
215 return seg;
216 }
217
218 #if 1
219 /* returns the first segment containing addr */
220 static struct segment *
221 seg_find(addr)
222 os_vm_address_t addr;
223 {
224 int n;
225 struct segment *seg;
226
227 for (n = n_segments, seg = segments; n > 0; n--, seg++)
228 if (seg->start <= addr && seg->start + seg->length > addr)
229 return seg;
230
231 return NULL;
232 }
233 #else
234 /* returns the first segment containing addr */
235 static struct segment *
236 seg_find(addr)
237 os_vm_address_t addr;
238 {
239 /* does a binary search */
240 struct segment *lo = segments, *hi = segments + n_segments;
241
242 while (hi > lo) {
243 struct segment *mid = lo + ((hi - lo) >> 1);
244 os_vm_address_t start = mid->start;
245
246 if (addr >= start && addr < start + mid->length)
247 return mid;
248 else if (addr < start)
249 hi = mid;
250 else
251 lo = mid + 1;
252 }
253
254 return NULL;
255 }
256 #endif
257
258 /* returns TRUE if the range from addr to addr+len intersects with any segment */
259 static boolean
260 collides_with_seg_p(addr, len)
261 os_vm_address_t addr;
262 os_vm_size_t len;
263 {
264 int n;
265 struct segment *seg;
266 os_vm_address_t end = addr + len;
267
268 for (n = n_segments, seg = segments; n > 0; n--, seg++)
269 if (seg->start >= end)
270 return FALSE;
271 else if (seg->start + seg->length > addr)
272 return TRUE;
273
274 return FALSE;
275 }
276
277 #if 0 /* WAY to SLOW */
278 /* returns TRUE if the range from addr to addr+len is a valid mapping
279 * (that we don't know about) */
280 static boolean
281 mem_in_use(addr, len)
282 os_vm_address_t addr;
283 os_vm_size_t len;
284 {
285 os_vm_address_t p;
286
287 for (p = addr; addr < addr + len; p += os_real_page_size) {
288 char c;
289
290 if (mincore((caddr_t) p, os_real_page_size, &c) == 0 || errno != ENOMEM)
291 return TRUE;
292 }
293 return FALSE;
294 }
295 #endif
296
297 #define seg_last_p(seg) (((seg)-segments)>=n_segments-1)
298
299 static void
300 seg_destroy(seg)
301 struct segment *seg;
302 {
303 if (seg != NULL) {
304 int n;
305
306 for (n = seg - segments + 1; n < n_segments; n++) {
307 seg[0] = seg[1];
308 seg++;
309 }
310
311 n_segments--;
312 }
313 }
314
315 static void
316 seg_try_merge_next(seg)
317 struct segment *seg;
318 {
319 struct segment *nseg = seg + 1;
320
321 if (!seg_last_p(seg)
322 && seg->start + seg->length == nseg->start
323 && seg->protection == nseg->protection
324 && seg->mapped_fd == nseg->mapped_fd
325 && ADJ_OFFSET(seg->file_offset, seg->length) == nseg->file_offset) {
326 /* can merge with the next segment */
327 #ifdef DEBUG
328 fprintf(stderr,
329 ";;; seg_try_merge: Merged 0x%08x[0x%08x] with 0x%08x[0x%08x]\n",
330 seg->start, seg->length, nseg->start, nseg->length);
331 #endif
332
333 if (((long) nseg->start & SPARSE_SIZE_MASK) != 0) {
334 /*
335 * if not on a block boundary, we have to ensure both parts
336 * of a common block are in a known state
337 */
338 seg_force_resident(seg, nseg->start - 1, 1);
339 seg_force_resident(nseg, nseg->start, 1);
340 }
341
342 seg->length += nseg->length;
343 seg_destroy(nseg);
344 }
345 }
346
347
348 /*
349 * Try to merge seg with adjacent segments.
350 */
351 static void
352 seg_try_merge_adjacent(seg)
353 struct segment *seg;
354 {
355 if (!seg_last_p(seg))
356 seg_try_merge_next(seg);
357 if (seg > segments)
358 seg_try_merge_next(seg - 1);
359 }
360
361 static struct segment *
362 seg_create(addr, len, protection, mapped_fd, file_offset)
363 os_vm_address_t addr;
364 os_vm_size_t len;
365 int protection;
366 int mapped_fd;
367 {
368 struct segment *seg =
369
370 seg_create_nomerge(addr, len, protection, mapped_fd, file_offset);
371 if (seg != NULL)
372 seg_try_merge_adjacent(seg);
373 return seg;
374 }
375
376 /*
377 * Change the attributes of the given range of an existing segment, and return
378 * a segment corresponding to the new bit.
379 */
380 static struct segment *
381 seg_change_range(seg, addr, len, protection, mapped_fd, file_offset)
382 struct segment *seg;
383 os_vm_address_t addr;
384 os_vm_size_t len;
385 int protection;
386 int mapped_fd;
387 {
388 os_vm_address_t end = addr + len;
389
390 if (len == 0)
391 return NULL;
392
393 if (protection != seg->protection
394 || mapped_fd != seg->mapped_fd
395 || file_offset != ADJ_OFFSET(seg->file_offset, addr - seg->start)) {
396 os_vm_size_t old_len = seg->length, seg_offset = (addr - seg->start);
397
398 if (old_len < len + seg_offset) {
399 struct segment *next = seg + 1;
400
401 #ifdef DEBUG
402 fprintf(stderr,
403 ";;; seg_change_range: region 0x%08x[0x%08x] overflows 0x%08x[0x%08x]\n",
404 addr, len, seg->start, old_len);
405 #endif
406
407 while (!seg_last_p(seg) && next->start + next->length <= end) {
408 #ifdef DEBUG
409 fprintf(stderr,
410 ";;; seg_change_range: merging extra segment 0x%08x[0x%08x]\n",
411 next->start, next->length);
412 #endif
413 seg_destroy(next);
414 }
415
416 if (!seg_last_p(seg) && next->start < end) {
417 next->length -= end - next->start;
418 next->start = end;
419 old_len = next->start - seg->start;
420 } else
421 old_len = len + seg_offset;
422
423 #ifdef DEBUG
424 fprintf(stderr,
425 ";;; seg_change_range: extended first seg to 0x%08x[0x%08x]\n",
426 seg->start, old_len);
427 #endif
428 }
429
430 if (seg_offset + len < old_len) {
431 /* add second part of old segment */
432 seg_create_nomerge(end,
433 old_len - (seg_offset + len),
434 seg->protection,
435 seg->mapped_fd,
436 ADJ_OFFSET(seg->file_offset, seg_offset + len));
437
438 #ifdef DEBUG
439 fprintf(stderr,
440 ";;; seg_change_range: Split off end of 0x%08x[0x%08x]: 0x%08x[0x%08x]\n",
441 seg->start, old_len, end, old_len - (seg_offset + len));
442 #endif
443 }
444
445 if (seg_offset == 0) {
446 seg->length = len;
447 seg->protection = protection;
448 seg->mapped_fd = mapped_fd;
449 seg->file_offset = file_offset;
450 } else {
451 /* adjust first part of remaining old segment */
452 seg->length = seg_offset;
453
454 #ifdef DEBUG
455 fprintf(stderr,
456 ";;; seg_change_range: Split off beginning of 0x%08x[0x%08x]: 0x%08x[0x%08x]\n",
457 seg->start, old_len, seg->start, seg_offset);
458 #endif
459
460 /* add new middle segment for new protected region */
461 seg =
462 seg_create_nomerge(addr, len, protection, mapped_fd,
463 file_offset);
464 }
465
466 seg_try_merge_adjacent(seg);
467
468 last_fault = 0;
469 }
470
471 return seg;
472 }
473
474 /* ---------------------------------------------------------------- */
475
476 static os_vm_address_t
477 mapin(addr, len, protection, map_fd, offset, is_readable)
478 os_vm_address_t addr;
479 os_vm_size_t len;
480 int protection;
481 int map_fd;
482 long offset;
483 int is_readable;
484 {
485 os_vm_address_t real;
486 boolean sparse = (len >= SPARSE_BLOCK_SIZE);
487
488 if (offset != OFFSET_NONE
489 && (offset < os_vm_page_size || (offset & (os_vm_page_size - 1)) != 0)) {
490 fprintf(stderr,
491 "mapin: file offset (%d) not multiple of pagesize (%d)\n",
492 offset, os_vm_page_size);
493 }
494
495 if (addr == NULL)
496 len += real_page_size_difference; /* futz around to get an aligned region */
497
498 last_fault = 0;
499 real = (os_vm_address_t)
500 mmap((caddr_t) addr,
501 (long) len,
502 sparse ? (is_readable ? PROT_READ | PROT_EXEC : 0) : protection,
503 (addr == NULL ? 0 : MAP_FIXED) | MAP_PRIVATE,
504 (is_readable || !sparse) ? map_fd : empty_fd,
505 (off_t) (offset == OFFSET_NONE ? 0 : offset));
506
507 if ((long) real == -1) {
508 perror("mapin: mmap");
509 return NULL;
510 }
511
512 if (addr == NULL) {
513 /*
514 * now play around with what the os gave us to make it align by
515 * our standards (which is why we overallocated)
516 */
517 os_vm_size_t overflow;
518
519 addr = os_round_up_to_page(real);
520 if (addr != real)
521 munmap((caddr_t) real, addr - real);
522
523 overflow = real_page_size_difference - (addr - real);
524 if (overflow != 0)
525 munmap((caddr_t) (addr + len - real_page_size_difference),
526 overflow);
527
528 real = addr;
529 }
530
531
532 return real;
533 }
534
535 static os_vm_address_t
536 map_and_remember(addr, len, protection, map_fd, offset, is_readable)
537 os_vm_address_t addr;
538 os_vm_size_t len;
539 int protection;
540 int map_fd;
541 long offset;
542 int is_readable;
543 {
544 os_vm_address_t real =
545
546 mapin(addr, len, protection, map_fd, offset, is_readable);
547
548 if (real != NULL) {
549 struct segment *seg = seg_find(real);
550
551 if (seg != NULL)
552 seg = seg_change_range(seg, real, len, protection, map_fd, offset);
553 else
554 seg = seg_create(real, len, protection, map_fd, offset);
555
556 if (seg == NULL) {
557 munmap((caddr_t) real, len);
558 return NULL;
559 }
560 }
561 #ifdef DEBUG
562 fprintf(stderr,
563 ";;; map_and_remember: 0x%08x[0x%08x] offset: %d, mapped to: %d\n",
564 real, len, offset, map_fd);
565 #endif
566
567 return real;
568 }
569
570 /* ---------------------------------------------------------------- */
571
572 os_vm_address_t
573 os_validate(addr, len)
574 os_vm_address_t addr;
575 os_vm_size_t len;
576 {
577 addr = os_trunc_to_page(addr);
578 len = os_round_up_size_to_page(len);
579
580 #ifdef DEBUG
581 fprintf(stderr, ";;; os_validate: 0x%08x[0x%08x]\n", addr, len);
582 #endif
583
584 if (addr != NULL && collides_with_seg_p(addr, len))
585 return NULL;
586
587 return map_and_remember(addr, len, PROT_DEFAULT, zero_fd, OFFSET_NONE,
588 FALSE);
589 }
590
591 void
592 os_invalidate(addr, len)
593 os_vm_address_t addr;
594 os_vm_size_t len;
595 {
596 struct segment *seg = seg_find(addr);
597
598 addr = os_trunc_to_page(addr);
599 len = os_round_up_size_to_page(len);
600
601 #ifdef DEBUG
602 fprintf(stderr, ";;; os_invalidate: 0x%08x[0x%08x]\n", addr, len);
603 #endif
604
605 if (seg == NULL)
606 fprintf(stderr, "os_invalidate: Unknown segment: 0x%08x[0x%08x]\n",
607 addr, len);
608 else {
609 seg = seg_change_range(seg, addr, len, 0, 0, OFFSET_NONE);
610 if (seg != NULL)
611 seg_destroy(seg);
612
613 last_fault = 0;
614 if (munmap((caddr_t) addr, len) != 0)
615 perror("os_invalidate: munmap");
616 }
617 }
618
619 os_vm_address_t
620 os_map(fd, offset, addr, len)
621 int fd;
622 int offset;
623 os_vm_address_t addr;
624 long len;
625 {
626 addr = os_trunc_to_page(addr);
627 len = os_round_up_size_to_page(len);
628
629 #ifdef DEBUG
630 fprintf(stderr, ";;; os_map: 0x%08x[0x%08x]\n", addr, len);
631 #endif
632
633 return map_and_remember(addr, len, PROT_DEFAULT, fd, offset, TRUE);
634 }
635
636 void
637 os_flush_icache(address, length)
638 os_vm_address_t address;
639 os_vm_size_t length;
640 {
641 #if defined(MACH) && defined(mips)
642 vm_machine_attribute_val_t flush;
643 kern_return_t kr;
644
645 flush = MATTR_VAL_ICACHE_FLUSH;
646
647 kr = vm_machine_attribute(task_self(), address, length,
648 MATTR_CACHE, &flush);
649 if (kr != KERN_SUCCESS)
650 mach_error("Could not flush the instruction cache", kr);
651 #endif
652 #ifdef SOLARIS /* also SunOS ?? */
653 static int flushit = -1;
654
655 /*
656 * On some systems, iflush needs to be emulated in the kernel
657 * On those systems, it isn't necessary
658 * Call getenv() only once.
659 */
660 if (flushit == -1)
661 flushit = getenv("CMUCL_NO_SPARC_IFLUSH") == 0;
662
663 if (flushit) {
664 static int traceit = -1;
665
666 if (traceit == -1)
667 traceit = getenv("CMUCL_TRACE_SPARC_IFLUSH") != 0;
668
669 if (traceit)
670 fprintf(stderr, ";;;iflush %p - %x\n", address, length);
671 flush_icache(address, length);
672 }
673 #endif
674 }
675
676 void
677 os_protect(addr, len, prot)
678 os_vm_address_t addr;
679 os_vm_size_t len;
680 int prot;
681 {
682 struct segment *seg = seg_find(addr);
683
684 addr = os_trunc_to_page(addr);
685 len = os_round_up_size_to_page(len);
686
687 #ifdef DEBUG
688 fprintf(stderr, ";;; os_protect: 0x%08x[0x%08x]\n", addr, len);
689 #endif
690
691 if (seg != NULL) {
692 int old_prot = seg->protection;
693
694 if (prot != old_prot) {
695 /*
696 * oooooh, sick: we have to make sure all the pages being protected have
697 * faulted in, so they're in a known state...
698 */
699 seg_force_resident(seg, addr, len);
700
701 seg_change_range(seg, addr, len, prot, seg->mapped_fd,
702 seg->file_offset);
703
704 if (mprotect((caddr_t) addr, (long) len, prot) != 0)
705 perror("os_unprotect: mprotect");
706 }
707 } else
708 fprintf(stderr, "os_protect: Unknown segment: 0x%08x[0x%08x]\n", addr,
709 len);
710 }
711
712 boolean
713 valid_addr(test)
714 os_vm_address_t test;
715 {
716 return seg_find(test) != NULL;
717 }
718
719 /* ---------------------------------------------------------------- */
720
721 static boolean
722 maybe_gc(HANDLER_ARGS)
723 {
724 /*
725 * It's necessary to enable recursive SEGVs, since the handle is
726 * used for multiple things (e.g., both gc-trigger & faulting in pages).
727 * We check against recursive gc's though...
728 */
729
730 boolean did_gc;
731 static already_trying = 0;
732
733 if (already_trying)
734 return FALSE;
735
736 SAVE_CONTEXT();
737
738 sigprocmask(SIG_SETMASK, &context->uc_sigmask, 0);
739
740 already_trying = TRUE;
741 did_gc = interrupt_maybe_gc(signal, code, context);
742 already_trying = FALSE;
743
744 return did_gc;
745 }
746
747 /*
748 * The primary point of catching segmentation violations is to allow
749 * read only memory to be re-mapped with more permissions when a write
750 * is attempted. this greatly decreases the residency of the program
751 * in swap space since read only areas don't take up room
752 *
753 * Running into the gc trigger page will also end up here...
754 */
755 #ifndef SOLARIS
756 void
757 segv_handler(HANDLER_ARGS, caddr_t addr)
758 #else
759 void
760 segv_handler(HANDLER_ARGS)
761 #endif /* SOLARIS */
762 {
763 #ifdef SOLARIS
764 caddr_t addr = code->si_addr;
765 #endif
766
767 SAVE_CONTEXT();
768
769 if (CODE(code) == OS_PROTERR) { /* allow writes to this chunk */
770 struct segment *seg = seg_find(addr);
771
772 if ((caddr_t) last_fault == addr) {
773 if (seg != NULL && maybe_gc(signal, code, context))
774 /* we just garbage collected */
775 return;
776 else {
777 /* a *real* protection fault */
778 fprintf(stderr,
779 "segv_handler: Real protection violation: 0x%08x\n",
780 addr);
781 interrupt_handle_now(signal, code, context);
782 }
783 } else
784 last_fault = (os_vm_address_t) addr;
785
786 if (seg != NULL) {
787 int err;
788
789 /* round down to a page */
790 os_vm_address_t block =
791
792 (os_vm_address_t) ((long) addr & ~SPARSE_SIZE_MASK);
793 os_vm_size_t length = SPARSE_BLOCK_SIZE;
794
795 if (block < seg->start) {
796 length -= (seg->start - block);
797 block = seg->start;
798 }
799 if (block + length > seg->start + seg->length)
800 length = seg->start + seg->length - block;
801
802 #if 0
803 /* unmap it. probably redundant. */
804 if (munmap((caddr_t) block, length) == -1)
805 perror("segv_handler: munmap");
806 #endif
807
808 /* and remap it with more permissions */
809 err = (int)
810 mmap((caddr_t) block,
811 length,
812 seg->protection,
813 MAP_PRIVATE | MAP_FIXED,
814 seg->mapped_fd,
815 seg->file_offset == OFFSET_NONE
816 ? 0 : seg->file_offset + (block - seg->start));
817
818 if (err == -1) {
819 perror("segv_handler: mmap");
820 interrupt_handle_now(signal, code, context);
821 }
822 } else {
823 fprintf(stderr, "segv_handler: 0x%08x not in any segment\n", addr);
824 interrupt_handle_now(signal, code, context);
825 }
826 }
827 /*
828 * note that we check for a gc-trigger hit even if it's not a PROT error
829 */
830 else if (!maybe_gc(signal, code, context)) {
831 static int nomap_count = 0;
832
833 if (CODE(code) == OS_MAPERR) {
834 if (nomap_count == 0) {
835 fprintf(stderr,
836 "segv_handler: No mapping fault: 0x%08x\n", addr);
837 nomap_count++;
838 } else {
839 /*
840 * There should be higher-level protection against stack
841 * overflow somewhere, but at least this prevents infinite
842 * puking of error messages...
843 */
844 fprintf(stderr,
845 "segv_handler: Recursive no mapping fault (stack overflow?)\n");
846 exit(-1);
847 }
848 } else if (OS_HASERRNO(code)) {
849 errno = OS_ERRNO(code);
850 perror("segv_handler: Object error");
851 }
852
853 interrupt_handle_now(signal, code, context);
854
855 if (CODE(code) == OS_MAPERR)
856 nomap_count--;
857 }
858 }
859
860 void
861 os_install_interrupt_handlers()
862 {
863 interrupt_install_low_level_handler(SIGSEGV, segv_handler);
864 }
865
866
867 #ifdef SOLARIS
868
869
870 /* function defintions for register lvalues */
871
872 int *
873 solaris_register_address(struct ucontext *context, int reg)
874 {
875 if (reg == 0) {
876 static int zero;
877
878 zero = 0;
879
880 return &zero;
881 } else if (reg < 16) {
882 return &context->uc_mcontext.gregs[reg + 3];
883 } else if (reg < 32) {
884 int *sp = (int *) context->uc_mcontext.gregs[REG_SP];
885
886 return &sp[reg - 16];
887 } else
888 return 0;
889 }
890
891 /* function defintions for backward compatibilty and static linking */
892
893 #if 0
894 void *
895 dlopen(const char *file, int flag)
896 {
897 return 0;
898 }
899
900 void *
901 dlsym(void *obj, const char *sym)
902 {
903 return 0;
904 }
905
906 int
907 dlclose(void *obj)
908 {
909 return 0;
910 }
911
912 char *
913 dlerror(void)
914 {
915 return "no dynamic linking";
916 }
917 #endif
918
919 /* For now we put in some porting functions */
920
921 #ifndef SOLARIS25
922 int
923 getdtablesize(void)
924 {
925 return sysconf(_SC_OPEN_MAX);
926 }
927
928 char *
929 getwd(char *path)
930 {
931 return getcwd(path, MAXPATHLEN);
932 }
933
934 int
935 getpagesize(void)
936 {
937 return sysconf(_SC_PAGESIZE);
938 }
939
940
941 #include <sys/procfs.h>
942 /* Old rusage definition */
943 struct rusage {
944 struct timeval ru_utime; /* user time used */
945 struct timeval ru_stime; /* system time used */
946 long ru_maxrss;
947 #define ru_first ru_ixrss
948 long ru_ixrss; /* XXX: 0 */
949 long ru_idrss; /* XXX: sum of rm_asrss */
950 long ru_isrss; /* XXX: 0 */
951 long ru_minflt; /* any page faults not requiring I/O */
952 long ru_majflt; /* any page faults requiring I/O */
953 long ru_nswap; /* swaps */
954 long ru_inblock; /* block input operations */
955 long ru_oublock; /* block output operations */
956 long ru_msgsnd; /* messages sent */
957 long ru_msgrcv; /* messages received */
958 long ru_nsignals; /* signals received */
959 long ru_nvcsw; /* voluntary context switches */
960 long ru_nivcsw; /* involuntary " */
961 #define ru_last ru_nivcsw
962 };
963
964
965 int
966 getrusage(int who, struct rusage *rp)
967 {
968 memset(rp, 0, sizeof(struct rusage));
969
970 return 0;
971 }
972
973 int
974 setreuid()
975 {
976 fprintf(stderr, "setreuid unimplemented\n");
977 errno = ENOSYS;
978 return -1;
979 }
980
981 int
982 setregid()
983 {
984 fprintf(stderr, "setregid unimplemented\n");
985 errno = ENOSYS;
986 return -1;
987 }
988
989 int
990 gethostid()
991 {
992 fprintf(stderr, "gethostid unimplemented\n");
993 errno = ENOSYS;
994 return -1;
995 }
996
997 int
998 killpg(int pgrp, int sig)
999 {
1000 if (pgrp < 0) {
1001 errno = ESRCH;
1002 return -1;
1003 }
1004 return kill(-pgrp, sig);
1005 }
1006 #endif
1007
1008 int
1009 sigblock(int mask)
1010 {
1011 sigset_t old, new;
1012
1013 sigemptyset(&new);
1014 new.__sigbits[0] = mask;
1015
1016 sigprocmask(SIG_BLOCK, &new, &old);
1017
1018 return old.__sigbits[0];
1019 }
1020
1021 #ifndef SOLARIS25
1022 int
1023 wait3(int *status, int options, struct rusage *rp)
1024 {
1025 if (rp)
1026 memset(rp, 0, sizeof(struct rusage));
1027
1028 return waitpid(-1, status, options);
1029 }
1030 #endif
1031
1032 int
1033 sigsetmask(int mask)
1034 {
1035 sigset_t old, new;
1036
1037 sigemptyset(&new);
1038 new.__sigbits[0] = mask;
1039
1040 sigprocmask(SIG_SETMASK, &new, &old);
1041
1042 return old.__sigbits[0];
1043
1044 }
1045
1046 #endif /* SOLARIS */
1047
1048 os_vm_address_t round_up_sparse_size(os_vm_address_t addr)
1049 {
1050 return (addr + SPARSE_BLOCK_SIZE - 1) & ~SPARSE_SIZE_MASK;
1051 }
1052
1053 /*
1054 * An array of the start of the spaces which should have holes placed
1055 * after them. Must not include the dynamic spaces because the size
1056 * of the dynamic space can be controlled from the command line.
1057 */
1058 static os_vm_address_t spaces[] = {
1059 READ_ONLY_SPACE_START, STATIC_SPACE_START,
1060 BINDING_STACK_START, CONTROL_STACK_START
1061 };
1062
1063 /*
1064
1065 * The corresponding array for the size of each space. Be sure that
1066 * the spaces and holes don't overlap! The sizes MUST be on
1067 * SPARSE_BLOCK_SIZE boundaries.
1068
1069 */
1070 static unsigned long space_size[] = {
1071 READ_ONLY_SPACE_SIZE, STATIC_SPACE_SIZE,
1072 BINDING_STACK_SIZE, CONTROL_STACK_SIZE
1073 };
1074
1075 /*
1076 * The size of the hole to make. It should be strictly smaller than
1077 * SPARSE_BLOCK_SIZE.
1078 */
1079
1080 #define HOLE_SIZE 0x2000
1081
1082 void
1083 make_holes(void)
1084 {
1085 int k;
1086 os_vm_address_t hole;
1087
1088 /* Make holes of the appropriate size for desired spaces */
1089
1090 for (k = 0; k < sizeof(spaces) / sizeof(spaces[0]); ++k) {
1091
1092 hole = spaces[k] + space_size[k];
1093
1094 if (os_validate(hole, HOLE_SIZE) == NULL) {
1095 fprintf(stderr,
1096 "ensure_space: Failed to validate hole of %ld bytes at 0x%08X\n",
1097 HOLE_SIZE, (unsigned long) hole);
1098 exit(1);
1099 }
1100 /* Make it inaccessible */
1101 os_protect(hole, HOLE_SIZE, 0);
1102 }
1103
1104 /* Round up the dynamic_space_size to the nearest SPARSE_BLOCK_SIZE */
1105 dynamic_space_size = round_up_sparse_size(dynamic_space_size);
1106
1107 /* Now make a hole for the dynamic spaces */
1108 hole = dynamic_space_size + (os_vm_address_t) dynamic_0_space;
1109
1110 if (os_validate(hole, HOLE_SIZE) == NULL) {
1111 fprintf(stderr,
1112 "ensure_space: Failed to validate hold of %ld bytes at 0x%08X\n",
1113 HOLE_SIZE, (unsigned long) hole);
1114 exit(1);
1115 }
1116 os_protect(hole, HOLE_SIZE, 0);
1117
1118 hole = dynamic_space_size + (os_vm_address_t) dynamic_1_space;
1119 if (os_validate(hole, HOLE_SIZE) == NULL) {
1120 fprintf(stderr,
1121 "ensure_space: Failed to validate hole of %ld bytes at 0x%08X\n",
1122 HOLE_SIZE, (unsigned long) hole);
1123 exit(1);
1124 }
1125 os_protect(hole, HOLE_SIZE, 0);
1126 }

  ViewVC Help
Powered by ViewVC 1.1.5