0.pre8.112:
[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
35    And, in fact, it sucks slightly more, as if you don't use MAP_ANON
36    you need to have /dev/zero open and pass the file descriptor to
37    mmap().  So overall, this counts as a KLUDGE. -- CSR, 2002-05-20 */
38 int KLUDGE_MAYBE_MAP_ANON = 0x0;
39 int kludge_mmap_fd = -1; /* default for MAP_ANON */
40
41 void os_init(void)
42 {
43     struct utsname name;
44     int major_version;
45     int minor_version;
46     
47     uname(&name);
48     major_version = atoi(name.release);
49     if (major_version != 5) {
50         lose("sunos major version=%d (which isn't 5!)", major_version);
51     }
52     minor_version = atoi(name.release+2);
53     if ((minor_version == 8) || (minor_version == 9)) {
54         KLUDGE_MAYBE_MAP_ANON = 0x100;
55     } else if (minor_version > 9) {
56         FSHOW((stderr, "os_init: Solaris version greater than 9?\nUnknown MAP_ANON behaviour.\n"));
57         lose("Unknown mmap() interaction with MAP_ANON");
58     } else { /* minor_version < 8 */
59         kludge_mmap_fd = open("/dev/zero",O_RDONLY);
60         if (kludge_mmap_fd < 0) {
61             perror("open");
62             lose("Error in open(..)");
63         }
64     }
65
66     /* I do not understand this at all. FIXME. */
67     os_vm_page_size = os_real_page_size = sysconf(_SC_PAGESIZE);
68
69     if(os_vm_page_size>OS_VM_DEFAULT_PAGESIZE){
70         fprintf(stderr,"os_init: Pagesize too large (%d > %d)\n",
71                 os_vm_page_size,OS_VM_DEFAULT_PAGESIZE);
72         exit(1);
73     } else {
74         /*
75          * we do this because there are apparently dependencies on
76          * the pagesize being OS_VM_DEFAULT_PAGESIZE somewhere...
77          * but since the OS doesn't know we're using this restriction,
78          * we have to grovel around a bit to enforce it, thus anything
79          * that uses real_page_size_difference.
80          */
81         /* FIXME: Is this still true? */
82         real_page_size_difference=OS_VM_DEFAULT_PAGESIZE-os_vm_page_size;
83         os_vm_page_size=OS_VM_DEFAULT_PAGESIZE;
84     }
85 }
86
87 os_vm_address_t os_validate(os_vm_address_t addr, os_vm_size_t len)
88 {
89     int flags = MAP_PRIVATE | MAP_NORESERVE | KLUDGE_MAYBE_MAP_ANON;
90     if (addr) 
91         flags |= MAP_FIXED;
92
93     addr = mmap(addr, len, 
94                 OS_VM_PROT_ALL, 
95                 flags, 
96                 kludge_mmap_fd, 0);
97
98     if (addr == MAP_FAILED) {
99         perror("mmap");
100         lose ("Error in mmap(..)");
101     }
102     
103     return addr;
104 }
105
106 void os_invalidate(os_vm_address_t addr, os_vm_size_t len)
107 {
108     if(munmap((void*) addr, len) == -1)
109         perror("munmap");
110 }
111
112 \f
113
114 os_vm_address_t 
115 os_map(int fd, int offset, os_vm_address_t addr, os_vm_size_t len)
116 {
117
118     addr = mmap(addr, len,
119                 OS_VM_PROT_ALL,
120                 MAP_PRIVATE | MAP_FIXED,
121                 fd, (off_t) offset);
122
123     if (addr == MAP_FAILED) {
124         perror("mmap");
125         lose("Unexpedted mmap(..) failure");
126     }
127   
128     return addr;
129 }
130
131 void
132 os_protect(os_vm_address_t address, os_vm_size_t length, os_vm_prot_t prot)
133 {
134     if(mprotect((void*)address, length, prot) == -1) {
135         perror("mprotect");
136     }
137 }
138
139 static boolean in_range_p(os_vm_address_t a, lispobj sbeg, size_t slen)
140 {
141     char* beg = (char*) sbeg;
142     char* end = (char*) sbeg + slen;
143     char* adr = (char*) a;
144     return (adr >= beg && adr < end);
145 }
146
147 boolean is_valid_lisp_addr(os_vm_address_t addr)
148 {
149     /* Old CMUCL comment:
150        
151        Just assume address is valid if it lies within one of the known
152        spaces.  (Unlike sunos-os which keeps track of every valid page.) */
153     
154     /* FIXME: this looks like a valid definition for all targets with
155        cheney-gc; it may not be impressively smart (witness the
156        comment above) but maybe associating these functions with the
157        GC rather than the OS would be a maintainability win.  -- CSR,
158        2003-04-04 */
159     struct thread *th;
160     if(in_range_p(addr, READ_ONLY_SPACE_START, READ_ONLY_SPACE_SIZE) ||
161        in_range_p(addr, STATIC_SPACE_START   , STATIC_SPACE_SIZE) ||
162        in_range_p(addr, DYNAMIC_0_SPACE_START, DYNAMIC_SPACE_SIZE) ||
163        in_range_p(addr, DYNAMIC_1_SPACE_START, DYNAMIC_SPACE_SIZE))
164         return 1;
165     for_each_thread(th) {
166         if((th->control_stack_start <= addr) && (addr < th->control_stack_end))
167             return 1;
168         if(in_range_p(addr, th->binding_stack_start, BINDING_STACK_SIZE))
169             return 1;
170     }
171     return 0;
172 }
173 \f
174
175
176 static void
177 sigsegv_handler(int signal, siginfo_t *info, void* void_context)
178 {
179     os_context_t *context = arch_os_get_context(&void_context);
180     os_vm_address_t addr;
181
182     addr = arch_get_bad_addr(signal, info, context);
183     if(!interrupt_maybe_gc(signal, info, context)) {
184         if(!handle_control_stack_guard_triggered(context,addr))
185             interrupt_handle_now(signal, info, context);
186     }
187 }
188
189 void
190 os_install_interrupt_handlers()
191 {
192     undoably_install_low_level_interrupt_handler(SIG_MEMORY_FAULT,
193                                                  sigsegv_handler);
194 }