]> git.proxmox.com Git - qemu.git/blame - linux-user/mmap.c
Check availavility of -fstack-protector-all
[qemu.git] / linux-user / mmap.c
CommitLineData
54936004
FB
1/*
2 * mmap support for qemu
5fafdf24 3 *
54936004
FB
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
8167ee88 17 * along with this program; if not, see <http://www.gnu.org/licenses/>.
54936004
FB
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>
54c5a2ae
EI
25#include <sys/types.h>
26#include <sys/stat.h>
54936004 27#include <sys/mman.h>
3af72a4d
BS
28#include <linux/mman.h>
29#include <linux/unistd.h>
54936004
FB
30
31#include "qemu.h"
78f5bf1e 32#include "qemu-common.h"
54936004
FB
33
34//#define DEBUG_MMAP
35
2f7bb878 36#if defined(CONFIG_USE_NPTL)
1e6eec8b 37static pthread_mutex_t mmap_mutex = PTHREAD_MUTEX_INITIALIZER;
dfd3f85c 38static __thread int mmap_lock_count;
c8a706fe
PB
39
40void mmap_lock(void)
41{
42 if (mmap_lock_count++ == 0) {
43 pthread_mutex_lock(&mmap_mutex);
44 }
45}
46
47void mmap_unlock(void)
48{
49 if (--mmap_lock_count == 0) {
50 pthread_mutex_unlock(&mmap_mutex);
51 }
52}
d5975363
PB
53
54/* Grab lock to make sure things are in a consistent state after fork(). */
55void mmap_fork_start(void)
56{
57 if (mmap_lock_count)
58 abort();
59 pthread_mutex_lock(&mmap_mutex);
60}
61
62void 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}
c8a706fe
PB
69#else
70/* We aren't threadsafe to start with, so no need to worry about locking. */
71void mmap_lock(void)
72{
73}
74
75void mmap_unlock(void)
76{
77}
78#endif
79
17e2377a
PB
80void *qemu_vmalloc(size_t size)
81{
82 void *p;
83 unsigned long addr;
84 mmap_lock();
85 /* Use map and mark the pages as used. */
86 p = mmap(NULL, size, PROT_READ | PROT_WRITE,
87 MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
88
89 addr = (unsigned long)p;
90 if (addr == (target_ulong) addr) {
91 /* Allocated region overlaps guest address space.
92 This may recurse. */
93 page_set_flags(addr & TARGET_PAGE_MASK, TARGET_PAGE_ALIGN(addr + size),
94 PAGE_RESERVED);
95 }
96
97 mmap_unlock();
98 return p;
99}
100
101void *qemu_malloc(size_t size)
102{
103 char * p;
104 size += 16;
105 p = qemu_vmalloc(size);
106 *(size_t *)p = size;
107 return p + 16;
108}
109
110/* We use map, which is always zero initialized. */
111void * qemu_mallocz(size_t size)
112{
113 return qemu_malloc(size);
114}
115
116void qemu_free(void *ptr)
117{
118 /* FIXME: We should unmark the reserved pages here. However this gets
119 complicated when one target page spans multiple host pages, so we
120 don't bother. */
121 size_t *p;
122 p = (size_t *)((char *)ptr - 16);
123 munmap(p, *p);
124}
125
1a6f0dbc
AL
126void *qemu_realloc(void *ptr, size_t size)
127{
128 size_t old_size, copy;
129 void *new_ptr;
130
baa8c602 131 if (!ptr)
132 return qemu_malloc(size);
1a6f0dbc
AL
133 old_size = *(size_t *)((char *)ptr - 16);
134 copy = old_size < size ? old_size : size;
135 new_ptr = qemu_malloc(size);
136 memcpy(new_ptr, ptr, copy);
137 qemu_free(ptr);
138 return new_ptr;
139}
140
53a5960a 141/* NOTE: all the constants are the HOST ones, but addresses are target. */
992f48a0 142int target_mprotect(abi_ulong start, abi_ulong len, int prot)
54936004 143{
992f48a0 144 abi_ulong end, host_start, host_end, addr;
54936004
FB
145 int prot1, ret;
146
147#ifdef DEBUG_MMAP
0bf9e31a
BS
148 printf("mprotect: start=0x" TARGET_ABI_FMT_lx
149 "len=0x" TARGET_ABI_FMT_lx " prot=%c%c%c\n", start, len,
54936004
FB
150 prot & PROT_READ ? 'r' : '-',
151 prot & PROT_WRITE ? 'w' : '-',
152 prot & PROT_EXEC ? 'x' : '-');
153#endif
154
155 if ((start & ~TARGET_PAGE_MASK) != 0)
156 return -EINVAL;
157 len = TARGET_PAGE_ALIGN(len);
158 end = start + len;
159 if (end < start)
160 return -EINVAL;
171cd1cd 161 prot &= PROT_READ | PROT_WRITE | PROT_EXEC;
54936004
FB
162 if (len == 0)
163 return 0;
3b46e624 164
c8a706fe 165 mmap_lock();
83fb7adf 166 host_start = start & qemu_host_page_mask;
54936004
FB
167 host_end = HOST_PAGE_ALIGN(end);
168 if (start > host_start) {
169 /* handle host page containing start */
170 prot1 = prot;
171 for(addr = host_start; addr < start; addr += TARGET_PAGE_SIZE) {
172 prot1 |= page_get_flags(addr);
173 }
83fb7adf 174 if (host_end == host_start + qemu_host_page_size) {
d418c81e
FB
175 for(addr = end; addr < host_end; addr += TARGET_PAGE_SIZE) {
176 prot1 |= page_get_flags(addr);
177 }
178 end = host_end;
179 }
53a5960a 180 ret = mprotect(g2h(host_start), qemu_host_page_size, prot1 & PAGE_BITS);
54936004 181 if (ret != 0)
c8a706fe 182 goto error;
83fb7adf 183 host_start += qemu_host_page_size;
54936004
FB
184 }
185 if (end < host_end) {
54936004
FB
186 prot1 = prot;
187 for(addr = end; addr < host_end; addr += TARGET_PAGE_SIZE) {
188 prot1 |= page_get_flags(addr);
189 }
5fafdf24 190 ret = mprotect(g2h(host_end - qemu_host_page_size), qemu_host_page_size,
54936004
FB
191 prot1 & PAGE_BITS);
192 if (ret != 0)
c8a706fe 193 goto error;
83fb7adf 194 host_end -= qemu_host_page_size;
54936004 195 }
3b46e624 196
54936004
FB
197 /* handle the pages in the middle */
198 if (host_start < host_end) {
53a5960a 199 ret = mprotect(g2h(host_start), host_end - host_start, prot);
54936004 200 if (ret != 0)
c8a706fe 201 goto error;
54936004 202 }
54936004 203 page_set_flags(start, start + len, prot | PAGE_VALID);
c8a706fe 204 mmap_unlock();
54936004 205 return 0;
c8a706fe
PB
206error:
207 mmap_unlock();
208 return ret;
54936004
FB
209}
210
211/* map an incomplete host page */
992f48a0
BS
212static int mmap_frag(abi_ulong real_start,
213 abi_ulong start, abi_ulong end,
214 int prot, int flags, int fd, abi_ulong offset)
54936004 215{
80210bcd 216 abi_ulong real_end, addr;
53a5960a 217 void *host_start;
54936004
FB
218 int prot1, prot_new;
219
53a5960a
PB
220 real_end = real_start + qemu_host_page_size;
221 host_start = g2h(real_start);
54936004
FB
222
223 /* get the protection of the target pages outside the mapping */
224 prot1 = 0;
53a5960a 225 for(addr = real_start; addr < real_end; addr++) {
54936004
FB
226 if (addr < start || addr >= end)
227 prot1 |= page_get_flags(addr);
228 }
3b46e624 229
54936004
FB
230 if (prot1 == 0) {
231 /* no page was there, so we allocate one */
80210bcd
TS
232 void *p = mmap(host_start, qemu_host_page_size, prot,
233 flags | MAP_ANONYMOUS, -1, 0);
234 if (p == MAP_FAILED)
235 return -1;
53a5960a 236 prot1 = prot;
54936004
FB
237 }
238 prot1 &= PAGE_BITS;
239
240 prot_new = prot | prot1;
241 if (!(flags & MAP_ANONYMOUS)) {
242 /* msync() won't work here, so we return an error if write is
243 possible while it is a shared mapping */
244 if ((flags & MAP_TYPE) == MAP_SHARED &&
245 (prot & PROT_WRITE))
246 return -EINVAL;
247
248 /* adjust protection to be able to read */
249 if (!(prot1 & PROT_WRITE))
53a5960a 250 mprotect(host_start, qemu_host_page_size, prot1 | PROT_WRITE);
3b46e624 251
54936004 252 /* read the corresponding file data */
fb7e378c
KS
253 if (pread(fd, g2h(start), end - start, offset) == -1)
254 return -1;
3b46e624 255
54936004
FB
256 /* put final protection */
257 if (prot_new != (prot1 | PROT_WRITE))
53a5960a 258 mprotect(host_start, qemu_host_page_size, prot_new);
54936004
FB
259 } else {
260 /* just update the protection */
261 if (prot_new != prot1) {
53a5960a 262 mprotect(host_start, qemu_host_page_size, prot_new);
54936004
FB
263 }
264 }
265 return 0;
266}
267
a03e2d42
FB
268#if defined(__CYGWIN__)
269/* Cygwin doesn't have a whole lot of address space. */
270static abi_ulong mmap_next_start = 0x18000000;
271#else
272static abi_ulong mmap_next_start = 0x40000000;
273#endif
274
0776590d
PB
275unsigned long last_brk;
276
fe3b4152
KS
277/*
278 * Find and reserve a free memory area of size 'size'. The search
279 * starts at 'start'.
280 * It must be called with mmap_lock() held.
281 * Return -1 if error.
282 */
9ad197d9 283abi_ulong mmap_find_vma(abi_ulong start, abi_ulong size)
a03e2d42 284{
fe3b4152
KS
285 void *ptr;
286 abi_ulong addr;
a03e2d42
FB
287
288 size = HOST_PAGE_ALIGN(size);
fe3b4152
KS
289 start &= qemu_host_page_mask;
290
291 /* If 'start' == 0, then a default start address is used. */
292 if (start == 0)
293 start = mmap_next_start;
294
a03e2d42 295 addr = start;
fe3b4152 296
a03e2d42 297 for(;;) {
fe3b4152
KS
298 /*
299 * Reserve needed memory area to avoid a race.
300 * It should be discarded using:
301 * - mmap() with MAP_FIXED flag
302 * - mremap() with MREMAP_FIXED flag
303 * - shmat() with SHM_REMAP flag
304 */
305 ptr = mmap((void *)(unsigned long)addr, size, PROT_NONE,
306 MAP_ANONYMOUS|MAP_PRIVATE|MAP_NORESERVE, -1, 0);
307
308 /* ENOMEM, if host address space has no memory */
309 if (ptr == MAP_FAILED)
310 return (abi_ulong)-1;
311
312 /* If address fits target address space we've found what we need */
313 if ((unsigned long)ptr + size - 1 <= (abi_ulong)-1)
a03e2d42 314 break;
fe3b4152
KS
315
316 /* Unmap and try again with new page */
317 munmap(ptr, size);
a03e2d42 318 addr += qemu_host_page_size;
fe3b4152
KS
319
320 /* ENOMEM if we check whole of target address space */
321 if (addr == start)
a03e2d42
FB
322 return (abi_ulong)-1;
323 }
fe3b4152
KS
324
325 /* Update default start address */
326 if (start == mmap_next_start)
327 mmap_next_start = (unsigned long)ptr + size;
328
329 return h2g(ptr);
a03e2d42
FB
330}
331
54936004 332/* NOTE: all the constants are the HOST ones */
992f48a0
BS
333abi_long target_mmap(abi_ulong start, abi_ulong len, int prot,
334 int flags, int fd, abi_ulong offset)
54936004 335{
992f48a0 336 abi_ulong ret, end, real_start, real_end, retaddr, host_offset, host_len;
a5b85f79 337 unsigned long host_start;
54936004 338
c8a706fe 339 mmap_lock();
54936004
FB
340#ifdef DEBUG_MMAP
341 {
0bf9e31a
BS
342 printf("mmap: start=0x" TARGET_ABI_FMT_lx
343 " len=0x" TARGET_ABI_FMT_lx " prot=%c%c%c flags=",
5fafdf24 344 start, len,
54936004
FB
345 prot & PROT_READ ? 'r' : '-',
346 prot & PROT_WRITE ? 'w' : '-',
347 prot & PROT_EXEC ? 'x' : '-');
348 if (flags & MAP_FIXED)
349 printf("MAP_FIXED ");
350 if (flags & MAP_ANONYMOUS)
351 printf("MAP_ANON ");
352 switch(flags & MAP_TYPE) {
353 case MAP_PRIVATE:
354 printf("MAP_PRIVATE ");
355 break;
356 case MAP_SHARED:
357 printf("MAP_SHARED ");
358 break;
359 default:
360 printf("[MAP_TYPE=0x%x] ", flags & MAP_TYPE);
361 break;
362 }
0bf9e31a 363 printf("fd=%d offset=" TARGET_ABI_FMT_lx "\n", fd, offset);
54936004
FB
364 }
365#endif
366
e89f07d3
PB
367 if (offset & ~TARGET_PAGE_MASK) {
368 errno = EINVAL;
c8a706fe 369 goto fail;
e89f07d3 370 }
54936004
FB
371
372 len = TARGET_PAGE_ALIGN(len);
373 if (len == 0)
c8a706fe 374 goto the_end;
53a5960a 375 real_start = start & qemu_host_page_mask;
54936004 376
54c5a2ae
EI
377 /* When mapping files into a memory area larger than the file, accesses
378 to pages beyond the file size will cause a SIGBUS.
379
380 For example, if mmaping a file of 100 bytes on a host with 4K pages
381 emulating a target with 8K pages, the target expects to be able to
382 access the first 8K. But the host will trap us on any access beyond
383 4K.
384
385 When emulating a target with a larger page-size than the hosts, we
386 may need to truncate file maps at EOF and add extra anonymous pages
387 up to the targets page boundary. */
388
389 if ((qemu_real_host_page_size < TARGET_PAGE_SIZE)
390 && !(flags & MAP_ANONYMOUS)) {
391 struct stat sb;
392
393 if (fstat (fd, &sb) == -1)
394 goto fail;
395
396 /* Are we trying to create a map beyond EOF?. */
397 if (offset + len > sb.st_size) {
398 /* If so, truncate the file map at eof aligned with
399 the hosts real pagesize. Additional anonymous maps
400 will be created beyond EOF. */
401 len = (sb.st_size - offset);
402 len += qemu_real_host_page_size - 1;
403 len &= ~(qemu_real_host_page_size - 1);
404 }
405 }
406
54936004 407 if (!(flags & MAP_FIXED)) {
a03e2d42
FB
408 abi_ulong mmap_start;
409 void *p;
410 host_offset = offset & qemu_host_page_mask;
411 host_len = len + offset - host_offset;
412 host_len = HOST_PAGE_ALIGN(host_len);
413 mmap_start = mmap_find_vma(real_start, host_len);
414 if (mmap_start == (abi_ulong)-1) {
415 errno = ENOMEM;
c8a706fe 416 goto fail;
54936004 417 }
a03e2d42
FB
418 /* Note: we prefer to control the mapping address. It is
419 especially important if qemu_host_page_size >
420 qemu_real_host_page_size */
421 p = mmap(g2h(mmap_start),
54c5a2ae 422 host_len, prot, flags | MAP_FIXED | MAP_ANONYMOUS, -1, 0);
a03e2d42 423 if (p == MAP_FAILED)
c8a706fe 424 goto fail;
a03e2d42
FB
425 /* update start so that it points to the file position at 'offset' */
426 host_start = (unsigned long)p;
54c5a2ae
EI
427 if (!(flags & MAP_ANONYMOUS)) {
428 p = mmap(g2h(mmap_start), len, prot,
429 flags | MAP_FIXED, fd, host_offset);
a03e2d42 430 host_start += offset - host_offset;
54c5a2ae 431 }
a03e2d42
FB
432 start = h2g(host_start);
433 } else {
7ab240ad
AZ
434 int flg;
435 target_ulong addr;
436
a03e2d42 437 if (start & ~TARGET_PAGE_MASK) {
e89f07d3 438 errno = EINVAL;
c8a706fe 439 goto fail;
e89f07d3 440 }
a03e2d42
FB
441 end = start + len;
442 real_end = HOST_PAGE_ALIGN(end);
7ab240ad 443
45bc1f52
AJ
444 /*
445 * Test if requested memory area fits target address space
446 * It can fail only on 64-bit host with 32-bit target.
447 * On any other target/host host mmap() handles this error correctly.
448 */
449 if ((unsigned long)start + len - 1 > (abi_ulong) -1) {
450 errno = EINVAL;
451 goto fail;
452 }
453
7ab240ad
AZ
454 for(addr = real_start; addr < real_end; addr += TARGET_PAGE_SIZE) {
455 flg = page_get_flags(addr);
456 if (flg & PAGE_RESERVED) {
457 errno = ENXIO;
c8a706fe 458 goto fail;
7ab240ad
AZ
459 }
460 }
461
a03e2d42
FB
462 /* worst case: we cannot map the file because the offset is not
463 aligned, so we read it */
464 if (!(flags & MAP_ANONYMOUS) &&
465 (offset & ~qemu_host_page_mask) != (start & ~qemu_host_page_mask)) {
466 /* msync() won't work here, so we return an error if write is
467 possible while it is a shared mapping */
468 if ((flags & MAP_TYPE) == MAP_SHARED &&
469 (prot & PROT_WRITE)) {
470 errno = EINVAL;
c8a706fe 471 goto fail;
a03e2d42
FB
472 }
473 retaddr = target_mmap(start, len, prot | PROT_WRITE,
474 MAP_FIXED | MAP_PRIVATE | MAP_ANONYMOUS,
475 -1, 0);
476 if (retaddr == -1)
c8a706fe 477 goto fail;
fb7e378c
KS
478 if (pread(fd, g2h(start), len, offset) == -1)
479 goto fail;
a03e2d42
FB
480 if (!(prot & PROT_WRITE)) {
481 ret = target_mprotect(start, len, prot);
c8a706fe
PB
482 if (ret != 0) {
483 start = ret;
484 goto the_end;
485 }
a03e2d42
FB
486 }
487 goto the_end;
54936004 488 }
a03e2d42
FB
489
490 /* handle the start of the mapping */
491 if (start > real_start) {
492 if (real_end == real_start + qemu_host_page_size) {
493 /* one single host page */
494 ret = mmap_frag(real_start, start, end,
495 prot, flags, fd, offset);
496 if (ret == -1)
c8a706fe 497 goto fail;
a03e2d42
FB
498 goto the_end1;
499 }
500 ret = mmap_frag(real_start, start, real_start + qemu_host_page_size,
54936004
FB
501 prot, flags, fd, offset);
502 if (ret == -1)
c8a706fe 503 goto fail;
a03e2d42
FB
504 real_start += qemu_host_page_size;
505 }
506 /* handle the end of the mapping */
507 if (end < real_end) {
508 ret = mmap_frag(real_end - qemu_host_page_size,
509 real_end - qemu_host_page_size, real_end,
510 prot, flags, fd,
511 offset + real_end - qemu_host_page_size - start);
512 if (ret == -1)
c8a706fe 513 goto fail;
a03e2d42 514 real_end -= qemu_host_page_size;
54936004 515 }
3b46e624 516
a03e2d42
FB
517 /* map the middle (easier) */
518 if (real_start < real_end) {
519 void *p;
520 unsigned long offset1;
521 if (flags & MAP_ANONYMOUS)
522 offset1 = 0;
523 else
524 offset1 = offset + real_start - start;
525 p = mmap(g2h(real_start), real_end - real_start,
526 prot, flags, fd, offset1);
527 if (p == MAP_FAILED)
c8a706fe 528 goto fail;
a03e2d42 529 }
54936004
FB
530 }
531 the_end1:
532 page_set_flags(start, start + len, prot | PAGE_VALID);
533 the_end:
534#ifdef DEBUG_MMAP
0bf9e31a 535 printf("ret=0x" TARGET_ABI_FMT_lx "\n", start);
54936004
FB
536 page_dump(stdout);
537 printf("\n");
538#endif
c8a706fe 539 mmap_unlock();
54936004 540 return start;
c8a706fe
PB
541fail:
542 mmap_unlock();
543 return -1;
54936004
FB
544}
545
992f48a0 546int target_munmap(abi_ulong start, abi_ulong len)
54936004 547{
992f48a0 548 abi_ulong end, real_start, real_end, addr;
54936004
FB
549 int prot, ret;
550
551#ifdef DEBUG_MMAP
0bf9e31a
BS
552 printf("munmap: start=0x" TARGET_ABI_FMT_lx " len=0x"
553 TARGET_ABI_FMT_lx "\n",
554 start, len);
54936004
FB
555#endif
556 if (start & ~TARGET_PAGE_MASK)
557 return -EINVAL;
558 len = TARGET_PAGE_ALIGN(len);
559 if (len == 0)
560 return -EINVAL;
c8a706fe 561 mmap_lock();
54936004 562 end = start + len;
53a5960a
PB
563 real_start = start & qemu_host_page_mask;
564 real_end = HOST_PAGE_ALIGN(end);
54936004 565
53a5960a 566 if (start > real_start) {
54936004
FB
567 /* handle host page containing start */
568 prot = 0;
53a5960a 569 for(addr = real_start; addr < start; addr += TARGET_PAGE_SIZE) {
54936004
FB
570 prot |= page_get_flags(addr);
571 }
53a5960a
PB
572 if (real_end == real_start + qemu_host_page_size) {
573 for(addr = end; addr < real_end; addr += TARGET_PAGE_SIZE) {
d418c81e
FB
574 prot |= page_get_flags(addr);
575 }
53a5960a 576 end = real_end;
d418c81e 577 }
54936004 578 if (prot != 0)
53a5960a 579 real_start += qemu_host_page_size;
54936004 580 }
53a5960a 581 if (end < real_end) {
54936004 582 prot = 0;
53a5960a 583 for(addr = end; addr < real_end; addr += TARGET_PAGE_SIZE) {
54936004
FB
584 prot |= page_get_flags(addr);
585 }
586 if (prot != 0)
53a5960a 587 real_end -= qemu_host_page_size;
54936004 588 }
3b46e624 589
c8a706fe 590 ret = 0;
54936004 591 /* unmap what we can */
53a5960a 592 if (real_start < real_end) {
4118a970 593 ret = munmap(g2h(real_start), real_end - real_start);
54936004
FB
594 }
595
c8a706fe
PB
596 if (ret == 0)
597 page_set_flags(start, start + len, 0);
598 mmap_unlock();
599 return ret;
54936004
FB
600}
601
992f48a0
BS
602abi_long target_mremap(abi_ulong old_addr, abi_ulong old_size,
603 abi_ulong new_size, unsigned long flags,
604 abi_ulong new_addr)
54936004
FB
605{
606 int prot;
f19412a2 607 void *host_addr;
54936004 608
c8a706fe 609 mmap_lock();
f19412a2
AJ
610
611 if (flags & MREMAP_FIXED)
3af72a4d
BS
612 host_addr = (void *) syscall(__NR_mremap, g2h(old_addr),
613 old_size, new_size,
614 flags,
615 new_addr);
f19412a2
AJ
616 else if (flags & MREMAP_MAYMOVE) {
617 abi_ulong mmap_start;
618
619 mmap_start = mmap_find_vma(0, new_size);
620
621 if (mmap_start == -1) {
622 errno = ENOMEM;
623 host_addr = MAP_FAILED;
624 } else
3af72a4d
BS
625 host_addr = (void *) syscall(__NR_mremap, g2h(old_addr),
626 old_size, new_size,
627 flags | MREMAP_FIXED,
628 g2h(mmap_start));
629 } else {
f19412a2
AJ
630 host_addr = mremap(g2h(old_addr), old_size, new_size, flags);
631 /* Check if address fits target address space */
632 if ((unsigned long)host_addr + new_size > (abi_ulong)-1) {
633 /* Revert mremap() changes */
634 host_addr = mremap(g2h(old_addr), new_size, old_size, flags);
635 errno = ENOMEM;
636 host_addr = MAP_FAILED;
637 }
638 }
639
640 if (host_addr == MAP_FAILED) {
c8a706fe
PB
641 new_addr = -1;
642 } else {
643 new_addr = h2g(host_addr);
644 prot = page_get_flags(old_addr);
645 page_set_flags(old_addr, old_addr + old_size, 0);
646 page_set_flags(new_addr, new_addr + new_size, prot | PAGE_VALID);
647 }
648 mmap_unlock();
54936004
FB
649 return new_addr;
650}
651
992f48a0 652int target_msync(abi_ulong start, abi_ulong len, int flags)
54936004 653{
992f48a0 654 abi_ulong end;
54936004
FB
655
656 if (start & ~TARGET_PAGE_MASK)
657 return -EINVAL;
658 len = TARGET_PAGE_ALIGN(len);
54936004 659 end = start + len;
d418c81e
FB
660 if (end < start)
661 return -EINVAL;
662 if (end == start)
663 return 0;
3b46e624 664
83fb7adf 665 start &= qemu_host_page_mask;
53a5960a 666 return msync(g2h(start), end - start, flags);
54936004 667}