]> git.proxmox.com Git - mirror_qemu.git/blob - linux-user/mmap.c
linux-user: fix mmap/munmap/mprotect/mremap/shmat
[mirror_qemu.git] / linux-user / mmap.c
1 /*
2 * mmap support for qemu
3 *
4 * Copyright (c) 2003 Fabrice Bellard
5 *
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; either version 2 of the License, or
9 * (at your option) any later version.
10 *
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
15 *
16 * You should have received a copy of the GNU General Public License
17 * along with this program; if not, see <http://www.gnu.org/licenses/>.
18 */
19 #include "qemu/osdep.h"
20
21 #include "qemu.h"
22 #include "qemu-common.h"
23 #include "translate-all.h"
24
25 //#define DEBUG_MMAP
26
27 static pthread_mutex_t mmap_mutex = PTHREAD_MUTEX_INITIALIZER;
28 static __thread int mmap_lock_count;
29
30 void mmap_lock(void)
31 {
32 if (mmap_lock_count++ == 0) {
33 pthread_mutex_lock(&mmap_mutex);
34 }
35 }
36
37 void mmap_unlock(void)
38 {
39 if (--mmap_lock_count == 0) {
40 pthread_mutex_unlock(&mmap_mutex);
41 }
42 }
43
44 bool have_mmap_lock(void)
45 {
46 return mmap_lock_count > 0 ? true : false;
47 }
48
49 /* Grab lock to make sure things are in a consistent state after fork(). */
50 void mmap_fork_start(void)
51 {
52 if (mmap_lock_count)
53 abort();
54 pthread_mutex_lock(&mmap_mutex);
55 }
56
57 void mmap_fork_end(int child)
58 {
59 if (child)
60 pthread_mutex_init(&mmap_mutex, NULL);
61 else
62 pthread_mutex_unlock(&mmap_mutex);
63 }
64
65 /* NOTE: all the constants are the HOST ones, but addresses are target. */
66 int target_mprotect(abi_ulong start, abi_ulong len, int prot)
67 {
68 abi_ulong end, host_start, host_end, addr;
69 int prot1, ret;
70
71 #ifdef DEBUG_MMAP
72 printf("mprotect: start=0x" TARGET_ABI_FMT_lx
73 "len=0x" TARGET_ABI_FMT_lx " prot=%c%c%c\n", start, len,
74 prot & PROT_READ ? 'r' : '-',
75 prot & PROT_WRITE ? 'w' : '-',
76 prot & PROT_EXEC ? 'x' : '-');
77 #endif
78
79 if ((start & ~TARGET_PAGE_MASK) != 0)
80 return -EINVAL;
81 len = TARGET_PAGE_ALIGN(len);
82 end = start + len;
83 if (!guest_range_valid(start, len)) {
84 return -ENOMEM;
85 }
86 prot &= PROT_READ | PROT_WRITE | PROT_EXEC;
87 if (len == 0)
88 return 0;
89
90 mmap_lock();
91 host_start = start & qemu_host_page_mask;
92 host_end = HOST_PAGE_ALIGN(end);
93 if (start > host_start) {
94 /* handle host page containing start */
95 prot1 = prot;
96 for(addr = host_start; addr < start; addr += TARGET_PAGE_SIZE) {
97 prot1 |= page_get_flags(addr);
98 }
99 if (host_end == host_start + qemu_host_page_size) {
100 for(addr = end; addr < host_end; addr += TARGET_PAGE_SIZE) {
101 prot1 |= page_get_flags(addr);
102 }
103 end = host_end;
104 }
105 ret = mprotect(g2h(host_start), qemu_host_page_size, prot1 & PAGE_BITS);
106 if (ret != 0)
107 goto error;
108 host_start += qemu_host_page_size;
109 }
110 if (end < host_end) {
111 prot1 = prot;
112 for(addr = end; addr < host_end; addr += TARGET_PAGE_SIZE) {
113 prot1 |= page_get_flags(addr);
114 }
115 ret = mprotect(g2h(host_end - qemu_host_page_size), qemu_host_page_size,
116 prot1 & PAGE_BITS);
117 if (ret != 0)
118 goto error;
119 host_end -= qemu_host_page_size;
120 }
121
122 /* handle the pages in the middle */
123 if (host_start < host_end) {
124 ret = mprotect(g2h(host_start), host_end - host_start, prot);
125 if (ret != 0)
126 goto error;
127 }
128 page_set_flags(start, start + len, prot | PAGE_VALID);
129 mmap_unlock();
130 return 0;
131 error:
132 mmap_unlock();
133 return ret;
134 }
135
136 /* map an incomplete host page */
137 static int mmap_frag(abi_ulong real_start,
138 abi_ulong start, abi_ulong end,
139 int prot, int flags, int fd, abi_ulong offset)
140 {
141 abi_ulong real_end, addr;
142 void *host_start;
143 int prot1, prot_new;
144
145 real_end = real_start + qemu_host_page_size;
146 host_start = g2h(real_start);
147
148 /* get the protection of the target pages outside the mapping */
149 prot1 = 0;
150 for(addr = real_start; addr < real_end; addr++) {
151 if (addr < start || addr >= end)
152 prot1 |= page_get_flags(addr);
153 }
154
155 if (prot1 == 0) {
156 /* no page was there, so we allocate one */
157 void *p = mmap(host_start, qemu_host_page_size, prot,
158 flags | MAP_ANONYMOUS, -1, 0);
159 if (p == MAP_FAILED)
160 return -1;
161 prot1 = prot;
162 }
163 prot1 &= PAGE_BITS;
164
165 prot_new = prot | prot1;
166 if (!(flags & MAP_ANONYMOUS)) {
167 /* msync() won't work here, so we return an error if write is
168 possible while it is a shared mapping */
169 if ((flags & MAP_TYPE) == MAP_SHARED &&
170 (prot & PROT_WRITE))
171 return -1;
172
173 /* adjust protection to be able to read */
174 if (!(prot1 & PROT_WRITE))
175 mprotect(host_start, qemu_host_page_size, prot1 | PROT_WRITE);
176
177 /* read the corresponding file data */
178 if (pread(fd, g2h(start), end - start, offset) == -1)
179 return -1;
180
181 /* put final protection */
182 if (prot_new != (prot1 | PROT_WRITE))
183 mprotect(host_start, qemu_host_page_size, prot_new);
184 } else {
185 if (prot_new != prot1) {
186 mprotect(host_start, qemu_host_page_size, prot_new);
187 }
188 if (prot_new & PROT_WRITE) {
189 memset(g2h(start), 0, end - start);
190 }
191 }
192 return 0;
193 }
194
195 #if HOST_LONG_BITS == 64 && TARGET_ABI_BITS == 64
196 # define TASK_UNMAPPED_BASE (1ul << 38)
197 #else
198 # define TASK_UNMAPPED_BASE 0x40000000
199 #endif
200 abi_ulong mmap_next_start = TASK_UNMAPPED_BASE;
201
202 unsigned long last_brk;
203
204 /* Subroutine of mmap_find_vma, used when we have pre-allocated a chunk
205 of guest address space. */
206 static abi_ulong mmap_find_vma_reserved(abi_ulong start, abi_ulong size)
207 {
208 abi_ulong addr;
209 abi_ulong end_addr;
210 int prot;
211 int looped = 0;
212
213 if (size > reserved_va) {
214 return (abi_ulong)-1;
215 }
216
217 size = HOST_PAGE_ALIGN(size);
218 end_addr = start + size;
219 if (end_addr > reserved_va) {
220 end_addr = reserved_va;
221 }
222 addr = end_addr - qemu_host_page_size;
223
224 while (1) {
225 if (addr > end_addr) {
226 if (looped) {
227 return (abi_ulong)-1;
228 }
229 end_addr = reserved_va;
230 addr = end_addr - qemu_host_page_size;
231 looped = 1;
232 continue;
233 }
234 prot = page_get_flags(addr);
235 if (prot) {
236 end_addr = addr;
237 }
238 if (addr && addr + size == end_addr) {
239 break;
240 }
241 addr -= qemu_host_page_size;
242 }
243
244 if (start == mmap_next_start) {
245 mmap_next_start = addr;
246 }
247
248 return addr;
249 }
250
251 /*
252 * Find and reserve a free memory area of size 'size'. The search
253 * starts at 'start'.
254 * It must be called with mmap_lock() held.
255 * Return -1 if error.
256 */
257 abi_ulong mmap_find_vma(abi_ulong start, abi_ulong size)
258 {
259 void *ptr, *prev;
260 abi_ulong addr;
261 int wrapped, repeat;
262
263 /* If 'start' == 0, then a default start address is used. */
264 if (start == 0) {
265 start = mmap_next_start;
266 } else {
267 start &= qemu_host_page_mask;
268 }
269
270 size = HOST_PAGE_ALIGN(size);
271
272 if (reserved_va) {
273 return mmap_find_vma_reserved(start, size);
274 }
275
276 addr = start;
277 wrapped = repeat = 0;
278 prev = 0;
279
280 for (;; prev = ptr) {
281 /*
282 * Reserve needed memory area to avoid a race.
283 * It should be discarded using:
284 * - mmap() with MAP_FIXED flag
285 * - mremap() with MREMAP_FIXED flag
286 * - shmat() with SHM_REMAP flag
287 */
288 ptr = mmap(g2h(addr), size, PROT_NONE,
289 MAP_ANONYMOUS|MAP_PRIVATE|MAP_NORESERVE, -1, 0);
290
291 /* ENOMEM, if host address space has no memory */
292 if (ptr == MAP_FAILED) {
293 return (abi_ulong)-1;
294 }
295
296 /* Count the number of sequential returns of the same address.
297 This is used to modify the search algorithm below. */
298 repeat = (ptr == prev ? repeat + 1 : 0);
299
300 if (h2g_valid(ptr + size - 1)) {
301 addr = h2g(ptr);
302
303 if ((addr & ~TARGET_PAGE_MASK) == 0) {
304 /* Success. */
305 if (start == mmap_next_start && addr >= TASK_UNMAPPED_BASE) {
306 mmap_next_start = addr + size;
307 }
308 return addr;
309 }
310
311 /* The address is not properly aligned for the target. */
312 switch (repeat) {
313 case 0:
314 /* Assume the result that the kernel gave us is the
315 first with enough free space, so start again at the
316 next higher target page. */
317 addr = TARGET_PAGE_ALIGN(addr);
318 break;
319 case 1:
320 /* Sometimes the kernel decides to perform the allocation
321 at the top end of memory instead. */
322 addr &= TARGET_PAGE_MASK;
323 break;
324 case 2:
325 /* Start over at low memory. */
326 addr = 0;
327 break;
328 default:
329 /* Fail. This unaligned block must the last. */
330 addr = -1;
331 break;
332 }
333 } else {
334 /* Since the result the kernel gave didn't fit, start
335 again at low memory. If any repetition, fail. */
336 addr = (repeat ? -1 : 0);
337 }
338
339 /* Unmap and try again. */
340 munmap(ptr, size);
341
342 /* ENOMEM if we checked the whole of the target address space. */
343 if (addr == (abi_ulong)-1) {
344 return (abi_ulong)-1;
345 } else if (addr == 0) {
346 if (wrapped) {
347 return (abi_ulong)-1;
348 }
349 wrapped = 1;
350 /* Don't actually use 0 when wrapping, instead indicate
351 that we'd truly like an allocation in low memory. */
352 addr = (mmap_min_addr > TARGET_PAGE_SIZE
353 ? TARGET_PAGE_ALIGN(mmap_min_addr)
354 : TARGET_PAGE_SIZE);
355 } else if (wrapped && addr >= start) {
356 return (abi_ulong)-1;
357 }
358 }
359 }
360
361 /* NOTE: all the constants are the HOST ones */
362 abi_long target_mmap(abi_ulong start, abi_ulong len, int prot,
363 int flags, int fd, abi_ulong offset)
364 {
365 abi_ulong ret, end, real_start, real_end, retaddr, host_offset, host_len;
366
367 mmap_lock();
368 #ifdef DEBUG_MMAP
369 {
370 printf("mmap: start=0x" TARGET_ABI_FMT_lx
371 " len=0x" TARGET_ABI_FMT_lx " prot=%c%c%c flags=",
372 start, len,
373 prot & PROT_READ ? 'r' : '-',
374 prot & PROT_WRITE ? 'w' : '-',
375 prot & PROT_EXEC ? 'x' : '-');
376 if (flags & MAP_FIXED)
377 printf("MAP_FIXED ");
378 if (flags & MAP_ANONYMOUS)
379 printf("MAP_ANON ");
380 switch(flags & MAP_TYPE) {
381 case MAP_PRIVATE:
382 printf("MAP_PRIVATE ");
383 break;
384 case MAP_SHARED:
385 printf("MAP_SHARED ");
386 break;
387 default:
388 printf("[MAP_TYPE=0x%x] ", flags & MAP_TYPE);
389 break;
390 }
391 printf("fd=%d offset=" TARGET_ABI_FMT_lx "\n", fd, offset);
392 }
393 #endif
394
395 if (offset & ~TARGET_PAGE_MASK) {
396 errno = EINVAL;
397 goto fail;
398 }
399
400 len = TARGET_PAGE_ALIGN(len);
401 if (len == 0)
402 goto the_end;
403 real_start = start & qemu_host_page_mask;
404 host_offset = offset & qemu_host_page_mask;
405
406 /* If the user is asking for the kernel to find a location, do that
407 before we truncate the length for mapping files below. */
408 if (!(flags & MAP_FIXED)) {
409 host_len = len + offset - host_offset;
410 host_len = HOST_PAGE_ALIGN(host_len);
411 start = mmap_find_vma(real_start, host_len);
412 if (start == (abi_ulong)-1) {
413 errno = ENOMEM;
414 goto fail;
415 }
416 }
417
418 /* When mapping files into a memory area larger than the file, accesses
419 to pages beyond the file size will cause a SIGBUS.
420
421 For example, if mmaping a file of 100 bytes on a host with 4K pages
422 emulating a target with 8K pages, the target expects to be able to
423 access the first 8K. But the host will trap us on any access beyond
424 4K.
425
426 When emulating a target with a larger page-size than the hosts, we
427 may need to truncate file maps at EOF and add extra anonymous pages
428 up to the targets page boundary. */
429
430 if ((qemu_real_host_page_size < qemu_host_page_size) &&
431 !(flags & MAP_ANONYMOUS)) {
432 struct stat sb;
433
434 if (fstat (fd, &sb) == -1)
435 goto fail;
436
437 /* Are we trying to create a map beyond EOF?. */
438 if (offset + len > sb.st_size) {
439 /* If so, truncate the file map at eof aligned with
440 the hosts real pagesize. Additional anonymous maps
441 will be created beyond EOF. */
442 len = REAL_HOST_PAGE_ALIGN(sb.st_size - offset);
443 }
444 }
445
446 if (!(flags & MAP_FIXED)) {
447 unsigned long host_start;
448 void *p;
449
450 host_len = len + offset - host_offset;
451 host_len = HOST_PAGE_ALIGN(host_len);
452
453 /* Note: we prefer to control the mapping address. It is
454 especially important if qemu_host_page_size >
455 qemu_real_host_page_size */
456 p = mmap(g2h(start), host_len, prot,
457 flags | MAP_FIXED | MAP_ANONYMOUS, -1, 0);
458 if (p == MAP_FAILED)
459 goto fail;
460 /* update start so that it points to the file position at 'offset' */
461 host_start = (unsigned long)p;
462 if (!(flags & MAP_ANONYMOUS)) {
463 p = mmap(g2h(start), len, prot,
464 flags | MAP_FIXED, fd, host_offset);
465 if (p == MAP_FAILED) {
466 munmap(g2h(start), host_len);
467 goto fail;
468 }
469 host_start += offset - host_offset;
470 }
471 start = h2g(host_start);
472 } else {
473 if (start & ~TARGET_PAGE_MASK) {
474 errno = EINVAL;
475 goto fail;
476 }
477 end = start + len;
478 real_end = HOST_PAGE_ALIGN(end);
479
480 /*
481 * Test if requested memory area fits target address space
482 * It can fail only on 64-bit host with 32-bit target.
483 * On any other target/host host mmap() handles this error correctly.
484 */
485 if (!guest_range_valid(start, len)) {
486 errno = ENOMEM;
487 goto fail;
488 }
489
490 /* worst case: we cannot map the file because the offset is not
491 aligned, so we read it */
492 if (!(flags & MAP_ANONYMOUS) &&
493 (offset & ~qemu_host_page_mask) != (start & ~qemu_host_page_mask)) {
494 /* msync() won't work here, so we return an error if write is
495 possible while it is a shared mapping */
496 if ((flags & MAP_TYPE) == MAP_SHARED &&
497 (prot & PROT_WRITE)) {
498 errno = EINVAL;
499 goto fail;
500 }
501 retaddr = target_mmap(start, len, prot | PROT_WRITE,
502 MAP_FIXED | MAP_PRIVATE | MAP_ANONYMOUS,
503 -1, 0);
504 if (retaddr == -1)
505 goto fail;
506 if (pread(fd, g2h(start), len, offset) == -1)
507 goto fail;
508 if (!(prot & PROT_WRITE)) {
509 ret = target_mprotect(start, len, prot);
510 assert(ret == 0);
511 }
512 goto the_end;
513 }
514
515 /* handle the start of the mapping */
516 if (start > real_start) {
517 if (real_end == real_start + qemu_host_page_size) {
518 /* one single host page */
519 ret = mmap_frag(real_start, start, end,
520 prot, flags, fd, offset);
521 if (ret == -1)
522 goto fail;
523 goto the_end1;
524 }
525 ret = mmap_frag(real_start, start, real_start + qemu_host_page_size,
526 prot, flags, fd, offset);
527 if (ret == -1)
528 goto fail;
529 real_start += qemu_host_page_size;
530 }
531 /* handle the end of the mapping */
532 if (end < real_end) {
533 ret = mmap_frag(real_end - qemu_host_page_size,
534 real_end - qemu_host_page_size, end,
535 prot, flags, fd,
536 offset + real_end - qemu_host_page_size - start);
537 if (ret == -1)
538 goto fail;
539 real_end -= qemu_host_page_size;
540 }
541
542 /* map the middle (easier) */
543 if (real_start < real_end) {
544 void *p;
545 unsigned long offset1;
546 if (flags & MAP_ANONYMOUS)
547 offset1 = 0;
548 else
549 offset1 = offset + real_start - start;
550 p = mmap(g2h(real_start), real_end - real_start,
551 prot, flags, fd, offset1);
552 if (p == MAP_FAILED)
553 goto fail;
554 }
555 }
556 the_end1:
557 page_set_flags(start, start + len, prot | PAGE_VALID);
558 the_end:
559 #ifdef DEBUG_MMAP
560 printf("ret=0x" TARGET_ABI_FMT_lx "\n", start);
561 page_dump(stdout);
562 printf("\n");
563 #endif
564 tb_invalidate_phys_range(start, start + len);
565 mmap_unlock();
566 return start;
567 fail:
568 mmap_unlock();
569 return -1;
570 }
571
572 static void mmap_reserve(abi_ulong start, abi_ulong size)
573 {
574 abi_ulong real_start;
575 abi_ulong real_end;
576 abi_ulong addr;
577 abi_ulong end;
578 int prot;
579
580 real_start = start & qemu_host_page_mask;
581 real_end = HOST_PAGE_ALIGN(start + size);
582 end = start + size;
583 if (start > real_start) {
584 /* handle host page containing start */
585 prot = 0;
586 for (addr = real_start; addr < start; addr += TARGET_PAGE_SIZE) {
587 prot |= page_get_flags(addr);
588 }
589 if (real_end == real_start + qemu_host_page_size) {
590 for (addr = end; addr < real_end; addr += TARGET_PAGE_SIZE) {
591 prot |= page_get_flags(addr);
592 }
593 end = real_end;
594 }
595 if (prot != 0)
596 real_start += qemu_host_page_size;
597 }
598 if (end < real_end) {
599 prot = 0;
600 for (addr = end; addr < real_end; addr += TARGET_PAGE_SIZE) {
601 prot |= page_get_flags(addr);
602 }
603 if (prot != 0)
604 real_end -= qemu_host_page_size;
605 }
606 if (real_start != real_end) {
607 mmap(g2h(real_start), real_end - real_start, PROT_NONE,
608 MAP_FIXED | MAP_ANONYMOUS | MAP_PRIVATE | MAP_NORESERVE,
609 -1, 0);
610 }
611 }
612
613 int target_munmap(abi_ulong start, abi_ulong len)
614 {
615 abi_ulong end, real_start, real_end, addr;
616 int prot, ret;
617
618 #ifdef DEBUG_MMAP
619 printf("munmap: start=0x" TARGET_ABI_FMT_lx " len=0x"
620 TARGET_ABI_FMT_lx "\n",
621 start, len);
622 #endif
623 if (start & ~TARGET_PAGE_MASK)
624 return -EINVAL;
625 len = TARGET_PAGE_ALIGN(len);
626 if (len == 0 || !guest_range_valid(start, len)) {
627 return -EINVAL;
628 }
629
630 mmap_lock();
631 end = start + len;
632 real_start = start & qemu_host_page_mask;
633 real_end = HOST_PAGE_ALIGN(end);
634
635 if (start > real_start) {
636 /* handle host page containing start */
637 prot = 0;
638 for(addr = real_start; addr < start; addr += TARGET_PAGE_SIZE) {
639 prot |= page_get_flags(addr);
640 }
641 if (real_end == real_start + qemu_host_page_size) {
642 for(addr = end; addr < real_end; addr += TARGET_PAGE_SIZE) {
643 prot |= page_get_flags(addr);
644 }
645 end = real_end;
646 }
647 if (prot != 0)
648 real_start += qemu_host_page_size;
649 }
650 if (end < real_end) {
651 prot = 0;
652 for(addr = end; addr < real_end; addr += TARGET_PAGE_SIZE) {
653 prot |= page_get_flags(addr);
654 }
655 if (prot != 0)
656 real_end -= qemu_host_page_size;
657 }
658
659 ret = 0;
660 /* unmap what we can */
661 if (real_start < real_end) {
662 if (reserved_va) {
663 mmap_reserve(real_start, real_end - real_start);
664 } else {
665 ret = munmap(g2h(real_start), real_end - real_start);
666 }
667 }
668
669 if (ret == 0) {
670 page_set_flags(start, start + len, 0);
671 tb_invalidate_phys_range(start, start + len);
672 }
673 mmap_unlock();
674 return ret;
675 }
676
677 abi_long target_mremap(abi_ulong old_addr, abi_ulong old_size,
678 abi_ulong new_size, unsigned long flags,
679 abi_ulong new_addr)
680 {
681 int prot;
682 void *host_addr;
683
684 if (!guest_range_valid(old_addr, old_size) ||
685 ((flags & MREMAP_FIXED) &&
686 !guest_range_valid(new_addr, new_size))) {
687 errno = ENOMEM;
688 return -1;
689 }
690
691 mmap_lock();
692
693 if (flags & MREMAP_FIXED) {
694 host_addr = mremap(g2h(old_addr), old_size, new_size,
695 flags, g2h(new_addr));
696
697 if (reserved_va && host_addr != MAP_FAILED) {
698 /* If new and old addresses overlap then the above mremap will
699 already have failed with EINVAL. */
700 mmap_reserve(old_addr, old_size);
701 }
702 } else if (flags & MREMAP_MAYMOVE) {
703 abi_ulong mmap_start;
704
705 mmap_start = mmap_find_vma(0, new_size);
706
707 if (mmap_start == -1) {
708 errno = ENOMEM;
709 host_addr = MAP_FAILED;
710 } else {
711 host_addr = mremap(g2h(old_addr), old_size, new_size,
712 flags | MREMAP_FIXED, g2h(mmap_start));
713 if (reserved_va) {
714 mmap_reserve(old_addr, old_size);
715 }
716 }
717 } else {
718 int prot = 0;
719 if (reserved_va && old_size < new_size) {
720 abi_ulong addr;
721 for (addr = old_addr + old_size;
722 addr < old_addr + new_size;
723 addr++) {
724 prot |= page_get_flags(addr);
725 }
726 }
727 if (prot == 0) {
728 host_addr = mremap(g2h(old_addr), old_size, new_size, flags);
729 if (host_addr != MAP_FAILED && reserved_va && old_size > new_size) {
730 mmap_reserve(old_addr + old_size, new_size - old_size);
731 }
732 } else {
733 errno = ENOMEM;
734 host_addr = MAP_FAILED;
735 }
736 /* Check if address fits target address space */
737 if ((unsigned long)host_addr + new_size > (abi_ulong)-1) {
738 /* Revert mremap() changes */
739 host_addr = mremap(g2h(old_addr), new_size, old_size, flags);
740 errno = ENOMEM;
741 host_addr = MAP_FAILED;
742 }
743 }
744
745 if (host_addr == MAP_FAILED) {
746 new_addr = -1;
747 } else {
748 new_addr = h2g(host_addr);
749 prot = page_get_flags(old_addr);
750 page_set_flags(old_addr, old_addr + old_size, 0);
751 page_set_flags(new_addr, new_addr + new_size, prot | PAGE_VALID);
752 }
753 tb_invalidate_phys_range(new_addr, new_addr + new_size);
754 mmap_unlock();
755 return new_addr;
756 }
757
758 int target_msync(abi_ulong start, abi_ulong len, int flags)
759 {
760 abi_ulong end;
761
762 if (start & ~TARGET_PAGE_MASK)
763 return -EINVAL;
764 len = TARGET_PAGE_ALIGN(len);
765 end = start + len;
766 if (end < start)
767 return -EINVAL;
768 if (end == start)
769 return 0;
770
771 start &= qemu_host_page_mask;
772 return msync(g2h(start), end - start, flags);
773 }