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