Revision fe3b4152
b/linux-user/mmap.c | ||
---|---|---|
273 | 273 |
|
274 | 274 |
unsigned long last_brk; |
275 | 275 |
|
276 |
/* find a free memory area of size 'size'. The search starts at
|
|
277 |
'start'. If 'start' == 0, then a default start address is used.
|
|
278 |
Return -1 if error.
|
|
279 |
*/
|
|
280 |
/* page_init() marks pages used by the host as reserved to be sure not
|
|
281 |
to use them. */
|
|
276 |
/* |
|
277 |
* Find and reserve a free memory area of size 'size'. The search
|
|
278 |
* starts at 'start'.
|
|
279 |
* It must be called with mmap_lock() held.
|
|
280 |
* Return -1 if error.
|
|
281 |
*/ |
|
282 | 282 |
abi_ulong mmap_find_vma(abi_ulong start, abi_ulong size) |
283 | 283 |
{ |
284 |
abi_ulong addr, addr1, addr_start; |
|
285 |
int prot; |
|
286 |
unsigned long new_brk; |
|
287 |
|
|
288 |
new_brk = (unsigned long)sbrk(0); |
|
289 |
if (last_brk && last_brk < new_brk && last_brk == (target_ulong)last_brk) { |
|
290 |
/* This is a hack to catch the host allocating memory with brk(). |
|
291 |
If it uses mmap then we loose. |
|
292 |
FIXME: We really want to avoid the host allocating memory in |
|
293 |
the first place, and maybe leave some slack to avoid switching |
|
294 |
to mmap. */ |
|
295 |
page_set_flags(last_brk & TARGET_PAGE_MASK, |
|
296 |
TARGET_PAGE_ALIGN(new_brk), |
|
297 |
PAGE_RESERVED); |
|
298 |
} |
|
299 |
last_brk = new_brk; |
|
284 |
void *ptr; |
|
285 |
abi_ulong addr; |
|
300 | 286 |
|
301 | 287 |
size = HOST_PAGE_ALIGN(size); |
302 |
start = start & qemu_host_page_mask; |
|
288 |
start &= qemu_host_page_mask; |
|
289 |
|
|
290 |
/* If 'start' == 0, then a default start address is used. */ |
|
291 |
if (start == 0) |
|
292 |
start = mmap_next_start; |
|
293 |
|
|
303 | 294 |
addr = start; |
304 |
if (addr == 0) |
|
305 |
addr = mmap_next_start; |
|
306 |
addr_start = addr; |
|
295 |
|
|
307 | 296 |
for(;;) { |
308 |
prot = 0; |
|
309 |
for(addr1 = addr; addr1 < (addr + size); addr1 += TARGET_PAGE_SIZE) { |
|
310 |
prot |= page_get_flags(addr1); |
|
311 |
} |
|
312 |
if (prot == 0) |
|
297 |
/* |
|
298 |
* Reserve needed memory area to avoid a race. |
|
299 |
* It should be discarded using: |
|
300 |
* - mmap() with MAP_FIXED flag |
|
301 |
* - mremap() with MREMAP_FIXED flag |
|
302 |
* - shmat() with SHM_REMAP flag |
|
303 |
*/ |
|
304 |
ptr = mmap((void *)(unsigned long)addr, size, PROT_NONE, |
|
305 |
MAP_ANONYMOUS|MAP_PRIVATE|MAP_NORESERVE, -1, 0); |
|
306 |
|
|
307 |
/* ENOMEM, if host address space has no memory */ |
|
308 |
if (ptr == MAP_FAILED) |
|
309 |
return (abi_ulong)-1; |
|
310 |
|
|
311 |
/* If address fits target address space we've found what we need */ |
|
312 |
if ((unsigned long)ptr + size - 1 <= (abi_ulong)-1) |
|
313 | 313 |
break; |
314 |
|
|
315 |
/* Unmap and try again with new page */ |
|
316 |
munmap(ptr, size); |
|
314 | 317 |
addr += qemu_host_page_size; |
315 |
/* we found nothing */ |
|
316 |
if (addr == addr_start) |
|
318 |
|
|
319 |
/* ENOMEM if we check whole of target address space */ |
|
320 |
if (addr == start) |
|
317 | 321 |
return (abi_ulong)-1; |
318 | 322 |
} |
319 |
if (start == 0) |
|
320 |
mmap_next_start = addr + size; |
|
321 |
return addr; |
|
323 |
|
|
324 |
/* Update default start address */ |
|
325 |
if (start == mmap_next_start) |
|
326 |
mmap_next_start = (unsigned long)ptr + size; |
|
327 |
|
|
328 |
return h2g(ptr); |
|
322 | 329 |
} |
323 | 330 |
|
324 | 331 |
/* NOTE: all the constants are the HOST ones */ |
Also available in: Unified diff