0b08cdcd8d6cb04d0a7e7ea3f8a654809aafd7a2
[projects/cmucl/cmucl.git] / src / lisp / mach-os.c
1 /*
2  * $Header: /Volumes/share2/src/cmucl/cvs2git/cvsroot/src/lisp/mach-os.c,v 1.9 2011/09/01 05:18:26 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 Mach version.
11  *
12  */
13
14 #include <stdio.h>
15 #include <mach.h>
16 #include <sys/file.h>
17 #include <signal.h>
18 #include "os.h"
19 #include "arch.h"
20 #include "interrupt.h"
21
22 #define MAX_SEGS 32
23
24 static struct segment {
25     vm_address_t start;
26     vm_size_t length;
27 } addr_map[MAX_SEGS];
28 static int segments = -1;
29
30 vm_size_t os_vm_page_size;
31
32 #if defined(i386) || defined(parisc)
33 mach_port_t
34 task_self(void)
35 {
36     return mach_task_self();
37 }
38 #endif
39
40 void
41 os_init0(const char *argv[], const char *envp[])
42 {}
43
44 void
45 os_init(const char *argv[], const char *envp[])
46 {
47     os_vm_page_size = vm_page_size;
48 }
49
50 os_vm_address_t
51 os_validate(vm_address_t addr, vm_size_t len)
52 {
53     kern_return_t res;
54
55     res = vm_allocate(task_self(), &addr, len, addr == NULL);
56
57     if (res != KERN_SUCCESS)
58         return 0;
59
60     segments = -1;
61
62     vm_protect(task_self(), addr, len, FALSE,
63                VM_PROT_READ | VM_PROT_WRITE | VM_PROT_EXECUTE);
64
65     return addr;
66 }
67
68 void
69 os_invalidate(vm_address_t addr, vm_size_t len)
70 {
71     kern_return_t res;
72
73     res = vm_deallocate(task_self(), addr, len);
74
75     if (res != KERN_SUCCESS)
76         mach_error("Could not vm_allocate memory: ", res);
77
78     segments = -1;
79 }
80
81 vm_address_t
82 os_map(int fd, int offset, vm_address_t addr, vm_size_t len)
83 {
84     kern_return_t res;
85
86     res = map_fd(fd, offset, &addr, 0, len);
87
88     if (res != KERN_SUCCESS) {
89         char buf[256];
90
91         sprintf(buf, "Could not map_fd(%d, %d, 0x%08x, 0x%08x): ",
92                 fd, offset, addr, len);
93         mach_error(buf, res);
94
95         lseek(fd, offset, L_SET);
96         read(fd, addr, len);
97     }
98
99     segments = -1;
100
101     vm_protect(task_self(), addr, len, FALSE,
102                VM_PROT_READ | VM_PROT_WRITE | VM_PROT_EXECUTE);
103
104     return addr;
105 }
106
107 void
108 os_flush_icache(vm_address_t address, vm_size_t length)
109 {
110 #ifdef mips
111     vm_machine_attribute_val_t flush;
112     kern_return_t kr;
113
114     flush = MATTR_VAL_ICACHE_FLUSH;
115
116     kr = vm_machine_attribute(task_self(), address, length,
117                               MATTR_CACHE, &flush);
118     if (kr != KERN_SUCCESS)
119         mach_error("Could not flush the instruction cache", kr);
120 #endif
121 }
122
123 void
124 os_protect(vm_address_t address, vm_size_t length, vm_prot_t protection)
125 {
126     vm_protect(task_self(), address, length, FALSE, protection);
127 }
128
129 boolean
130 valid_addr(test)
131      vm_address_t test;
132 {
133     vm_address_t addr;
134     vm_size_t size;
135     int bullshit;
136     int curseg;
137
138     if (segments == -1) {
139         addr = 0;
140         curseg = 0;
141
142         while (1) {
143             if (vm_region
144                 (task_self(), &addr, &size, &bullshit, &bullshit, &bullshit,
145                  &bullshit, &bullshit, &bullshit) != KERN_SUCCESS)
146                 break;
147
148             if (curseg > 0
149                 && addr_map[curseg - 1].start + addr_map[curseg - 1].length ==
150                 addr) addr_map[curseg - 1].length += size;
151             else {
152                 addr_map[curseg].start = addr;
153                 addr_map[curseg].length = size;
154                 curseg++;
155             }
156
157             addr += size;
158         }
159
160         segments = curseg;
161     }
162
163     for (curseg = 0; curseg < segments; curseg++)
164         if (addr_map[curseg].start <= test
165             && test < addr_map[curseg].start + addr_map[curseg].length)
166             return TRUE;
167     return FALSE;
168 }
169
170 #ifndef ibmrt
171 static void
172 sigbus_handler(int signal, int code, struct sigcontext *context)
173 {
174     if (!interrupt_maybe_gc(signal, code, context))
175         interrupt_handle_now(signal, code, context);
176 }
177 #endif
178
179 void
180 os_install_interrupt_handlers(void)
181 {
182 #ifndef ibmrt
183     interrupt_install_low_level_handler(SIGBUS, sigbus_handler);
184 #endif
185 #ifdef mips
186     interrupt_install_low_level_handler(SIGSEGV, sigbus_handler);
187 #endif
188 }