Commit a5b85f7959378bc038803e51918e0f64461eb9b6
1 parent
0574b6fb
Fix mmap to handle differing host/target page sizes, by Edgar E. Iglesias.
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@3291 c046a42c-6fe2-441c-8c8c-71466251a162
Showing
2 changed files
with
67 additions
and
39 deletions
linux-user/mmap.c
@@ -36,7 +36,8 @@ int target_mprotect(target_ulong start, target_ulong len, int prot) | @@ -36,7 +36,8 @@ int target_mprotect(target_ulong start, target_ulong len, int prot) | ||
36 | int prot1, ret; | 36 | int prot1, ret; |
37 | 37 | ||
38 | #ifdef DEBUG_MMAP | 38 | #ifdef DEBUG_MMAP |
39 | - printf("mprotect: start=0x%lx len=0x%lx prot=%c%c%c\n", start, len, | 39 | + printf("mprotect: start=0x" TARGET_FMT_lx |
40 | + "len=0x" TARGET_FMT_lx " prot=%c%c%c\n", start, len, | ||
40 | prot & PROT_READ ? 'r' : '-', | 41 | prot & PROT_READ ? 'r' : '-', |
41 | prot & PROT_WRITE ? 'w' : '-', | 42 | prot & PROT_WRITE ? 'w' : '-', |
42 | prot & PROT_EXEC ? 'x' : '-'); | 43 | prot & PROT_EXEC ? 'x' : '-'); |
@@ -151,11 +152,11 @@ static int mmap_frag(target_ulong real_start, | @@ -151,11 +152,11 @@ static int mmap_frag(target_ulong real_start, | ||
151 | } | 152 | } |
152 | 153 | ||
153 | /* NOTE: all the constants are the HOST ones */ | 154 | /* NOTE: all the constants are the HOST ones */ |
154 | -long target_mmap(target_ulong start, target_ulong len, int prot, | 155 | +target_long target_mmap(target_ulong start, target_ulong len, int prot, |
155 | int flags, int fd, target_ulong offset) | 156 | int flags, int fd, target_ulong offset) |
156 | { | 157 | { |
157 | target_ulong ret, end, real_start, real_end, retaddr, host_offset, host_len; | 158 | target_ulong ret, end, real_start, real_end, retaddr, host_offset, host_len; |
158 | - long host_start; | 159 | + unsigned long host_start; |
159 | #if defined(__alpha__) || defined(__sparc__) || defined(__x86_64__) || \ | 160 | #if defined(__alpha__) || defined(__sparc__) || defined(__x86_64__) || \ |
160 | defined(__ia64) || defined(__mips__) | 161 | defined(__ia64) || defined(__mips__) |
161 | static target_ulong last_start = 0x40000000; | 162 | static target_ulong last_start = 0x40000000; |
@@ -166,7 +167,8 @@ long target_mmap(target_ulong start, target_ulong len, int prot, | @@ -166,7 +167,8 @@ long target_mmap(target_ulong start, target_ulong len, int prot, | ||
166 | 167 | ||
167 | #ifdef DEBUG_MMAP | 168 | #ifdef DEBUG_MMAP |
168 | { | 169 | { |
169 | - printf("mmap: start=0x%lx len=0x%lx prot=%c%c%c flags=", | 170 | + printf("mmap: start=0x" TARGET_FMT_lx |
171 | + " len=0x" TARGET_FMT_lx " prot=%c%c%c flags=", | ||
170 | start, len, | 172 | start, len, |
171 | prot & PROT_READ ? 'r' : '-', | 173 | prot & PROT_READ ? 'r' : '-', |
172 | prot & PROT_WRITE ? 'w' : '-', | 174 | prot & PROT_WRITE ? 'w' : '-', |
@@ -186,7 +188,7 @@ long target_mmap(target_ulong start, target_ulong len, int prot, | @@ -186,7 +188,7 @@ long target_mmap(target_ulong start, target_ulong len, int prot, | ||
186 | printf("[MAP_TYPE=0x%x] ", flags & MAP_TYPE); | 188 | printf("[MAP_TYPE=0x%x] ", flags & MAP_TYPE); |
187 | break; | 189 | break; |
188 | } | 190 | } |
189 | - printf("fd=%d offset=%lx\n", fd, offset); | 191 | + printf("fd=%d offset=" TARGET_FMT_lx "\n", fd, offset); |
190 | } | 192 | } |
191 | #endif | 193 | #endif |
192 | 194 | ||
@@ -209,34 +211,59 @@ long target_mmap(target_ulong start, target_ulong len, int prot, | @@ -209,34 +211,59 @@ long target_mmap(target_ulong start, target_ulong len, int prot, | ||
209 | last_start += HOST_PAGE_ALIGN(len); | 211 | last_start += HOST_PAGE_ALIGN(len); |
210 | } | 212 | } |
211 | #endif | 213 | #endif |
212 | - if (0 && qemu_host_page_size != qemu_real_host_page_size) { | ||
213 | - /* NOTE: this code is only for debugging with '-p' option */ | ||
214 | - /* ??? Can also occur when TARGET_PAGE_SIZE > host page size. */ | ||
215 | - /* reserve a memory area */ | ||
216 | - /* ??? This needs fixing for remapping. */ | ||
217 | -abort(); | ||
218 | - host_len = HOST_PAGE_ALIGN(len) + qemu_host_page_size - TARGET_PAGE_SIZE; | ||
219 | - real_start = (long)mmap(g2h(real_start), host_len, PROT_NONE, | ||
220 | - MAP_PRIVATE | MAP_ANONYMOUS, -1, 0); | ||
221 | - if (real_start == -1) | ||
222 | - return real_start; | ||
223 | - real_end = real_start + host_len; | ||
224 | - start = HOST_PAGE_ALIGN(real_start); | ||
225 | - end = start + HOST_PAGE_ALIGN(len); | ||
226 | - if (start > real_start) | ||
227 | - munmap((void *)g2h(real_start), start - real_start); | ||
228 | - if (end < real_end) | ||
229 | - munmap((void *)g2h(end), real_end - end); | ||
230 | - /* use it as a fixed mapping */ | ||
231 | - flags |= MAP_FIXED; | ||
232 | - } else { | ||
233 | - /* if not fixed, no need to do anything */ | ||
234 | host_offset = offset & qemu_host_page_mask; | 214 | host_offset = offset & qemu_host_page_mask; |
235 | host_len = len + offset - host_offset; | 215 | host_len = len + offset - host_offset; |
216 | + | ||
217 | + if (qemu_host_page_size > qemu_real_host_page_size) { | ||
218 | + /* | ||
219 | + * The guest expects to see mmapped areas aligned to it's pagesize. | ||
220 | + * If the host's real page size is smaller than the guest's, we need | ||
221 | + * to fixup the maps. It is done by allocating a larger area, | ||
222 | + * displacing the map (if needed) and finally chopping off the spare | ||
223 | + * room at the edges. | ||
224 | + */ | ||
225 | + | ||
226 | + /* | ||
227 | + * We assume qemu_host_page_size is always the same as | ||
228 | + * TARGET_PAGE_SIZE, see exec.c. qemu_real_host_page_size is the | ||
229 | + * hosts real page size. | ||
230 | + */ | ||
231 | + target_ulong host_end; | ||
232 | + unsigned long host_aligned_start; | ||
233 | + | ||
234 | + host_len = HOST_PAGE_ALIGN(host_len + qemu_host_page_size | ||
235 | + - qemu_real_host_page_size); | ||
236 | + host_start = (unsigned long) mmap(real_start ? | ||
237 | + g2h(real_start) : NULL, | ||
238 | + host_len, prot, flags, | ||
239 | + fd, host_offset); | ||
240 | + if (host_start == -1) | ||
241 | + return -1; | ||
242 | + | ||
243 | + host_end = host_start + host_len; | ||
244 | + | ||
245 | + /* Find start and end, aligned to the targets pagesize with-in the | ||
246 | + large mmaped area. */ | ||
247 | + host_aligned_start = TARGET_PAGE_ALIGN(host_start); | ||
248 | + if (!(flags & MAP_ANONYMOUS)) | ||
249 | + host_aligned_start += offset - host_offset; | ||
250 | + | ||
251 | + start = h2g(host_aligned_start); | ||
252 | + end = start + TARGET_PAGE_ALIGN(len); | ||
253 | + | ||
254 | + /* Chop off the leftovers, if any. */ | ||
255 | + if (host_aligned_start > host_start) | ||
256 | + munmap((void *)host_start, host_aligned_start - host_start); | ||
257 | + if (end < host_end) | ||
258 | + munmap((void *)g2h(end), host_end - end); | ||
259 | + | ||
260 | + goto the_end1; | ||
261 | + } else { | ||
262 | + /* if not fixed, no need to do anything */ | ||
236 | host_start = (long)mmap(real_start ? g2h(real_start) : NULL, | 263 | host_start = (long)mmap(real_start ? g2h(real_start) : NULL, |
237 | host_len, prot, flags, fd, host_offset); | 264 | host_len, prot, flags, fd, host_offset); |
238 | if (host_start == -1) | 265 | if (host_start == -1) |
239 | - return host_start; | 266 | + return -1; |
240 | /* update start so that it points to the file position at 'offset' */ | 267 | /* update start so that it points to the file position at 'offset' */ |
241 | if (!(flags & MAP_ANONYMOUS)) | 268 | if (!(flags & MAP_ANONYMOUS)) |
242 | host_start += offset - host_offset; | 269 | host_start += offset - host_offset; |
@@ -267,7 +294,7 @@ abort(); | @@ -267,7 +294,7 @@ abort(); | ||
267 | MAP_FIXED | MAP_PRIVATE | MAP_ANONYMOUS, | 294 | MAP_FIXED | MAP_PRIVATE | MAP_ANONYMOUS, |
268 | -1, 0); | 295 | -1, 0); |
269 | if (retaddr == -1) | 296 | if (retaddr == -1) |
270 | - return retaddr; | 297 | + return -1; |
271 | pread(fd, g2h(start), len, offset); | 298 | pread(fd, g2h(start), len, offset); |
272 | if (!(prot & PROT_WRITE)) { | 299 | if (!(prot & PROT_WRITE)) { |
273 | ret = target_mprotect(start, len, prot); | 300 | ret = target_mprotect(start, len, prot); |
@@ -300,7 +327,7 @@ abort(); | @@ -300,7 +327,7 @@ abort(); | ||
300 | prot, flags, fd, | 327 | prot, flags, fd, |
301 | offset + real_end - qemu_host_page_size - start); | 328 | offset + real_end - qemu_host_page_size - start); |
302 | if (ret == -1) | 329 | if (ret == -1) |
303 | - return ret; | 330 | + return -1; |
304 | real_end -= qemu_host_page_size; | 331 | real_end -= qemu_host_page_size; |
305 | } | 332 | } |
306 | 333 | ||
@@ -314,13 +341,13 @@ abort(); | @@ -314,13 +341,13 @@ abort(); | ||
314 | ret = (long)mmap(g2h(real_start), real_end - real_start, | 341 | ret = (long)mmap(g2h(real_start), real_end - real_start, |
315 | prot, flags, fd, offset1); | 342 | prot, flags, fd, offset1); |
316 | if (ret == -1) | 343 | if (ret == -1) |
317 | - return ret; | 344 | + return -1; |
318 | } | 345 | } |
319 | the_end1: | 346 | the_end1: |
320 | page_set_flags(start, start + len, prot | PAGE_VALID); | 347 | page_set_flags(start, start + len, prot | PAGE_VALID); |
321 | the_end: | 348 | the_end: |
322 | #ifdef DEBUG_MMAP | 349 | #ifdef DEBUG_MMAP |
323 | - printf("ret=0x%lx\n", (long)start); | 350 | + printf("ret=0x%llx\n", start); |
324 | page_dump(stdout); | 351 | page_dump(stdout); |
325 | printf("\n"); | 352 | printf("\n"); |
326 | #endif | 353 | #endif |
@@ -381,17 +408,18 @@ int target_munmap(target_ulong start, target_ulong len) | @@ -381,17 +408,18 @@ int target_munmap(target_ulong start, target_ulong len) | ||
381 | 408 | ||
382 | /* XXX: currently, we only handle MAP_ANONYMOUS and not MAP_FIXED | 409 | /* XXX: currently, we only handle MAP_ANONYMOUS and not MAP_FIXED |
383 | blocks which have been allocated starting on a host page */ | 410 | blocks which have been allocated starting on a host page */ |
384 | -long target_mremap(target_ulong old_addr, target_ulong old_size, | 411 | +target_long target_mremap(target_ulong old_addr, target_ulong old_size, |
385 | target_ulong new_size, unsigned long flags, | 412 | target_ulong new_size, unsigned long flags, |
386 | target_ulong new_addr) | 413 | target_ulong new_addr) |
387 | { | 414 | { |
388 | int prot; | 415 | int prot; |
416 | + unsigned long host_addr; | ||
389 | 417 | ||
390 | /* XXX: use 5 args syscall */ | 418 | /* XXX: use 5 args syscall */ |
391 | - new_addr = (long)mremap(g2h(old_addr), old_size, new_size, flags); | ||
392 | - if (new_addr == -1) | ||
393 | - return new_addr; | ||
394 | - new_addr = h2g(new_addr); | 419 | + host_addr = (long)mremap(g2h(old_addr), old_size, new_size, flags); |
420 | + if (host_addr == -1) | ||
421 | + return -1; | ||
422 | + new_addr = h2g(host_addr); | ||
395 | prot = page_get_flags(old_addr); | 423 | prot = page_get_flags(old_addr); |
396 | page_set_flags(old_addr, old_addr + old_size, 0); | 424 | page_set_flags(old_addr, old_addr + old_size, 0); |
397 | page_set_flags(new_addr, new_addr + new_size, prot | PAGE_VALID); | 425 | page_set_flags(new_addr, new_addr + new_size, prot | PAGE_VALID); |
linux-user/qemu.h
@@ -164,10 +164,10 @@ int do_vm86(CPUX86State *env, long subfunction, target_ulong v86_addr); | @@ -164,10 +164,10 @@ int do_vm86(CPUX86State *env, long subfunction, target_ulong v86_addr); | ||
164 | 164 | ||
165 | /* mmap.c */ | 165 | /* mmap.c */ |
166 | int target_mprotect(target_ulong start, target_ulong len, int prot); | 166 | int target_mprotect(target_ulong start, target_ulong len, int prot); |
167 | -long target_mmap(target_ulong start, target_ulong len, int prot, | 167 | +target_long target_mmap(target_ulong start, target_ulong len, int prot, |
168 | int flags, int fd, target_ulong offset); | 168 | int flags, int fd, target_ulong offset); |
169 | int target_munmap(target_ulong start, target_ulong len); | 169 | int target_munmap(target_ulong start, target_ulong len); |
170 | -long target_mremap(target_ulong old_addr, target_ulong old_size, | 170 | +target_long target_mremap(target_ulong old_addr, target_ulong old_size, |
171 | target_ulong new_size, unsigned long flags, | 171 | target_ulong new_size, unsigned long flags, |
172 | target_ulong new_addr); | 172 | target_ulong new_addr); |
173 | int target_msync(target_ulong start, target_ulong len, int flags); | 173 | int target_msync(target_ulong start, target_ulong len, int flags); |