xref: /openbmc/qemu/linux-user/mmap.c (revision ab1b2ba9)
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 #include "trace.h"
21 #include "exec/log.h"
22 #include "qemu.h"
23 #include "user-internals.h"
24 #include "user-mmap.h"
25 #include "target_mman.h"
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 /*
66  * Validate target prot bitmask.
67  * Return the prot bitmask for the host in *HOST_PROT.
68  * Return 0 if the target prot bitmask is invalid, otherwise
69  * the internal qemu page_flags (which will include PAGE_VALID).
70  */
71 static int validate_prot_to_pageflags(int *host_prot, int prot)
72 {
73     int valid = PROT_READ | PROT_WRITE | PROT_EXEC | TARGET_PROT_SEM;
74     int page_flags = (prot & PAGE_BITS) | PAGE_VALID;
75 
76     /*
77      * For the host, we need not pass anything except read/write/exec.
78      * While PROT_SEM is allowed by all hosts, it is also ignored, so
79      * don't bother transforming guest bit to host bit.  Any other
80      * target-specific prot bits will not be understood by the host
81      * and will need to be encoded into page_flags for qemu emulation.
82      *
83      * Pages that are executable by the guest will never be executed
84      * by the host, but the host will need to be able to read them.
85      */
86     *host_prot = (prot & (PROT_READ | PROT_WRITE))
87                | (prot & PROT_EXEC ? PROT_READ : 0);
88 
89 #ifdef TARGET_AARCH64
90     {
91         ARMCPU *cpu = ARM_CPU(thread_cpu);
92 
93         /*
94          * The PROT_BTI bit is only accepted if the cpu supports the feature.
95          * Since this is the unusual case, don't bother checking unless
96          * the bit has been requested.  If set and valid, record the bit
97          * within QEMU's page_flags.
98          */
99         if ((prot & TARGET_PROT_BTI) && cpu_isar_feature(aa64_bti, cpu)) {
100             valid |= TARGET_PROT_BTI;
101             page_flags |= PAGE_BTI;
102         }
103         /* Similarly for the PROT_MTE bit. */
104         if ((prot & TARGET_PROT_MTE) && cpu_isar_feature(aa64_mte, cpu)) {
105             valid |= TARGET_PROT_MTE;
106             page_flags |= PAGE_MTE;
107         }
108     }
109 #elif defined(TARGET_HPPA)
110     valid |= PROT_GROWSDOWN | PROT_GROWSUP;
111 #endif
112 
113     return prot & ~valid ? 0 : page_flags;
114 }
115 
116 /* NOTE: all the constants are the HOST ones, but addresses are target. */
117 int target_mprotect(abi_ulong start, abi_ulong len, int target_prot)
118 {
119     abi_ulong end, host_start, host_end, addr;
120     int prot1, ret, page_flags, host_prot;
121 
122     trace_target_mprotect(start, len, target_prot);
123 
124     if ((start & ~TARGET_PAGE_MASK) != 0) {
125         return -TARGET_EINVAL;
126     }
127     page_flags = validate_prot_to_pageflags(&host_prot, target_prot);
128     if (!page_flags) {
129         return -TARGET_EINVAL;
130     }
131     len = TARGET_PAGE_ALIGN(len);
132     end = start + len;
133     if (!guest_range_valid_untagged(start, len)) {
134         return -TARGET_ENOMEM;
135     }
136     if (len == 0) {
137         return 0;
138     }
139 
140     mmap_lock();
141     host_start = start & qemu_host_page_mask;
142     host_end = HOST_PAGE_ALIGN(end);
143     if (start > host_start) {
144         /* handle host page containing start */
145         prot1 = host_prot;
146         for (addr = host_start; addr < start; addr += TARGET_PAGE_SIZE) {
147             prot1 |= page_get_flags(addr);
148         }
149         if (host_end == host_start + qemu_host_page_size) {
150             for (addr = end; addr < host_end; addr += TARGET_PAGE_SIZE) {
151                 prot1 |= page_get_flags(addr);
152             }
153             end = host_end;
154         }
155         ret = mprotect(g2h_untagged(host_start), qemu_host_page_size,
156                        prot1 & PAGE_BITS);
157         if (ret != 0) {
158             goto error;
159         }
160         host_start += qemu_host_page_size;
161     }
162     if (end < host_end) {
163         prot1 = host_prot;
164         for (addr = end; addr < host_end; addr += TARGET_PAGE_SIZE) {
165             prot1 |= page_get_flags(addr);
166         }
167         ret = mprotect(g2h_untagged(host_end - qemu_host_page_size),
168                        qemu_host_page_size, prot1 & PAGE_BITS);
169         if (ret != 0) {
170             goto error;
171         }
172         host_end -= qemu_host_page_size;
173     }
174 
175     /* handle the pages in the middle */
176     if (host_start < host_end) {
177         ret = mprotect(g2h_untagged(host_start),
178                        host_end - host_start, host_prot);
179         if (ret != 0) {
180             goto error;
181         }
182     }
183 
184     page_set_flags(start, start + len, page_flags);
185     ret = 0;
186 
187 error:
188     mmap_unlock();
189     return ret;
190 }
191 
192 /* map an incomplete host page */
193 static int mmap_frag(abi_ulong real_start,
194                      abi_ulong start, abi_ulong end,
195                      int prot, int flags, int fd, abi_ulong offset)
196 {
197     abi_ulong real_end, addr;
198     void *host_start;
199     int prot1, prot_new;
200 
201     real_end = real_start + qemu_host_page_size;
202     host_start = g2h_untagged(real_start);
203 
204     /* get the protection of the target pages outside the mapping */
205     prot1 = 0;
206     for(addr = real_start; addr < real_end; addr++) {
207         if (addr < start || addr >= end)
208             prot1 |= page_get_flags(addr);
209     }
210 
211     if (prot1 == 0) {
212         /* no page was there, so we allocate one */
213         void *p = mmap(host_start, qemu_host_page_size, prot,
214                        flags | MAP_ANONYMOUS, -1, 0);
215         if (p == MAP_FAILED)
216             return -1;
217         prot1 = prot;
218     }
219     prot1 &= PAGE_BITS;
220 
221     prot_new = prot | prot1;
222     if (!(flags & MAP_ANONYMOUS)) {
223         /* msync() won't work here, so we return an error if write is
224            possible while it is a shared mapping */
225         if ((flags & MAP_TYPE) == MAP_SHARED &&
226             (prot & PROT_WRITE))
227             return -1;
228 
229         /* adjust protection to be able to read */
230         if (!(prot1 & PROT_WRITE))
231             mprotect(host_start, qemu_host_page_size, prot1 | PROT_WRITE);
232 
233         /* read the corresponding file data */
234         if (pread(fd, g2h_untagged(start), end - start, offset) == -1)
235             return -1;
236 
237         /* put final protection */
238         if (prot_new != (prot1 | PROT_WRITE))
239             mprotect(host_start, qemu_host_page_size, prot_new);
240     } else {
241         if (prot_new != prot1) {
242             mprotect(host_start, qemu_host_page_size, prot_new);
243         }
244         if (prot_new & PROT_WRITE) {
245             memset(g2h_untagged(start), 0, end - start);
246         }
247     }
248     return 0;
249 }
250 
251 #if HOST_LONG_BITS == 64 && TARGET_ABI_BITS == 64
252 #ifdef TARGET_AARCH64
253 # define TASK_UNMAPPED_BASE  0x5500000000
254 #else
255 # define TASK_UNMAPPED_BASE  (1ul << 38)
256 #endif
257 #else
258 #ifdef TARGET_HPPA
259 # define TASK_UNMAPPED_BASE  0xfa000000
260 #else
261 # define TASK_UNMAPPED_BASE  0x40000000
262 #endif
263 #endif
264 abi_ulong mmap_next_start = TASK_UNMAPPED_BASE;
265 
266 unsigned long last_brk;
267 
268 /* Subroutine of mmap_find_vma, used when we have pre-allocated a chunk
269    of guest address space.  */
270 static abi_ulong mmap_find_vma_reserved(abi_ulong start, abi_ulong size,
271                                         abi_ulong align)
272 {
273     abi_ulong addr, end_addr, incr = qemu_host_page_size;
274     int prot;
275     bool looped = false;
276 
277     if (size > reserved_va) {
278         return (abi_ulong)-1;
279     }
280 
281     /* Note that start and size have already been aligned by mmap_find_vma. */
282 
283     end_addr = start + size;
284     if (start > reserved_va - size) {
285         /* Start at the top of the address space.  */
286         end_addr = ((reserved_va - size) & -align) + size;
287         looped = true;
288     }
289 
290     /* Search downward from END_ADDR, checking to see if a page is in use.  */
291     addr = end_addr;
292     while (1) {
293         addr -= incr;
294         if (addr > end_addr) {
295             if (looped) {
296                 /* Failure.  The entire address space has been searched.  */
297                 return (abi_ulong)-1;
298             }
299             /* Re-start at the top of the address space.  */
300             addr = end_addr = ((reserved_va - size) & -align) + size;
301             looped = true;
302         } else {
303             prot = page_get_flags(addr);
304             if (prot) {
305                 /* Page in use.  Restart below this page.  */
306                 addr = end_addr = ((addr - size) & -align) + size;
307             } else if (addr && addr + size == end_addr) {
308                 /* Success!  All pages between ADDR and END_ADDR are free.  */
309                 if (start == mmap_next_start) {
310                     mmap_next_start = addr;
311                 }
312                 return addr;
313             }
314         }
315     }
316 }
317 
318 /*
319  * Find and reserve a free memory area of size 'size'. The search
320  * starts at 'start'.
321  * It must be called with mmap_lock() held.
322  * Return -1 if error.
323  */
324 abi_ulong mmap_find_vma(abi_ulong start, abi_ulong size, abi_ulong align)
325 {
326     void *ptr, *prev;
327     abi_ulong addr;
328     int wrapped, repeat;
329 
330     align = MAX(align, qemu_host_page_size);
331 
332     /* If 'start' == 0, then a default start address is used. */
333     if (start == 0) {
334         start = mmap_next_start;
335     } else {
336         start &= qemu_host_page_mask;
337     }
338     start = ROUND_UP(start, align);
339 
340     size = HOST_PAGE_ALIGN(size);
341 
342     if (reserved_va) {
343         return mmap_find_vma_reserved(start, size, align);
344     }
345 
346     addr = start;
347     wrapped = repeat = 0;
348     prev = 0;
349 
350     for (;; prev = ptr) {
351         /*
352          * Reserve needed memory area to avoid a race.
353          * It should be discarded using:
354          *  - mmap() with MAP_FIXED flag
355          *  - mremap() with MREMAP_FIXED flag
356          *  - shmat() with SHM_REMAP flag
357          */
358         ptr = mmap(g2h_untagged(addr), size, PROT_NONE,
359                    MAP_ANONYMOUS|MAP_PRIVATE|MAP_NORESERVE, -1, 0);
360 
361         /* ENOMEM, if host address space has no memory */
362         if (ptr == MAP_FAILED) {
363             return (abi_ulong)-1;
364         }
365 
366         /* Count the number of sequential returns of the same address.
367            This is used to modify the search algorithm below.  */
368         repeat = (ptr == prev ? repeat + 1 : 0);
369 
370         if (h2g_valid(ptr + size - 1)) {
371             addr = h2g(ptr);
372 
373             if ((addr & (align - 1)) == 0) {
374                 /* Success.  */
375                 if (start == mmap_next_start && addr >= TASK_UNMAPPED_BASE) {
376                     mmap_next_start = addr + size;
377                 }
378                 return addr;
379             }
380 
381             /* The address is not properly aligned for the target.  */
382             switch (repeat) {
383             case 0:
384                 /* Assume the result that the kernel gave us is the
385                    first with enough free space, so start again at the
386                    next higher target page.  */
387                 addr = ROUND_UP(addr, align);
388                 break;
389             case 1:
390                 /* Sometimes the kernel decides to perform the allocation
391                    at the top end of memory instead.  */
392                 addr &= -align;
393                 break;
394             case 2:
395                 /* Start over at low memory.  */
396                 addr = 0;
397                 break;
398             default:
399                 /* Fail.  This unaligned block must the last.  */
400                 addr = -1;
401                 break;
402             }
403         } else {
404             /* Since the result the kernel gave didn't fit, start
405                again at low memory.  If any repetition, fail.  */
406             addr = (repeat ? -1 : 0);
407         }
408 
409         /* Unmap and try again.  */
410         munmap(ptr, size);
411 
412         /* ENOMEM if we checked the whole of the target address space.  */
413         if (addr == (abi_ulong)-1) {
414             return (abi_ulong)-1;
415         } else if (addr == 0) {
416             if (wrapped) {
417                 return (abi_ulong)-1;
418             }
419             wrapped = 1;
420             /* Don't actually use 0 when wrapping, instead indicate
421                that we'd truly like an allocation in low memory.  */
422             addr = (mmap_min_addr > TARGET_PAGE_SIZE
423                      ? TARGET_PAGE_ALIGN(mmap_min_addr)
424                      : TARGET_PAGE_SIZE);
425         } else if (wrapped && addr >= start) {
426             return (abi_ulong)-1;
427         }
428     }
429 }
430 
431 /* NOTE: all the constants are the HOST ones */
432 abi_long target_mmap(abi_ulong start, abi_ulong len, int target_prot,
433                      int flags, int fd, abi_ulong offset)
434 {
435     abi_ulong ret, end, real_start, real_end, retaddr, host_offset, host_len,
436               passthrough_start = -1, passthrough_end = -1;
437     int page_flags, host_prot;
438 
439     mmap_lock();
440     trace_target_mmap(start, len, target_prot, flags, fd, offset);
441 
442     if (!len) {
443         errno = EINVAL;
444         goto fail;
445     }
446 
447     page_flags = validate_prot_to_pageflags(&host_prot, target_prot);
448     if (!page_flags) {
449         errno = EINVAL;
450         goto fail;
451     }
452 
453     /* Also check for overflows... */
454     len = TARGET_PAGE_ALIGN(len);
455     if (!len) {
456         errno = ENOMEM;
457         goto fail;
458     }
459 
460     if (offset & ~TARGET_PAGE_MASK) {
461         errno = EINVAL;
462         goto fail;
463     }
464 
465     /*
466      * If we're mapping shared memory, ensure we generate code for parallel
467      * execution and flush old translations.  This will work up to the level
468      * supported by the host -- anything that requires EXCP_ATOMIC will not
469      * be atomic with respect to an external process.
470      */
471     if (flags & MAP_SHARED) {
472         CPUState *cpu = thread_cpu;
473         if (!(cpu->tcg_cflags & CF_PARALLEL)) {
474             cpu->tcg_cflags |= CF_PARALLEL;
475             tb_flush(cpu);
476         }
477     }
478 
479     real_start = start & qemu_host_page_mask;
480     host_offset = offset & qemu_host_page_mask;
481 
482     /* If the user is asking for the kernel to find a location, do that
483        before we truncate the length for mapping files below.  */
484     if (!(flags & MAP_FIXED)) {
485         host_len = len + offset - host_offset;
486         host_len = HOST_PAGE_ALIGN(host_len);
487         start = mmap_find_vma(real_start, host_len, TARGET_PAGE_SIZE);
488         if (start == (abi_ulong)-1) {
489             errno = ENOMEM;
490             goto fail;
491         }
492     }
493 
494     /* When mapping files into a memory area larger than the file, accesses
495        to pages beyond the file size will cause a SIGBUS.
496 
497        For example, if mmaping a file of 100 bytes on a host with 4K pages
498        emulating a target with 8K pages, the target expects to be able to
499        access the first 8K. But the host will trap us on any access beyond
500        4K.
501 
502        When emulating a target with a larger page-size than the hosts, we
503        may need to truncate file maps at EOF and add extra anonymous pages
504        up to the targets page boundary.  */
505 
506     if ((qemu_real_host_page_size() < qemu_host_page_size) &&
507         !(flags & MAP_ANONYMOUS)) {
508         struct stat sb;
509 
510        if (fstat (fd, &sb) == -1)
511            goto fail;
512 
513        /* Are we trying to create a map beyond EOF?.  */
514        if (offset + len > sb.st_size) {
515            /* If so, truncate the file map at eof aligned with
516               the hosts real pagesize. Additional anonymous maps
517               will be created beyond EOF.  */
518            len = REAL_HOST_PAGE_ALIGN(sb.st_size - offset);
519        }
520     }
521 
522     if (!(flags & MAP_FIXED)) {
523         unsigned long host_start;
524         void *p;
525 
526         host_len = len + offset - host_offset;
527         host_len = HOST_PAGE_ALIGN(host_len);
528 
529         /* Note: we prefer to control the mapping address. It is
530            especially important if qemu_host_page_size >
531            qemu_real_host_page_size */
532         p = mmap(g2h_untagged(start), host_len, host_prot,
533                  flags | MAP_FIXED | MAP_ANONYMOUS, -1, 0);
534         if (p == MAP_FAILED) {
535             goto fail;
536         }
537         /* update start so that it points to the file position at 'offset' */
538         host_start = (unsigned long)p;
539         if (!(flags & MAP_ANONYMOUS)) {
540             p = mmap(g2h_untagged(start), len, host_prot,
541                      flags | MAP_FIXED, fd, host_offset);
542             if (p == MAP_FAILED) {
543                 munmap(g2h_untagged(start), host_len);
544                 goto fail;
545             }
546             host_start += offset - host_offset;
547         }
548         start = h2g(host_start);
549         passthrough_start = start;
550         passthrough_end = start + len;
551     } else {
552         if (start & ~TARGET_PAGE_MASK) {
553             errno = EINVAL;
554             goto fail;
555         }
556         end = start + len;
557         real_end = HOST_PAGE_ALIGN(end);
558 
559         /*
560          * Test if requested memory area fits target address space
561          * It can fail only on 64-bit host with 32-bit target.
562          * On any other target/host host mmap() handles this error correctly.
563          */
564         if (end < start || !guest_range_valid_untagged(start, len)) {
565             errno = ENOMEM;
566             goto fail;
567         }
568 
569         /* worst case: we cannot map the file because the offset is not
570            aligned, so we read it */
571         if (!(flags & MAP_ANONYMOUS) &&
572             (offset & ~qemu_host_page_mask) != (start & ~qemu_host_page_mask)) {
573             /* msync() won't work here, so we return an error if write is
574                possible while it is a shared mapping */
575             if ((flags & MAP_TYPE) == MAP_SHARED &&
576                 (host_prot & PROT_WRITE)) {
577                 errno = EINVAL;
578                 goto fail;
579             }
580             retaddr = target_mmap(start, len, target_prot | PROT_WRITE,
581                                   MAP_FIXED | MAP_PRIVATE | MAP_ANONYMOUS,
582                                   -1, 0);
583             if (retaddr == -1)
584                 goto fail;
585             if (pread(fd, g2h_untagged(start), len, offset) == -1)
586                 goto fail;
587             if (!(host_prot & PROT_WRITE)) {
588                 ret = target_mprotect(start, len, target_prot);
589                 assert(ret == 0);
590             }
591             goto the_end;
592         }
593 
594         /* handle the start of the mapping */
595         if (start > real_start) {
596             if (real_end == real_start + qemu_host_page_size) {
597                 /* one single host page */
598                 ret = mmap_frag(real_start, start, end,
599                                 host_prot, flags, fd, offset);
600                 if (ret == -1)
601                     goto fail;
602                 goto the_end1;
603             }
604             ret = mmap_frag(real_start, start, real_start + qemu_host_page_size,
605                             host_prot, flags, fd, offset);
606             if (ret == -1)
607                 goto fail;
608             real_start += qemu_host_page_size;
609         }
610         /* handle the end of the mapping */
611         if (end < real_end) {
612             ret = mmap_frag(real_end - qemu_host_page_size,
613                             real_end - qemu_host_page_size, end,
614                             host_prot, flags, fd,
615                             offset + real_end - qemu_host_page_size - start);
616             if (ret == -1)
617                 goto fail;
618             real_end -= qemu_host_page_size;
619         }
620 
621         /* map the middle (easier) */
622         if (real_start < real_end) {
623             void *p;
624             unsigned long offset1;
625             if (flags & MAP_ANONYMOUS)
626                 offset1 = 0;
627             else
628                 offset1 = offset + real_start - start;
629             p = mmap(g2h_untagged(real_start), real_end - real_start,
630                      host_prot, flags, fd, offset1);
631             if (p == MAP_FAILED)
632                 goto fail;
633             passthrough_start = real_start;
634             passthrough_end = real_end;
635         }
636     }
637  the_end1:
638     if (flags & MAP_ANONYMOUS) {
639         page_flags |= PAGE_ANON;
640     }
641     page_flags |= PAGE_RESET;
642     if (passthrough_start == passthrough_end) {
643         page_set_flags(start, start + len, page_flags);
644     } else {
645         if (start < passthrough_start) {
646             page_set_flags(start, passthrough_start, page_flags);
647         }
648         page_set_flags(passthrough_start, passthrough_end,
649                        page_flags | PAGE_PASSTHROUGH);
650         if (passthrough_end < start + len) {
651             page_set_flags(passthrough_end, start + len, page_flags);
652         }
653     }
654  the_end:
655     trace_target_mmap_complete(start);
656     if (qemu_loglevel_mask(CPU_LOG_PAGE)) {
657         FILE *f = qemu_log_trylock();
658         if (f) {
659             fprintf(f, "page layout changed following mmap\n");
660             page_dump(f);
661             qemu_log_unlock(f);
662         }
663     }
664     mmap_unlock();
665     return start;
666 fail:
667     mmap_unlock();
668     return -1;
669 }
670 
671 static void mmap_reserve(abi_ulong start, abi_ulong size)
672 {
673     abi_ulong real_start;
674     abi_ulong real_end;
675     abi_ulong addr;
676     abi_ulong end;
677     int prot;
678 
679     real_start = start & qemu_host_page_mask;
680     real_end = HOST_PAGE_ALIGN(start + size);
681     end = start + size;
682     if (start > real_start) {
683         /* handle host page containing start */
684         prot = 0;
685         for (addr = real_start; addr < start; addr += TARGET_PAGE_SIZE) {
686             prot |= page_get_flags(addr);
687         }
688         if (real_end == real_start + qemu_host_page_size) {
689             for (addr = end; addr < real_end; addr += TARGET_PAGE_SIZE) {
690                 prot |= page_get_flags(addr);
691             }
692             end = real_end;
693         }
694         if (prot != 0)
695             real_start += qemu_host_page_size;
696     }
697     if (end < real_end) {
698         prot = 0;
699         for (addr = end; addr < real_end; addr += TARGET_PAGE_SIZE) {
700             prot |= page_get_flags(addr);
701         }
702         if (prot != 0)
703             real_end -= qemu_host_page_size;
704     }
705     if (real_start != real_end) {
706         mmap(g2h_untagged(real_start), real_end - real_start, PROT_NONE,
707                  MAP_FIXED | MAP_ANONYMOUS | MAP_PRIVATE | MAP_NORESERVE,
708                  -1, 0);
709     }
710 }
711 
712 int target_munmap(abi_ulong start, abi_ulong len)
713 {
714     abi_ulong end, real_start, real_end, addr;
715     int prot, ret;
716 
717     trace_target_munmap(start, len);
718 
719     if (start & ~TARGET_PAGE_MASK)
720         return -TARGET_EINVAL;
721     len = TARGET_PAGE_ALIGN(len);
722     if (len == 0 || !guest_range_valid_untagged(start, len)) {
723         return -TARGET_EINVAL;
724     }
725 
726     mmap_lock();
727     end = start + len;
728     real_start = start & qemu_host_page_mask;
729     real_end = HOST_PAGE_ALIGN(end);
730 
731     if (start > real_start) {
732         /* handle host page containing start */
733         prot = 0;
734         for(addr = real_start; addr < start; addr += TARGET_PAGE_SIZE) {
735             prot |= page_get_flags(addr);
736         }
737         if (real_end == real_start + qemu_host_page_size) {
738             for(addr = end; addr < real_end; addr += TARGET_PAGE_SIZE) {
739                 prot |= page_get_flags(addr);
740             }
741             end = real_end;
742         }
743         if (prot != 0)
744             real_start += qemu_host_page_size;
745     }
746     if (end < real_end) {
747         prot = 0;
748         for(addr = end; addr < real_end; addr += TARGET_PAGE_SIZE) {
749             prot |= page_get_flags(addr);
750         }
751         if (prot != 0)
752             real_end -= qemu_host_page_size;
753     }
754 
755     ret = 0;
756     /* unmap what we can */
757     if (real_start < real_end) {
758         if (reserved_va) {
759             mmap_reserve(real_start, real_end - real_start);
760         } else {
761             ret = munmap(g2h_untagged(real_start), real_end - real_start);
762         }
763     }
764 
765     if (ret == 0) {
766         page_set_flags(start, start + len, 0);
767     }
768     mmap_unlock();
769     return ret;
770 }
771 
772 abi_long target_mremap(abi_ulong old_addr, abi_ulong old_size,
773                        abi_ulong new_size, unsigned long flags,
774                        abi_ulong new_addr)
775 {
776     int prot;
777     void *host_addr;
778 
779     if (!guest_range_valid_untagged(old_addr, old_size) ||
780         ((flags & MREMAP_FIXED) &&
781          !guest_range_valid_untagged(new_addr, new_size)) ||
782         ((flags & MREMAP_MAYMOVE) == 0 &&
783          !guest_range_valid_untagged(old_addr, new_size))) {
784         errno = ENOMEM;
785         return -1;
786     }
787 
788     mmap_lock();
789 
790     if (flags & MREMAP_FIXED) {
791         host_addr = mremap(g2h_untagged(old_addr), old_size, new_size,
792                            flags, g2h_untagged(new_addr));
793 
794         if (reserved_va && host_addr != MAP_FAILED) {
795             /* If new and old addresses overlap then the above mremap will
796                already have failed with EINVAL.  */
797             mmap_reserve(old_addr, old_size);
798         }
799     } else if (flags & MREMAP_MAYMOVE) {
800         abi_ulong mmap_start;
801 
802         mmap_start = mmap_find_vma(0, new_size, TARGET_PAGE_SIZE);
803 
804         if (mmap_start == -1) {
805             errno = ENOMEM;
806             host_addr = MAP_FAILED;
807         } else {
808             host_addr = mremap(g2h_untagged(old_addr), old_size, new_size,
809                                flags | MREMAP_FIXED,
810                                g2h_untagged(mmap_start));
811             if (reserved_va) {
812                 mmap_reserve(old_addr, old_size);
813             }
814         }
815     } else {
816         int prot = 0;
817         if (reserved_va && old_size < new_size) {
818             abi_ulong addr;
819             for (addr = old_addr + old_size;
820                  addr < old_addr + new_size;
821                  addr++) {
822                 prot |= page_get_flags(addr);
823             }
824         }
825         if (prot == 0) {
826             host_addr = mremap(g2h_untagged(old_addr),
827                                old_size, new_size, flags);
828 
829             if (host_addr != MAP_FAILED) {
830                 /* Check if address fits target address space */
831                 if (!guest_range_valid_untagged(h2g(host_addr), new_size)) {
832                     /* Revert mremap() changes */
833                     host_addr = mremap(g2h_untagged(old_addr),
834                                        new_size, old_size, flags);
835                     errno = ENOMEM;
836                     host_addr = MAP_FAILED;
837                 } else if (reserved_va && old_size > new_size) {
838                     mmap_reserve(old_addr + old_size, old_size - new_size);
839                 }
840             }
841         } else {
842             errno = ENOMEM;
843             host_addr = MAP_FAILED;
844         }
845     }
846 
847     if (host_addr == MAP_FAILED) {
848         new_addr = -1;
849     } else {
850         new_addr = h2g(host_addr);
851         prot = page_get_flags(old_addr);
852         page_set_flags(old_addr, old_addr + old_size, 0);
853         page_set_flags(new_addr, new_addr + new_size,
854                        prot | PAGE_VALID | PAGE_RESET);
855     }
856     mmap_unlock();
857     return new_addr;
858 }
859 
860 static bool can_passthrough_madv_dontneed(abi_ulong start, abi_ulong end)
861 {
862     ulong addr;
863 
864     if ((start | end) & ~qemu_host_page_mask) {
865         return false;
866     }
867 
868     for (addr = start; addr < end; addr += TARGET_PAGE_SIZE) {
869         if (!(page_get_flags(addr) & PAGE_PASSTHROUGH)) {
870             return false;
871         }
872     }
873 
874     return true;
875 }
876 
877 abi_long target_madvise(abi_ulong start, abi_ulong len_in, int advice)
878 {
879     abi_ulong len, end;
880     int ret = 0;
881 
882     if (start & ~TARGET_PAGE_MASK) {
883         return -TARGET_EINVAL;
884     }
885     len = TARGET_PAGE_ALIGN(len_in);
886 
887     if (len_in && !len) {
888         return -TARGET_EINVAL;
889     }
890 
891     end = start + len;
892     if (end < start) {
893         return -TARGET_EINVAL;
894     }
895 
896     if (end == start) {
897         return 0;
898     }
899 
900     if (!guest_range_valid_untagged(start, len)) {
901         return -TARGET_EINVAL;
902     }
903 
904     /*
905      * A straight passthrough may not be safe because qemu sometimes turns
906      * private file-backed mappings into anonymous mappings.
907      *
908      * This is a hint, so ignoring and returning success is ok.
909      *
910      * This breaks MADV_DONTNEED, completely implementing which is quite
911      * complicated. However, there is one low-hanging fruit: mappings that are
912      * known to have the same semantics in the host and the guest. In this case
913      * passthrough is safe, so do it.
914      */
915     mmap_lock();
916     if (advice == TARGET_MADV_DONTNEED &&
917         can_passthrough_madv_dontneed(start, end)) {
918         ret = get_errno(madvise(g2h_untagged(start), len, MADV_DONTNEED));
919         if (ret == 0) {
920             page_reset_target_data(start, start + len);
921         }
922     }
923     mmap_unlock();
924 
925     return ret;
926 }
927