mirror of https://github.com/xemu-project/xemu.git
Userspace guest address offsetting
Re-implement GUEST_BASE support. Offset guest ddress space by default if the guest binary contains regions below the host mmap_min_addr. Implement support for i386, x86-64 and arm hosts. Signed-off-by: Riku Voipio <riku.voipio@iki.fi> Signed-off-by: Paul Brook <paul@codesourcery.com>
This commit is contained in:
parent
a9ff9df188
commit
379f6698d7
|
@ -184,6 +184,7 @@ softmmu="yes"
|
||||||
linux_user="no"
|
linux_user="no"
|
||||||
darwin_user="no"
|
darwin_user="no"
|
||||||
bsd_user="no"
|
bsd_user="no"
|
||||||
|
guest_base=""
|
||||||
build_docs="yes"
|
build_docs="yes"
|
||||||
uname_release=""
|
uname_release=""
|
||||||
curses="yes"
|
curses="yes"
|
||||||
|
@ -465,6 +466,10 @@ for opt do
|
||||||
;;
|
;;
|
||||||
--enable-bsd-user) bsd_user="yes"
|
--enable-bsd-user) bsd_user="yes"
|
||||||
;;
|
;;
|
||||||
|
--enable-guest-base) guest_base="yes"
|
||||||
|
;;
|
||||||
|
--disable-guest-base) guest_base="no"
|
||||||
|
;;
|
||||||
--enable-uname-release=*) uname_release="$optarg"
|
--enable-uname-release=*) uname_release="$optarg"
|
||||||
;;
|
;;
|
||||||
--sparc_cpu=*)
|
--sparc_cpu=*)
|
||||||
|
@ -544,6 +549,7 @@ fi
|
||||||
# If cpu ~= sparc and sparc_cpu hasn't been defined, plug in the right
|
# If cpu ~= sparc and sparc_cpu hasn't been defined, plug in the right
|
||||||
# ARCH_CFLAGS/ARCH_LDFLAGS (assume sparc_v8plus for 32-bit and sparc_v9 for 64-bit)
|
# ARCH_CFLAGS/ARCH_LDFLAGS (assume sparc_v8plus for 32-bit and sparc_v9 for 64-bit)
|
||||||
#
|
#
|
||||||
|
host_guest_base="no"
|
||||||
case "$cpu" in
|
case "$cpu" in
|
||||||
sparc) if test -z "$sparc_cpu" ; then
|
sparc) if test -z "$sparc_cpu" ; then
|
||||||
ARCH_CFLAGS="-m32 -mcpu=ultrasparc -D__sparc_v8plus__"
|
ARCH_CFLAGS="-m32 -mcpu=ultrasparc -D__sparc_v8plus__"
|
||||||
|
@ -576,13 +582,20 @@ case "$cpu" in
|
||||||
i386)
|
i386)
|
||||||
ARCH_CFLAGS="-m32"
|
ARCH_CFLAGS="-m32"
|
||||||
ARCH_LDFLAGS="-m32"
|
ARCH_LDFLAGS="-m32"
|
||||||
|
host_guest_base="yes"
|
||||||
;;
|
;;
|
||||||
x86_64)
|
x86_64)
|
||||||
ARCH_CFLAGS="-m64"
|
ARCH_CFLAGS="-m64"
|
||||||
ARCH_LDFLAGS="-m64"
|
ARCH_LDFLAGS="-m64"
|
||||||
|
host_guest_base="yes"
|
||||||
|
;;
|
||||||
|
arm*)
|
||||||
|
host_guest_base="yes"
|
||||||
;;
|
;;
|
||||||
esac
|
esac
|
||||||
|
|
||||||
|
[ -z "$guest_base" ] && guest_base="$host_guest_base"
|
||||||
|
|
||||||
if test x"$show_help" = x"yes" ; then
|
if test x"$show_help" = x"yes" ; then
|
||||||
cat << EOF
|
cat << EOF
|
||||||
|
|
||||||
|
@ -641,6 +654,9 @@ echo " --enable-darwin-user enable all darwin usermode emulation targets"
|
||||||
echo " --disable-darwin-user disable all darwin usermode emulation targets"
|
echo " --disable-darwin-user disable all darwin usermode emulation targets"
|
||||||
echo " --enable-bsd-user enable all BSD usermode emulation targets"
|
echo " --enable-bsd-user enable all BSD usermode emulation targets"
|
||||||
echo " --disable-bsd-user disable all BSD usermode emulation targets"
|
echo " --disable-bsd-user disable all BSD usermode emulation targets"
|
||||||
|
echo " --enable-guest-base enable GUEST_BASE support for usermode"
|
||||||
|
echo " emulation targets"
|
||||||
|
echo " --disable-guest-base disable GUEST_BASE support"
|
||||||
echo " --fmod-lib path to FMOD library"
|
echo " --fmod-lib path to FMOD library"
|
||||||
echo " --fmod-inc path to FMOD includes"
|
echo " --fmod-inc path to FMOD includes"
|
||||||
echo " --oss-lib path to OSS library"
|
echo " --oss-lib path to OSS library"
|
||||||
|
@ -1446,6 +1462,7 @@ echo "Documentation $build_docs"
|
||||||
[ ! -z "$uname_release" ] && \
|
[ ! -z "$uname_release" ] && \
|
||||||
echo "uname -r $uname_release"
|
echo "uname -r $uname_release"
|
||||||
echo "NPTL support $nptl"
|
echo "NPTL support $nptl"
|
||||||
|
echo "GUEST_BASE $guest_base"
|
||||||
echo "vde support $vde"
|
echo "vde support $vde"
|
||||||
echo "AIO support $aio"
|
echo "AIO support $aio"
|
||||||
echo "IO thread $io_thread"
|
echo "IO thread $io_thread"
|
||||||
|
@ -2070,6 +2087,9 @@ fi
|
||||||
if test "$target_user_only" = "yes" -a "$elfload32" = "yes"; then
|
if test "$target_user_only" = "yes" -a "$elfload32" = "yes"; then
|
||||||
echo "TARGET_HAS_ELFLOAD32=y" >> $config_mak
|
echo "TARGET_HAS_ELFLOAD32=y" >> $config_mak
|
||||||
fi
|
fi
|
||||||
|
if test "$target_user_only" = "yes" -a "$guest_base" = "yes"; then
|
||||||
|
echo "CONFIG_USE_GUEST_BASE=y" >> $config_mak
|
||||||
|
fi
|
||||||
if test "$target_bsd_user" = "yes" ; then
|
if test "$target_bsd_user" = "yes" ; then
|
||||||
echo "CONFIG_BSD_USER=y" >> $config_mak
|
echo "CONFIG_BSD_USER=y" >> $config_mak
|
||||||
fi
|
fi
|
||||||
|
|
|
@ -624,8 +624,13 @@ static inline void stfq_be_p(void *ptr, float64 v)
|
||||||
/* On some host systems the guest address space is reserved on the host.
|
/* On some host systems the guest address space is reserved on the host.
|
||||||
* This allows the guest address space to be offset to a convenient location.
|
* This allows the guest address space to be offset to a convenient location.
|
||||||
*/
|
*/
|
||||||
//#define GUEST_BASE 0x20000000
|
#if defined(CONFIG_USE_GUEST_BASE)
|
||||||
#define GUEST_BASE 0
|
extern unsigned long guest_base;
|
||||||
|
extern int have_guest_base;
|
||||||
|
#define GUEST_BASE guest_base
|
||||||
|
#else
|
||||||
|
#define GUEST_BASE 0ul
|
||||||
|
#endif
|
||||||
|
|
||||||
/* All direct uses of g2h and h2g need to go away for usermode softmmu. */
|
/* All direct uses of g2h and h2g need to go away for usermode softmmu. */
|
||||||
#define g2h(x) ((void *)((unsigned long)(x) + GUEST_BASE))
|
#define g2h(x) ((void *)((unsigned long)(x) + GUEST_BASE))
|
||||||
|
|
|
@ -1545,6 +1545,29 @@ int load_elf_binary(struct linux_binprm * bprm, struct target_pt_regs * regs,
|
||||||
info->mmap = 0;
|
info->mmap = 0;
|
||||||
elf_entry = (abi_ulong) elf_ex.e_entry;
|
elf_entry = (abi_ulong) elf_ex.e_entry;
|
||||||
|
|
||||||
|
#if defined(CONFIG_USE_GUEST_BASE)
|
||||||
|
/*
|
||||||
|
* In case where user has not explicitly set the guest_base, we
|
||||||
|
* probe here that should we set it automatically.
|
||||||
|
*/
|
||||||
|
if (!have_guest_base) {
|
||||||
|
/*
|
||||||
|
* Go through ELF program header table and find out whether
|
||||||
|
* any of the segments drop below our current mmap_min_addr and
|
||||||
|
* in that case set guest_base to corresponding address.
|
||||||
|
*/
|
||||||
|
for (i = 0, elf_ppnt = elf_phdata; i < elf_ex.e_phnum;
|
||||||
|
i++, elf_ppnt++) {
|
||||||
|
if (elf_ppnt->p_type != PT_LOAD)
|
||||||
|
continue;
|
||||||
|
if (HOST_PAGE_ALIGN(elf_ppnt->p_vaddr) < mmap_min_addr) {
|
||||||
|
guest_base = HOST_PAGE_ALIGN(mmap_min_addr);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#endif /* CONFIG_USE_GUEST_BASE */
|
||||||
|
|
||||||
/* Do this so that we can load the interpreter, if need be. We will
|
/* Do this so that we can load the interpreter, if need be. We will
|
||||||
change some of these later */
|
change some of these later */
|
||||||
info->rss = 0;
|
info->rss = 0;
|
||||||
|
|
|
@ -39,6 +39,11 @@
|
||||||
char *exec_path;
|
char *exec_path;
|
||||||
|
|
||||||
int singlestep;
|
int singlestep;
|
||||||
|
#if defined(CONFIG_USE_GUEST_BASE)
|
||||||
|
unsigned long mmap_min_addr;
|
||||||
|
unsigned long guest_base;
|
||||||
|
int have_guest_base;
|
||||||
|
#endif
|
||||||
|
|
||||||
static const char *interp_prefix = CONFIG_QEMU_PREFIX;
|
static const char *interp_prefix = CONFIG_QEMU_PREFIX;
|
||||||
const char *qemu_uname_release = CONFIG_UNAME_RELEASE;
|
const char *qemu_uname_release = CONFIG_UNAME_RELEASE;
|
||||||
|
@ -2320,6 +2325,9 @@ static void usage(void)
|
||||||
"-E var=value sets/modifies targets environment variable(s)\n"
|
"-E var=value sets/modifies targets environment variable(s)\n"
|
||||||
"-U var unsets targets environment variable(s)\n"
|
"-U var unsets targets environment variable(s)\n"
|
||||||
"-0 argv0 forces target process argv[0] to be argv0\n"
|
"-0 argv0 forces target process argv[0] to be argv0\n"
|
||||||
|
#if defined(CONFIG_USE_GUEST_BASE)
|
||||||
|
"-B address set guest_base address to address\n"
|
||||||
|
#endif
|
||||||
"\n"
|
"\n"
|
||||||
"Debug options:\n"
|
"Debug options:\n"
|
||||||
"-d options activate log (logfile=%s)\n"
|
"-d options activate log (logfile=%s)\n"
|
||||||
|
@ -2495,6 +2503,11 @@ int main(int argc, char **argv, char **envp)
|
||||||
#endif
|
#endif
|
||||||
exit(1);
|
exit(1);
|
||||||
}
|
}
|
||||||
|
#if defined(CONFIG_USE_GUEST_BASE)
|
||||||
|
} else if (!strcmp(r, "B")) {
|
||||||
|
guest_base = strtol(argv[optind++], NULL, 0);
|
||||||
|
have_guest_base = 1;
|
||||||
|
#endif
|
||||||
} else if (!strcmp(r, "drop-ld-preload")) {
|
} else if (!strcmp(r, "drop-ld-preload")) {
|
||||||
(void) envlist_unsetenv(envlist, "LD_PRELOAD");
|
(void) envlist_unsetenv(envlist, "LD_PRELOAD");
|
||||||
} else if (!strcmp(r, "singlestep")) {
|
} else if (!strcmp(r, "singlestep")) {
|
||||||
|
@ -2572,6 +2585,35 @@ int main(int argc, char **argv, char **envp)
|
||||||
target_environ = envlist_to_environ(envlist, NULL);
|
target_environ = envlist_to_environ(envlist, NULL);
|
||||||
envlist_free(envlist);
|
envlist_free(envlist);
|
||||||
|
|
||||||
|
#if defined(CONFIG_USE_GUEST_BASE)
|
||||||
|
/*
|
||||||
|
* Now that page sizes are configured in cpu_init() we can do
|
||||||
|
* proper page alignment for guest_base.
|
||||||
|
*/
|
||||||
|
guest_base = HOST_PAGE_ALIGN(guest_base);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Read in mmap_min_addr kernel parameter. This value is used
|
||||||
|
* When loading the ELF image to determine whether guest_base
|
||||||
|
* is needed.
|
||||||
|
*
|
||||||
|
* When user has explicitly set the quest base, we skip this
|
||||||
|
* test.
|
||||||
|
*/
|
||||||
|
if (!have_guest_base) {
|
||||||
|
FILE *fp;
|
||||||
|
|
||||||
|
if ((fp = fopen("/proc/sys/vm/mmap_min_addr", "r")) != NULL) {
|
||||||
|
unsigned long tmp;
|
||||||
|
if (fscanf(fp, "%lu", &tmp) == 1) {
|
||||||
|
mmap_min_addr = tmp;
|
||||||
|
qemu_log("host mmap_min_addr=0x%lx\n", mmap_min_addr);
|
||||||
|
}
|
||||||
|
fclose(fp);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#endif /* CONFIG_USE_GUEST_BASE */
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Prepare copy of argv vector for target.
|
* Prepare copy of argv vector for target.
|
||||||
*/
|
*/
|
||||||
|
@ -2622,6 +2664,9 @@ int main(int argc, char **argv, char **envp)
|
||||||
free(target_environ);
|
free(target_environ);
|
||||||
|
|
||||||
if (qemu_log_enabled()) {
|
if (qemu_log_enabled()) {
|
||||||
|
#if defined(CONFIG_USE_GUEST_BASE)
|
||||||
|
qemu_log("guest_base 0x%lx\n", guest_base);
|
||||||
|
#endif
|
||||||
log_page_dump();
|
log_page_dump();
|
||||||
|
|
||||||
qemu_log("start_brk 0x" TARGET_ABI_FMT_lx "\n", info->start_brk);
|
qemu_log("start_brk 0x" TARGET_ABI_FMT_lx "\n", info->start_brk);
|
||||||
|
|
|
@ -133,6 +133,9 @@ void init_task_state(TaskState *ts);
|
||||||
void task_settid(TaskState *);
|
void task_settid(TaskState *);
|
||||||
void stop_all_tasks(void);
|
void stop_all_tasks(void);
|
||||||
extern const char *qemu_uname_release;
|
extern const char *qemu_uname_release;
|
||||||
|
#if defined(CONFIG_USE_GUEST_BASE)
|
||||||
|
extern unsigned long mmap_min_addr;
|
||||||
|
#endif
|
||||||
|
|
||||||
/* ??? See if we can avoid exposing so much of the loader internals. */
|
/* ??? See if we can avoid exposing so much of the loader internals. */
|
||||||
/*
|
/*
|
||||||
|
|
|
@ -2026,7 +2026,7 @@ qemu-i386 /usr/local/qemu-i386/wine/bin/wine \
|
||||||
@subsection Command line options
|
@subsection Command line options
|
||||||
|
|
||||||
@example
|
@example
|
||||||
usage: qemu-i386 [-h] [-d] [-L path] [-s size] [-cpu model] [-g port] program [arguments...]
|
usage: qemu-i386 [-h] [-d] [-L path] [-s size] [-cpu model] [-g port] [-B offset] program [arguments...]
|
||||||
@end example
|
@end example
|
||||||
|
|
||||||
@table @option
|
@table @option
|
||||||
|
@ -2038,6 +2038,10 @@ Set the x86 elf interpreter prefix (default=/usr/local/qemu-i386)
|
||||||
Set the x86 stack size in bytes (default=524288)
|
Set the x86 stack size in bytes (default=524288)
|
||||||
@item -cpu model
|
@item -cpu model
|
||||||
Select CPU model (-cpu ? for list and additional feature selection)
|
Select CPU model (-cpu ? for list and additional feature selection)
|
||||||
|
@item -B offset
|
||||||
|
Offset guest address by the specified number of bytes. This is useful when
|
||||||
|
the address region rewuired by guest applications is reserved on the host.
|
||||||
|
Ths option is currently only supported on some hosts.
|
||||||
@end table
|
@end table
|
||||||
|
|
||||||
Debug options:
|
Debug options:
|
||||||
|
|
|
@ -990,7 +990,22 @@ static inline void tcg_out_qemu_ld(TCGContext *s, int cond,
|
||||||
# endif
|
# endif
|
||||||
|
|
||||||
*label_ptr += ((void *) s->code_ptr - (void *) label_ptr - 8) >> 2;
|
*label_ptr += ((void *) s->code_ptr - (void *) label_ptr - 8) >> 2;
|
||||||
#else
|
#else /* !CONFIG_SOFTMMU */
|
||||||
|
if (GUEST_BASE) {
|
||||||
|
uint32_t offset = GUEST_BASE;
|
||||||
|
int i;
|
||||||
|
int rot;
|
||||||
|
|
||||||
|
while (offset) {
|
||||||
|
i = ctz32(offset) & ~1;
|
||||||
|
rot = ((32 - i) << 7) & 0xf00;
|
||||||
|
|
||||||
|
tcg_out_dat_imm(s, COND_AL, ARITH_ADD, 8, addr_reg,
|
||||||
|
((offset >> i) & 0xff) | rot);
|
||||||
|
addr_reg = 8;
|
||||||
|
offset &= ~(0xff << i);
|
||||||
|
}
|
||||||
|
}
|
||||||
switch (opc) {
|
switch (opc) {
|
||||||
case 0:
|
case 0:
|
||||||
tcg_out_ld8_12(s, COND_AL, data_reg, addr_reg, 0);
|
tcg_out_ld8_12(s, COND_AL, data_reg, addr_reg, 0);
|
||||||
|
@ -1200,7 +1215,22 @@ static inline void tcg_out_qemu_st(TCGContext *s, int cond,
|
||||||
# endif
|
# endif
|
||||||
|
|
||||||
*label_ptr += ((void *) s->code_ptr - (void *) label_ptr - 8) >> 2;
|
*label_ptr += ((void *) s->code_ptr - (void *) label_ptr - 8) >> 2;
|
||||||
#else
|
#else /* !CONFIG_SOFTMMU */
|
||||||
|
if (GUEST_BASE) {
|
||||||
|
uint32_t offset = GUEST_BASE;
|
||||||
|
int i;
|
||||||
|
int rot;
|
||||||
|
|
||||||
|
while (offset) {
|
||||||
|
i = ctz32(offset) & ~1;
|
||||||
|
rot = ((32 - i) << 7) & 0xf00;
|
||||||
|
|
||||||
|
tcg_out_dat_imm(s, COND_AL, ARITH_ADD, 8, addr_reg,
|
||||||
|
((offset >> i) & 0xff) | rot);
|
||||||
|
addr_reg = 8;
|
||||||
|
offset &= ~(0xff << i);
|
||||||
|
}
|
||||||
|
}
|
||||||
switch (opc) {
|
switch (opc) {
|
||||||
case 0:
|
case 0:
|
||||||
tcg_out_st8_12(s, COND_AL, data_reg, addr_reg, 0);
|
tcg_out_st8_12(s, COND_AL, data_reg, addr_reg, 0);
|
||||||
|
|
|
@ -60,6 +60,8 @@ enum {
|
||||||
#define TCG_TARGET_STACK_ALIGN 8
|
#define TCG_TARGET_STACK_ALIGN 8
|
||||||
#define TCG_TARGET_CALL_STACK_OFFSET 0
|
#define TCG_TARGET_CALL_STACK_OFFSET 0
|
||||||
|
|
||||||
|
#define TCG_TARGET_HAS_GUEST_BASE
|
||||||
|
|
||||||
enum {
|
enum {
|
||||||
/* Note: must be synced with dyngen-exec.h */
|
/* Note: must be synced with dyngen-exec.h */
|
||||||
TCG_AREG0 = TCG_REG_R7,
|
TCG_AREG0 = TCG_REG_R7,
|
||||||
|
|
|
@ -427,6 +427,10 @@ static void *qemu_st_helpers[4] = {
|
||||||
};
|
};
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#ifndef CONFIG_USER_ONLY
|
||||||
|
#define GUEST_BASE 0
|
||||||
|
#endif
|
||||||
|
|
||||||
/* XXX: qemu_ld and qemu_st could be modified to clobber only EDX and
|
/* XXX: qemu_ld and qemu_st could be modified to clobber only EDX and
|
||||||
EAX. It will be useful once fixed registers globals are less
|
EAX. It will be useful once fixed registers globals are less
|
||||||
common. */
|
common. */
|
||||||
|
@ -572,15 +576,15 @@ static void tcg_out_qemu_ld(TCGContext *s, const TCGArg *args,
|
||||||
switch(opc) {
|
switch(opc) {
|
||||||
case 0:
|
case 0:
|
||||||
/* movzbl */
|
/* movzbl */
|
||||||
tcg_out_modrm_offset(s, 0xb6 | P_EXT, data_reg, r0, 0);
|
tcg_out_modrm_offset(s, 0xb6 | P_EXT, data_reg, r0, GUEST_BASE);
|
||||||
break;
|
break;
|
||||||
case 0 | 4:
|
case 0 | 4:
|
||||||
/* movsbl */
|
/* movsbl */
|
||||||
tcg_out_modrm_offset(s, 0xbe | P_EXT, data_reg, r0, 0);
|
tcg_out_modrm_offset(s, 0xbe | P_EXT, data_reg, r0, GUEST_BASE);
|
||||||
break;
|
break;
|
||||||
case 1:
|
case 1:
|
||||||
/* movzwl */
|
/* movzwl */
|
||||||
tcg_out_modrm_offset(s, 0xb7 | P_EXT, data_reg, r0, 0);
|
tcg_out_modrm_offset(s, 0xb7 | P_EXT, data_reg, r0, GUEST_BASE);
|
||||||
if (bswap) {
|
if (bswap) {
|
||||||
/* rolw $8, data_reg */
|
/* rolw $8, data_reg */
|
||||||
tcg_out8(s, 0x66);
|
tcg_out8(s, 0x66);
|
||||||
|
@ -590,7 +594,7 @@ static void tcg_out_qemu_ld(TCGContext *s, const TCGArg *args,
|
||||||
break;
|
break;
|
||||||
case 1 | 4:
|
case 1 | 4:
|
||||||
/* movswl */
|
/* movswl */
|
||||||
tcg_out_modrm_offset(s, 0xbf | P_EXT, data_reg, r0, 0);
|
tcg_out_modrm_offset(s, 0xbf | P_EXT, data_reg, r0, GUEST_BASE);
|
||||||
if (bswap) {
|
if (bswap) {
|
||||||
/* rolw $8, data_reg */
|
/* rolw $8, data_reg */
|
||||||
tcg_out8(s, 0x66);
|
tcg_out8(s, 0x66);
|
||||||
|
@ -603,7 +607,7 @@ static void tcg_out_qemu_ld(TCGContext *s, const TCGArg *args,
|
||||||
break;
|
break;
|
||||||
case 2:
|
case 2:
|
||||||
/* movl (r0), data_reg */
|
/* movl (r0), data_reg */
|
||||||
tcg_out_modrm_offset(s, 0x8b, data_reg, r0, 0);
|
tcg_out_modrm_offset(s, 0x8b, data_reg, r0, GUEST_BASE);
|
||||||
if (bswap) {
|
if (bswap) {
|
||||||
/* bswap */
|
/* bswap */
|
||||||
tcg_out_opc(s, (0xc8 + data_reg) | P_EXT);
|
tcg_out_opc(s, (0xc8 + data_reg) | P_EXT);
|
||||||
|
@ -619,13 +623,13 @@ static void tcg_out_qemu_ld(TCGContext *s, const TCGArg *args,
|
||||||
r0 = r1;
|
r0 = r1;
|
||||||
}
|
}
|
||||||
if (!bswap) {
|
if (!bswap) {
|
||||||
tcg_out_modrm_offset(s, 0x8b, data_reg, r0, 0);
|
tcg_out_modrm_offset(s, 0x8b, data_reg, r0, GUEST_BASE);
|
||||||
tcg_out_modrm_offset(s, 0x8b, data_reg2, r0, 4);
|
tcg_out_modrm_offset(s, 0x8b, data_reg2, r0, GUEST+BASE + 4);
|
||||||
} else {
|
} else {
|
||||||
tcg_out_modrm_offset(s, 0x8b, data_reg, r0, 4);
|
tcg_out_modrm_offset(s, 0x8b, data_reg, r0, GUEST_BASE + 4);
|
||||||
tcg_out_opc(s, (0xc8 + data_reg) | P_EXT);
|
tcg_out_opc(s, (0xc8 + data_reg) | P_EXT);
|
||||||
|
|
||||||
tcg_out_modrm_offset(s, 0x8b, data_reg2, r0, 0);
|
tcg_out_modrm_offset(s, 0x8b, data_reg2, r0, GUEST_BASE);
|
||||||
/* bswap */
|
/* bswap */
|
||||||
tcg_out_opc(s, (0xc8 + data_reg2) | P_EXT);
|
tcg_out_opc(s, (0xc8 + data_reg2) | P_EXT);
|
||||||
}
|
}
|
||||||
|
@ -806,7 +810,7 @@ static void tcg_out_qemu_st(TCGContext *s, const TCGArg *args,
|
||||||
switch(opc) {
|
switch(opc) {
|
||||||
case 0:
|
case 0:
|
||||||
/* movb */
|
/* movb */
|
||||||
tcg_out_modrm_offset(s, 0x88, data_reg, r0, 0);
|
tcg_out_modrm_offset(s, 0x88, data_reg, r0, GUEST_BASE);
|
||||||
break;
|
break;
|
||||||
case 1:
|
case 1:
|
||||||
if (bswap) {
|
if (bswap) {
|
||||||
|
@ -818,7 +822,7 @@ static void tcg_out_qemu_st(TCGContext *s, const TCGArg *args,
|
||||||
}
|
}
|
||||||
/* movw */
|
/* movw */
|
||||||
tcg_out8(s, 0x66);
|
tcg_out8(s, 0x66);
|
||||||
tcg_out_modrm_offset(s, 0x89, data_reg, r0, 0);
|
tcg_out_modrm_offset(s, 0x89, data_reg, r0, GUEST_BASE);
|
||||||
break;
|
break;
|
||||||
case 2:
|
case 2:
|
||||||
if (bswap) {
|
if (bswap) {
|
||||||
|
@ -828,21 +832,21 @@ static void tcg_out_qemu_st(TCGContext *s, const TCGArg *args,
|
||||||
data_reg = r1;
|
data_reg = r1;
|
||||||
}
|
}
|
||||||
/* movl */
|
/* movl */
|
||||||
tcg_out_modrm_offset(s, 0x89, data_reg, r0, 0);
|
tcg_out_modrm_offset(s, 0x89, data_reg, r0, GUEST_BASE);
|
||||||
break;
|
break;
|
||||||
case 3:
|
case 3:
|
||||||
if (bswap) {
|
if (bswap) {
|
||||||
tcg_out_mov(s, r1, data_reg2);
|
tcg_out_mov(s, r1, data_reg2);
|
||||||
/* bswap data_reg */
|
/* bswap data_reg */
|
||||||
tcg_out_opc(s, (0xc8 + r1) | P_EXT);
|
tcg_out_opc(s, (0xc8 + r1) | P_EXT);
|
||||||
tcg_out_modrm_offset(s, 0x89, r1, r0, 0);
|
tcg_out_modrm_offset(s, 0x89, r1, r0, GUEST_BASE);
|
||||||
tcg_out_mov(s, r1, data_reg);
|
tcg_out_mov(s, r1, data_reg);
|
||||||
/* bswap data_reg */
|
/* bswap data_reg */
|
||||||
tcg_out_opc(s, (0xc8 + r1) | P_EXT);
|
tcg_out_opc(s, (0xc8 + r1) | P_EXT);
|
||||||
tcg_out_modrm_offset(s, 0x89, r1, r0, 4);
|
tcg_out_modrm_offset(s, 0x89, r1, r0, GUEST_BASE + 4);
|
||||||
} else {
|
} else {
|
||||||
tcg_out_modrm_offset(s, 0x89, data_reg, r0, 0);
|
tcg_out_modrm_offset(s, 0x89, data_reg, r0, GUEST_BASE);
|
||||||
tcg_out_modrm_offset(s, 0x89, data_reg2, r0, 4);
|
tcg_out_modrm_offset(s, 0x89, data_reg2, r0, GUEST_BASE + 4);
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
|
|
|
@ -53,6 +53,8 @@ enum {
|
||||||
#define TCG_TARGET_HAS_ext16s_i32
|
#define TCG_TARGET_HAS_ext16s_i32
|
||||||
#define TCG_TARGET_HAS_rot_i32
|
#define TCG_TARGET_HAS_rot_i32
|
||||||
|
|
||||||
|
#define TCG_TARGET_HAS_GUEST_BASE
|
||||||
|
|
||||||
/* Note: must be synced with dyngen-exec.h */
|
/* Note: must be synced with dyngen-exec.h */
|
||||||
#define TCG_AREG0 TCG_REG_EBP
|
#define TCG_AREG0 TCG_REG_EBP
|
||||||
#define TCG_AREG1 TCG_REG_EBX
|
#define TCG_AREG1 TCG_REG_EBX
|
||||||
|
|
|
@ -46,6 +46,7 @@
|
||||||
|
|
||||||
#include "qemu-common.h"
|
#include "qemu-common.h"
|
||||||
#include "cache-utils.h"
|
#include "cache-utils.h"
|
||||||
|
#include "host-utils.h"
|
||||||
|
|
||||||
/* Note: the long term plan is to reduce the dependancies on the QEMU
|
/* Note: the long term plan is to reduce the dependancies on the QEMU
|
||||||
CPU definitions. Currently they are used for qemu_ld/st
|
CPU definitions. Currently they are used for qemu_ld/st
|
||||||
|
@ -57,6 +58,9 @@
|
||||||
#include "tcg-op.h"
|
#include "tcg-op.h"
|
||||||
#include "elf.h"
|
#include "elf.h"
|
||||||
|
|
||||||
|
#if defined(CONFIG_USE_GUEST_BASE) && !defined(TCG_TARGET_HAS_GUEST_BASE)
|
||||||
|
#error GUEST_BASE not supported on this host.
|
||||||
|
#endif
|
||||||
|
|
||||||
static void patch_reloc(uint8_t *code_ptr, int type,
|
static void patch_reloc(uint8_t *code_ptr, int type,
|
||||||
tcg_target_long value, tcg_target_long addend);
|
tcg_target_long value, tcg_target_long addend);
|
||||||
|
|
|
@ -508,6 +508,7 @@ static void tcg_out_qemu_ld(TCGContext *s, const TCGArg *args,
|
||||||
int opc)
|
int opc)
|
||||||
{
|
{
|
||||||
int addr_reg, data_reg, r0, r1, mem_index, s_bits, bswap, rexw;
|
int addr_reg, data_reg, r0, r1, mem_index, s_bits, bswap, rexw;
|
||||||
|
int32_t offset;
|
||||||
#if defined(CONFIG_SOFTMMU)
|
#if defined(CONFIG_SOFTMMU)
|
||||||
uint8_t *label1_ptr, *label2_ptr;
|
uint8_t *label1_ptr, *label2_ptr;
|
||||||
#endif
|
#endif
|
||||||
|
@ -604,8 +605,20 @@ static void tcg_out_qemu_ld(TCGContext *s, const TCGArg *args,
|
||||||
/* add x(r1), r0 */
|
/* add x(r1), r0 */
|
||||||
tcg_out_modrm_offset(s, 0x03 | P_REXW, r0, r1, offsetof(CPUTLBEntry, addend) -
|
tcg_out_modrm_offset(s, 0x03 | P_REXW, r0, r1, offsetof(CPUTLBEntry, addend) -
|
||||||
offsetof(CPUTLBEntry, addr_read));
|
offsetof(CPUTLBEntry, addr_read));
|
||||||
|
offset = 0;
|
||||||
#else
|
#else
|
||||||
r0 = addr_reg;
|
if (GUEST_BASE == (int32_t)GUEST_BASE) {
|
||||||
|
r0 = addr_reg;
|
||||||
|
offset = GUEST_BASE;
|
||||||
|
} else {
|
||||||
|
offset = 0;
|
||||||
|
/* movq $GUEST_BASE, r0 */
|
||||||
|
tcg_out_opc(s, (0xb8 + (r0 & 7)) | P_REXW, 0, r0, 0);
|
||||||
|
tcg_out32(s, GUEST_BASE);
|
||||||
|
tcg_out32(s, GUEST_BASE >> 32);
|
||||||
|
/* addq addr_reg, r0 */
|
||||||
|
tcg_out_modrm(s, 0x01 | P_REXW, addr_reg, r0);
|
||||||
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#ifdef TARGET_WORDS_BIGENDIAN
|
#ifdef TARGET_WORDS_BIGENDIAN
|
||||||
|
@ -616,15 +629,15 @@ static void tcg_out_qemu_ld(TCGContext *s, const TCGArg *args,
|
||||||
switch(opc) {
|
switch(opc) {
|
||||||
case 0:
|
case 0:
|
||||||
/* movzbl */
|
/* movzbl */
|
||||||
tcg_out_modrm_offset(s, 0xb6 | P_EXT, data_reg, r0, 0);
|
tcg_out_modrm_offset(s, 0xb6 | P_EXT, data_reg, r0, offset);
|
||||||
break;
|
break;
|
||||||
case 0 | 4:
|
case 0 | 4:
|
||||||
/* movsbX */
|
/* movsbX */
|
||||||
tcg_out_modrm_offset(s, 0xbe | P_EXT | rexw, data_reg, r0, 0);
|
tcg_out_modrm_offset(s, 0xbe | P_EXT | rexw, data_reg, r0, offset);
|
||||||
break;
|
break;
|
||||||
case 1:
|
case 1:
|
||||||
/* movzwl */
|
/* movzwl */
|
||||||
tcg_out_modrm_offset(s, 0xb7 | P_EXT, data_reg, r0, 0);
|
tcg_out_modrm_offset(s, 0xb7 | P_EXT, data_reg, r0, offset);
|
||||||
if (bswap) {
|
if (bswap) {
|
||||||
/* rolw $8, data_reg */
|
/* rolw $8, data_reg */
|
||||||
tcg_out8(s, 0x66);
|
tcg_out8(s, 0x66);
|
||||||
|
@ -635,7 +648,7 @@ static void tcg_out_qemu_ld(TCGContext *s, const TCGArg *args,
|
||||||
case 1 | 4:
|
case 1 | 4:
|
||||||
if (bswap) {
|
if (bswap) {
|
||||||
/* movzwl */
|
/* movzwl */
|
||||||
tcg_out_modrm_offset(s, 0xb7 | P_EXT, data_reg, r0, 0);
|
tcg_out_modrm_offset(s, 0xb7 | P_EXT, data_reg, r0, offset);
|
||||||
/* rolw $8, data_reg */
|
/* rolw $8, data_reg */
|
||||||
tcg_out8(s, 0x66);
|
tcg_out8(s, 0x66);
|
||||||
tcg_out_modrm(s, 0xc1, 0, data_reg);
|
tcg_out_modrm(s, 0xc1, 0, data_reg);
|
||||||
|
@ -645,12 +658,12 @@ static void tcg_out_qemu_ld(TCGContext *s, const TCGArg *args,
|
||||||
tcg_out_modrm(s, 0xbf | P_EXT | rexw, data_reg, data_reg);
|
tcg_out_modrm(s, 0xbf | P_EXT | rexw, data_reg, data_reg);
|
||||||
} else {
|
} else {
|
||||||
/* movswX */
|
/* movswX */
|
||||||
tcg_out_modrm_offset(s, 0xbf | P_EXT | rexw, data_reg, r0, 0);
|
tcg_out_modrm_offset(s, 0xbf | P_EXT | rexw, data_reg, r0, offset);
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case 2:
|
case 2:
|
||||||
/* movl (r0), data_reg */
|
/* movl (r0), data_reg */
|
||||||
tcg_out_modrm_offset(s, 0x8b, data_reg, r0, 0);
|
tcg_out_modrm_offset(s, 0x8b, data_reg, r0, offset);
|
||||||
if (bswap) {
|
if (bswap) {
|
||||||
/* bswap */
|
/* bswap */
|
||||||
tcg_out_opc(s, (0xc8 + (data_reg & 7)) | P_EXT, 0, data_reg, 0);
|
tcg_out_opc(s, (0xc8 + (data_reg & 7)) | P_EXT, 0, data_reg, 0);
|
||||||
|
@ -659,19 +672,19 @@ static void tcg_out_qemu_ld(TCGContext *s, const TCGArg *args,
|
||||||
case 2 | 4:
|
case 2 | 4:
|
||||||
if (bswap) {
|
if (bswap) {
|
||||||
/* movl (r0), data_reg */
|
/* movl (r0), data_reg */
|
||||||
tcg_out_modrm_offset(s, 0x8b, data_reg, r0, 0);
|
tcg_out_modrm_offset(s, 0x8b, data_reg, r0, offset);
|
||||||
/* bswap */
|
/* bswap */
|
||||||
tcg_out_opc(s, (0xc8 + (data_reg & 7)) | P_EXT, 0, data_reg, 0);
|
tcg_out_opc(s, (0xc8 + (data_reg & 7)) | P_EXT, 0, data_reg, 0);
|
||||||
/* movslq */
|
/* movslq */
|
||||||
tcg_out_modrm(s, 0x63 | P_REXW, data_reg, data_reg);
|
tcg_out_modrm(s, 0x63 | P_REXW, data_reg, data_reg);
|
||||||
} else {
|
} else {
|
||||||
/* movslq */
|
/* movslq */
|
||||||
tcg_out_modrm_offset(s, 0x63 | P_REXW, data_reg, r0, 0);
|
tcg_out_modrm_offset(s, 0x63 | P_REXW, data_reg, r0, offset);
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case 3:
|
case 3:
|
||||||
/* movq (r0), data_reg */
|
/* movq (r0), data_reg */
|
||||||
tcg_out_modrm_offset(s, 0x8b | P_REXW, data_reg, r0, 0);
|
tcg_out_modrm_offset(s, 0x8b | P_REXW, data_reg, r0, offset);
|
||||||
if (bswap) {
|
if (bswap) {
|
||||||
/* bswap */
|
/* bswap */
|
||||||
tcg_out_opc(s, (0xc8 + (data_reg & 7)) | P_EXT | P_REXW, 0, data_reg, 0);
|
tcg_out_opc(s, (0xc8 + (data_reg & 7)) | P_EXT | P_REXW, 0, data_reg, 0);
|
||||||
|
@ -691,6 +704,7 @@ static void tcg_out_qemu_st(TCGContext *s, const TCGArg *args,
|
||||||
int opc)
|
int opc)
|
||||||
{
|
{
|
||||||
int addr_reg, data_reg, r0, r1, mem_index, s_bits, bswap, rexw;
|
int addr_reg, data_reg, r0, r1, mem_index, s_bits, bswap, rexw;
|
||||||
|
int32_t offset;
|
||||||
#if defined(CONFIG_SOFTMMU)
|
#if defined(CONFIG_SOFTMMU)
|
||||||
uint8_t *label1_ptr, *label2_ptr;
|
uint8_t *label1_ptr, *label2_ptr;
|
||||||
#endif
|
#endif
|
||||||
|
@ -775,8 +789,20 @@ static void tcg_out_qemu_st(TCGContext *s, const TCGArg *args,
|
||||||
/* add x(r1), r0 */
|
/* add x(r1), r0 */
|
||||||
tcg_out_modrm_offset(s, 0x03 | P_REXW, r0, r1, offsetof(CPUTLBEntry, addend) -
|
tcg_out_modrm_offset(s, 0x03 | P_REXW, r0, r1, offsetof(CPUTLBEntry, addend) -
|
||||||
offsetof(CPUTLBEntry, addr_write));
|
offsetof(CPUTLBEntry, addr_write));
|
||||||
|
offset = 0;
|
||||||
#else
|
#else
|
||||||
r0 = addr_reg;
|
if (GUEST_BASE == (int32_t)GUEST_BASE) {
|
||||||
|
r0 = addr_reg;
|
||||||
|
offset = GUEST_BASE;
|
||||||
|
} else {
|
||||||
|
offset = 0;
|
||||||
|
/* movq $GUEST_BASE, r0 */
|
||||||
|
tcg_out_opc(s, (0xb8 + (r0 & 7)) | P_REXW, 0, r0, 0);
|
||||||
|
tcg_out32(s, GUEST_BASE);
|
||||||
|
tcg_out32(s, GUEST_BASE >> 32);
|
||||||
|
/* addq addr_reg, r0 */
|
||||||
|
tcg_out_modrm(s, 0x01 | P_REXW, addr_reg, r0);
|
||||||
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#ifdef TARGET_WORDS_BIGENDIAN
|
#ifdef TARGET_WORDS_BIGENDIAN
|
||||||
|
@ -787,7 +813,7 @@ static void tcg_out_qemu_st(TCGContext *s, const TCGArg *args,
|
||||||
switch(opc) {
|
switch(opc) {
|
||||||
case 0:
|
case 0:
|
||||||
/* movb */
|
/* movb */
|
||||||
tcg_out_modrm_offset(s, 0x88 | P_REXB, data_reg, r0, 0);
|
tcg_out_modrm_offset(s, 0x88 | P_REXB, data_reg, r0, offset);
|
||||||
break;
|
break;
|
||||||
case 1:
|
case 1:
|
||||||
if (bswap) {
|
if (bswap) {
|
||||||
|
@ -799,7 +825,7 @@ static void tcg_out_qemu_st(TCGContext *s, const TCGArg *args,
|
||||||
}
|
}
|
||||||
/* movw */
|
/* movw */
|
||||||
tcg_out8(s, 0x66);
|
tcg_out8(s, 0x66);
|
||||||
tcg_out_modrm_offset(s, 0x89, data_reg, r0, 0);
|
tcg_out_modrm_offset(s, 0x89, data_reg, r0, offset);
|
||||||
break;
|
break;
|
||||||
case 2:
|
case 2:
|
||||||
if (bswap) {
|
if (bswap) {
|
||||||
|
@ -809,7 +835,7 @@ static void tcg_out_qemu_st(TCGContext *s, const TCGArg *args,
|
||||||
data_reg = r1;
|
data_reg = r1;
|
||||||
}
|
}
|
||||||
/* movl */
|
/* movl */
|
||||||
tcg_out_modrm_offset(s, 0x89, data_reg, r0, 0);
|
tcg_out_modrm_offset(s, 0x89, data_reg, r0, offset);
|
||||||
break;
|
break;
|
||||||
case 3:
|
case 3:
|
||||||
if (bswap) {
|
if (bswap) {
|
||||||
|
@ -819,7 +845,7 @@ static void tcg_out_qemu_st(TCGContext *s, const TCGArg *args,
|
||||||
data_reg = r1;
|
data_reg = r1;
|
||||||
}
|
}
|
||||||
/* movq */
|
/* movq */
|
||||||
tcg_out_modrm_offset(s, 0x89 | P_REXW, data_reg, r0, 0);
|
tcg_out_modrm_offset(s, 0x89 | P_REXW, data_reg, r0, offset);
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
tcg_abort();
|
tcg_abort();
|
||||||
|
|
|
@ -73,6 +73,8 @@ enum {
|
||||||
#define TCG_TARGET_HAS_rot_i32
|
#define TCG_TARGET_HAS_rot_i32
|
||||||
#define TCG_TARGET_HAS_rot_i64
|
#define TCG_TARGET_HAS_rot_i64
|
||||||
|
|
||||||
|
#define TCG_TARGET_HAS_GUEST_BASE
|
||||||
|
|
||||||
/* Note: must be synced with dyngen-exec.h */
|
/* Note: must be synced with dyngen-exec.h */
|
||||||
#define TCG_AREG0 TCG_REG_R14
|
#define TCG_AREG0 TCG_REG_R14
|
||||||
#define TCG_AREG1 TCG_REG_R15
|
#define TCG_AREG1 TCG_REG_R15
|
||||||
|
|
Loading…
Reference in New Issue