mirror of
https://github.com/xemu-project/xemu.git
synced 2024-11-24 03:59:52 +00:00
linux-user: Factor out guest space probing into a function
Signed-off-by: Meador Inge <meadori@codesourcery.com> Reviewed-by: Peter Maydell <peter.maydell@linaro.org> Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
This commit is contained in:
parent
cd8e407d24
commit
dce104013d
@ -1426,6 +1426,73 @@ bool guest_validate_base(unsigned long guest_base)
|
|||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
unsigned long init_guest_space(unsigned long host_start,
|
||||||
|
unsigned long host_size,
|
||||||
|
unsigned long guest_start,
|
||||||
|
bool fixed)
|
||||||
|
{
|
||||||
|
unsigned long current_start, real_start;
|
||||||
|
int flags;
|
||||||
|
|
||||||
|
assert(host_start || host_size);
|
||||||
|
|
||||||
|
/* If just a starting address is given, then just verify that
|
||||||
|
* address. */
|
||||||
|
if (host_start && !host_size) {
|
||||||
|
if (guest_validate_base(host_start)) {
|
||||||
|
return host_start;
|
||||||
|
} else {
|
||||||
|
return (unsigned long)-1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Setup the initial flags and start address. */
|
||||||
|
current_start = host_start & qemu_host_page_mask;
|
||||||
|
flags = MAP_ANONYMOUS | MAP_PRIVATE | MAP_NORESERVE;
|
||||||
|
if (fixed) {
|
||||||
|
flags |= MAP_FIXED;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Otherwise, a non-zero size region of memory needs to be mapped
|
||||||
|
* and validated. */
|
||||||
|
while (1) {
|
||||||
|
/* Do not use mmap_find_vma here because that is limited to the
|
||||||
|
* guest address space. We are going to make the
|
||||||
|
* guest address space fit whatever we're given.
|
||||||
|
*/
|
||||||
|
real_start = (unsigned long)
|
||||||
|
mmap((void *)current_start, host_size, PROT_NONE, flags, -1, 0);
|
||||||
|
if (real_start == (unsigned long)-1) {
|
||||||
|
return (unsigned long)-1;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ((real_start == current_start)
|
||||||
|
&& guest_validate_base(real_start - guest_start)) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* That address didn't work. Unmap and try a different one.
|
||||||
|
* The address the host picked because is typically right at
|
||||||
|
* the top of the host address space and leaves the guest with
|
||||||
|
* no usable address space. Resort to a linear search. We
|
||||||
|
* already compensated for mmap_min_addr, so this should not
|
||||||
|
* happen often. Probably means we got unlucky and host
|
||||||
|
* address space randomization put a shared library somewhere
|
||||||
|
* inconvenient.
|
||||||
|
*/
|
||||||
|
munmap((void *)real_start, host_size);
|
||||||
|
current_start += qemu_host_page_size;
|
||||||
|
if (host_start == current_start) {
|
||||||
|
/* Theoretically possible if host doesn't have any suitably
|
||||||
|
* aligned areas. Normally the first mmap will fail.
|
||||||
|
*/
|
||||||
|
return (unsigned long)-1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return real_start;
|
||||||
|
}
|
||||||
|
|
||||||
static void probe_guest_base(const char *image_name,
|
static void probe_guest_base(const char *image_name,
|
||||||
abi_ulong loaddr, abi_ulong hiaddr)
|
abi_ulong loaddr, abi_ulong hiaddr)
|
||||||
{
|
{
|
||||||
@ -1452,46 +1519,23 @@ static void probe_guest_base(const char *image_name,
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
host_size = hiaddr - loaddr;
|
host_size = hiaddr - loaddr;
|
||||||
while (1) {
|
|
||||||
/* Do not use mmap_find_vma here because that is limited to the
|
/* Setup the initial guest memory space with ranges gleaned from
|
||||||
guest address space. We are going to make the
|
* the ELF image that is being loaded.
|
||||||
guest address space fit whatever we're given. */
|
*/
|
||||||
real_start = (unsigned long)
|
real_start = init_guest_space(host_start, host_size, loaddr, false);
|
||||||
mmap((void *)host_start, host_size, PROT_NONE,
|
if (real_start == (unsigned long)-1) {
|
||||||
MAP_ANONYMOUS | MAP_PRIVATE | MAP_NORESERVE, -1, 0);
|
errmsg = "Unable to find space for application";
|
||||||
if (real_start == (unsigned long)-1) {
|
goto exit_errmsg;
|
||||||
goto exit_perror;
|
|
||||||
}
|
|
||||||
guest_base = real_start - loaddr;
|
|
||||||
if ((real_start == host_start) &&
|
|
||||||
guest_validate_base(guest_base)) {
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
/* That address didn't work. Unmap and try a different one.
|
|
||||||
The address the host picked because is typically right at
|
|
||||||
the top of the host address space and leaves the guest with
|
|
||||||
no usable address space. Resort to a linear search. We
|
|
||||||
already compensated for mmap_min_addr, so this should not
|
|
||||||
happen often. Probably means we got unlucky and host
|
|
||||||
address space randomization put a shared library somewhere
|
|
||||||
inconvenient. */
|
|
||||||
munmap((void *)real_start, host_size);
|
|
||||||
host_start += qemu_host_page_size;
|
|
||||||
if (host_start == loaddr) {
|
|
||||||
/* Theoretically possible if host doesn't have any suitably
|
|
||||||
aligned areas. Normally the first mmap will fail. */
|
|
||||||
errmsg = "Unable to find space for application";
|
|
||||||
goto exit_errmsg;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
guest_base = real_start - loaddr;
|
||||||
|
|
||||||
qemu_log("Relocating guest address space from 0x"
|
qemu_log("Relocating guest address space from 0x"
|
||||||
TARGET_ABI_FMT_lx " to 0x%lx\n",
|
TARGET_ABI_FMT_lx " to 0x%lx\n",
|
||||||
loaddr, real_start);
|
loaddr, real_start);
|
||||||
}
|
}
|
||||||
return;
|
return;
|
||||||
|
|
||||||
exit_perror:
|
|
||||||
errmsg = strerror(errno);
|
|
||||||
exit_errmsg:
|
exit_errmsg:
|
||||||
fprintf(stderr, "%s: %s\n", image_name, errmsg);
|
fprintf(stderr, "%s: %s\n", image_name, errmsg);
|
||||||
exit(-1);
|
exit(-1);
|
||||||
|
@ -210,6 +210,19 @@ void fork_end(int child);
|
|||||||
*/
|
*/
|
||||||
bool guest_validate_base(unsigned long guest_base);
|
bool guest_validate_base(unsigned long guest_base);
|
||||||
|
|
||||||
|
/* Creates the initial guest address space in the host memory space using
|
||||||
|
* the given host start address hint and size. The guest_start parameter
|
||||||
|
* specifies the start address of the guest space. guest_base will be the
|
||||||
|
* difference between the host start address computed by this function and
|
||||||
|
* guest_start. If fixed is specified, then the mapped address space must
|
||||||
|
* start at host_start. The real start address of the mapped memory space is
|
||||||
|
* returned or -1 if there was an error.
|
||||||
|
*/
|
||||||
|
unsigned long init_guest_space(unsigned long host_start,
|
||||||
|
unsigned long host_size,
|
||||||
|
unsigned long guest_start,
|
||||||
|
bool fixed);
|
||||||
|
|
||||||
#include "qemu-log.h"
|
#include "qemu-log.h"
|
||||||
|
|
||||||
/* strace.c */
|
/* strace.c */
|
||||||
|
Loading…
Reference in New Issue
Block a user