mirror of
https://github.com/Motorhead1991/qemu.git
synced 2025-12-17 21:26:13 -07:00
Pre-allocate guest address space
Allow pre-allocation of the guest virtual address space in usermode emulation. Signed-off-by: Paul Brook <paul@codesourcery.com>
This commit is contained in:
parent
0be1d07c0e
commit
68a1c81686
5 changed files with 183 additions and 8 deletions
|
|
@ -216,6 +216,40 @@ static abi_ulong mmap_next_start = TASK_UNMAPPED_BASE;
|
|||
|
||||
unsigned long last_brk;
|
||||
|
||||
/* Subroutine of mmap_find_vma, used when we have pre-allocated a chunk
|
||||
of guest address space. */
|
||||
static abi_ulong mmap_find_vma_reserved(abi_ulong start, abi_ulong size)
|
||||
{
|
||||
abi_ulong addr;
|
||||
abi_ulong last_addr;
|
||||
int prot;
|
||||
int looped = 0;
|
||||
|
||||
if (size > reserved_va) {
|
||||
return (abi_ulong)-1;
|
||||
}
|
||||
|
||||
last_addr = start;
|
||||
for (addr = start; last_addr + size != addr; addr += qemu_host_page_size) {
|
||||
if (last_addr + size >= reserved_va
|
||||
|| (abi_ulong)(last_addr + size) < last_addr) {
|
||||
if (looped) {
|
||||
return (abi_ulong)-1;
|
||||
}
|
||||
last_addr = qemu_host_page_size;
|
||||
addr = 0;
|
||||
looped = 1;
|
||||
continue;
|
||||
}
|
||||
prot = page_get_flags(addr);
|
||||
if (prot) {
|
||||
last_addr = addr + qemu_host_page_size;
|
||||
}
|
||||
}
|
||||
mmap_next_start = addr;
|
||||
return last_addr;
|
||||
}
|
||||
|
||||
/*
|
||||
* Find and reserve a free memory area of size 'size'. The search
|
||||
* starts at 'start'.
|
||||
|
|
@ -237,6 +271,10 @@ abi_ulong mmap_find_vma(abi_ulong start, abi_ulong size)
|
|||
|
||||
size = HOST_PAGE_ALIGN(size);
|
||||
|
||||
if (reserved_va) {
|
||||
return mmap_find_vma_reserved(start, size);
|
||||
}
|
||||
|
||||
addr = start;
|
||||
wrapped = repeat = 0;
|
||||
prev = 0;
|
||||
|
|
@ -525,6 +563,47 @@ fail:
|
|||
return -1;
|
||||
}
|
||||
|
||||
static void mmap_reserve(abi_ulong start, abi_ulong size)
|
||||
{
|
||||
abi_ulong real_start;
|
||||
abi_ulong real_end;
|
||||
abi_ulong addr;
|
||||
abi_ulong end;
|
||||
int prot;
|
||||
|
||||
real_start = start & qemu_host_page_mask;
|
||||
real_end = HOST_PAGE_ALIGN(start + size);
|
||||
end = start + size;
|
||||
if (start > real_start) {
|
||||
/* handle host page containing start */
|
||||
prot = 0;
|
||||
for (addr = real_start; addr < start; addr += TARGET_PAGE_SIZE) {
|
||||
prot |= page_get_flags(addr);
|
||||
}
|
||||
if (real_end == real_start + qemu_host_page_size) {
|
||||
for (addr = end; addr < real_end; addr += TARGET_PAGE_SIZE) {
|
||||
prot |= page_get_flags(addr);
|
||||
}
|
||||
end = real_end;
|
||||
}
|
||||
if (prot != 0)
|
||||
real_start += qemu_host_page_size;
|
||||
}
|
||||
if (end < real_end) {
|
||||
prot = 0;
|
||||
for (addr = end; addr < real_end; addr += TARGET_PAGE_SIZE) {
|
||||
prot |= page_get_flags(addr);
|
||||
}
|
||||
if (prot != 0)
|
||||
real_end -= qemu_host_page_size;
|
||||
}
|
||||
if (real_start != real_end) {
|
||||
mmap(g2h(real_start), real_end - real_start, PROT_NONE,
|
||||
MAP_FIXED | MAP_ANONYMOUS | MAP_PRIVATE | MAP_NORESERVE,
|
||||
-1, 0);
|
||||
}
|
||||
}
|
||||
|
||||
int target_munmap(abi_ulong start, abi_ulong len)
|
||||
{
|
||||
abi_ulong end, real_start, real_end, addr;
|
||||
|
|
@ -572,7 +651,11 @@ int target_munmap(abi_ulong start, abi_ulong len)
|
|||
ret = 0;
|
||||
/* unmap what we can */
|
||||
if (real_start < real_end) {
|
||||
ret = munmap(g2h(real_start), real_end - real_start);
|
||||
if (reserved_va) {
|
||||
mmap_reserve(real_start, real_end - real_start);
|
||||
} else {
|
||||
ret = munmap(g2h(real_start), real_end - real_start);
|
||||
}
|
||||
}
|
||||
|
||||
if (ret == 0)
|
||||
|
|
@ -590,12 +673,18 @@ abi_long target_mremap(abi_ulong old_addr, abi_ulong old_size,
|
|||
|
||||
mmap_lock();
|
||||
|
||||
if (flags & MREMAP_FIXED)
|
||||
if (flags & MREMAP_FIXED) {
|
||||
host_addr = (void *) syscall(__NR_mremap, g2h(old_addr),
|
||||
old_size, new_size,
|
||||
flags,
|
||||
new_addr);
|
||||
else if (flags & MREMAP_MAYMOVE) {
|
||||
g2h(new_addr));
|
||||
|
||||
if (reserved_va && host_addr != MAP_FAILED) {
|
||||
/* If new and old addresses overlap then the above mremap will
|
||||
already have failed with EINVAL. */
|
||||
mmap_reserve(old_addr, old_size);
|
||||
}
|
||||
} else if (flags & MREMAP_MAYMOVE) {
|
||||
abi_ulong mmap_start;
|
||||
|
||||
mmap_start = mmap_find_vma(0, new_size);
|
||||
|
|
@ -603,13 +692,32 @@ abi_long target_mremap(abi_ulong old_addr, abi_ulong old_size,
|
|||
if (mmap_start == -1) {
|
||||
errno = ENOMEM;
|
||||
host_addr = MAP_FAILED;
|
||||
} else
|
||||
} else {
|
||||
host_addr = (void *) syscall(__NR_mremap, g2h(old_addr),
|
||||
old_size, new_size,
|
||||
flags | MREMAP_FIXED,
|
||||
g2h(mmap_start));
|
||||
mmap_reserve(old_addr, old_size);
|
||||
}
|
||||
} else {
|
||||
host_addr = mremap(g2h(old_addr), old_size, new_size, flags);
|
||||
int prot = 0;
|
||||
if (reserved_va && old_size < new_size) {
|
||||
abi_ulong addr;
|
||||
for (addr = old_addr + old_size;
|
||||
addr < old_addr + new_size;
|
||||
addr++) {
|
||||
prot |= page_get_flags(addr);
|
||||
}
|
||||
}
|
||||
if (prot == 0) {
|
||||
host_addr = mremap(g2h(old_addr), old_size, new_size, flags);
|
||||
if (host_addr != MAP_FAILED && reserved_va && old_size > new_size) {
|
||||
mmap_reserve(old_addr + old_size, new_size - old_size);
|
||||
}
|
||||
} else {
|
||||
errno = ENOMEM;
|
||||
host_addr = MAP_FAILED;
|
||||
}
|
||||
/* Check if address fits target address space */
|
||||
if ((unsigned long)host_addr + new_size > (abi_ulong)-1) {
|
||||
/* Revert mremap() changes */
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue