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