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