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 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

# User Rev Content
1 gbeauche 1.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 gbeauche 1.3 static char * next_address = 0;
43 gbeauche 1.1 #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 gbeauche 1.3 if ((addr = mmap(next_address, size, VM_PAGE_DEFAULT, map_flags, zero_fd, 0)) == MAP_FAILED)
100 gbeauche 1.1 return VM_MAP_FAILED;
101    
102 gbeauche 1.3 next_address = (char *)addr + size;
103    
104 gbeauche 1.1 // 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 cebix 1.2
116 gbeauche 1.1 // 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 gbeauche 1.3 // Safety check: don't try to release memory that was not allocated
161     if (addr == VM_MAP_FAILED)
162     return 0;
163    
164 gbeauche 1.1 #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