Commit 379f6698d73f476de38682b3ff96ecb226728c43
1 parent
a9ff9df1
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>
Showing
13 changed files
with
206 additions
and
36 deletions
configure
| ... | ... | @@ -184,6 +184,7 @@ softmmu="yes" |
| 184 | 184 | linux_user="no" |
| 185 | 185 | darwin_user="no" |
| 186 | 186 | bsd_user="no" |
| 187 | +guest_base="" | |
| 187 | 188 | build_docs="yes" |
| 188 | 189 | uname_release="" |
| 189 | 190 | curses="yes" |
| ... | ... | @@ -465,6 +466,10 @@ for opt do |
| 465 | 466 | ;; |
| 466 | 467 | --enable-bsd-user) bsd_user="yes" |
| 467 | 468 | ;; |
| 469 | + --enable-guest-base) guest_base="yes" | |
| 470 | + ;; | |
| 471 | + --disable-guest-base) guest_base="no" | |
| 472 | + ;; | |
| 468 | 473 | --enable-uname-release=*) uname_release="$optarg" |
| 469 | 474 | ;; |
| 470 | 475 | --sparc_cpu=*) |
| ... | ... | @@ -544,6 +549,7 @@ fi |
| 544 | 549 | # If cpu ~= sparc and sparc_cpu hasn't been defined, plug in the right |
| 545 | 550 | # ARCH_CFLAGS/ARCH_LDFLAGS (assume sparc_v8plus for 32-bit and sparc_v9 for 64-bit) |
| 546 | 551 | # |
| 552 | +host_guest_base="no" | |
| 547 | 553 | case "$cpu" in |
| 548 | 554 | sparc) if test -z "$sparc_cpu" ; then |
| 549 | 555 | ARCH_CFLAGS="-m32 -mcpu=ultrasparc -D__sparc_v8plus__" |
| ... | ... | @@ -576,13 +582,20 @@ case "$cpu" in |
| 576 | 582 | i386) |
| 577 | 583 | ARCH_CFLAGS="-m32" |
| 578 | 584 | ARCH_LDFLAGS="-m32" |
| 585 | + host_guest_base="yes" | |
| 579 | 586 | ;; |
| 580 | 587 | x86_64) |
| 581 | 588 | ARCH_CFLAGS="-m64" |
| 582 | 589 | ARCH_LDFLAGS="-m64" |
| 590 | + host_guest_base="yes" | |
| 591 | + ;; | |
| 592 | + arm*) | |
| 593 | + host_guest_base="yes" | |
| 583 | 594 | ;; |
| 584 | 595 | esac |
| 585 | 596 | |
| 597 | +[ -z "$guest_base" ] && guest_base="$host_guest_base" | |
| 598 | + | |
| 586 | 599 | if test x"$show_help" = x"yes" ; then |
| 587 | 600 | cat << EOF |
| 588 | 601 | |
| ... | ... | @@ -641,6 +654,9 @@ echo " --enable-darwin-user enable all darwin usermode emulation targets" |
| 641 | 654 | echo " --disable-darwin-user disable all darwin usermode emulation targets" |
| 642 | 655 | echo " --enable-bsd-user enable all BSD usermode emulation targets" |
| 643 | 656 | echo " --disable-bsd-user disable all BSD usermode emulation targets" |
| 657 | +echo " --enable-guest-base enable GUEST_BASE support for usermode" | |
| 658 | +echo " emulation targets" | |
| 659 | +echo " --disable-guest-base disable GUEST_BASE support" | |
| 644 | 660 | echo " --fmod-lib path to FMOD library" |
| 645 | 661 | echo " --fmod-inc path to FMOD includes" |
| 646 | 662 | echo " --oss-lib path to OSS library" |
| ... | ... | @@ -1446,6 +1462,7 @@ echo "Documentation $build_docs" |
| 1446 | 1462 | [ ! -z "$uname_release" ] && \ |
| 1447 | 1463 | echo "uname -r $uname_release" |
| 1448 | 1464 | echo "NPTL support $nptl" |
| 1465 | +echo "GUEST_BASE $guest_base" | |
| 1449 | 1466 | echo "vde support $vde" |
| 1450 | 1467 | echo "AIO support $aio" |
| 1451 | 1468 | echo "IO thread $io_thread" |
| ... | ... | @@ -2070,6 +2087,9 @@ fi |
| 2070 | 2087 | if test "$target_user_only" = "yes" -a "$elfload32" = "yes"; then |
| 2071 | 2088 | echo "TARGET_HAS_ELFLOAD32=y" >> $config_mak |
| 2072 | 2089 | fi |
| 2090 | +if test "$target_user_only" = "yes" -a "$guest_base" = "yes"; then | |
| 2091 | + echo "CONFIG_USE_GUEST_BASE=y" >> $config_mak | |
| 2092 | +fi | |
| 2073 | 2093 | if test "$target_bsd_user" = "yes" ; then |
| 2074 | 2094 | echo "CONFIG_BSD_USER=y" >> $config_mak |
| 2075 | 2095 | fi | ... | ... |
cpu-all.h
| ... | ... | @@ -624,8 +624,13 @@ static inline void stfq_be_p(void *ptr, float64 v) |
| 624 | 624 | /* On some host systems the guest address space is reserved on the host. |
| 625 | 625 | * This allows the guest address space to be offset to a convenient location. |
| 626 | 626 | */ |
| 627 | -//#define GUEST_BASE 0x20000000 | |
| 628 | -#define GUEST_BASE 0 | |
| 627 | +#if defined(CONFIG_USE_GUEST_BASE) | |
| 628 | +extern unsigned long guest_base; | |
| 629 | +extern int have_guest_base; | |
| 630 | +#define GUEST_BASE guest_base | |
| 631 | +#else | |
| 632 | +#define GUEST_BASE 0ul | |
| 633 | +#endif | |
| 629 | 634 | |
| 630 | 635 | /* All direct uses of g2h and h2g need to go away for usermode softmmu. */ |
| 631 | 636 | #define g2h(x) ((void *)((unsigned long)(x) + GUEST_BASE)) | ... | ... |
linux-user/elfload.c
| ... | ... | @@ -1545,6 +1545,29 @@ int load_elf_binary(struct linux_binprm * bprm, struct target_pt_regs * regs, |
| 1545 | 1545 | info->mmap = 0; |
| 1546 | 1546 | elf_entry = (abi_ulong) elf_ex.e_entry; |
| 1547 | 1547 | |
| 1548 | +#if defined(CONFIG_USE_GUEST_BASE) | |
| 1549 | + /* | |
| 1550 | + * In case where user has not explicitly set the guest_base, we | |
| 1551 | + * probe here that should we set it automatically. | |
| 1552 | + */ | |
| 1553 | + if (!have_guest_base) { | |
| 1554 | + /* | |
| 1555 | + * Go through ELF program header table and find out whether | |
| 1556 | + * any of the segments drop below our current mmap_min_addr and | |
| 1557 | + * in that case set guest_base to corresponding address. | |
| 1558 | + */ | |
| 1559 | + for (i = 0, elf_ppnt = elf_phdata; i < elf_ex.e_phnum; | |
| 1560 | + i++, elf_ppnt++) { | |
| 1561 | + if (elf_ppnt->p_type != PT_LOAD) | |
| 1562 | + continue; | |
| 1563 | + if (HOST_PAGE_ALIGN(elf_ppnt->p_vaddr) < mmap_min_addr) { | |
| 1564 | + guest_base = HOST_PAGE_ALIGN(mmap_min_addr); | |
| 1565 | + break; | |
| 1566 | + } | |
| 1567 | + } | |
| 1568 | + } | |
| 1569 | +#endif /* CONFIG_USE_GUEST_BASE */ | |
| 1570 | + | |
| 1548 | 1571 | /* Do this so that we can load the interpreter, if need be. We will |
| 1549 | 1572 | change some of these later */ |
| 1550 | 1573 | info->rss = 0; | ... | ... |
linux-user/main.c
| ... | ... | @@ -39,6 +39,11 @@ |
| 39 | 39 | char *exec_path; |
| 40 | 40 | |
| 41 | 41 | int singlestep; |
| 42 | +#if defined(CONFIG_USE_GUEST_BASE) | |
| 43 | +unsigned long mmap_min_addr; | |
| 44 | +unsigned long guest_base; | |
| 45 | +int have_guest_base; | |
| 46 | +#endif | |
| 42 | 47 | |
| 43 | 48 | static const char *interp_prefix = CONFIG_QEMU_PREFIX; |
| 44 | 49 | const char *qemu_uname_release = CONFIG_UNAME_RELEASE; |
| ... | ... | @@ -2320,6 +2325,9 @@ static void usage(void) |
| 2320 | 2325 | "-E var=value sets/modifies targets environment variable(s)\n" |
| 2321 | 2326 | "-U var unsets targets environment variable(s)\n" |
| 2322 | 2327 | "-0 argv0 forces target process argv[0] to be argv0\n" |
| 2328 | +#if defined(CONFIG_USE_GUEST_BASE) | |
| 2329 | + "-B address set guest_base address to address\n" | |
| 2330 | +#endif | |
| 2323 | 2331 | "\n" |
| 2324 | 2332 | "Debug options:\n" |
| 2325 | 2333 | "-d options activate log (logfile=%s)\n" |
| ... | ... | @@ -2495,6 +2503,11 @@ int main(int argc, char **argv, char **envp) |
| 2495 | 2503 | #endif |
| 2496 | 2504 | exit(1); |
| 2497 | 2505 | } |
| 2506 | +#if defined(CONFIG_USE_GUEST_BASE) | |
| 2507 | + } else if (!strcmp(r, "B")) { | |
| 2508 | + guest_base = strtol(argv[optind++], NULL, 0); | |
| 2509 | + have_guest_base = 1; | |
| 2510 | +#endif | |
| 2498 | 2511 | } else if (!strcmp(r, "drop-ld-preload")) { |
| 2499 | 2512 | (void) envlist_unsetenv(envlist, "LD_PRELOAD"); |
| 2500 | 2513 | } else if (!strcmp(r, "singlestep")) { |
| ... | ... | @@ -2572,6 +2585,35 @@ int main(int argc, char **argv, char **envp) |
| 2572 | 2585 | target_environ = envlist_to_environ(envlist, NULL); |
| 2573 | 2586 | envlist_free(envlist); |
| 2574 | 2587 | |
| 2588 | +#if defined(CONFIG_USE_GUEST_BASE) | |
| 2589 | + /* | |
| 2590 | + * Now that page sizes are configured in cpu_init() we can do | |
| 2591 | + * proper page alignment for guest_base. | |
| 2592 | + */ | |
| 2593 | + guest_base = HOST_PAGE_ALIGN(guest_base); | |
| 2594 | + | |
| 2595 | + /* | |
| 2596 | + * Read in mmap_min_addr kernel parameter. This value is used | |
| 2597 | + * When loading the ELF image to determine whether guest_base | |
| 2598 | + * is needed. | |
| 2599 | + * | |
| 2600 | + * When user has explicitly set the quest base, we skip this | |
| 2601 | + * test. | |
| 2602 | + */ | |
| 2603 | + if (!have_guest_base) { | |
| 2604 | + FILE *fp; | |
| 2605 | + | |
| 2606 | + if ((fp = fopen("/proc/sys/vm/mmap_min_addr", "r")) != NULL) { | |
| 2607 | + unsigned long tmp; | |
| 2608 | + if (fscanf(fp, "%lu", &tmp) == 1) { | |
| 2609 | + mmap_min_addr = tmp; | |
| 2610 | + qemu_log("host mmap_min_addr=0x%lx\n", mmap_min_addr); | |
| 2611 | + } | |
| 2612 | + fclose(fp); | |
| 2613 | + } | |
| 2614 | + } | |
| 2615 | +#endif /* CONFIG_USE_GUEST_BASE */ | |
| 2616 | + | |
| 2575 | 2617 | /* |
| 2576 | 2618 | * Prepare copy of argv vector for target. |
| 2577 | 2619 | */ |
| ... | ... | @@ -2622,6 +2664,9 @@ int main(int argc, char **argv, char **envp) |
| 2622 | 2664 | free(target_environ); |
| 2623 | 2665 | |
| 2624 | 2666 | if (qemu_log_enabled()) { |
| 2667 | +#if defined(CONFIG_USE_GUEST_BASE) | |
| 2668 | + qemu_log("guest_base 0x%lx\n", guest_base); | |
| 2669 | +#endif | |
| 2625 | 2670 | log_page_dump(); |
| 2626 | 2671 | |
| 2627 | 2672 | qemu_log("start_brk 0x" TARGET_ABI_FMT_lx "\n", info->start_brk); | ... | ... |
linux-user/qemu.h
| ... | ... | @@ -133,6 +133,9 @@ void init_task_state(TaskState *ts); |
| 133 | 133 | void task_settid(TaskState *); |
| 134 | 134 | void stop_all_tasks(void); |
| 135 | 135 | extern const char *qemu_uname_release; |
| 136 | +#if defined(CONFIG_USE_GUEST_BASE) | |
| 137 | +extern unsigned long mmap_min_addr; | |
| 138 | +#endif | |
| 136 | 139 | |
| 137 | 140 | /* ??? See if we can avoid exposing so much of the loader internals. */ |
| 138 | 141 | /* | ... | ... |
qemu-doc.texi
| ... | ... | @@ -2026,7 +2026,7 @@ qemu-i386 /usr/local/qemu-i386/wine/bin/wine \ |
| 2026 | 2026 | @subsection Command line options |
| 2027 | 2027 | |
| 2028 | 2028 | @example |
| 2029 | -usage: qemu-i386 [-h] [-d] [-L path] [-s size] [-cpu model] [-g port] program [arguments...] | |
| 2029 | +usage: qemu-i386 [-h] [-d] [-L path] [-s size] [-cpu model] [-g port] [-B offset] program [arguments...] | |
| 2030 | 2030 | @end example |
| 2031 | 2031 | |
| 2032 | 2032 | @table @option |
| ... | ... | @@ -2038,6 +2038,10 @@ Set the x86 elf interpreter prefix (default=/usr/local/qemu-i386) |
| 2038 | 2038 | Set the x86 stack size in bytes (default=524288) |
| 2039 | 2039 | @item -cpu model |
| 2040 | 2040 | Select CPU model (-cpu ? for list and additional feature selection) |
| 2041 | +@item -B offset | |
| 2042 | +Offset guest address by the specified number of bytes. This is useful when | |
| 2043 | +the address region rewuired by guest applications is reserved on the host. | |
| 2044 | +Ths option is currently only supported on some hosts. | |
| 2041 | 2045 | @end table |
| 2042 | 2046 | |
| 2043 | 2047 | Debug options: | ... | ... |
tcg/arm/tcg-target.c
| ... | ... | @@ -990,7 +990,22 @@ static inline void tcg_out_qemu_ld(TCGContext *s, int cond, |
| 990 | 990 | # endif |
| 991 | 991 | |
| 992 | 992 | *label_ptr += ((void *) s->code_ptr - (void *) label_ptr - 8) >> 2; |
| 993 | -#else | |
| 993 | +#else /* !CONFIG_SOFTMMU */ | |
| 994 | + if (GUEST_BASE) { | |
| 995 | + uint32_t offset = GUEST_BASE; | |
| 996 | + int i; | |
| 997 | + int rot; | |
| 998 | + | |
| 999 | + while (offset) { | |
| 1000 | + i = ctz32(offset) & ~1; | |
| 1001 | + rot = ((32 - i) << 7) & 0xf00; | |
| 1002 | + | |
| 1003 | + tcg_out_dat_imm(s, COND_AL, ARITH_ADD, 8, addr_reg, | |
| 1004 | + ((offset >> i) & 0xff) | rot); | |
| 1005 | + addr_reg = 8; | |
| 1006 | + offset &= ~(0xff << i); | |
| 1007 | + } | |
| 1008 | + } | |
| 994 | 1009 | switch (opc) { |
| 995 | 1010 | case 0: |
| 996 | 1011 | 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, |
| 1200 | 1215 | # endif |
| 1201 | 1216 | |
| 1202 | 1217 | *label_ptr += ((void *) s->code_ptr - (void *) label_ptr - 8) >> 2; |
| 1203 | -#else | |
| 1218 | +#else /* !CONFIG_SOFTMMU */ | |
| 1219 | + if (GUEST_BASE) { | |
| 1220 | + uint32_t offset = GUEST_BASE; | |
| 1221 | + int i; | |
| 1222 | + int rot; | |
| 1223 | + | |
| 1224 | + while (offset) { | |
| 1225 | + i = ctz32(offset) & ~1; | |
| 1226 | + rot = ((32 - i) << 7) & 0xf00; | |
| 1227 | + | |
| 1228 | + tcg_out_dat_imm(s, COND_AL, ARITH_ADD, 8, addr_reg, | |
| 1229 | + ((offset >> i) & 0xff) | rot); | |
| 1230 | + addr_reg = 8; | |
| 1231 | + offset &= ~(0xff << i); | |
| 1232 | + } | |
| 1233 | + } | |
| 1204 | 1234 | switch (opc) { |
| 1205 | 1235 | case 0: |
| 1206 | 1236 | tcg_out_st8_12(s, COND_AL, data_reg, addr_reg, 0); | ... | ... |
tcg/arm/tcg-target.h
tcg/i386/tcg-target.c
| ... | ... | @@ -427,6 +427,10 @@ static void *qemu_st_helpers[4] = { |
| 427 | 427 | }; |
| 428 | 428 | #endif |
| 429 | 429 | |
| 430 | +#ifndef CONFIG_USER_ONLY | |
| 431 | +#define GUEST_BASE 0 | |
| 432 | +#endif | |
| 433 | + | |
| 430 | 434 | /* XXX: qemu_ld and qemu_st could be modified to clobber only EDX and |
| 431 | 435 | EAX. It will be useful once fixed registers globals are less |
| 432 | 436 | common. */ |
| ... | ... | @@ -572,15 +576,15 @@ static void tcg_out_qemu_ld(TCGContext *s, const TCGArg *args, |
| 572 | 576 | switch(opc) { |
| 573 | 577 | case 0: |
| 574 | 578 | /* movzbl */ |
| 575 | - tcg_out_modrm_offset(s, 0xb6 | P_EXT, data_reg, r0, 0); | |
| 579 | + tcg_out_modrm_offset(s, 0xb6 | P_EXT, data_reg, r0, GUEST_BASE); | |
| 576 | 580 | break; |
| 577 | 581 | case 0 | 4: |
| 578 | 582 | /* movsbl */ |
| 579 | - tcg_out_modrm_offset(s, 0xbe | P_EXT, data_reg, r0, 0); | |
| 583 | + tcg_out_modrm_offset(s, 0xbe | P_EXT, data_reg, r0, GUEST_BASE); | |
| 580 | 584 | break; |
| 581 | 585 | case 1: |
| 582 | 586 | /* movzwl */ |
| 583 | - tcg_out_modrm_offset(s, 0xb7 | P_EXT, data_reg, r0, 0); | |
| 587 | + tcg_out_modrm_offset(s, 0xb7 | P_EXT, data_reg, r0, GUEST_BASE); | |
| 584 | 588 | if (bswap) { |
| 585 | 589 | /* rolw $8, data_reg */ |
| 586 | 590 | tcg_out8(s, 0x66); |
| ... | ... | @@ -590,7 +594,7 @@ static void tcg_out_qemu_ld(TCGContext *s, const TCGArg *args, |
| 590 | 594 | break; |
| 591 | 595 | case 1 | 4: |
| 592 | 596 | /* movswl */ |
| 593 | - tcg_out_modrm_offset(s, 0xbf | P_EXT, data_reg, r0, 0); | |
| 597 | + tcg_out_modrm_offset(s, 0xbf | P_EXT, data_reg, r0, GUEST_BASE); | |
| 594 | 598 | if (bswap) { |
| 595 | 599 | /* rolw $8, data_reg */ |
| 596 | 600 | tcg_out8(s, 0x66); |
| ... | ... | @@ -603,7 +607,7 @@ static void tcg_out_qemu_ld(TCGContext *s, const TCGArg *args, |
| 603 | 607 | break; |
| 604 | 608 | case 2: |
| 605 | 609 | /* movl (r0), data_reg */ |
| 606 | - tcg_out_modrm_offset(s, 0x8b, data_reg, r0, 0); | |
| 610 | + tcg_out_modrm_offset(s, 0x8b, data_reg, r0, GUEST_BASE); | |
| 607 | 611 | if (bswap) { |
| 608 | 612 | /* bswap */ |
| 609 | 613 | tcg_out_opc(s, (0xc8 + data_reg) | P_EXT); |
| ... | ... | @@ -619,13 +623,13 @@ static void tcg_out_qemu_ld(TCGContext *s, const TCGArg *args, |
| 619 | 623 | r0 = r1; |
| 620 | 624 | } |
| 621 | 625 | if (!bswap) { |
| 622 | - tcg_out_modrm_offset(s, 0x8b, data_reg, r0, 0); | |
| 623 | - tcg_out_modrm_offset(s, 0x8b, data_reg2, r0, 4); | |
| 626 | + tcg_out_modrm_offset(s, 0x8b, data_reg, r0, GUEST_BASE); | |
| 627 | + tcg_out_modrm_offset(s, 0x8b, data_reg2, r0, GUEST+BASE + 4); | |
| 624 | 628 | } else { |
| 625 | - tcg_out_modrm_offset(s, 0x8b, data_reg, r0, 4); | |
| 629 | + tcg_out_modrm_offset(s, 0x8b, data_reg, r0, GUEST_BASE + 4); | |
| 626 | 630 | tcg_out_opc(s, (0xc8 + data_reg) | P_EXT); |
| 627 | 631 | |
| 628 | - tcg_out_modrm_offset(s, 0x8b, data_reg2, r0, 0); | |
| 632 | + tcg_out_modrm_offset(s, 0x8b, data_reg2, r0, GUEST_BASE); | |
| 629 | 633 | /* bswap */ |
| 630 | 634 | tcg_out_opc(s, (0xc8 + data_reg2) | P_EXT); |
| 631 | 635 | } |
| ... | ... | @@ -806,7 +810,7 @@ static void tcg_out_qemu_st(TCGContext *s, const TCGArg *args, |
| 806 | 810 | switch(opc) { |
| 807 | 811 | case 0: |
| 808 | 812 | /* movb */ |
| 809 | - tcg_out_modrm_offset(s, 0x88, data_reg, r0, 0); | |
| 813 | + tcg_out_modrm_offset(s, 0x88, data_reg, r0, GUEST_BASE); | |
| 810 | 814 | break; |
| 811 | 815 | case 1: |
| 812 | 816 | if (bswap) { |
| ... | ... | @@ -818,7 +822,7 @@ static void tcg_out_qemu_st(TCGContext *s, const TCGArg *args, |
| 818 | 822 | } |
| 819 | 823 | /* movw */ |
| 820 | 824 | tcg_out8(s, 0x66); |
| 821 | - tcg_out_modrm_offset(s, 0x89, data_reg, r0, 0); | |
| 825 | + tcg_out_modrm_offset(s, 0x89, data_reg, r0, GUEST_BASE); | |
| 822 | 826 | break; |
| 823 | 827 | case 2: |
| 824 | 828 | if (bswap) { |
| ... | ... | @@ -828,21 +832,21 @@ static void tcg_out_qemu_st(TCGContext *s, const TCGArg *args, |
| 828 | 832 | data_reg = r1; |
| 829 | 833 | } |
| 830 | 834 | /* movl */ |
| 831 | - tcg_out_modrm_offset(s, 0x89, data_reg, r0, 0); | |
| 835 | + tcg_out_modrm_offset(s, 0x89, data_reg, r0, GUEST_BASE); | |
| 832 | 836 | break; |
| 833 | 837 | case 3: |
| 834 | 838 | if (bswap) { |
| 835 | 839 | tcg_out_mov(s, r1, data_reg2); |
| 836 | 840 | /* bswap data_reg */ |
| 837 | 841 | tcg_out_opc(s, (0xc8 + r1) | P_EXT); |
| 838 | - tcg_out_modrm_offset(s, 0x89, r1, r0, 0); | |
| 842 | + tcg_out_modrm_offset(s, 0x89, r1, r0, GUEST_BASE); | |
| 839 | 843 | tcg_out_mov(s, r1, data_reg); |
| 840 | 844 | /* bswap data_reg */ |
| 841 | 845 | tcg_out_opc(s, (0xc8 + r1) | P_EXT); |
| 842 | - tcg_out_modrm_offset(s, 0x89, r1, r0, 4); | |
| 846 | + tcg_out_modrm_offset(s, 0x89, r1, r0, GUEST_BASE + 4); | |
| 843 | 847 | } else { |
| 844 | - tcg_out_modrm_offset(s, 0x89, data_reg, r0, 0); | |
| 845 | - tcg_out_modrm_offset(s, 0x89, data_reg2, r0, 4); | |
| 848 | + tcg_out_modrm_offset(s, 0x89, data_reg, r0, GUEST_BASE); | |
| 849 | + tcg_out_modrm_offset(s, 0x89, data_reg2, r0, GUEST_BASE + 4); | |
| 846 | 850 | } |
| 847 | 851 | break; |
| 848 | 852 | default: | ... | ... |
tcg/i386/tcg-target.h
tcg/tcg.c
| ... | ... | @@ -46,6 +46,7 @@ |
| 46 | 46 | |
| 47 | 47 | #include "qemu-common.h" |
| 48 | 48 | #include "cache-utils.h" |
| 49 | +#include "host-utils.h" | |
| 49 | 50 | |
| 50 | 51 | /* Note: the long term plan is to reduce the dependancies on the QEMU |
| 51 | 52 | CPU definitions. Currently they are used for qemu_ld/st |
| ... | ... | @@ -57,6 +58,9 @@ |
| 57 | 58 | #include "tcg-op.h" |
| 58 | 59 | #include "elf.h" |
| 59 | 60 | |
| 61 | +#if defined(CONFIG_USE_GUEST_BASE) && !defined(TCG_TARGET_HAS_GUEST_BASE) | |
| 62 | +#error GUEST_BASE not supported on this host. | |
| 63 | +#endif | |
| 60 | 64 | |
| 61 | 65 | static void patch_reloc(uint8_t *code_ptr, int type, |
| 62 | 66 | tcg_target_long value, tcg_target_long addend); | ... | ... |
tcg/x86_64/tcg-target.c
| ... | ... | @@ -508,6 +508,7 @@ static void tcg_out_qemu_ld(TCGContext *s, const TCGArg *args, |
| 508 | 508 | int opc) |
| 509 | 509 | { |
| 510 | 510 | int addr_reg, data_reg, r0, r1, mem_index, s_bits, bswap, rexw; |
| 511 | + int32_t offset; | |
| 511 | 512 | #if defined(CONFIG_SOFTMMU) |
| 512 | 513 | uint8_t *label1_ptr, *label2_ptr; |
| 513 | 514 | #endif |
| ... | ... | @@ -604,8 +605,20 @@ static void tcg_out_qemu_ld(TCGContext *s, const TCGArg *args, |
| 604 | 605 | /* add x(r1), r0 */ |
| 605 | 606 | tcg_out_modrm_offset(s, 0x03 | P_REXW, r0, r1, offsetof(CPUTLBEntry, addend) - |
| 606 | 607 | offsetof(CPUTLBEntry, addr_read)); |
| 608 | + offset = 0; | |
| 607 | 609 | #else |
| 608 | - r0 = addr_reg; | |
| 610 | + if (GUEST_BASE == (int32_t)GUEST_BASE) { | |
| 611 | + r0 = addr_reg; | |
| 612 | + offset = GUEST_BASE; | |
| 613 | + } else { | |
| 614 | + offset = 0; | |
| 615 | + /* movq $GUEST_BASE, r0 */ | |
| 616 | + tcg_out_opc(s, (0xb8 + (r0 & 7)) | P_REXW, 0, r0, 0); | |
| 617 | + tcg_out32(s, GUEST_BASE); | |
| 618 | + tcg_out32(s, GUEST_BASE >> 32); | |
| 619 | + /* addq addr_reg, r0 */ | |
| 620 | + tcg_out_modrm(s, 0x01 | P_REXW, addr_reg, r0); | |
| 621 | + } | |
| 609 | 622 | #endif |
| 610 | 623 | |
| 611 | 624 | #ifdef TARGET_WORDS_BIGENDIAN |
| ... | ... | @@ -616,15 +629,15 @@ static void tcg_out_qemu_ld(TCGContext *s, const TCGArg *args, |
| 616 | 629 | switch(opc) { |
| 617 | 630 | case 0: |
| 618 | 631 | /* movzbl */ |
| 619 | - tcg_out_modrm_offset(s, 0xb6 | P_EXT, data_reg, r0, 0); | |
| 632 | + tcg_out_modrm_offset(s, 0xb6 | P_EXT, data_reg, r0, offset); | |
| 620 | 633 | break; |
| 621 | 634 | case 0 | 4: |
| 622 | 635 | /* movsbX */ |
| 623 | - tcg_out_modrm_offset(s, 0xbe | P_EXT | rexw, data_reg, r0, 0); | |
| 636 | + tcg_out_modrm_offset(s, 0xbe | P_EXT | rexw, data_reg, r0, offset); | |
| 624 | 637 | break; |
| 625 | 638 | case 1: |
| 626 | 639 | /* movzwl */ |
| 627 | - tcg_out_modrm_offset(s, 0xb7 | P_EXT, data_reg, r0, 0); | |
| 640 | + tcg_out_modrm_offset(s, 0xb7 | P_EXT, data_reg, r0, offset); | |
| 628 | 641 | if (bswap) { |
| 629 | 642 | /* rolw $8, data_reg */ |
| 630 | 643 | tcg_out8(s, 0x66); |
| ... | ... | @@ -635,7 +648,7 @@ static void tcg_out_qemu_ld(TCGContext *s, const TCGArg *args, |
| 635 | 648 | case 1 | 4: |
| 636 | 649 | if (bswap) { |
| 637 | 650 | /* movzwl */ |
| 638 | - tcg_out_modrm_offset(s, 0xb7 | P_EXT, data_reg, r0, 0); | |
| 651 | + tcg_out_modrm_offset(s, 0xb7 | P_EXT, data_reg, r0, offset); | |
| 639 | 652 | /* rolw $8, data_reg */ |
| 640 | 653 | tcg_out8(s, 0x66); |
| 641 | 654 | tcg_out_modrm(s, 0xc1, 0, data_reg); |
| ... | ... | @@ -645,12 +658,12 @@ static void tcg_out_qemu_ld(TCGContext *s, const TCGArg *args, |
| 645 | 658 | tcg_out_modrm(s, 0xbf | P_EXT | rexw, data_reg, data_reg); |
| 646 | 659 | } else { |
| 647 | 660 | /* movswX */ |
| 648 | - tcg_out_modrm_offset(s, 0xbf | P_EXT | rexw, data_reg, r0, 0); | |
| 661 | + tcg_out_modrm_offset(s, 0xbf | P_EXT | rexw, data_reg, r0, offset); | |
| 649 | 662 | } |
| 650 | 663 | break; |
| 651 | 664 | case 2: |
| 652 | 665 | /* movl (r0), data_reg */ |
| 653 | - tcg_out_modrm_offset(s, 0x8b, data_reg, r0, 0); | |
| 666 | + tcg_out_modrm_offset(s, 0x8b, data_reg, r0, offset); | |
| 654 | 667 | if (bswap) { |
| 655 | 668 | /* bswap */ |
| 656 | 669 | 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, |
| 659 | 672 | case 2 | 4: |
| 660 | 673 | if (bswap) { |
| 661 | 674 | /* movl (r0), data_reg */ |
| 662 | - tcg_out_modrm_offset(s, 0x8b, data_reg, r0, 0); | |
| 675 | + tcg_out_modrm_offset(s, 0x8b, data_reg, r0, offset); | |
| 663 | 676 | /* bswap */ |
| 664 | 677 | tcg_out_opc(s, (0xc8 + (data_reg & 7)) | P_EXT, 0, data_reg, 0); |
| 665 | 678 | /* movslq */ |
| 666 | 679 | tcg_out_modrm(s, 0x63 | P_REXW, data_reg, data_reg); |
| 667 | 680 | } else { |
| 668 | 681 | /* movslq */ |
| 669 | - tcg_out_modrm_offset(s, 0x63 | P_REXW, data_reg, r0, 0); | |
| 682 | + tcg_out_modrm_offset(s, 0x63 | P_REXW, data_reg, r0, offset); | |
| 670 | 683 | } |
| 671 | 684 | break; |
| 672 | 685 | case 3: |
| 673 | 686 | /* movq (r0), data_reg */ |
| 674 | - tcg_out_modrm_offset(s, 0x8b | P_REXW, data_reg, r0, 0); | |
| 687 | + tcg_out_modrm_offset(s, 0x8b | P_REXW, data_reg, r0, offset); | |
| 675 | 688 | if (bswap) { |
| 676 | 689 | /* bswap */ |
| 677 | 690 | 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, |
| 691 | 704 | int opc) |
| 692 | 705 | { |
| 693 | 706 | int addr_reg, data_reg, r0, r1, mem_index, s_bits, bswap, rexw; |
| 707 | + int32_t offset; | |
| 694 | 708 | #if defined(CONFIG_SOFTMMU) |
| 695 | 709 | uint8_t *label1_ptr, *label2_ptr; |
| 696 | 710 | #endif |
| ... | ... | @@ -775,8 +789,20 @@ static void tcg_out_qemu_st(TCGContext *s, const TCGArg *args, |
| 775 | 789 | /* add x(r1), r0 */ |
| 776 | 790 | tcg_out_modrm_offset(s, 0x03 | P_REXW, r0, r1, offsetof(CPUTLBEntry, addend) - |
| 777 | 791 | offsetof(CPUTLBEntry, addr_write)); |
| 792 | + offset = 0; | |
| 778 | 793 | #else |
| 779 | - r0 = addr_reg; | |
| 794 | + if (GUEST_BASE == (int32_t)GUEST_BASE) { | |
| 795 | + r0 = addr_reg; | |
| 796 | + offset = GUEST_BASE; | |
| 797 | + } else { | |
| 798 | + offset = 0; | |
| 799 | + /* movq $GUEST_BASE, r0 */ | |
| 800 | + tcg_out_opc(s, (0xb8 + (r0 & 7)) | P_REXW, 0, r0, 0); | |
| 801 | + tcg_out32(s, GUEST_BASE); | |
| 802 | + tcg_out32(s, GUEST_BASE >> 32); | |
| 803 | + /* addq addr_reg, r0 */ | |
| 804 | + tcg_out_modrm(s, 0x01 | P_REXW, addr_reg, r0); | |
| 805 | + } | |
| 780 | 806 | #endif |
| 781 | 807 | |
| 782 | 808 | #ifdef TARGET_WORDS_BIGENDIAN |
| ... | ... | @@ -787,7 +813,7 @@ static void tcg_out_qemu_st(TCGContext *s, const TCGArg *args, |
| 787 | 813 | switch(opc) { |
| 788 | 814 | case 0: |
| 789 | 815 | /* movb */ |
| 790 | - tcg_out_modrm_offset(s, 0x88 | P_REXB, data_reg, r0, 0); | |
| 816 | + tcg_out_modrm_offset(s, 0x88 | P_REXB, data_reg, r0, offset); | |
| 791 | 817 | break; |
| 792 | 818 | case 1: |
| 793 | 819 | if (bswap) { |
| ... | ... | @@ -799,7 +825,7 @@ static void tcg_out_qemu_st(TCGContext *s, const TCGArg *args, |
| 799 | 825 | } |
| 800 | 826 | /* movw */ |
| 801 | 827 | tcg_out8(s, 0x66); |
| 802 | - tcg_out_modrm_offset(s, 0x89, data_reg, r0, 0); | |
| 828 | + tcg_out_modrm_offset(s, 0x89, data_reg, r0, offset); | |
| 803 | 829 | break; |
| 804 | 830 | case 2: |
| 805 | 831 | if (bswap) { |
| ... | ... | @@ -809,7 +835,7 @@ static void tcg_out_qemu_st(TCGContext *s, const TCGArg *args, |
| 809 | 835 | data_reg = r1; |
| 810 | 836 | } |
| 811 | 837 | /* movl */ |
| 812 | - tcg_out_modrm_offset(s, 0x89, data_reg, r0, 0); | |
| 838 | + tcg_out_modrm_offset(s, 0x89, data_reg, r0, offset); | |
| 813 | 839 | break; |
| 814 | 840 | case 3: |
| 815 | 841 | if (bswap) { |
| ... | ... | @@ -819,7 +845,7 @@ static void tcg_out_qemu_st(TCGContext *s, const TCGArg *args, |
| 819 | 845 | data_reg = r1; |
| 820 | 846 | } |
| 821 | 847 | /* movq */ |
| 822 | - tcg_out_modrm_offset(s, 0x89 | P_REXW, data_reg, r0, 0); | |
| 848 | + tcg_out_modrm_offset(s, 0x89 | P_REXW, data_reg, r0, offset); | |
| 823 | 849 | break; |
| 824 | 850 | default: |
| 825 | 851 | tcg_abort(); | ... | ... |
tcg/x86_64/tcg-target.h