ViewVC Help
View File | Revision Log | Show Annotations | Revision Graph | Root Listing
root/cebix/BasiliskII/src/Unix/vm_alloc.cpp
Revision: 1.3
Committed: 2001-07-07T09:07:38Z (23 years, 4 months ago) by gbeauche
Branch: MAIN
Changes since 1.2: +8 -1 lines
Log Message:
- Try to map memory contiguously with base addresses returned in increasing
  order. No host memory region used for Mac emulation (ScratchMem, RAM, ROM,
  frame buffer) shall be allocated below the RAM space. Actually, MEMBaseDiff
  should be set to the min(above-mentioned address spaces).
  ==> Temporary fix for 64-bit addressing systems (e.g. Linux/ia64)

File Contents

# Content
1 /*
2 * vm_alloc.cpp - Wrapper to various virtual memory allocation schemes
3 * (supports mmap, vm_allocate or fallbacks to malloc)
4 *
5 * Basilisk II (C) 1997-2001 Christian Bauer
6 *
7 * This program is free software; you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License as published by
9 * the Free Software Foundation; either version 2 of the License, or
10 * (at your option) any later version.
11 *
12 * This program is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 * GNU General Public License for more details.
16 *
17 * You should have received a copy of the GNU General Public License
18 * along with this program; if not, write to the Free Software
19 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
20 */
21
22 #ifdef HAVE_CONFIG_H
23 #include "config.h"
24 #endif
25
26 // TODO: Win32 VMs ?
27 #include <stdlib.h>
28 #include <string.h>
29 #include "vm_alloc.h"
30
31 #ifdef HAVE_MACH_VM
32 #ifndef HAVE_MACH_TASK_SELF
33 #ifdef HAVE_TASK_SELF
34 #define mach_task_self task_self
35 #else
36 #error "No task_self(), you lose."
37 #endif
38 #endif
39 #endif
40
41 #ifdef HAVE_MMAP_VM
42 static char * next_address = 0;
43 #ifdef HAVE_MMAP_ANON
44 #define map_flags (MAP_PRIVATE | MAP_ANON)
45 #define zero_fd -1
46 #else
47 #ifdef HAVE_MMAP_ANONYMOUS
48 #define map_flags (MAP_PRIVATE | MAP_ANONYMOUS)
49 #define zero_fd -1
50 #else
51 #ifdef HAVE_FCNTL_H
52 #include <fcntl.h>
53 #endif
54 #define map_flags (MAP_PRIVATE)
55 static int zero_fd = -1;
56 #endif
57 #endif
58 #endif
59
60 /* Initialize the VM system. Returns 0 if successful, -1 for errors. */
61
62 int vm_init(void)
63 {
64 #ifdef HAVE_MMAP_VM
65 #ifndef zero_fd
66 zero_fd = open("/dev/zero", O_RDWR);
67 if (zero_fd < 0)
68 return -1;
69 #endif
70 #endif
71 return 0;
72 }
73
74 /* Deallocate all internal data used to wrap virtual memory allocators. */
75
76 void vm_exit(void)
77 {
78 #ifdef HAVE_MMAP_VM
79 #ifndef zero_fd
80 close(zero_fd);
81 #endif
82 #endif
83 }
84
85 /* Allocate zero-filled memory of SIZE bytes. The mapping is private
86 and default protection bits are read / write. The return value
87 is the actual mapping address chosen or VM_MAP_FAILED for errors. */
88
89 void * vm_acquire(size_t size)
90 {
91 void * addr;
92
93 #ifdef HAVE_MACH_VM
94 // vm_allocate() returns a zero-filled memory region
95 if (vm_allocate(mach_task_self(), (vm_address_t *)&addr, size, TRUE) != KERN_SUCCESS)
96 return VM_MAP_FAILED;
97 #else
98 #ifdef HAVE_MMAP_VM
99 if ((addr = mmap(next_address, size, VM_PAGE_DEFAULT, map_flags, zero_fd, 0)) == MAP_FAILED)
100 return VM_MAP_FAILED;
101
102 next_address = (char *)addr + size;
103
104 // Since I don't know the standard behavior of mmap(), zero-fill here
105 if (memset(addr, 0, size) != addr)
106 return VM_MAP_FAILED;
107 #else
108 if ((addr = calloc(size, 1)) == 0)
109 return VM_MAP_FAILED;
110
111 // Omit changes for protections because they are not supported in this mode
112 return addr;
113 #endif
114 #endif
115
116 // Explicitely protect the newly mapped region here because on some systems,
117 // say MacOS X, mmap() doesn't honour the requested protection flags.
118 if (vm_protect(addr, size, VM_PAGE_DEFAULT) != 0)
119 return VM_MAP_FAILED;
120
121 return addr;
122 }
123
124 /* Allocate zero-filled memory at exactly ADDR (which must be page-aligned).
125 Retuns 0 if successful, -1 on errors. */
126
127 int vm_acquire_fixed(void * addr, size_t size)
128 {
129 #ifdef HAVE_MACH_VM
130 // vm_allocate() returns a zero-filled memory region
131 if (vm_allocate(mach_task_self(), (vm_address_t *)&addr, size, 0) != KERN_SUCCESS)
132 return -1;
133 #else
134 #ifdef HAVE_MMAP_VM
135 if (mmap(addr, size, VM_PAGE_DEFAULT, map_flags | MAP_FIXED, zero_fd, 0) == MAP_FAILED)
136 return -1;
137
138 // Since I don't know the standard behavior of mmap(), zero-fill here
139 if (memset(0, 0, size) != 0)
140 return -1;
141 #else
142 // Unsupported
143 return -1;
144 #endif
145 #endif
146
147 // Explicitely protect the newly mapped region here because on some systems,
148 // say MacOS X, mmap() doesn't honour the requested protection flags.
149 if (vm_protect(0, size, VM_PAGE_DEFAULT) != 0)
150 return -1;
151
152 return 0;
153 }
154
155 /* Deallocate any mapping for the region starting at ADDR and extending
156 LEN bytes. Returns 0 if successful, -1 on errors. */
157
158 int vm_release(void * addr, size_t size)
159 {
160 // Safety check: don't try to release memory that was not allocated
161 if (addr == VM_MAP_FAILED)
162 return 0;
163
164 #ifdef HAVE_MACH_VM
165 int ret_code = vm_deallocate(mach_task_self(), (vm_address_t)addr, size);
166 return ret_code == KERN_SUCCESS ? 0 : -1;
167 #else
168 #ifdef HAVE_MMAP_VM
169 int ret_code = munmap(addr, size);
170 return ret_code == 0 ? 0 : -1;
171 #else
172 free(addr);
173 return 0;
174 #endif
175 #endif
176 }
177
178 /* Change the memory protection of the region starting at ADDR and
179 extending LEN bytes to PROT. Returns 0 if successful, -1 for errors. */
180
181 int vm_protect(void * addr, size_t size, int prot)
182 {
183 #ifdef HAVE_MACH_VM
184 int ret_code = vm_protect(mach_task_self(), (vm_address_t)addr, size, 0, prot);
185 return ret_code == KERN_SUCCESS ? 0 : -1;
186 #else
187 #ifdef HAVE_MMAP_VM
188 int ret_code = mprotect(addr, size, prot);
189 return ret_code == 0 ? 0 : -1;
190 #else
191 // Unsupported
192 return -1;
193 #endif
194 #endif
195 }
196
197 #ifdef CONFIGURE_TEST_VM_MAP
198 /* Tests covered here:
199 - TEST_VM_PROT_* program slices actually succeeds when a crash occurs
200 - TEST_VM_MAP_ANON* program slices succeeds when it could be compiled
201 */
202 int main(void)
203 {
204 vm_init();
205
206 #define page_align(address) ((char *)((unsigned long)(address) & -page_size))
207 unsigned long page_size = getpagesize();
208
209 const int area_size = 6 * page_size;
210 volatile char * area = (volatile char *) vm_acquire(area_size);
211 volatile char * fault_address = area + (page_size * 7) / 2;
212
213 #if defined(TEST_VM_MMAP_ANON) || defined(TEST_VM_MMAP_ANONYMOUS)
214 if (area == VM_MAP_FAILED)
215 return 1;
216
217 if (vm_release((char *)area, area_size) < 0)
218 return 1;
219
220 return 0;
221 #endif
222
223 #if defined(TEST_VM_PROT_NONE_READ) || defined(TEST_VM_PROT_NONE_WRITE)
224 if (area == VM_MAP_FAILED)
225 return 0;
226
227 if (vm_protect(page_align(fault_address), page_size, VM_PAGE_NOACCESS) < 0)
228 return 0;
229 #endif
230
231 #if defined(TEST_VM_PROT_RDWR_WRITE)
232 if (area == VM_MAP_FAILED)
233 return 1;
234
235 if (vm_protect(page_align(fault_address), page_size, VM_PAGE_READ) < 0)
236 return 1;
237
238 if (vm_protect(page_align(fault_address), page_size, VM_PAGE_READ | VM_PAGE_WRITE) < 0)
239 return 1;
240 #endif
241
242 #if defined(TEST_VM_PROT_READ_WRITE)
243 if (vm_protect(page_align(fault_address), page_size, VM_PAGE_READ) < 0)
244 return 0;
245 #endif
246
247 #if defined(TEST_VM_PROT_NONE_READ)
248 // this should cause a core dump
249 char foo = *fault_address;
250 return 0;
251 #endif
252
253 #if defined(TEST_VM_PROT_NONE_WRITE) || defined(TEST_VM_PROT_READ_WRITE)
254 // this should cause a core dump
255 *fault_address = 'z';
256 return 0;
257 #endif
258
259 #if defined(TEST_VM_PROT_RDWR_WRITE)
260 // this should not cause a core dump
261 *fault_address = 'z';
262 return 0;
263 #endif
264 }
265 #endif