/[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.6.18.1 - (show annotations)
Mon Dec 19 01:10:15 2005 UTC (8 years, 4 months ago) by rtoy
Branch: ppc_gencgc_branch
CVS Tags: ppc_gencgc_snap_2006-01-06, ppc_gencgc_snap_2005-12-17
Changes since 1.6: +485 -437 lines
File MIME type: text/plain
Merge code from main branch of 2005-12-17 to ppc gencgc branch.  Still
doesn't work of course.
1 /*
2 * $Header: /tiger/var/lib/cvsroots/cmucl/src/lisp/sunos-os.c,v 1.6.18.1 2005/12/19 01:10:15 rtoy 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 #ifdef POSIX_SIGS
739 sigprocmask(SIG_SETMASK, &context->uc_sigmask, 0);
740 #else
741 sigsetmask(context->sc_mask);
742 #endif
743
744 already_trying = TRUE;
745 did_gc = interrupt_maybe_gc(signal, code, context);
746 already_trying = FALSE;
747
748 return did_gc;
749 }
750
751 /*
752 * The primary point of catching segmentation violations is to allow
753 * read only memory to be re-mapped with more permissions when a write
754 * is attempted. this greatly decreases the residency of the program
755 * in swap space since read only areas don't take up room
756 *
757 * Running into the gc trigger page will also end up here...
758 */
759 #ifndef SOLARIS
760 void
761 segv_handler(HANDLER_ARGS, caddr_t addr)
762 #else
763 void
764 segv_handler(HANDLER_ARGS)
765 #endif /* SOLARIS */
766 {
767 #ifdef SOLARIS
768 caddr_t addr = code->si_addr;
769 #endif
770
771 SAVE_CONTEXT();
772
773 if (CODE(code) == OS_PROTERR) { /* allow writes to this chunk */
774 struct segment *seg = seg_find(addr);
775
776 if ((caddr_t) last_fault == addr) {
777 if (seg != NULL && maybe_gc(signal, code, context))
778 /* we just garbage collected */
779 return;
780 else {
781 /* a *real* protection fault */
782 fprintf(stderr,
783 "segv_handler: Real protection violation: 0x%08x\n",
784 addr);
785 interrupt_handle_now(signal, code, context);
786 }
787 } else
788 last_fault = (os_vm_address_t) addr;
789
790 if (seg != NULL) {
791 int err;
792
793 /* round down to a page */
794 os_vm_address_t block =
795
796 (os_vm_address_t) ((long) addr & ~SPARSE_SIZE_MASK);
797 os_vm_size_t length = SPARSE_BLOCK_SIZE;
798
799 if (block < seg->start) {
800 length -= (seg->start - block);
801 block = seg->start;
802 }
803 if (block + length > seg->start + seg->length)
804 length = seg->start + seg->length - block;
805
806 #if 0
807 /* unmap it. probably redundant. */
808 if (munmap((caddr_t) block, length) == -1)
809 perror("segv_handler: munmap");
810 #endif
811
812 /* and remap it with more permissions */
813 err = (int)
814 mmap((caddr_t) block,
815 length,
816 seg->protection,
817 MAP_PRIVATE | MAP_FIXED,
818 seg->mapped_fd,
819 seg->file_offset == OFFSET_NONE
820 ? 0 : seg->file_offset + (block - seg->start));
821
822 if (err == -1) {
823 perror("segv_handler: mmap");
824 interrupt_handle_now(signal, code, context);
825 }
826 } else {
827 fprintf(stderr, "segv_handler: 0x%08x not in any segment\n", addr);
828 interrupt_handle_now(signal, code, context);
829 }
830 }
831 /*
832 * note that we check for a gc-trigger hit even if it's not a PROT error
833 */
834 else if (!maybe_gc(signal, code, context)) {
835 static int nomap_count = 0;
836
837 if (CODE(code) == OS_MAPERR) {
838 if (nomap_count == 0) {
839 fprintf(stderr,
840 "segv_handler: No mapping fault: 0x%08x\n", addr);
841 nomap_count++;
842 } else {
843 /*
844 * There should be higher-level protection against stack
845 * overflow somewhere, but at least this prevents infinite
846 * puking of error messages...
847 */
848 fprintf(stderr,
849 "segv_handler: Recursive no mapping fault (stack overflow?)\n");
850 exit(-1);
851 }
852 } else if (OS_HASERRNO(code)) {
853 errno = OS_ERRNO(code);
854 perror("segv_handler: Object error");
855 }
856
857 interrupt_handle_now(signal, code, context);
858
859 if (CODE(code) == OS_MAPERR)
860 nomap_count--;
861 }
862 }
863
864 void
865 os_install_interrupt_handlers()
866 {
867 interrupt_install_low_level_handler(SIGSEGV, segv_handler);
868 }
869
870
871 #ifdef SOLARIS
872
873
874 /* function defintions for register lvalues */
875
876 int *
877 solaris_register_address(struct ucontext *context, int reg)
878 {
879 if (reg == 0) {
880 static int zero;
881
882 zero = 0;
883
884 return &zero;
885 } else if (reg < 16) {
886 return &context->uc_mcontext.gregs[reg + 3];
887 } else if (reg < 32) {
888 int *sp = (int *) context->uc_mcontext.gregs[REG_SP];
889
890 return &sp[reg - 16];
891 } else
892 return 0;
893 }
894
895 /* function defintions for backward compatibilty and static linking */
896
897 #if 0
898 void *
899 dlopen(const char *file, int flag)
900 {
901 return 0;
902 }
903
904 void *
905 dlsym(void *obj, const char *sym)
906 {
907 return 0;
908 }
909
910 int
911 dlclose(void *obj)
912 {
913 return 0;
914 }
915
916 char *
917 dlerror(void)
918 {
919 return "no dynamic linking";
920 }
921 #endif
922
923 /* For now we put in some porting functions */
924
925 #ifndef SOLARIS25
926 int
927 getdtablesize(void)
928 {
929 return sysconf(_SC_OPEN_MAX);
930 }
931
932 char *
933 getwd(char *path)
934 {
935 return getcwd(path, MAXPATHLEN);
936 }
937
938 int
939 getpagesize(void)
940 {
941 return sysconf(_SC_PAGESIZE);
942 }
943
944
945 #include <sys/procfs.h>
946 /* Old rusage definition */
947 struct rusage {
948 struct timeval ru_utime; /* user time used */
949 struct timeval ru_stime; /* system time used */
950 long ru_maxrss;
951 #define ru_first ru_ixrss
952 long ru_ixrss; /* XXX: 0 */
953 long ru_idrss; /* XXX: sum of rm_asrss */
954 long ru_isrss; /* XXX: 0 */
955 long ru_minflt; /* any page faults not requiring I/O */
956 long ru_majflt; /* any page faults requiring I/O */
957 long ru_nswap; /* swaps */
958 long ru_inblock; /* block input operations */
959 long ru_oublock; /* block output operations */
960 long ru_msgsnd; /* messages sent */
961 long ru_msgrcv; /* messages received */
962 long ru_nsignals; /* signals received */
963 long ru_nvcsw; /* voluntary context switches */
964 long ru_nivcsw; /* involuntary " */
965 #define ru_last ru_nivcsw
966 };
967
968
969 int
970 getrusage(int who, struct rusage *rp)
971 {
972 memset(rp, 0, sizeof(struct rusage));
973
974 return 0;
975 }
976
977 int
978 setreuid()
979 {
980 fprintf(stderr, "setreuid unimplemented\n");
981 errno = ENOSYS;
982 return -1;
983 }
984
985 int
986 setregid()
987 {
988 fprintf(stderr, "setregid unimplemented\n");
989 errno = ENOSYS;
990 return -1;
991 }
992
993 int
994 gethostid()
995 {
996 fprintf(stderr, "gethostid unimplemented\n");
997 errno = ENOSYS;
998 return -1;
999 }
1000
1001 int
1002 killpg(int pgrp, int sig)
1003 {
1004 if (pgrp < 0) {
1005 errno = ESRCH;
1006 return -1;
1007 }
1008 return kill(-pgrp, sig);
1009 }
1010 #endif
1011
1012 int
1013 sigblock(int mask)
1014 {
1015 sigset_t old, new;
1016
1017 sigemptyset(&new);
1018 new.__sigbits[0] = mask;
1019
1020 sigprocmask(SIG_BLOCK, &new, &old);
1021
1022 return old.__sigbits[0];
1023 }
1024
1025 #ifndef SOLARIS25
1026 int
1027 wait3(int *status, int options, struct rusage *rp)
1028 {
1029 if (rp)
1030 memset(rp, 0, sizeof(struct rusage));
1031
1032 return waitpid(-1, status, options);
1033 }
1034 #endif
1035
1036 int
1037 sigsetmask(int mask)
1038 {
1039 sigset_t old, new;
1040
1041 sigemptyset(&new);
1042 new.__sigbits[0] = mask;
1043
1044 sigprocmask(SIG_SETMASK, &new, &old);
1045
1046 return old.__sigbits[0];
1047
1048 }
1049
1050 #endif /* SOLARIS */
1051
1052 os_vm_address_t round_up_sparse_size(os_vm_address_t addr)
1053 {
1054 return (addr + SPARSE_BLOCK_SIZE - 1) & ~SPARSE_SIZE_MASK;
1055 }
1056
1057 /*
1058 * An array of the start of the spaces which should have holes placed
1059 * after them. Must not include the dynamic spaces because the size
1060 * of the dynamic space can be controlled from the command line.
1061 */
1062 static os_vm_address_t spaces[] = {
1063 READ_ONLY_SPACE_START, STATIC_SPACE_START,
1064 BINDING_STACK_START, CONTROL_STACK_START
1065 };
1066
1067 /*
1068
1069 * The corresponding array for the size of each space. Be sure that
1070 * the spaces and holes don't overlap! The sizes MUST be on
1071 * SPARSE_BLOCK_SIZE boundaries.
1072
1073 */
1074 static unsigned long space_size[] = {
1075 READ_ONLY_SPACE_SIZE, STATIC_SPACE_SIZE,
1076 BINDING_STACK_SIZE, CONTROL_STACK_SIZE
1077 };
1078
1079 /*
1080 * The size of the hole to make. It should be strictly smaller than
1081 * SPARSE_BLOCK_SIZE.
1082 */
1083
1084 #define HOLE_SIZE 0x2000
1085
1086 void
1087 make_holes(void)
1088 {
1089 int k;
1090 os_vm_address_t hole;
1091
1092 /* Make holes of the appropriate size for desired spaces */
1093
1094 for (k = 0; k < sizeof(spaces) / sizeof(spaces[0]); ++k) {
1095
1096 hole = spaces[k] + space_size[k];
1097
1098 if (os_validate(hole, HOLE_SIZE) == NULL) {
1099 fprintf(stderr,
1100 "ensure_space: Failed to validate hole of %ld bytes at 0x%08X\n",
1101 HOLE_SIZE, (unsigned long) hole);
1102 exit(1);
1103 }
1104 /* Make it inaccessible */
1105 os_protect(hole, HOLE_SIZE, 0);
1106 }
1107
1108 /* Round up the dynamic_space_size to the nearest SPARSE_BLOCK_SIZE */
1109 dynamic_space_size = round_up_sparse_size(dynamic_space_size);
1110
1111 /* Now make a hole for the dynamic spaces */
1112 hole = dynamic_space_size + (os_vm_address_t) dynamic_0_space;
1113
1114 if (os_validate(hole, HOLE_SIZE) == NULL) {
1115 fprintf(stderr,
1116 "ensure_space: Failed to validate hold of %ld bytes at 0x%08X\n",
1117 HOLE_SIZE, (unsigned long) hole);
1118 exit(1);
1119 }
1120 os_protect(hole, HOLE_SIZE, 0);
1121
1122 hole = dynamic_space_size + (os_vm_address_t) dynamic_1_space;
1123 if (os_validate(hole, HOLE_SIZE) == NULL) {
1124 fprintf(stderr,
1125 "ensure_space: Failed to validate hole of %ld bytes at 0x%08X\n",
1126 HOLE_SIZE, (unsigned long) hole);
1127 exit(1);
1128 }
1129 os_protect(hole, HOLE_SIZE, 0);
1130 }

  ViewVC Help
Powered by ViewVC 1.1.5