/[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.9 - (hide annotations)
Wed Mar 19 09:17:13 2008 UTC (6 years, 1 month ago) by cshapiro
Branch: MAIN
CVS Tags: snapshot-2008-08, snapshot-2008-09, snapshot-2008-05, snapshot-2008-06, snapshot-2008-07, unicode-utf16-sync-2008-07, unicode-utf16-sync-2008-09, snapshot-2008-04, unicode-utf16-extfmts-pre-sync-2008-11, unicode-utf16-string-support, unicode-utf16-base
Branch point for: unicode-utf16-branch, unicode-utf16-extfmt-branch
Changes since 1.8: +6 -6 lines
File MIME type: text/plain
Always use prototype style function definitions.  Consistently use the
void keyword to specify empty parameter lists.
1 wlott 1.1 /*
2 cshapiro 1.9 * $Header: /tiger/var/lib/cvsroots/cmucl/src/lisp/sunos-os.c,v 1.9 2008/03/19 09:17:13 cshapiro Exp $
3 wlott 1.1 *
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 ram 1.3 #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 wlott 1.1 #include "os.h"
39 dtc 1.6 /* To get dynamic_0_space and friends */
40     #include "globals.h"
41     /* To get memory map */
42     #include "sparc-validate.h"
43 wlott 1.1
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 ram 1.2 #define INITIAL_MAX_SEGS 32
56     #define GROW_MAX_SEGS 16
57 wlott 1.1
58     extern char *getenv();
59    
60     /* ---------------------------------------------------------------- */
61    
62     #define ADJ_OFFSET(off,adj) (((off)==OFFSET_NONE) ? OFFSET_NONE : ((off)+(adj)))
63    
64 rtoy 1.7 long os_vm_page_size = (-1);
65     static long os_real_page_size = (-1);
66 wlott 1.1
67     static struct segment {
68     os_vm_address_t start; /* note: start & length are expected to be on page */
69 rtoy 1.7 os_vm_size_t length; /* boundaries */
70 wlott 1.1 long file_offset;
71     short mapped_fd;
72     short protection;
73 ram 1.2 } *segments;
74 wlott 1.1
75 rtoy 1.7 static int n_segments = 0, max_segments = 0;
76 wlott 1.1
77 rtoy 1.7 static int zero_fd = (-1), empty_fd = (-1);
78 wlott 1.1
79 rtoy 1.7 static os_vm_address_t last_fault = 0;
80     static os_vm_size_t real_page_size_difference = 0;
81 wlott 1.1
82 rtoy 1.7 static void
83     os_init_bailout(arg)
84     char *arg;
85 ram 1.2 {
86     char buf[500];
87 rtoy 1.7
88     sprintf(buf, "os_init: %s", arg);
89 ram 1.2 perror(buf);
90     exit(1);
91     }
92    
93 rtoy 1.7 void
94 cshapiro 1.9 os_init(void)
95 wlott 1.1 {
96 rtoy 1.7 char *empty_file = getenv("CMUCL_EMPTYFILE");
97 wlott 1.1
98 rtoy 1.7 if (empty_file == NULL)
99     empty_file = EMPTYFILE;
100 wlott 1.1
101 rtoy 1.7 empty_fd = open(empty_file, O_RDONLY | O_CREAT);
102     if (empty_fd < 0)
103 ram 1.2 os_init_bailout(empty_file);
104 wlott 1.1 unlink(empty_file);
105    
106 rtoy 1.7 zero_fd = open(ZEROFILE, O_RDONLY);
107     if (zero_fd < 0)
108 ram 1.2 os_init_bailout(ZEROFILE);
109 wlott 1.1
110 ram 1.3
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 wlott 1.1
117 rtoy 1.7 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 ram 1.2 max_segments);
123     exit(1);
124     }
125    
126 rtoy 1.7 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 wlott 1.1 exit(1);
130 rtoy 1.7 } else {
131 wlott 1.1 /*
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 rtoy 1.7 real_page_size_difference = OS_VM_DEFAULT_PAGESIZE - os_vm_page_size;
139     os_vm_page_size = OS_VM_DEFAULT_PAGESIZE;
140 wlott 1.1 }
141     }
142    
143     /* ---------------------------------------------------------------- */
144    
145 rtoy 1.7 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 wlott 1.1 }
162     }
163     }
164    
165 rtoy 1.7 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 wlott 1.1 {
172     int n;
173     struct segment *seg;
174    
175 rtoy 1.7 if (len == 0)
176 wlott 1.1 return NULL;
177    
178 rtoy 1.7 if (n_segments == max_segments) {
179 ram 1.2 struct segment *new_segs;
180    
181 rtoy 1.7 max_segments += GROW_MAX_SEGS;
182 ram 1.2
183 rtoy 1.7 new_segs = (struct segment *)
184     realloc(segments, max_segments * sizeof(struct segment));
185 ram 1.2
186 rtoy 1.7 if (new_segs == NULL) {
187 ram 1.2 fprintf(stderr,
188     "seg_create_nomerge: Couldn't grow segment descriptor table to %s segments\n",
189     max_segments);
190 rtoy 1.7 max_segments -= GROW_MAX_SEGS;
191 ram 1.2 return NULL;
192     }
193 rtoy 1.7
194     segments = new_segs;
195 wlott 1.1 }
196    
197 rtoy 1.7 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 wlott 1.1 seg--;
203     }
204     break;
205     }
206    
207     n_segments++;
208    
209 rtoy 1.7 seg->start = addr;
210     seg->length = len;
211     seg->protection = protection;
212     seg->mapped_fd = mapped_fd;
213     seg->file_offset = file_offset;
214 wlott 1.1
215     return seg;
216     }
217    
218 ram 1.2 #if 1
219 wlott 1.1 /* returns the first segment containing addr */
220 rtoy 1.7 static struct segment *
221     seg_find(addr)
222     os_vm_address_t addr;
223 wlott 1.1 {
224     int n;
225     struct segment *seg;
226    
227 rtoy 1.7 for (n = n_segments, seg = segments; n > 0; n--, seg++)
228     if (seg->start <= addr && seg->start + seg->length > addr)
229 wlott 1.1 return seg;
230    
231     return NULL;
232     }
233 ram 1.2 #else
234     /* returns the first segment containing addr */
235 rtoy 1.7 static struct segment *
236     seg_find(addr)
237     os_vm_address_t addr;
238 ram 1.2 {
239     /* does a binary search */
240 rtoy 1.7 struct segment *lo = segments, *hi = segments + n_segments;
241 wlott 1.1
242 rtoy 1.7 while (hi > lo) {
243     struct segment *mid = lo + ((hi - lo) >> 1);
244     os_vm_address_t start = mid->start;
245 ram 1.2
246 rtoy 1.7 if (addr >= start && addr < start + mid->length)
247 ram 1.2 return mid;
248 rtoy 1.7 else if (addr < start)
249     hi = mid;
250 ram 1.2 else
251 rtoy 1.7 lo = mid + 1;
252 ram 1.2 }
253    
254     return NULL;
255     }
256     #endif
257    
258 wlott 1.1 /* returns TRUE if the range from addr to addr+len intersects with any segment */
259 rtoy 1.7 static boolean
260     collides_with_seg_p(addr, len)
261     os_vm_address_t addr;
262     os_vm_size_t len;
263 wlott 1.1 {
264     int n;
265     struct segment *seg;
266 rtoy 1.7 os_vm_address_t end = addr + len;
267 wlott 1.1
268 rtoy 1.7 for (n = n_segments, seg = segments; n > 0; n--, seg++)
269     if (seg->start >= end)
270 wlott 1.1 return FALSE;
271 rtoy 1.7 else if (seg->start + seg->length > addr)
272 wlott 1.1 return TRUE;
273    
274     return FALSE;
275     }
276    
277 rtoy 1.7 #if 0 /* WAY to SLOW */
278 ram 1.3 /* returns TRUE if the range from addr to addr+len is a valid mapping
279     * (that we don't know about) */
280 rtoy 1.7 static boolean
281     mem_in_use(addr, len)
282     os_vm_address_t addr;
283     os_vm_size_t len;
284 ram 1.3 {
285     os_vm_address_t p;
286    
287     for (p = addr; addr < addr + len; p += os_real_page_size) {
288     char c;
289    
290 rtoy 1.7 if (mincore((caddr_t) p, os_real_page_size, &c) == 0 || errno != ENOMEM)
291 ram 1.3 return TRUE;
292     }
293     return FALSE;
294     }
295     #endif
296    
297 ram 1.2 #define seg_last_p(seg) (((seg)-segments)>=n_segments-1)
298 wlott 1.1
299 rtoy 1.7 static void
300     seg_destroy(seg)
301     struct segment *seg;
302 wlott 1.1 {
303 rtoy 1.7 if (seg != NULL) {
304 wlott 1.1 int n;
305    
306 rtoy 1.7 for (n = seg - segments + 1; n < n_segments; n++) {
307     seg[0] = seg[1];
308 wlott 1.1 seg++;
309     }
310    
311     n_segments--;
312     }
313     }
314    
315 rtoy 1.7 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 wlott 1.1 /* 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 rtoy 1.7 seg->start, seg->length, nseg->start, nseg->length);
331 wlott 1.1 #endif
332    
333 rtoy 1.7 if (((long) nseg->start & SPARSE_SIZE_MASK) != 0) {
334 wlott 1.1 /*
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 rtoy 1.7 seg_force_resident(seg, nseg->start - 1, 1);
339     seg_force_resident(nseg, nseg->start, 1);
340 wlott 1.1 }
341    
342 rtoy 1.7 seg->length += nseg->length;
343 wlott 1.1 seg_destroy(nseg);
344     }
345     }
346    
347    
348     /*
349     * Try to merge seg with adjacent segments.
350     */
351 rtoy 1.7 static void
352     seg_try_merge_adjacent(seg)
353     struct segment *seg;
354 wlott 1.1 {
355 rtoy 1.7 if (!seg_last_p(seg))
356 wlott 1.1 seg_try_merge_next(seg);
357 rtoy 1.7 if (seg > segments)
358     seg_try_merge_next(seg - 1);
359 wlott 1.1 }
360    
361 rtoy 1.7 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 wlott 1.1 {
368 rtoy 1.7 struct segment *seg =
369    
370     seg_create_nomerge(addr, len, protection, mapped_fd, file_offset);
371     if (seg != NULL)
372 wlott 1.1 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 rtoy 1.7 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 wlott 1.1 {
388 rtoy 1.7 os_vm_address_t end = addr + len;
389 wlott 1.1
390 rtoy 1.7 if (len == 0)
391 wlott 1.1 return NULL;
392    
393 rtoy 1.7 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 wlott 1.1 #ifdef DEBUG
402     fprintf(stderr,
403     ";;; seg_change_range: region 0x%08x[0x%08x] overflows 0x%08x[0x%08x]\n",
404 rtoy 1.7 addr, len, seg->start, old_len);
405 wlott 1.1 #endif
406 rtoy 1.7
407     while (!seg_last_p(seg) && next->start + next->length <= end) {
408 wlott 1.1 #ifdef DEBUG
409     fprintf(stderr,
410     ";;; seg_change_range: merging extra segment 0x%08x[0x%08x]\n",
411 rtoy 1.7 next->start, next->length);
412 wlott 1.1 #endif
413     seg_destroy(next);
414     }
415 rtoy 1.7
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 wlott 1.1 #ifdef DEBUG
424     fprintf(stderr,
425     ";;; seg_change_range: extended first seg to 0x%08x[0x%08x]\n",
426 rtoy 1.7 seg->start, old_len);
427 wlott 1.1 #endif
428     }
429    
430 rtoy 1.7 if (seg_offset + len < old_len) {
431 wlott 1.1 /* add second part of old segment */
432     seg_create_nomerge(end,
433 rtoy 1.7 old_len - (seg_offset + len),
434 wlott 1.1 seg->protection,
435     seg->mapped_fd,
436 rtoy 1.7 ADJ_OFFSET(seg->file_offset, seg_offset + len));
437 wlott 1.1
438     #ifdef DEBUG
439     fprintf(stderr,
440     ";;; seg_change_range: Split off end of 0x%08x[0x%08x]: 0x%08x[0x%08x]\n",
441 rtoy 1.7 seg->start, old_len, end, old_len - (seg_offset + len));
442 wlott 1.1 #endif
443     }
444    
445 rtoy 1.7 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 wlott 1.1 /* adjust first part of remaining old segment */
452 rtoy 1.7 seg->length = seg_offset;
453 wlott 1.1
454     #ifdef DEBUG
455     fprintf(stderr,
456     ";;; seg_change_range: Split off beginning of 0x%08x[0x%08x]: 0x%08x[0x%08x]\n",
457 rtoy 1.7 seg->start, old_len, seg->start, seg_offset);
458 wlott 1.1 #endif
459    
460     /* add new middle segment for new protected region */
461 rtoy 1.7 seg =
462     seg_create_nomerge(addr, len, protection, mapped_fd,
463     file_offset);
464 wlott 1.1 }
465    
466     seg_try_merge_adjacent(seg);
467    
468 rtoy 1.7 last_fault = 0;
469 wlott 1.1 }
470    
471     return seg;
472     }
473    
474     /* ---------------------------------------------------------------- */
475    
476 rtoy 1.7 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 wlott 1.1 {
485     os_vm_address_t real;
486 rtoy 1.7 boolean sparse = (len >= SPARSE_BLOCK_SIZE);
487 wlott 1.1
488 rtoy 1.7 if (offset != OFFSET_NONE
489     && (offset < os_vm_page_size || (offset & (os_vm_page_size - 1)) != 0)) {
490 wlott 1.1 fprintf(stderr,
491     "mapin: file offset (%d) not multiple of pagesize (%d)\n",
492 rtoy 1.7 offset, os_vm_page_size);
493 wlott 1.1 }
494    
495 rtoy 1.7 if (addr == NULL)
496     len += real_page_size_difference; /* futz around to get an aligned region */
497 wlott 1.1
498 rtoy 1.7 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 wlott 1.1 (is_readable || !sparse) ? map_fd : empty_fd,
505 rtoy 1.7 (off_t) (offset == OFFSET_NONE ? 0 : offset));
506 wlott 1.1
507 rtoy 1.7 if ((long) real == -1) {
508 wlott 1.1 perror("mapin: mmap");
509     return NULL;
510     }
511    
512 rtoy 1.7 if (addr == NULL) {
513 wlott 1.1 /*
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 rtoy 1.7 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 wlott 1.1
528 rtoy 1.7 real = addr;
529 wlott 1.1 }
530    
531    
532     return real;
533     }
534    
535 rtoy 1.7 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 wlott 1.1
548 rtoy 1.7 if (real != NULL) {
549     struct segment *seg = seg_find(real);
550 wlott 1.1
551 rtoy 1.7 if (seg != NULL)
552     seg = seg_change_range(seg, real, len, protection, map_fd, offset);
553 wlott 1.1 else
554 rtoy 1.7 seg = seg_create(real, len, protection, map_fd, offset);
555 wlott 1.1
556 rtoy 1.7 if (seg == NULL) {
557     munmap((caddr_t) real, len);
558 wlott 1.1 return NULL;
559     }
560     }
561     #ifdef DEBUG
562 rtoy 1.7 fprintf(stderr,
563     ";;; map_and_remember: 0x%08x[0x%08x] offset: %d, mapped to: %d\n",
564     real, len, offset, map_fd);
565 wlott 1.1 #endif
566    
567     return real;
568     }
569    
570     /* ---------------------------------------------------------------- */
571    
572 rtoy 1.7 os_vm_address_t
573     os_validate(addr, len)
574     os_vm_address_t addr;
575     os_vm_size_t len;
576 wlott 1.1 {
577 rtoy 1.7 addr = os_trunc_to_page(addr);
578     len = os_round_up_size_to_page(len);
579 wlott 1.1
580     #ifdef DEBUG
581 rtoy 1.7 fprintf(stderr, ";;; os_validate: 0x%08x[0x%08x]\n", addr, len);
582 wlott 1.1 #endif
583    
584 rtoy 1.7 if (addr != NULL && collides_with_seg_p(addr, len))
585 wlott 1.1 return NULL;
586    
587 rtoy 1.7 return map_and_remember(addr, len, PROT_DEFAULT, zero_fd, OFFSET_NONE,
588     FALSE);
589 wlott 1.1 }
590    
591 rtoy 1.7 void
592     os_invalidate(addr, len)
593     os_vm_address_t addr;
594     os_vm_size_t len;
595 wlott 1.1 {
596 rtoy 1.7 struct segment *seg = seg_find(addr);
597 wlott 1.1
598 rtoy 1.7 addr = os_trunc_to_page(addr);
599     len = os_round_up_size_to_page(len);
600 wlott 1.1
601     #ifdef DEBUG
602 rtoy 1.7 fprintf(stderr, ";;; os_invalidate: 0x%08x[0x%08x]\n", addr, len);
603 wlott 1.1 #endif
604    
605 rtoy 1.7 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 wlott 1.1 seg_destroy(seg);
612    
613 rtoy 1.7 last_fault = 0;
614     if (munmap((caddr_t) addr, len) != 0)
615 wlott 1.1 perror("os_invalidate: munmap");
616     }
617     }
618    
619 rtoy 1.7 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 wlott 1.1 {
626 rtoy 1.7 addr = os_trunc_to_page(addr);
627     len = os_round_up_size_to_page(len);
628 wlott 1.1
629     #ifdef DEBUG
630 rtoy 1.7 fprintf(stderr, ";;; os_map: 0x%08x[0x%08x]\n", addr, len);
631 wlott 1.1 #endif
632    
633 rtoy 1.7 return map_and_remember(addr, len, PROT_DEFAULT, fd, offset, TRUE);
634 wlott 1.1 }
635    
636 rtoy 1.7 void
637     os_flush_icache(address, length)
638     os_vm_address_t address;
639     os_vm_size_t length;
640 wlott 1.1 {
641     #if defined(MACH) && defined(mips)
642 rtoy 1.7 vm_machine_attribute_val_t flush;
643     kern_return_t kr;
644 wlott 1.1
645 rtoy 1.7 flush = MATTR_VAL_ICACHE_FLUSH;
646 wlott 1.1
647 rtoy 1.7 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 wlott 1.1 #endif
652 rtoy 1.7 #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 dtc 1.4
669 rtoy 1.7 if (traceit)
670     fprintf(stderr, ";;;iflush %p - %x\n", address, length);
671     flush_icache(address, length);
672     }
673 dtc 1.4 #endif
674 wlott 1.1 }
675    
676 rtoy 1.7 void
677     os_protect(addr, len, prot)
678     os_vm_address_t addr;
679     os_vm_size_t len;
680     int prot;
681 wlott 1.1 {
682 rtoy 1.7 struct segment *seg = seg_find(addr);
683 wlott 1.1
684 rtoy 1.7 addr = os_trunc_to_page(addr);
685     len = os_round_up_size_to_page(len);
686 wlott 1.1
687     #ifdef DEBUG
688 rtoy 1.7 fprintf(stderr, ";;; os_protect: 0x%08x[0x%08x]\n", addr, len);
689 wlott 1.1 #endif
690    
691 rtoy 1.7 if (seg != NULL) {
692     int old_prot = seg->protection;
693 wlott 1.1
694 rtoy 1.7 if (prot != old_prot) {
695 wlott 1.1 /*
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 rtoy 1.7 seg_force_resident(seg, addr, len);
700 wlott 1.1
701 rtoy 1.7 seg_change_range(seg, addr, len, prot, seg->mapped_fd,
702     seg->file_offset);
703 wlott 1.1
704 rtoy 1.7 if (mprotect((caddr_t) addr, (long) len, prot) != 0)
705 wlott 1.1 perror("os_unprotect: mprotect");
706     }
707 rtoy 1.7 } else
708     fprintf(stderr, "os_protect: Unknown segment: 0x%08x[0x%08x]\n", addr,
709     len);
710 wlott 1.1 }
711    
712 rtoy 1.7 boolean
713     valid_addr(test)
714     os_vm_address_t test;
715 wlott 1.1 {
716 rtoy 1.7 return seg_find(test) != NULL;
717 wlott 1.1 }
718    
719     /* ---------------------------------------------------------------- */
720    
721 rtoy 1.7 static boolean
722     maybe_gc(HANDLER_ARGS)
723 wlott 1.1 {
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 rtoy 1.7 static already_trying = 0;
732 wlott 1.1
733 rtoy 1.7 if (already_trying)
734 wlott 1.1 return FALSE;
735    
736 ram 1.3 SAVE_CONTEXT();
737    
738 rtoy 1.7 sigprocmask(SIG_SETMASK, &context->uc_sigmask, 0);
739 wlott 1.1
740 rtoy 1.7 already_trying = TRUE;
741     did_gc = interrupt_maybe_gc(signal, code, context);
742     already_trying = FALSE;
743 wlott 1.1
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 ram 1.3 #ifndef SOLARIS
756 rtoy 1.7 void
757     segv_handler(HANDLER_ARGS, caddr_t addr)
758 ram 1.3 #else
759 rtoy 1.7 void
760     segv_handler(HANDLER_ARGS)
761     #endif /* SOLARIS */
762 wlott 1.1 {
763 ram 1.3 #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 rtoy 1.7 struct segment *seg = seg_find(addr);
771 wlott 1.1
772 rtoy 1.7 if ((caddr_t) last_fault == addr) {
773     if (seg != NULL && maybe_gc(signal, code, context))
774 wlott 1.1 /* we just garbage collected */
775     return;
776 rtoy 1.7 else {
777 wlott 1.1 /* a *real* protection fault */
778     fprintf(stderr,
779     "segv_handler: Real protection violation: 0x%08x\n",
780     addr);
781 rtoy 1.7 interrupt_handle_now(signal, code, context);
782 wlott 1.1 }
783 rtoy 1.7 } else
784     last_fault = (os_vm_address_t) addr;
785 wlott 1.1
786 rtoy 1.7 if (seg != NULL) {
787 wlott 1.1 int err;
788 rtoy 1.7
789 wlott 1.1 /* round down to a page */
790 rtoy 1.7 os_vm_address_t block =
791 wlott 1.1
792 rtoy 1.7 (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 wlott 1.1 }
799 rtoy 1.7 if (block + length > seg->start + seg->length)
800     length = seg->start + seg->length - block;
801 wlott 1.1
802     #if 0
803     /* unmap it. probably redundant. */
804 rtoy 1.7 if (munmap((caddr_t) block, length) == -1)
805 wlott 1.1 perror("segv_handler: munmap");
806     #endif
807    
808     /* and remap it with more permissions */
809 rtoy 1.7 err = (int)
810     mmap((caddr_t) block,
811 wlott 1.1 length,
812     seg->protection,
813 rtoy 1.7 MAP_PRIVATE | MAP_FIXED,
814 wlott 1.1 seg->mapped_fd,
815 rtoy 1.7 seg->file_offset == OFFSET_NONE
816     ? 0 : seg->file_offset + (block - seg->start));
817 wlott 1.1
818     if (err == -1) {
819     perror("segv_handler: mmap");
820 rtoy 1.7 interrupt_handle_now(signal, code, context);
821 wlott 1.1 }
822 rtoy 1.7 } else {
823     fprintf(stderr, "segv_handler: 0x%08x not in any segment\n", addr);
824     interrupt_handle_now(signal, code, context);
825 wlott 1.1 }
826     }
827     /*
828     * note that we check for a gc-trigger hit even if it's not a PROT error
829     */
830 rtoy 1.7 else if (!maybe_gc(signal, code, context)) {
831     static int nomap_count = 0;
832 wlott 1.1
833 rtoy 1.7 if (CODE(code) == OS_MAPERR) {
834     if (nomap_count == 0) {
835 wlott 1.1 fprintf(stderr,
836 rtoy 1.7 "segv_handler: No mapping fault: 0x%08x\n", addr);
837 wlott 1.1 nomap_count++;
838 rtoy 1.7 } else {
839 wlott 1.1 /*
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 rtoy 1.7 } else if (OS_HASERRNO(code)) {
849     errno = OS_ERRNO(code);
850 wlott 1.1 perror("segv_handler: Object error");
851     }
852    
853 rtoy 1.7 interrupt_handle_now(signal, code, context);
854 wlott 1.1
855 rtoy 1.7 if (CODE(code) == OS_MAPERR)
856 wlott 1.1 nomap_count--;
857     }
858     }
859    
860 rtoy 1.7 void
861 cshapiro 1.9 os_install_interrupt_handlers(void)
862 wlott 1.1 {
863 rtoy 1.7 interrupt_install_low_level_handler(SIGSEGV, segv_handler);
864 wlott 1.1 }
865 ram 1.3
866    
867     #ifdef SOLARIS
868    
869    
870     /* function defintions for register lvalues */
871    
872 rtoy 1.7 int *
873     solaris_register_address(struct ucontext *context, int reg)
874 ram 1.3 {
875     if (reg == 0) {
876     static int zero;
877    
878     zero = 0;
879    
880     return &zero;
881     } else if (reg < 16) {
882 rtoy 1.7 return &context->uc_mcontext.gregs[reg + 3];
883 ram 1.3 } else if (reg < 32) {
884 rtoy 1.7 int *sp = (int *) context->uc_mcontext.gregs[REG_SP];
885    
886     return &sp[reg - 16];
887 ram 1.3 } else
888     return 0;
889     }
890 rtoy 1.7
891 ram 1.3 /* function defintions for backward compatibilty and static linking */
892    
893     #if 0
894 rtoy 1.7 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 ram 1.3 #endif
918    
919     /* For now we put in some porting functions */
920    
921 dtc 1.4 #ifndef SOLARIS25
922 ram 1.3 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 rtoy 1.7 struct rusage {
944     struct timeval ru_utime; /* user time used */
945     struct timeval ru_stime; /* system time used */
946     long ru_maxrss;
947 ram 1.3 #define ru_first ru_ixrss
948 rtoy 1.7 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 ram 1.3 #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 rtoy 1.7
970 ram 1.3 return 0;
971     }
972    
973     int
974 cshapiro 1.9 setreuid(void)
975 ram 1.3 {
976 rtoy 1.7 fprintf(stderr, "setreuid unimplemented\n");
977 ram 1.3 errno = ENOSYS;
978     return -1;
979     }
980    
981     int
982 cshapiro 1.9 setregid(void)
983 ram 1.3 {
984 rtoy 1.7 fprintf(stderr, "setregid unimplemented\n");
985 ram 1.3 errno = ENOSYS;
986     return -1;
987     }
988    
989     int
990 cshapiro 1.9 gethostid(void)
991 ram 1.3 {
992 rtoy 1.7 fprintf(stderr, "gethostid unimplemented\n");
993 ram 1.3 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 dtc 1.4 #endif
1007 ram 1.3
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 dtc 1.4 #ifndef SOLARIS25
1022 ram 1.3 int
1023     wait3(int *status, int options, struct rusage *rp)
1024     {
1025     if (rp)
1026     memset(rp, 0, sizeof(struct rusage));
1027 rtoy 1.7
1028 ram 1.3 return waitpid(-1, status, options);
1029     }
1030 dtc 1.4 #endif
1031 ram 1.3
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 dtc 1.4 }
1045    
1046 ram 1.3 #endif /* SOLARIS */
1047 dtc 1.6
1048 rtoy 1.7 os_vm_address_t round_up_sparse_size(os_vm_address_t addr)
1049 dtc 1.6 {
1050 rtoy 1.7 return (addr + SPARSE_BLOCK_SIZE - 1) & ~SPARSE_SIZE_MASK;
1051 dtc 1.6 }
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 rtoy 1.7 static os_vm_address_t spaces[] = {
1059     READ_ONLY_SPACE_START, STATIC_SPACE_START,
1060     BINDING_STACK_START, CONTROL_STACK_START
1061 dtc 1.6 };
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 rtoy 1.7 static unsigned long space_size[] = {
1071     READ_ONLY_SPACE_SIZE, STATIC_SPACE_SIZE,
1072     BINDING_STACK_SIZE, CONTROL_STACK_SIZE
1073 dtc 1.6 };
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 rtoy 1.7 void
1083     make_holes(void)
1084 dtc 1.6 {
1085 rtoy 1.7 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 dtc 1.6
1110 rtoy 1.7 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 dtc 1.6 }
1116 rtoy 1.7 os_protect(hole, HOLE_SIZE, 0);
1117 dtc 1.6
1118 rtoy 1.7 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 dtc 1.6 }
1125 rtoy 1.7 os_protect(hole, HOLE_SIZE, 0);
1126 dtc 1.6 }

  ViewVC Help
Powered by ViewVC 1.1.5