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 36 int prot1, ret;
37 37  
38 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 41 prot & PROT_READ ? 'r' : '-',
41 42 prot & PROT_WRITE ? 'w' : '-',
42 43 prot & PROT_EXEC ? 'x' : '-');
... ... @@ -151,11 +152,11 @@ static int mmap_frag(target_ulong real_start,
151 152 }
152 153  
153 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 156 int flags, int fd, target_ulong offset)
156 157 {
157 158 target_ulong ret, end, real_start, real_end, retaddr, host_offset, host_len;
158   - long host_start;
  159 + unsigned long host_start;
159 160 #if defined(__alpha__) || defined(__sparc__) || defined(__x86_64__) || \
160 161 defined(__ia64) || defined(__mips__)
161 162 static target_ulong last_start = 0x40000000;
... ... @@ -166,7 +167,8 @@ long target_mmap(target_ulong start, target_ulong len, int prot,
166 167  
167 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 172 start, len,
171 173 prot & PROT_READ ? 'r' : '-',
172 174 prot & PROT_WRITE ? 'w' : '-',
... ... @@ -186,7 +188,7 @@ long target_mmap(target_ulong start, target_ulong len, int prot,
186 188 printf("[MAP_TYPE=0x%x] ", flags & MAP_TYPE);
187 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 193 #endif
192 194  
... ... @@ -209,34 +211,59 @@ long target_mmap(target_ulong start, target_ulong len, int prot,
209 211 last_start += HOST_PAGE_ALIGN(len);
210 212 }
211 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 214 host_offset = offset & qemu_host_page_mask;
235 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 263 host_start = (long)mmap(real_start ? g2h(real_start) : NULL,
237 264 host_len, prot, flags, fd, host_offset);
238 265 if (host_start == -1)
239   - return host_start;
  266 + return -1;
240 267 /* update start so that it points to the file position at 'offset' */
241 268 if (!(flags & MAP_ANONYMOUS))
242 269 host_start += offset - host_offset;
... ... @@ -267,7 +294,7 @@ abort();
267 294 MAP_FIXED | MAP_PRIVATE | MAP_ANONYMOUS,
268 295 -1, 0);
269 296 if (retaddr == -1)
270   - return retaddr;
  297 + return -1;
271 298 pread(fd, g2h(start), len, offset);
272 299 if (!(prot & PROT_WRITE)) {
273 300 ret = target_mprotect(start, len, prot);
... ... @@ -300,7 +327,7 @@ abort();
300 327 prot, flags, fd,
301 328 offset + real_end - qemu_host_page_size - start);
302 329 if (ret == -1)
303   - return ret;
  330 + return -1;
304 331 real_end -= qemu_host_page_size;
305 332 }
306 333  
... ... @@ -314,13 +341,13 @@ abort();
314 341 ret = (long)mmap(g2h(real_start), real_end - real_start,
315 342 prot, flags, fd, offset1);
316 343 if (ret == -1)
317   - return ret;
  344 + return -1;
318 345 }
319 346 the_end1:
320 347 page_set_flags(start, start + len, prot | PAGE_VALID);
321 348 the_end:
322 349 #ifdef DEBUG_MMAP
323   - printf("ret=0x%lx\n", (long)start);
  350 + printf("ret=0x%llx\n", start);
324 351 page_dump(stdout);
325 352 printf("\n");
326 353 #endif
... ... @@ -381,17 +408,18 @@ int target_munmap(target_ulong start, target_ulong len)
381 408  
382 409 /* XXX: currently, we only handle MAP_ANONYMOUS and not MAP_FIXED
383 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 412 target_ulong new_size, unsigned long flags,
386 413 target_ulong new_addr)
387 414 {
388 415 int prot;
  416 + unsigned long host_addr;
389 417  
390 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 423 prot = page_get_flags(old_addr);
396 424 page_set_flags(old_addr, old_addr + old_size, 0);
397 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 164  
165 165 /* mmap.c */
166 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 168 int flags, int fd, target_ulong offset);
169 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 171 target_ulong new_size, unsigned long flags,
172 172 target_ulong new_addr);
173 173 int target_msync(target_ulong start, target_ulong len, int flags);
... ...