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