- Now GUEST_BASE is dynamic and can be set from command line.
- Qemu checks /proc/sys/vm/mmap_min_addr and sets GUEST_BASE
if needed.
- Code generation supports GUEST_BASE for i386 and x86_64 hosts.
[v3]: implemented GUEST_BASE with offset mods
Using malc's advice, instead of a mov or lea, just adjust
the offset parameter of tcg_out_modrm_offset(). - Riku
[v5]: set a GUEST_BASE_MAX instead of supporting moving
to arbitary ranges
Signed-off-by: Mika Westerberg <mika.westerberg@iki.fi>
Signed-off-by: Riku Voipio <riku.voipio@iki.fi>
darwin_user="no"
bsd_user="no"
build_docs="yes"
+guest_base="no"
uname_release=""
curses="yes"
curl="yes"
;;
--enable-bsd-user) bsd_user="yes"
;;
+ --enable-guest-base) guest_base="yes"
+ ;;
--enable-uname-release=*) uname_release="$optarg"
;;
--sparc_cpu=*)
echo " --disable-darwin-user disable all darwin usermode emulation targets"
echo " --enable-bsd-user enable 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 " --fmod-lib path to FMOD library"
echo " --fmod-inc path to FMOD includes"
echo " --oss-lib path to OSS library"
[ ! -z "$uname_release" ] && \
echo "uname -r $uname_release"
echo "NPTL support $nptl"
+echo "GUEST_BASE $guest_base"
echo "vde support $vde"
echo "AIO support $aio"
echo "IO thread $io_thread"
echo "TARGET_HAS_ELFLOAD32=yes" >> $config_mak
echo "#define TARGET_HAS_ELFLOAD32 1" >> $config_h
fi
+if test "$target_user_only" = "yes" -a "$guest_base" = "yes"; then
+ echo "#define CONFIG_USE_GUEST_BASE 1" >> $config_h
+fi
if test "$target_bsd_user" = "yes" ; then
echo "CONFIG_BSD_USER=yes" >> $config_mak
echo "#define CONFIG_BSD_USER 1" >> $config_h
/* 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.
*/
-//#define GUEST_BASE 0x20000000
+#if defined(CONFIG_USE_GUEST_BASE)
+#define GUEST_BASE_MAX 0x38000000
+extern unsigned long guest_base;
+#define GUEST_BASE guest_base
+#else
#define GUEST_BASE 0
+#endif
/* All direct uses of g2h and h2g need to go away for usermode softmmu. */
#define g2h(x) ((void *)((unsigned long)(x) + GUEST_BASE))
info->mmap = 0;
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 (guest_base == 0) {
+ /*
+ * 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);
+ qemu_log("setting guest_base=0x%lx\n", guest_base);
+ break;
+ }
+ }
+ }
+#endif /* CONFIG_USE_GUEST_BASE */
+
/* Do this so that we can load the interpreter, if need be. We will
change some of these later */
info->rss = 0;
char *exec_path;
int singlestep;
+#if defined(CONFIG_USE_GUEST_BASE)
+unsigned long mmap_min_addr = 0;
+unsigned long guest_base = 0;
+#endif
static const char *interp_prefix = CONFIG_QEMU_PREFIX;
const char *qemu_uname_release = CONFIG_UNAME_RELEASE;
"-E var=value sets/modifies targets environment variable(s)\n"
"-U var unsets targets environment variable(s)\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"
"Debug options:\n"
"-d options activate log (logfile=%s)\n"
#endif
exit(1);
}
+#if defined(CONFIG_USE_GUEST_BASE)
+ } else if (!strcmp(r, "B")) {
+ guest_base = strtol(argv[optind++], NULL, 0);
+#endif
} else if (!strcmp(r, "drop-ld-preload")) {
(void) envlist_unsetenv(envlist, "LD_PRELOAD");
} else if (!strcmp(r, "singlestep")) {
target_environ = envlist_to_environ(envlist, NULL);
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 and check
+ * whether it is set to some value > 0. This value is used
+ * later on when doing mmap(2)s to calculate where guest_base
+ * is to set, if needed.
+ *
+ * When user has explicitly set the quest base, we skip this
+ * test.
+ */
+ if (guest_base == 0) {
+ 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("kernel mmap_min_addr=%lu\n", mmap_min_addr);
+ }
+ fclose(fp);
+ }
+ }
+ if (guest_base >= GUEST_BASE_MAX) {
+ fprintf(stderr, "guest base %lu is larger than GUEST_BASE_MAX: %d \n",
+ guest_base, GUEST_BASE_MAX);
+ exit(1);
+ }
+#endif /* CONFIG_USE_GUEST_BASE */
+
/*
* Prepare copy of argv vector for target.
*/
free(target_environ);
if (qemu_log_enabled()) {
+#if defined(CONFIG_USE_GUEST_BASE)
+ if (guest_base > 0) {
+ qemu_log("guest_base is set to 0x%lx\n", guest_base);
+ qemu_log(
+ "==========================================================\n"
+ "Note that all target addresses below are given in target\n"
+ "address space which is different from host by guest_base.\n"
+ "For example: target address 0x" TARGET_ABI_FMT_lx " becomes\n"
+ "%p and so on.\n"
+ "==========================================================\n",
+ (abi_ulong)0x8000, g2h(0x8000));
+ }
+#endif
log_page_dump();
qemu_log("start_brk 0x" TARGET_ABI_FMT_lx "\n", info->start_brk);
void task_settid(TaskState *);
void stop_all_tasks(void);
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. */
/*
* THE SOFTWARE.
*/
+#ifndef CONFIG_USE_GUEST_BASE
+#define GUEST_BASE 0
+#endif
+
#ifndef NDEBUG
static const char * const tcg_target_reg_names[TCG_TARGET_NB_REGS] = {
"%eax",
switch(opc) {
case 0:
/* 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;
case 0 | 4:
/* 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;
case 1:
/* 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) {
/* rolw $8, data_reg */
tcg_out8(s, 0x66);
break;
case 1 | 4:
/* 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) {
/* rolw $8, data_reg */
tcg_out8(s, 0x66);
break;
case 2:
/* 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) {
/* bswap */
tcg_out_opc(s, (0xc8 + data_reg) | P_EXT);
r0 = r1;
}
if (!bswap) {
- tcg_out_modrm_offset(s, 0x8b, data_reg, r0, 0);
- tcg_out_modrm_offset(s, 0x8b, data_reg2, r0, 4);
+ tcg_out_modrm_offset(s, 0x8b, data_reg, r0, GUEST_BASE);
+ tcg_out_modrm_offset(s, 0x8b, data_reg2, r0, GUEST_BASE + 4);
} 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_modrm_offset(s, 0x8b, data_reg2, r0, 0);
+ tcg_out_modrm_offset(s, 0x8b, data_reg2, r0, GUEST_BASE);
/* bswap */
tcg_out_opc(s, (0xc8 + data_reg2) | P_EXT);
}
switch(opc) {
case 0:
/* movb */
- tcg_out_modrm_offset(s, 0x88, data_reg, r0, 0);
+ tcg_out_modrm_offset(s, 0x88, data_reg, r0, GUEST_BASE);
break;
case 1:
if (bswap) {
}
/* movw */
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;
case 2:
if (bswap) {
data_reg = r1;
}
/* movl */
- tcg_out_modrm_offset(s, 0x89, data_reg, r0, 0);
+ tcg_out_modrm_offset(s, 0x89, data_reg, r0, GUEST_BASE);
break;
case 3:
if (bswap) {
tcg_out_mov(s, r1, data_reg2);
/* bswap data_reg */
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);
/* bswap data_reg */
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 {
- tcg_out_modrm_offset(s, 0x89, data_reg, r0, 0);
- tcg_out_modrm_offset(s, 0x89, data_reg2, r0, 4);
+ tcg_out_modrm_offset(s, 0x89, data_reg, r0, GUEST_BASE);
+ tcg_out_modrm_offset(s, 0x89, data_reg2, r0, GUEST_BASE + 4);
}
break;
default:
* THE SOFTWARE.
*/
+#ifndef CONFIG_USE_GUEST_BASE
+#define GUEST_BASE 0
+#endif
+
#ifndef NDEBUG
static const char * const tcg_target_reg_names[TCG_TARGET_NB_REGS] = {
"%rax",
switch(opc) {
case 0:
/* 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;
case 0 | 4:
/* 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, GUEST_BASE);
break;
case 1:
/* 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) {
/* rolw $8, data_reg */
tcg_out8(s, 0x66);
case 1 | 4:
if (bswap) {
/* 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);
/* rolw $8, data_reg */
tcg_out8(s, 0x66);
tcg_out_modrm(s, 0xc1, 0, data_reg);
tcg_out_modrm(s, 0xbf | P_EXT | rexw, data_reg, data_reg);
} else {
/* 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, GUEST_BASE);
}
break;
case 2:
/* 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) {
/* bswap */
tcg_out_opc(s, (0xc8 + (data_reg & 7)) | P_EXT, 0, data_reg, 0);
case 2 | 4:
if (bswap) {
/* 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);
/* bswap */
tcg_out_opc(s, (0xc8 + (data_reg & 7)) | P_EXT, 0, data_reg, 0);
/* movslq */
tcg_out_modrm(s, 0x63 | P_REXW, data_reg, data_reg);
} else {
/* movslq */
- tcg_out_modrm_offset(s, 0x63 | P_REXW, data_reg, r0, 0);
+ tcg_out_modrm_offset(s, 0x63 | P_REXW, data_reg, r0, GUEST_BASE);
}
break;
case 3:
/* 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, GUEST_BASE);
if (bswap) {
/* bswap */
tcg_out_opc(s, (0xc8 + (data_reg & 7)) | P_EXT | P_REXW, 0, data_reg, 0);
switch(opc) {
case 0:
/* movb */
- tcg_out_modrm_offset(s, 0x88 | P_REXB, data_reg, r0, 0);
+ tcg_out_modrm_offset(s, 0x88 | P_REXB, data_reg, r0, GUEST_BASE);
break;
case 1:
if (bswap) {
}
/* movw */
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;
case 2:
if (bswap) {
data_reg = r1;
}
/* movl */
- tcg_out_modrm_offset(s, 0x89, data_reg, r0, 0);
+ tcg_out_modrm_offset(s, 0x89, data_reg, r0, GUEST_BASE);
break;
case 3:
if (bswap) {
data_reg = r1;
}
/* movq */
- tcg_out_modrm_offset(s, 0x89 | P_REXW, data_reg, r0, 0);
+ tcg_out_modrm_offset(s, 0x89 | P_REXW, data_reg, r0, GUEST_BASE);
break;
default:
tcg_abort();