d6d3215a7246bdc55d5666f3fa3830629db83790
[sbcl.git] / src / runtime / sunos-os.c
1 #include <stdio.h>
2 #include <stdlib.h>
3 #include <signal.h>
4 #include <sys/file.h>
5
6 #include <unistd.h>
7 #include <errno.h>
8 #include <sys/param.h>
9 #include <sys/utsname.h>
10
11 #include "os.h"
12 #include "arch.h"
13 #include "interr.h"
14 #include "interrupt.h"
15 #include "globals.h"
16 #include "validate.h"
17 #include "sbcl.h"
18 #include "target-arch-os.h"
19
20 #define OS_VM_DEFAULT_PAGESIZE 8192
21
22 long os_vm_page_size=(-1);
23 static long os_real_page_size=(-1);
24
25 static os_vm_size_t real_page_size_difference=0;
26
27 /* So, this sucks. Versions of Solaris prior to 8 (SunOS releases
28    earlier than 5.8) do not support MAP_ANON passed as a flag to
29    mmap(). However, we would like SBCL compiled on SunOS 5.7 but
30    running on 5.8 to use MAP_ANON, but because of C's lack of
31    introspection at runtime, we can't grab the right value because
32    it's stuffed in a header file somewhere. We can, however, hardcode
33    it, and test at runtime for whether to use it... -- CSR, 2002-05-06 */
34 int KLUDGE_MAYBE_MAP_ANON = 0x0;
35
36 void os_init(void)
37 {
38     struct utsname name;
39     int major_version;
40     int minor_version;
41     
42     uname(&name);
43     major_version = atoi(name.release);
44     if (major_version != 5) {
45         lose("sunos major version=%d (which isn't 5!)", major_version);
46     }
47     minor_version = atoi(name.release+2);
48     if (minor_version == 8) {
49         KLUDGE_MAYBE_MAP_ANON = 0x100;
50     }
51     if (minor_version > 8) {
52         FSHOW((stderr, "os_init: Solaris version greater than 8?\nUnknown MAP_ANON behaviour.\n"));
53     }
54
55     /* I do not understand this at all. FIXME. */
56     os_vm_page_size = os_real_page_size = sysconf(_SC_PAGESIZE);
57
58     if(os_vm_page_size>OS_VM_DEFAULT_PAGESIZE){
59         fprintf(stderr,"os_init: Pagesize too large (%d > %d)\n",
60                 os_vm_page_size,OS_VM_DEFAULT_PAGESIZE);
61         exit(1);
62     } else {
63         /*
64          * we do this because there are apparently dependencies on
65          * the pagesize being OS_VM_DEFAULT_PAGESIZE somewhere...
66          * but since the OS doesn't know we're using this restriction,
67          * we have to grovel around a bit to enforce it, thus anything
68          * that uses real_page_size_difference.
69          */
70         /* FIXME: Is this still true? */
71         real_page_size_difference=OS_VM_DEFAULT_PAGESIZE-os_vm_page_size;
72         os_vm_page_size=OS_VM_DEFAULT_PAGESIZE;
73     }
74 }
75
76 os_vm_address_t os_validate(os_vm_address_t addr, os_vm_size_t len)
77 {
78     int flags = MAP_PRIVATE | MAP_NORESERVE | KLUDGE_MAYBE_MAP_ANON;
79     
80     if (addr) 
81         flags |= MAP_FIXED;
82     
83     addr = mmap(addr, len, 
84                 OS_VM_PROT_ALL, 
85                 flags, 
86                 -1, 0);
87     if (addr == MAP_FAILED) {
88         perror("mmap");
89         lose ("Error in mmap(..)");
90     }
91     
92     return addr;
93 }
94
95 void os_invalidate(os_vm_address_t addr, os_vm_size_t len)
96 {
97     if(munmap((void*) addr, len) == -1)
98         perror("munmap");
99 }
100
101 \f
102
103 os_vm_address_t 
104 os_map(int fd, int offset, os_vm_address_t addr, os_vm_size_t len)
105 {
106
107     addr = mmap(addr, len,
108                 OS_VM_PROT_ALL,
109                 MAP_PRIVATE | MAP_FIXED,
110                 fd, (off_t) offset);
111
112     if (addr == MAP_FAILED) {
113         perror("mmap");
114         lose("Unexpedted mmap(..) failure");
115     }
116   
117     return addr;
118 }
119
120 void
121 os_protect(os_vm_address_t address, os_vm_size_t length, os_vm_prot_t prot)
122 {
123     if(mprotect((void*)address, length, prot) == -1) {
124         perror("mprotect");
125     }
126 }
127
128 static boolean in_range_p(os_vm_address_t a, lispobj sbeg, size_t slen)
129 {
130     char* beg = (char*) sbeg;
131     char* end = (char*) sbeg + slen;
132     char* adr = (char*) a;
133     return (adr >= beg && adr < end);
134 }
135
136 boolean is_valid_lisp_addr(os_vm_address_t addr)
137 {
138     /* Old CMUCL comment:
139        
140        Just assume address is valid if it lies within one of the known
141        spaces.  (Unlike sunos-os which keeps track of every valid page.) */
142     return (   in_range_p(addr, READ_ONLY_SPACE_START, READ_ONLY_SPACE_SIZE)
143                || in_range_p(addr, STATIC_SPACE_START   , STATIC_SPACE_SIZE   )
144                || in_range_p(addr, DYNAMIC_0_SPACE_START, DYNAMIC_SPACE_SIZE  )
145                || in_range_p(addr, DYNAMIC_1_SPACE_START, DYNAMIC_SPACE_SIZE  )
146                || in_range_p(addr, CONTROL_STACK_START  , CONTROL_STACK_SIZE  )
147                || in_range_p(addr, BINDING_STACK_START  , BINDING_STACK_SIZE  ));
148 }
149
150 \f
151
152 #if defined GENCGC
153
154 #error "GENCGC is not yet supported (presumably on x86 solaris?)"
155
156 #else
157
158 static void
159 sigsegv_handler(int signal, siginfo_t *info, void* void_context)
160 {
161     os_context_t *context = arch_os_get_context(&void_context);
162     os_vm_address_t addr;
163
164     addr = arch_get_bad_addr(signal, info, context);
165         /* There's some complicated recovery code in linux-os.c here
166            that I'm currently too confused to understand. Fixme. */
167     if(!interrupt_maybe_gc(signal, info, context)) {
168         interrupt_handle_now(signal, info, context);
169     }
170 }
171
172 #endif
173
174 void
175 os_install_interrupt_handlers()
176 {
177     undoably_install_low_level_interrupt_handler(SIGSEGV,sigsegv_handler);
178 }