Commit a5b85f7959378bc038803e51918e0f64461eb9b6

Authored by ths
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
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);