From 32a2003af9cb0cb11b3992fd3248cb89752c53e9 Mon Sep 17 00:00:00 2001 From: Alex Barcelo Date: Thu, 9 Feb 2012 23:55:46 +0000 Subject: [PATCH 01/42] Bad zero comparison for sas_ss_flags on powerpc All architectures work the same way, and all check for sas_ss_flags == 0. The powerpc lines are wrong, and do the check the other way round (it's a qemu internal check, which is done wrong only for this architecture, it's more a typo than a bug). It's NOT ppc specific, it's POSIX standard (sigaltstack) and qemu internal. I have a test source that I will send in a follow-up (it's longer than I would have wished, I'm sure that a better test case can be written if needed) Signed-off-by: Alex Barcelo Signed-off-by: Alexander Graf --- linux-user/signal.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/linux-user/signal.c b/linux-user/signal.c index fca51e2b11..b1e139d6fd 100644 --- a/linux-user/signal.c +++ b/linux-user/signal.c @@ -4118,7 +4118,7 @@ static target_ulong get_sigframe(struct target_sigaction *ka, oldsp = env->gpr[1]; if ((ka->sa_flags & TARGET_SA_ONSTACK) && - (sas_ss_flags(oldsp))) { + (sas_ss_flags(oldsp) == 0)) { oldsp = (target_sigaltstack_used.ss_sp + target_sigaltstack_used.ss_size); } From d715ea961254512c6989e17edbfaf959aa7805b0 Mon Sep 17 00:00:00 2001 From: Alexander Graf Date: Tue, 21 Feb 2012 19:01:11 +0100 Subject: [PATCH 02/42] PPC: 405: Fix ppc405ep initialization When trying to run a ppc405 guest, it segfaults quite quickly, trying to access timers that weren't initialized. Initialize them properly instead. Reported-by: Andreas Faerber Signed-off-by: Alexander Graf --- hw/ppc405_uc.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/hw/ppc405_uc.c b/hw/ppc405_uc.c index 6f8342e0e7..89e5013b57 100644 --- a/hw/ppc405_uc.c +++ b/hw/ppc405_uc.c @@ -2471,6 +2471,8 @@ CPUPPCState *ppc405ep_init(MemoryRegion *address_space_mem, ppc4xx_pob_init(env); /* OBP arbitrer */ ppc4xx_opba_init(0xef600600); + /* Initialize timers */ + ppc_booke_timers_init(env, sysclk, 0); /* Universal interrupt controller */ irqs = g_malloc0(sizeof(qemu_irq) * PPCUIC_OUTPUT_NB); irqs[PPCUIC_OUTPUT_INT] = From b7c28f02a12c98a4710b5c150b0753d39454101e Mon Sep 17 00:00:00 2001 From: Stefan Weil Date: Sat, 25 Feb 2012 02:37:12 +0000 Subject: [PATCH 03/42] ppc: Add missing 'static' to spin_rw_ops MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit spin_rw_ops is only used in hw/ppce500_spin.c. Signed-off-by: Stefan Weil Acked-by: Andreas Färber Signed-off-by: Alexander Graf --- hw/ppce500_spin.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/hw/ppce500_spin.c b/hw/ppce500_spin.c index 268f5fdb9c..960b7b0c3d 100644 --- a/hw/ppce500_spin.c +++ b/hw/ppce500_spin.c @@ -182,7 +182,7 @@ static uint64_t spin_read(void *opaque, target_phys_addr_t addr, unsigned len) } } -const MemoryRegionOps spin_rw_ops = { +static const MemoryRegionOps spin_rw_ops = { .read = spin_read, .write = spin_write, .endianness = DEVICE_BIG_ENDIAN, From b5aec39672dc6084b43fa3f77764a6f549255a53 Mon Sep 17 00:00:00 2001 From: David Gibson Date: Mon, 27 Feb 2012 17:18:07 +0000 Subject: [PATCH 04/42] pseries: Don't try to munmap() a malloc()ed TCE table For the pseries machine, TCE (IOMMU) tables can either be directly malloc()ed in qemu or, when running on a KVM which supports it, mmap()ed from a KVM ioctl. The latter option is used when available, because it allows the (frequent bottlenext) H_PUT_TCE hypercall to be KVM accelerated. However, even when KVM is persent, TCE acceleration is not always possible. Only KVM HV supports this ioctl(), not KVM PR, or the kernel could run out of contiguous memory to allocate the new table. In this case we need to fall back on the malloc()ed table. When a device is removed, and we need to remove the TCE table, we need to either munmap() or free() the table as appropriate for how it was allocated. The code is supposed to do that, but we buggily fail to initialize the tcet->fd variable in the malloc() case, which is used as a flag to determine which is the right choice. This patch fixes the bug, and cleans up error messages relating to this path while we're at it. Signed-off-by: Benjamin Herrenschmidt Signed-off-by: David Gibson Signed-off-by: Alexander Graf --- target-ppc/kvm.c | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/target-ppc/kvm.c b/target-ppc/kvm.c index aeb3de9ae7..724f4c7815 100644 --- a/target-ppc/kvm.c +++ b/target-ppc/kvm.c @@ -843,12 +843,18 @@ void *kvmppc_create_spapr_tce(uint32_t liobn, uint32_t window_size, int *pfd) int fd; void *table; + /* Must set fd to -1 so we don't try to munmap when called for + * destroying the table, which the upper layers -will- do + */ + *pfd = -1; if (!cap_spapr_tce) { return NULL; } fd = kvm_vm_ioctl(kvm_state, KVM_CREATE_SPAPR_TCE, &args); if (fd < 0) { + fprintf(stderr, "KVM: Failed to create TCE table for liobn 0x%x\n", + liobn); return NULL; } @@ -857,6 +863,8 @@ void *kvmppc_create_spapr_tce(uint32_t liobn, uint32_t window_size, int *pfd) table = mmap(NULL, len, PROT_READ|PROT_WRITE, MAP_SHARED, fd, 0); if (table == MAP_FAILED) { + fprintf(stderr, "KVM: Failed to map TCE table for liobn 0x%x\n", + liobn); close(fd); return NULL; } @@ -876,8 +884,8 @@ int kvmppc_remove_spapr_tce(void *table, int fd, uint32_t window_size) len = (window_size / SPAPR_VIO_TCE_PAGE_SIZE)*sizeof(VIOsPAPR_RTCE); if ((munmap(table, len) < 0) || (close(fd) < 0)) { - fprintf(stderr, "KVM: Unexpected error removing KVM SPAPR TCE " - "table: %s", strerror(errno)); + fprintf(stderr, "KVM: Unexpected error removing TCE table: %s", + strerror(errno)); /* Leak the table */ } From cd6e9320142fea0d9e82c8ca7f3a4c2f20fecf39 Mon Sep 17 00:00:00 2001 From: Thomas Huth Date: Mon, 27 Feb 2012 17:18:08 +0000 Subject: [PATCH 05/42] PPC64: Add support for ldbrx and stdbrx instructions These instructions for loading and storing byte-swapped 64-bit values have been introduced in PowerISA 2.06. Signed-off-by: Thomas Huth Signed-off-by: David Gibson Signed-off-by: Alexander Graf --- target-ppc/cpu.h | 4 ++- target-ppc/translate.c | 52 ++++++++++++++++++++++++++++++------- target-ppc/translate_init.c | 2 +- 3 files changed, 47 insertions(+), 11 deletions(-) diff --git a/target-ppc/cpu.h b/target-ppc/cpu.h index ad09cbe06a..ca6f1cb58c 100644 --- a/target-ppc/cpu.h +++ b/target-ppc/cpu.h @@ -1918,8 +1918,10 @@ enum { PPC2_DFP = 0x0000000000000004ULL, /* Embedded.Processor Control */ PPC2_PRCNTL = 0x0000000000000008ULL, + /* Byte-reversed, indexed, double-word load and store */ + PPC2_DBRX = 0x0000000000000010ULL, -#define PPC_TCG_INSNS2 (PPC2_BOOKE206 | PPC2_PRCNTL) +#define PPC_TCG_INSNS2 (PPC2_BOOKE206 | PPC2_PRCNTL | PPC2_DBRX) }; /*****************************************************************************/ diff --git a/target-ppc/translate.c b/target-ppc/translate.c index 3ec59a7eeb..4722a09020 100644 --- a/target-ppc/translate.c +++ b/target-ppc/translate.c @@ -2650,7 +2650,7 @@ static void glue(gen_, name##ux)(DisasContext *ctx) tcg_temp_free(EA); \ } -#define GEN_LDX(name, ldop, opc2, opc3, type) \ +#define GEN_LDX_E(name, ldop, opc2, opc3, type, type2) \ static void glue(gen_, name##x)(DisasContext *ctx) \ { \ TCGv EA; \ @@ -2660,6 +2660,8 @@ static void glue(gen_, name##x)(DisasContext *ctx) \ gen_qemu_##ldop(ctx, cpu_gpr[rD(ctx->opcode)], EA); \ tcg_temp_free(EA); \ } +#define GEN_LDX(name, ldop, opc2, opc3, type) \ + GEN_LDX_E(name, ldop, opc2, opc3, type, PPC_NONE) #define GEN_LDS(name, ldop, op, type) \ GEN_LD(name, ldop, op | 0x20, type); \ @@ -2793,8 +2795,8 @@ static void glue(gen_, name##ux)(DisasContext *ctx) tcg_temp_free(EA); \ } -#define GEN_STX(name, stop, opc2, opc3, type) \ -static void glue(gen_, name##x)(DisasContext *ctx) \ +#define GEN_STX_E(name, stop, opc2, opc3, type, type2) \ +static void glue(gen_, name##x)(DisasContext *ctx) \ { \ TCGv EA; \ gen_set_access_type(ctx, ACCESS_INT); \ @@ -2803,6 +2805,8 @@ static void glue(gen_, name##x)(DisasContext *ctx) gen_qemu_##stop(ctx, cpu_gpr[rS(ctx->opcode)], EA); \ tcg_temp_free(EA); \ } +#define GEN_STX(name, stop, opc2, opc3, type) \ + GEN_STX_E(name, stop, opc2, opc3, type, PPC_NONE) #define GEN_STS(name, stop, op, type) \ GEN_ST(name, stop, op | 0x20, type); \ @@ -2891,6 +2895,18 @@ static inline void gen_qemu_ld32ur(DisasContext *ctx, TCGv arg1, TCGv arg2) } GEN_LDX(lwbr, ld32ur, 0x16, 0x10, PPC_INTEGER); +#if defined(TARGET_PPC64) +/* ldbrx */ +static inline void gen_qemu_ld64ur(DisasContext *ctx, TCGv arg1, TCGv arg2) +{ + tcg_gen_qemu_ld64(arg1, arg2, ctx->mem_idx); + if (likely(!ctx->le_mode)) { + tcg_gen_bswap64_tl(arg1, arg1); + } +} +GEN_LDX_E(ldbr, ld64ur, 0x14, 0x10, PPC_NONE, PPC2_DBRX); +#endif /* TARGET_PPC64 */ + /* sthbrx */ static inline void gen_qemu_st16r(DisasContext *ctx, TCGv arg1, TCGv arg2) { @@ -2921,6 +2937,22 @@ static inline void gen_qemu_st32r(DisasContext *ctx, TCGv arg1, TCGv arg2) } GEN_STX(stwbr, st32r, 0x16, 0x14, PPC_INTEGER); +#if defined(TARGET_PPC64) +/* stdbrx */ +static inline void gen_qemu_st64r(DisasContext *ctx, TCGv arg1, TCGv arg2) +{ + if (likely(!ctx->le_mode)) { + TCGv t0 = tcg_temp_new(); + tcg_gen_bswap64_tl(t0, arg1); + tcg_gen_qemu_st64(t0, arg2, ctx->mem_idx); + tcg_temp_free(t0); + } else { + tcg_gen_qemu_st64(arg1, arg2, ctx->mem_idx); + } +} +GEN_STX_E(stdbr, st64r, 0x14, 0x14, PPC_NONE, PPC2_DBRX); +#endif /* TARGET_PPC64 */ + /*** Integer load and store multiple ***/ /* lmw */ @@ -8818,7 +8850,7 @@ GEN_FLOAT_B(neg, 0x08, 0x01, 0, PPC_FLOAT), #undef GEN_LD #undef GEN_LDU #undef GEN_LDUX -#undef GEN_LDX +#undef GEN_LDX_E #undef GEN_LDS #define GEN_LD(name, ldop, opc, type) \ GEN_HANDLER(name, opc, 0xFF, 0xFF, 0x00000000, type), @@ -8826,8 +8858,8 @@ GEN_HANDLER(name, opc, 0xFF, 0xFF, 0x00000000, type), GEN_HANDLER(name##u, opc, 0xFF, 0xFF, 0x00000000, type), #define GEN_LDUX(name, ldop, opc2, opc3, type) \ GEN_HANDLER(name##ux, 0x1F, opc2, opc3, 0x00000001, type), -#define GEN_LDX(name, ldop, opc2, opc3, type) \ -GEN_HANDLER(name##x, 0x1F, opc2, opc3, 0x00000001, type), +#define GEN_LDX_E(name, ldop, opc2, opc3, type, type2) \ +GEN_HANDLER_E(name##x, 0x1F, opc2, opc3, 0x00000001, type, type2), #define GEN_LDS(name, ldop, op, type) \ GEN_LD(name, ldop, op | 0x20, type) \ GEN_LDU(name, ldop, op | 0x21, type) \ @@ -8843,6 +8875,7 @@ GEN_LDUX(lwa, ld32s, 0x15, 0x0B, PPC_64B) GEN_LDX(lwa, ld32s, 0x15, 0x0A, PPC_64B) GEN_LDUX(ld, ld64, 0x15, 0x01, PPC_64B) GEN_LDX(ld, ld64, 0x15, 0x00, PPC_64B) +GEN_LDX_E(ldbr, ld64ur, 0x14, 0x10, PPC_NONE, PPC2_DBRX) #endif GEN_LDX(lhbr, ld16ur, 0x16, 0x18, PPC_INTEGER) GEN_LDX(lwbr, ld32ur, 0x16, 0x10, PPC_INTEGER) @@ -8850,7 +8883,7 @@ GEN_LDX(lwbr, ld32ur, 0x16, 0x10, PPC_INTEGER) #undef GEN_ST #undef GEN_STU #undef GEN_STUX -#undef GEN_STX +#undef GEN_STX_E #undef GEN_STS #define GEN_ST(name, stop, opc, type) \ GEN_HANDLER(name, opc, 0xFF, 0xFF, 0x00000000, type), @@ -8858,8 +8891,8 @@ GEN_HANDLER(name, opc, 0xFF, 0xFF, 0x00000000, type), GEN_HANDLER(stop##u, opc, 0xFF, 0xFF, 0x00000000, type), #define GEN_STUX(name, stop, opc2, opc3, type) \ GEN_HANDLER(name##ux, 0x1F, opc2, opc3, 0x00000001, type), -#define GEN_STX(name, stop, opc2, opc3, type) \ -GEN_HANDLER(name##x, 0x1F, opc2, opc3, 0x00000001, type), +#define GEN_STX_E(name, stop, opc2, opc3, type, type2) \ +GEN_HANDLER_E(name##x, 0x1F, opc2, opc3, 0x00000001, type, type2), #define GEN_STS(name, stop, op, type) \ GEN_ST(name, stop, op | 0x20, type) \ GEN_STU(name, stop, op | 0x21, type) \ @@ -8872,6 +8905,7 @@ GEN_STS(stw, st32, 0x04, PPC_INTEGER) #if defined(TARGET_PPC64) GEN_STUX(std, st64, 0x15, 0x05, PPC_64B) GEN_STX(std, st64, 0x15, 0x04, PPC_64B) +GEN_STX_E(stdbr, st64r, 0x14, 0x14, PPC_NONE, PPC2_DBRX) #endif GEN_STX(sthbr, st16r, 0x16, 0x1C, PPC_INTEGER) GEN_STX(stwbr, st32r, 0x16, 0x14, PPC_INTEGER) diff --git a/target-ppc/translate_init.c b/target-ppc/translate_init.c index 1ec6f4248f..c707959e23 100644 --- a/target-ppc/translate_init.c +++ b/target-ppc/translate_init.c @@ -6571,7 +6571,7 @@ static void init_proc_970MP (CPUPPCState *env) PPC_64B | PPC_ALTIVEC | \ PPC_SEGMENT_64B | PPC_SLBI | \ PPC_POPCNTB | PPC_POPCNTWD) -#define POWERPC_INSNS2_POWER7 (PPC2_VSX | PPC2_DFP) +#define POWERPC_INSNS2_POWER7 (PPC2_VSX | PPC2_DFP | PPC2_DBRX) #define POWERPC_MSRM_POWER7 (0x800000000204FF36ULL) #define POWERPC_MMU_POWER7 (POWERPC_MMU_2_06) #define POWERPC_EXCP_POWER7 (POWERPC_EXCP_POWER7) From 53f649e863dd08b6ff212093556add42f456d14d Mon Sep 17 00:00:00 2001 From: David Gibson Date: Mon, 27 Feb 2012 17:18:10 +0000 Subject: [PATCH 06/42] pseries: Update SLOF firmware image This patch updates the SLOF firmware image used on the pseries machine. The new version adds support for Cirrus VGA and virtfs, as well as including a number of bugfixes. Signed-off-by: David Gibson Signed-off-by: Alexander Graf --- pc-bios/README | 2 +- pc-bios/slof.bin | Bin 869584 -> 880496 bytes roms/SLOF | 2 +- 3 files changed, 2 insertions(+), 2 deletions(-) diff --git a/pc-bios/README b/pc-bios/README index 5dce355f56..71f48711b2 100644 --- a/pc-bios/README +++ b/pc-bios/README @@ -17,7 +17,7 @@ - SLOF (Slimline Open Firmware) is a free IEEE 1275 Open Firmware implementation for certain IBM POWER hardware. The sources are at https://github.com/dgibson/SLOF, and the image currently in qemu is - built from git tag qemu-slof-20120111.1. + built from git tag qemu-slof-20120217. - sgabios (the Serial Graphics Adapter option ROM) provides a means for legacy x86 software to communicate with an attached serial console as diff --git a/pc-bios/slof.bin b/pc-bios/slof.bin index 8554f54b5773f0771eec28f6c3bc0dc17e063a47..449a7bb2afaf604f6c089612e99086df0800d7dc 100644 GIT binary patch delta 124949 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%0A7w<0SgO14Ej;ye7w088KVslO*s;57 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 diff --git a/roms/SLOF b/roms/SLOF index ab062ff3b3..d153364253 160000 --- a/roms/SLOF +++ b/roms/SLOF @@ -1 +1 @@ -Subproject commit ab062ff3b37c39649f2b0d94ed607adc6f6b3c7d +Subproject commit d153364253548d6cd91403711f84996e6a7dab31 From 323abebf9997f30fb357602e169ea6333ac20bc3 Mon Sep 17 00:00:00 2001 From: David Gibson Date: Mon, 27 Feb 2012 17:18:11 +0000 Subject: [PATCH 07/42] pseries: Remove unused constant from PCI code The 'bars' constant array was used in experimental device allocation code which is no longer necessary now that we always run the SLOF firmware. This patch removes the now redundant variable. Signed-off-by: Alexey Kardashevskiy Signed-off-by: David Gibson Signed-off-by: Alexander Graf --- hw/spapr_pci.c | 7 ------- 1 file changed, 7 deletions(-) diff --git a/hw/spapr_pci.c b/hw/spapr_pci.c index 374dcf8be7..3d5e50a1ee 100644 --- a/hw/spapr_pci.c +++ b/hw/spapr_pci.c @@ -32,13 +32,6 @@ #include "hw/pci_internals.h" -static const uint32_t bars[] = { - PCI_BASE_ADDRESS_0, PCI_BASE_ADDRESS_1, - PCI_BASE_ADDRESS_2, PCI_BASE_ADDRESS_3, - PCI_BASE_ADDRESS_4, PCI_BASE_ADDRESS_5 - /*, PCI_ROM_ADDRESS*/ -}; - static PCIDevice *find_dev(sPAPREnvironment *spapr, uint64_t buid, uint32_t config_addr) { From 76ab9583cea5c742f32743cc65abc326719bd646 Mon Sep 17 00:00:00 2001 From: Alexey Kardashevskiy Date: Mon, 27 Feb 2012 17:18:12 +0000 Subject: [PATCH 08/42] pseries: Remove PCI device from PCI host bridge code The sPAPR PCI code defines a PCI device "spapr-pci-host-bridge-pci" which is never used. This came over from the earlier bridge driver we used as a template. Some other bridges appear on their own PCI bus as a device, but that is not true of pSeries bridges, which are pure host to PCI with no visible presence on the PCI side. Signed-off-by: Alexey Kardashevskiy Signed-off-by: David Gibson Signed-off-by: Alexander Graf --- hw/spapr_pci.c | 20 -------------------- 1 file changed, 20 deletions(-) diff --git a/hw/spapr_pci.c b/hw/spapr_pci.c index 3d5e50a1ee..c06afacbb2 100644 --- a/hw/spapr_pci.c +++ b/hw/spapr_pci.c @@ -202,25 +202,6 @@ static int spapr_phb_init(SysBusDevice *s) return 0; } -static int spapr_main_pci_host_init(PCIDevice *d) -{ - return 0; -} - -static void spapr_main_pci_host_class_init(ObjectClass *klass, void *data) -{ - PCIDeviceClass *k = PCI_DEVICE_CLASS(klass); - - k->init = spapr_main_pci_host_init; -} - -static TypeInfo spapr_main_pci_host_info = { - .name = "spapr-pci-host-bridge-pci", - .parent = TYPE_PCI_DEVICE, - .instance_size = sizeof(PCIDevice), - .class_init = spapr_main_pci_host_class_init, -}; - static void spapr_phb_class_init(ObjectClass *klass, void *data) { SysBusDeviceClass *sdc = SYS_BUS_DEVICE_CLASS(klass); @@ -238,7 +219,6 @@ static TypeInfo spapr_phb_info = { static void spapr_register_types(void) { type_register_static(&spapr_phb_info); - type_register_static(&spapr_main_pci_host_info); } type_init(spapr_register_types) From 2e06214f22e080be4a8a17b0fae3b4c03b0aa3ea Mon Sep 17 00:00:00 2001 From: Nathan Whitehorn Date: Sat, 3 Mar 2012 06:36:36 +0000 Subject: [PATCH 09/42] PPC: Add PIR register to POWER7 CPU The POWER7 emulation is missing the Processor Identification Register, mandatory in recent POWER CPUs, that is required for SMP on at least some operating systems (e.g. FreeBSD) to function properly. This patch copies the existing PIR code from the other CPUs that implement it. Signed-off-by: Nathan Whitehorn Signed-off-by: Alexander Graf --- target-ppc/translate_init.c | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/target-ppc/translate_init.c b/target-ppc/translate_init.c index c707959e23..5a958b931f 100644 --- a/target-ppc/translate_init.c +++ b/target-ppc/translate_init.c @@ -6588,6 +6588,11 @@ static void init_proc_POWER7 (CPUPPCState *env) gen_spr_7xx(env); /* Time base */ gen_tbl(env); + /* Processor identification */ + spr_register(env, SPR_PIR, "PIR", + SPR_NOACCESS, SPR_NOACCESS, + &spr_read_generic, &spr_write_pir, + 0x00000000); #if !defined(CONFIG_USER_ONLY) /* PURR & SPURR: Hack - treat these as aliases for the TB for now */ spr_register(env, SPR_PURR, "PURR", From eb6ea4b22e89d4c6ed510c7cfcd33d15be92733b Mon Sep 17 00:00:00 2001 From: Nathan Whitehorn Date: Fri, 9 Mar 2012 04:30:41 +0000 Subject: [PATCH 10/42] PPC: Fix large page support in TCG Fix large page support in TCG. The old code would overwrite the large page table entry with the fake 4 KB one generated here whenever the ref/change bits were updated, causing it to point to the wrong area of memory. Signed-off-by: Nathan Whitehorn Acked-by: David Gibson [agraf: fix whitespace, braces] Signed-off-by: Alexander Graf --- target-ppc/helper.c | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/target-ppc/helper.c b/target-ppc/helper.c index bd711b6e22..39dcc273e5 100644 --- a/target-ppc/helper.c +++ b/target-ppc/helper.c @@ -591,12 +591,6 @@ static inline int _find_pte(CPUPPCState *env, mmu_ctx_t *ctx, int is_64b, int h, pte1 = ldq_phys(env->htab_base + pteg_off + (i * 16) + 8); } - /* We have a TLB that saves 4K pages, so let's - * split a huge page to 4k chunks */ - if (target_page_bits != TARGET_PAGE_BITS) - pte1 |= (ctx->eaddr & (( 1 << target_page_bits ) - 1)) - & TARGET_PAGE_MASK; - r = pte64_check(ctx, pte0, pte1, h, rw, type); LOG_MMU("Load pte from " TARGET_FMT_lx " => " TARGET_FMT_lx " " TARGET_FMT_lx " %d %d %d " TARGET_FMT_lx "\n", @@ -672,6 +666,12 @@ static inline int _find_pte(CPUPPCState *env, mmu_ctx_t *ctx, int is_64b, int h, } } + /* We have a TLB that saves 4K pages, so let's + * split a huge page to 4k chunks */ + if (target_page_bits != TARGET_PAGE_BITS) { + ctx->raddr |= (ctx->eaddr & ((1 << target_page_bits) - 1)) + & TARGET_PAGE_MASK; + } return ret; } From d07fee7e8ad9d3611404fa145270d3b885b2772a Mon Sep 17 00:00:00 2001 From: David Gibson Date: Wed, 7 Mar 2012 15:12:21 +0000 Subject: [PATCH 11/42] pseries: Add support for level interrupts to XICS The pseries "xics" interrupt controller, like most interrupt controllers can support both message (i.e. edge sensitive) interrupts and level sensitive interrupts, but it needs to know which are which. When I implemented the xics emulation for qemu, the only devices we supported were the PAPR virtual IO devices. These devices only use message interrupts, so they were the only ones I implemented in xics. Since then, however, we have added support for PCI devices, which use level sensitive interrupts. It turns out the message interrupt logic still actually works most of the time for these, but there are circumstances where we can lost interrupts due to the incorrect interrupt logic. This patch, therefore, implements the correct xics level-sensitive interrupt logic. The type of the interrupt is set when a device allocates a new xics interrupt. Signed-off-by: David Gibson Signed-off-by: Alexander Graf --- hw/spapr.c | 5 +- hw/spapr.h | 13 ++++- hw/spapr_pci.c | 2 +- hw/spapr_vio.c | 2 +- hw/xics.c | 145 +++++++++++++++++++++++++++++++++++-------------- hw/xics.h | 8 ++- 6 files changed, 127 insertions(+), 48 deletions(-) diff --git a/hw/spapr.c b/hw/spapr.c index 3719e0e4a7..bfaf260d54 100644 --- a/hw/spapr.c +++ b/hw/spapr.c @@ -83,7 +83,8 @@ sPAPREnvironment *spapr; -qemu_irq spapr_allocate_irq(uint32_t hint, uint32_t *irq_num) +qemu_irq spapr_allocate_irq(uint32_t hint, uint32_t *irq_num, + enum xics_irq_type type) { uint32_t irq; qemu_irq qirq; @@ -95,7 +96,7 @@ qemu_irq spapr_allocate_irq(uint32_t hint, uint32_t *irq_num) irq = spapr->next_irq++; } - qirq = xics_find_qirq(spapr->icp, irq); + qirq = xics_assign_irq(spapr->icp, irq, type); if (!qirq) { return NULL; } diff --git a/hw/spapr.h b/hw/spapr.h index a41641fdde..11160b02da 100644 --- a/hw/spapr.h +++ b/hw/spapr.h @@ -286,7 +286,18 @@ void spapr_register_hypercall(target_ulong opcode, spapr_hcall_fn fn); target_ulong spapr_hypercall(CPUPPCState *env, target_ulong opcode, target_ulong *args); -qemu_irq spapr_allocate_irq(uint32_t hint, uint32_t *irq_num); +qemu_irq spapr_allocate_irq(uint32_t hint, uint32_t *irq_num, + enum xics_irq_type type); + +static inline qemu_irq spapr_allocate_msi(uint32_t hint, uint32_t *irq_num) +{ + return spapr_allocate_irq(hint, irq_num, XICS_MSI); +} + +static inline qemu_irq spapr_allocate_lsi(uint32_t hint, uint32_t *irq_num) +{ + return spapr_allocate_irq(hint, irq_num, XICS_LSI); +} static inline uint32_t rtas_ld(target_ulong phys, int n) { diff --git a/hw/spapr_pci.c b/hw/spapr_pci.c index c06afacbb2..233250fac6 100644 --- a/hw/spapr_pci.c +++ b/hw/spapr_pci.c @@ -190,7 +190,7 @@ static int spapr_phb_init(SysBusDevice *s) qemu_irq qirq; uint32_t num; - qirq = spapr_allocate_irq(0, &num); + qirq = spapr_allocate_lsi(0, &num); if (!qirq) { return -1; } diff --git a/hw/spapr_vio.c b/hw/spapr_vio.c index 2fb3cee266..dbf5a9017e 100644 --- a/hw/spapr_vio.c +++ b/hw/spapr_vio.c @@ -670,7 +670,7 @@ static int spapr_vio_busdev_init(DeviceState *qdev) dev->qdev.id = id; } - dev->qirq = spapr_allocate_irq(dev->vio_irq_num, &dev->vio_irq_num); + dev->qirq = spapr_allocate_msi(dev->vio_irq_num, &dev->vio_irq_num); if (!dev->qirq) { return -1; } diff --git a/hw/xics.c b/hw/xics.c index f7963f3096..668a0d6484 100644 --- a/hw/xics.c +++ b/hw/xics.c @@ -132,9 +132,9 @@ static void icp_eoi(struct icp_state *icp, int server, uint32_t xirr) { struct icp_server_state *ss = icp->ss + server; - ics_eoi(icp->ics, xirr & XISR_MASK); /* Send EOI -> ICS */ ss->xirr = (ss->xirr & ~CPPR_MASK) | (xirr & CPPR_MASK); + ics_eoi(icp->ics, xirr & XISR_MASK); if (!XISR(ss)) { icp_resend(icp, server); } @@ -165,8 +165,9 @@ struct ics_irq_state { int server; uint8_t priority; uint8_t saved_priority; - /* int pending:1; */ - /* int presented:1; */ + enum xics_irq_type type; + int asserted:1; + int sent:1; int rejected:1; int masked_pending:1; }; @@ -185,9 +186,32 @@ static int ics_valid_irq(struct ics_state *ics, uint32_t nr) && (nr < (ics->offset + ics->nr_irqs)); } -static void ics_set_irq_msi(void *opaque, int srcno, int val) +static void resend_msi(struct ics_state *ics, int srcno) +{ + struct ics_irq_state *irq = ics->irqs + srcno; + + /* FIXME: filter by server#? */ + if (irq->rejected) { + irq->rejected = 0; + if (irq->priority != 0xff) { + icp_irq(ics->icp, irq->server, srcno + ics->offset, + irq->priority); + } + } +} + +static void resend_lsi(struct ics_state *ics, int srcno) +{ + struct ics_irq_state *irq = ics->irqs + srcno; + + if ((irq->priority != 0xff) && irq->asserted && !irq->sent) { + irq->sent = 1; + icp_irq(ics->icp, irq->server, srcno + ics->offset, irq->priority); + } +} + +static void set_irq_msi(struct ics_state *ics, int srcno, int val) { - struct ics_state *ics = (struct ics_state *)opaque; struct ics_irq_state *irq = ics->irqs + srcno; if (val) { @@ -200,14 +224,68 @@ static void ics_set_irq_msi(void *opaque, int srcno, int val) } } -static void ics_reject_msi(struct ics_state *ics, int nr) +static void set_irq_lsi(struct ics_state *ics, int srcno, int val) +{ + struct ics_irq_state *irq = ics->irqs + srcno; + + irq->asserted = val; + resend_lsi(ics, srcno); +} + +static void ics_set_irq(void *opaque, int srcno, int val) +{ + struct ics_state *ics = (struct ics_state *)opaque; + struct ics_irq_state *irq = ics->irqs + srcno; + + if (irq->type == XICS_LSI) { + set_irq_lsi(ics, srcno, val); + } else { + set_irq_msi(ics, srcno, val); + } +} + +static void write_xive_msi(struct ics_state *ics, int srcno) +{ + struct ics_irq_state *irq = ics->irqs + srcno; + + if (!irq->masked_pending || (irq->priority == 0xff)) { + return; + } + + irq->masked_pending = 0; + icp_irq(ics->icp, irq->server, srcno + ics->offset, irq->priority); +} + +static void write_xive_lsi(struct ics_state *ics, int srcno) +{ + resend_lsi(ics, srcno); +} + +static void ics_write_xive(struct ics_state *ics, int nr, int server, + uint8_t priority) +{ + int srcno = nr - ics->offset; + struct ics_irq_state *irq = ics->irqs + srcno; + + irq->server = server; + irq->priority = priority; + + if (irq->type == XICS_LSI) { + write_xive_lsi(ics, srcno); + } else { + write_xive_msi(ics, srcno); + } +} + +static void ics_reject(struct ics_state *ics, int nr) { struct ics_irq_state *irq = ics->irqs + nr - ics->offset; - irq->rejected = 1; + irq->rejected = 1; /* Irrelevant but harmless for LSI */ + irq->sent = 0; /* Irrelevant but harmless for MSI */ } -static void ics_resend_msi(struct ics_state *ics) +static void ics_resend(struct ics_state *ics) { int i; @@ -215,56 +293,39 @@ static void ics_resend_msi(struct ics_state *ics) struct ics_irq_state *irq = ics->irqs + i; /* FIXME: filter by server#? */ - if (irq->rejected) { - irq->rejected = 0; - if (irq->priority != 0xff) { - icp_irq(ics->icp, irq->server, i + ics->offset, irq->priority); - } + if (irq->type == XICS_LSI) { + resend_lsi(ics, i); + } else { + resend_msi(ics, i); } } } -static void ics_write_xive_msi(struct ics_state *ics, int nr, int server, - uint8_t priority) -{ - struct ics_irq_state *irq = ics->irqs + nr - ics->offset; - - irq->server = server; - irq->priority = priority; - - if (!irq->masked_pending || (priority == 0xff)) { - return; - } - - irq->masked_pending = 0; - icp_irq(ics->icp, server, nr, priority); -} - -static void ics_reject(struct ics_state *ics, int nr) -{ - ics_reject_msi(ics, nr); -} - -static void ics_resend(struct ics_state *ics) -{ - ics_resend_msi(ics); -} - static void ics_eoi(struct ics_state *ics, int nr) { + int srcno = nr - ics->offset; + struct ics_irq_state *irq = ics->irqs + srcno; + + if (irq->type == XICS_LSI) { + irq->sent = 0; + } } /* * Exported functions */ -qemu_irq xics_find_qirq(struct icp_state *icp, int irq) +qemu_irq xics_assign_irq(struct icp_state *icp, int irq, + enum xics_irq_type type) { if ((irq < icp->ics->offset) || (irq >= (icp->ics->offset + icp->ics->nr_irqs))) { return NULL; } + assert((type == XICS_MSI) || (type == XICS_LSI)); + + icp->ics->irqs[irq - icp->ics->offset].type = type; return icp->ics->qirqs[irq - icp->ics->offset]; } @@ -332,7 +393,7 @@ static void rtas_set_xive(sPAPREnvironment *spapr, uint32_t token, return; } - ics_write_xive_msi(ics, nr, server, priority); + ics_write_xive(ics, nr, server, priority); rtas_st(rets, 0, 0); /* Success */ } @@ -477,7 +538,7 @@ struct icp_state *xics_system_init(int nr_irqs) ics->irqs[i].saved_priority = 0xff; } - ics->qirqs = qemu_allocate_irqs(ics_set_irq_msi, ics, nr_irqs); + ics->qirqs = qemu_allocate_irqs(ics_set_irq, ics, nr_irqs); spapr_register_hypercall(H_CPPR, h_cppr); spapr_register_hypercall(H_IPI, h_ipi); diff --git a/hw/xics.h b/hw/xics.h index 83c1182598..208015939c 100644 --- a/hw/xics.h +++ b/hw/xics.h @@ -31,7 +31,13 @@ struct icp_state; -qemu_irq xics_find_qirq(struct icp_state *icp, int irq); +enum xics_irq_type { + XICS_MSI, /* Message-signalled (edge) interrupt */ + XICS_LSI, /* Level-signalled interrupt */ +}; + +qemu_irq xics_assign_irq(struct icp_state *icp, int irq, + enum xics_irq_type type); struct icp_state *xics_system_init(int nr_irqs); From 6bbc5ed163d0eb8e3268ec81742a0d4f4f0bfc22 Mon Sep 17 00:00:00 2001 From: Meador Inge Date: Thu, 23 Feb 2012 03:44:14 +0000 Subject: [PATCH 12/42] ppc: Correctly define POWERPC_INSNS2_DEFAULT 'POWERPC_INSNS2_DEFAULT' was defined incorrectly which was causing the opcode table creation code to erroneously register 'eieio' and 'mbar' for the "default" processor: ** ERROR: opcode 1a already assigned in opcode table 16 *** ERROR: unable to insert opcode [1f-16-1a] *** ERROR initializing PowerPC instruction 0x1f 0x16 0x1a Signed-off-by: Meador Inge Signed-off-by: Alexander Graf --- target-ppc/translate_init.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/target-ppc/translate_init.c b/target-ppc/translate_init.c index 5a958b931f..367eefaf9e 100644 --- a/target-ppc/translate_init.c +++ b/target-ppc/translate_init.c @@ -6718,7 +6718,7 @@ static void init_proc_620 (CPUPPCState *env) #if defined (TARGET_PPC64) && 0 // XXX: TODO #define CPU_POWERPC_DEFAULT CPU_POWERPC_PPC64 #define POWERPC_INSNS_DEFAULT POWERPC_INSNS_PPC64 -#define POWERPC_INSNS2_DEFAULT POWERPC_INSNS_PPC64 +#define POWERPC_INSNS2_DEFAULT POWERPC_INSNS2_PPC64 #define POWERPC_MSRM_DEFAULT POWERPC_MSRM_PPC64 #define POWERPC_MMU_DEFAULT POWERPC_MMU_PPC64 #define POWERPC_EXCP_DEFAULT POWERPC_EXCP_PPC64 @@ -6730,7 +6730,7 @@ static void init_proc_620 (CPUPPCState *env) #else #define CPU_POWERPC_DEFAULT CPU_POWERPC_PPC32 #define POWERPC_INSNS_DEFAULT POWERPC_INSNS_PPC32 -#define POWERPC_INSNS2_DEFAULT POWERPC_INSNS_PPC32 +#define POWERPC_INSNS2_DEFAULT POWERPC_INSNS2_PPC32 #define POWERPC_MSRM_DEFAULT POWERPC_MSRM_PPC32 #define POWERPC_MMU_DEFAULT POWERPC_MMU_PPC32 #define POWERPC_EXCP_DEFAULT POWERPC_EXCP_PPC32 From 92e4b519e0808948ae4bc710fb1db7d3cc2245a1 Mon Sep 17 00:00:00 2001 From: David Gibson Date: Wed, 7 Mar 2012 14:41:09 +0000 Subject: [PATCH 13/42] kvm: Comparison with ioctl number macros needs to be unsigned In kvm-all.c we store an ioctl cmd number in the irqchip_inject_ioctl field of KVMState, which has type 'int'. This seems to make sense since the ioctl() man page says that the cmd parameter has type int. However, the kernel treats ioctl numbers as unsigned - sys_ioctl() takes an unsigned int, and the macros which generate ioctl numbers expand to unsigned expressions. Furthermore, some ioctls (IOC_READ ioctls on x86 and IOC_WRITE ioctls on powerpc) have bit 31 set, and so would be negative if interpreted as an int. This has the surprising and compile-breaking consequence that in kvm_irqchip_set_irq() where we do: return (s->irqchip_inject_ioctl == KVM_IRQ_LINE) ? 1 : event.status; We will get a "comparison is always false due to limited range of data type" warning from gcc if KVM_IRQ_LINE is one of the bit-31-set ioctls, which it is on powerpc. So, despite the fact that the man page and posix say ioctl numbers are signed, they're actually unsigned. The kernel uses unsigned, the glibc header uses unsigned long, and FreeBSD, NetBSD and OSX also use unsigned long ioctl numbers in the code. Therefore, this patch changes the variable to be unsigned, fixing the compile. Signed-off-by: David Gibson Signed-off-by: Alexander Graf --- kvm-all.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/kvm-all.c b/kvm-all.c index 42e5e23d5d..ba2cee10f2 100644 --- a/kvm-all.c +++ b/kvm-all.c @@ -79,7 +79,10 @@ struct KVMState int pit_state2; int xsave, xcrs; int many_ioeventfds; - int irqchip_inject_ioctl; + /* The man page (and posix) say ioctl numbers are signed int, but + * they're not. Linux, glibc and *BSD all treat ioctl numbers as + * unsigned, and treating them as signed here can break things */ + unsigned irqchip_inject_ioctl; #ifdef KVM_CAP_IRQ_ROUTING struct kvm_irq_routing *irq_routes; int nr_allocated_irq_routes; From 29979a8d2596d33b474c11efb376ed47ba1d44d3 Mon Sep 17 00:00:00 2001 From: Alexander Graf Date: Wed, 14 Mar 2012 00:13:22 +0100 Subject: [PATCH 14/42] PPC: KVM: Synchronize regs on CPU dump When we dump the CPU registers, there's a certain chance they haven't been synchronized with KVM yet, so we have to manually trigger that. This aligns the code with x86 and fixes a bug where the register state was bogus on invalid/unknown kvm exit reasons. Reported-by: Benjamin Herrenschmidt Signed-off-by: Alexander Graf --- target-ppc/translate.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/target-ppc/translate.c b/target-ppc/translate.c index 4722a09020..c9a503a1db 100644 --- a/target-ppc/translate.c +++ b/target-ppc/translate.c @@ -9319,6 +9319,8 @@ void cpu_dump_state (CPUPPCState *env, FILE *f, fprintf_function cpu_fprintf, int i; + cpu_synchronize_state(env); + cpu_fprintf(f, "NIP " TARGET_FMT_lx " LR " TARGET_FMT_lx " CTR " TARGET_FMT_lx " XER " TARGET_FMT_lx "\n", env->nip, env->lr, env->ctr, env->xer); From 298a971024534e9ab6c7b57845bbbd8188867d7a Mon Sep 17 00:00:00 2001 From: David Gibson Date: Mon, 12 Mar 2012 17:50:24 +0000 Subject: [PATCH 15/42] pseries: Configure PCI bridge using properties MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Currently, the function spapr_create_phb() uses its parameters to initialize the correct memory windows for the new PCI Host Bridge (PHB). This is not the way things are supposed to be done with qdevs, and means you can't create extra PHBs easily using -device. Since pSeries machines can and do have many PHBs with various configurations, this is a real limitation, not just a theoretical. This patch, therefore, alters the PHB initialization code to use qdev properties to set these parameters of the new bridge, moving most of the code from spapr_create_phb() to spapr_phb_init(). While we're at it, we change the naming of each PCI bus and its associated memory regions to be less arbitrary and make it easier to relate the guest and qemu views of memory to each other. Signed-off-by: Alexey Kardashevskiy Signed-off-by: David Gibson Reviewed-by: Andreas Färber Signed-off-by: Alexander Graf --- hw/spapr_pci.c | 166 +++++++++++++++++++++++++++---------------------- hw/spapr_pci.h | 4 +- 2 files changed, 94 insertions(+), 76 deletions(-) diff --git a/hw/spapr_pci.c b/hw/spapr_pci.c index 233250fac6..e7ef551c1c 100644 --- a/hw/spapr_pci.c +++ b/hw/spapr_pci.c @@ -180,49 +180,6 @@ static void pci_spapr_set_irq(void *opaque, int irq_num, int level) qemu_set_irq(phb->lsi_table[irq_num].qirq, level); } -static int spapr_phb_init(SysBusDevice *s) -{ - sPAPRPHBState *phb = FROM_SYSBUS(sPAPRPHBState, s); - int i; - - /* Initialize the LSI table */ - for (i = 0; i < SPAPR_PCI_NUM_LSI; i++) { - qemu_irq qirq; - uint32_t num; - - qirq = spapr_allocate_lsi(0, &num); - if (!qirq) { - return -1; - } - - phb->lsi_table[i].dt_irq = num; - phb->lsi_table[i].qirq = qirq; - } - - return 0; -} - -static void spapr_phb_class_init(ObjectClass *klass, void *data) -{ - SysBusDeviceClass *sdc = SYS_BUS_DEVICE_CLASS(klass); - - sdc->init = spapr_phb_init; -} - -static TypeInfo spapr_phb_info = { - .name = "spapr-pci-host-bridge", - .parent = TYPE_SYS_BUS_DEVICE, - .instance_size = sizeof(sPAPRPHBState), - .class_init = spapr_phb_class_init, -}; - -static void spapr_register_types(void) -{ - type_register_static(&spapr_phb_info); -} - -type_init(spapr_register_types) - static uint64_t spapr_io_read(void *opaque, target_phys_addr_t addr, unsigned size) { @@ -260,35 +217,29 @@ static const MemoryRegionOps spapr_io_ops = { .write = spapr_io_write }; -void spapr_create_phb(sPAPREnvironment *spapr, - const char *busname, uint64_t buid, - uint64_t mem_win_addr, uint64_t mem_win_size, - uint64_t io_win_addr) +/* + * PHB PCI device + */ +static int spapr_phb_init(SysBusDevice *s) { - DeviceState *dev; - SysBusDevice *s; - sPAPRPHBState *phb; + sPAPRPHBState *phb = FROM_SYSBUS(sPAPRPHBState, s); + char *namebuf; + int i; PCIBus *bus; - char namebuf[strlen(busname)+11]; - dev = qdev_create(NULL, "spapr-pci-host-bridge"); - qdev_init_nofail(dev); - s = sysbus_from_qdev(dev); - phb = FROM_SYSBUS(sPAPRPHBState, s); + phb->dtbusname = g_strdup_printf("pci@%" PRIx64, phb->buid); + namebuf = alloca(strlen(phb->dtbusname) + 32); - phb->mem_win_addr = mem_win_addr; - - sprintf(namebuf, "%s-mem", busname); + /* Initialize memory regions */ + sprintf(namebuf, "%s.mmio", phb->dtbusname); memory_region_init(&phb->memspace, namebuf, INT64_MAX); - sprintf(namebuf, "%s-memwindow", busname); + sprintf(namebuf, "%s.mmio-alias", phb->dtbusname); memory_region_init_alias(&phb->memwindow, namebuf, &phb->memspace, - SPAPR_PCI_MEM_WIN_BUS_OFFSET, mem_win_size); - memory_region_add_subregion(get_system_memory(), mem_win_addr, + SPAPR_PCI_MEM_WIN_BUS_OFFSET, phb->mem_win_size); + memory_region_add_subregion(get_system_memory(), phb->mem_win_addr, &phb->memwindow); - phb->io_win_addr = io_win_addr; - /* On ppc, we only have MMIO no specific IO space from the CPU * perspective. In theory we ought to be able to embed the PCI IO * memory region direction in the system memory space. However, @@ -297,33 +248,92 @@ void spapr_create_phb(sPAPREnvironment *spapr, * system io address space. This hack to bounce things via * system_io works around the problem until all the users of * old_portion are updated */ - sprintf(namebuf, "%s-io", busname); + sprintf(namebuf, "%s.io", phb->dtbusname); memory_region_init(&phb->iospace, namebuf, SPAPR_PCI_IO_WIN_SIZE); /* FIXME: fix to support multiple PHBs */ memory_region_add_subregion(get_system_io(), 0, &phb->iospace); - sprintf(namebuf, "%s-iowindow", busname); + sprintf(namebuf, "%s.io-alias", phb->dtbusname); memory_region_init_io(&phb->iowindow, &spapr_io_ops, phb, namebuf, SPAPR_PCI_IO_WIN_SIZE); - memory_region_add_subregion(get_system_memory(), io_win_addr, + memory_region_add_subregion(get_system_memory(), phb->io_win_addr, &phb->iowindow); - phb->host_state.bus = bus = pci_register_bus(&phb->busdev.qdev, busname, - pci_spapr_set_irq, - pci_spapr_map_irq, - phb, - &phb->memspace, &phb->iospace, - PCI_DEVFN(0, 0), - SPAPR_PCI_NUM_LSI); + bus = pci_register_bus(&phb->busdev.qdev, + phb->busname ? phb->busname : phb->dtbusname, + pci_spapr_set_irq, pci_spapr_map_irq, phb, + &phb->memspace, &phb->iospace, + PCI_DEVFN(0, 0), SPAPR_PCI_NUM_LSI); + phb->host_state.bus = bus; + + QLIST_INSERT_HEAD(&spapr->phbs, phb, list); + + /* Initialize the LSI table */ + for (i = 0; i < SPAPR_PCI_NUM_LSI; i++) { + qemu_irq qirq; + uint32_t num; + + qirq = spapr_allocate_lsi(0, &num); + if (!qirq) { + return -1; + } + + phb->lsi_table[i].dt_irq = num; + phb->lsi_table[i].qirq = qirq; + } + + return 0; +} + +static Property spapr_phb_properties[] = { + DEFINE_PROP_HEX64("buid", sPAPRPHBState, buid, 0), + DEFINE_PROP_STRING("busname", sPAPRPHBState, busname), + DEFINE_PROP_HEX64("mem_win_addr", sPAPRPHBState, mem_win_addr, 0), + DEFINE_PROP_HEX64("mem_win_size", sPAPRPHBState, mem_win_size, 0x20000000), + DEFINE_PROP_HEX64("io_win_addr", sPAPRPHBState, io_win_addr, 0), + DEFINE_PROP_HEX64("io_win_size", sPAPRPHBState, io_win_size, 0x10000), + DEFINE_PROP_END_OF_LIST(), +}; + +static void spapr_phb_class_init(ObjectClass *klass, void *data) +{ + SysBusDeviceClass *sdc = SYS_BUS_DEVICE_CLASS(klass); + DeviceClass *dc = DEVICE_CLASS(klass); + + sdc->init = spapr_phb_init; + dc->props = spapr_phb_properties; spapr_rtas_register("read-pci-config", rtas_read_pci_config); spapr_rtas_register("write-pci-config", rtas_write_pci_config); spapr_rtas_register("ibm,read-pci-config", rtas_ibm_read_pci_config); spapr_rtas_register("ibm,write-pci-config", rtas_ibm_write_pci_config); +} - QLIST_INSERT_HEAD(&spapr->phbs, phb, list); +static TypeInfo spapr_phb_info = { + .name = "spapr-pci-host-bridge", + .parent = TYPE_SYS_BUS_DEVICE, + .instance_size = sizeof(sPAPRPHBState), + .class_init = spapr_phb_class_init, +}; - /* pci_bus_set_mem_base(bus, mem_va_start - SPAPR_PCI_MEM_BAR_START); */ +void spapr_create_phb(sPAPREnvironment *spapr, + const char *busname, uint64_t buid, + uint64_t mem_win_addr, uint64_t mem_win_size, + uint64_t io_win_addr) +{ + DeviceState *dev; + + dev = qdev_create(NULL, spapr_phb_info.name); + + if (busname) { + qdev_prop_set_string(dev, "busname", g_strdup(busname)); + } + qdev_prop_set_uint64(dev, "buid", buid); + qdev_prop_set_uint64(dev, "mem_win_addr", mem_win_addr); + qdev_prop_set_uint64(dev, "mem_win_size", mem_win_size); + qdev_prop_set_uint64(dev, "io_win_addr", io_win_addr); + + qdev_init_nofail(dev); } /* Macros to operate with address in OF binding to PCI */ @@ -415,3 +425,9 @@ int spapr_populate_pci_devices(sPAPRPHBState *phb, return 0; } + +static void register_types(void) +{ + type_register_static(&spapr_phb_info); +} +type_init(register_types) diff --git a/hw/spapr_pci.h b/hw/spapr_pci.h index 213340c915..039f85bd4b 100644 --- a/hw/spapr_pci.h +++ b/hw/spapr_pci.h @@ -33,9 +33,11 @@ typedef struct sPAPRPHBState { PCIHostState host_state; uint64_t buid; + char *busname; + char *dtbusname; MemoryRegion memspace, iospace; - target_phys_addr_t mem_win_addr, io_win_addr; + target_phys_addr_t mem_win_addr, mem_win_size, io_win_addr, io_win_size; MemoryRegion memwindow, iowindow; struct { From 38ae51a804a6ad2baec3e45ecb1571583b312441 Mon Sep 17 00:00:00 2001 From: Alexander Graf Date: Wed, 14 Mar 2012 20:17:07 +0100 Subject: [PATCH 16/42] PPC: Fix openpic with relative memregions After commit 5312bd8b3152 we got memory region relative offsets into our mmio callbacks instead of page boundary based offsets. This broke the OpenPIC emulation which expected offsets to be on page boundary and substracted its region offset manually. This patch gets rid of that manual substraction and lets the memory api do its magic instead. Signed-off-by: Alexander Graf --- hw/openpic.c | 12 ++---------- 1 file changed, 2 insertions(+), 10 deletions(-) diff --git a/hw/openpic.c b/hw/openpic.c index 280b7a9bbb..58ef871f68 100644 --- a/hw/openpic.c +++ b/hw/openpic.c @@ -713,7 +713,7 @@ static void openpic_timer_write (void *opaque, uint32_t addr, uint32_t val) DPRINTF("%s: addr %08x <= %08x\n", __func__, addr, val); if (addr & 0xF) return; - addr -= 0x1100; + addr -= 0x10; addr &= 0xFFFF; idx = (addr & 0xFFF0) >> 6; addr = addr & 0x30; @@ -746,7 +746,7 @@ static uint32_t openpic_timer_read (void *opaque, uint32_t addr) retval = 0xFFFFFFFF; if (addr & 0xF) return retval; - addr -= 0x1100; + addr -= 0x10; addr &= 0xFFFF; idx = (addr & 0xFFF0) >> 6; addr = addr & 0x30; @@ -1361,7 +1361,6 @@ static void mpic_src_ext_write (void *opaque, target_phys_addr_t addr, if (addr & 0xF) return; - addr -= MPIC_EXT_REG_START & (OPENPIC_PAGE_SIZE - 1); if (addr < MPIC_EXT_REG_SIZE) { idx += (addr & 0xFFF0) >> 5; if (addr & 0x10) { @@ -1385,7 +1384,6 @@ static uint32_t mpic_src_ext_read (void *opaque, target_phys_addr_t addr) if (addr & 0xF) return retval; - addr -= MPIC_EXT_REG_START & (OPENPIC_PAGE_SIZE - 1); if (addr < MPIC_EXT_REG_SIZE) { idx += (addr & 0xFFF0) >> 5; if (addr & 0x10) { @@ -1411,7 +1409,6 @@ static void mpic_src_int_write (void *opaque, target_phys_addr_t addr, if (addr & 0xF) return; - addr -= MPIC_INT_REG_START & (OPENPIC_PAGE_SIZE - 1); if (addr < MPIC_INT_REG_SIZE) { idx += (addr & 0xFFF0) >> 5; if (addr & 0x10) { @@ -1435,7 +1432,6 @@ static uint32_t mpic_src_int_read (void *opaque, target_phys_addr_t addr) if (addr & 0xF) return retval; - addr -= MPIC_INT_REG_START & (OPENPIC_PAGE_SIZE - 1); if (addr < MPIC_INT_REG_SIZE) { idx += (addr & 0xFFF0) >> 5; if (addr & 0x10) { @@ -1461,7 +1457,6 @@ static void mpic_src_msg_write (void *opaque, target_phys_addr_t addr, if (addr & 0xF) return; - addr -= MPIC_MSG_REG_START & (OPENPIC_PAGE_SIZE - 1); if (addr < MPIC_MSG_REG_SIZE) { idx += (addr & 0xFFF0) >> 5; if (addr & 0x10) { @@ -1485,7 +1480,6 @@ static uint32_t mpic_src_msg_read (void *opaque, target_phys_addr_t addr) if (addr & 0xF) return retval; - addr -= MPIC_MSG_REG_START & (OPENPIC_PAGE_SIZE - 1); if (addr < MPIC_MSG_REG_SIZE) { idx += (addr & 0xFFF0) >> 5; if (addr & 0x10) { @@ -1511,7 +1505,6 @@ static void mpic_src_msi_write (void *opaque, target_phys_addr_t addr, if (addr & 0xF) return; - addr -= MPIC_MSI_REG_START & (OPENPIC_PAGE_SIZE - 1); if (addr < MPIC_MSI_REG_SIZE) { idx += (addr & 0xFFF0) >> 5; if (addr & 0x10) { @@ -1534,7 +1527,6 @@ static uint32_t mpic_src_msi_read (void *opaque, target_phys_addr_t addr) if (addr & 0xF) return retval; - addr -= MPIC_MSI_REG_START & (OPENPIC_PAGE_SIZE - 1); if (addr < MPIC_MSI_REG_SIZE) { idx += (addr & 0xFFF0) >> 5; if (addr & 0x10) { From 54e17933bf78cdbbeb0f12b2db38f210c2a992d4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Juha=20Riihim=C3=A4ki?= Date: Wed, 14 Mar 2012 15:37:53 +0000 Subject: [PATCH 17/42] hw/omap_i2c: Convert to qdev MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Convert the omap_i2c device to qdev. Signed-off-by: Juha Riihimäki [Riku Voipio: Fixes and restructuring patchset] Signed-off-by: Riku Voipio [Peter Maydell: More fixes and cleanups for upstream submission] Signed-off-by: Peter Maydell --- hw/nseries.c | 12 +++--- hw/omap.h | 13 +----- hw/omap1.c | 13 ++++-- hw/omap2.c | 35 ++++++++++------ hw/omap_i2c.c | 111 +++++++++++++++++++++++++++++--------------------- 5 files changed, 103 insertions(+), 81 deletions(-) diff --git a/hw/nseries.c b/hw/nseries.c index c5b31843dd..a5cfa8ccbc 100644 --- a/hw/nseries.c +++ b/hw/nseries.c @@ -45,7 +45,6 @@ struct n800_s { uint32_t (*txrx)(void *opaque, uint32_t value, int len); uWireSlave *chip; } ts; - i2c_bus *i2c; int keymap[0x80]; DeviceState *kbd; @@ -194,12 +193,10 @@ static void n8x0_i2c_setup(struct n800_s *s) { DeviceState *dev; qemu_irq tmp_irq = qdev_get_gpio_in(s->cpu->gpio, N8X0_TMP105_GPIO); - - /* Attach the CPU on one end of our I2C bus. */ - s->i2c = omap_i2c_bus(s->cpu->i2c[0]); + i2c_bus *i2c = omap_i2c_bus(s->cpu->i2c[0]); /* Attach a menelaus PM chip */ - dev = i2c_create_slave(s->i2c, "twl92230", N8X0_MENELAUS_ADDR); + dev = i2c_create_slave(i2c, "twl92230", N8X0_MENELAUS_ADDR); qdev_connect_gpio_out(dev, 3, qdev_get_gpio_in(s->cpu->ih[0], OMAP_INT_24XX_SYS_NIRQ)); @@ -207,7 +204,7 @@ static void n8x0_i2c_setup(struct n800_s *s) qemu_system_powerdown = qdev_get_gpio_in(dev, 3); /* Attach a TMP105 PM chip (A0 wired to ground) */ - dev = i2c_create_slave(s->i2c, "tmp105", N8X0_TMP105_ADDR); + dev = i2c_create_slave(i2c, "tmp105", N8X0_TMP105_ADDR); qdev_connect_gpio_out(dev, 0, tmp_irq); } @@ -391,7 +388,8 @@ static void n810_kbd_setup(struct n800_s *s) /* Attach the LM8322 keyboard to the I2C bus, * should happen in n8x0_i2c_setup and s->kbd be initialised here. */ - s->kbd = i2c_create_slave(s->i2c, "lm8323", N810_LM8323_ADDR); + s->kbd = i2c_create_slave(omap_i2c_bus(s->cpu->i2c[0]), + "lm8323", N810_LM8323_ADDR); qdev_connect_gpio_out(s->kbd, 0, kbd_irq); } diff --git a/hw/omap.h b/hw/omap.h index 63ef847ed0..6c3d004719 100644 --- a/hw/omap.h +++ b/hw/omap.h @@ -764,16 +764,7 @@ void omap_mmc_handlers(struct omap_mmc_s *s, qemu_irq ro, qemu_irq cover); void omap_mmc_enable(struct omap_mmc_s *s, int enable); /* omap_i2c.c */ -struct omap_i2c_s; -struct omap_i2c_s *omap_i2c_init(MemoryRegion *sysmem, - target_phys_addr_t base, - qemu_irq irq, - qemu_irq *dma, - omap_clk clk); -struct omap_i2c_s *omap2_i2c_init(struct omap_target_agent_s *ta, - qemu_irq irq, qemu_irq *dma, omap_clk fclk, omap_clk iclk); -void omap_i2c_reset(struct omap_i2c_s *s); -i2c_bus *omap_i2c_bus(struct omap_i2c_s *s); +i2c_bus *omap_i2c_bus(DeviceState *omap_i2c); # define cpu_is_omap310(cpu) (cpu->mpu_model == omap310) # define cpu_is_omap1510(cpu) (cpu->mpu_model == omap1510) @@ -867,7 +858,7 @@ struct omap_mpu_state_s { struct omap_pwl_s *pwl; struct omap_pwt_s *pwt; - struct omap_i2c_s *i2c[2]; + DeviceState *i2c[2]; struct omap_rtc_s *rtc; diff --git a/hw/omap1.c b/hw/omap1.c index 5317b9be2b..2a341bfe7f 100644 --- a/hw/omap1.c +++ b/hw/omap1.c @@ -3694,7 +3694,6 @@ static void omap1_mpu_reset(void *opaque) omap_uwire_reset(mpu->microwire); omap_pwl_reset(mpu->pwl); omap_pwt_reset(mpu->pwt); - omap_i2c_reset(mpu->i2c[0]); omap_rtc_reset(mpu->rtc); omap_mcbsp_reset(mpu->mcbsp1); omap_mcbsp_reset(mpu->mcbsp2); @@ -3993,9 +3992,15 @@ struct omap_mpu_state_s *omap310_mpu_init(MemoryRegion *system_memory, s->pwt = omap_pwt_init(system_memory, 0xfffb6000, omap_findclk(s, "armxor_ck")); - s->i2c[0] = omap_i2c_init(system_memory, 0xfffb3800, - qdev_get_gpio_in(s->ih[1], OMAP_INT_I2C), - &s->drq[OMAP_DMA_I2C_RX], omap_findclk(s, "mpuper_ck")); + s->i2c[0] = qdev_create(NULL, "omap_i2c"); + qdev_prop_set_uint8(s->i2c[0], "revision", 0x11); + qdev_prop_set_ptr(s->i2c[0], "fclk", omap_findclk(s, "mpuper_ck")); + qdev_init_nofail(s->i2c[0]); + busdev = sysbus_from_qdev(s->i2c[0]); + sysbus_connect_irq(busdev, 0, qdev_get_gpio_in(s->ih[1], OMAP_INT_I2C)); + sysbus_connect_irq(busdev, 1, s->drq[OMAP_DMA_I2C_TX]); + sysbus_connect_irq(busdev, 2, s->drq[OMAP_DMA_I2C_RX]); + sysbus_mmio_map(busdev, 0, 0xfffb3800); s->rtc = omap_rtc_init(system_memory, 0xfffb4800, qdev_get_gpio_in(s->ih[1], OMAP_INT_RTC_TIMER), diff --git a/hw/omap2.c b/hw/omap2.c index 157defb393..42fce5e986 100644 --- a/hw/omap2.c +++ b/hw/omap2.c @@ -2222,8 +2222,6 @@ static void omap2_mpu_reset(void *opaque) omap_mmc_reset(mpu->mmc); omap_mcspi_reset(mpu->mcspi[0]); omap_mcspi_reset(mpu->mcspi[1]); - omap_i2c_reset(mpu->i2c[0]); - omap_i2c_reset(mpu->i2c[1]); cpu_state_reset(mpu->env); } @@ -2395,16 +2393,29 @@ struct omap_mpu_state_s *omap2420_mpu_init(MemoryRegion *sysmem, omap_findclk(s, "clk32-kHz"), omap_findclk(s, "core_l4_iclk")); - s->i2c[0] = omap2_i2c_init(omap_l4tao(s->l4, 5), - qdev_get_gpio_in(s->ih[0], OMAP_INT_24XX_I2C1_IRQ), - &s->drq[OMAP24XX_DMA_I2C1_TX], - omap_findclk(s, "i2c1.fclk"), - omap_findclk(s, "i2c1.iclk")); - s->i2c[1] = omap2_i2c_init(omap_l4tao(s->l4, 6), - qdev_get_gpio_in(s->ih[0], OMAP_INT_24XX_I2C2_IRQ), - &s->drq[OMAP24XX_DMA_I2C2_TX], - omap_findclk(s, "i2c2.fclk"), - omap_findclk(s, "i2c2.iclk")); + s->i2c[0] = qdev_create(NULL, "omap_i2c"); + qdev_prop_set_uint8(s->i2c[0], "revision", 0x34); + qdev_prop_set_ptr(s->i2c[0], "iclk", omap_findclk(s, "i2c1.iclk")); + qdev_prop_set_ptr(s->i2c[0], "fclk", omap_findclk(s, "i2c1.fclk")); + qdev_init_nofail(s->i2c[0]); + busdev = sysbus_from_qdev(s->i2c[0]); + sysbus_connect_irq(busdev, 0, + qdev_get_gpio_in(s->ih[0], OMAP_INT_24XX_I2C1_IRQ)); + sysbus_connect_irq(busdev, 1, s->drq[OMAP24XX_DMA_I2C1_TX]); + sysbus_connect_irq(busdev, 2, s->drq[OMAP24XX_DMA_I2C1_RX]); + sysbus_mmio_map(busdev, 0, omap_l4_region_base(omap_l4tao(s->l4, 5), 0)); + + s->i2c[1] = qdev_create(NULL, "omap_i2c"); + qdev_prop_set_uint8(s->i2c[1], "revision", 0x34); + qdev_prop_set_ptr(s->i2c[1], "iclk", omap_findclk(s, "i2c2.iclk")); + qdev_prop_set_ptr(s->i2c[1], "fclk", omap_findclk(s, "i2c2.fclk")); + qdev_init_nofail(s->i2c[1]); + busdev = sysbus_from_qdev(s->i2c[1]); + sysbus_connect_irq(busdev, 0, + qdev_get_gpio_in(s->ih[0], OMAP_INT_24XX_I2C2_IRQ)); + sysbus_connect_irq(busdev, 1, s->drq[OMAP24XX_DMA_I2C2_TX]); + sysbus_connect_irq(busdev, 2, s->drq[OMAP24XX_DMA_I2C2_RX]); + sysbus_mmio_map(busdev, 0, omap_l4_region_base(omap_l4tao(s->l4, 6), 0)); s->gpio = qdev_create(NULL, "omap2-gpio"); qdev_prop_set_int32(s->gpio, "mpu_model", s->mpu_model); diff --git a/hw/omap_i2c.c b/hw/omap_i2c.c index 5ec422c566..20bc82e3b8 100644 --- a/hw/omap_i2c.c +++ b/hw/omap_i2c.c @@ -19,14 +19,20 @@ #include "hw.h" #include "i2c.h" #include "omap.h" +#include "sysbus.h" -struct omap_i2c_s { + +typedef struct OMAPI2CState { + SysBusDevice busdev; MemoryRegion iomem; qemu_irq irq; qemu_irq drq[2]; i2c_bus *bus; uint8_t revision; + void *iclk; + void *fclk; + uint8_t mask; uint16_t stat; uint16_t dma; @@ -40,12 +46,12 @@ struct omap_i2c_s { uint8_t divider; uint8_t times[2]; uint16_t test; -}; +} OMAPI2CState; #define OMAP2_INTR_REV 0x34 #define OMAP2_GC_REV 0x34 -static void omap_i2c_interrupts_update(struct omap_i2c_s *s) +static void omap_i2c_interrupts_update(OMAPI2CState *s) { qemu_set_irq(s->irq, s->stat & s->mask); if ((s->dma >> 15) & 1) /* RDMA_EN */ @@ -54,7 +60,7 @@ static void omap_i2c_interrupts_update(struct omap_i2c_s *s) qemu_set_irq(s->drq[1], (s->stat >> 4) & 1); /* XRDY */ } -static void omap_i2c_fifo_run(struct omap_i2c_s *s) +static void omap_i2c_fifo_run(OMAPI2CState *s) { int ack = 1; @@ -122,8 +128,10 @@ static void omap_i2c_fifo_run(struct omap_i2c_s *s) s->control &= ~(1 << 1); /* STP */ } -void omap_i2c_reset(struct omap_i2c_s *s) +static void omap_i2c_reset(DeviceState *dev) { + OMAPI2CState *s = FROM_SYSBUS(OMAPI2CState, + sysbus_from_qdev(dev)); s->mask = 0; s->stat = 0; s->dma = 0; @@ -143,7 +151,7 @@ void omap_i2c_reset(struct omap_i2c_s *s) static uint32_t omap_i2c_read(void *opaque, target_phys_addr_t addr) { - struct omap_i2c_s *s = (struct omap_i2c_s *) opaque; + OMAPI2CState *s = opaque; int offset = addr & OMAP_MPUI_REG_MASK; uint16_t ret; @@ -243,7 +251,7 @@ static uint32_t omap_i2c_read(void *opaque, target_phys_addr_t addr) static void omap_i2c_write(void *opaque, target_phys_addr_t addr, uint32_t value) { - struct omap_i2c_s *s = (struct omap_i2c_s *) opaque; + OMAPI2CState *s = opaque; int offset = addr & OMAP_MPUI_REG_MASK; int nack; @@ -309,14 +317,14 @@ static void omap_i2c_write(void *opaque, target_phys_addr_t addr, } if (value & 2) - omap_i2c_reset(s); + omap_i2c_reset(&s->busdev.qdev); break; case 0x24: /* I2C_CON */ s->control = value & 0xcf87; if (~value & (1 << 15)) { /* I2C_EN */ if (s->revision < OMAP2_INTR_REV) - omap_i2c_reset(s); + omap_i2c_reset(&s->busdev.qdev); break; } if ((value & (1 << 15)) && !(value & (1 << 10))) { /* MST */ @@ -385,7 +393,7 @@ static void omap_i2c_write(void *opaque, target_phys_addr_t addr, static void omap_i2c_writeb(void *opaque, target_phys_addr_t addr, uint32_t value) { - struct omap_i2c_s *s = (struct omap_i2c_s *) opaque; + OMAPI2CState *s = opaque; int offset = addr & OMAP_MPUI_REG_MASK; switch (offset) { @@ -426,50 +434,59 @@ static const MemoryRegionOps omap_i2c_ops = { .endianness = DEVICE_NATIVE_ENDIAN, }; -struct omap_i2c_s *omap_i2c_init(MemoryRegion *sysmem, - target_phys_addr_t base, - qemu_irq irq, - qemu_irq *dma, - omap_clk clk) +static int omap_i2c_init(SysBusDevice *dev) { - struct omap_i2c_s *s = (struct omap_i2c_s *) - g_malloc0(sizeof(struct omap_i2c_s)); + OMAPI2CState *s = FROM_SYSBUS(OMAPI2CState, dev); - /* TODO: set a value greater or equal to real hardware */ - s->revision = 0x11; - s->irq = irq; - s->drq[0] = dma[0]; - s->drq[1] = dma[1]; - s->bus = i2c_init_bus(NULL, "i2c"); - omap_i2c_reset(s); - - memory_region_init_io(&s->iomem, &omap_i2c_ops, s, "omap.i2c", 0x800); - memory_region_add_subregion(sysmem, base, &s->iomem); - - return s; + if (!s->fclk) { + hw_error("omap_i2c: fclk not connected\n"); + } + if (s->revision >= OMAP2_INTR_REV && !s->iclk) { + /* Note that OMAP1 doesn't have a separate interface clock */ + hw_error("omap_i2c: iclk not connected\n"); + } + sysbus_init_irq(dev, &s->irq); + sysbus_init_irq(dev, &s->drq[0]); + sysbus_init_irq(dev, &s->drq[1]); + memory_region_init_io(&s->iomem, &omap_i2c_ops, s, "omap.i2c", + (s->revision < OMAP2_INTR_REV) ? 0x800 : 0x1000); + sysbus_init_mmio(dev, &s->iomem); + s->bus = i2c_init_bus(&dev->qdev, NULL); + return 0; } -struct omap_i2c_s *omap2_i2c_init(struct omap_target_agent_s *ta, - qemu_irq irq, qemu_irq *dma, omap_clk fclk, omap_clk iclk) +static Property omap_i2c_properties[] = { + DEFINE_PROP_UINT8("revision", OMAPI2CState, revision, 0), + DEFINE_PROP_PTR("iclk", OMAPI2CState, iclk), + DEFINE_PROP_PTR("fclk", OMAPI2CState, fclk), + DEFINE_PROP_END_OF_LIST(), +}; + +static void omap_i2c_class_init(ObjectClass *klass, void *data) { - struct omap_i2c_s *s = (struct omap_i2c_s *) - g_malloc0(sizeof(struct omap_i2c_s)); - - s->revision = 0x34; - s->irq = irq; - s->drq[0] = dma[0]; - s->drq[1] = dma[1]; - s->bus = i2c_init_bus(NULL, "i2c"); - omap_i2c_reset(s); - - memory_region_init_io(&s->iomem, &omap_i2c_ops, s, "omap2.i2c", - omap_l4_region_size(ta, 0)); - omap_l4_attach(ta, 0, &s->iomem); - - return s; + DeviceClass *dc = DEVICE_CLASS(klass); + SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass); + k->init = omap_i2c_init; + dc->props = omap_i2c_properties; + dc->reset = omap_i2c_reset; } -i2c_bus *omap_i2c_bus(struct omap_i2c_s *s) +static TypeInfo omap_i2c_info = { + .name = "omap_i2c", + .parent = TYPE_SYS_BUS_DEVICE, + .instance_size = sizeof(OMAPI2CState), + .class_init = omap_i2c_class_init, +}; + +static void omap_i2c_register_types(void) { + type_register_static(&omap_i2c_info); +} + +i2c_bus *omap_i2c_bus(DeviceState *omap_i2c) +{ + OMAPI2CState *s = FROM_SYSBUS(OMAPI2CState, sysbus_from_qdev(omap_i2c)); return s->bus; } + +type_init(omap_i2c_register_types) From 4de47793d49e70ee048e15889d4bf139e7b36ce7 Mon Sep 17 00:00:00 2001 From: Peter Maydell Date: Wed, 14 Mar 2012 12:26:10 +0000 Subject: [PATCH 18/42] target-arm: Fix typo in ARM946 cp15 c5 handling Fix a typo in handling of the ARM946 cp15 c5 c0 0 1 handling (instruction access permission bits) that meant it would return the data access permission bits by mistake. Signed-off-by: Peter Maydell --- target-arm/helper.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/target-arm/helper.c b/target-arm/helper.c index 8a08db8d57..4116feebf5 100644 --- a/target-arm/helper.c +++ b/target-arm/helper.c @@ -2025,7 +2025,7 @@ uint32_t HELPER(get_cp15)(CPUARMState *env, uint32_t insn) return env->cp15.c5_data; case 1: if (arm_feature(env, ARM_FEATURE_MPU)) - return simple_mpu_ap_bits(env->cp15.c5_data); + return simple_mpu_ap_bits(env->cp15.c5_insn); return env->cp15.c5_insn; case 2: if (!arm_feature(env, ARM_FEATURE_MPU)) From c98d174c24b915e9908785feb63eb3b5abe33818 Mon Sep 17 00:00:00 2001 From: Peter Maydell Date: Wed, 14 Mar 2012 12:26:10 +0000 Subject: [PATCH 19/42] target-arm: Clear IT bits when taking exceptions in v7M When taking an exception for an M profile core, we must clear the IT bits. Since the IT bits are cached in env->condexec_bits we must clear them there: writing the bits in env->uncached_cpsr has no effect. (Reported as LP:944645.) Signed-off-by: Peter Maydell --- target-arm/helper.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/target-arm/helper.c b/target-arm/helper.c index 4116feebf5..1314f23d59 100644 --- a/target-arm/helper.c +++ b/target-arm/helper.c @@ -877,7 +877,8 @@ static void do_interrupt_v7m(CPUARMState *env) v7m_push(env, env->regs[1]); v7m_push(env, env->regs[0]); switch_v7m_sp(env, 0); - env->uncached_cpsr &= ~CPSR_IT; + /* Clear IT bits */ + env->condexec_bits = 0; env->regs[14] = lr; addr = ldl_phys(env->v7m.vecbase + env->v7m.exception * 4); env->regs[15] = addr & 0xfffffffe; From d9e028c1d9c2a8d2ad42f2aeb502b71086a52d4d Mon Sep 17 00:00:00 2001 From: Peter Maydell Date: Wed, 14 Mar 2012 12:26:11 +0000 Subject: [PATCH 20/42] target-arm: Decode SETEND correctly in Thumb Decode the SETEND instruction correctly in Thumb mode, rather than accidentally treating it like CPS. We don't support BE8 mode, but this change brings the Thumb mode in to line with behaviour in ARM mode: 'SETEND BE' is not supported and will provoke an UNDEF exception, but 'SETEND LE' is correctly handled as a no-op. Signed-off-by: Peter Maydell Reported-by: Daniel Forsgren Reviewed-by: Laurent Desnogues --- target-arm/translate.c | 63 +++++++++++++++++++++++++++--------------- 1 file changed, 40 insertions(+), 23 deletions(-) diff --git a/target-arm/translate.c b/target-arm/translate.c index 2709010f4a..81725d1687 100644 --- a/target-arm/translate.c +++ b/target-arm/translate.c @@ -9704,32 +9704,49 @@ static void disas_thumb_insn(CPUARMState *env, DisasContext *s) store_reg(s, rd, tmp); break; - case 6: /* cps */ - ARCH(6); - if (IS_USER(s)) + case 6: + switch ((insn >> 5) & 7) { + case 2: + /* setend */ + ARCH(6); + if (insn & (1 << 3)) { + /* BE8 mode not implemented. */ + goto illegal_op; + } break; - if (IS_M(env)) { - tmp = tcg_const_i32((insn & (1 << 4)) != 0); - /* FAULTMASK */ - if (insn & 1) { - addr = tcg_const_i32(19); - gen_helper_v7m_msr(cpu_env, addr, tmp); - tcg_temp_free_i32(addr); + case 3: + /* cps */ + ARCH(6); + if (IS_USER(s)) { + break; } - /* PRIMASK */ - if (insn & 2) { - addr = tcg_const_i32(16); - gen_helper_v7m_msr(cpu_env, addr, tmp); - tcg_temp_free_i32(addr); + if (IS_M(env)) { + tmp = tcg_const_i32((insn & (1 << 4)) != 0); + /* FAULTMASK */ + if (insn & 1) { + addr = tcg_const_i32(19); + gen_helper_v7m_msr(cpu_env, addr, tmp); + tcg_temp_free_i32(addr); + } + /* PRIMASK */ + if (insn & 2) { + addr = tcg_const_i32(16); + gen_helper_v7m_msr(cpu_env, addr, tmp); + tcg_temp_free_i32(addr); + } + tcg_temp_free_i32(tmp); + gen_lookup_tb(s); + } else { + if (insn & (1 << 4)) { + shift = CPSR_A | CPSR_I | CPSR_F; + } else { + shift = 0; + } + gen_set_psr_im(s, ((insn & 7) << 6), 0, shift); } - tcg_temp_free_i32(tmp); - gen_lookup_tb(s); - } else { - if (insn & (1 << 4)) - shift = CPSR_A | CPSR_I | CPSR_F; - else - shift = 0; - gen_set_psr_im(s, ((insn & 7) << 6), 0, shift); + break; + default: + goto undef; } break; From 82a9807bcaa2db2825eee0d1236218ccebaaf875 Mon Sep 17 00:00:00 2001 From: Stefan Weil Date: Sat, 28 Jan 2012 05:18:16 +0000 Subject: [PATCH 21/42] malta: Clean allocation of bios region alias It is sufficient to define the region alias once for all code branches. Signed-off-by: Stefan Weil --- hw/mips_malta.c | 21 ++++++--------------- 1 file changed, 6 insertions(+), 15 deletions(-) diff --git a/hw/mips_malta.c b/hw/mips_malta.c index 5e26775e64..2528fbe265 100644 --- a/hw/mips_malta.c +++ b/hw/mips_malta.c @@ -856,10 +856,7 @@ void mips_malta_init (ram_addr_t ram_size, memory_region_init_ram(bios, "mips_malta.bios", BIOS_SIZE); vmstate_register_ram_global(bios); memory_region_set_readonly(bios, true); - memory_region_init_alias(bios_alias, "bios.1fc", bios, 0, BIOS_SIZE); - /* Map the bios at two physical locations, as on the real board. */ memory_region_add_subregion(system_memory, 0x1e000000LL, bios); - memory_region_add_subregion(system_memory, 0x1fc00000LL, bios_alias); loaderparams.ram_size = ram_size; loaderparams.kernel_filename = kernel_filename; loaderparams.kernel_cmdline = kernel_cmdline; @@ -883,29 +880,19 @@ void mips_malta_init (ram_addr_t ram_size, dinfo->bdrv, 65536, fl_sectors, 4, 0x0000, 0x0000, 0x0000, 0x0000, be); bios = pflash_cfi01_get_memory(fl); - /* Map the bios at two physical locations, as on the real board. */ - memory_region_init_alias(bios_alias, "bios.1fc", - bios, 0, BIOS_SIZE); - memory_region_add_subregion(system_memory, 0x1fc00000LL, - bios_alias); - fl_idx++; + fl_idx++; } else { bios = g_new(MemoryRegion, 1); memory_region_init_ram(bios, "mips_malta.bios", BIOS_SIZE); vmstate_register_ram_global(bios); memory_region_set_readonly(bios, true); - memory_region_init_alias(bios_alias, "bios.1fc", - bios, 0, BIOS_SIZE); - /* Map the bios at two physical locations, as on the real board. */ memory_region_add_subregion(system_memory, 0x1e000000LL, bios); - memory_region_add_subregion(system_memory, 0x1fc00000LL, - bios_alias); /* Load a BIOS image. */ if (bios_name == NULL) bios_name = BIOS_FILENAME; filename = qemu_find_file(QEMU_FILE_TYPE_BIOS, bios_name); if (filename) { - bios_size = load_image_targphys(filename, 0x1fc00000LL, + bios_size = load_image_targphys(filename, 0x1e000000LL, BIOS_SIZE); g_free(filename); } else { @@ -932,6 +919,10 @@ void mips_malta_init (ram_addr_t ram_size, #endif } + /* Map the BIOS at a 2nd physical location, as on the real board. */ + memory_region_init_alias(bios_alias, "bios.1fc", bios, 0, BIOS_SIZE); + memory_region_add_subregion(system_memory, 0x1fc00000LL, bios_alias); + /* Board ID = 0x420 (Malta Board with CoreLV) XXX: theoretically 0x1e000010 should map to flash and 0x1fc00010 should map to the board ID. */ From bb4b335871677e0aa447484332e975d6c2ab0ba4 Mon Sep 17 00:00:00 2001 From: Stefan Weil Date: Sat, 28 Jan 2012 05:18:17 +0000 Subject: [PATCH 22/42] malta: Always allocate flash memory There is no reason why there should not be a flash memory when the Malta emulation is started with a Linux kernel. When flash memory is always available, the code is simpler, and it can be better tested. Signed-off-by: Stefan Weil --- hw/mips_malta.c | 54 ++++++++++++++++++++----------------------------- 1 file changed, 22 insertions(+), 32 deletions(-) diff --git a/hw/mips_malta.c b/hw/mips_malta.c index 2528fbe265..734e70011c 100644 --- a/hw/mips_malta.c +++ b/hw/mips_malta.c @@ -777,7 +777,7 @@ void mips_malta_init (ram_addr_t ram_size, MemoryRegion *system_memory = get_system_memory(); MemoryRegion *ram = g_new(MemoryRegion, 1); MemoryRegion *bios, *bios_alias = g_new(MemoryRegion, 1); - target_long bios_size; + target_long bios_size = 0x400000; int64_t kernel_entry; PCIBus *pci_bus; ISABus *isa_bus; @@ -791,7 +791,7 @@ void mips_malta_init (ram_addr_t ram_size, DriveInfo *hd[MAX_IDE_BUS * MAX_IDE_DEVS]; DriveInfo *fd[MAX_FD]; int fl_idx = 0; - int fl_sectors = 0; + int fl_sectors = bios_size >> 16; int be; DeviceState *dev = qdev_create(NULL, "mips-malta"); @@ -849,14 +849,24 @@ void mips_malta_init (ram_addr_t ram_size, /* FPGA */ malta_fpga_init(system_memory, 0x1f000000LL, env->irq[2], serial_hds[2]); - /* Load firmware in flash / BIOS unless we boot directly into a kernel. */ + /* Load firmware in flash / BIOS. */ + dinfo = drive_get(IF_PFLASH, 0, fl_idx); +#ifdef DEBUG_BOARD_INIT + if (dinfo) { + printf("Register parallel flash %d size " TARGET_FMT_lx " at " + "addr %08llx '%s' %x\n", + fl_idx, bios_size, 0x1e000000LL, + bdrv_get_device_name(dinfo->bdrv), fl_sectors); + } +#endif + fl = pflash_cfi01_register(0x1e000000LL, NULL, "mips_malta.bios", + BIOS_SIZE, dinfo ? dinfo->bdrv : NULL, + 65536, fl_sectors, + 4, 0x0000, 0x0000, 0x0000, 0x0000, be); + bios = pflash_cfi01_get_memory(fl); + fl_idx++; if (kernel_filename) { /* Write a small bootloader to the flash location. */ - bios = g_new(MemoryRegion, 1); - memory_region_init_ram(bios, "mips_malta.bios", BIOS_SIZE); - vmstate_register_ram_global(bios); - memory_region_set_readonly(bios, true); - memory_region_add_subregion(system_memory, 0x1e000000LL, bios); loaderparams.ram_size = ram_size; loaderparams.kernel_filename = kernel_filename; loaderparams.kernel_cmdline = kernel_cmdline; @@ -864,32 +874,12 @@ void mips_malta_init (ram_addr_t ram_size, kernel_entry = load_kernel(); write_bootloader(env, memory_region_get_ram_ptr(bios), kernel_entry); } else { - dinfo = drive_get(IF_PFLASH, 0, fl_idx); - if (dinfo) { - /* Load firmware from flash. */ - bios_size = 0x400000; - fl_sectors = bios_size >> 16; -#ifdef DEBUG_BOARD_INIT - printf("Register parallel flash %d size " TARGET_FMT_lx " at " - "addr %08llx '%s' %x\n", - fl_idx, bios_size, 0x1e000000LL, - bdrv_get_device_name(dinfo->bdrv), fl_sectors); -#endif - fl = pflash_cfi01_register(0x1e000000LL, - NULL, "mips_malta.bios", BIOS_SIZE, - dinfo->bdrv, 65536, fl_sectors, - 4, 0x0000, 0x0000, 0x0000, 0x0000, be); - bios = pflash_cfi01_get_memory(fl); - fl_idx++; - } else { - bios = g_new(MemoryRegion, 1); - memory_region_init_ram(bios, "mips_malta.bios", BIOS_SIZE); - vmstate_register_ram_global(bios); - memory_region_set_readonly(bios, true); - memory_region_add_subregion(system_memory, 0x1e000000LL, bios); + /* Load firmware from flash. */ + if (!dinfo) { /* Load a BIOS image. */ - if (bios_name == NULL) + if (bios_name == NULL) { bios_name = BIOS_FILENAME; + } filename = qemu_find_file(QEMU_FILE_TYPE_BIOS, bios_name); if (filename) { bios_size = load_image_targphys(filename, 0x1e000000LL, From 03a1a8e1b13bb447c898eb282ee8c3fc41c866b4 Mon Sep 17 00:00:00 2001 From: Stefan Weil Date: Sat, 28 Jan 2012 05:18:18 +0000 Subject: [PATCH 23/42] malta: Use symbolic hardware addresses The patch adds definitions of some hardware addresses and uses these definitions. It also replaces the type of all addresses from signed to unsigned values. This is only a cosmetic change because addresses are unsigned values, the functions called also expect unsigned values, and we need no sign extension here. Signed-off-by: Stefan Weil --- hw/mips_malta.c | 19 +++++++++++++------ 1 file changed, 13 insertions(+), 6 deletions(-) diff --git a/hw/mips_malta.c b/hw/mips_malta.c index 734e70011c..d8c8c35bd9 100644 --- a/hw/mips_malta.c +++ b/hw/mips_malta.c @@ -55,6 +55,13 @@ #define ENVP_NB_ENTRIES 16 #define ENVP_ENTRY_SIZE 256 +/* Hardware addresses */ +#define FLASH_ADDRESS 0x1e000000ULL +#define FPGA_ADDRESS 0x1f000000ULL +#define RESET_ADDRESS 0x1fc00000ULL + +#define FLASH_SIZE 0x400000 + #define MAX_IDE_BUS 2 typedef struct { @@ -777,7 +784,7 @@ void mips_malta_init (ram_addr_t ram_size, MemoryRegion *system_memory = get_system_memory(); MemoryRegion *ram = g_new(MemoryRegion, 1); MemoryRegion *bios, *bios_alias = g_new(MemoryRegion, 1); - target_long bios_size = 0x400000; + target_long bios_size = FLASH_SIZE; int64_t kernel_entry; PCIBus *pci_bus; ISABus *isa_bus; @@ -847,7 +854,7 @@ void mips_malta_init (ram_addr_t ram_size, be = 0; #endif /* FPGA */ - malta_fpga_init(system_memory, 0x1f000000LL, env->irq[2], serial_hds[2]); + malta_fpga_init(system_memory, FPGA_ADDRESS, env->irq[2], serial_hds[2]); /* Load firmware in flash / BIOS. */ dinfo = drive_get(IF_PFLASH, 0, fl_idx); @@ -855,11 +862,11 @@ void mips_malta_init (ram_addr_t ram_size, if (dinfo) { printf("Register parallel flash %d size " TARGET_FMT_lx " at " "addr %08llx '%s' %x\n", - fl_idx, bios_size, 0x1e000000LL, + fl_idx, bios_size, FLASH_ADDRESS, bdrv_get_device_name(dinfo->bdrv), fl_sectors); } #endif - fl = pflash_cfi01_register(0x1e000000LL, NULL, "mips_malta.bios", + fl = pflash_cfi01_register(FLASH_ADDRESS, NULL, "mips_malta.bios", BIOS_SIZE, dinfo ? dinfo->bdrv : NULL, 65536, fl_sectors, 4, 0x0000, 0x0000, 0x0000, 0x0000, be); @@ -882,7 +889,7 @@ void mips_malta_init (ram_addr_t ram_size, } filename = qemu_find_file(QEMU_FILE_TYPE_BIOS, bios_name); if (filename) { - bios_size = load_image_targphys(filename, 0x1e000000LL, + bios_size = load_image_targphys(filename, FLASH_ADDRESS, BIOS_SIZE); g_free(filename); } else { @@ -911,7 +918,7 @@ void mips_malta_init (ram_addr_t ram_size, /* Map the BIOS at a 2nd physical location, as on the real board. */ memory_region_init_alias(bios_alias, "bios.1fc", bios, 0, BIOS_SIZE); - memory_region_add_subregion(system_memory, 0x1fc00000LL, bios_alias); + memory_region_add_subregion(system_memory, RESET_ADDRESS, bios_alias); /* Board ID = 0x420 (Malta Board with CoreLV) XXX: theoretically 0x1e000010 should map to flash and 0x1fc00010 should From 1d7a1197068da26813e2a4706b4573143db166f5 Mon Sep 17 00:00:00 2001 From: Stefan Weil Date: Sat, 28 Jan 2012 05:18:19 +0000 Subject: [PATCH 24/42] malta: Fix display for LED array The 8-LED array was already implemented in the first commit to Malta, but this implementation was incomplete. Signed-off-by: Stefan Weil --- hw/mips_malta.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/hw/mips_malta.c b/hw/mips_malta.c index d8c8c35bd9..4752bb2865 100644 --- a/hw/mips_malta.c +++ b/hw/mips_malta.c @@ -338,9 +338,9 @@ static void malta_fpga_write(void *opaque, target_phys_addr_t addr, break; /* LEDBAR Register */ - /* XXX: implement a 8-LED array */ case 0x00408: s->leds = val & 0xff; + malta_fpga_update_display(s); break; /* ASCIIWORD Register */ From 0e4a398ab2c5e9b540a80859ec28163b65e7a891 Mon Sep 17 00:00:00 2001 From: Peter Maydell Date: Wed, 14 Mar 2012 15:37:53 +0000 Subject: [PATCH 25/42] ARM: Remove unnecessary subpage workarounds MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit In the ARM per-CPU peripherals (GIC, private timers, SCU, etc), remove workarounds for subpage memory region read/write functions being passed offsets from the start of the page rather than the start of the region. Following commit 5312bd8b3 the masking off of high bits of the address offset is now harmless but unnecessary. Signed-off-by: Peter Maydell Reviewed-by: Andreas Färber --- hw/arm11mpcore.c | 2 -- hw/arm_gic.c | 8 ++++---- hw/arm_mptimer.c | 2 -- 3 files changed, 4 insertions(+), 8 deletions(-) diff --git a/hw/arm11mpcore.c b/hw/arm11mpcore.c index c67b70f3b9..ba6a89d3ed 100644 --- a/hw/arm11mpcore.c +++ b/hw/arm11mpcore.c @@ -42,7 +42,6 @@ static uint64_t mpcore_scu_read(void *opaque, target_phys_addr_t offset, { mpcore_priv_state *s = (mpcore_priv_state *)opaque; int id; - offset &= 0xff; /* SCU */ switch (offset) { case 0x00: /* Control. */ @@ -63,7 +62,6 @@ static void mpcore_scu_write(void *opaque, target_phys_addr_t offset, uint64_t value, unsigned size) { mpcore_priv_state *s = (mpcore_priv_state *)opaque; - offset &= 0xff; /* SCU */ switch (offset) { case 0: /* Control register. */ diff --git a/hw/arm_gic.c b/hw/arm_gic.c index d8a7a190e8..6b34c06a8f 100644 --- a/hw/arm_gic.c +++ b/hw/arm_gic.c @@ -658,14 +658,14 @@ static uint64_t gic_thiscpu_read(void *opaque, target_phys_addr_t addr, unsigned size) { gic_state *s = (gic_state *)opaque; - return gic_cpu_read(s, gic_get_current_cpu(), addr & 0xff); + return gic_cpu_read(s, gic_get_current_cpu(), addr); } static void gic_thiscpu_write(void *opaque, target_phys_addr_t addr, uint64_t value, unsigned size) { gic_state *s = (gic_state *)opaque; - gic_cpu_write(s, gic_get_current_cpu(), addr & 0xff, value); + gic_cpu_write(s, gic_get_current_cpu(), addr, value); } /* Wrappers to read/write the GIC CPU interface for a specific CPU. @@ -677,7 +677,7 @@ static uint64_t gic_do_cpu_read(void *opaque, target_phys_addr_t addr, gic_state **backref = (gic_state **)opaque; gic_state *s = *backref; int id = (backref - s->backref); - return gic_cpu_read(s, id, addr & 0xff); + return gic_cpu_read(s, id, addr); } static void gic_do_cpu_write(void *opaque, target_phys_addr_t addr, @@ -686,7 +686,7 @@ static void gic_do_cpu_write(void *opaque, target_phys_addr_t addr, gic_state **backref = (gic_state **)opaque; gic_state *s = *backref; int id = (backref - s->backref); - gic_cpu_write(s, id, addr & 0xff, value); + gic_cpu_write(s, id, addr, value); } static const MemoryRegionOps gic_thiscpu_ops = { diff --git a/hw/arm_mptimer.c b/hw/arm_mptimer.c index 361e887dec..df7fb4c9bd 100644 --- a/hw/arm_mptimer.c +++ b/hw/arm_mptimer.c @@ -97,7 +97,6 @@ static uint64_t timerblock_read(void *opaque, target_phys_addr_t addr, { timerblock *tb = (timerblock *)opaque; int64_t val; - addr &= 0x1f; switch (addr) { case 0: /* Load */ return tb->load; @@ -126,7 +125,6 @@ static void timerblock_write(void *opaque, target_phys_addr_t addr, { timerblock *tb = (timerblock *)opaque; int64_t old; - addr &= 0x1f; switch (addr) { case 0: /* Load */ tb->load = value; From a10394e1daff859517566b9882d4bdec0f6969ca Mon Sep 17 00:00:00 2001 From: Mitsyanko Igor Date: Wed, 14 Mar 2012 15:37:53 +0000 Subject: [PATCH 26/42] hw/pxa2xx_dma.c: drop target_phys_addr_t usage in device state MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Pxa2xx DMA controller is a 32-bit device and it has no knowledge of system's physical address size, so it should not use target_phys_addr_t in it's state. Convert variables descr, src and dest from type target_phys_addr_t to uint32_t, use VMSTATE_UINT32 instead of VMSTATE_UINTTL for these variables. We can do this safely because: 1) pxa2xx actually has 32-bit physical address size; 2) rest of the code in file never assumes descr, src and dest variables to have size different from uint32_t; 3) we shouldn't have used VMSTATE_UINTTL in the first place because this macro is for target_ulong type (which can be different from target_phys_addr_t). Signed-off-by: Igor Mitsyanko Reviewed-by: Andreas Färber Reviewed-by: Michael Roth Signed-off-by: Peter Maydell --- hw/pxa2xx_dma.c | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/hw/pxa2xx_dma.c b/hw/pxa2xx_dma.c index 8ced0dd8ec..031015400b 100644 --- a/hw/pxa2xx_dma.c +++ b/hw/pxa2xx_dma.c @@ -18,9 +18,9 @@ #define PXA2XX_DMA_NUM_REQUESTS 75 typedef struct { - target_phys_addr_t descr; - target_phys_addr_t src; - target_phys_addr_t dest; + uint32_t descr; + uint32_t src; + uint32_t dest; uint32_t cmd; uint32_t state; int request; @@ -512,9 +512,9 @@ static VMStateDescription vmstate_pxa2xx_dma_chan = { .minimum_version_id = 1, .minimum_version_id_old = 1, .fields = (VMStateField[]) { - VMSTATE_UINTTL(descr, PXA2xxDMAChannel), - VMSTATE_UINTTL(src, PXA2xxDMAChannel), - VMSTATE_UINTTL(dest, PXA2xxDMAChannel), + VMSTATE_UINT32(descr, PXA2xxDMAChannel), + VMSTATE_UINT32(src, PXA2xxDMAChannel), + VMSTATE_UINT32(dest, PXA2xxDMAChannel), VMSTATE_UINT32(cmd, PXA2xxDMAChannel), VMSTATE_UINT32(state, PXA2xxDMAChannel), VMSTATE_INT32(request, PXA2xxDMAChannel), From 27424dcc6804e630602a61229e57e42b14050869 Mon Sep 17 00:00:00 2001 From: Mitsyanko Igor Date: Wed, 14 Mar 2012 15:37:53 +0000 Subject: [PATCH 27/42] hw/pxa2xx_lcd.c: drop target_phys_addr_t usage in device state MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Pxa2xx LCD controller is intended to work with 32-bit bus and it has no knowledge of system's physical address size, so it should not use target_phys_addr_t in it's state. Convert three variables in DMAChannel state from target_phys_addr_t to uint32_t, use VMSTATE_UINT32 instead of VMSTATE_UINTTL for these variables. We can do this safely because: 1) pxa2xx has 32-bit physical address; 2) rest of the code in file never assumes converted variables to have any size different from uint32_t; 3) we shouldn't have used VMSTATE_UINTTL in the first place because this macro is for target_ulong type (which can be different from target_phys_addr_t). Signed-off-by: Igor Mitsyanko Reviewed-by: Andreas Färber Signed-off-by: Peter Maydell --- hw/pxa2xx_lcd.c | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/hw/pxa2xx_lcd.c b/hw/pxa2xx_lcd.c index fcbdfb3fba..ee8bf577cb 100644 --- a/hw/pxa2xx_lcd.c +++ b/hw/pxa2xx_lcd.c @@ -19,15 +19,15 @@ #include "framebuffer.h" struct DMAChannel { - target_phys_addr_t branch; + uint32_t branch; uint8_t up; uint8_t palette[1024]; uint8_t pbuffer[1024]; void (*redraw)(PXA2xxLCDState *s, target_phys_addr_t addr, int *miny, int *maxy); - target_phys_addr_t descriptor; - target_phys_addr_t source; + uint32_t descriptor; + uint32_t source; uint32_t id; uint32_t command; }; @@ -929,11 +929,11 @@ static const VMStateDescription vmstate_dma_channel = { .minimum_version_id = 0, .minimum_version_id_old = 0, .fields = (VMStateField[]) { - VMSTATE_UINTTL(branch, struct DMAChannel), + VMSTATE_UINT32(branch, struct DMAChannel), VMSTATE_UINT8(up, struct DMAChannel), VMSTATE_BUFFER(pbuffer, struct DMAChannel), - VMSTATE_UINTTL(descriptor, struct DMAChannel), - VMSTATE_UINTTL(source, struct DMAChannel), + VMSTATE_UINT32(descriptor, struct DMAChannel), + VMSTATE_UINT32(source, struct DMAChannel), VMSTATE_UINT32(id, struct DMAChannel), VMSTATE_UINT32(command, struct DMAChannel), VMSTATE_END_OF_LIST() From 14dd5faa7e168d70760902c269dc68f3104b8ed6 Mon Sep 17 00:00:00 2001 From: Peter Maydell Date: Wed, 14 Mar 2012 15:37:53 +0000 Subject: [PATCH 28/42] hw/pxa2xx.c: Fix handling of pxa2xx_i2c variable offset within region MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The pxa2xx I2C controller can have its registers at an arbitrary offset within the MemoryRegion it creates. We use this to create two controllers, one which covers a region of size 0x10000 with registers starting at an offset 0x1600 into that region, and a second one which covers a region of size just 0x100 with the registers starting at the base of the region. The implementation of this offsetting uses two qdev properties, "offset" (which sets the offset which must be subtracted from the address to get the offset into the actual register bank) and "size", which is the size of the MemoryRegion. We were actually using "offset" for two purposes: firstly the required one of handling the registers not being at the base of the MemoryRegion, and secondly as a workaround for a deficiency of QEMU. Until commit 5312bd8b3, if a MemoryRegion was mapped at a non-page boundary, the address passed into the read and write functions would be the offset from the start of the page, not the offset from the start of the MemoryRegion. So when calculating the value to set the "offset" qdev property we included a rounding to a page boundary. Following commit 5312bd8b3 MemoryRegion read/write functions are now correctly passed the offset from the base of the region, and our workaround now means we're subtracting too much from addresses, resulting in warnings like "pxa2xx_i2c_read: Bad register 0xffffff90". The fix for this is simply to remove the rounding to a page boundary; this allows us to slightly simplify the expression since base - (base & (~region_size)) == base & region_size The qdev property "offset" itself must remain because it is still performing its primary job of handling register banks not being at the base of the MemoryRegion. Signed-off-by: Peter Maydell Reviewed-by: Andreas Färber --- hw/pxa2xx.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/hw/pxa2xx.c b/hw/pxa2xx.c index f55287774a..1d5c35f174 100644 --- a/hw/pxa2xx.c +++ b/hw/pxa2xx.c @@ -1507,8 +1507,7 @@ PXA2xxI2CState *pxa2xx_i2c_init(target_phys_addr_t base, i2c_dev = sysbus_from_qdev(qdev_create(NULL, "pxa2xx_i2c")); qdev_prop_set_uint32(&i2c_dev->qdev, "size", region_size + 1); - qdev_prop_set_uint32(&i2c_dev->qdev, "offset", - base - (base & (~region_size) & TARGET_PAGE_MASK)); + qdev_prop_set_uint32(&i2c_dev->qdev, "offset", base & region_size); qdev_init_nofail(&i2c_dev->qdev); From 4055299ef0e1c6e4a9b09ce000757b1274129991 Mon Sep 17 00:00:00 2001 From: Kirill Batuzov Date: Fri, 2 Mar 2012 13:22:17 +0400 Subject: [PATCH 29/42] Fix large memory chunks allocation with tcg_malloc. An attempt to allocate a large memory chunk after a small one resulted in circular links in list of pools. It caused the same memory being allocated twice for different arrays. Now pools for large memory chunks are kept in separate list and are freed during pool reset because current allocator can not reuse them. Signed-off-by: Kirill Batuzov Signed-off-by: Blue Swirl --- tcg/tcg.c | 14 +++++++++----- tcg/tcg.h | 2 +- 2 files changed, 10 insertions(+), 6 deletions(-) diff --git a/tcg/tcg.c b/tcg/tcg.c index 531db55f5d..ad2e983c2b 100644 --- a/tcg/tcg.c +++ b/tcg/tcg.c @@ -173,11 +173,9 @@ void *tcg_malloc_internal(TCGContext *s, int size) /* big malloc: insert a new pool (XXX: could optimize) */ p = g_malloc(sizeof(TCGPool) + size); p->size = size; - if (s->pool_current) - s->pool_current->next = p; - else - s->pool_first = p; - p->next = s->pool_current; + p->next = s->pool_first_large; + s->pool_first_large = p; + return p->data; } else { p = s->pool_current; if (!p) { @@ -208,6 +206,12 @@ void *tcg_malloc_internal(TCGContext *s, int size) void tcg_pool_reset(TCGContext *s) { + TCGPool *p, *t; + for (p = s->pool_first_large; p; p = t) { + t = p->next; + g_free(p); + } + s->pool_first_large = NULL; s->pool_cur = s->pool_end = NULL; s->pool_current = NULL; } diff --git a/tcg/tcg.h b/tcg/tcg.h index cc223ea540..92943c11fb 100644 --- a/tcg/tcg.h +++ b/tcg/tcg.h @@ -337,7 +337,7 @@ typedef struct TCGContext TCGContext; struct TCGContext { uint8_t *pool_cur, *pool_end; - TCGPool *pool_first, *pool_current; + TCGPool *pool_first, *pool_current, *pool_first_large; TCGLabel *labels; int nb_labels; TCGTemp *temps; /* globals first, temps after */ From 1329d1896cc627cf71e3833525152ff59dd5113b Mon Sep 17 00:00:00 2001 From: Amos Kong Date: Tue, 13 Mar 2012 14:05:36 +0800 Subject: [PATCH 30/42] vmstate: fix varrays with uint32_t indexes MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit VMSTATE_VARRAY_UINT32() is used in hw/ds1225y.c, and we checked VMS_VARRAY_UINT32 bit of field->flags in vmstate_load_state(), but we don't check this bit in vmstate_save_state(). Signed-off-by: Amos Kong Acked-by: Juan Quintela Acked-by: Hervé Poussineau Signed-off-by: Blue Swirl --- savevm.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/savevm.c b/savevm.c index 80be1ff063..694eaa4f85 100644 --- a/savevm.c +++ b/savevm.c @@ -1486,6 +1486,8 @@ void vmstate_save_state(QEMUFile *f, const VMStateDescription *vmsd, n_elems = field->num; } else if (field->flags & VMS_VARRAY_INT32) { n_elems = *(int32_t *)(opaque+field->num_offset); + } else if (field->flags & VMS_VARRAY_UINT32) { + n_elems = *(uint32_t *)(opaque+field->num_offset); } else if (field->flags & VMS_VARRAY_UINT16) { n_elems = *(uint16_t *)(opaque+field->num_offset); } else if (field->flags & VMS_VARRAY_UINT8) { From 3bf7e40ab9140e577a6e7e17d3f5711b28aed833 Mon Sep 17 00:00:00 2001 From: Avi Kivity Date: Tue, 27 Dec 2011 17:11:20 +0200 Subject: [PATCH 31/42] softfloat: fix for C99 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit C99 appears to consider compound literals as non-constants, and complains when they are used in static initializers. Switch to ordinary initializer syntax. Signed-off-by: Avi Kivity Acked-by: Andreas Färber Reported-by: Andreas Färber Signed-off-by: Blue Swirl --- fpu/softfloat-specialize.h | 8 ++++---- fpu/softfloat.h | 2 ++ 2 files changed, 6 insertions(+), 4 deletions(-) diff --git a/fpu/softfloat-specialize.h b/fpu/softfloat-specialize.h index c5e2dab9f6..490245004f 100644 --- a/fpu/softfloat-specialize.h +++ b/fpu/softfloat-specialize.h @@ -89,8 +89,8 @@ const float64 float64_default_nan = const_float64(LIT64( 0xFFF8000000000000 )); #define floatx80_default_nan_low LIT64( 0xC000000000000000 ) #endif -const floatx80 floatx80_default_nan = make_floatx80(floatx80_default_nan_high, - floatx80_default_nan_low); +const floatx80 floatx80_default_nan + = make_floatx80_init(floatx80_default_nan_high, floatx80_default_nan_low); /*---------------------------------------------------------------------------- | The pattern for a default generated quadruple-precision NaN. The `high' and @@ -104,8 +104,8 @@ const floatx80 floatx80_default_nan = make_floatx80(floatx80_default_nan_high, #define float128_default_nan_low LIT64( 0x0000000000000000 ) #endif -const float128 float128_default_nan = make_float128(float128_default_nan_high, - float128_default_nan_low); +const float128 float128_default_nan + = make_float128_init(float128_default_nan_high, float128_default_nan_low); /*---------------------------------------------------------------------------- | Raises the exceptions specified by `flags'. Floating-point traps can be diff --git a/fpu/softfloat.h b/fpu/softfloat.h index 07c2929613..2ce4110c07 100644 --- a/fpu/softfloat.h +++ b/fpu/softfloat.h @@ -129,6 +129,7 @@ typedef struct { uint16_t high; } floatx80; #define make_floatx80(exp, mant) ((floatx80) { mant, exp }) +#define make_floatx80_init(exp, mant) { .low = mant, .high = exp } typedef struct { #ifdef HOST_WORDS_BIGENDIAN uint64_t high, low; @@ -137,6 +138,7 @@ typedef struct { #endif } float128; #define make_float128(high_, low_) ((float128) { .high = high_, .low = low_ }) +#define make_float128_init(high_, low_) { .high = high_, .low = low_ } /*---------------------------------------------------------------------------- | Software IEC/IEEE floating-point underflow tininess-detection mode. From 69784eaec335d09619639db4da6c1e4770290526 Mon Sep 17 00:00:00 2001 From: Stefan Weil Date: Fri, 16 Mar 2012 23:50:54 +0100 Subject: [PATCH 32/42] w64: Fix data type of next_tb and tcg_qemu_tb_exec next_tb is the numeric value of a tcg target (= QEMU host) address. Using tcg_target_ulong instead of unsigned long shows this and makes the code portable for hosts with an unusual size of long (w64). The type cast '(long)(next_tb & ~3)' was not needed (casting unsigned long to long does not change the bits, and nor does casting long to pointer for most (= all non w64) hosts. It is removed here. Macro or function tcg_qemu_tb_exec is used to set next_tb. The function also returns next_tb. Therefore tcg_qemu_tb_exec must return a tcg_target_ulong. Signed-off-by: Stefan Weil Signed-off-by: Blue Swirl --- cpu-exec.c | 6 +++--- tcg/tcg.h | 2 +- tcg/tci/tcg-target.h | 2 +- tci.c | 4 ++-- 4 files changed, 7 insertions(+), 7 deletions(-) diff --git a/cpu-exec.c b/cpu-exec.c index bd5791f8fa..0fa8325b27 100644 --- a/cpu-exec.c +++ b/cpu-exec.c @@ -55,7 +55,7 @@ void cpu_resume_from_signal(CPUArchState *env, void *puc) static void cpu_exec_nocache(CPUArchState *env, int max_cycles, TranslationBlock *orig_tb) { - unsigned long next_tb; + tcg_target_ulong next_tb; TranslationBlock *tb; /* Should never happen. @@ -186,7 +186,7 @@ int cpu_exec(CPUArchState *env) int ret, interrupt_request; TranslationBlock *tb; uint8_t *tc_ptr; - unsigned long next_tb; + tcg_target_ulong next_tb; if (env->halted) { if (!cpu_has_work(env)) { @@ -565,7 +565,7 @@ int cpu_exec(CPUArchState *env) if ((next_tb & 3) == 2) { /* Instruction counter expired. */ int insns_left; - tb = (TranslationBlock *)(long)(next_tb & ~3); + tb = (TranslationBlock *)(next_tb & ~3); /* Restore PC. */ cpu_pc_from_tb(env, tb); insns_left = env->icount_decr.u32; diff --git a/tcg/tcg.h b/tcg/tcg.h index 92943c11fb..9bc9fc9052 100644 --- a/tcg/tcg.h +++ b/tcg/tcg.h @@ -589,5 +589,5 @@ extern uint8_t code_gen_prologue[]; /* TCG targets may use a different definition of tcg_qemu_tb_exec. */ #if !defined(tcg_qemu_tb_exec) # define tcg_qemu_tb_exec(env, tb_ptr) \ - ((long REGPARM (*)(void *, void *))code_gen_prologue)(env, tb_ptr) + ((tcg_target_ulong REGPARM (*)(void *, void *))code_gen_prologue)(env, tb_ptr) #endif diff --git a/tcg/tci/tcg-target.h b/tcg/tci/tcg-target.h index b61e99aff1..30a0f21596 100644 --- a/tcg/tci/tcg-target.h +++ b/tcg/tci/tcg-target.h @@ -154,7 +154,7 @@ typedef enum { void tci_disas(uint8_t opc); -unsigned long tcg_qemu_tb_exec(CPUArchState *env, uint8_t *tb_ptr); +tcg_target_ulong tcg_qemu_tb_exec(CPUArchState *env, uint8_t *tb_ptr); #define tcg_qemu_tb_exec tcg_qemu_tb_exec static inline void flush_icache_range(tcg_target_ulong start, diff --git a/tci.c b/tci.c index fb9ebef107..70e7bfb759 100644 --- a/tci.c +++ b/tci.c @@ -429,9 +429,9 @@ static bool tci_compare64(uint64_t u0, uint64_t u1, TCGCond condition) } /* Interpret pseudo code in tb. */ -unsigned long tcg_qemu_tb_exec(CPUArchState *cpustate, uint8_t *tb_ptr) +tcg_target_ulong tcg_qemu_tb_exec(CPUArchState *cpustate, uint8_t *tb_ptr) { - unsigned long next_tb = 0; + tcg_target_ulong next_tb = 0; env = cpustate; tci_reg[TCG_AREG0] = (tcg_target_ulong)env; From b21227c499b5939891cdc1e5e6834c92eaf2dee0 Mon Sep 17 00:00:00 2001 From: Blue Swirl Date: Sat, 10 Mar 2012 16:53:47 +0000 Subject: [PATCH 33/42] apb: use normal PCI device header for PBM device PBM has a normal PCI device header, fix. Signed-off-by: Blue Swirl --- hw/apb_pci.c | 1 - 1 file changed, 1 deletion(-) diff --git a/hw/apb_pci.c b/hw/apb_pci.c index 1d25da8da9..b10f31ea3a 100644 --- a/hw/apb_pci.c +++ b/hw/apb_pci.c @@ -444,7 +444,6 @@ static void pbm_pci_host_class_init(ObjectClass *klass, void *data) k->vendor_id = PCI_VENDOR_ID_SUN; k->device_id = PCI_DEVICE_ID_SUN_SABRE; k->class_id = PCI_CLASS_BRIDGE_HOST; - k->is_bridge = 1; } static TypeInfo pbm_pci_host_info = { From 89aaf60dedbe0e6415acfe816e02b538e5c54e68 Mon Sep 17 00:00:00 2001 From: Blue Swirl Date: Sat, 10 Mar 2012 17:55:05 +0000 Subject: [PATCH 34/42] sparc: reset CPU state on reset Not strictly accurate for Sparc64 but avoid confusing Valgrind. Reported-by: Michael S. Tsirkin Signed-off-by: Blue Swirl --- target-sparc/cpu.h | 5 +++-- target-sparc/cpu_init.c | 1 + 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/target-sparc/cpu.h b/target-sparc/cpu.h index 86f9de6cfe..887adc3631 100644 --- a/target-sparc/cpu.h +++ b/target-sparc/cpu.h @@ -415,14 +415,15 @@ struct CPUSPARCState { #if !defined(TARGET_SPARC64) int psref; /* enable fpu */ #endif - target_ulong version; int interrupt_index; - uint32_t nwindows; /* NOTE: we allow 8 more registers to handle wrapping */ target_ulong regbase[MAX_NWINDOWS * 16 + 8]; CPU_COMMON + target_ulong version; + uint32_t nwindows; + /* MMU regs */ #if defined(TARGET_SPARC64) uint64_t lsu; diff --git a/target-sparc/cpu_init.c b/target-sparc/cpu_init.c index 29132fb995..5c03f0b893 100644 --- a/target-sparc/cpu_init.c +++ b/target-sparc/cpu_init.c @@ -30,6 +30,7 @@ void cpu_state_reset(CPUSPARCState *env) log_cpu_state(env, 0); } + memset(env, 0, offsetof(CPUSPARCState, breakpoints)); tlb_flush(env, 1); env->cwp = 0; #ifndef TARGET_SPARC64 From 361dea401f529fc136aaeb49c82b2a5bb7faa316 Mon Sep 17 00:00:00 2001 From: Blue Swirl Date: Sat, 10 Mar 2012 20:37:00 +0000 Subject: [PATCH 35/42] sparc64: implement PCI and ISA irqs Generate correct trap for external interrupts. Map PCI and ISA IRQs to RIC/UltraSPARC-IIi interrupt vectors. Signed-off-by: Blue Swirl --- hw/apb_pci.c | 48 +++++++++++++++++++++++--------- hw/apb_pci.h | 3 +- hw/sun4u.c | 57 ++++++++++++++++++++++++++------------ target-sparc/cpu.h | 3 ++ target-sparc/ldst_helper.c | 20 +++++++++---- 5 files changed, 93 insertions(+), 38 deletions(-) diff --git a/hw/apb_pci.c b/hw/apb_pci.c index b10f31ea3a..7e28808ec4 100644 --- a/hw/apb_pci.c +++ b/hw/apb_pci.c @@ -66,6 +66,8 @@ do { printf("APB: " fmt , ## __VA_ARGS__); } while (0) #define RESET_WCMASK 0x98000000 #define RESET_WMASK 0x60000000 +#define MAX_IVEC 0x30 + typedef struct APBState { SysBusDevice busdev; PCIBus *bus; @@ -77,7 +79,8 @@ typedef struct APBState { uint32_t pci_control[16]; uint32_t pci_irq_map[8]; uint32_t obio_irq_map[32]; - qemu_irq pci_irqs[32]; + qemu_irq *pbm_irqs; + qemu_irq *ivec_irqs; uint32_t reset_control; unsigned int nr_resets; } APBState; @@ -87,7 +90,7 @@ static void apb_config_writel (void *opaque, target_phys_addr_t addr, { APBState *s = opaque; - APB_DPRINTF("%s: addr " TARGET_FMT_lx " val %x\n", __func__, addr, val); + APB_DPRINTF("%s: addr " TARGET_FMT_lx " val %" PRIx64 "\n", __func__, addr, val); switch (addr & 0xffff) { case 0x30 ... 0x4f: /* DMA error registers */ @@ -104,6 +107,12 @@ static void apb_config_writel (void *opaque, target_phys_addr_t addr, s->pci_irq_map[(addr & 0x3f) >> 3] |= val & ~PBM_PCI_IMR_MASK; } break; + case 0x1000 ... 0x1080: /* OBIO interrupt control */ + if (addr & 4) { + s->obio_irq_map[(addr & 0xff) >> 3] &= PBM_PCI_IMR_MASK; + s->obio_irq_map[(addr & 0xff) >> 3] |= val & ~PBM_PCI_IMR_MASK; + } + break; case 0x2000 ... 0x202f: /* PCI control */ s->pci_control[(addr & 0x3f) >> 2] = val; break; @@ -154,6 +163,13 @@ static uint64_t apb_config_readl (void *opaque, val = 0; } break; + case 0x1000 ... 0x1080: /* OBIO interrupt control */ + if (addr & 4) { + val = s->obio_irq_map[(addr & 0xff) >> 3]; + } else { + val = 0; + } + break; case 0x2000 ... 0x202f: /* PCI control */ val = s->pci_control[(addr & 0x3f) >> 2]; break; @@ -190,7 +206,7 @@ static void apb_pci_config_write(void *opaque, target_phys_addr_t addr, APBState *s = opaque; val = qemu_bswap_len(val, size); - APB_DPRINTF("%s: addr " TARGET_FMT_lx " val %x\n", __func__, addr, val); + APB_DPRINTF("%s: addr " TARGET_FMT_lx " val %" PRIx64 "\n", __func__, addr, val); pci_data_write(s->bus, addr, val, size); } @@ -280,10 +296,19 @@ static void pci_apb_set_irq(void *opaque, int irq_num, int level) if (irq_num < 32) { if (s->pci_irq_map[irq_num >> 2] & PBM_PCI_IMR_ENABLED) { APB_DPRINTF("%s: set irq %d level %d\n", __func__, irq_num, level); - qemu_set_irq(s->pci_irqs[irq_num], level); + qemu_set_irq(s->ivec_irqs[irq_num], level); } else { APB_DPRINTF("%s: not enabled: lower irq %d\n", __func__, irq_num); - qemu_irq_lower(s->pci_irqs[irq_num]); + qemu_irq_lower(s->ivec_irqs[irq_num]); + } + } else { + /* OBIO IRQ map onto the next 16 INO. */ + if (s->obio_irq_map[irq_num - 32] & PBM_PCI_IMR_ENABLED) { + APB_DPRINTF("%s: set irq %d level %d\n", __func__, irq_num, level); + qemu_set_irq(s->ivec_irqs[irq_num], level); + } else { + APB_DPRINTF("%s: not enabled: lower irq %d\n", __func__, irq_num); + qemu_irq_lower(s->ivec_irqs[irq_num]); } } } @@ -316,12 +341,12 @@ static int apb_pci_bridge_initfn(PCIDevice *dev) PCIBus *pci_apb_init(target_phys_addr_t special_base, target_phys_addr_t mem_base, - qemu_irq *pic, PCIBus **bus2, PCIBus **bus3) + qemu_irq *ivec_irqs, PCIBus **bus2, PCIBus **bus3, + qemu_irq **pbm_irqs) { DeviceState *dev; SysBusDevice *s; APBState *d; - unsigned int i; PCIDevice *pci_dev; PCIBridge *br; @@ -346,9 +371,8 @@ PCIBus *pci_apb_init(target_phys_addr_t special_base, get_system_io(), 0, 32); - for (i = 0; i < 32; i++) { - sysbus_connect_irq(s, i, pic[i]); - } + *pbm_irqs = d->pbm_irqs; + d->ivec_irqs = ivec_irqs; pci_create_simple(d->bus, 0, "pbm-pci"); @@ -402,9 +426,7 @@ static int pci_pbm_init_device(SysBusDevice *dev) for (i = 0; i < 8; i++) { s->pci_irq_map[i] = (0x1f << 6) | (i << 2); } - for (i = 0; i < 32; i++) { - sysbus_init_irq(dev, &s->pci_irqs[i]); - } + s->pbm_irqs = qemu_allocate_irqs(pci_apb_set_irq, s, MAX_IVEC); /* apb_config */ memory_region_init_io(&s->apb_config, &apb_config_ops, s, "apb-config", diff --git a/hw/apb_pci.h b/hw/apb_pci.h index 8869f9d326..55f7c4c3b2 100644 --- a/hw/apb_pci.h +++ b/hw/apb_pci.h @@ -5,5 +5,6 @@ PCIBus *pci_apb_init(target_phys_addr_t special_base, target_phys_addr_t mem_base, - qemu_irq *pic, PCIBus **bus2, PCIBus **bus3); + qemu_irq *ivec_irqs, PCIBus **bus2, PCIBus **bus3, + qemu_irq **pbm_irqs); #endif diff --git a/hw/sun4u.c b/hw/sun4u.c index c32eddb31f..237e20c1bf 100644 --- a/hw/sun4u.c +++ b/hw/sun4u.c @@ -81,7 +81,7 @@ #define FW_CFG_SPARC64_HEIGHT (FW_CFG_ARCH_LOCAL + 0x01) #define FW_CFG_SPARC64_DEPTH (FW_CFG_ARCH_LOCAL + 0x02) -#define MAX_PILS 16 +#define IVEC_MAX 0x30 #define TICK_MAX 0x7fffffffffffffffULL @@ -304,18 +304,24 @@ static void cpu_kick_irq(CPUSPARCState *env) qemu_cpu_kick(env); } -static void cpu_set_irq(void *opaque, int irq, int level) +static void cpu_set_ivec_irq(void *opaque, int irq, int level) { CPUSPARCState *env = opaque; if (level) { - CPUIRQ_DPRINTF("Raise CPU IRQ %d\n", irq); - env->pil_in |= 1 << irq; - cpu_kick_irq(env); - } else { - CPUIRQ_DPRINTF("Lower CPU IRQ %d\n", irq); - env->pil_in &= ~(1 << irq); - cpu_check_irqs(env); + CPUIRQ_DPRINTF("Raise IVEC IRQ %d\n", irq); + env->interrupt_index = TT_IVEC; + env->pil_in |= 1 << 5; + env->ivec_status |= 0x20; + env->ivec_data[0] = (0x1f << 6) | irq; + env->ivec_data[1] = 0; + env->ivec_data[2] = 0; + cpu_interrupt(env, CPU_INTERRUPT_HARD); + } else { + CPUIRQ_DPRINTF("Lower IVEC IRQ %d\n", irq); + env->pil_in &= ~(1 << 5); + env->ivec_status &= ~0x20; + cpu_reset_interrupt(env, CPU_INTERRUPT_HARD); } } @@ -521,13 +527,29 @@ void cpu_tick_set_limit(CPUTimer *timer, uint64_t limit) } } -static void dummy_isa_irq_handler(void *opaque, int n, int level) +static void isa_irq_handler(void *opaque, int n, int level) { + static const int isa_irq_to_ivec[16] = { + [1] = 0x29, /* keyboard */ + [4] = 0x2b, /* serial */ + [6] = 0x27, /* floppy */ + [7] = 0x22, /* parallel */ + [12] = 0x2a, /* mouse */ + }; + qemu_irq *irqs = opaque; + int ivec; + + assert(n < 16); + ivec = isa_irq_to_ivec[n]; + EBUS_DPRINTF("Set ISA IRQ %d level %d -> ivec 0x%x\n", n, level, ivec); + if (ivec) { + qemu_set_irq(irqs[ivec], level); + } } /* EBUS (Eight bit bus) bridge */ static ISABus * -pci_ebus_init(PCIBus *bus, int devfn) +pci_ebus_init(PCIBus *bus, int devfn, qemu_irq *irqs) { qemu_irq *isa_irq; PCIDevice *pci_dev; @@ -536,7 +558,7 @@ pci_ebus_init(PCIBus *bus, int devfn) pci_dev = pci_create_simple(bus, devfn, "ebus"); isa_bus = DO_UPCAST(ISABus, qbus, qdev_get_child_bus(&pci_dev->qdev, "isa.0")); - isa_irq = qemu_allocate_irqs(dummy_isa_irq_handler, NULL, 16); + isa_irq = qemu_allocate_irqs(isa_irq_handler, irqs, 16); isa_bus_irqs(isa_bus, isa_irq); return isa_bus; } @@ -761,7 +783,7 @@ static void sun4uv_init(MemoryRegion *address_space_mem, long initrd_size, kernel_size; PCIBus *pci_bus, *pci_bus2, *pci_bus3; ISABus *isa_bus; - qemu_irq *irq; + qemu_irq *ivec_irqs, *pbm_irqs; DriveInfo *hd[MAX_IDE_BUS * MAX_IDE_DEVS]; DriveInfo *fd[MAX_FD]; void *fw_cfg; @@ -774,14 +796,13 @@ static void sun4uv_init(MemoryRegion *address_space_mem, prom_init(hwdef->prom_addr, bios_name); - - irq = qemu_allocate_irqs(cpu_set_irq, env, MAX_PILS); - pci_bus = pci_apb_init(APB_SPECIAL_BASE, APB_MEM_BASE, irq, &pci_bus2, - &pci_bus3); + ivec_irqs = qemu_allocate_irqs(cpu_set_ivec_irq, env, IVEC_MAX); + pci_bus = pci_apb_init(APB_SPECIAL_BASE, APB_MEM_BASE, ivec_irqs, &pci_bus2, + &pci_bus3, &pbm_irqs); pci_vga_init(pci_bus); // XXX Should be pci_bus3 - isa_bus = pci_ebus_init(pci_bus, -1); + isa_bus = pci_ebus_init(pci_bus, -1, pbm_irqs); i = 0; if (hwdef->console_serial_base) { diff --git a/target-sparc/cpu.h b/target-sparc/cpu.h index 887adc3631..f638457a89 100644 --- a/target-sparc/cpu.h +++ b/target-sparc/cpu.h @@ -493,6 +493,9 @@ struct CPUSPARCState { /* UA 2005 hyperprivileged registers */ uint64_t hpstate, htstate[MAXTL_MAX], hintp, htba, hver, hstick_cmpr, ssr; CPUTimer *hstick; // UA 2005 + /* Interrupt vector registers */ + uint64_t ivec_status; + uint64_t ivec_data[3]; uint32_t softint; #define SOFTINT_TIMER 1 #define SOFTINT_STIMER (1 << 16) diff --git a/target-sparc/ldst_helper.c b/target-sparc/ldst_helper.c index 48d433c571..97afdd32a5 100644 --- a/target-sparc/ldst_helper.c +++ b/target-sparc/ldst_helper.c @@ -1526,6 +1526,19 @@ uint64_t helper_ld_asi(target_ulong addr, int asi, int size, int sign) ret = env->dtlb[reg].tag; break; } + case 0x48: /* Interrupt dispatch, RO */ + break; + case 0x49: /* Interrupt data receive */ + ret = env->ivec_status; + break; + case 0x7f: /* Incoming interrupt vector, RO */ + { + int reg = (addr >> 4) & 0x3; + if (reg < 3) { + ret = env->ivec_data[reg]; + } + break; + } case 0x46: /* D-cache data */ case 0x47: /* D-cache tag access */ case 0x4b: /* E-cache error enable */ @@ -1540,11 +1553,6 @@ uint64_t helper_ld_asi(target_ulong addr, int asi, int size, int sign) case 0x7e: /* E-cache tag */ break; case 0x5b: /* D-MMU data pointer */ - case 0x48: /* Interrupt dispatch, RO */ - case 0x49: /* Interrupt data receive */ - case 0x7f: /* Incoming interrupt vector, RO */ - /* XXX */ - break; case 0x54: /* I-MMU data in, WO */ case 0x57: /* I-MMU demap, WO */ case 0x5c: /* D-MMU data in, WO */ @@ -1954,7 +1962,7 @@ void helper_st_asi(target_ulong addr, target_ulong val, int asi, int size) demap_tlb(env->dtlb, addr, "dmmu", env); return; case 0x49: /* Interrupt data receive */ - /* XXX */ + env->ivec_status = val & 0x20; return; case 0x46: /* D-cache data */ case 0x47: /* D-cache tag access */ From 6a18ae2d2947532d5c26439548afa0481c4529f9 Mon Sep 17 00:00:00 2001 From: Blue Swirl Date: Wed, 15 Feb 2012 18:02:32 +0000 Subject: [PATCH 36/42] i386: Remove REGPARM Use stack based calling convention (GCC default) for interfacing with generated code instead of register based convention (regparm(3)). Signed-off-by: Blue Swirl --- osdep.h | 6 --- softmmu_defs.h | 32 ++++++------ softmmu_template.h | 8 ++- tcg/i386/tcg-target.c | 112 +++++++++++++++++++++--------------------- tcg/ppc/tcg-target.h | 2 +- tcg/tcg.c | 14 ------ tcg/tcg.h | 7 +-- 7 files changed, 77 insertions(+), 104 deletions(-) diff --git a/osdep.h b/osdep.h index 0350383711..156666e0ee 100644 --- a/osdep.h +++ b/osdep.h @@ -70,12 +70,6 @@ #define inline always_inline #endif -#ifdef __i386__ -#define REGPARM __attribute((regparm(3))) -#else -#define REGPARM -#endif - #define qemu_printf printf int qemu_daemon(int nochdir, int noclose); diff --git a/softmmu_defs.h b/softmmu_defs.h index c5a2bcd3e2..d47d30d711 100644 --- a/softmmu_defs.h +++ b/softmmu_defs.h @@ -9,22 +9,22 @@ #ifndef SOFTMMU_DEFS_H #define SOFTMMU_DEFS_H -uint8_t REGPARM __ldb_mmu(target_ulong addr, int mmu_idx); -void REGPARM __stb_mmu(target_ulong addr, uint8_t val, int mmu_idx); -uint16_t REGPARM __ldw_mmu(target_ulong addr, int mmu_idx); -void REGPARM __stw_mmu(target_ulong addr, uint16_t val, int mmu_idx); -uint32_t REGPARM __ldl_mmu(target_ulong addr, int mmu_idx); -void REGPARM __stl_mmu(target_ulong addr, uint32_t val, int mmu_idx); -uint64_t REGPARM __ldq_mmu(target_ulong addr, int mmu_idx); -void REGPARM __stq_mmu(target_ulong addr, uint64_t val, int mmu_idx); +uint8_t __ldb_mmu(target_ulong addr, int mmu_idx); +void __stb_mmu(target_ulong addr, uint8_t val, int mmu_idx); +uint16_t __ldw_mmu(target_ulong addr, int mmu_idx); +void __stw_mmu(target_ulong addr, uint16_t val, int mmu_idx); +uint32_t __ldl_mmu(target_ulong addr, int mmu_idx); +void __stl_mmu(target_ulong addr, uint32_t val, int mmu_idx); +uint64_t __ldq_mmu(target_ulong addr, int mmu_idx); +void __stq_mmu(target_ulong addr, uint64_t val, int mmu_idx); -uint8_t REGPARM __ldb_cmmu(target_ulong addr, int mmu_idx); -void REGPARM __stb_cmmu(target_ulong addr, uint8_t val, int mmu_idx); -uint16_t REGPARM __ldw_cmmu(target_ulong addr, int mmu_idx); -void REGPARM __stw_cmmu(target_ulong addr, uint16_t val, int mmu_idx); -uint32_t REGPARM __ldl_cmmu(target_ulong addr, int mmu_idx); -void REGPARM __stl_cmmu(target_ulong addr, uint32_t val, int mmu_idx); -uint64_t REGPARM __ldq_cmmu(target_ulong addr, int mmu_idx); -void REGPARM __stq_cmmu(target_ulong addr, uint64_t val, int mmu_idx); +uint8_t __ldb_cmmu(target_ulong addr, int mmu_idx); +void __stb_cmmu(target_ulong addr, uint8_t val, int mmu_idx); +uint16_t __ldw_cmmu(target_ulong addr, int mmu_idx); +void __stw_cmmu(target_ulong addr, uint16_t val, int mmu_idx); +uint32_t __ldl_cmmu(target_ulong addr, int mmu_idx); +void __stl_cmmu(target_ulong addr, uint32_t val, int mmu_idx); +uint64_t __ldq_cmmu(target_ulong addr, int mmu_idx); +void __stq_cmmu(target_ulong addr, uint64_t val, int mmu_idx); #endif diff --git a/softmmu_template.h b/softmmu_template.h index e3950204cd..d633bb5558 100644 --- a/softmmu_template.h +++ b/softmmu_template.h @@ -89,8 +89,7 @@ static inline DATA_TYPE glue(io_read, SUFFIX)(target_phys_addr_t physaddr, } /* handle all cases except unaligned access which span two pages */ -DATA_TYPE REGPARM glue(glue(__ld, SUFFIX), MMUSUFFIX)(target_ulong addr, - int mmu_idx) +DATA_TYPE glue(glue(__ld, SUFFIX), MMUSUFFIX)(target_ulong addr, int mmu_idx) { DATA_TYPE res; int index; @@ -232,9 +231,8 @@ static inline void glue(io_write, SUFFIX)(target_phys_addr_t physaddr, #endif /* SHIFT > 2 */ } -void REGPARM glue(glue(__st, SUFFIX), MMUSUFFIX)(target_ulong addr, - DATA_TYPE val, - int mmu_idx) +void glue(glue(__st, SUFFIX), MMUSUFFIX)(target_ulong addr, DATA_TYPE val, + int mmu_idx) { target_phys_addr_t ioaddr; unsigned long addend; diff --git a/tcg/i386/tcg-target.c b/tcg/i386/tcg-target.c index fafd900c5a..c4e940da5b 100644 --- a/tcg/i386/tcg-target.c +++ b/tcg/i386/tcg-target.c @@ -116,17 +116,7 @@ static inline int tcg_target_get_call_iarg_regs_count(int flags) return 6; } - flags &= TCG_CALL_TYPE_MASK; - switch(flags) { - case TCG_CALL_TYPE_STD: - return 0; - case TCG_CALL_TYPE_REGPARM_1: - case TCG_CALL_TYPE_REGPARM_2: - case TCG_CALL_TYPE_REGPARM: - return flags - TCG_CALL_TYPE_REGPARM_1 + 1; - default: - tcg_abort(); - } + return 0; } /* parse target specific constraints */ @@ -1148,7 +1138,12 @@ static void tcg_out_qemu_ld(TCGContext *s, const TCGArg *args, int data_reg, data_reg2 = 0; int addrlo_idx; #if defined(CONFIG_SOFTMMU) - int mem_index, s_bits, arg_idx; + int mem_index, s_bits; +#if TCG_TARGET_REG_BITS == 64 + int arg_idx; +#else + int stack_adjust; +#endif uint8_t *label_ptr[3]; #endif @@ -1184,16 +1179,33 @@ static void tcg_out_qemu_ld(TCGContext *s, const TCGArg *args, } /* XXX: move that code at the end of the TB */ +#if TCG_TARGET_REG_BITS == 32 + tcg_out_pushi(s, mem_index); + stack_adjust = 4; + if (TARGET_LONG_BITS == 64) { + tcg_out_push(s, args[addrlo_idx + 1]); + stack_adjust += 4; + } + tcg_out_push(s, args[addrlo_idx]); + stack_adjust += 4; +#else /* The first argument is already loaded with addrlo. */ arg_idx = 1; - if (TCG_TARGET_REG_BITS == 32 && TARGET_LONG_BITS == 64) { - tcg_out_mov(s, TCG_TYPE_I32, tcg_target_call_iarg_regs[arg_idx++], - args[addrlo_idx + 1]); - } tcg_out_movi(s, TCG_TYPE_I32, tcg_target_call_iarg_regs[arg_idx], mem_index); +#endif + tcg_out_calli(s, (tcg_target_long)qemu_ld_helpers[s_bits]); +#if TCG_TARGET_REG_BITS == 32 + if (stack_adjust == (TCG_TARGET_REG_BITS / 8)) { + /* Pop and discard. This is 2 bytes smaller than the add. */ + tcg_out_pop(s, TCG_REG_ECX); + } else if (stack_adjust != 0) { + tcg_out_addi(s, TCG_REG_CALL_STACK, stack_adjust); + } +#endif + switch(opc) { case 0 | 4: tcg_out_ext8s(s, data_reg, TCG_REG_EAX, P_REXW); @@ -1359,45 +1371,27 @@ static void tcg_out_qemu_st(TCGContext *s, const TCGArg *args, } /* XXX: move that code at the end of the TB */ - if (TCG_TARGET_REG_BITS == 64) { - tcg_out_mov(s, (opc == 3 ? TCG_TYPE_I64 : TCG_TYPE_I32), - TCG_REG_RSI, data_reg); - tcg_out_movi(s, TCG_TYPE_I32, TCG_REG_RDX, mem_index); - stack_adjust = 0; - } else if (TARGET_LONG_BITS == 32) { - tcg_out_mov(s, TCG_TYPE_I32, TCG_REG_EDX, data_reg); - if (opc == 3) { - tcg_out_mov(s, TCG_TYPE_I32, TCG_REG_ECX, data_reg2); - tcg_out_pushi(s, mem_index); - stack_adjust = 4; - } else { - tcg_out_movi(s, TCG_TYPE_I32, TCG_REG_ECX, mem_index); - stack_adjust = 0; - } - } else { - if (opc == 3) { - tcg_out_mov(s, TCG_TYPE_I32, TCG_REG_EDX, args[addrlo_idx + 1]); - tcg_out_pushi(s, mem_index); - tcg_out_push(s, data_reg2); - tcg_out_push(s, data_reg); - stack_adjust = 12; - } else { - tcg_out_mov(s, TCG_TYPE_I32, TCG_REG_EDX, args[addrlo_idx + 1]); - switch(opc) { - case 0: - tcg_out_ext8u(s, TCG_REG_ECX, data_reg); - break; - case 1: - tcg_out_ext16u(s, TCG_REG_ECX, data_reg); - break; - case 2: - tcg_out_mov(s, TCG_TYPE_I32, TCG_REG_ECX, data_reg); - break; - } - tcg_out_pushi(s, mem_index); - stack_adjust = 4; - } +#if TCG_TARGET_REG_BITS == 32 + tcg_out_pushi(s, mem_index); + stack_adjust = 4; + if (opc == 3) { + tcg_out_push(s, data_reg2); + stack_adjust += 4; } + tcg_out_push(s, data_reg); + stack_adjust += 4; + if (TARGET_LONG_BITS == 64) { + tcg_out_push(s, args[addrlo_idx + 1]); + stack_adjust += 4; + } + tcg_out_push(s, args[addrlo_idx]); + stack_adjust += 4; +#else + tcg_out_mov(s, (opc == 3 ? TCG_TYPE_I64 : TCG_TYPE_I32), + TCG_REG_RSI, data_reg); + tcg_out_movi(s, TCG_TYPE_I32, TCG_REG_RDX, mem_index); + stack_adjust = 0; +#endif tcg_out_calli(s, (tcg_target_long)qemu_st_helpers[s_bits]); @@ -1962,9 +1956,15 @@ static void tcg_target_qemu_prologue(TCGContext *s) tcg_out_push(s, tcg_target_callee_save_regs[i]); } - tcg_out_addi(s, TCG_REG_ESP, -stack_addend); - +#if TCG_TARGET_REG_BITS == 32 + tcg_out_ld(s, TCG_TYPE_PTR, TCG_AREG0, TCG_REG_ESP, + (ARRAY_SIZE(tcg_target_callee_save_regs) + 1) * 4); + tcg_out_ld(s, TCG_TYPE_PTR, tcg_target_call_iarg_regs[1], TCG_REG_ESP, + (ARRAY_SIZE(tcg_target_callee_save_regs) + 2) * 4); +#else tcg_out_mov(s, TCG_TYPE_PTR, TCG_AREG0, tcg_target_call_iarg_regs[0]); +#endif + tcg_out_addi(s, TCG_REG_ESP, -stack_addend); /* jmp *tb. */ tcg_out_modrm(s, OPC_GRP5, EXT5_JMPN_Ev, tcg_target_call_iarg_regs[1]); diff --git a/tcg/ppc/tcg-target.h b/tcg/ppc/tcg-target.h index 3f22aaac9d..2f37fd289b 100644 --- a/tcg/ppc/tcg-target.h +++ b/tcg/ppc/tcg-target.h @@ -98,5 +98,5 @@ typedef enum { #define TCG_TARGET_HAS_GUEST_BASE #define tcg_qemu_tb_exec(env, tb_ptr) \ - ((long REGPARM __attribute__ ((longcall)) \ + ((long __attribute__ ((longcall)) \ (*)(void *, void *))code_gen_prologue)(env, tb_ptr) diff --git a/tcg/tcg.c b/tcg/tcg.c index ad2e983c2b..ccfcd1abe1 100644 --- a/tcg/tcg.c +++ b/tcg/tcg.c @@ -594,9 +594,6 @@ void tcg_register_helper(void *func, const char *name) void tcg_gen_callN(TCGContext *s, TCGv_ptr func, unsigned int flags, int sizemask, TCGArg ret, int nargs, TCGArg *args) { -#if defined(TCG_TARGET_I386) && TCG_TARGET_REG_BITS < 64 - int call_type; -#endif int i; int real_args; int nb_rets; @@ -621,9 +618,6 @@ void tcg_gen_callN(TCGContext *s, TCGv_ptr func, unsigned int flags, *gen_opc_ptr++ = INDEX_op_call; nparam = gen_opparam_ptr++; -#if defined(TCG_TARGET_I386) && TCG_TARGET_REG_BITS < 64 - call_type = (flags & TCG_CALL_TYPE_MASK); -#endif if (ret != TCG_CALL_DUMMY_ARG) { #if TCG_TARGET_REG_BITS < 64 if (sizemask & 1) { @@ -649,14 +643,6 @@ void tcg_gen_callN(TCGContext *s, TCGv_ptr func, unsigned int flags, #if TCG_TARGET_REG_BITS < 64 int is_64bit = sizemask & (1 << (i+1)*2); if (is_64bit) { -#ifdef TCG_TARGET_I386 - /* REGPARM case: if the third parameter is 64 bit, it is - allocated on the stack */ - if (i == 2 && call_type == TCG_CALL_TYPE_REGPARM) { - call_type = TCG_CALL_TYPE_REGPARM_2; - flags = (flags & ~TCG_CALL_TYPE_MASK) | call_type; - } -#endif #ifdef TCG_TARGET_CALL_ALIGN_ARGS /* some targets want aligned 64 bit args */ if (real_args & 1) { diff --git a/tcg/tcg.h b/tcg/tcg.h index 9bc9fc9052..5f6c647ea5 100644 --- a/tcg/tcg.h +++ b/tcg/tcg.h @@ -252,11 +252,6 @@ typedef int TCGv_i64; #define TCGV_UNUSED_I64(x) x = MAKE_TCGV_I64(-1) /* call flags */ -#define TCG_CALL_TYPE_MASK 0x000f -#define TCG_CALL_TYPE_STD 0x0000 /* standard C call */ -#define TCG_CALL_TYPE_REGPARM_1 0x0001 /* i386 style regparm call (1 reg) */ -#define TCG_CALL_TYPE_REGPARM_2 0x0002 /* i386 style regparm call (2 regs) */ -#define TCG_CALL_TYPE_REGPARM 0x0003 /* i386 style regparm call (3 regs) */ /* A pure function only reads its arguments and TCG global variables and cannot raise exceptions. Hence a call to a pure function can be safely suppressed if the return value is not used. */ @@ -589,5 +584,5 @@ extern uint8_t code_gen_prologue[]; /* TCG targets may use a different definition of tcg_qemu_tb_exec. */ #if !defined(tcg_qemu_tb_exec) # define tcg_qemu_tb_exec(env, tb_ptr) \ - ((tcg_target_ulong REGPARM (*)(void *, void *))code_gen_prologue)(env, tb_ptr) + ((tcg_target_ulong (*)(void *, void *))code_gen_prologue)(env, tb_ptr) #endif From e141ab52d2ea5d0bc6ad3b1ad32841127ca04adc Mon Sep 17 00:00:00 2001 From: Blue Swirl Date: Sun, 18 Sep 2011 14:55:46 +0000 Subject: [PATCH 37/42] softmmu templates: optionally pass CPUState to memory access functions Optionally, make memory access helpers take a parameter for CPUState instead of relying on global env. On most targets, perform simple moves to reorder registers. On i386, switch from regparm(3) calling convention to standard stack-based version. Signed-off-by: Blue Swirl --- cpu-all.h | 9 +++++ exec-all.h | 2 + exec.c | 4 ++ softmmu_defs.h | 28 ++++++++++++++ softmmu_header.h | 60 +++++++++++++++++++++++------- softmmu_template.h | 84 ++++++++++++++++++++++++++++-------------- tcg/arm/tcg-target.c | 53 ++++++++++++++++++++++++++ tcg/hppa/tcg-target.c | 44 ++++++++++++++++++++++ tcg/i386/tcg-target.c | 57 ++++++++++++++++++++++++++++ tcg/ia64/tcg-target.c | 46 +++++++++++++++++++++++ tcg/mips/tcg-target.c | 44 ++++++++++++++++++++++ tcg/ppc/tcg-target.c | 45 ++++++++++++++++++++++ tcg/ppc64/tcg-target.c | 44 ++++++++++++++++++++++ tcg/s390/tcg-target.c | 44 ++++++++++++++++++++++ tcg/sparc/tcg-target.c | 50 +++++++++++++++++++++++-- tcg/tci/tcg-target.c | 6 +++ 16 files changed, 576 insertions(+), 44 deletions(-) diff --git a/cpu-all.h b/cpu-all.h index 8ad1ec7a44..9621c3c92e 100644 --- a/cpu-all.h +++ b/cpu-all.h @@ -259,12 +259,21 @@ extern unsigned long reserved_va; #define stfl(p, v) stfl_raw(p, v) #define stfq(p, v) stfq_raw(p, v) +#ifndef CONFIG_TCG_PASS_AREG0 #define ldub_code(p) ldub_raw(p) #define ldsb_code(p) ldsb_raw(p) #define lduw_code(p) lduw_raw(p) #define ldsw_code(p) ldsw_raw(p) #define ldl_code(p) ldl_raw(p) #define ldq_code(p) ldq_raw(p) +#else +#define cpu_ldub_code(env1, p) ldub_raw(p) +#define cpu_ldsb_code(env1, p) ldsb_raw(p) +#define cpu_lduw_code(env1, p) lduw_raw(p) +#define cpu_ldsw_code(env1, p) ldsw_raw(p) +#define cpu_ldl_code(env1, p) ldl_raw(p) +#define cpu_ldq_code(env1, p) ldq_raw(p) +#endif #define ldub_kernel(p) ldub_raw(p) #define ldsb_kernel(p) ldsb_raw(p) diff --git a/exec-all.h b/exec-all.h index 8fca67b117..93a5b22c1c 100644 --- a/exec-all.h +++ b/exec-all.h @@ -312,7 +312,9 @@ void tlb_fill(CPUArchState *env1, target_ulong addr, int is_write, int mmu_idx, #define ACCESS_TYPE (NB_MMU_MODES + 1) #define MEMSUFFIX _code +#ifndef CONFIG_TCG_PASS_AREG0 #define env cpu_single_env +#endif #define DATA_SIZE 1 #include "softmmu_header.h" diff --git a/exec.c b/exec.c index 8fd50a1c4b..be392e2764 100644 --- a/exec.c +++ b/exec.c @@ -4595,7 +4595,11 @@ tb_page_addr_t get_page_addr_code(CPUArchState *env1, target_ulong addr) mmu_idx = cpu_mmu_index(env1); if (unlikely(env1->tlb_table[mmu_idx][page_index].addr_code != (addr & TARGET_PAGE_MASK))) { +#ifdef CONFIG_TCG_PASS_AREG0 + cpu_ldub_code(env1, addr); +#else ldub_code(addr); +#endif } pd = env1->iotlb[mmu_idx][page_index] & ~TARGET_PAGE_MASK; mr = iotlb_to_region(pd); diff --git a/softmmu_defs.h b/softmmu_defs.h index d47d30d711..8d59f9d4f8 100644 --- a/softmmu_defs.h +++ b/softmmu_defs.h @@ -9,6 +9,7 @@ #ifndef SOFTMMU_DEFS_H #define SOFTMMU_DEFS_H +#ifndef CONFIG_TCG_PASS_AREG0 uint8_t __ldb_mmu(target_ulong addr, int mmu_idx); void __stb_mmu(target_ulong addr, uint8_t val, int mmu_idx); uint16_t __ldw_mmu(target_ulong addr, int mmu_idx); @@ -26,5 +27,32 @@ uint32_t __ldl_cmmu(target_ulong addr, int mmu_idx); void __stl_cmmu(target_ulong addr, uint32_t val, int mmu_idx); uint64_t __ldq_cmmu(target_ulong addr, int mmu_idx); void __stq_cmmu(target_ulong addr, uint64_t val, int mmu_idx); +#else +uint8_t helper_ldb_mmu(CPUArchState *env, target_ulong addr, int mmu_idx); +void helper_stb_mmu(CPUArchState *env, target_ulong addr, uint8_t val, + int mmu_idx); +uint16_t helper_ldw_mmu(CPUArchState *env, target_ulong addr, int mmu_idx); +void helper_stw_mmu(CPUArchState *env, target_ulong addr, uint16_t val, + int mmu_idx); +uint32_t helper_ldl_mmu(CPUArchState *env, target_ulong addr, int mmu_idx); +void helper_stl_mmu(CPUArchState *env, target_ulong addr, uint32_t val, + int mmu_idx); +uint64_t helper_ldq_mmu(CPUArchState *env, target_ulong addr, int mmu_idx); +void helper_stq_mmu(CPUArchState *env, target_ulong addr, uint64_t val, + int mmu_idx); + +uint8_t helper_ldb_cmmu(CPUArchState *env, target_ulong addr, int mmu_idx); +void helper_stb_cmmu(CPUArchState *env, target_ulong addr, uint8_t val, +int mmu_idx); +uint16_t helper_ldw_cmmu(CPUArchState *env, target_ulong addr, int mmu_idx); +void helper_stw_cmmu(CPUArchState *env, target_ulong addr, uint16_t val, + int mmu_idx); +uint32_t helper_ldl_cmmu(CPUArchState *env, target_ulong addr, int mmu_idx); +void helper_stl_cmmu(CPUArchState *env, target_ulong addr, uint32_t val, + int mmu_idx); +uint64_t helper_ldq_cmmu(CPUArchState *env, target_ulong addr, int mmu_idx); +void helper_stq_cmmu(CPUArchState *env, target_ulong addr, uint64_t val, + int mmu_idx); +#endif #endif diff --git a/softmmu_header.h b/softmmu_header.h index 818d7b662e..6b72093a0c 100644 --- a/softmmu_header.h +++ b/softmmu_header.h @@ -78,9 +78,23 @@ #define ADDR_READ addr_read #endif +#ifndef CONFIG_TCG_PASS_AREG0 +#define ENV_PARAM +#define ENV_VAR +#define CPU_PREFIX +#define HELPER_PREFIX __ +#else +#define ENV_PARAM CPUArchState *env, +#define ENV_VAR env, +#define CPU_PREFIX cpu_ +#define HELPER_PREFIX helper_ +#endif + /* generic load/store macros */ -static inline RES_TYPE glue(glue(ld, USUFFIX), MEMSUFFIX)(target_ulong ptr) +static inline RES_TYPE +glue(glue(glue(CPU_PREFIX, ld), USUFFIX), MEMSUFFIX)(ENV_PARAM + target_ulong ptr) { int page_index; RES_TYPE res; @@ -93,7 +107,9 @@ static inline RES_TYPE glue(glue(ld, USUFFIX), MEMSUFFIX)(target_ulong ptr) mmu_idx = CPU_MMU_INDEX; if (unlikely(env->tlb_table[mmu_idx][page_index].ADDR_READ != (addr & (TARGET_PAGE_MASK | (DATA_SIZE - 1))))) { - res = glue(glue(__ld, SUFFIX), MMUSUFFIX)(addr, mmu_idx); + res = glue(glue(glue(HELPER_PREFIX, ld), SUFFIX), MMUSUFFIX)(ENV_VAR + addr, + mmu_idx); } else { physaddr = addr + env->tlb_table[mmu_idx][page_index].addend; res = glue(glue(ld, USUFFIX), _raw)((uint8_t *)physaddr); @@ -102,7 +118,9 @@ static inline RES_TYPE glue(glue(ld, USUFFIX), MEMSUFFIX)(target_ulong ptr) } #if DATA_SIZE <= 2 -static inline int glue(glue(lds, SUFFIX), MEMSUFFIX)(target_ulong ptr) +static inline int +glue(glue(glue(CPU_PREFIX, lds), SUFFIX), MEMSUFFIX)(ENV_PARAM + target_ulong ptr) { int res, page_index; target_ulong addr; @@ -114,7 +132,8 @@ static inline int glue(glue(lds, SUFFIX), MEMSUFFIX)(target_ulong ptr) mmu_idx = CPU_MMU_INDEX; if (unlikely(env->tlb_table[mmu_idx][page_index].ADDR_READ != (addr & (TARGET_PAGE_MASK | (DATA_SIZE - 1))))) { - res = (DATA_STYPE)glue(glue(__ld, SUFFIX), MMUSUFFIX)(addr, mmu_idx); + res = (DATA_STYPE)glue(glue(glue(HELPER_PREFIX, ld), SUFFIX), + MMUSUFFIX)(ENV_VAR addr, mmu_idx); } else { physaddr = addr + env->tlb_table[mmu_idx][page_index].addend; res = glue(glue(lds, SUFFIX), _raw)((uint8_t *)physaddr); @@ -127,7 +146,9 @@ static inline int glue(glue(lds, SUFFIX), MEMSUFFIX)(target_ulong ptr) /* generic store macro */ -static inline void glue(glue(st, SUFFIX), MEMSUFFIX)(target_ulong ptr, RES_TYPE v) +static inline void +glue(glue(glue(CPU_PREFIX, st), SUFFIX), MEMSUFFIX)(ENV_PARAM target_ulong ptr, + RES_TYPE v) { int page_index; target_ulong addr; @@ -139,7 +160,8 @@ static inline void glue(glue(st, SUFFIX), MEMSUFFIX)(target_ulong ptr, RES_TYPE mmu_idx = CPU_MMU_INDEX; if (unlikely(env->tlb_table[mmu_idx][page_index].addr_write != (addr & (TARGET_PAGE_MASK | (DATA_SIZE - 1))))) { - glue(glue(__st, SUFFIX), MMUSUFFIX)(addr, v, mmu_idx); + glue(glue(glue(HELPER_PREFIX, st), SUFFIX), MMUSUFFIX)(ENV_VAR addr, v, + mmu_idx); } else { physaddr = addr + env->tlb_table[mmu_idx][page_index].addend; glue(glue(st, SUFFIX), _raw)((uint8_t *)physaddr, v); @@ -151,46 +173,52 @@ static inline void glue(glue(st, SUFFIX), MEMSUFFIX)(target_ulong ptr, RES_TYPE #if ACCESS_TYPE != (NB_MMU_MODES + 1) #if DATA_SIZE == 8 -static inline float64 glue(ldfq, MEMSUFFIX)(target_ulong ptr) +static inline float64 glue(glue(CPU_PREFIX, ldfq), MEMSUFFIX)(ENV_PARAM + target_ulong ptr) { union { float64 d; uint64_t i; } u; - u.i = glue(ldq, MEMSUFFIX)(ptr); + u.i = glue(glue(CPU_PREFIX, ldq), MEMSUFFIX)(ENV_VAR ptr); return u.d; } -static inline void glue(stfq, MEMSUFFIX)(target_ulong ptr, float64 v) +static inline void glue(glue(CPU_PREFIX, stfq), MEMSUFFIX)(ENV_PARAM + target_ulong ptr, + float64 v) { union { float64 d; uint64_t i; } u; u.d = v; - glue(stq, MEMSUFFIX)(ptr, u.i); + glue(glue(CPU_PREFIX, stq), MEMSUFFIX)(ENV_VAR ptr, u.i); } #endif /* DATA_SIZE == 8 */ #if DATA_SIZE == 4 -static inline float32 glue(ldfl, MEMSUFFIX)(target_ulong ptr) +static inline float32 glue(glue(CPU_PREFIX, ldfl), MEMSUFFIX)(ENV_PARAM + target_ulong ptr) { union { float32 f; uint32_t i; } u; - u.i = glue(ldl, MEMSUFFIX)(ptr); + u.i = glue(glue(CPU_PREFIX, ldl), MEMSUFFIX)(ENV_VAR ptr); return u.f; } -static inline void glue(stfl, MEMSUFFIX)(target_ulong ptr, float32 v) +static inline void glue(glue(CPU_PREFIX, stfl), MEMSUFFIX)(ENV_PARAM + target_ulong ptr, + float32 v) { union { float32 f; uint32_t i; } u; u.f = v; - glue(stl, MEMSUFFIX)(ptr, u.i); + glue(glue(CPU_PREFIX, stl), MEMSUFFIX)(ENV_VAR ptr, u.i); } #endif /* DATA_SIZE == 4 */ @@ -205,3 +233,7 @@ static inline void glue(stfl, MEMSUFFIX)(target_ulong ptr, float32 v) #undef CPU_MMU_INDEX #undef MMUSUFFIX #undef ADDR_READ +#undef ENV_PARAM +#undef ENV_VAR +#undef CPU_PREFIX +#undef HELPER_PREFIX diff --git a/softmmu_template.h b/softmmu_template.h index d633bb5558..afcab1e6a9 100644 --- a/softmmu_template.h +++ b/softmmu_template.h @@ -54,10 +54,24 @@ #define ADDR_READ addr_read #endif -static DATA_TYPE glue(glue(slow_ld, SUFFIX), MMUSUFFIX)(target_ulong addr, +#ifndef CONFIG_TCG_PASS_AREG0 +#define ENV_PARAM +#define ENV_VAR +#define CPU_PREFIX +#define HELPER_PREFIX __ +#else +#define ENV_PARAM CPUArchState *env, +#define ENV_VAR env, +#define CPU_PREFIX cpu_ +#define HELPER_PREFIX helper_ +#endif + +static DATA_TYPE glue(glue(slow_ld, SUFFIX), MMUSUFFIX)(ENV_PARAM + target_ulong addr, int mmu_idx, void *retaddr); -static inline DATA_TYPE glue(io_read, SUFFIX)(target_phys_addr_t physaddr, +static inline DATA_TYPE glue(io_read, SUFFIX)(ENV_PARAM + target_phys_addr_t physaddr, target_ulong addr, void *retaddr) { @@ -89,7 +103,10 @@ static inline DATA_TYPE glue(io_read, SUFFIX)(target_phys_addr_t physaddr, } /* handle all cases except unaligned access which span two pages */ -DATA_TYPE glue(glue(__ld, SUFFIX), MMUSUFFIX)(target_ulong addr, int mmu_idx) +DATA_TYPE +glue(glue(glue(HELPER_PREFIX, ld), SUFFIX), MMUSUFFIX)(ENV_PARAM + target_ulong addr, + int mmu_idx) { DATA_TYPE res; int index; @@ -110,22 +127,22 @@ DATA_TYPE glue(glue(__ld, SUFFIX), MMUSUFFIX)(target_ulong addr, int mmu_idx) goto do_unaligned_access; retaddr = GETPC(); ioaddr = env->iotlb[mmu_idx][index]; - res = glue(io_read, SUFFIX)(ioaddr, addr, retaddr); + res = glue(io_read, SUFFIX)(ENV_VAR ioaddr, addr, retaddr); } else if (((addr & ~TARGET_PAGE_MASK) + DATA_SIZE - 1) >= TARGET_PAGE_SIZE) { /* slow unaligned access (it spans two pages or IO) */ do_unaligned_access: retaddr = GETPC(); #ifdef ALIGNED_ONLY - do_unaligned_access(addr, READ_ACCESS_TYPE, mmu_idx, retaddr); + do_unaligned_access(ENV_VAR addr, READ_ACCESS_TYPE, mmu_idx, retaddr); #endif - res = glue(glue(slow_ld, SUFFIX), MMUSUFFIX)(addr, + res = glue(glue(slow_ld, SUFFIX), MMUSUFFIX)(ENV_VAR addr, mmu_idx, retaddr); } else { /* unaligned/aligned access in the same page */ #ifdef ALIGNED_ONLY if ((addr & (DATA_SIZE - 1)) != 0) { retaddr = GETPC(); - do_unaligned_access(addr, READ_ACCESS_TYPE, mmu_idx, retaddr); + do_unaligned_access(ENV_VAR addr, READ_ACCESS_TYPE, mmu_idx, retaddr); } #endif addend = env->tlb_table[mmu_idx][index].addend; @@ -136,7 +153,7 @@ DATA_TYPE glue(glue(__ld, SUFFIX), MMUSUFFIX)(target_ulong addr, int mmu_idx) retaddr = GETPC(); #ifdef ALIGNED_ONLY if ((addr & (DATA_SIZE - 1)) != 0) - do_unaligned_access(addr, READ_ACCESS_TYPE, mmu_idx, retaddr); + do_unaligned_access(ENV_VAR addr, READ_ACCESS_TYPE, mmu_idx, retaddr); #endif tlb_fill(env, addr, READ_ACCESS_TYPE, mmu_idx, retaddr); goto redo; @@ -145,9 +162,11 @@ DATA_TYPE glue(glue(__ld, SUFFIX), MMUSUFFIX)(target_ulong addr, int mmu_idx) } /* handle all unaligned cases */ -static DATA_TYPE glue(glue(slow_ld, SUFFIX), MMUSUFFIX)(target_ulong addr, - int mmu_idx, - void *retaddr) +static DATA_TYPE +glue(glue(slow_ld, SUFFIX), MMUSUFFIX)(ENV_PARAM + target_ulong addr, + int mmu_idx, + void *retaddr) { DATA_TYPE res, res1, res2; int index, shift; @@ -164,15 +183,15 @@ static DATA_TYPE glue(glue(slow_ld, SUFFIX), MMUSUFFIX)(target_ulong addr, if ((addr & (DATA_SIZE - 1)) != 0) goto do_unaligned_access; ioaddr = env->iotlb[mmu_idx][index]; - res = glue(io_read, SUFFIX)(ioaddr, addr, retaddr); + res = glue(io_read, SUFFIX)(ENV_VAR ioaddr, addr, retaddr); } else if (((addr & ~TARGET_PAGE_MASK) + DATA_SIZE - 1) >= TARGET_PAGE_SIZE) { do_unaligned_access: /* slow unaligned access (it spans two pages) */ addr1 = addr & ~(DATA_SIZE - 1); addr2 = addr1 + DATA_SIZE; - res1 = glue(glue(slow_ld, SUFFIX), MMUSUFFIX)(addr1, + res1 = glue(glue(slow_ld, SUFFIX), MMUSUFFIX)(ENV_VAR addr1, mmu_idx, retaddr); - res2 = glue(glue(slow_ld, SUFFIX), MMUSUFFIX)(addr2, + res2 = glue(glue(slow_ld, SUFFIX), MMUSUFFIX)(ENV_VAR addr2, mmu_idx, retaddr); shift = (addr & (DATA_SIZE - 1)) * 8; #ifdef TARGET_WORDS_BIGENDIAN @@ -196,12 +215,14 @@ static DATA_TYPE glue(glue(slow_ld, SUFFIX), MMUSUFFIX)(target_ulong addr, #ifndef SOFTMMU_CODE_ACCESS -static void glue(glue(slow_st, SUFFIX), MMUSUFFIX)(target_ulong addr, +static void glue(glue(slow_st, SUFFIX), MMUSUFFIX)(ENV_PARAM + target_ulong addr, DATA_TYPE val, int mmu_idx, void *retaddr); -static inline void glue(io_write, SUFFIX)(target_phys_addr_t physaddr, +static inline void glue(io_write, SUFFIX)(ENV_PARAM + target_phys_addr_t physaddr, DATA_TYPE val, target_ulong addr, void *retaddr) @@ -231,8 +252,10 @@ static inline void glue(io_write, SUFFIX)(target_phys_addr_t physaddr, #endif /* SHIFT > 2 */ } -void glue(glue(__st, SUFFIX), MMUSUFFIX)(target_ulong addr, DATA_TYPE val, - int mmu_idx) +void glue(glue(glue(HELPER_PREFIX, st), SUFFIX), MMUSUFFIX)(ENV_PARAM + target_ulong addr, + DATA_TYPE val, + int mmu_idx) { target_phys_addr_t ioaddr; unsigned long addend; @@ -250,21 +273,21 @@ void glue(glue(__st, SUFFIX), MMUSUFFIX)(target_ulong addr, DATA_TYPE val, goto do_unaligned_access; retaddr = GETPC(); ioaddr = env->iotlb[mmu_idx][index]; - glue(io_write, SUFFIX)(ioaddr, val, addr, retaddr); + glue(io_write, SUFFIX)(ENV_VAR ioaddr, val, addr, retaddr); } else if (((addr & ~TARGET_PAGE_MASK) + DATA_SIZE - 1) >= TARGET_PAGE_SIZE) { do_unaligned_access: retaddr = GETPC(); #ifdef ALIGNED_ONLY - do_unaligned_access(addr, 1, mmu_idx, retaddr); + do_unaligned_access(ENV_VAR addr, 1, mmu_idx, retaddr); #endif - glue(glue(slow_st, SUFFIX), MMUSUFFIX)(addr, val, + glue(glue(slow_st, SUFFIX), MMUSUFFIX)(ENV_VAR addr, val, mmu_idx, retaddr); } else { /* aligned/unaligned access in the same page */ #ifdef ALIGNED_ONLY if ((addr & (DATA_SIZE - 1)) != 0) { retaddr = GETPC(); - do_unaligned_access(addr, 1, mmu_idx, retaddr); + do_unaligned_access(ENV_VAR addr, 1, mmu_idx, retaddr); } #endif addend = env->tlb_table[mmu_idx][index].addend; @@ -275,7 +298,7 @@ void glue(glue(__st, SUFFIX), MMUSUFFIX)(target_ulong addr, DATA_TYPE val, retaddr = GETPC(); #ifdef ALIGNED_ONLY if ((addr & (DATA_SIZE - 1)) != 0) - do_unaligned_access(addr, 1, mmu_idx, retaddr); + do_unaligned_access(ENV_VAR addr, 1, mmu_idx, retaddr); #endif tlb_fill(env, addr, 1, mmu_idx, retaddr); goto redo; @@ -283,7 +306,8 @@ void glue(glue(__st, SUFFIX), MMUSUFFIX)(target_ulong addr, DATA_TYPE val, } /* handles all unaligned cases */ -static void glue(glue(slow_st, SUFFIX), MMUSUFFIX)(target_ulong addr, +static void glue(glue(slow_st, SUFFIX), MMUSUFFIX)(ENV_PARAM + target_ulong addr, DATA_TYPE val, int mmu_idx, void *retaddr) @@ -302,7 +326,7 @@ static void glue(glue(slow_st, SUFFIX), MMUSUFFIX)(target_ulong addr, if ((addr & (DATA_SIZE - 1)) != 0) goto do_unaligned_access; ioaddr = env->iotlb[mmu_idx][index]; - glue(io_write, SUFFIX)(ioaddr, val, addr, retaddr); + glue(io_write, SUFFIX)(ENV_VAR ioaddr, val, addr, retaddr); } else if (((addr & ~TARGET_PAGE_MASK) + DATA_SIZE - 1) >= TARGET_PAGE_SIZE) { do_unaligned_access: /* XXX: not efficient, but simple */ @@ -310,10 +334,12 @@ static void glue(glue(slow_st, SUFFIX), MMUSUFFIX)(target_ulong addr, * previous page from the TLB cache. */ for(i = DATA_SIZE - 1; i >= 0; i--) { #ifdef TARGET_WORDS_BIGENDIAN - glue(slow_stb, MMUSUFFIX)(addr + i, val >> (((DATA_SIZE - 1) * 8) - (i * 8)), + glue(slow_stb, MMUSUFFIX)(ENV_VAR addr + i, + val >> (((DATA_SIZE - 1) * 8) - (i * 8)), mmu_idx, retaddr); #else - glue(slow_stb, MMUSUFFIX)(addr + i, val >> (i * 8), + glue(slow_stb, MMUSUFFIX)(ENV_VAR addr + i, + val >> (i * 8), mmu_idx, retaddr); #endif } @@ -338,3 +364,7 @@ static void glue(glue(slow_st, SUFFIX), MMUSUFFIX)(target_ulong addr, #undef USUFFIX #undef DATA_SIZE #undef ADDR_READ +#undef ENV_PARAM +#undef ENV_VAR +#undef CPU_PREFIX +#undef HELPER_PREFIX diff --git a/tcg/arm/tcg-target.c b/tcg/arm/tcg-target.c index 5af21b3f5d..4d59a63855 100644 --- a/tcg/arm/tcg-target.c +++ b/tcg/arm/tcg-target.c @@ -929,6 +929,27 @@ static inline void tcg_out_goto_label(TCGContext *s, int cond, int label_index) #include "../../softmmu_defs.h" +#ifdef CONFIG_TCG_PASS_AREG0 +/* helper signature: helper_ld_mmu(CPUState *env, target_ulong addr, + int mmu_idx) */ +static const void * const qemu_ld_helpers[4] = { + helper_ldb_mmu, + helper_ldw_mmu, + helper_ldl_mmu, + helper_ldq_mmu, +}; + +/* helper signature: helper_st_mmu(CPUState *env, target_ulong addr, + uintxx_t val, int mmu_idx) */ +static const void * const qemu_st_helpers[4] = { + helper_stb_mmu, + helper_stw_mmu, + helper_stl_mmu, + helper_stq_mmu, +}; +#else +/* legacy helper signature: __ld_mmu(target_ulong addr, int + mmu_idx) */ static void *qemu_ld_helpers[4] = { __ldb_mmu, __ldw_mmu, @@ -936,6 +957,8 @@ static void *qemu_ld_helpers[4] = { __ldq_mmu, }; +/* legacy helper signature: __st_mmu(target_ulong addr, uintxx_t val, + int mmu_idx) */ static void *qemu_st_helpers[4] = { __stb_mmu, __stw_mmu, @@ -943,6 +966,7 @@ static void *qemu_st_helpers[4] = { __stq_mmu, }; #endif +#endif #define TLB_SHIFT (CPU_TLB_ENTRY_BITS + CPU_TLB_BITS) @@ -1075,6 +1099,19 @@ static inline void tcg_out_qemu_ld(TCGContext *s, const TCGArg *args, int opc) TCG_REG_R1, 0, addr_reg2, SHIFT_IMM_LSL(0)); tcg_out_dat_imm(s, COND_AL, ARITH_MOV, TCG_REG_R2, 0, mem_index); # endif +#ifdef CONFIG_TCG_PASS_AREG0 + /* XXX/FIXME: suboptimal and incorrect for 64 bit */ + tcg_out_dat_reg(s, COND_AL, ARITH_MOV, + tcg_target_call_iarg_regs[2], 0, + tcg_target_call_iarg_regs[1], SHIFT_IMM_LSL(0)); + tcg_out_dat_reg(s, COND_AL, ARITH_MOV, + tcg_target_call_iarg_regs[1], 0, + tcg_target_call_iarg_regs[0], SHIFT_IMM_LSL(0)); + + tcg_out_dat_reg(s, COND_AL, ARITH_MOV, + tcg_target_call_iarg_regs[0], 0, TCG_AREG0, + SHIFT_IMM_LSL(0)); +#endif tcg_out_call(s, (tcg_target_long) qemu_ld_helpers[s_bits]); switch (opc) { @@ -1341,6 +1378,22 @@ static inline void tcg_out_qemu_st(TCGContext *s, const TCGArg *args, int opc) } # endif +#ifdef CONFIG_TCG_PASS_AREG0 + /* XXX/FIXME: suboptimal and incorrect for 64 bit */ + tcg_out_dat_reg(s, COND_AL, ARITH_MOV, + tcg_target_call_iarg_regs[3], 0, + tcg_target_call_iarg_regs[2], SHIFT_IMM_LSL(0)); + tcg_out_dat_reg(s, COND_AL, ARITH_MOV, + tcg_target_call_iarg_regs[2], 0, + tcg_target_call_iarg_regs[1], SHIFT_IMM_LSL(0)); + tcg_out_dat_reg(s, COND_AL, ARITH_MOV, + tcg_target_call_iarg_regs[1], 0, + tcg_target_call_iarg_regs[0], SHIFT_IMM_LSL(0)); + + tcg_out_dat_reg(s, COND_AL, ARITH_MOV, + tcg_target_call_iarg_regs[0], 0, TCG_AREG0, + SHIFT_IMM_LSL(0)); +#endif tcg_out_call(s, (tcg_target_long) qemu_st_helpers[s_bits]); if (opc == 3) tcg_out_dat_imm(s, COND_AL, ARITH_ADD, TCG_REG_R13, TCG_REG_R13, 0x10); diff --git a/tcg/hppa/tcg-target.c b/tcg/hppa/tcg-target.c index c5a3730a2b..e579ef06a1 100644 --- a/tcg/hppa/tcg-target.c +++ b/tcg/hppa/tcg-target.c @@ -882,6 +882,27 @@ static void tcg_out_setcond2(TCGContext *s, int cond, TCGArg ret, #if defined(CONFIG_SOFTMMU) #include "../../softmmu_defs.h" +#ifdef CONFIG_TCG_PASS_AREG0 +/* helper signature: helper_ld_mmu(CPUState *env, target_ulong addr, + int mmu_idx) */ +static const void * const qemu_ld_helpers[4] = { + helper_ldb_mmu, + helper_ldw_mmu, + helper_ldl_mmu, + helper_ldq_mmu, +}; + +/* helper signature: helper_st_mmu(CPUState *env, target_ulong addr, + uintxx_t val, int mmu_idx) */ +static const void * const qemu_st_helpers[4] = { + helper_stb_mmu, + helper_stw_mmu, + helper_stl_mmu, + helper_stq_mmu, +}; +#else +/* legacy helper signature: __ld_mmu(target_ulong addr, int + mmu_idx) */ static void *qemu_ld_helpers[4] = { __ldb_mmu, __ldw_mmu, @@ -889,12 +910,15 @@ static void *qemu_ld_helpers[4] = { __ldq_mmu, }; +/* legacy helper signature: __st_mmu(target_ulong addr, uintxx_t val, + int mmu_idx) */ static void *qemu_st_helpers[4] = { __stb_mmu, __stw_mmu, __stl_mmu, __stq_mmu, }; +#endif /* Load and compare a TLB entry, and branch if TLB miss. OFFSET is set to the offset of the first ADDR_READ or ADDR_WRITE member of the appropriate @@ -1061,6 +1085,15 @@ static void tcg_out_qemu_ld(TCGContext *s, const TCGArg *args, int opc) } tcg_out_movi(s, TCG_TYPE_I32, argreg, mem_index); +#ifdef CONFIG_TCG_PASS_AREG0 + /* XXX/FIXME: suboptimal */ + tcg_out_mov(s, TCG_TYPE_I32, tcg_target_call_iarg_regs[2], + tcg_target_call_iarg_regs[1]); + tcg_out_mov(s, TCG_TYPE_TL, tcg_target_call_iarg_regs[1], + tcg_target_call_iarg_regs[0]); + tcg_out_mov(s, TCG_TYPE_PTR, tcg_target_call_iarg_regs[0], + TCG_AREG0); +#endif tcg_out_call(s, qemu_ld_helpers[opc & 3]); switch (opc) { @@ -1212,6 +1245,17 @@ static void tcg_out_qemu_st(TCGContext *s, const TCGArg *args, int opc) tcg_abort(); } +#ifdef CONFIG_TCG_PASS_AREG0 + /* XXX/FIXME: suboptimal */ + tcg_out_mov(s, TCG_TYPE_I32, tcg_target_call_iarg_regs[3], + tcg_target_call_iarg_regs[2]); + tcg_out_mov(s, TCG_TYPE_I64, tcg_target_call_iarg_regs[2], + tcg_target_call_iarg_regs[1]); + tcg_out_mov(s, TCG_TYPE_TL, tcg_target_call_iarg_regs[1], + tcg_target_call_iarg_regs[0]); + tcg_out_mov(s, TCG_TYPE_PTR, tcg_target_call_iarg_regs[0], + TCG_AREG0); +#endif tcg_out_call(s, qemu_st_helpers[opc]); /* label2: */ diff --git a/tcg/i386/tcg-target.c b/tcg/i386/tcg-target.c index c4e940da5b..43a51a1c54 100644 --- a/tcg/i386/tcg-target.c +++ b/tcg/i386/tcg-target.c @@ -178,6 +178,9 @@ static int target_parse_constraint(TCGArgConstraint *ct, const char **pct_str) tcg_regset_set32(ct->u.regs, 0, 0xffff); tcg_regset_reset_reg(ct->u.regs, TCG_REG_RSI); tcg_regset_reset_reg(ct->u.regs, TCG_REG_RDI); +#ifdef CONFIG_TCG_PASS_AREG0 + tcg_regset_reset_reg(ct->u.regs, TCG_REG_RDX); +#endif } else { tcg_regset_set32(ct->u.regs, 0, 0xff); tcg_regset_reset_reg(ct->u.regs, TCG_REG_EAX); @@ -957,6 +960,27 @@ static void tcg_out_jmp(TCGContext *s, tcg_target_long dest) #include "../../softmmu_defs.h" +#ifdef CONFIG_TCG_PASS_AREG0 +/* helper signature: helper_ld_mmu(CPUState *env, target_ulong addr, + int mmu_idx) */ +static const void *qemu_ld_helpers[4] = { + helper_ldb_mmu, + helper_ldw_mmu, + helper_ldl_mmu, + helper_ldq_mmu, +}; + +/* helper signature: helper_st_mmu(CPUState *env, target_ulong addr, + uintxx_t val, int mmu_idx) */ +static const void *qemu_st_helpers[4] = { + helper_stb_mmu, + helper_stw_mmu, + helper_stl_mmu, + helper_stq_mmu, +}; +#else +/* legacy helper signature: __ld_mmu(target_ulong addr, int + mmu_idx) */ static void *qemu_ld_helpers[4] = { __ldb_mmu, __ldw_mmu, @@ -964,12 +988,15 @@ static void *qemu_ld_helpers[4] = { __ldq_mmu, }; +/* legacy helper signature: __st_mmu(target_ulong addr, uintxx_t val, + int mmu_idx) */ static void *qemu_st_helpers[4] = { __stb_mmu, __stw_mmu, __stl_mmu, __stq_mmu, }; +#endif /* Perform the TLB load and compare. @@ -1188,11 +1215,26 @@ static void tcg_out_qemu_ld(TCGContext *s, const TCGArg *args, } tcg_out_push(s, args[addrlo_idx]); stack_adjust += 4; +#ifdef CONFIG_TCG_PASS_AREG0 + tcg_out_push(s, TCG_AREG0); + stack_adjust += 4; +#endif #else /* The first argument is already loaded with addrlo. */ arg_idx = 1; tcg_out_movi(s, TCG_TYPE_I32, tcg_target_call_iarg_regs[arg_idx], mem_index); +#ifdef CONFIG_TCG_PASS_AREG0 + /* XXX/FIXME: suboptimal */ + tcg_out_mov(s, TCG_TYPE_I64, tcg_target_call_iarg_regs[3], + tcg_target_call_iarg_regs[2]); + tcg_out_mov(s, TCG_TYPE_I64, tcg_target_call_iarg_regs[2], + tcg_target_call_iarg_regs[1]); + tcg_out_mov(s, TCG_TYPE_I64, tcg_target_call_iarg_regs[1], + tcg_target_call_iarg_regs[0]); + tcg_out_mov(s, TCG_TYPE_I64, tcg_target_call_iarg_regs[0], + TCG_AREG0); +#endif #endif tcg_out_calli(s, (tcg_target_long)qemu_ld_helpers[s_bits]); @@ -1386,11 +1428,26 @@ static void tcg_out_qemu_st(TCGContext *s, const TCGArg *args, } tcg_out_push(s, args[addrlo_idx]); stack_adjust += 4; +#ifdef CONFIG_TCG_PASS_AREG0 + tcg_out_push(s, TCG_AREG0); + stack_adjust += 4; +#endif #else tcg_out_mov(s, (opc == 3 ? TCG_TYPE_I64 : TCG_TYPE_I32), TCG_REG_RSI, data_reg); tcg_out_movi(s, TCG_TYPE_I32, TCG_REG_RDX, mem_index); stack_adjust = 0; +#ifdef CONFIG_TCG_PASS_AREG0 + /* XXX/FIXME: suboptimal */ + tcg_out_mov(s, TCG_TYPE_I64, tcg_target_call_iarg_regs[3], + tcg_target_call_iarg_regs[2]); + tcg_out_mov(s, TCG_TYPE_I64, tcg_target_call_iarg_regs[2], + tcg_target_call_iarg_regs[1]); + tcg_out_mov(s, TCG_TYPE_I64, tcg_target_call_iarg_regs[1], + tcg_target_call_iarg_regs[0]); + tcg_out_mov(s, TCG_TYPE_I64, tcg_target_call_iarg_regs[0], + TCG_AREG0); +#endif #endif tcg_out_calli(s, (tcg_target_long)qemu_st_helpers[s_bits]); diff --git a/tcg/ia64/tcg-target.c b/tcg/ia64/tcg-target.c index f90252a443..e02dacc84f 100644 --- a/tcg/ia64/tcg-target.c +++ b/tcg/ia64/tcg-target.c @@ -1452,12 +1452,25 @@ static inline void tcg_out_qemu_tlb(TCGContext *s, TCGArg addr_reg, TCG_REG_P7, TCG_REG_R3, TCG_REG_R57)); } +#ifdef CONFIG_TCG_PASS_AREG0 +/* helper signature: helper_ld_mmu(CPUState *env, target_ulong addr, + int mmu_idx) */ +static const void * const qemu_ld_helpers[4] = { + helper_ldb_mmu, + helper_ldw_mmu, + helper_ldl_mmu, + helper_ldq_mmu, +}; +#else +/* legacy helper signature: __ld_mmu(target_ulong addr, int + mmu_idx) */ static void *qemu_ld_helpers[4] = { __ldb_mmu, __ldw_mmu, __ldl_mmu, __ldq_mmu, }; +#endif static inline void tcg_out_qemu_ld(TCGContext *s, const TCGArg *args, int opc) { @@ -1517,6 +1530,15 @@ static inline void tcg_out_qemu_ld(TCGContext *s, const TCGArg *args, int opc) tcg_opc_m1 (TCG_REG_P7, OPC_LD8_M1, TCG_REG_R1, TCG_REG_R2), tcg_opc_i18(TCG_REG_P0, OPC_NOP_I18, 0)); } +#ifdef CONFIG_TCG_PASS_AREG0 + /* XXX/FIXME: suboptimal */ + tcg_out_mov(s, TCG_TYPE_I32, tcg_target_call_iarg_regs[2], + tcg_target_call_iarg_regs[1]); + tcg_out_mov(s, TCG_TYPE_TL, tcg_target_call_iarg_regs[1], + tcg_target_call_iarg_regs[0]); + tcg_out_mov(s, TCG_TYPE_PTR, tcg_target_call_iarg_regs[0], + TCG_AREG0); +#endif if (!bswap || s_bits == 0) { tcg_out_bundle(s, miB, tcg_opc_m48(TCG_REG_P0, OPC_NOP_M48, 0), @@ -1547,12 +1569,25 @@ static inline void tcg_out_qemu_ld(TCGContext *s, const TCGArg *args, int opc) } } +#ifdef CONFIG_TCG_PASS_AREG0 +/* helper signature: helper_st_mmu(CPUState *env, target_ulong addr, + uintxx_t val, int mmu_idx) */ +static const void * const qemu_st_helpers[4] = { + helper_stb_mmu, + helper_stw_mmu, + helper_stl_mmu, + helper_stq_mmu, +}; +#else +/* legacy helper signature: __st_mmu(target_ulong addr, uintxx_t val, + int mmu_idx) */ static void *qemu_st_helpers[4] = { __stb_mmu, __stw_mmu, __stl_mmu, __stq_mmu, }; +#endif static inline void tcg_out_qemu_st(TCGContext *s, const TCGArg *args, int opc) { @@ -1622,6 +1657,17 @@ static inline void tcg_out_qemu_st(TCGContext *s, const TCGArg *args, int opc) data_reg = TCG_REG_R2; } +#ifdef CONFIG_TCG_PASS_AREG0 + /* XXX/FIXME: suboptimal */ + tcg_out_mov(s, TCG_TYPE_I32, tcg_target_call_iarg_regs[3], + tcg_target_call_iarg_regs[2]); + tcg_out_mov(s, TCG_TYPE_I64, tcg_target_call_iarg_regs[2], + tcg_target_call_iarg_regs[1]); + tcg_out_mov(s, TCG_TYPE_TL, tcg_target_call_iarg_regs[1], + tcg_target_call_iarg_regs[0]); + tcg_out_mov(s, TCG_TYPE_PTR, tcg_target_call_iarg_regs[0], + TCG_AREG0); +#endif tcg_out_bundle(s, miB, tcg_opc_m4 (TCG_REG_P6, opc_st_m4[opc], data_reg, TCG_REG_R3), diff --git a/tcg/mips/tcg-target.c b/tcg/mips/tcg-target.c index c6aa5bced5..393ba07f25 100644 --- a/tcg/mips/tcg-target.c +++ b/tcg/mips/tcg-target.c @@ -750,6 +750,27 @@ static void tcg_out_setcond2(TCGContext *s, TCGCond cond, int ret, #include "../../softmmu_defs.h" +#ifdef CONFIG_TCG_PASS_AREG0 +/* helper signature: helper_ld_mmu(CPUState *env, target_ulong addr, + int mmu_idx) */ +static const void * const qemu_ld_helpers[4] = { + helper_ldb_mmu, + helper_ldw_mmu, + helper_ldl_mmu, + helper_ldq_mmu, +}; + +/* helper signature: helper_st_mmu(CPUState *env, target_ulong addr, + uintxx_t val, int mmu_idx) */ +static const void * const qemu_st_helpers[4] = { + helper_stb_mmu, + helper_stw_mmu, + helper_stl_mmu, + helper_stq_mmu, +}; +#else +/* legacy helper signature: __ld_mmu(target_ulong addr, int + mmu_idx) */ static void *qemu_ld_helpers[4] = { __ldb_mmu, __ldw_mmu, @@ -757,6 +778,8 @@ static void *qemu_ld_helpers[4] = { __ldq_mmu, }; +/* legacy helper signature: __st_mmu(target_ulong addr, uintxx_t val, + int mmu_idx) */ static void *qemu_st_helpers[4] = { __stb_mmu, __stw_mmu, @@ -764,6 +787,7 @@ static void *qemu_st_helpers[4] = { __stq_mmu, }; #endif +#endif static void tcg_out_qemu_ld(TCGContext *s, const TCGArg *args, int opc) @@ -858,6 +882,15 @@ static void tcg_out_qemu_ld(TCGContext *s, const TCGArg *args, # endif tcg_out_movi(s, TCG_TYPE_I32, sp_args++, mem_index); tcg_out_movi(s, TCG_TYPE_I32, TCG_REG_T9, (tcg_target_long)qemu_ld_helpers[s_bits]); +#ifdef CONFIG_TCG_PASS_AREG0 + /* XXX/FIXME: suboptimal and incorrect for 64 on 32 bit */ + tcg_out_mov(s, TCG_TYPE_I32, tcg_target_call_iarg_regs[2], + tcg_target_call_iarg_regs[1]); + tcg_out_mov(s, TCG_TYPE_TL, tcg_target_call_iarg_regs[1], + tcg_target_call_iarg_regs[0]); + tcg_out_mov(s, TCG_TYPE_PTR, tcg_target_call_iarg_regs[0], + TCG_AREG0); +#endif tcg_out_opc_reg(s, OPC_JALR, TCG_REG_RA, TCG_REG_T9, 0); tcg_out_nop(s); @@ -1069,6 +1102,17 @@ static void tcg_out_qemu_st(TCGContext *s, const TCGArg *args, } tcg_out_movi(s, TCG_TYPE_I32, TCG_REG_T9, (tcg_target_long)qemu_st_helpers[s_bits]); +#ifdef CONFIG_TCG_PASS_AREG0 + /* XXX/FIXME: suboptimal and incorrect for 64 on 32 bit */ + tcg_out_mov(s, TCG_TYPE_I32, tcg_target_call_iarg_regs[3], + tcg_target_call_iarg_regs[2]); + tcg_out_mov(s, TCG_TYPE_I64, tcg_target_call_iarg_regs[2], + tcg_target_call_iarg_regs[1]); + tcg_out_mov(s, TCG_TYPE_TL, tcg_target_call_iarg_regs[1], + tcg_target_call_iarg_regs[0]); + tcg_out_mov(s, TCG_TYPE_PTR, tcg_target_call_iarg_regs[0], + TCG_AREG0); +#endif tcg_out_opc_reg(s, OPC_JALR, TCG_REG_RA, TCG_REG_T9, 0); tcg_out_nop(s); diff --git a/tcg/ppc/tcg-target.c b/tcg/ppc/tcg-target.c index 6a34cab5f9..b0aa914798 100644 --- a/tcg/ppc/tcg-target.c +++ b/tcg/ppc/tcg-target.c @@ -508,6 +508,27 @@ static void tcg_out_call (TCGContext *s, tcg_target_long arg, int const_arg) #include "../../softmmu_defs.h" +#ifdef CONFIG_TCG_PASS_AREG0 +/* helper signature: helper_ld_mmu(CPUState *env, target_ulong addr, + int mmu_idx) */ +static const void * const qemu_ld_helpers[4] = { + helper_ldb_mmu, + helper_ldw_mmu, + helper_ldl_mmu, + helper_ldq_mmu, +}; + +/* helper signature: helper_st_mmu(CPUState *env, target_ulong addr, + uintxx_t val, int mmu_idx) */ +static const void * const qemu_st_helpers[4] = { + helper_stb_mmu, + helper_stw_mmu, + helper_stl_mmu, + helper_stq_mmu, +}; +#else +/* legacy helper signature: __ld_mmu(target_ulong addr, int + mmu_idx) */ static void *qemu_ld_helpers[4] = { __ldb_mmu, __ldw_mmu, @@ -515,6 +536,8 @@ static void *qemu_ld_helpers[4] = { __ldq_mmu, }; +/* legacy helper signature: __ld_mmu(target_ulong addr, int + mmu_idx) */ static void *qemu_st_helpers[4] = { __stb_mmu, __stw_mmu, @@ -522,6 +545,7 @@ static void *qemu_st_helpers[4] = { __stq_mmu, }; #endif +#endif static void tcg_out_qemu_ld (TCGContext *s, const TCGArg *args, int opc) { @@ -598,6 +622,16 @@ static void tcg_out_qemu_ld (TCGContext *s, const TCGArg *args, int opc) tcg_out_movi (s, TCG_TYPE_I32, 5, mem_index); #endif +#ifdef CONFIG_TCG_PASS_AREG0 + /* XXX/FIXME: suboptimal */ + tcg_out_mov(s, TCG_TYPE_I32, tcg_target_call_iarg_regs[2], + tcg_target_call_iarg_regs[1]); + tcg_out_mov(s, TCG_TYPE_TL, tcg_target_call_iarg_regs[1], + tcg_target_call_iarg_regs[0]); + tcg_out_mov(s, TCG_TYPE_PTR, tcg_target_call_iarg_regs[0], + TCG_AREG0); +#endif + tcg_out_call (s, (tcg_target_long) qemu_ld_helpers[s_bits], 1); switch (opc) { case 0|4: @@ -829,6 +863,17 @@ static void tcg_out_qemu_st (TCGContext *s, const TCGArg *args, int opc) ir++; tcg_out_movi (s, TCG_TYPE_I32, ir, mem_index); +#ifdef CONFIG_TCG_PASS_AREG0 + /* XXX/FIXME: suboptimal */ + tcg_out_mov(s, TCG_TYPE_I32, tcg_target_call_iarg_regs[3], + tcg_target_call_iarg_regs[2]); + tcg_out_mov(s, TCG_TYPE_I64, tcg_target_call_iarg_regs[2], + tcg_target_call_iarg_regs[1]); + tcg_out_mov(s, TCG_TYPE_TL, tcg_target_call_iarg_regs[1], + tcg_target_call_iarg_regs[0]); + tcg_out_mov(s, TCG_TYPE_PTR, tcg_target_call_iarg_regs[0], + TCG_AREG0); +#endif tcg_out_call (s, (tcg_target_long) qemu_st_helpers[opc], 1); label2_ptr = s->code_ptr; tcg_out32 (s, B); diff --git a/tcg/ppc64/tcg-target.c b/tcg/ppc64/tcg-target.c index 7f723b5c2c..409a1ac1ce 100644 --- a/tcg/ppc64/tcg-target.c +++ b/tcg/ppc64/tcg-target.c @@ -552,6 +552,27 @@ static void tcg_out_ldsta (TCGContext *s, int ret, int addr, #include "../../softmmu_defs.h" +#ifdef CONFIG_TCG_PASS_AREG0 +/* helper signature: helper_ld_mmu(CPUState *env, target_ulong addr, + int mmu_idx) */ +static const void * const qemu_ld_helpers[4] = { + helper_ldb_mmu, + helper_ldw_mmu, + helper_ldl_mmu, + helper_ldq_mmu, +}; + +/* helper signature: helper_st_mmu(CPUState *env, target_ulong addr, + uintxx_t val, int mmu_idx) */ +static const void * const qemu_st_helpers[4] = { + helper_stb_mmu, + helper_stw_mmu, + helper_stl_mmu, + helper_stq_mmu, +}; +#else +/* legacy helper signature: __ld_mmu(target_ulong addr, int + mmu_idx) */ static void *qemu_ld_helpers[4] = { __ldb_mmu, __ldw_mmu, @@ -559,12 +580,15 @@ static void *qemu_ld_helpers[4] = { __ldq_mmu, }; +/* legacy helper signature: __st_mmu(target_ulong addr, uintxx_t val, + int mmu_idx) */ static void *qemu_st_helpers[4] = { __stb_mmu, __stw_mmu, __stl_mmu, __stq_mmu, }; +#endif static void tcg_out_tlb_read (TCGContext *s, int r0, int r1, int r2, int addr_reg, int s_bits, int offset) @@ -648,6 +672,15 @@ static void tcg_out_qemu_ld (TCGContext *s, const TCGArg *args, int opc) tcg_out_mov (s, TCG_TYPE_I64, 3, addr_reg); tcg_out_movi (s, TCG_TYPE_I64, 4, mem_index); +#ifdef CONFIG_TCG_PASS_AREG0 + /* XXX/FIXME: suboptimal */ + tcg_out_mov(s, TCG_TYPE_I32, tcg_target_call_iarg_regs[2], + tcg_target_call_iarg_regs[1]); + tcg_out_mov(s, TCG_TYPE_TL, tcg_target_call_iarg_regs[1], + tcg_target_call_iarg_regs[0]); + tcg_out_mov(s, TCG_TYPE_PTR, tcg_target_call_iarg_regs[0], + TCG_AREG0); +#endif tcg_out_call (s, (tcg_target_long) qemu_ld_helpers[s_bits], 1); switch (opc) { @@ -796,6 +829,17 @@ static void tcg_out_qemu_st (TCGContext *s, const TCGArg *args, int opc) tcg_out_rld (s, RLDICL, 4, data_reg, 0, 64 - (1 << (3 + opc))); tcg_out_movi (s, TCG_TYPE_I64, 5, mem_index); +#ifdef CONFIG_TCG_PASS_AREG0 + /* XXX/FIXME: suboptimal */ + tcg_out_mov(s, TCG_TYPE_I32, tcg_target_call_iarg_regs[3], + tcg_target_call_iarg_regs[2]); + tcg_out_mov(s, TCG_TYPE_I64, tcg_target_call_iarg_regs[2], + tcg_target_call_iarg_regs[1]); + tcg_out_mov(s, TCG_TYPE_TL, tcg_target_call_iarg_regs[1], + tcg_target_call_iarg_regs[0]); + tcg_out_mov(s, TCG_TYPE_PTR, tcg_target_call_iarg_regs[0], + TCG_AREG0); +#endif tcg_out_call (s, (tcg_target_long) qemu_st_helpers[opc], 1); label2_ptr = s->code_ptr; diff --git a/tcg/s390/tcg-target.c b/tcg/s390/tcg-target.c index 47ffcc1f51..04662c15fd 100644 --- a/tcg/s390/tcg-target.c +++ b/tcg/s390/tcg-target.c @@ -301,6 +301,27 @@ static const uint8_t tcg_cond_to_ltr_cond[10] = { #include "../../softmmu_defs.h" +#ifdef CONFIG_TCG_PASS_AREG0 +/* helper signature: helper_ld_mmu(CPUState *env, target_ulong addr, + int mmu_idx) */ +static const void * const qemu_ld_helpers[4] = { + helper_ldb_mmu, + helper_ldw_mmu, + helper_ldl_mmu, + helper_ldq_mmu, +}; + +/* helper signature: helper_st_mmu(CPUState *env, target_ulong addr, + uintxx_t val, int mmu_idx) */ +static const void * const qemu_st_helpers[4] = { + helper_stb_mmu, + helper_stw_mmu, + helper_stl_mmu, + helper_stq_mmu, +}; +#else +/* legacy helper signature: __ld_mmu(target_ulong addr, int + mmu_idx) */ static void *qemu_ld_helpers[4] = { __ldb_mmu, __ldw_mmu, @@ -308,6 +329,8 @@ static void *qemu_ld_helpers[4] = { __ldq_mmu, }; +/* legacy helper signature: __st_mmu(target_ulong addr, uintxx_t val, + int mmu_idx) */ static void *qemu_st_helpers[4] = { __stb_mmu, __stw_mmu, @@ -315,6 +338,7 @@ static void *qemu_st_helpers[4] = { __stq_mmu, }; #endif +#endif static uint8_t *tb_ret_addr; @@ -1483,9 +1507,29 @@ static void tcg_prepare_qemu_ldst(TCGContext* s, TCGReg data_reg, tcg_abort(); } tcg_out_movi(s, TCG_TYPE_I32, TCG_REG_R4, mem_index); +#ifdef CONFIG_TCG_PASS_AREG0 + /* XXX/FIXME: suboptimal */ + tcg_out_mov(s, TCG_TYPE_I32, tcg_target_call_iarg_regs[2], + tcg_target_call_iarg_regs[1]); + tcg_out_mov(s, TCG_TYPE_TL, tcg_target_call_iarg_regs[1], + tcg_target_call_iarg_regs[0]); + tcg_out_mov(s, TCG_TYPE_PTR, tcg_target_call_iarg_regs[0], + TCG_AREG0); +#endif tgen_calli(s, (tcg_target_ulong)qemu_st_helpers[s_bits]); } else { tcg_out_movi(s, TCG_TYPE_I32, arg1, mem_index); +#ifdef CONFIG_TCG_PASS_AREG0 + /* XXX/FIXME: suboptimal */ + tcg_out_mov(s, TCG_TYPE_I32, tcg_target_call_iarg_regs[3], + tcg_target_call_iarg_regs[2]); + tcg_out_mov(s, TCG_TYPE_I64, tcg_target_call_iarg_regs[2], + tcg_target_call_iarg_regs[1]); + tcg_out_mov(s, TCG_TYPE_TL, tcg_target_call_iarg_regs[1], + tcg_target_call_iarg_regs[0]); + tcg_out_mov(s, TCG_TYPE_PTR, tcg_target_call_iarg_regs[0], + TCG_AREG0); +#endif tgen_calli(s, (tcg_target_ulong)qemu_ld_helpers[s_bits]); /* sign extension */ diff --git a/tcg/sparc/tcg-target.c b/tcg/sparc/tcg-target.c index b287122df5..80f0818679 100644 --- a/tcg/sparc/tcg-target.c +++ b/tcg/sparc/tcg-target.c @@ -59,6 +59,12 @@ static const char * const tcg_target_reg_names[TCG_TARGET_NB_REGS] = { }; #endif +#ifdef CONFIG_TCG_PASS_AREG0 +#define ARG_OFFSET 1 +#else +#define ARG_OFFSET 0 +#endif + static const int tcg_target_reg_alloc_order[] = { TCG_REG_L0, TCG_REG_L1, @@ -86,9 +92,9 @@ static const int tcg_target_call_iarg_regs[6] = { static const int tcg_target_call_oarg_regs[] = { TCG_REG_O0, -#if TCG_TARGET_REG_BITS == 32 - TCG_REG_O1 -#endif + TCG_REG_O1, + TCG_REG_O2, + TCG_REG_O3, }; static inline int check_fit_tl(tcg_target_long val, unsigned int bits) @@ -155,6 +161,9 @@ static int target_parse_constraint(TCGArgConstraint *ct, const char **pct_str) tcg_regset_reset_reg(ct->u.regs, TCG_REG_O0); tcg_regset_reset_reg(ct->u.regs, TCG_REG_O1); tcg_regset_reset_reg(ct->u.regs, TCG_REG_O2); +#ifdef CONFIG_TCG_PASS_AREG0 + tcg_regset_reset_reg(ct->u.regs, TCG_REG_O3); +#endif break; case 'I': ct->ct |= TCG_CT_CONST_S11; @@ -706,6 +715,27 @@ static void tcg_target_qemu_prologue(TCGContext *s) #include "../../softmmu_defs.h" +#ifdef CONFIG_TCG_PASS_AREG0 +/* helper signature: helper_ld_mmu(CPUState *env, target_ulong addr, + int mmu_idx) */ +static const void * const qemu_ld_helpers[4] = { + helper_ldb_mmu, + helper_ldw_mmu, + helper_ldl_mmu, + helper_ldq_mmu, +}; + +/* helper signature: helper_st_mmu(CPUState *env, target_ulong addr, + uintxx_t val, int mmu_idx) */ +static const void * const qemu_st_helpers[4] = { + helper_stb_mmu, + helper_stw_mmu, + helper_stl_mmu, + helper_stq_mmu, +}; +#else +/* legacy helper signature: __ld_mmu(target_ulong addr, int + mmu_idx) */ static const void * const qemu_ld_helpers[4] = { __ldb_mmu, __ldw_mmu, @@ -713,6 +743,8 @@ static const void * const qemu_ld_helpers[4] = { __ldq_mmu, }; +/* legacy helper signature: __st_mmu(target_ulong addr, uintxx_t val, + int mmu_idx) */ static const void * const qemu_st_helpers[4] = { __stb_mmu, __stw_mmu, @@ -720,6 +752,7 @@ static const void * const qemu_st_helpers[4] = { __stq_mmu, }; #endif +#endif #if TARGET_LONG_BITS == 32 #define TARGET_LD_OP LDUW @@ -801,6 +834,17 @@ static void tcg_out_qemu_ld(TCGContext *s, const TCGArg *args, /* mov */ tcg_out_movi(s, TCG_TYPE_I32, arg1, mem_index); +#ifdef CONFIG_TCG_PASS_AREG0 + /* XXX/FIXME: suboptimal */ + tcg_out_mov(s, TCG_TYPE_I32, tcg_target_call_iarg_regs[3], + tcg_target_call_iarg_regs[2]); + tcg_out_mov(s, TCG_TYPE_I64, tcg_target_call_iarg_regs[2], + tcg_target_call_iarg_regs[1]); + tcg_out_mov(s, TCG_TYPE_TL, tcg_target_call_iarg_regs[1], + tcg_target_call_iarg_regs[0]); + tcg_out_mov(s, TCG_TYPE_PTR, tcg_target_call_iarg_regs[0], + TCG_AREG0); +#endif /* XXX: move that code at the end of the TB */ /* qemu_ld_helper[s_bits](arg0, arg1) */ diff --git a/tcg/tci/tcg-target.c b/tcg/tci/tcg-target.c index bd85073662..453f1875e2 100644 --- a/tcg/tci/tcg-target.c +++ b/tcg/tci/tcg-target.c @@ -798,6 +798,9 @@ static void tcg_out_op(TCGContext *s, TCGOpcode opc, const TCGArg *args, case INDEX_op_qemu_st8: case INDEX_op_qemu_st16: case INDEX_op_qemu_st32: +#ifdef CONFIG_TCG_PASS_AREG0 + tcg_out_r(s, TCG_AREG0); +#endif tcg_out_r(s, *args++); tcg_out_r(s, *args++); #if TARGET_LONG_BITS > TCG_TARGET_REG_BITS @@ -808,6 +811,9 @@ static void tcg_out_op(TCGContext *s, TCGOpcode opc, const TCGArg *args, #endif break; case INDEX_op_qemu_st64: +#ifdef CONFIG_TCG_PASS_AREG0 + tcg_out_r(s, TCG_AREG0); +#endif tcg_out_r(s, *args++); #if TCG_TARGET_REG_BITS == 32 tcg_out_r(s, *args++); From 57d585f7d14fefc8ebf2b29b2b5a955bec77b5da Mon Sep 17 00:00:00 2001 From: Blue Swirl Date: Tue, 12 Jul 2011 13:14:47 +0000 Subject: [PATCH 38/42] TCG: add 5 arg helpers to def-helper.h Signed-off-by: Blue Swirl --- def-helper.h | 26 ++++++++++++++++++++++++++ 1 file changed, 26 insertions(+) diff --git a/def-helper.h b/def-helper.h index 5d057d68d6..0e70c31bc4 100644 --- a/def-helper.h +++ b/def-helper.h @@ -118,6 +118,8 @@ DEF_HELPER_FLAGS_3(name, 0, ret, t1, t2, t3) #define DEF_HELPER_4(name, ret, t1, t2, t3, t4) \ DEF_HELPER_FLAGS_4(name, 0, ret, t1, t2, t3, t4) +#define DEF_HELPER_5(name, ret, t1, t2, t3, t4, t5) \ + DEF_HELPER_FLAGS_5(name, 0, ret, t1, t2, t3, t4, t5) #endif /* DEF_HELPER_H */ @@ -140,6 +142,10 @@ dh_ctype(ret) HELPER(name) (dh_ctype(t1), dh_ctype(t2), dh_ctype(t3)); dh_ctype(ret) HELPER(name) (dh_ctype(t1), dh_ctype(t2), dh_ctype(t3), \ dh_ctype(t4)); +#define DEF_HELPER_FLAGS_5(name, flags, ret, t1, t2, t3, t4, t5) \ +dh_ctype(ret) HELPER(name) (dh_ctype(t1), dh_ctype(t2), dh_ctype(t3), \ + dh_ctype(t4), dh_ctype(t5)); + #undef GEN_HELPER #define GEN_HELPER -1 @@ -203,6 +209,22 @@ static inline void glue(gen_helper_, name)(dh_retvar_decl(ret) dh_arg_decl(t1, 1 tcg_gen_helperN(HELPER(name), flags, sizemask, dh_retvar(ret), 4, args); \ } +#define DEF_HELPER_FLAGS_5(name, flags, ret, t1, t2, t3, t4, t5) \ +static inline void glue(gen_helper_, name)(dh_retvar_decl(ret) \ + dh_arg_decl(t1, 1), dh_arg_decl(t2, 2), dh_arg_decl(t3, 3), \ + dh_arg_decl(t4, 4), dh_arg_decl(t5, 5)) \ +{ \ + TCGArg args[5]; \ + int sizemask = 0; \ + dh_sizemask(ret, 0); \ + dh_arg(t1, 1); \ + dh_arg(t2, 2); \ + dh_arg(t3, 3); \ + dh_arg(t4, 4); \ + dh_arg(t5, 5); \ + tcg_gen_helperN(HELPER(name), flags, sizemask, dh_retvar(ret), 5, args); \ +} + #undef GEN_HELPER #define GEN_HELPER -1 @@ -224,6 +246,9 @@ DEF_HELPER_FLAGS_0(name, flags, ret) #define DEF_HELPER_FLAGS_4(name, flags, ret, t1, t2, t3, t4) \ DEF_HELPER_FLAGS_0(name, flags, ret) +#define DEF_HELPER_FLAGS_5(name, flags, ret, t1, t2, t3, t4, t5) \ +DEF_HELPER_FLAGS_0(name, flags, ret) + #undef GEN_HELPER #define GEN_HELPER -1 @@ -235,6 +260,7 @@ DEF_HELPER_FLAGS_0(name, flags, ret) #undef DEF_HELPER_FLAGS_2 #undef DEF_HELPER_FLAGS_3 #undef DEF_HELPER_FLAGS_4 +#undef DEF_HELPER_FLAGS_5 #undef GEN_HELPER #endif From fe8d8f0f1c3ed0f5e84edffbbc8fcdf3b7da589b Mon Sep 17 00:00:00 2001 From: Blue Swirl Date: Mon, 4 Jul 2011 20:34:28 +0000 Subject: [PATCH 39/42] Sparc: avoid AREG0 for memory access helpers Make memory access helpers take a parameter for CPUState instead of relying on global env. Introduce wrappers for load and store ops. Signed-off-by: Blue Swirl --- Makefile.target | 2 +- target-sparc/cpu.h | 84 ++++++++- target-sparc/helper.h | 20 +-- target-sparc/ldst_helper.c | 356 +++++++++++++++++-------------------- target-sparc/op_helper.c | 102 ++++++++++- target-sparc/translate.c | 52 +++--- 6 files changed, 389 insertions(+), 227 deletions(-) diff --git a/Makefile.target b/Makefile.target index eb2594188a..d2ba029a94 100644 --- a/Makefile.target +++ b/Makefile.target @@ -103,7 +103,7 @@ $(libobj-y): $(GENERATED_HEADERS) # HELPER_CFLAGS is used for all the code compiled with static register # variables -op_helper.o ldst_helper.o user-exec.o: QEMU_CFLAGS += $(HELPER_CFLAGS) +op_helper.o user-exec.o: QEMU_CFLAGS += $(HELPER_CFLAGS) # Note: this is a workaround. The real fix is to avoid compiling # cpu_signal_handler() in user-exec.c. diff --git a/target-sparc/cpu.h b/target-sparc/cpu.h index f638457a89..ee28daa507 100644 --- a/target-sparc/cpu.h +++ b/target-sparc/cpu.h @@ -586,8 +586,90 @@ void cpu_unassigned_access(CPUSPARCState *env1, target_phys_addr_t addr, #if defined(TARGET_SPARC64) target_phys_addr_t cpu_get_phys_page_nofault(CPUSPARCState *env, target_ulong addr, int mmu_idx); - #endif + +#define WRAP_LD(rettype, fn) \ + rettype cpu_ ## fn (CPUSPARCState *env1, target_ulong addr) + +WRAP_LD(uint32_t, ldub_kernel); +WRAP_LD(uint32_t, lduw_kernel); +WRAP_LD(uint32_t, ldl_kernel); +WRAP_LD(uint64_t, ldq_kernel); + +WRAP_LD(uint32_t, ldub_user); +WRAP_LD(uint32_t, lduw_user); +WRAP_LD(uint32_t, ldl_user); +WRAP_LD(uint64_t, ldq_user); + +WRAP_LD(uint64_t, ldfq_kernel); +WRAP_LD(uint64_t, ldfq_user); + +#ifdef TARGET_SPARC64 +WRAP_LD(uint32_t, ldub_hypv); +WRAP_LD(uint32_t, lduw_hypv); +WRAP_LD(uint32_t, ldl_hypv); +WRAP_LD(uint64_t, ldq_hypv); + +WRAP_LD(uint64_t, ldfq_hypv); + +WRAP_LD(uint32_t, ldub_nucleus); +WRAP_LD(uint32_t, lduw_nucleus); +WRAP_LD(uint32_t, ldl_nucleus); +WRAP_LD(uint64_t, ldq_nucleus); + +WRAP_LD(uint32_t, ldub_kernel_secondary); +WRAP_LD(uint32_t, lduw_kernel_secondary); +WRAP_LD(uint32_t, ldl_kernel_secondary); +WRAP_LD(uint64_t, ldq_kernel_secondary); + +WRAP_LD(uint32_t, ldub_user_secondary); +WRAP_LD(uint32_t, lduw_user_secondary); +WRAP_LD(uint32_t, ldl_user_secondary); +WRAP_LD(uint64_t, ldq_user_secondary); +#endif +#undef WRAP_LD + +#define WRAP_ST(datatype, fn) \ + void cpu_ ## fn (CPUSPARCState *env1, target_ulong addr, datatype val) + +WRAP_ST(uint32_t, stb_kernel); +WRAP_ST(uint32_t, stw_kernel); +WRAP_ST(uint32_t, stl_kernel); +WRAP_ST(uint64_t, stq_kernel); + +WRAP_ST(uint32_t, stb_user); +WRAP_ST(uint32_t, stw_user); +WRAP_ST(uint32_t, stl_user); +WRAP_ST(uint64_t, stq_user); + +WRAP_ST(uint64_t, stfq_kernel); +WRAP_ST(uint64_t, stfq_user); + +#ifdef TARGET_SPARC64 +WRAP_ST(uint32_t, stb_hypv); +WRAP_ST(uint32_t, stw_hypv); +WRAP_ST(uint32_t, stl_hypv); +WRAP_ST(uint64_t, stq_hypv); + +WRAP_ST(uint64_t, stfq_hypv); + +WRAP_ST(uint32_t, stb_nucleus); +WRAP_ST(uint32_t, stw_nucleus); +WRAP_ST(uint32_t, stl_nucleus); +WRAP_ST(uint64_t, stq_nucleus); + +WRAP_ST(uint32_t, stb_kernel_secondary); +WRAP_ST(uint32_t, stw_kernel_secondary); +WRAP_ST(uint32_t, stl_kernel_secondary); +WRAP_ST(uint64_t, stq_kernel_secondary); + +WRAP_ST(uint32_t, stb_user_secondary); +WRAP_ST(uint32_t, stw_user_secondary); +WRAP_ST(uint32_t, stl_user_secondary); +WRAP_ST(uint64_t, stq_user_secondary); +#endif + +#undef WRAP_ST #endif int cpu_sparc_signal_handler(int host_signum, void *pinfo, void *puc); diff --git a/target-sparc/helper.h b/target-sparc/helper.h index 1f67b08065..c4d6225102 100644 --- a/target-sparc/helper.h +++ b/target-sparc/helper.h @@ -18,11 +18,11 @@ DEF_HELPER_1(rdcwp, tl, env) DEF_HELPER_2(wrcwp, void, env, tl) DEF_HELPER_FLAGS_2(array8, TCG_CALL_CONST | TCG_CALL_PURE, tl, tl, tl) DEF_HELPER_1(popc, tl, tl) -DEF_HELPER_3(ldda_asi, void, tl, int, int) -DEF_HELPER_4(ldf_asi, void, tl, int, int, int) -DEF_HELPER_4(stf_asi, void, tl, int, int, int) -DEF_HELPER_4(cas_asi, tl, tl, tl, tl, i32) -DEF_HELPER_4(casx_asi, tl, tl, tl, tl, i32) +DEF_HELPER_4(ldda_asi, void, env, tl, int, int) +DEF_HELPER_5(ldf_asi, void, env, tl, int, int, int) +DEF_HELPER_5(stf_asi, void, env, tl, int, int, int) +DEF_HELPER_5(cas_asi, tl, env, tl, tl, tl, i32) +DEF_HELPER_5(casx_asi, tl, env, tl, tl, tl, i32) DEF_HELPER_2(set_softint, void, env, i64) DEF_HELPER_2(clear_softint, void, env, i64) DEF_HELPER_2(write_softint, void, env, i64) @@ -30,7 +30,7 @@ DEF_HELPER_2(tick_set_count, void, ptr, i64) DEF_HELPER_1(tick_get_count, i64, ptr) DEF_HELPER_2(tick_set_limit, void, ptr, i64) #endif -DEF_HELPER_2(check_align, void, tl, i32) +DEF_HELPER_3(check_align, void, env, tl, i32) DEF_HELPER_1(debug, void, env) DEF_HELPER_1(save, void, env) DEF_HELPER_1(restore, void, env) @@ -38,11 +38,11 @@ DEF_HELPER_3(udiv, tl, env, tl, tl) DEF_HELPER_3(udiv_cc, tl, env, tl, tl) DEF_HELPER_3(sdiv, tl, env, tl, tl) DEF_HELPER_3(sdiv_cc, tl, env, tl, tl) -DEF_HELPER_2(ldqf, void, tl, int) -DEF_HELPER_2(stqf, void, tl, int) +DEF_HELPER_3(ldqf, void, env, tl, int) +DEF_HELPER_3(stqf, void, env, tl, int) #if !defined(CONFIG_USER_ONLY) || defined(TARGET_SPARC64) -DEF_HELPER_4(ld_asi, i64, tl, int, int, int) -DEF_HELPER_4(st_asi, void, tl, i64, int, int) +DEF_HELPER_5(ld_asi, i64, env, tl, int, int, int) +DEF_HELPER_5(st_asi, void, env, tl, i64, int, int) #endif DEF_HELPER_2(ldfsr, void, env, i32) DEF_HELPER_FLAGS_1(fabss, TCG_CALL_CONST | TCG_CALL_PURE, f32, f32) diff --git a/target-sparc/ldst_helper.c b/target-sparc/ldst_helper.c index 97afdd32a5..8468cde07e 100644 --- a/target-sparc/ldst_helper.c +++ b/target-sparc/ldst_helper.c @@ -18,13 +18,8 @@ */ #include "cpu.h" -#include "dyngen-exec.h" #include "helper.h" -#if !defined(CONFIG_USER_ONLY) -#include "softmmu_exec.h" -#endif - //#define DEBUG_MMU //#define DEBUG_MXCC //#define DEBUG_UNALIGNED @@ -69,16 +64,6 @@ #define QT0 (env->qt0) #define QT1 (env->qt1) -#if !defined(CONFIG_USER_ONLY) -static void do_unassigned_access(target_phys_addr_t addr, int is_write, - int is_exec, int is_asi, int size); -#else -#ifdef TARGET_SPARC64 -static void do_unassigned_access(target_ulong addr, int is_write, int is_exec, - int is_asi, int size); -#endif -#endif - #if defined(TARGET_SPARC64) && !defined(CONFIG_USER_ONLY) /* Calculates TSB pointer value for fault page size 8k or 64k */ static uint64_t ultrasparc_tsb_pointer(uint64_t tsb_register, @@ -300,7 +285,7 @@ static inline int is_translating_asi(int asi) #endif } -static inline target_ulong asi_address_mask(CPUSPARCState *env1, +static inline target_ulong asi_address_mask(CPUSPARCState *env, int asi, target_ulong addr) { if (is_translating_asi(asi)) { @@ -310,7 +295,7 @@ static inline target_ulong asi_address_mask(CPUSPARCState *env1, } } -void helper_check_align(target_ulong addr, uint32_t align) +void helper_check_align(CPUSPARCState *env, target_ulong addr, uint32_t align) { if (addr & align) { #ifdef DEBUG_UNALIGNED @@ -372,7 +357,8 @@ static void dump_asi(const char *txt, target_ulong addr, int asi, int size, /* Leon3 cache control */ -static void leon3_cache_control_st(target_ulong addr, uint64_t val, int size) +static void leon3_cache_control_st(CPUSPARCState *env, target_ulong addr, + uint64_t val, int size) { DPRINTF_CACHE_CONTROL("st addr:%08x, val:%" PRIx64 ", size:%d\n", addr, val, size); @@ -404,7 +390,8 @@ static void leon3_cache_control_st(target_ulong addr, uint64_t val, int size) }; } -static uint64_t leon3_cache_control_ld(target_ulong addr, int size) +static uint64_t leon3_cache_control_ld(CPUSPARCState *env, target_ulong addr, + int size) { uint64_t ret = 0; @@ -436,14 +423,15 @@ static uint64_t leon3_cache_control_ld(target_ulong addr, int size) return ret; } -uint64_t helper_ld_asi(target_ulong addr, int asi, int size, int sign) +uint64_t helper_ld_asi(CPUSPARCState *env, target_ulong addr, int asi, int size, + int sign) { uint64_t ret = 0; #if defined(DEBUG_MXCC) || defined(DEBUG_ASI) uint32_t last_addr = addr; #endif - helper_check_align(addr, size - 1); + helper_check_align(env, addr, size - 1); switch (asi) { case 2: /* SuperSparc MXCC registers and Leon3 cache control */ switch (addr) { @@ -451,7 +439,7 @@ uint64_t helper_ld_asi(target_ulong addr, int asi, int size, int sign) case 0x08: /* Leon3 Instruction Cache config */ case 0x0C: /* Leon3 Date Cache config */ if (env->def->features & CPU_FEATURE_CACHE_CTRL) { - ret = leon3_cache_control_ld(addr, size); + ret = leon3_cache_control_ld(env, addr, size); } break; case 0x01c00a00: /* MXCC control register */ @@ -552,34 +540,34 @@ uint64_t helper_ld_asi(target_ulong addr, int asi, int size, int sign) case 0xa: /* User data access */ switch (size) { case 1: - ret = ldub_user(addr); + ret = cpu_ldub_user(env, addr); break; case 2: - ret = lduw_user(addr); + ret = cpu_lduw_user(env, addr); break; default: case 4: - ret = ldl_user(addr); + ret = cpu_ldl_user(env, addr); break; case 8: - ret = ldq_user(addr); + ret = cpu_ldq_user(env, addr); break; } break; case 0xb: /* Supervisor data access */ switch (size) { case 1: - ret = ldub_kernel(addr); + ret = cpu_ldub_kernel(env, addr); break; case 2: - ret = lduw_kernel(addr); + ret = cpu_lduw_kernel(env, addr); break; default: case 4: - ret = ldl_kernel(addr); + ret = cpu_ldl_kernel(env, addr); break; case 8: - ret = ldq_kernel(addr); + ret = cpu_ldq_kernel(env, addr); break; } break; @@ -669,7 +657,7 @@ uint64_t helper_ld_asi(target_ulong addr, int asi, int size, int sign) break; case 8: /* User code access, XXX */ default: - do_unassigned_access(addr, 0, 0, asi, size); + cpu_unassigned_access(env, addr, 0, 0, asi, size); ret = 0; break; } @@ -694,9 +682,10 @@ uint64_t helper_ld_asi(target_ulong addr, int asi, int size, int sign) return ret; } -void helper_st_asi(target_ulong addr, uint64_t val, int asi, int size) +void helper_st_asi(CPUSPARCState *env, target_ulong addr, uint64_t val, int asi, + int size) { - helper_check_align(addr, size - 1); + helper_check_align(env, addr, size - 1); switch (asi) { case 2: /* SuperSparc MXCC registers and Leon3 cache control */ switch (addr) { @@ -704,7 +693,7 @@ void helper_st_asi(target_ulong addr, uint64_t val, int asi, int size) case 0x08: /* Leon3 Instruction Cache config */ case 0x0C: /* Leon3 Date Cache config */ if (env->def->features & CPU_FEATURE_CACHE_CTRL) { - leon3_cache_control_st(addr, val, size); + leon3_cache_control_st(env, addr, val, size); } break; @@ -902,34 +891,34 @@ void helper_st_asi(target_ulong addr, uint64_t val, int asi, int size) case 0xa: /* User data access */ switch (size) { case 1: - stb_user(addr, val); + cpu_stb_user(env, addr, val); break; case 2: - stw_user(addr, val); + cpu_stw_user(env, addr, val); break; default: case 4: - stl_user(addr, val); + cpu_stl_user(env, addr, val); break; case 8: - stq_user(addr, val); + cpu_stq_user(env, addr, val); break; } break; case 0xb: /* Supervisor data access */ switch (size) { case 1: - stb_kernel(addr, val); + cpu_stb_kernel(env, addr, val); break; case 2: - stw_kernel(addr, val); + cpu_stw_kernel(env, addr, val); break; default: case 4: - stl_kernel(addr, val); + cpu_stl_kernel(env, addr, val); break; case 8: - stq_kernel(addr, val); + cpu_stq_kernel(env, addr, val); break; } break; @@ -952,8 +941,8 @@ void helper_st_asi(target_ulong addr, uint64_t val, int asi, int size) uint32_t src = val & ~3, dst = addr & ~3, temp; for (i = 0; i < 32; i += 4, src += 4, dst += 4) { - temp = ldl_kernel(src); - stl_kernel(dst, temp); + temp = cpu_ldl_kernel(env, src); + cpu_stl_kernel(env, dst, temp); } } break; @@ -965,7 +954,7 @@ void helper_st_asi(target_ulong addr, uint64_t val, int asi, int size) uint32_t dst = addr & 7; for (i = 0; i < 32; i += 8, dst += 8) { - stq_kernel(dst, val); + cpu_stq_kernel(env, dst, val); } } break; @@ -1056,7 +1045,7 @@ void helper_st_asi(target_ulong addr, uint64_t val, int asi, int size) case 8: /* User code access, XXX */ case 9: /* Supervisor code access, XXX */ default: - do_unassigned_access(addr, 1, 0, asi, size); + cpu_unassigned_access(env, addr, 1, 0, asi, size); break; } #ifdef DEBUG_ASI @@ -1068,7 +1057,8 @@ void helper_st_asi(target_ulong addr, uint64_t val, int asi, int size) #else /* TARGET_SPARC64 */ #ifdef CONFIG_USER_ONLY -uint64_t helper_ld_asi(target_ulong addr, int asi, int size, int sign) +uint64_t helper_ld_asi(CPUSPARCState *env, target_ulong addr, int asi, int size, + int sign) { uint64_t ret = 0; #if defined(DEBUG_ASI) @@ -1079,7 +1069,7 @@ uint64_t helper_ld_asi(target_ulong addr, int asi, int size, int sign) helper_raise_exception(env, TT_PRIV_ACT); } - helper_check_align(addr, size - 1); + helper_check_align(env, addr, size - 1); addr = asi_address_mask(env, asi, addr); switch (asi) { @@ -1174,7 +1164,8 @@ uint64_t helper_ld_asi(target_ulong addr, int asi, int size, int sign) return ret; } -void helper_st_asi(target_ulong addr, target_ulong val, int asi, int size) +void helper_st_asi(CPUSPARCState *env, target_ulong addr, target_ulong val, + int asi, int size) { #ifdef DEBUG_ASI dump_asi("write", addr, asi, size, val); @@ -1183,7 +1174,7 @@ void helper_st_asi(target_ulong addr, target_ulong val, int asi, int size) helper_raise_exception(env, TT_PRIV_ACT); } - helper_check_align(addr, size - 1); + helper_check_align(env, addr, size - 1); addr = asi_address_mask(env, asi, addr); /* Convert to little endian */ @@ -1238,14 +1229,15 @@ void helper_st_asi(target_ulong addr, target_ulong val, int asi, int size) case 0x8a: /* Primary no-fault LE, RO */ case 0x8b: /* Secondary no-fault LE, RO */ default: - do_unassigned_access(addr, 1, 0, 1, size); + helper_raise_exception(env, TT_DATA_ACCESS); return; } } #else /* CONFIG_USER_ONLY */ -uint64_t helper_ld_asi(target_ulong addr, int asi, int size, int sign) +uint64_t helper_ld_asi(CPUSPARCState *env, target_ulong addr, int asi, int size, + int sign) { uint64_t ret = 0; #if defined(DEBUG_ASI) @@ -1261,7 +1253,7 @@ uint64_t helper_ld_asi(target_ulong addr, int asi, int size, int sign) helper_raise_exception(env, TT_PRIV_ACT); } - helper_check_align(addr, size - 1); + helper_check_align(env, addr, size - 1); addr = asi_address_mask(env, asi, addr); /* process nonfaulting loads first */ @@ -1302,17 +1294,17 @@ uint64_t helper_ld_asi(target_ulong addr, int asi, int size, int sign) if (cpu_hypervisor_mode(env)) { switch (size) { case 1: - ret = ldub_hypv(addr); + ret = cpu_ldub_hypv(env, addr); break; case 2: - ret = lduw_hypv(addr); + ret = cpu_lduw_hypv(env, addr); break; case 4: - ret = ldl_hypv(addr); + ret = cpu_ldl_hypv(env, addr); break; default: case 8: - ret = ldq_hypv(addr); + ret = cpu_ldq_hypv(env, addr); break; } } else { @@ -1320,33 +1312,33 @@ uint64_t helper_ld_asi(target_ulong addr, int asi, int size, int sign) if (asi & 1) { switch (size) { case 1: - ret = ldub_kernel_secondary(addr); + ret = cpu_ldub_kernel_secondary(env, addr); break; case 2: - ret = lduw_kernel_secondary(addr); + ret = cpu_lduw_kernel_secondary(env, addr); break; case 4: - ret = ldl_kernel_secondary(addr); + ret = cpu_ldl_kernel_secondary(env, addr); break; default: case 8: - ret = ldq_kernel_secondary(addr); + ret = cpu_ldq_kernel_secondary(env, addr); break; } } else { switch (size) { case 1: - ret = ldub_kernel(addr); + ret = cpu_ldub_kernel(env, addr); break; case 2: - ret = lduw_kernel(addr); + ret = cpu_lduw_kernel(env, addr); break; case 4: - ret = ldl_kernel(addr); + ret = cpu_ldl_kernel(env, addr); break; default: case 8: - ret = ldq_kernel(addr); + ret = cpu_ldq_kernel(env, addr); break; } } @@ -1356,33 +1348,33 @@ uint64_t helper_ld_asi(target_ulong addr, int asi, int size, int sign) if (asi & 1) { switch (size) { case 1: - ret = ldub_user_secondary(addr); + ret = cpu_ldub_user_secondary(env, addr); break; case 2: - ret = lduw_user_secondary(addr); + ret = cpu_lduw_user_secondary(env, addr); break; case 4: - ret = ldl_user_secondary(addr); + ret = cpu_ldl_user_secondary(env, addr); break; default: case 8: - ret = ldq_user_secondary(addr); + ret = cpu_ldq_user_secondary(env, addr); break; } } else { switch (size) { case 1: - ret = ldub_user(addr); + ret = cpu_ldub_user(env, addr); break; case 2: - ret = lduw_user(addr); + ret = cpu_lduw_user(env, addr); break; case 4: - ret = ldl_user(addr); + ret = cpu_ldl_user(env, addr); break; default: case 8: - ret = ldq_user(addr); + ret = cpu_ldq_user(env, addr); break; } } @@ -1420,17 +1412,17 @@ uint64_t helper_ld_asi(target_ulong addr, int asi, int size, int sign) { switch (size) { case 1: - ret = ldub_nucleus(addr); + ret = cpu_ldub_nucleus(env, addr); break; case 2: - ret = lduw_nucleus(addr); + ret = cpu_lduw_nucleus(env, addr); break; case 4: - ret = ldl_nucleus(addr); + ret = cpu_ldl_nucleus(env, addr); break; default: case 8: - ret = ldq_nucleus(addr); + ret = cpu_ldq_nucleus(env, addr); break; } break; @@ -1559,7 +1551,7 @@ uint64_t helper_ld_asi(target_ulong addr, int asi, int size, int sign) case 0x5f: /* D-MMU demap, WO */ case 0x77: /* Interrupt vector, WO */ default: - do_unassigned_access(addr, 0, 0, 1, size); + cpu_unassigned_access(env, addr, 0, 0, 1, size); ret = 0; break; } @@ -1612,7 +1604,8 @@ uint64_t helper_ld_asi(target_ulong addr, int asi, int size, int sign) return ret; } -void helper_st_asi(target_ulong addr, target_ulong val, int asi, int size) +void helper_st_asi(CPUSPARCState *env, target_ulong addr, target_ulong val, + int asi, int size) { #ifdef DEBUG_ASI dump_asi("write", addr, asi, size, val); @@ -1627,7 +1620,7 @@ void helper_st_asi(target_ulong addr, target_ulong val, int asi, int size) helper_raise_exception(env, TT_PRIV_ACT); } - helper_check_align(addr, size - 1); + helper_check_align(env, addr, size - 1); addr = asi_address_mask(env, asi, addr); /* Convert to little endian */ @@ -1671,17 +1664,17 @@ void helper_st_asi(target_ulong addr, target_ulong val, int asi, int size) if (cpu_hypervisor_mode(env)) { switch (size) { case 1: - stb_hypv(addr, val); + cpu_stb_hypv(env, addr, val); break; case 2: - stw_hypv(addr, val); + cpu_stw_hypv(env, addr, val); break; case 4: - stl_hypv(addr, val); + cpu_stl_hypv(env, addr, val); break; case 8: default: - stq_hypv(addr, val); + cpu_stq_hypv(env, addr, val); break; } } else { @@ -1689,33 +1682,33 @@ void helper_st_asi(target_ulong addr, target_ulong val, int asi, int size) if (asi & 1) { switch (size) { case 1: - stb_kernel_secondary(addr, val); + cpu_stb_kernel_secondary(env, addr, val); break; case 2: - stw_kernel_secondary(addr, val); + cpu_stw_kernel_secondary(env, addr, val); break; case 4: - stl_kernel_secondary(addr, val); + cpu_stl_kernel_secondary(env, addr, val); break; case 8: default: - stq_kernel_secondary(addr, val); + cpu_stq_kernel_secondary(env, addr, val); break; } } else { switch (size) { case 1: - stb_kernel(addr, val); + cpu_stb_kernel(env, addr, val); break; case 2: - stw_kernel(addr, val); + cpu_stw_kernel(env, addr, val); break; case 4: - stl_kernel(addr, val); + cpu_stl_kernel(env, addr, val); break; case 8: default: - stq_kernel(addr, val); + cpu_stq_kernel(env, addr, val); break; } } @@ -1725,33 +1718,33 @@ void helper_st_asi(target_ulong addr, target_ulong val, int asi, int size) if (asi & 1) { switch (size) { case 1: - stb_user_secondary(addr, val); + cpu_stb_user_secondary(env, addr, val); break; case 2: - stw_user_secondary(addr, val); + cpu_stw_user_secondary(env, addr, val); break; case 4: - stl_user_secondary(addr, val); + cpu_stl_user_secondary(env, addr, val); break; case 8: default: - stq_user_secondary(addr, val); + cpu_stq_user_secondary(env, addr, val); break; } } else { switch (size) { case 1: - stb_user(addr, val); + cpu_stb_user(env, addr, val); break; case 2: - stw_user(addr, val); + cpu_stw_user(env, addr, val); break; case 4: - stl_user(addr, val); + cpu_stl_user(env, addr, val); break; case 8: default: - stq_user(addr, val); + cpu_stq_user(env, addr, val); break; } } @@ -1789,17 +1782,17 @@ void helper_st_asi(target_ulong addr, target_ulong val, int asi, int size) { switch (size) { case 1: - stb_nucleus(addr, val); + cpu_stb_nucleus(env, addr, val); break; case 2: - stw_nucleus(addr, val); + cpu_stw_nucleus(env, addr, val); break; case 4: - stl_nucleus(addr, val); + cpu_stl_nucleus(env, addr, val); break; default: case 8: - stq_nucleus(addr, val); + cpu_stq_nucleus(env, addr, val); break; } break; @@ -1991,13 +1984,13 @@ void helper_st_asi(target_ulong addr, target_ulong val, int asi, int size) case 0x8a: /* Primary no-fault LE, RO */ case 0x8b: /* Secondary no-fault LE, RO */ default: - do_unassigned_access(addr, 1, 0, 1, size); + cpu_unassigned_access(env, addr, 1, 0, 1, size); return; } } #endif /* CONFIG_USER_ONLY */ -void helper_ldda_asi(target_ulong addr, int asi, int rd) +void helper_ldda_asi(CPUSPARCState *env, target_ulong addr, int asi, int rd) { if ((asi < 0x80 && (env->pstate & PS_PRIV) == 0) || (cpu_has_hypervisor(env) @@ -2012,22 +2005,22 @@ void helper_ldda_asi(target_ulong addr, int asi, int rd) #if !defined(CONFIG_USER_ONLY) case 0x24: /* Nucleus quad LDD 128 bit atomic */ case 0x2c: /* Nucleus quad LDD 128 bit atomic LE */ - helper_check_align(addr, 0xf); + helper_check_align(env, addr, 0xf); if (rd == 0) { - env->gregs[1] = ldq_nucleus(addr + 8); + env->gregs[1] = cpu_ldq_nucleus(env, addr + 8); if (asi == 0x2c) { bswap64s(&env->gregs[1]); } } else if (rd < 8) { - env->gregs[rd] = ldq_nucleus(addr); - env->gregs[rd + 1] = ldq_nucleus(addr + 8); + env->gregs[rd] = cpu_ldq_nucleus(env, addr); + env->gregs[rd + 1] = cpu_ldq_nucleus(env, addr + 8); if (asi == 0x2c) { bswap64s(&env->gregs[rd]); bswap64s(&env->gregs[rd + 1]); } } else { - env->regwptr[rd] = ldq_nucleus(addr); - env->regwptr[rd + 1] = ldq_nucleus(addr + 8); + env->regwptr[rd] = cpu_ldq_nucleus(env, addr); + env->regwptr[rd + 1] = cpu_ldq_nucleus(env, addr + 8); if (asi == 0x2c) { bswap64s(&env->regwptr[rd]); bswap64s(&env->regwptr[rd + 1]); @@ -2036,26 +2029,27 @@ void helper_ldda_asi(target_ulong addr, int asi, int rd) break; #endif default: - helper_check_align(addr, 0x3); + helper_check_align(env, addr, 0x3); if (rd == 0) { - env->gregs[1] = helper_ld_asi(addr + 4, asi, 4, 0); + env->gregs[1] = helper_ld_asi(env, addr + 4, asi, 4, 0); } else if (rd < 8) { - env->gregs[rd] = helper_ld_asi(addr, asi, 4, 0); - env->gregs[rd + 1] = helper_ld_asi(addr + 4, asi, 4, 0); + env->gregs[rd] = helper_ld_asi(env, addr, asi, 4, 0); + env->gregs[rd + 1] = helper_ld_asi(env, addr + 4, asi, 4, 0); } else { - env->regwptr[rd] = helper_ld_asi(addr, asi, 4, 0); - env->regwptr[rd + 1] = helper_ld_asi(addr + 4, asi, 4, 0); + env->regwptr[rd] = helper_ld_asi(env, addr, asi, 4, 0); + env->regwptr[rd + 1] = helper_ld_asi(env, addr + 4, asi, 4, 0); } break; } } -void helper_ldf_asi(target_ulong addr, int asi, int size, int rd) +void helper_ldf_asi(CPUSPARCState *env, target_ulong addr, int asi, int size, + int rd) { unsigned int i; target_ulong val; - helper_check_align(addr, 3); + helper_check_align(env, addr, 3); addr = asi_address_mask(env, asi, addr); switch (asi) { @@ -2067,9 +2061,9 @@ void helper_ldf_asi(target_ulong addr, int asi, int size, int rd) helper_raise_exception(env, TT_ILL_INSN); return; } - helper_check_align(addr, 0x3f); + helper_check_align(env, addr, 0x3f); for (i = 0; i < 8; i++, rd += 2, addr += 8) { - env->fpr[rd/2].ll = helper_ld_asi(addr, asi & 0x8f, 8, 0); + env->fpr[rd / 2].ll = helper_ld_asi(env, addr, asi & 0x8f, 8, 0); } return; @@ -2085,9 +2079,9 @@ void helper_ldf_asi(target_ulong addr, int asi, int size, int rd) helper_raise_exception(env, TT_ILL_INSN); return; } - helper_check_align(addr, 0x3f); + helper_check_align(env, addr, 0x3f); for (i = 0; i < 8; i++, rd += 2, addr += 4) { - env->fpr[rd/2].ll = helper_ld_asi(addr, asi & 0x19, 8, 0); + env->fpr[rd / 2].ll = helper_ld_asi(env, addr, asi & 0x19, 8, 0); } return; @@ -2098,29 +2092,30 @@ void helper_ldf_asi(target_ulong addr, int asi, int size, int rd) switch (size) { default: case 4: - val = helper_ld_asi(addr, asi, size, 0); + val = helper_ld_asi(env, addr, asi, size, 0); if (rd & 1) { - env->fpr[rd/2].l.lower = val; + env->fpr[rd / 2].l.lower = val; } else { - env->fpr[rd/2].l.upper = val; + env->fpr[rd / 2].l.upper = val; } break; case 8: - env->fpr[rd/2].ll = helper_ld_asi(addr, asi, size, 0); + env->fpr[rd / 2].ll = helper_ld_asi(env, addr, asi, size, 0); break; case 16: - env->fpr[rd/2].ll = helper_ld_asi(addr, asi, 8, 0); - env->fpr[rd/2 + 1].ll = helper_ld_asi(addr + 8, asi, 8, 0); + env->fpr[rd / 2].ll = helper_ld_asi(env, addr, asi, 8, 0); + env->fpr[rd / 2 + 1].ll = helper_ld_asi(env, addr + 8, asi, 8, 0); break; } } -void helper_stf_asi(target_ulong addr, int asi, int size, int rd) +void helper_stf_asi(CPUSPARCState *env, target_ulong addr, int asi, int size, + int rd) { unsigned int i; target_ulong val; - helper_check_align(addr, 3); + helper_check_align(env, addr, 3); addr = asi_address_mask(env, asi, addr); switch (asi) { @@ -2134,9 +2129,9 @@ void helper_stf_asi(target_ulong addr, int asi, int size, int rd) helper_raise_exception(env, TT_ILL_INSN); return; } - helper_check_align(addr, 0x3f); + helper_check_align(env, addr, 0x3f); for (i = 0; i < 8; i++, rd += 2, addr += 8) { - helper_st_asi(addr, env->fpr[rd/2].ll, asi & 0x8f, 8); + helper_st_asi(env, addr, env->fpr[rd / 2].ll, asi & 0x8f, 8); } return; @@ -2152,9 +2147,9 @@ void helper_stf_asi(target_ulong addr, int asi, int size, int rd) helper_raise_exception(env, TT_ILL_INSN); return; } - helper_check_align(addr, 0x3f); + helper_check_align(env, addr, 0x3f); for (i = 0; i < 8; i++, rd += 2, addr += 8) { - helper_st_asi(addr, env->fpr[rd/2].ll, asi & 0x19, 8); + helper_st_asi(env, addr, env->fpr[rd / 2].ll, asi & 0x19, 8); } return; @@ -2166,71 +2161,72 @@ void helper_stf_asi(target_ulong addr, int asi, int size, int rd) default: case 4: if (rd & 1) { - val = env->fpr[rd/2].l.lower; + val = env->fpr[rd / 2].l.lower; } else { - val = env->fpr[rd/2].l.upper; + val = env->fpr[rd / 2].l.upper; } - helper_st_asi(addr, val, asi, size); + helper_st_asi(env, addr, val, asi, size); break; case 8: - helper_st_asi(addr, env->fpr[rd/2].ll, asi, size); + helper_st_asi(env, addr, env->fpr[rd / 2].ll, asi, size); break; case 16: - helper_st_asi(addr, env->fpr[rd/2].ll, asi, 8); - helper_st_asi(addr + 8, env->fpr[rd/2 + 1].ll, asi, 8); + helper_st_asi(env, addr, env->fpr[rd / 2].ll, asi, 8); + helper_st_asi(env, addr + 8, env->fpr[rd / 2 + 1].ll, asi, 8); break; } } -target_ulong helper_cas_asi(target_ulong addr, target_ulong val1, - target_ulong val2, uint32_t asi) +target_ulong helper_cas_asi(CPUSPARCState *env, target_ulong addr, + target_ulong val1, target_ulong val2, uint32_t asi) { target_ulong ret; val2 &= 0xffffffffUL; - ret = helper_ld_asi(addr, asi, 4, 0); + ret = helper_ld_asi(env, addr, asi, 4, 0); ret &= 0xffffffffUL; if (val2 == ret) { - helper_st_asi(addr, val1 & 0xffffffffUL, asi, 4); + helper_st_asi(env, addr, val1 & 0xffffffffUL, asi, 4); } return ret; } -target_ulong helper_casx_asi(target_ulong addr, target_ulong val1, - target_ulong val2, uint32_t asi) +target_ulong helper_casx_asi(CPUSPARCState *env, target_ulong addr, + target_ulong val1, target_ulong val2, + uint32_t asi) { target_ulong ret; - ret = helper_ld_asi(addr, asi, 8, 0); + ret = helper_ld_asi(env, addr, asi, 8, 0); if (val2 == ret) { - helper_st_asi(addr, val1, asi, 8); + helper_st_asi(env, addr, val1, asi, 8); } return ret; } #endif /* TARGET_SPARC64 */ -void helper_ldqf(target_ulong addr, int mem_idx) +void helper_ldqf(CPUSPARCState *env, target_ulong addr, int mem_idx) { /* XXX add 128 bit load */ CPU_QuadU u; - helper_check_align(addr, 7); + helper_check_align(env, addr, 7); #if !defined(CONFIG_USER_ONLY) switch (mem_idx) { case MMU_USER_IDX: - u.ll.upper = ldq_user(addr); - u.ll.lower = ldq_user(addr + 8); + u.ll.upper = cpu_ldq_user(env, addr); + u.ll.lower = cpu_ldq_user(env, addr + 8); QT0 = u.q; break; case MMU_KERNEL_IDX: - u.ll.upper = ldq_kernel(addr); - u.ll.lower = ldq_kernel(addr + 8); + u.ll.upper = cpu_ldq_kernel(env, addr); + u.ll.lower = cpu_ldq_kernel(env, addr + 8); QT0 = u.q; break; #ifdef TARGET_SPARC64 case MMU_HYPV_IDX: - u.ll.upper = ldq_hypv(addr); - u.ll.lower = ldq_hypv(addr + 8); + u.ll.upper = cpu_ldq_hypv(env, addr); + u.ll.lower = cpu_ldq_hypv(env, addr + 8); QT0 = u.q; break; #endif @@ -2245,29 +2241,29 @@ void helper_ldqf(target_ulong addr, int mem_idx) #endif } -void helper_stqf(target_ulong addr, int mem_idx) +void helper_stqf(CPUSPARCState *env, target_ulong addr, int mem_idx) { /* XXX add 128 bit store */ CPU_QuadU u; - helper_check_align(addr, 7); + helper_check_align(env, addr, 7); #if !defined(CONFIG_USER_ONLY) switch (mem_idx) { case MMU_USER_IDX: u.q = QT0; - stq_user(addr, u.ll.upper); - stq_user(addr + 8, u.ll.lower); + cpu_stq_user(env, addr, u.ll.upper); + cpu_stq_user(env, addr + 8, u.ll.lower); break; case MMU_KERNEL_IDX: u.q = QT0; - stq_kernel(addr, u.ll.upper); - stq_kernel(addr + 8, u.ll.lower); + cpu_stq_kernel(env, addr, u.ll.upper); + cpu_stq_kernel(env, addr + 8, u.ll.lower); break; #ifdef TARGET_SPARC64 case MMU_HYPV_IDX: u.q = QT0; - stq_hypv(addr, u.ll.upper); - stq_hypv(addr + 8, u.ll.lower); + cpu_stq_hypv(env, addr, u.ll.upper); + cpu_stq_hypv(env, addr + 8, u.ll.lower); break; #endif default: @@ -2281,10 +2277,10 @@ void helper_stqf(target_ulong addr, int mem_idx) #endif } -#ifndef TARGET_SPARC64 #if !defined(CONFIG_USER_ONLY) -static void do_unassigned_access(target_phys_addr_t addr, int is_write, - int is_exec, int is_asi, int size) +#ifndef TARGET_SPARC64 +void cpu_unassigned_access(CPUSPARCState *env, target_phys_addr_t addr, + int is_write, int is_exec, int is_asi, int size) { int fault_type; @@ -2342,15 +2338,9 @@ static void do_unassigned_access(target_phys_addr_t addr, int is_write, tlb_flush(env, 1); } } -#endif #else -#if defined(CONFIG_USER_ONLY) -static void do_unassigned_access(target_ulong addr, int is_write, int is_exec, - int is_asi, int size) -#else -static void do_unassigned_access(target_phys_addr_t addr, int is_write, - int is_exec, int is_asi, int size) -#endif +void cpu_unassigned_access(CPUSPARCState *env, target_phys_addr_t addr, + int is_write, int is_exec, int is_asi, int size) { #ifdef DEBUG_UNASSIGNED printf("Unassigned mem access to " TARGET_FMT_plx " from " TARGET_FMT_lx @@ -2364,16 +2354,4 @@ static void do_unassigned_access(target_phys_addr_t addr, int is_write, } } #endif - -#if !defined(CONFIG_USER_ONLY) -void cpu_unassigned_access(CPUSPARCState *env1, target_phys_addr_t addr, - int is_write, int is_exec, int is_asi, int size) -{ - CPUSPARCState *saved_env; - - saved_env = env; - env = env1; - do_unassigned_access(addr, is_write, is_exec, is_asi, size); - env = saved_env; -} #endif diff --git a/target-sparc/op_helper.c b/target-sparc/op_helper.c index 1aff12516e..b7171d8b94 100644 --- a/target-sparc/op_helper.c +++ b/target-sparc/op_helper.c @@ -3,6 +3,7 @@ #include "helper.h" #if !defined(CONFIG_USER_ONLY) +#include "softmmu_exec.h" static void do_unaligned_access(target_ulong addr, int is_write, int is_user, void *retaddr); @@ -71,4 +72,103 @@ void tlb_fill(CPUSPARCState *env1, target_ulong addr, int is_write, int mmu_idx, env = saved_env; } -#endif /* !CONFIG_USER_ONLY */ +#define WRAP_LD(rettype, fn) \ + rettype cpu_ ## fn (CPUSPARCState *env1, target_ulong addr) \ + { \ + CPUSPARCState *saved_env; \ + rettype ret; \ + \ + saved_env = env; \ + env = env1; \ + ret = fn(addr); \ + env = saved_env; \ + return ret; \ + } + +WRAP_LD(uint32_t, ldub_kernel) +WRAP_LD(uint32_t, lduw_kernel) +WRAP_LD(uint32_t, ldl_kernel) +WRAP_LD(uint64_t, ldq_kernel) + +WRAP_LD(uint32_t, ldub_user) +WRAP_LD(uint32_t, lduw_user) +WRAP_LD(uint32_t, ldl_user) +WRAP_LD(uint64_t, ldq_user) + +WRAP_LD(uint64_t, ldfq_kernel) +WRAP_LD(uint64_t, ldfq_user) +#ifdef TARGET_SPARC64 +WRAP_LD(uint32_t, ldub_hypv) +WRAP_LD(uint32_t, lduw_hypv) +WRAP_LD(uint32_t, ldl_hypv) +WRAP_LD(uint64_t, ldq_hypv) + +WRAP_LD(uint64_t, ldfq_hypv) + +WRAP_LD(uint32_t, ldub_nucleus) +WRAP_LD(uint32_t, lduw_nucleus) +WRAP_LD(uint32_t, ldl_nucleus) +WRAP_LD(uint64_t, ldq_nucleus) + +WRAP_LD(uint32_t, ldub_kernel_secondary) +WRAP_LD(uint32_t, lduw_kernel_secondary) +WRAP_LD(uint32_t, ldl_kernel_secondary) +WRAP_LD(uint64_t, ldq_kernel_secondary) + +WRAP_LD(uint32_t, ldub_user_secondary) +WRAP_LD(uint32_t, lduw_user_secondary) +WRAP_LD(uint32_t, ldl_user_secondary) +WRAP_LD(uint64_t, ldq_user_secondary) +#endif +#undef WRAP_LD + +#define WRAP_ST(datatype, fn) \ + void cpu_ ## fn (CPUSPARCState *env1, target_ulong addr, datatype val) \ + { \ + CPUSPARCState *saved_env; \ + \ + saved_env = env; \ + env = env1; \ + fn(addr, val); \ + env = saved_env; \ + } + +WRAP_ST(uint32_t, stb_kernel) +WRAP_ST(uint32_t, stw_kernel) +WRAP_ST(uint32_t, stl_kernel) +WRAP_ST(uint64_t, stq_kernel) + +WRAP_ST(uint32_t, stb_user) +WRAP_ST(uint32_t, stw_user) +WRAP_ST(uint32_t, stl_user) +WRAP_ST(uint64_t, stq_user) + +WRAP_ST(uint64_t, stfq_kernel) +WRAP_ST(uint64_t, stfq_user) + +#ifdef TARGET_SPARC64 +WRAP_ST(uint32_t, stb_hypv) +WRAP_ST(uint32_t, stw_hypv) +WRAP_ST(uint32_t, stl_hypv) +WRAP_ST(uint64_t, stq_hypv) + +WRAP_ST(uint64_t, stfq_hypv) + +WRAP_ST(uint32_t, stb_nucleus) +WRAP_ST(uint32_t, stw_nucleus) +WRAP_ST(uint32_t, stl_nucleus) +WRAP_ST(uint64_t, stq_nucleus) + +WRAP_ST(uint32_t, stb_kernel_secondary) +WRAP_ST(uint32_t, stw_kernel_secondary) +WRAP_ST(uint32_t, stl_kernel_secondary) +WRAP_ST(uint64_t, stq_kernel_secondary) + +WRAP_ST(uint32_t, stb_user_secondary) +WRAP_ST(uint32_t, stw_user_secondary) +WRAP_ST(uint32_t, stl_user_secondary) +WRAP_ST(uint64_t, stq_user_secondary) +#endif + +#undef WRAP_ST +#endif diff --git a/target-sparc/translate.c b/target-sparc/translate.c index ef176e94b3..670ea2b01f 100644 --- a/target-sparc/translate.c +++ b/target-sparc/translate.c @@ -1955,7 +1955,7 @@ static inline void gen_ld_asi(TCGv dst, TCGv addr, int insn, int size, r_asi = gen_get_asi(insn, addr); r_size = tcg_const_i32(size); r_sign = tcg_const_i32(sign); - gen_helper_ld_asi(dst, addr, r_asi, r_size, r_sign); + gen_helper_ld_asi(dst, cpu_env, addr, r_asi, r_size, r_sign); tcg_temp_free_i32(r_sign); tcg_temp_free_i32(r_size); tcg_temp_free_i32(r_asi); @@ -1967,7 +1967,7 @@ static inline void gen_st_asi(TCGv src, TCGv addr, int insn, int size) r_asi = gen_get_asi(insn, addr); r_size = tcg_const_i32(size); - gen_helper_st_asi(addr, src, r_asi, r_size); + gen_helper_st_asi(cpu_env, addr, src, r_asi, r_size); tcg_temp_free_i32(r_size); tcg_temp_free_i32(r_asi); } @@ -1979,7 +1979,7 @@ static inline void gen_ldf_asi(TCGv addr, int insn, int size, int rd) r_asi = gen_get_asi(insn, addr); r_size = tcg_const_i32(size); r_rd = tcg_const_i32(rd); - gen_helper_ldf_asi(addr, r_asi, r_size, r_rd); + gen_helper_ldf_asi(cpu_env, addr, r_asi, r_size, r_rd); tcg_temp_free_i32(r_rd); tcg_temp_free_i32(r_size); tcg_temp_free_i32(r_asi); @@ -1992,7 +1992,7 @@ static inline void gen_stf_asi(TCGv addr, int insn, int size, int rd) r_asi = gen_get_asi(insn, addr); r_size = tcg_const_i32(size); r_rd = tcg_const_i32(rd); - gen_helper_stf_asi(addr, r_asi, r_size, r_rd); + gen_helper_stf_asi(cpu_env, addr, r_asi, r_size, r_rd); tcg_temp_free_i32(r_rd); tcg_temp_free_i32(r_size); tcg_temp_free_i32(r_asi); @@ -2005,9 +2005,9 @@ static inline void gen_swap_asi(TCGv dst, TCGv addr, int insn) r_asi = gen_get_asi(insn, addr); r_size = tcg_const_i32(4); r_sign = tcg_const_i32(0); - gen_helper_ld_asi(cpu_tmp64, addr, r_asi, r_size, r_sign); + gen_helper_ld_asi(cpu_tmp64, cpu_env, addr, r_asi, r_size, r_sign); tcg_temp_free_i32(r_sign); - gen_helper_st_asi(addr, dst, r_asi, r_size); + gen_helper_st_asi(cpu_env, addr, dst, r_asi, r_size); tcg_temp_free_i32(r_size); tcg_temp_free_i32(r_asi); tcg_gen_trunc_i64_tl(dst, cpu_tmp64); @@ -2019,7 +2019,7 @@ static inline void gen_ldda_asi(TCGv hi, TCGv addr, int insn, int rd) r_asi = gen_get_asi(insn, addr); r_rd = tcg_const_i32(rd); - gen_helper_ldda_asi(addr, r_asi, r_rd); + gen_helper_ldda_asi(cpu_env, addr, r_asi, r_rd); tcg_temp_free_i32(r_rd); tcg_temp_free_i32(r_asi); } @@ -2032,7 +2032,7 @@ static inline void gen_stda_asi(TCGv hi, TCGv addr, int insn, int rd) tcg_gen_concat_tl_i64(cpu_tmp64, cpu_tmp0, hi); r_asi = gen_get_asi(insn, addr); r_size = tcg_const_i32(8); - gen_helper_st_asi(addr, cpu_tmp64, r_asi, r_size); + gen_helper_st_asi(cpu_env, addr, cpu_tmp64, r_asi, r_size); tcg_temp_free_i32(r_size); tcg_temp_free_i32(r_asi); } @@ -2046,7 +2046,7 @@ static inline void gen_cas_asi(TCGv dst, TCGv addr, TCGv val2, int insn, r_val1 = tcg_temp_new(); gen_movl_reg_TN(rd, r_val1); r_asi = gen_get_asi(insn, addr); - gen_helper_cas_asi(dst, addr, r_val1, val2, r_asi); + gen_helper_cas_asi(dst, cpu_env, addr, r_val1, val2, r_asi); tcg_temp_free_i32(r_asi); tcg_temp_free(r_val1); } @@ -2058,7 +2058,7 @@ static inline void gen_casx_asi(TCGv dst, TCGv addr, TCGv val2, int insn, gen_movl_reg_TN(rd, cpu_tmp64); r_asi = gen_get_asi(insn, addr); - gen_helper_casx_asi(dst, addr, cpu_tmp64, val2, r_asi); + gen_helper_casx_asi(dst, cpu_env, addr, cpu_tmp64, val2, r_asi); tcg_temp_free_i32(r_asi); } @@ -2072,7 +2072,7 @@ static inline void gen_ld_asi(TCGv dst, TCGv addr, int insn, int size, r_asi = tcg_const_i32(GET_FIELD(insn, 19, 26)); r_size = tcg_const_i32(size); r_sign = tcg_const_i32(sign); - gen_helper_ld_asi(cpu_tmp64, addr, r_asi, r_size, r_sign); + gen_helper_ld_asi(cpu_tmp64, cpu_env, addr, r_asi, r_size, r_sign); tcg_temp_free(r_sign); tcg_temp_free(r_size); tcg_temp_free(r_asi); @@ -2086,7 +2086,7 @@ static inline void gen_st_asi(TCGv src, TCGv addr, int insn, int size) tcg_gen_extu_tl_i64(cpu_tmp64, src); r_asi = tcg_const_i32(GET_FIELD(insn, 19, 26)); r_size = tcg_const_i32(size); - gen_helper_st_asi(addr, cpu_tmp64, r_asi, r_size); + gen_helper_st_asi(cpu_env, addr, cpu_tmp64, r_asi, r_size); tcg_temp_free(r_size); tcg_temp_free(r_asi); } @@ -2099,11 +2099,11 @@ static inline void gen_swap_asi(TCGv dst, TCGv addr, int insn) r_asi = tcg_const_i32(GET_FIELD(insn, 19, 26)); r_size = tcg_const_i32(4); r_sign = tcg_const_i32(0); - gen_helper_ld_asi(cpu_tmp64, addr, r_asi, r_size, r_sign); + gen_helper_ld_asi(cpu_tmp64, cpu_env, addr, r_asi, r_size, r_sign); tcg_temp_free(r_sign); r_val = tcg_temp_new_i64(); tcg_gen_extu_tl_i64(r_val, dst); - gen_helper_st_asi(addr, r_val, r_asi, r_size); + gen_helper_st_asi(cpu_env, addr, r_val, r_asi, r_size); tcg_temp_free_i64(r_val); tcg_temp_free(r_size); tcg_temp_free(r_asi); @@ -2117,7 +2117,7 @@ static inline void gen_ldda_asi(TCGv hi, TCGv addr, int insn, int rd) r_asi = tcg_const_i32(GET_FIELD(insn, 19, 26)); r_size = tcg_const_i32(8); r_sign = tcg_const_i32(0); - gen_helper_ld_asi(cpu_tmp64, addr, r_asi, r_size, r_sign); + gen_helper_ld_asi(cpu_tmp64, cpu_env, addr, r_asi, r_size, r_sign); tcg_temp_free(r_sign); tcg_temp_free(r_size); tcg_temp_free(r_asi); @@ -2136,7 +2136,7 @@ static inline void gen_stda_asi(TCGv hi, TCGv addr, int insn, int rd) tcg_gen_concat_tl_i64(cpu_tmp64, cpu_tmp0, hi); r_asi = tcg_const_i32(GET_FIELD(insn, 19, 26)); r_size = tcg_const_i32(8); - gen_helper_st_asi(addr, cpu_tmp64, r_asi, r_size); + gen_helper_st_asi(cpu_env, addr, cpu_tmp64, r_asi, r_size); tcg_temp_free(r_size); tcg_temp_free(r_asi); } @@ -2153,7 +2153,7 @@ static inline void gen_ldstub_asi(TCGv dst, TCGv addr, int insn) r_val = tcg_const_i64(0xffULL); r_asi = tcg_const_i32(GET_FIELD(insn, 19, 26)); r_size = tcg_const_i32(1); - gen_helper_st_asi(addr, r_val, r_asi, r_size); + gen_helper_st_asi(cpu_env, addr, r_val, r_asi, r_size); tcg_temp_free_i32(r_size); tcg_temp_free_i32(r_asi); tcg_temp_free_i64(r_val); @@ -4547,7 +4547,7 @@ static void disas_sparc_insn(DisasContext * dc) gen_helper_restore(cpu_env); gen_mov_pc_npc(dc, cpu_cond); r_const = tcg_const_i32(3); - gen_helper_check_align(cpu_dst, r_const); + gen_helper_check_align(cpu_env, cpu_dst, r_const); tcg_temp_free_i32(r_const); tcg_gen_mov_tl(cpu_npc, cpu_dst); dc->npc = DYNAMIC_PC; @@ -4577,7 +4577,7 @@ static void disas_sparc_insn(DisasContext * dc) tcg_temp_free(r_pc); gen_mov_pc_npc(dc, cpu_cond); r_const = tcg_const_i32(3); - gen_helper_check_align(cpu_dst, r_const); + gen_helper_check_align(cpu_env, cpu_dst, r_const); tcg_temp_free_i32(r_const); tcg_gen_mov_tl(cpu_npc, cpu_dst); dc->npc = DYNAMIC_PC; @@ -4592,7 +4592,7 @@ static void disas_sparc_insn(DisasContext * dc) goto priv_insn; gen_mov_pc_npc(dc, cpu_cond); r_const = tcg_const_i32(3); - gen_helper_check_align(cpu_dst, r_const); + gen_helper_check_align(cpu_env, cpu_dst, r_const); tcg_temp_free_i32(r_const); tcg_gen_mov_tl(cpu_npc, cpu_dst); dc->npc = DYNAMIC_PC; @@ -4696,7 +4696,8 @@ static void disas_sparc_insn(DisasContext * dc) save_state(dc, cpu_cond); r_const = tcg_const_i32(7); - gen_helper_check_align(cpu_addr, r_const); // XXX remove + /* XXX remove alignment check */ + gen_helper_check_align(cpu_env, cpu_addr, r_const); tcg_temp_free_i32(r_const); gen_address_mask(dc, cpu_addr); tcg_gen_qemu_ld64(cpu_tmp64, cpu_addr, dc->mem_idx); @@ -4921,7 +4922,7 @@ static void disas_sparc_insn(DisasContext * dc) CHECK_FPU_FEATURE(dc, FLOAT128); r_const = tcg_const_i32(dc->mem_idx); gen_address_mask(dc, cpu_addr); - gen_helper_ldqf(cpu_addr, r_const); + gen_helper_ldqf(cpu_env, cpu_addr, r_const); tcg_temp_free_i32(r_const); gen_op_store_QT0_fpr(QFPREG(rd)); gen_update_fprs_dirty(QFPREG(rd)); @@ -4961,7 +4962,8 @@ static void disas_sparc_insn(DisasContext * dc) save_state(dc, cpu_cond); gen_address_mask(dc, cpu_addr); r_const = tcg_const_i32(7); - gen_helper_check_align(cpu_addr, r_const); // XXX remove + /* XXX remove alignment check */ + gen_helper_check_align(cpu_env, cpu_addr, r_const); tcg_temp_free_i32(r_const); gen_movl_reg_TN(rd + 1, cpu_tmp0); tcg_gen_concat_tl_i64(cpu_tmp64, cpu_tmp0, cpu_val); @@ -5065,7 +5067,7 @@ static void disas_sparc_insn(DisasContext * dc) gen_op_load_fpr_QT0(QFPREG(rd)); r_const = tcg_const_i32(dc->mem_idx); gen_address_mask(dc, cpu_addr); - gen_helper_stqf(cpu_addr, r_const); + gen_helper_stqf(cpu_env, cpu_addr, r_const); tcg_temp_free_i32(r_const); } break; @@ -5108,7 +5110,7 @@ static void disas_sparc_insn(DisasContext * dc) goto jmp_insn; } r_const = tcg_const_i32(7); - gen_helper_check_align(cpu_addr, r_const); + gen_helper_check_align(cpu_env, cpu_addr, r_const); tcg_temp_free_i32(r_const); gen_stf_asi(cpu_addr, insn, 16, QFPREG(rd)); } From 0184e266cb7584feefaf4b54abbaa9fa81b62fac Mon Sep 17 00:00:00 2001 From: Blue Swirl Date: Mon, 1 Aug 2011 12:19:05 +0000 Subject: [PATCH 40/42] Sparc: avoid AREG0 wrappers for memory access helpers Adjust generation of load and store templates so that the functions take a parameter for CPUState instead of relying on global env. Remove wrappers. Move remaining memory helpers to ldst_helper.c. Signed-off-by: Blue Swirl --- Makefile.target | 12 ++- configure | 7 ++ target-sparc/cpu.h | 85 +----------------- target-sparc/ldst_helper.c | 73 +++++++++++++++- target-sparc/op_helper.c | 174 ------------------------------------- target-sparc/translate.c | 10 ++- 6 files changed, 93 insertions(+), 268 deletions(-) delete mode 100644 target-sparc/op_helper.c diff --git a/Makefile.target b/Makefile.target index d2ba029a94..37fb7edd6d 100644 --- a/Makefile.target +++ b/Makefile.target @@ -80,7 +80,10 @@ libobj-y = exec.o translate-all.o cpu-exec.o translate.o libobj-y += tcg/tcg.o tcg/optimize.o libobj-$(CONFIG_TCG_INTERPRETER) += tci.o libobj-y += fpu/softfloat.o -libobj-y += op_helper.o helper.o +ifneq ($(TARGET_BASE_ARCH), sparc) +libobj-y += op_helper.o +endif +libobj-y += helper.o ifeq ($(TARGET_BASE_ARCH), i386) libobj-y += cpuid.o endif @@ -101,9 +104,12 @@ tci-dis.o: QEMU_CFLAGS += -I$(SRC_PATH)/tcg -I$(SRC_PATH)/tcg/tci $(libobj-y): $(GENERATED_HEADERS) -# HELPER_CFLAGS is used for all the code compiled with static register +# HELPER_CFLAGS is used for all the legacy code compiled with static register # variables -op_helper.o user-exec.o: QEMU_CFLAGS += $(HELPER_CFLAGS) +ifneq ($(TARGET_BASE_ARCH), sparc) +op_helper.o: QEMU_CFLAGS += $(HELPER_CFLAGS) +endif +user-exec.o: QEMU_CFLAGS += $(HELPER_CFLAGS) # Note: this is a workaround. The real fix is to avoid compiling # cpu_signal_handler() in user-exec.c. diff --git a/configure b/configure index afe7395577..8b4e3c1a02 100755 --- a/configure +++ b/configure @@ -3606,6 +3606,13 @@ case "$target_arch2" in exit 1 ;; esac + +case "$target_arch2" in + sparc*) + echo "CONFIG_TCG_PASS_AREG0=y" >> $config_target_mak + ;; +esac + echo "TARGET_SHORT_ALIGNMENT=$target_short_alignment" >> $config_target_mak echo "TARGET_INT_ALIGNMENT=$target_int_alignment" >> $config_target_mak echo "TARGET_LONG_ALIGNMENT=$target_long_alignment" >> $config_target_mak diff --git a/target-sparc/cpu.h b/target-sparc/cpu.h index ee28daa507..1025752e8f 100644 --- a/target-sparc/cpu.h +++ b/target-sparc/cpu.h @@ -587,89 +587,6 @@ void cpu_unassigned_access(CPUSPARCState *env1, target_phys_addr_t addr, target_phys_addr_t cpu_get_phys_page_nofault(CPUSPARCState *env, target_ulong addr, int mmu_idx); #endif - -#define WRAP_LD(rettype, fn) \ - rettype cpu_ ## fn (CPUSPARCState *env1, target_ulong addr) - -WRAP_LD(uint32_t, ldub_kernel); -WRAP_LD(uint32_t, lduw_kernel); -WRAP_LD(uint32_t, ldl_kernel); -WRAP_LD(uint64_t, ldq_kernel); - -WRAP_LD(uint32_t, ldub_user); -WRAP_LD(uint32_t, lduw_user); -WRAP_LD(uint32_t, ldl_user); -WRAP_LD(uint64_t, ldq_user); - -WRAP_LD(uint64_t, ldfq_kernel); -WRAP_LD(uint64_t, ldfq_user); - -#ifdef TARGET_SPARC64 -WRAP_LD(uint32_t, ldub_hypv); -WRAP_LD(uint32_t, lduw_hypv); -WRAP_LD(uint32_t, ldl_hypv); -WRAP_LD(uint64_t, ldq_hypv); - -WRAP_LD(uint64_t, ldfq_hypv); - -WRAP_LD(uint32_t, ldub_nucleus); -WRAP_LD(uint32_t, lduw_nucleus); -WRAP_LD(uint32_t, ldl_nucleus); -WRAP_LD(uint64_t, ldq_nucleus); - -WRAP_LD(uint32_t, ldub_kernel_secondary); -WRAP_LD(uint32_t, lduw_kernel_secondary); -WRAP_LD(uint32_t, ldl_kernel_secondary); -WRAP_LD(uint64_t, ldq_kernel_secondary); - -WRAP_LD(uint32_t, ldub_user_secondary); -WRAP_LD(uint32_t, lduw_user_secondary); -WRAP_LD(uint32_t, ldl_user_secondary); -WRAP_LD(uint64_t, ldq_user_secondary); -#endif -#undef WRAP_LD - -#define WRAP_ST(datatype, fn) \ - void cpu_ ## fn (CPUSPARCState *env1, target_ulong addr, datatype val) - -WRAP_ST(uint32_t, stb_kernel); -WRAP_ST(uint32_t, stw_kernel); -WRAP_ST(uint32_t, stl_kernel); -WRAP_ST(uint64_t, stq_kernel); - -WRAP_ST(uint32_t, stb_user); -WRAP_ST(uint32_t, stw_user); -WRAP_ST(uint32_t, stl_user); -WRAP_ST(uint64_t, stq_user); - -WRAP_ST(uint64_t, stfq_kernel); -WRAP_ST(uint64_t, stfq_user); - -#ifdef TARGET_SPARC64 -WRAP_ST(uint32_t, stb_hypv); -WRAP_ST(uint32_t, stw_hypv); -WRAP_ST(uint32_t, stl_hypv); -WRAP_ST(uint64_t, stq_hypv); - -WRAP_ST(uint64_t, stfq_hypv); - -WRAP_ST(uint32_t, stb_nucleus); -WRAP_ST(uint32_t, stw_nucleus); -WRAP_ST(uint32_t, stl_nucleus); -WRAP_ST(uint64_t, stq_nucleus); - -WRAP_ST(uint32_t, stb_kernel_secondary); -WRAP_ST(uint32_t, stw_kernel_secondary); -WRAP_ST(uint32_t, stl_kernel_secondary); -WRAP_ST(uint64_t, stq_kernel_secondary); - -WRAP_ST(uint32_t, stb_user_secondary); -WRAP_ST(uint32_t, stw_user_secondary); -WRAP_ST(uint32_t, stl_user_secondary); -WRAP_ST(uint64_t, stq_user_secondary); -#endif - -#undef WRAP_ST #endif int cpu_sparc_signal_handler(int host_signum, void *pinfo, void *puc); @@ -782,6 +699,8 @@ uint64_t cpu_tick_get_count(CPUTimer *timer); void cpu_tick_set_limit(CPUTimer *timer, uint64_t limit); trap_state* cpu_tsptr(CPUSPARCState* env); #endif +void do_unaligned_access(CPUSPARCState *env, target_ulong addr, int is_write, + int is_user, void *retaddr); #define TB_FLAG_FPU_ENABLED (1 << 4) #define TB_FLAG_AM_ENABLED (1 << 5) diff --git a/target-sparc/ldst_helper.c b/target-sparc/ldst_helper.c index 8468cde07e..1418205f99 100644 --- a/target-sparc/ldst_helper.c +++ b/target-sparc/ldst_helper.c @@ -64,6 +64,24 @@ #define QT0 (env->qt0) #define QT1 (env->qt1) +#if !defined(CONFIG_USER_ONLY) +#include "softmmu_exec.h" +#define MMUSUFFIX _mmu +#define ALIGNED_ONLY + +#define SHIFT 0 +#include "softmmu_template.h" + +#define SHIFT 1 +#include "softmmu_template.h" + +#define SHIFT 2 +#include "softmmu_template.h" + +#define SHIFT 3 +#include "softmmu_template.h" +#endif + #if defined(TARGET_SPARC64) && !defined(CONFIG_USER_ONLY) /* Calculates TSB pointer value for fault page size 8k or 64k */ static uint64_t ultrasparc_tsb_pointer(uint64_t tsb_register, @@ -523,17 +541,17 @@ uint64_t helper_ld_asi(CPUSPARCState *env, target_ulong addr, int asi, int size, case 9: /* Supervisor code access */ switch (size) { case 1: - ret = ldub_code(addr); + ret = cpu_ldub_code(env, addr); break; case 2: - ret = lduw_code(addr); + ret = cpu_lduw_code(env, addr); break; default: case 4: - ret = ldl_code(addr); + ret = cpu_ldl_code(env, addr); break; case 8: - ret = ldq_code(addr); + ret = cpu_ldq_code(env, addr); break; } break; @@ -2355,3 +2373,50 @@ void cpu_unassigned_access(CPUSPARCState *env, target_phys_addr_t addr, } #endif #endif + +#if !defined(CONFIG_USER_ONLY) +/* XXX: make it generic ? */ +static void cpu_restore_state2(CPUSPARCState *env, void *retaddr) +{ + TranslationBlock *tb; + unsigned long pc; + + if (retaddr) { + /* now we have a real cpu fault */ + pc = (unsigned long)retaddr; + tb = tb_find_pc(pc); + if (tb) { + /* the PC is inside the translated code. It means that we have + a virtual CPU fault */ + cpu_restore_state(tb, env, pc); + } + } +} + +void do_unaligned_access(CPUSPARCState *env, target_ulong addr, int is_write, + int is_user, void *retaddr) +{ +#ifdef DEBUG_UNALIGNED + printf("Unaligned access to 0x" TARGET_FMT_lx " from 0x" TARGET_FMT_lx + "\n", addr, env->pc); +#endif + cpu_restore_state2(env, retaddr); + helper_raise_exception(env, TT_UNALIGNED); +} + +/* try to fill the TLB and return an exception if error. If retaddr is + NULL, it means that the function was called in C code (i.e. not + from generated code or from helper.c) */ +/* XXX: fix it to restore all registers */ +void tlb_fill(CPUSPARCState *env, target_ulong addr, int is_write, int mmu_idx, + void *retaddr) +{ + int ret; + + ret = cpu_sparc_handle_mmu_fault(env, addr, is_write, mmu_idx); + if (ret) { + cpu_restore_state2(env, retaddr); + cpu_loop_exit(env); + } +} +#endif diff --git a/target-sparc/op_helper.c b/target-sparc/op_helper.c deleted file mode 100644 index b7171d8b94..0000000000 --- a/target-sparc/op_helper.c +++ /dev/null @@ -1,174 +0,0 @@ -#include "cpu.h" -#include "dyngen-exec.h" -#include "helper.h" - -#if !defined(CONFIG_USER_ONLY) -#include "softmmu_exec.h" -static void do_unaligned_access(target_ulong addr, int is_write, int is_user, - void *retaddr); - -#define MMUSUFFIX _mmu -#define ALIGNED_ONLY - -#define SHIFT 0 -#include "softmmu_template.h" - -#define SHIFT 1 -#include "softmmu_template.h" - -#define SHIFT 2 -#include "softmmu_template.h" - -#define SHIFT 3 -#include "softmmu_template.h" - -/* XXX: make it generic ? */ -static void cpu_restore_state2(void *retaddr) -{ - TranslationBlock *tb; - unsigned long pc; - - if (retaddr) { - /* now we have a real cpu fault */ - pc = (unsigned long)retaddr; - tb = tb_find_pc(pc); - if (tb) { - /* the PC is inside the translated code. It means that we have - a virtual CPU fault */ - cpu_restore_state(tb, env, pc); - } - } -} - -static void do_unaligned_access(target_ulong addr, int is_write, int is_user, - void *retaddr) -{ -#ifdef DEBUG_UNALIGNED - printf("Unaligned access to 0x" TARGET_FMT_lx " from 0x" TARGET_FMT_lx - "\n", addr, env->pc); -#endif - cpu_restore_state2(retaddr); - helper_raise_exception(env, TT_UNALIGNED); -} - -/* try to fill the TLB and return an exception if error. If retaddr is - NULL, it means that the function was called in C code (i.e. not - from generated code or from helper.c) */ -/* XXX: fix it to restore all registers */ -void tlb_fill(CPUSPARCState *env1, target_ulong addr, int is_write, int mmu_idx, - void *retaddr) -{ - int ret; - CPUSPARCState *saved_env; - - saved_env = env; - env = env1; - - ret = cpu_sparc_handle_mmu_fault(env, addr, is_write, mmu_idx); - if (ret) { - cpu_restore_state2(retaddr); - cpu_loop_exit(env); - } - env = saved_env; -} - -#define WRAP_LD(rettype, fn) \ - rettype cpu_ ## fn (CPUSPARCState *env1, target_ulong addr) \ - { \ - CPUSPARCState *saved_env; \ - rettype ret; \ - \ - saved_env = env; \ - env = env1; \ - ret = fn(addr); \ - env = saved_env; \ - return ret; \ - } - -WRAP_LD(uint32_t, ldub_kernel) -WRAP_LD(uint32_t, lduw_kernel) -WRAP_LD(uint32_t, ldl_kernel) -WRAP_LD(uint64_t, ldq_kernel) - -WRAP_LD(uint32_t, ldub_user) -WRAP_LD(uint32_t, lduw_user) -WRAP_LD(uint32_t, ldl_user) -WRAP_LD(uint64_t, ldq_user) - -WRAP_LD(uint64_t, ldfq_kernel) -WRAP_LD(uint64_t, ldfq_user) -#ifdef TARGET_SPARC64 -WRAP_LD(uint32_t, ldub_hypv) -WRAP_LD(uint32_t, lduw_hypv) -WRAP_LD(uint32_t, ldl_hypv) -WRAP_LD(uint64_t, ldq_hypv) - -WRAP_LD(uint64_t, ldfq_hypv) - -WRAP_LD(uint32_t, ldub_nucleus) -WRAP_LD(uint32_t, lduw_nucleus) -WRAP_LD(uint32_t, ldl_nucleus) -WRAP_LD(uint64_t, ldq_nucleus) - -WRAP_LD(uint32_t, ldub_kernel_secondary) -WRAP_LD(uint32_t, lduw_kernel_secondary) -WRAP_LD(uint32_t, ldl_kernel_secondary) -WRAP_LD(uint64_t, ldq_kernel_secondary) - -WRAP_LD(uint32_t, ldub_user_secondary) -WRAP_LD(uint32_t, lduw_user_secondary) -WRAP_LD(uint32_t, ldl_user_secondary) -WRAP_LD(uint64_t, ldq_user_secondary) -#endif -#undef WRAP_LD - -#define WRAP_ST(datatype, fn) \ - void cpu_ ## fn (CPUSPARCState *env1, target_ulong addr, datatype val) \ - { \ - CPUSPARCState *saved_env; \ - \ - saved_env = env; \ - env = env1; \ - fn(addr, val); \ - env = saved_env; \ - } - -WRAP_ST(uint32_t, stb_kernel) -WRAP_ST(uint32_t, stw_kernel) -WRAP_ST(uint32_t, stl_kernel) -WRAP_ST(uint64_t, stq_kernel) - -WRAP_ST(uint32_t, stb_user) -WRAP_ST(uint32_t, stw_user) -WRAP_ST(uint32_t, stl_user) -WRAP_ST(uint64_t, stq_user) - -WRAP_ST(uint64_t, stfq_kernel) -WRAP_ST(uint64_t, stfq_user) - -#ifdef TARGET_SPARC64 -WRAP_ST(uint32_t, stb_hypv) -WRAP_ST(uint32_t, stw_hypv) -WRAP_ST(uint32_t, stl_hypv) -WRAP_ST(uint64_t, stq_hypv) - -WRAP_ST(uint64_t, stfq_hypv) - -WRAP_ST(uint32_t, stb_nucleus) -WRAP_ST(uint32_t, stw_nucleus) -WRAP_ST(uint32_t, stl_nucleus) -WRAP_ST(uint64_t, stq_nucleus) - -WRAP_ST(uint32_t, stb_kernel_secondary) -WRAP_ST(uint32_t, stw_kernel_secondary) -WRAP_ST(uint32_t, stl_kernel_secondary) -WRAP_ST(uint64_t, stq_kernel_secondary) - -WRAP_ST(uint32_t, stb_user_secondary) -WRAP_ST(uint32_t, stw_user_secondary) -WRAP_ST(uint32_t, stl_user_secondary) -WRAP_ST(uint64_t, stq_user_secondary) -#endif - -#undef WRAP_ST -#endif diff --git a/target-sparc/translate.c b/target-sparc/translate.c index 670ea2b01f..4967152e88 100644 --- a/target-sparc/translate.c +++ b/target-sparc/translate.c @@ -2373,9 +2373,9 @@ static void gen_faligndata(TCGv dst, TCGv gsr, TCGv s1, TCGv s2) goto nfpu_insn; /* before an instruction, dc->pc must be static */ -static void disas_sparc_insn(DisasContext * dc) +static void disas_sparc_insn(DisasContext * dc, unsigned int insn) { - unsigned int insn, opc, rs1, rs2, rd; + unsigned int opc, rs1, rs2, rd; TCGv cpu_src1, cpu_src2, cpu_tmp1, cpu_tmp2; TCGv_i32 cpu_src1_32, cpu_src2_32, cpu_dst_32; TCGv_i64 cpu_src1_64, cpu_src2_64, cpu_dst_64; @@ -2383,7 +2383,7 @@ static void disas_sparc_insn(DisasContext * dc) if (unlikely(qemu_loglevel_mask(CPU_LOG_TB_OP))) tcg_gen_debug_insn_start(dc->pc); - insn = ldl_code(dc->pc); + opc = GET_FIELD(insn, 0, 1); rd = GET_FIELD(insn, 2, 6); @@ -5240,6 +5240,7 @@ static inline void gen_intermediate_code_internal(TranslationBlock * tb, int j, lj = -1; int num_insns; int max_insns; + unsigned int insn; memset(dc, 0, sizeof(DisasContext)); dc->tb = tb; @@ -5299,7 +5300,8 @@ static inline void gen_intermediate_code_internal(TranslationBlock * tb, if (num_insns + 1 == max_insns && (tb->cflags & CF_LAST_IO)) gen_io_start(); last_pc = dc->pc; - disas_sparc_insn(dc); + insn = cpu_ldl_code(env, dc->pc); + disas_sparc_insn(dc, insn); num_insns++; if (dc->is_br) From 7859cc6e39bf86f890bb1c72fd9ba41deb6ce2e7 Mon Sep 17 00:00:00 2001 From: Avi Kivity Date: Wed, 14 Mar 2012 16:19:39 +0200 Subject: [PATCH 41/42] exec: fix write tlb entry misused as iotlb A couple of code paths check the lower bits of CPUTLBEntry::addr_write against io_mem_ram as a way of looking for a dirty RAM page. This works by accident since the value is zero, which matches all clear bits for TLB_INVALID, TLB_MMIO, and TLB_NOTDIRTY (indicating dirty RAM). Make it work by design by checking for the proper bits. Signed-off-by: Avi Kivity --- exec.c | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/exec.c b/exec.c index be392e2764..3c2b7e5180 100644 --- a/exec.c +++ b/exec.c @@ -2031,14 +2031,19 @@ static void tlb_unprotect_code_phys(CPUArchState *env, ram_addr_t ram_addr, cpu_physical_memory_set_dirty_flags(ram_addr, CODE_DIRTY_FLAG); } +static bool tlb_is_dirty_ram(CPUTLBEntry *tlbe) +{ + return (tlbe->addr_write & (TLB_INVALID_MASK|TLB_MMIO|TLB_NOTDIRTY)) == 0; +} + static inline void tlb_reset_dirty_range(CPUTLBEntry *tlb_entry, unsigned long start, unsigned long length) { unsigned long addr; - if ((tlb_entry->addr_write & ~TARGET_PAGE_MASK) == io_mem_ram.ram_addr) { + if (tlb_is_dirty_ram(tlb_entry)) { addr = (tlb_entry->addr_write & TARGET_PAGE_MASK) + tlb_entry->addend; if ((addr - start) < length) { - tlb_entry->addr_write = (tlb_entry->addr_write & TARGET_PAGE_MASK) | TLB_NOTDIRTY; + tlb_entry->addr_write |= TLB_NOTDIRTY; } } } @@ -2091,7 +2096,7 @@ static inline void tlb_update_dirty(CPUTLBEntry *tlb_entry) ram_addr_t ram_addr; void *p; - if ((tlb_entry->addr_write & ~TARGET_PAGE_MASK) == io_mem_ram.ram_addr) { + if (tlb_is_dirty_ram(tlb_entry)) { p = (void *)(unsigned long)((tlb_entry->addr_write & TARGET_PAGE_MASK) + tlb_entry->addend); ram_addr = qemu_ram_addr_from_host_nofail(p); From 32b089808f125470b3563bf4209c2301fa35c58e Mon Sep 17 00:00:00 2001 From: Avi Kivity Date: Sun, 18 Mar 2012 18:31:13 +0200 Subject: [PATCH 42/42] memory: check for watchpoints when getting code ram_addr The code to get the ram_addr from a (tlb entry, vaddr) pair checks that the resulting memory is not MMIO, but neglects to check whether the region is hidden by a watchpoint page. Add the missing check. Signed-off-by: Avi Kivity --- exec.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/exec.c b/exec.c index 3c2b7e5180..a3818ffeb7 100644 --- a/exec.c +++ b/exec.c @@ -4609,7 +4609,8 @@ tb_page_addr_t get_page_addr_code(CPUArchState *env1, target_ulong addr) pd = env1->iotlb[mmu_idx][page_index] & ~TARGET_PAGE_MASK; mr = iotlb_to_region(pd); if (mr != &io_mem_ram && mr != &io_mem_rom - && mr != &io_mem_notdirty && !mr->rom_device) { + && mr != &io_mem_notdirty && !mr->rom_device + && mr != &io_mem_watch) { #if defined(TARGET_ALPHA) || defined(TARGET_MIPS) || defined(TARGET_SPARC) cpu_unassigned_access(env1, addr, 0, 1, 0, 4); #else