Merge remote-tracking branch 'remotes/weil/tags/pull-wxx-20150924' into staging
[qemu/ar7.git] / linux-user / mmap.c
blobb2126c76fab529bacd7f269159e1b7bbdc64e556
1 /*
2 * mmap support for qemu
4 * Copyright (c) 2003 Fabrice Bellard
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.
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.
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/>.
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>
31 #include "qemu.h"
32 #include "qemu-common.h"
33 #include "translate-all.h"
35 //#define DEBUG_MMAP
37 static pthread_mutex_t mmap_mutex = PTHREAD_MUTEX_INITIALIZER;
38 static __thread int mmap_lock_count;
40 void mmap_lock(void)
42 if (mmap_lock_count++ == 0) {
43 pthread_mutex_lock(&mmap_mutex);
47 void mmap_unlock(void)
49 if (--mmap_lock_count == 0) {
50 pthread_mutex_unlock(&mmap_mutex);
54 /* Grab lock to make sure things are in a consistent state after fork(). */
55 void mmap_fork_start(void)
57 if (mmap_lock_count)
58 abort();
59 pthread_mutex_lock(&mmap_mutex);
62 void mmap_fork_end(int child)
64 if (child)
65 pthread_mutex_init(&mmap_mutex, NULL);
66 else
67 pthread_mutex_unlock(&mmap_mutex);
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)
73 abi_ulong end, host_start, host_end, addr;
74 int prot1, ret;
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
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;
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);
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);
107 end = host_end;
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;
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);
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;
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;
132 page_set_flags(start, start + len, prot | PAGE_VALID);
133 mmap_unlock();
134 return 0;
135 error:
136 mmap_unlock();
137 return ret;
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)
145 abi_ulong real_end, addr;
146 void *host_start;
147 int prot1, prot_new;
149 real_end = real_start + qemu_host_page_size;
150 host_start = g2h(real_start);
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);
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;
167 prot1 &= PAGE_BITS;
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;
177 /* adjust protection to be able to read */
178 if (!(prot1 & PROT_WRITE))
179 mprotect(host_start, qemu_host_page_size, prot1 | PROT_WRITE);
181 /* read the corresponding file data */
182 if (pread(fd, g2h(start), end - start, offset) == -1)
183 return -1;
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);
194 return 0;
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;
207 unsigned long last_brk;
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)
213 abi_ulong addr;
214 abi_ulong end_addr;
215 int prot;
216 int looped = 0;
218 if (size > reserved_va) {
219 return (abi_ulong)-1;
222 size = HOST_PAGE_ALIGN(size);
223 end_addr = start + size;
224 if (end_addr > reserved_va) {
225 end_addr = reserved_va;
227 addr = end_addr - qemu_host_page_size;
229 while (1) {
230 if (addr > end_addr) {
231 if (looped) {
232 return (abi_ulong)-1;
234 end_addr = reserved_va;
235 addr = end_addr - qemu_host_page_size;
236 looped = 1;
237 continue;
239 prot = page_get_flags(addr);
240 if (prot) {
241 end_addr = addr;
243 if (addr + size == end_addr) {
244 break;
246 addr -= qemu_host_page_size;
249 if (start == mmap_next_start) {
250 mmap_next_start = addr;
253 return addr;
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.
262 abi_ulong mmap_find_vma(abi_ulong start, abi_ulong size)
264 void *ptr, *prev;
265 abi_ulong addr;
266 int wrapped, repeat;
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;
275 size = HOST_PAGE_ALIGN(size);
277 if (reserved_va) {
278 return mmap_find_vma_reserved(start, size);
281 addr = start;
282 wrapped = repeat = 0;
283 prev = 0;
285 for (;; prev = ptr) {
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
293 ptr = mmap(g2h(addr), size, PROT_NONE,
294 MAP_ANONYMOUS|MAP_PRIVATE|MAP_NORESERVE, -1, 0);
296 /* ENOMEM, if host address space has no memory */
297 if (ptr == MAP_FAILED) {
298 return (abi_ulong)-1;
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);
305 if (h2g_valid(ptr + size - 1)) {
306 addr = h2g(ptr);
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;
313 return addr;
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;
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);
344 /* Unmap and try again. */
345 munmap(ptr, size);
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;
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;
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)
370 abi_ulong ret, end, real_start, real_end, retaddr, host_offset, host_len;
372 mmap_lock();
373 #ifdef DEBUG_MMAP
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;
396 printf("fd=%d offset=" TARGET_ABI_FMT_lx "\n", fd, offset);
398 #endif
400 if (offset & ~TARGET_PAGE_MASK) {
401 errno = EINVAL;
402 goto fail;
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;
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;
423 /* When mapping files into a memory area larger than the file, accesses
424 to pages beyond the file size will cause a SIGBUS.
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.
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. */
435 if ((qemu_real_host_page_size < TARGET_PAGE_SIZE)
436 && !(flags & MAP_ANONYMOUS)) {
437 struct stat sb;
439 if (fstat (fd, &sb) == -1)
440 goto fail;
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);
453 if (!(flags & MAP_FIXED)) {
454 unsigned long host_start;
455 void *p;
457 host_len = len + offset - host_offset;
458 host_len = HOST_PAGE_ALIGN(host_len);
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;
476 host_start += offset - host_offset;
478 start = h2g(host_start);
479 } else {
480 if (start & ~TARGET_PAGE_MASK) {
481 errno = EINVAL;
482 goto fail;
484 end = start + len;
485 real_end = HOST_PAGE_ALIGN(end);
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.
492 if ((unsigned long)start + len - 1 > (abi_ulong) -1) {
493 errno = EINVAL;
494 goto fail;
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;
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;
522 goto the_end;
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;
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;
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;
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;
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;
582 static void mmap_reserve(abi_ulong start, abi_ulong size)
584 abi_ulong real_start;
585 abi_ulong real_end;
586 abi_ulong addr;
587 abi_ulong end;
588 int prot;
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);
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);
603 end = real_end;
605 if (prot != 0)
606 real_start += qemu_host_page_size;
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);
613 if (prot != 0)
614 real_end -= qemu_host_page_size;
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);
623 int target_munmap(abi_ulong start, abi_ulong len)
625 abi_ulong end, real_start, real_end, addr;
626 int prot, ret;
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);
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);
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);
653 end = real_end;
655 if (prot != 0)
656 real_start += qemu_host_page_size;
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);
663 if (prot != 0)
664 real_end -= qemu_host_page_size;
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);
677 if (ret == 0) {
678 page_set_flags(start, start + len, 0);
679 tb_invalidate_phys_range(start, start + len);
681 mmap_unlock();
682 return ret;
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)
689 int prot;
690 void *host_addr;
692 mmap_lock();
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));
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);
705 } else if (flags & MREMAP_MAYMOVE) {
706 abi_ulong mmap_start;
708 mmap_start = mmap_find_vma(0, new_size);
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);
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);
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);
737 } else {
738 errno = ENOMEM;
739 host_addr = MAP_FAILED;
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;
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);
758 tb_invalidate_phys_range(new_addr, new_addr + new_size);
759 mmap_unlock();
760 return new_addr;
763 int target_msync(abi_ulong start, abi_ulong len, int flags)
765 abi_ulong end;
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;
776 start &= qemu_host_page_mask;
777 return msync(g2h(start), end - start, flags);