From dfdcf34031db02eb8d81dd3b1c3415ec900c40bb Mon Sep 17 00:00:00 2001 From: Michael Weiser Date: Thu, 11 Jan 2018 13:25:31 +0000 Subject: [PATCH 01/26] linux-user: Add support for big-endian aarch64 Enable big-endian mode for data accesses on aarch64 for big-endian linux user mode. Activate it for all exception levels as documented by ARM: Set the SCTLR EE bit for ELs 1 through 3. Additionally set bit E0E in EL1 to enable it in EL0 as well. Signed-off-by: Michael Weiser Reviewed-by: Richard Henderson Message-id: 20171220212308.12614-2-michael.weiser@gmx.de Signed-off-by: Peter Maydell --- linux-user/main.c | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/linux-user/main.c b/linux-user/main.c index 99a551b04f..450eb3ce65 100644 --- a/linux-user/main.c +++ b/linux-user/main.c @@ -4629,6 +4629,12 @@ int main(int argc, char **argv, char **envp) } env->pc = regs->pc; env->xregs[31] = regs->sp; +#ifdef TARGET_WORDS_BIGENDIAN + env->cp15.sctlr_el[1] |= SCTLR_E0E; + for (i = 1; i < 4; ++i) { + env->cp15.sctlr_el[i] |= SCTLR_EE; + } +#endif } #elif defined(TARGET_ARM) { From cb3aa5fea19cdc108baf6c3aff2e768bf9475b50 Mon Sep 17 00:00:00 2001 From: Michael Weiser Date: Thu, 11 Jan 2018 13:25:31 +0000 Subject: [PATCH 02/26] linux-user: Add separate aarch64_be uname Make big-endian aarch64 systems identify as aarch64_be as expected by big-endian userland and toolchains. Signed-off-by: Michael Weiser Reviewed-by: Richard Henderson Reviewed-by: Laurent Vivier Message-id: 20171220212308.12614-3-michael.weiser@gmx.de Signed-off-by: Peter Maydell --- linux-user/aarch64/target_syscall.h | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/linux-user/aarch64/target_syscall.h b/linux-user/aarch64/target_syscall.h index 1b62953eeb..604ab99b14 100644 --- a/linux-user/aarch64/target_syscall.h +++ b/linux-user/aarch64/target_syscall.h @@ -8,7 +8,11 @@ struct target_pt_regs { uint64_t pstate; }; +#if defined(TARGET_WORDS_BIGENDIAN) +#define UNAME_MACHINE "aarch64_be" +#else #define UNAME_MACHINE "aarch64" +#endif #define UNAME_MINIMUM_RELEASE "3.8.0" #define TARGET_CLONE_BACKWARDS #define TARGET_MINSIGSTKSZ 2048 From 50f22fa60d95c04a179e2cbf4b5f58d1f6068b61 Mon Sep 17 00:00:00 2001 From: Michael Weiser Date: Thu, 11 Jan 2018 13:25:31 +0000 Subject: [PATCH 03/26] linux-user: Fix endianess of aarch64 signal trampoline Since for aarch64 the signal trampoline is synthesized directly into the signal frame we need to make sure the instructions end up little-endian. Otherwise the wrong endianness will cause a SIGILL upon return from the signal handler on big-endian targets. Signed-off-by: Michael Weiser Reviewed-by: Richard Henderson Message-id: 20171220212308.12614-4-michael.weiser@gmx.de Signed-off-by: Peter Maydell --- linux-user/signal.c | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/linux-user/signal.c b/linux-user/signal.c index 74fa03f96d..f85f0dd780 100644 --- a/linux-user/signal.c +++ b/linux-user/signal.c @@ -1599,9 +1599,13 @@ static void target_setup_frame(int usig, struct target_sigaction *ka, if (ka->sa_flags & TARGET_SA_RESTORER) { return_addr = ka->sa_restorer; } else { - /* mov x8,#__NR_rt_sigreturn; svc #0 */ - __put_user(0xd2801168, &frame->tramp[0]); - __put_user(0xd4000001, &frame->tramp[1]); + /* + * mov x8,#__NR_rt_sigreturn; svc #0 + * Since these are instructions they need to be put as little-endian + * regardless of target default or current CPU endianness. + */ + __put_user_e(0xd2801168, &frame->tramp[0], le); + __put_user_e(0xd4000001, &frame->tramp[1], le); return_addr = frame_addr + offsetof(struct target_rt_sigframe, tramp); } env->xregs[0] = usig; From 722dd7be8c5a9bc73e0a19be1418046ed043ce0b Mon Sep 17 00:00:00 2001 From: Michael Weiser Date: Thu, 11 Jan 2018 13:25:32 +0000 Subject: [PATCH 04/26] configure: Add aarch64_be-linux-user target Add target aarch64_be-linux-user. This allows a qemu-aarch64_be binary to be built that will run big-endian aarch64 binaries. Signed-off-by: Michael Weiser Reviewed-by: Richard Henderson Reviewed-by: Laurent Vivier Message-id: 20171220212308.12614-5-michael.weiser@gmx.de Signed-off-by: Peter Maydell --- configure | 5 +++-- default-configs/aarch64_be-linux-user.mak | 1 + 2 files changed, 4 insertions(+), 2 deletions(-) create mode 100644 default-configs/aarch64_be-linux-user.mak diff --git a/configure b/configure index 6a040821c6..89bd662a6a 100755 --- a/configure +++ b/configure @@ -6439,7 +6439,7 @@ target_name=$(echo $target | cut -d '-' -f 1) target_bigendian="no" case "$target_name" in - armeb|hppa|lm32|m68k|microblaze|mips|mipsn32|mips64|moxie|or1k|ppc|ppcemb|ppc64|ppc64abi32|s390x|sh4eb|sparc|sparc64|sparc32plus|xtensaeb) + armeb|aarch64_be|hppa|lm32|m68k|microblaze|mips|mipsn32|mips64|moxie|or1k|ppc|ppcemb|ppc64|ppc64abi32|s390x|sh4eb|sparc|sparc64|sparc32plus|xtensaeb) target_bigendian=yes ;; esac @@ -6494,7 +6494,8 @@ case "$target_name" in mttcg="yes" gdb_xml_files="arm-core.xml arm-vfp.xml arm-vfp3.xml arm-neon.xml" ;; - aarch64) + aarch64|aarch64_be) + TARGET_ARCH=aarch64 TARGET_BASE_ARCH=arm bflt="yes" mttcg="yes" diff --git a/default-configs/aarch64_be-linux-user.mak b/default-configs/aarch64_be-linux-user.mak new file mode 100644 index 0000000000..a69d9d2e41 --- /dev/null +++ b/default-configs/aarch64_be-linux-user.mak @@ -0,0 +1 @@ +# Default configuration for aarch64_be-linux-user From f772f212b39a79b4510b0e9b403714cc03dae9b9 Mon Sep 17 00:00:00 2001 From: Michael Weiser Date: Thu, 11 Jan 2018 13:25:32 +0000 Subject: [PATCH 05/26] linux-user: Add aarch64_be magic numbers to qemu-binfmt-conf.sh As we now have a linux-user aarch64_be target, we can add it to the list of supported targets in qemu-binfmt-conf.sh Signed-off-by: Michael Weiser Reviewed-by: Laurent Vivier Message-id: 20171220212308.12614-6-michael.weiser@gmx.de Signed-off-by: Peter Maydell --- scripts/qemu-binfmt-conf.sh | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/scripts/qemu-binfmt-conf.sh b/scripts/qemu-binfmt-conf.sh index 8afc3eb5bb..d69953525c 100755 --- a/scripts/qemu-binfmt-conf.sh +++ b/scripts/qemu-binfmt-conf.sh @@ -4,7 +4,7 @@ qemu_target_list="i386 i486 alpha arm sparc32plus ppc ppc64 ppc64le m68k \ mips mipsel mipsn32 mipsn32el mips64 mips64el \ -sh4 sh4eb s390x aarch64 hppa" +sh4 sh4eb s390x aarch64 aarch64_be hppa" i386_magic='\x7fELF\x01\x01\x01\x00\x00\x00\x00\x00\x00\x00\x00\x00\x02\x00\x03\x00' i386_mask='\xff\xff\xff\xff\xff\xfe\xfe\xff\xff\xff\xff\xff\xff\xff\xff\xff\xfe\xff\xff\xff' @@ -92,6 +92,10 @@ aarch64_magic='\x7fELF\x02\x01\x01\x00\x00\x00\x00\x00\x00\x00\x00\x00\x02\x00\x aarch64_mask='\xff\xff\xff\xff\xff\xff\xff\x00\xff\xff\xff\xff\xff\xff\xff\xff\xfe\xff\xff\xff' aarch64_family=arm +aarch64_be_magic='\x7fELF\x02\x02\x01\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x02\x00\xb7' +aarch64_be_mask='\xff\xff\xff\xff\xff\xff\xff\x00\xff\xff\xff\xff\xff\xff\xff\xff\xff\xfe\xff\xff' +aarch64_be_family=arm + hppa_magic='\x7f\x45\x4c\x46\x01\x02\x01\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x02\x00\x0f' hppa_mask='\xff\xff\xff\xff\xff\xff\xff\x00\xff\xff\xff\xff\xff\xff\xff\xff\xff\xfe\xff\xff' hppa_family=hppa From 2ced93eee04ac636387233c64720d0f764d8d24d Mon Sep 17 00:00:00 2001 From: Michael Weiser Date: Thu, 11 Jan 2018 13:25:33 +0000 Subject: [PATCH 06/26] linux-user: Separate binfmt arm CPU families Give big-endian arm and aarch64 CPUs their own family in qemu-binfmt-conf.sh to make sure we register qemu-user for binaries of the opposite endianness on arm and aarch64. Apart from the family assignments of the magic values, qemu_get_family() needs to be able to distinguish the two and recognise aarch64{,_be} as well. Signed-off-by: Michael Weiser Reviewed-by: Laurent Vivier Message-id: 20171220212308.12614-7-michael.weiser@gmx.de Signed-off-by: Peter Maydell --- scripts/qemu-binfmt-conf.sh | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/scripts/qemu-binfmt-conf.sh b/scripts/qemu-binfmt-conf.sh index d69953525c..597efdbe50 100755 --- a/scripts/qemu-binfmt-conf.sh +++ b/scripts/qemu-binfmt-conf.sh @@ -24,7 +24,7 @@ arm_family=arm armeb_magic='\x7fELF\x01\x02\x01\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x02\x00\x28' armeb_mask='\xff\xff\xff\xff\xff\xff\xff\x00\xff\xff\xff\xff\xff\xff\xff\xff\xff\xfe\xff\xff' -armeb_family=arm +armeb_family=armeb sparc_magic='\x7fELF\x01\x02\x01\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x02\x00\x02' sparc_mask='\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xfe\xff\xff' @@ -94,7 +94,7 @@ aarch64_family=arm aarch64_be_magic='\x7fELF\x02\x02\x01\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x02\x00\xb7' aarch64_be_mask='\xff\xff\xff\xff\xff\xff\xff\x00\xff\xff\xff\xff\xff\xff\xff\xff\xff\xfe\xff\xff' -aarch64_be_family=arm +aarch64_be_family=armeb hppa_magic='\x7f\x45\x4c\x46\x01\x02\x01\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x02\x00\x0f' hppa_mask='\xff\xff\xff\xff\xff\xff\xff\x00\xff\xff\xff\xff\xff\xff\xff\xff\xff\xfe\xff\xff' @@ -115,9 +115,12 @@ qemu_get_family() { ppc64el|ppc64le) echo "ppcle" ;; - arm|armel|armhf|arm64|armv[4-9]*) + arm|armel|armhf|arm64|armv[4-9]*l|aarch64) echo "arm" ;; + armeb|armv[4-9]*b|aarch64_be) + echo "armeb" + ;; sparc*) echo "sparc" ;; From bfe69cc867dfef4b8af348f1f7e36b2727283c4c Mon Sep 17 00:00:00 2001 From: Michael Weiser Date: Thu, 11 Jan 2018 13:25:33 +0000 Subject: [PATCH 07/26] linux-user: Activate armeb handler registration armeb is missing from the target list in qemu-binfmt-conf.sh. Add it so the handler for those binaries gets registered by the script. Signed-off-by: Michael Weiser Reviewed-by: Laurent Vivier Message-id: 20171220212308.12614-8-michael.weiser@gmx.de Signed-off-by: Peter Maydell --- scripts/qemu-binfmt-conf.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/scripts/qemu-binfmt-conf.sh b/scripts/qemu-binfmt-conf.sh index 597efdbe50..ea5a748745 100755 --- a/scripts/qemu-binfmt-conf.sh +++ b/scripts/qemu-binfmt-conf.sh @@ -2,7 +2,7 @@ # enable automatic i386/ARM/M68K/MIPS/SPARC/PPC/s390/HPPA # program execution by the kernel -qemu_target_list="i386 i486 alpha arm sparc32plus ppc ppc64 ppc64le m68k \ +qemu_target_list="i386 i486 alpha arm armeb sparc32plus ppc ppc64 ppc64le m68k \ mips mipsel mipsn32 mipsn32el mips64 mips64el \ sh4 sh4eb s390x aarch64 aarch64_be hppa" From 0785557f8811133bd69be02aeccf018d47a26373 Mon Sep 17 00:00:00 2001 From: Michael Weiser Date: Thu, 11 Jan 2018 13:25:33 +0000 Subject: [PATCH 08/26] target/arm: Fix stlxp for aarch64_be ldxp loads two consecutive doublewords from memory regardless of CPU endianness. On store, stlxp currently assumes to work with a 128bit value and consequently switches order in big-endian mode. With this change it packs the doublewords in reverse order in anticipation of the 128bit big-endian store operation interposing them so they end up in memory in the right order. This makes it work for both MTTCG and !MTTCG. It effectively implements the ARM ARM STLXP operation pseudo-code: data = if BigEndian() then el1:el2 else el2:el1; With this change an aarch64_be Linux 4.14.4 kernel succeeds to boot up in system emulation mode. Signed-off-by: Michael Weiser Reviewed-by: Richard Henderson Signed-off-by: Peter Maydell --- target/arm/helper-a64.c | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/target/arm/helper-a64.c b/target/arm/helper-a64.c index b84ebcae6e..3e00a9ead1 100644 --- a/target/arm/helper-a64.c +++ b/target/arm/helper-a64.c @@ -506,8 +506,11 @@ static uint64_t do_paired_cmpxchg64_be(CPUARMState *env, uint64_t addr, Int128 oldv, cmpv, newv; bool success; - cmpv = int128_make128(env->exclusive_val, env->exclusive_high); - newv = int128_make128(new_lo, new_hi); + /* high and low need to be switched here because this is not actually a + * 128bit store but two doublewords stored consecutively + */ + cmpv = int128_make128(env->exclusive_high, env->exclusive_val); + newv = int128_make128(new_hi, new_lo); if (parallel) { #ifndef CONFIG_ATOMIC128 From 4d027afeb3a9781bf15ad30d43d07a02c2b08c73 Mon Sep 17 00:00:00 2001 From: Zhaoshenglong Date: Thu, 11 Jan 2018 13:25:34 +0000 Subject: [PATCH 09/26] Virt: ACPI: fix qemu assert due to re-assigned table data address acpi_data_push uses g_array_set_size to resize the memory size. If there is no enough contiguous memory, the address will be changed. If we use the old value, it will assert. qemu-kvm: hw/acpi/bios-linker-loader.c:214: bios_linker_loader_add_checksum: Assertion `start_offset < file->blob->len' failed.` This issue only happens in building SRAT table now but here we unify the pattern for other tables as well to avoid possible issues in the future. Signed-off-by: Zhaoshenglong Reviewed-by: Andrew Jones Signed-off-by: Peter Maydell --- hw/arm/virt-acpi-build.c | 18 +++++++++++------- 1 file changed, 11 insertions(+), 7 deletions(-) diff --git a/hw/arm/virt-acpi-build.c b/hw/arm/virt-acpi-build.c index 3d78ff68e6..f7fa795278 100644 --- a/hw/arm/virt-acpi-build.c +++ b/hw/arm/virt-acpi-build.c @@ -453,6 +453,7 @@ build_spcr(GArray *table_data, BIOSLinker *linker, VirtMachineState *vms) AcpiSerialPortConsoleRedirection *spcr; const MemMapEntry *uart_memmap = &vms->memmap[VIRT_UART]; int irq = vms->irqmap[VIRT_UART] + ARM_SPI_BASE; + int spcr_start = table_data->len; spcr = acpi_data_push(table_data, sizeof(*spcr)); @@ -476,8 +477,8 @@ build_spcr(GArray *table_data, BIOSLinker *linker, VirtMachineState *vms) spcr->pci_device_id = 0xffff; /* PCI Device ID: not a PCI device */ spcr->pci_vendor_id = 0xffff; /* PCI Vendor ID: not a PCI device */ - build_header(linker, table_data, (void *)spcr, "SPCR", sizeof(*spcr), 2, - NULL, NULL); + build_header(linker, table_data, (void *)(table_data->data + spcr_start), + "SPCR", table_data->len - spcr_start, 2, NULL, NULL); } static void @@ -512,8 +513,8 @@ build_srat(GArray *table_data, BIOSLinker *linker, VirtMachineState *vms) mem_base += numa_info[i].node_mem; } - build_header(linker, table_data, (void *)srat, "SRAT", - table_data->len - srat_start, 3, NULL, NULL); + build_header(linker, table_data, (void *)(table_data->data + srat_start), + "SRAT", table_data->len - srat_start, 3, NULL, NULL); } static void @@ -522,6 +523,7 @@ build_mcfg(GArray *table_data, BIOSLinker *linker, VirtMachineState *vms) AcpiTableMcfg *mcfg; const MemMapEntry *memmap = vms->memmap; int len = sizeof(*mcfg) + sizeof(mcfg->allocation[0]); + int mcfg_start = table_data->len; mcfg = acpi_data_push(table_data, len); mcfg->allocation[0].address = cpu_to_le64(memmap[VIRT_PCIE_ECAM].base); @@ -532,7 +534,8 @@ build_mcfg(GArray *table_data, BIOSLinker *linker, VirtMachineState *vms) mcfg->allocation[0].end_bus_number = (memmap[VIRT_PCIE_ECAM].size / PCIE_MMCFG_SIZE_MIN) - 1; - build_header(linker, table_data, (void *)mcfg, "MCFG", len, 1, NULL, NULL); + build_header(linker, table_data, (void *)(table_data->data + mcfg_start), + "MCFG", table_data->len - mcfg_start, 1, NULL, NULL); } /* GTDT */ @@ -651,6 +654,7 @@ build_madt(GArray *table_data, BIOSLinker *linker, VirtMachineState *vms) static void build_fadt(GArray *table_data, BIOSLinker *linker, VirtMachineState *vms, unsigned dsdt_tbl_offset) { + int fadt_start = table_data->len; AcpiFadtDescriptorRev5_1 *fadt = acpi_data_push(table_data, sizeof(*fadt)); unsigned xdsdt_entry_offset = (char *)&fadt->x_dsdt - table_data->data; uint16_t bootflags; @@ -681,8 +685,8 @@ static void build_fadt(GArray *table_data, BIOSLinker *linker, ACPI_BUILD_TABLE_FILE, xdsdt_entry_offset, sizeof(fadt->x_dsdt), ACPI_BUILD_TABLE_FILE, dsdt_tbl_offset); - build_header(linker, table_data, - (void *)fadt, "FACP", sizeof(*fadt), 5, NULL, NULL); + build_header(linker, table_data, (void *)(table_data->data + fadt_start), + "FACP", table_data->len - fadt_start, 5, NULL, NULL); } /* DSDT */ From 1fdde6537ecec4a6b416bc232c868b64d645cc62 Mon Sep 17 00:00:00 2001 From: Andrey Smirnov Date: Thu, 11 Jan 2018 13:25:34 +0000 Subject: [PATCH 10/26] imx_fec: Do not link to netdev MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Binding to a particular netdev doesn't seem to belong to this layer and should probably be done as a part of board or SoC specific code. Convert all of the users of this IP block to use qdev_set_nic_properties() instead. Cc: Peter Maydell Cc: Jason Wang Cc: Philippe Mathieu-Daudé Cc: qemu-devel@nongnu.org Cc: qemu-arm@nongnu.org Cc: yurovsky@gmail.com Reviewed-by: Peter Maydell Signed-off-by: Andrey Smirnov Signed-off-by: Peter Maydell --- hw/arm/fsl-imx6.c | 1 + hw/net/imx_fec.c | 2 -- 2 files changed, 1 insertion(+), 2 deletions(-) diff --git a/hw/arm/fsl-imx6.c b/hw/arm/fsl-imx6.c index 59ef33efa9..b0d4088290 100644 --- a/hw/arm/fsl-imx6.c +++ b/hw/arm/fsl-imx6.c @@ -385,6 +385,7 @@ static void fsl_imx6_realize(DeviceState *dev, Error **errp) spi_table[i].irq)); } + qdev_set_nic_properties(DEVICE(&s->eth), &nd_table[0]); object_property_set_bool(OBJECT(&s->eth), true, "realized", &err); if (err) { error_propagate(errp, err); diff --git a/hw/net/imx_fec.c b/hw/net/imx_fec.c index 90e6ee35ba..88b4b049d7 100644 --- a/hw/net/imx_fec.c +++ b/hw/net/imx_fec.c @@ -1171,8 +1171,6 @@ static void imx_eth_realize(DeviceState *dev, Error **errp) qemu_macaddr_default_if_unset(&s->conf.macaddr); - s->conf.peers.ncs[0] = nd_table[0].netdev; - s->nic = qemu_new_nic(&imx_eth_net_info, &s->conf, object_get_typename(OBJECT(dev)), DEVICE(dev)->id, s); From a6383e99ffc3b615d8465aebbd5d48f1fa9b2949 Mon Sep 17 00:00:00 2001 From: Andrey Smirnov Date: Thu, 11 Jan 2018 13:25:35 +0000 Subject: [PATCH 11/26] imx_fec: Refactor imx_eth_enable_rx() MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Refactor imx_eth_enable_rx() to have more meaningfull variable name than 'tmp' and to reduce number of logical negations done. Cc: Peter Maydell Cc: Jason Wang Cc: Philippe Mathieu-Daudé Cc: qemu-devel@nongnu.org Cc: qemu-arm@nongnu.org Cc: yurovsky@gmail.com Reviewed-by: Philippe Mathieu-Daudé Reviewed-by: Peter Maydell Signed-off-by: Andrey Smirnov Signed-off-by: Peter Maydell --- hw/net/imx_fec.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/hw/net/imx_fec.c b/hw/net/imx_fec.c index 88b4b049d7..8b2e4b8ffe 100644 --- a/hw/net/imx_fec.c +++ b/hw/net/imx_fec.c @@ -536,19 +536,19 @@ static void imx_eth_do_tx(IMXFECState *s) static void imx_eth_enable_rx(IMXFECState *s) { IMXFECBufDesc bd; - bool tmp; + bool rx_ring_full; imx_fec_read_bd(&bd, s->rx_descriptor); - tmp = ((bd.flags & ENET_BD_E) != 0); + rx_ring_full = !(bd.flags & ENET_BD_E); - if (!tmp) { + if (rx_ring_full) { FEC_PRINTF("RX buffer full\n"); } else if (!s->regs[ENET_RDAR]) { qemu_flush_queued_packets(qemu_get_queue(s->nic)); } - s->regs[ENET_RDAR] = tmp ? ENET_RDAR_RDAR : 0; + s->regs[ENET_RDAR] = rx_ring_full ? 0 : ENET_RDAR_RDAR; } static void imx_eth_reset(DeviceState *d) From b2b012afdd9c03ba8a1619f45301d34f358d367b Mon Sep 17 00:00:00 2001 From: Andrey Smirnov Date: Thu, 11 Jan 2018 13:25:35 +0000 Subject: [PATCH 12/26] imx_fec: Change queue flushing heuristics MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit In current implementation, packet queue flushing logic seem to suffer from a deadlock like scenario if a packet is received by the interface before before Rx ring is initialized by Guest's driver. Consider the following sequence of events: 1. A QEMU instance is started against a TAP device on Linux host, running Linux guest, e. g., something to the effect of: qemu-system-arm \ -net nic,model=imx.fec,netdev=lan0 \ netdev tap,id=lan0,ifname=tap0,script=no,downscript=no \ ... rest of the arguments ... 2. Once QEMU starts, but before guest reaches the point where FEC deriver is done initializing the HW, Guest, via TAP interface, receives a number of multicast MDNS packets from Host (not necessarily true for every OS, but it happens at least on Fedora 25) 3. Recieving a packet in such a state results in imx_eth_can_receive() returning '0', which in turn causes tap_send() to disable corresponding event (tap.c:203) 4. Once Guest's driver reaches the point where it is ready to recieve packets it prepares Rx ring descriptors and writes ENET_RDAR_RDAR to ENET_RDAR register to indicate to HW that more descriptors are ready. And at this points emulation layer does this: s->regs[index] = ENET_RDAR_RDAR; imx_eth_enable_rx(s); which, combined with: if (!s->regs[ENET_RDAR]) { qemu_flush_queued_packets(qemu_get_queue(s->nic)); } results in Rx queue never being flushed and corresponding I/O event beign disabled. To prevent the problem, change the code to always flush packet queue when ENET_RDAR transitions 0 -> ENET_RDAR_RDAR. Cc: Peter Maydell Cc: Jason Wang Cc: Philippe Mathieu-Daudé Cc: qemu-devel@nongnu.org Cc: qemu-arm@nongnu.org Cc: yurovsky@gmail.com Reviewed-by: Peter Maydell Signed-off-by: Andrey Smirnov Signed-off-by: Peter Maydell --- hw/net/imx_fec.c | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/hw/net/imx_fec.c b/hw/net/imx_fec.c index 8b2e4b8ffe..eb034ffd0c 100644 --- a/hw/net/imx_fec.c +++ b/hw/net/imx_fec.c @@ -533,7 +533,7 @@ static void imx_eth_do_tx(IMXFECState *s) } } -static void imx_eth_enable_rx(IMXFECState *s) +static void imx_eth_enable_rx(IMXFECState *s, bool flush) { IMXFECBufDesc bd; bool rx_ring_full; @@ -544,7 +544,7 @@ static void imx_eth_enable_rx(IMXFECState *s) if (rx_ring_full) { FEC_PRINTF("RX buffer full\n"); - } else if (!s->regs[ENET_RDAR]) { + } else if (flush) { qemu_flush_queued_packets(qemu_get_queue(s->nic)); } @@ -807,7 +807,7 @@ static void imx_eth_write(void *opaque, hwaddr offset, uint64_t value, if (s->regs[ENET_ECR] & ENET_ECR_ETHEREN) { if (!s->regs[index]) { s->regs[index] = ENET_RDAR_RDAR; - imx_eth_enable_rx(s); + imx_eth_enable_rx(s, true); } } else { s->regs[index] = 0; @@ -930,7 +930,7 @@ static int imx_eth_can_receive(NetClientState *nc) FEC_PRINTF("\n"); - return s->regs[ENET_RDAR] ? 1 : 0; + return !!s->regs[ENET_RDAR]; } static ssize_t imx_fec_receive(NetClientState *nc, const uint8_t *buf, @@ -1020,7 +1020,7 @@ static ssize_t imx_fec_receive(NetClientState *nc, const uint8_t *buf, } } s->rx_descriptor = addr; - imx_eth_enable_rx(s); + imx_eth_enable_rx(s, false); imx_eth_update(s); return len; } @@ -1116,7 +1116,7 @@ static ssize_t imx_enet_receive(NetClientState *nc, const uint8_t *buf, } } s->rx_descriptor = addr; - imx_eth_enable_rx(s); + imx_eth_enable_rx(s, false); imx_eth_update(s); return len; } From 7bac20dc5111963083686743dee00e0ae4fd976b Mon Sep 17 00:00:00 2001 From: Andrey Smirnov Date: Thu, 11 Jan 2018 13:25:35 +0000 Subject: [PATCH 13/26] imx_fec: Move Tx frame buffer away from the stack MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Make Tx frame assembly buffer to be a paort of IMXFECState structure to avoid a concern about having large data buffer on the stack. Cc: Peter Maydell Cc: Jason Wang Cc: Philippe Mathieu-Daudé Cc: qemu-devel@nongnu.org Cc: qemu-arm@nongnu.org Cc: yurovsky@gmail.com Signed-off-by: Andrey Smirnov Reviewed-by: Peter Maydell Signed-off-by: Peter Maydell --- hw/net/imx_fec.c | 22 +++++++++++----------- include/hw/net/imx_fec.h | 3 +++ 2 files changed, 14 insertions(+), 11 deletions(-) diff --git a/hw/net/imx_fec.c b/hw/net/imx_fec.c index eb034ffd0c..56cb72273c 100644 --- a/hw/net/imx_fec.c +++ b/hw/net/imx_fec.c @@ -405,8 +405,7 @@ static void imx_eth_update(IMXFECState *s) static void imx_fec_do_tx(IMXFECState *s) { int frame_size = 0, descnt = 0; - uint8_t frame[ENET_MAX_FRAME_SIZE]; - uint8_t *ptr = frame; + uint8_t *ptr = s->frame; uint32_t addr = s->tx_descriptor; while (descnt++ < IMX_MAX_DESC) { @@ -431,8 +430,8 @@ static void imx_fec_do_tx(IMXFECState *s) frame_size += len; if (bd.flags & ENET_BD_L) { /* Last buffer in frame. */ - qemu_send_packet(qemu_get_queue(s->nic), frame, frame_size); - ptr = frame; + qemu_send_packet(qemu_get_queue(s->nic), s->frame, frame_size); + ptr = s->frame; frame_size = 0; s->regs[ENET_EIR] |= ENET_INT_TXF; } @@ -456,8 +455,7 @@ static void imx_fec_do_tx(IMXFECState *s) static void imx_enet_do_tx(IMXFECState *s) { int frame_size = 0, descnt = 0; - uint8_t frame[ENET_MAX_FRAME_SIZE]; - uint8_t *ptr = frame; + uint8_t *ptr = s->frame; uint32_t addr = s->tx_descriptor; while (descnt++ < IMX_MAX_DESC) { @@ -482,13 +480,13 @@ static void imx_enet_do_tx(IMXFECState *s) frame_size += len; if (bd.flags & ENET_BD_L) { if (bd.option & ENET_BD_PINS) { - struct ip_header *ip_hd = PKT_GET_IP_HDR(frame); + struct ip_header *ip_hd = PKT_GET_IP_HDR(s->frame); if (IP_HEADER_VERSION(ip_hd) == 4) { - net_checksum_calculate(frame, frame_size); + net_checksum_calculate(s->frame, frame_size); } } if (bd.option & ENET_BD_IINS) { - struct ip_header *ip_hd = PKT_GET_IP_HDR(frame); + struct ip_header *ip_hd = PKT_GET_IP_HDR(s->frame); /* We compute checksum only for IPv4 frames */ if (IP_HEADER_VERSION(ip_hd) == 4) { uint16_t csum; @@ -498,8 +496,10 @@ static void imx_enet_do_tx(IMXFECState *s) } } /* Last buffer in frame. */ - qemu_send_packet(qemu_get_queue(s->nic), frame, len); - ptr = frame; + + qemu_send_packet(qemu_get_queue(s->nic), s->frame, len); + ptr = s->frame; + frame_size = 0; if (bd.option & ENET_BD_TX_INT) { s->regs[ENET_EIR] |= ENET_INT_TXF; diff --git a/include/hw/net/imx_fec.h b/include/hw/net/imx_fec.h index 62ad473b05..67993870a2 100644 --- a/include/hw/net/imx_fec.h +++ b/include/hw/net/imx_fec.h @@ -252,6 +252,9 @@ typedef struct IMXFECState { uint32_t phy_int_mask; bool is_fec; + + /* Buffer used to assemble a Tx frame */ + uint8_t frame[ENET_MAX_FRAME_SIZE]; } IMXFECState; #endif From ff9a7feeab59323d70a9377e9196f042b0647d66 Mon Sep 17 00:00:00 2001 From: Andrey Smirnov Date: Thu, 11 Jan 2018 13:25:36 +0000 Subject: [PATCH 14/26] imx_fec: Use ENET_FTRL to determine truncation length MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Frame truncation length, TRUNC_FL, is determined by the contents of ENET_FTRL register, so convert the code to use it instead of a hardcoded constant. To avoid the case where TRUNC_FL is greater that ENET_MAX_FRAME_SIZE, increase the value of the latter to its theoretical maximum of 16K. Cc: Peter Maydell Cc: Jason Wang Cc: Philippe Mathieu-Daudé Cc: qemu-devel@nongnu.org Cc: qemu-arm@nongnu.org Cc: yurovsky@gmail.com Signed-off-by: Andrey Smirnov Reviewed-by: Peter Maydell Signed-off-by: Peter Maydell --- hw/net/imx_fec.c | 4 ++-- include/hw/net/imx_fec.h | 3 ++- 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/hw/net/imx_fec.c b/hw/net/imx_fec.c index 56cb72273c..50da91bf9e 100644 --- a/hw/net/imx_fec.c +++ b/hw/net/imx_fec.c @@ -1052,8 +1052,8 @@ static ssize_t imx_enet_receive(NetClientState *nc, const uint8_t *buf, crc_ptr = (uint8_t *) &crc; /* Huge frames are truncted. */ - if (size > ENET_MAX_FRAME_SIZE) { - size = ENET_MAX_FRAME_SIZE; + if (size > s->regs[ENET_FTRL]) { + size = s->regs[ENET_FTRL]; flags |= ENET_BD_TR | ENET_BD_LG; } diff --git a/include/hw/net/imx_fec.h b/include/hw/net/imx_fec.h index 67993870a2..a390d704a6 100644 --- a/include/hw/net/imx_fec.h +++ b/include/hw/net/imx_fec.h @@ -86,7 +86,6 @@ #define ENET_TCCR3 393 #define ENET_MAX 400 -#define ENET_MAX_FRAME_SIZE 2032 /* EIR and EIMR */ #define ENET_INT_HB (1 << 31) @@ -155,6 +154,8 @@ #define ENET_RCR_NLC (1 << 30) #define ENET_RCR_GRS (1 << 31) +#define ENET_MAX_FRAME_SIZE (1 << ENET_RCR_MAX_FL_LENGTH) + /* TCR */ #define ENET_TCR_GTS (1 << 0) #define ENET_TCR_FDEN (1 << 2) From 4c5e7a6cdae78ed823042375824ced09cccefbdb Mon Sep 17 00:00:00 2001 From: Andrey Smirnov Date: Thu, 11 Jan 2018 13:25:36 +0000 Subject: [PATCH 15/26] imx_fec: Use MIN instead of explicit ternary operator MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Cc: Peter Maydell Cc: Jason Wang Cc: Philippe Mathieu-Daudé Cc: qemu-devel@nongnu.org Cc: qemu-arm@nongnu.org Cc: yurovsky@gmail.com Reviewed-by: Philippe Mathieu-Daudé Signed-off-by: Andrey Smirnov Signed-off-by: Peter Maydell --- hw/net/imx_fec.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/hw/net/imx_fec.c b/hw/net/imx_fec.c index 50da91bf9e..6feda18742 100644 --- a/hw/net/imx_fec.c +++ b/hw/net/imx_fec.c @@ -1076,7 +1076,7 @@ static ssize_t imx_enet_receive(NetClientState *nc, const uint8_t *buf, TYPE_IMX_FEC, __func__); break; } - buf_len = (size <= s->regs[ENET_MRBR]) ? size : s->regs[ENET_MRBR]; + buf_len = MIN(size, s->regs[ENET_MRBR]); bd.length = buf_len; size -= buf_len; From ebdd8cddb9e657ef75024b4cc9057dd4ce397a55 Mon Sep 17 00:00:00 2001 From: Andrey Smirnov Date: Thu, 11 Jan 2018 13:25:37 +0000 Subject: [PATCH 16/26] imx_fec: Emulate SHIFT16 in ENETx_RACC MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Needed to support latest Linux kernel driver which relies on that functionality. Cc: Peter Maydell Cc: Jason Wang Cc: Philippe Mathieu-Daudé Cc: qemu-devel@nongnu.org Cc: qemu-arm@nongnu.org Cc: yurovsky@gmail.com Reviewed-by: Peter Maydell Signed-off-by: Andrey Smirnov Signed-off-by: Peter Maydell --- hw/net/imx_fec.c | 23 +++++++++++++++++++++++ include/hw/net/imx_fec.h | 2 ++ 2 files changed, 25 insertions(+) diff --git a/hw/net/imx_fec.c b/hw/net/imx_fec.c index 6feda18742..825c879a28 100644 --- a/hw/net/imx_fec.c +++ b/hw/net/imx_fec.c @@ -1037,6 +1037,7 @@ static ssize_t imx_enet_receive(NetClientState *nc, const uint8_t *buf, uint8_t *crc_ptr; unsigned int buf_len; size_t size = len; + bool shift16 = s->regs[ENET_RACC] & ENET_RACC_SHIFT16; FEC_PRINTF("len %d\n", (int)size); @@ -1051,6 +1052,10 @@ static ssize_t imx_enet_receive(NetClientState *nc, const uint8_t *buf, crc = cpu_to_be32(crc32(~0, buf, size)); crc_ptr = (uint8_t *) &crc; + if (shift16) { + size += 2; + } + /* Huge frames are truncted. */ if (size > s->regs[ENET_FTRL]) { size = s->regs[ENET_FTRL]; @@ -1087,6 +1092,24 @@ static ssize_t imx_enet_receive(NetClientState *nc, const uint8_t *buf, buf_len += size - 4; } buf_addr = bd.data; + + if (shift16) { + /* + * If SHIFT16 bit of ENETx_RACC register is set we need to + * align the payload to 4-byte boundary. + */ + const uint8_t zeros[2] = { 0 }; + + dma_memory_write(&address_space_memory, buf_addr, + zeros, sizeof(zeros)); + + buf_addr += sizeof(zeros); + buf_len -= sizeof(zeros); + + /* We only do this once per Ethernet frame */ + shift16 = false; + } + dma_memory_write(&address_space_memory, buf_addr, buf, buf_len); buf += buf_len; if (size < 4) { diff --git a/include/hw/net/imx_fec.h b/include/hw/net/imx_fec.h index a390d704a6..af0840a0fa 100644 --- a/include/hw/net/imx_fec.h +++ b/include/hw/net/imx_fec.h @@ -170,6 +170,8 @@ #define ENET_TWFR_TFWR_LENGTH (6) #define ENET_TWFR_STRFWD (1 << 8) +#define ENET_RACC_SHIFT16 BIT(7) + /* Buffer Descriptor. */ typedef struct { uint16_t length; From f93f961c40a31228e3f66e66d99a68937aa242c5 Mon Sep 17 00:00:00 2001 From: Andrey Smirnov Date: Thu, 11 Jan 2018 13:25:37 +0000 Subject: [PATCH 17/26] imx_fec: Add support for multiple Tx DMA rings MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit More recent version of the IP block support more than one Tx DMA ring, so add the code implementing that feature. Cc: Peter Maydell Cc: Jason Wang Cc: Philippe Mathieu-Daudé Cc: qemu-devel@nongnu.org Cc: qemu-arm@nongnu.org Cc: yurovsky@gmail.com Reviewed-by: Peter Maydell Signed-off-by: Andrey Smirnov Signed-off-by: Peter Maydell --- hw/net/imx_fec.c | 133 +++++++++++++++++++++++++++++++++------ include/hw/net/imx_fec.h | 18 +++++- 2 files changed, 130 insertions(+), 21 deletions(-) diff --git a/hw/net/imx_fec.c b/hw/net/imx_fec.c index 825c879a28..77d27f763e 100644 --- a/hw/net/imx_fec.c +++ b/hw/net/imx_fec.c @@ -196,6 +196,31 @@ static const char *imx_eth_reg_name(IMXFECState *s, uint32_t index) } } +/* + * Versions of this device with more than one TX descriptor save the + * 2nd and 3rd descriptors in a subsection, to maintain migration + * compatibility with previous versions of the device that only + * supported a single descriptor. + */ +static bool imx_eth_is_multi_tx_ring(void *opaque) +{ + IMXFECState *s = IMX_FEC(opaque); + + return s->tx_ring_num > 1; +} + +static const VMStateDescription vmstate_imx_eth_txdescs = { + .name = "imx.fec/txdescs", + .version_id = 1, + .minimum_version_id = 1, + .needed = imx_eth_is_multi_tx_ring, + .fields = (VMStateField[]) { + VMSTATE_UINT32(tx_descriptor[1], IMXFECState), + VMSTATE_UINT32(tx_descriptor[2], IMXFECState), + VMSTATE_END_OF_LIST() + } +}; + static const VMStateDescription vmstate_imx_eth = { .name = TYPE_IMX_FEC, .version_id = 2, @@ -203,15 +228,18 @@ static const VMStateDescription vmstate_imx_eth = { .fields = (VMStateField[]) { VMSTATE_UINT32_ARRAY(regs, IMXFECState, ENET_MAX), VMSTATE_UINT32(rx_descriptor, IMXFECState), - VMSTATE_UINT32(tx_descriptor, IMXFECState), - + VMSTATE_UINT32(tx_descriptor[0], IMXFECState), VMSTATE_UINT32(phy_status, IMXFECState), VMSTATE_UINT32(phy_control, IMXFECState), VMSTATE_UINT32(phy_advertise, IMXFECState), VMSTATE_UINT32(phy_int, IMXFECState), VMSTATE_UINT32(phy_int_mask, IMXFECState), VMSTATE_END_OF_LIST() - } + }, + .subsections = (const VMStateDescription * []) { + &vmstate_imx_eth_txdescs, + NULL + }, }; #define PHY_INT_ENERGYON (1 << 7) @@ -406,7 +434,7 @@ static void imx_fec_do_tx(IMXFECState *s) { int frame_size = 0, descnt = 0; uint8_t *ptr = s->frame; - uint32_t addr = s->tx_descriptor; + uint32_t addr = s->tx_descriptor[0]; while (descnt++ < IMX_MAX_DESC) { IMXFECBufDesc bd; @@ -447,16 +475,47 @@ static void imx_fec_do_tx(IMXFECState *s) } } - s->tx_descriptor = addr; + s->tx_descriptor[0] = addr; imx_eth_update(s); } -static void imx_enet_do_tx(IMXFECState *s) +static void imx_enet_do_tx(IMXFECState *s, uint32_t index) { int frame_size = 0, descnt = 0; + uint8_t *ptr = s->frame; - uint32_t addr = s->tx_descriptor; + uint32_t addr, int_txb, int_txf, tdsr; + size_t ring; + + switch (index) { + case ENET_TDAR: + ring = 0; + int_txb = ENET_INT_TXB; + int_txf = ENET_INT_TXF; + tdsr = ENET_TDSR; + break; + case ENET_TDAR1: + ring = 1; + int_txb = ENET_INT_TXB1; + int_txf = ENET_INT_TXF1; + tdsr = ENET_TDSR1; + break; + case ENET_TDAR2: + ring = 2; + int_txb = ENET_INT_TXB2; + int_txf = ENET_INT_TXF2; + tdsr = ENET_TDSR2; + break; + default: + qemu_log_mask(LOG_GUEST_ERROR, + "%s: bogus value for index %x\n", + __func__, index); + abort(); + break; + } + + addr = s->tx_descriptor[ring]; while (descnt++ < IMX_MAX_DESC) { IMXENETBufDesc bd; @@ -502,32 +561,32 @@ static void imx_enet_do_tx(IMXFECState *s) frame_size = 0; if (bd.option & ENET_BD_TX_INT) { - s->regs[ENET_EIR] |= ENET_INT_TXF; + s->regs[ENET_EIR] |= int_txf; } } if (bd.option & ENET_BD_TX_INT) { - s->regs[ENET_EIR] |= ENET_INT_TXB; + s->regs[ENET_EIR] |= int_txb; } bd.flags &= ~ENET_BD_R; /* Write back the modified descriptor. */ imx_enet_write_bd(&bd, addr); /* Advance to the next descriptor. */ if ((bd.flags & ENET_BD_W) != 0) { - addr = s->regs[ENET_TDSR]; + addr = s->regs[tdsr]; } else { addr += sizeof(bd); } } - s->tx_descriptor = addr; + s->tx_descriptor[ring] = addr; imx_eth_update(s); } -static void imx_eth_do_tx(IMXFECState *s) +static void imx_eth_do_tx(IMXFECState *s, uint32_t index) { if (!s->is_fec && (s->regs[ENET_ECR] & ENET_ECR_EN1588)) { - imx_enet_do_tx(s); + imx_enet_do_tx(s, index); } else { imx_fec_do_tx(s); } @@ -585,7 +644,7 @@ static void imx_eth_reset(DeviceState *d) } s->rx_descriptor = 0; - s->tx_descriptor = 0; + memset(s->tx_descriptor, 0, sizeof(s->tx_descriptor)); /* We also reset the PHY */ phy_reset(s); @@ -791,6 +850,7 @@ static void imx_eth_write(void *opaque, hwaddr offset, uint64_t value, unsigned size) { IMXFECState *s = IMX_FEC(opaque); + const bool single_tx_ring = !imx_eth_is_multi_tx_ring(s); uint32_t index = offset >> 2; FEC_PRINTF("reg[%s] <= 0x%" PRIx32 "\n", imx_eth_reg_name(s, index), @@ -813,10 +873,18 @@ static void imx_eth_write(void *opaque, hwaddr offset, uint64_t value, s->regs[index] = 0; } break; - case ENET_TDAR: + case ENET_TDAR1: /* FALLTHROUGH */ + case ENET_TDAR2: /* FALLTHROUGH */ + if (unlikely(single_tx_ring)) { + qemu_log_mask(LOG_GUEST_ERROR, + "[%s]%s: trying to access TDAR2 or TDAR1\n", + TYPE_IMX_FEC, __func__); + return; + } + case ENET_TDAR: /* FALLTHROUGH */ if (s->regs[ENET_ECR] & ENET_ECR_ETHEREN) { s->regs[index] = ENET_TDAR_TDAR; - imx_eth_do_tx(s); + imx_eth_do_tx(s, index); } s->regs[index] = 0; break; @@ -828,8 +896,12 @@ static void imx_eth_write(void *opaque, hwaddr offset, uint64_t value, if ((s->regs[index] & ENET_ECR_ETHEREN) == 0) { s->regs[ENET_RDAR] = 0; s->rx_descriptor = s->regs[ENET_RDSR]; - s->regs[ENET_TDAR] = 0; - s->tx_descriptor = s->regs[ENET_TDSR]; + s->regs[ENET_TDAR] = 0; + s->regs[ENET_TDAR1] = 0; + s->regs[ENET_TDAR2] = 0; + s->tx_descriptor[0] = s->regs[ENET_TDSR]; + s->tx_descriptor[1] = s->regs[ENET_TDSR1]; + s->tx_descriptor[2] = s->regs[ENET_TDSR2]; } break; case ENET_MMFR: @@ -907,7 +979,29 @@ static void imx_eth_write(void *opaque, hwaddr offset, uint64_t value, } else { s->regs[index] = value & ~7; } - s->tx_descriptor = s->regs[index]; + s->tx_descriptor[0] = s->regs[index]; + break; + case ENET_TDSR1: + if (unlikely(single_tx_ring)) { + qemu_log_mask(LOG_GUEST_ERROR, + "[%s]%s: trying to access TDSR1\n", + TYPE_IMX_FEC, __func__); + return; + } + + s->regs[index] = value & ~7; + s->tx_descriptor[1] = s->regs[index]; + break; + case ENET_TDSR2: + if (unlikely(single_tx_ring)) { + qemu_log_mask(LOG_GUEST_ERROR, + "[%s]%s: trying to access TDSR2\n", + TYPE_IMX_FEC, __func__); + return; + } + + s->regs[index] = value & ~7; + s->tx_descriptor[2] = s->regs[index]; break; case ENET_MRBR: s->regs[index] = value & 0x00003ff0; @@ -1203,6 +1297,7 @@ static void imx_eth_realize(DeviceState *dev, Error **errp) static Property imx_eth_properties[] = { DEFINE_NIC_PROPERTIES(IMXFECState, conf), + DEFINE_PROP_UINT32("tx-ring-num", IMXFECState, tx_ring_num, 1), DEFINE_PROP_END_OF_LIST(), }; diff --git a/include/hw/net/imx_fec.h b/include/hw/net/imx_fec.h index af0840a0fa..91ef8f89a6 100644 --- a/include/hw/net/imx_fec.h +++ b/include/hw/net/imx_fec.h @@ -52,6 +52,8 @@ #define ENET_TFWR 81 #define ENET_FRBR 83 #define ENET_FRSR 84 +#define ENET_TDSR1 89 +#define ENET_TDSR2 92 #define ENET_RDSR 96 #define ENET_TDSR 97 #define ENET_MRBR 98 @@ -66,6 +68,8 @@ #define ENET_FTRL 108 #define ENET_TACC 112 #define ENET_RACC 113 +#define ENET_TDAR1 121 +#define ENET_TDAR2 123 #define ENET_MIIGSK_CFGR 192 #define ENET_MIIGSK_ENR 194 #define ENET_ATCR 256 @@ -105,13 +109,18 @@ #define ENET_INT_WAKEUP (1 << 17) #define ENET_INT_TS_AVAIL (1 << 16) #define ENET_INT_TS_TIMER (1 << 15) +#define ENET_INT_TXF2 (1 << 7) +#define ENET_INT_TXB2 (1 << 6) +#define ENET_INT_TXF1 (1 << 3) +#define ENET_INT_TXB1 (1 << 2) #define ENET_INT_MAC (ENET_INT_HB | ENET_INT_BABR | ENET_INT_BABT | \ ENET_INT_GRA | ENET_INT_TXF | ENET_INT_TXB | \ ENET_INT_RXF | ENET_INT_RXB | ENET_INT_MII | \ ENET_INT_EBERR | ENET_INT_LC | ENET_INT_RL | \ ENET_INT_UN | ENET_INT_PLR | ENET_INT_WAKEUP | \ - ENET_INT_TS_AVAIL) + ENET_INT_TS_AVAIL | ENET_INT_TXF1 | \ + ENET_INT_TXB1 | ENET_INT_TXF2 | ENET_INT_TXB2) /* RDAR */ #define ENET_RDAR_RDAR (1 << 24) @@ -234,6 +243,9 @@ typedef struct { #define ENET_BD_BDU (1 << 31) +#define ENET_TX_RING_NUM 3 + + typedef struct IMXFECState { /*< private >*/ SysBusDevice parent_obj; @@ -246,7 +258,9 @@ typedef struct IMXFECState { uint32_t regs[ENET_MAX]; uint32_t rx_descriptor; - uint32_t tx_descriptor; + + uint32_t tx_descriptor[ENET_TX_RING_NUM]; + uint32_t tx_ring_num; uint32_t phy_status; uint32_t phy_control; From 52cfd5846b8979805077ce7608aa36c18a2a9f32 Mon Sep 17 00:00:00 2001 From: Andrey Smirnov Date: Thu, 11 Jan 2018 13:25:37 +0000 Subject: [PATCH 18/26] imx_fec: Use correct length for packet size MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Use 'frame_size' instead of 'len' when calling qemu_send_packet(), failing to do so results in malformed packets send in case when that packed is fragmented into multiple DMA transactions. Cc: Peter Maydell Cc: Jason Wang Cc: Philippe Mathieu-Daudé Cc: qemu-devel@nongnu.org Cc: qemu-arm@nongnu.org Cc: yurovsky@gmail.com Reviewed-by: Peter Maydell Signed-off-by: Andrey Smirnov Signed-off-by: Peter Maydell --- hw/net/imx_fec.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/hw/net/imx_fec.c b/hw/net/imx_fec.c index 77d27f763e..6cb9e2e20e 100644 --- a/hw/net/imx_fec.c +++ b/hw/net/imx_fec.c @@ -556,7 +556,7 @@ static void imx_enet_do_tx(IMXFECState *s, uint32_t index) } /* Last buffer in frame. */ - qemu_send_packet(qemu_get_queue(s->nic), s->frame, len); + qemu_send_packet(qemu_get_queue(s->nic), s->frame, frame_size); ptr = s->frame; frame_size = 0; From 894d74cc4f2fa577765bae711b9dc9ac9309521e Mon Sep 17 00:00:00 2001 From: Andrey Smirnov Date: Thu, 11 Jan 2018 13:25:38 +0000 Subject: [PATCH 19/26] imx_fec: Fix a typo in imx_enet_receive() MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Cc: Peter Maydell Cc: Jason Wang Cc: Philippe Mathieu-Daudé Cc: qemu-devel@nongnu.org Cc: qemu-arm@nongnu.org Cc: yurovsky@gmail.com Reviewed-by: Peter Maydell Signed-off-by: Andrey Smirnov Signed-off-by: Peter Maydell --- hw/net/imx_fec.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/hw/net/imx_fec.c b/hw/net/imx_fec.c index 6cb9e2e20e..c1cf7f9c58 100644 --- a/hw/net/imx_fec.c +++ b/hw/net/imx_fec.c @@ -1150,7 +1150,7 @@ static ssize_t imx_enet_receive(NetClientState *nc, const uint8_t *buf, size += 2; } - /* Huge frames are truncted. */ + /* Huge frames are truncated. */ if (size > s->regs[ENET_FTRL]) { size = s->regs[ENET_FTRL]; flags |= ENET_BD_TR | ENET_BD_LG; From 831858ad9da7eccf4c260c60ed56cff0f1666424 Mon Sep 17 00:00:00 2001 From: Andrey Smirnov Date: Thu, 11 Jan 2018 13:25:38 +0000 Subject: [PATCH 20/26] imx_fec: Reserve full FSL_IMX25_FEC_SIZE page for the register file MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Some i.MX SoCs (e.g. i.MX7) have FEC registers going as far as offset 0x614, so to avoid getting aborts when accessing those on QEMU, extend the register file to cover FSL_IMX25_FEC_SIZE(16K) of address space instead of just 1K. Cc: Peter Maydell Cc: Jason Wang Cc: Philippe Mathieu-Daudé Cc: qemu-devel@nongnu.org Cc: qemu-arm@nongnu.org Cc: yurovsky@gmail.com Reviewed-by: Peter Maydell Signed-off-by: Andrey Smirnov Signed-off-by: Peter Maydell --- hw/net/imx_fec.c | 2 +- include/hw/arm/fsl-imx25.h | 1 - include/hw/net/imx_fec.h | 1 + 3 files changed, 2 insertions(+), 2 deletions(-) diff --git a/hw/net/imx_fec.c b/hw/net/imx_fec.c index c1cf7f9c58..4fb48f62ba 100644 --- a/hw/net/imx_fec.c +++ b/hw/net/imx_fec.c @@ -1281,7 +1281,7 @@ static void imx_eth_realize(DeviceState *dev, Error **errp) SysBusDevice *sbd = SYS_BUS_DEVICE(dev); memory_region_init_io(&s->iomem, OBJECT(dev), &imx_eth_ops, s, - TYPE_IMX_FEC, 0x400); + TYPE_IMX_FEC, FSL_IMX25_FEC_SIZE); sysbus_init_mmio(sbd, &s->iomem); sysbus_init_irq(sbd, &s->irq[0]); sysbus_init_irq(sbd, &s->irq[1]); diff --git a/include/hw/arm/fsl-imx25.h b/include/hw/arm/fsl-imx25.h index d0e8e9d956..65a73714ef 100644 --- a/include/hw/arm/fsl-imx25.h +++ b/include/hw/arm/fsl-imx25.h @@ -192,7 +192,6 @@ typedef struct FslIMX25State { #define FSL_IMX25_UART5_ADDR 0x5002C000 #define FSL_IMX25_UART5_SIZE 0x4000 #define FSL_IMX25_FEC_ADDR 0x50038000 -#define FSL_IMX25_FEC_SIZE 0x4000 #define FSL_IMX25_CCM_ADDR 0x53F80000 #define FSL_IMX25_CCM_SIZE 0x4000 #define FSL_IMX25_GPT4_ADDR 0x53F84000 diff --git a/include/hw/net/imx_fec.h b/include/hw/net/imx_fec.h index 91ef8f89a6..7b3faa4019 100644 --- a/include/hw/net/imx_fec.h +++ b/include/hw/net/imx_fec.h @@ -245,6 +245,7 @@ typedef struct { #define ENET_TX_RING_NUM 3 +#define FSL_IMX25_FEC_SIZE 0x4000 typedef struct IMXFECState { /*< private >*/ From 2ba63e4af69b674f4fabd317dd438061de1ea310 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Philippe=20Mathieu-Daud=C3=A9?= Date: Thu, 11 Jan 2018 13:25:38 +0000 Subject: [PATCH 21/26] hw/timer/pxa2xx_timer: replace hw_error() -> qemu_log_mask() MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Philippe Mathieu-Daudé Reviewed-by: Alistair Francis Message-id: 20180103224208.30291-2-f4bug@amsat.org Signed-off-by: Peter Maydell --- hw/timer/pxa2xx_timer.c | 17 +++++++++++++++-- 1 file changed, 15 insertions(+), 2 deletions(-) diff --git a/hw/timer/pxa2xx_timer.c b/hw/timer/pxa2xx_timer.c index 68ba5a70b3..a489bf5159 100644 --- a/hw/timer/pxa2xx_timer.c +++ b/hw/timer/pxa2xx_timer.c @@ -13,6 +13,7 @@ #include "sysemu/sysemu.h" #include "hw/arm/pxa.h" #include "hw/sysbus.h" +#include "qemu/log.h" #define OSMR0 0x00 #define OSMR1 0x04 @@ -252,8 +253,14 @@ static uint64_t pxa2xx_timer_read(void *opaque, hwaddr offset, case OSNR: return s->snapshot; default: + qemu_log_mask(LOG_UNIMP, + "%s: unknown register 0x%02" HWADDR_PRIx "\n", + __func__, offset); + break; badreg: - hw_error("pxa2xx_timer_read: Bad offset " REG_FMT "\n", offset); + qemu_log_mask(LOG_GUEST_ERROR, + "%s: incorrect register 0x%02" HWADDR_PRIx "\n", + __func__, offset); } return 0; @@ -377,8 +384,14 @@ static void pxa2xx_timer_write(void *opaque, hwaddr offset, } break; default: + qemu_log_mask(LOG_UNIMP, + "%s: unknown register 0x%02" HWADDR_PRIx " " + "(value 0x%08" PRIx64 ")\n", __func__, offset, value); + break; badreg: - hw_error("pxa2xx_timer_write: Bad offset " REG_FMT "\n", offset); + qemu_log_mask(LOG_GUEST_ERROR, + "%s: incorrect register 0x%02" HWADDR_PRIx " " + "(value 0x%08" PRIx64 ")\n", __func__, offset, value); } } From 487b406af1164dc036c70126f53a20c4c395db92 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Philippe=20Mathieu-Daud=C3=A9?= Date: Thu, 11 Jan 2018 13:25:39 +0000 Subject: [PATCH 22/26] hw/sd/pxa2xx_mmci: add read/write() trace events MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Philippe Mathieu-Daudé Reviewed-by: Alistair Francis Message-id: 20180104000156.30932-1-f4bug@amsat.org [PMM: add missing include] Signed-off-by: Peter Maydell --- hw/sd/pxa2xx_mmci.c | 78 +++++++++++++++++++++++++++++---------------- hw/sd/trace-events | 4 +++ 2 files changed, 54 insertions(+), 28 deletions(-) diff --git a/hw/sd/pxa2xx_mmci.c b/hw/sd/pxa2xx_mmci.c index 3deccf02c9..82f8ec0d50 100644 --- a/hw/sd/pxa2xx_mmci.c +++ b/hw/sd/pxa2xx_mmci.c @@ -19,6 +19,8 @@ #include "hw/qdev.h" #include "hw/qdev-properties.h" #include "qemu/error-report.h" +#include "qemu/log.h" +#include "trace.h" #define TYPE_PXA2XX_MMCI "pxa2xx-mmci" #define PXA2XX_MMCI(obj) OBJECT_CHECK(PXA2xxMMCIState, (obj), TYPE_PXA2XX_MMCI) @@ -278,45 +280,56 @@ static void pxa2xx_mmci_wakequeues(PXA2xxMMCIState *s) static uint64_t pxa2xx_mmci_read(void *opaque, hwaddr offset, unsigned size) { PXA2xxMMCIState *s = (PXA2xxMMCIState *) opaque; - uint32_t ret; + uint32_t ret = 0; switch (offset) { case MMC_STRPCL: - return 0; + break; case MMC_STAT: - return s->status; + ret = s->status; + break; case MMC_CLKRT: - return s->clkrt; + ret = s->clkrt; + break; case MMC_SPI: - return s->spi; + ret = s->spi; + break; case MMC_CMDAT: - return s->cmdat; + ret = s->cmdat; + break; case MMC_RESTO: - return s->resp_tout; + ret = s->resp_tout; + break; case MMC_RDTO: - return s->read_tout; + ret = s->read_tout; + break; case MMC_BLKLEN: - return s->blklen; + ret = s->blklen; + break; case MMC_NUMBLK: - return s->numblk; + ret = s->numblk; + break; case MMC_PRTBUF: - return 0; + break; case MMC_I_MASK: - return s->intmask; + ret = s->intmask; + break; case MMC_I_REG: - return s->intreq; + ret = s->intreq; + break; case MMC_CMD: - return s->cmd | 0x40; + ret = s->cmd | 0x40; + break; case MMC_ARGH: - return s->arg >> 16; + ret = s->arg >> 16; + break; case MMC_ARGL: - return s->arg & 0xffff; + ret = s->arg & 0xffff; + break; case MMC_RES: - if (s->resp_len < 9) - return s->resp_fifo[s->resp_len ++]; - return 0; + ret = (s->resp_len < 9) ? s->resp_fifo[s->resp_len++] : 0; + break; case MMC_RXFIFO: - ret = 0; while (size-- && s->rx_len) { ret |= s->rx_fifo[s->rx_start++] << (size << 3); s->rx_start &= 0x1f; @@ -324,16 +337,20 @@ static uint64_t pxa2xx_mmci_read(void *opaque, hwaddr offset, unsigned size) } s->intreq &= ~INT_RXFIFO_REQ; pxa2xx_mmci_fifo_update(s); - return ret; + break; case MMC_RDWAIT: - return 0; + break; case MMC_BLKS_REM: - return s->numblk; + ret = s->numblk; + break; default: - hw_error("%s: Bad offset " REG_FMT "\n", __FUNCTION__, offset); + qemu_log_mask(LOG_GUEST_ERROR, + "%s: incorrect register 0x%02" HWADDR_PRIx "\n", + __func__, offset); } + trace_pxa2xx_mmci_read(size, offset, ret); - return 0; + return ret; } static void pxa2xx_mmci_write(void *opaque, @@ -341,6 +358,7 @@ static void pxa2xx_mmci_write(void *opaque, { PXA2xxMMCIState *s = (PXA2xxMMCIState *) opaque; + trace_pxa2xx_mmci_write(size, offset, value); switch (offset) { case MMC_STRPCL: if (value & STRPCL_STRT_CLK) { @@ -368,8 +386,10 @@ static void pxa2xx_mmci_write(void *opaque, case MMC_SPI: s->spi = value & 0xf; - if (value & SPI_SPI_MODE) - printf("%s: attempted to use card in SPI mode\n", __FUNCTION__); + if (value & SPI_SPI_MODE) { + qemu_log_mask(LOG_GUEST_ERROR, + "%s: attempted to use card in SPI mode\n", __func__); + } break; case MMC_CMDAT: @@ -442,7 +462,9 @@ static void pxa2xx_mmci_write(void *opaque, break; default: - hw_error("%s: Bad offset " REG_FMT "\n", __FUNCTION__, offset); + qemu_log_mask(LOG_GUEST_ERROR, + "%s: incorrect reg 0x%02" HWADDR_PRIx " " + "(value 0x%08" PRIx64 ")\n", __func__, offset, value); } } diff --git a/hw/sd/trace-events b/hw/sd/trace-events index 1fc0bcf44b..6eca3470e2 100644 --- a/hw/sd/trace-events +++ b/hw/sd/trace-events @@ -3,3 +3,7 @@ # hw/sd/milkymist-memcard.c milkymist_memcard_memory_read(uint32_t addr, uint32_t value) "addr 0x%08x value 0x%08x" milkymist_memcard_memory_write(uint32_t addr, uint32_t value) "addr 0x%08x value 0x%08x" + +# hw/sd/pxa2xx_mmci.c +pxa2xx_mmci_read(uint8_t size, uint32_t addr, uint32_t value) "size %d addr 0x%02x value 0x%08x" +pxa2xx_mmci_write(uint8_t size, uint32_t addr, uint32_t value) "size %d addr 0x%02x value 0x%08x" From 579648554acbd6c22d5cc2f03cf77cfc25332650 Mon Sep 17 00:00:00 2001 From: Peter Maydell Date: Thu, 11 Jan 2018 13:25:39 +0000 Subject: [PATCH 23/26] linux-user/arm/nwfpe: Check coprocessor number for FPA emulation Our copy of the nwfpe code for emulating of the old FPA11 floating point unit doesn't check the coprocessor number in the instruction when it emulates it. This means that we might treat some instructions which should really UNDEF as being FPA11 instructions by accident. The kernel's copy of the nwfpe code doesn't make this error; I suspect the bug was noticed and fixed as part of the process of mainlining the nwfpe code more than a decade ago. Add a check that the coprocessor number (which is always in bits [11:8] of the instruction) is either 1 or 2, which is where the FPA11 lives. Reported-by: Richard Henderson Signed-off-by: Peter Maydell --- linux-user/arm/nwfpe/fpa11.c | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/linux-user/arm/nwfpe/fpa11.c b/linux-user/arm/nwfpe/fpa11.c index 441e3b1cf6..f6f8163eab 100644 --- a/linux-user/arm/nwfpe/fpa11.c +++ b/linux-user/arm/nwfpe/fpa11.c @@ -137,8 +137,17 @@ unsigned int EmulateAll(unsigned int opcode, FPA11* qfpa, CPUARMState* qregs) unsigned int nRc = 0; // unsigned long flags; FPA11 *fpa11; + unsigned int cp; // save_flags(flags); sti(); + /* Check that this is really an FPA11 instruction: the coprocessor + * field in bits [11:8] must be 1 or 2. + */ + cp = (opcode >> 8) & 0xf; + if (cp != 1 && cp != 2) { + return 0; + } + qemufpa=qfpa; user_registers=qregs; From 2eea841c11096e8dcc457b80e21f3fbdc32d2590 Mon Sep 17 00:00:00 2001 From: Peter Maydell Date: Thu, 11 Jan 2018 13:25:40 +0000 Subject: [PATCH 24/26] target/arm: Make disas_thumb2_insn() generate its own UNDEF exceptions Refactor disas_thumb2_insn() so that it generates the code for raising an UNDEF exception for invalid insns, rather than returning a flag which the caller must check to see if it needs to generate the UNDEF code. This brings the function in to line with the behaviour of disas_thumb_insn() and disas_arm_insn(). Signed-off-by: Peter Maydell Reviewed-by: Richard Henderson Message-id: 1513080506-17703-1-git-send-email-peter.maydell@linaro.org --- target/arm/translate.c | 23 ++++++++++------------- 1 file changed, 10 insertions(+), 13 deletions(-) diff --git a/target/arm/translate.c b/target/arm/translate.c index c690658493..781be1e219 100644 --- a/target/arm/translate.c +++ b/target/arm/translate.c @@ -9775,9 +9775,8 @@ gen_thumb2_data_op(DisasContext *s, int op, int conds, uint32_t shifter_out, return 0; } -/* Translate a 32-bit thumb instruction. Returns nonzero if the instruction - is not legal. */ -static int disas_thumb2_insn(DisasContext *s, uint32_t insn) +/* Translate a 32-bit thumb instruction. */ +static void disas_thumb2_insn(DisasContext *s, uint32_t insn) { uint32_t imm, shift, offset; uint32_t rd, rn, rm, rs; @@ -11016,16 +11015,16 @@ static int disas_thumb2_insn(DisasContext *s, uint32_t insn) /* UNPREDICTABLE, unallocated hint or * PLD/PLDW/PLI (literal) */ - return 0; + return; } if (op1 & 1) { - return 0; /* PLD/PLDW/PLI or unallocated hint */ + return; /* PLD/PLDW/PLI or unallocated hint */ } if ((op2 == 0) || ((op2 & 0x3c) == 0x30)) { - return 0; /* PLD/PLDW/PLI or unallocated hint */ + return; /* PLD/PLDW/PLI or unallocated hint */ } /* UNDEF space, or an UNPREDICTABLE */ - return 1; + goto illegal_op; } } memidx = get_mem_index(s); @@ -11151,9 +11150,10 @@ static int disas_thumb2_insn(DisasContext *s, uint32_t insn) default: goto illegal_op; } - return 0; + return; illegal_op: - return 1; + gen_exception_insn(s, 4, EXCP_UDEF, syn_uncategorized(), + default_exception_el(s)); } static void disas_thumb_insn(DisasContext *s, uint32_t insn) @@ -12275,10 +12275,7 @@ static void thumb_tr_translate_insn(DisasContextBase *dcbase, CPUState *cpu) if (is_16bit) { disas_thumb_insn(dc, insn); } else { - if (disas_thumb2_insn(dc, insn)) { - gen_exception_insn(dc, 4, EXCP_UDEF, syn_uncategorized(), - default_exception_el(dc)); - } + disas_thumb2_insn(dc, insn); } /* Advance the Thumb condexec condition. */ From f1945632b43e36bd9f3e0c2feb0e5b152be7ed91 Mon Sep 17 00:00:00 2001 From: Peter Maydell Date: Thu, 11 Jan 2018 13:25:40 +0000 Subject: [PATCH 25/26] hw/intc/arm_gicv3: Make reserved register addresses RAZ/WI The GICv3 specification says that reserved register addresses should RAZ/WI. This means we need to return MEMTX_OK, not MEMTX_ERROR, because now that we support generating external aborts the latter will cause an abort on new board models. Cc: qemu-stable@nongnu.org Signed-off-by: Peter Maydell Message-id: 1513183941-24300-2-git-send-email-peter.maydell@linaro.org Reviewed-by: Alistair Francis --- hw/intc/arm_gicv3_dist.c | 13 +++++++++++++ hw/intc/arm_gicv3_its_common.c | 8 +++----- hw/intc/arm_gicv3_redist.c | 13 +++++++++++++ 3 files changed, 29 insertions(+), 5 deletions(-) diff --git a/hw/intc/arm_gicv3_dist.c b/hw/intc/arm_gicv3_dist.c index 3ea3dd0d40..93fe936862 100644 --- a/hw/intc/arm_gicv3_dist.c +++ b/hw/intc/arm_gicv3_dist.c @@ -817,6 +817,13 @@ MemTxResult gicv3_dist_read(void *opaque, hwaddr offset, uint64_t *data, "%s: invalid guest read at offset " TARGET_FMT_plx "size %u\n", __func__, offset, size); trace_gicv3_dist_badread(offset, size, attrs.secure); + /* The spec requires that reserved registers are RAZ/WI; + * so use MEMTX_ERROR returns from leaf functions as a way to + * trigger the guest-error logging but don't return it to + * the caller, or we'll cause a spurious guest data abort. + */ + r = MEMTX_OK; + *data = 0; } else { trace_gicv3_dist_read(offset, *data, size, attrs.secure); } @@ -852,6 +859,12 @@ MemTxResult gicv3_dist_write(void *opaque, hwaddr offset, uint64_t data, "%s: invalid guest write at offset " TARGET_FMT_plx "size %u\n", __func__, offset, size); trace_gicv3_dist_badwrite(offset, data, size, attrs.secure); + /* The spec requires that reserved registers are RAZ/WI; + * so use MEMTX_ERROR returns from leaf functions as a way to + * trigger the guest-error logging but don't return it to + * the caller, or we'll cause a spurious guest data abort. + */ + r = MEMTX_OK; } else { trace_gicv3_dist_write(offset, data, size, attrs.secure); } diff --git a/hw/intc/arm_gicv3_its_common.c b/hw/intc/arm_gicv3_its_common.c index 2bd2f0f3c9..284c0a7584 100644 --- a/hw/intc/arm_gicv3_its_common.c +++ b/hw/intc/arm_gicv3_its_common.c @@ -67,7 +67,8 @@ static MemTxResult gicv3_its_trans_read(void *opaque, hwaddr offset, MemTxAttrs attrs) { qemu_log_mask(LOG_GUEST_ERROR, "ITS read at offset 0x%"PRIx64"\n", offset); - return MEMTX_ERROR; + *data = 0; + return MEMTX_OK; } static MemTxResult gicv3_its_trans_write(void *opaque, hwaddr offset, @@ -82,15 +83,12 @@ static MemTxResult gicv3_its_trans_write(void *opaque, hwaddr offset, if (ret <= 0) { qemu_log_mask(LOG_GUEST_ERROR, "ITS: Error sending MSI: %s\n", strerror(-ret)); - return MEMTX_DECODE_ERROR; } - - return MEMTX_OK; } else { qemu_log_mask(LOG_GUEST_ERROR, "ITS write at bad offset 0x%"PRIx64"\n", offset); - return MEMTX_DECODE_ERROR; } + return MEMTX_OK; } static const MemoryRegionOps gicv3_its_trans_ops = { diff --git a/hw/intc/arm_gicv3_redist.c b/hw/intc/arm_gicv3_redist.c index 77e5cfa327..8a8684d76e 100644 --- a/hw/intc/arm_gicv3_redist.c +++ b/hw/intc/arm_gicv3_redist.c @@ -455,6 +455,13 @@ MemTxResult gicv3_redist_read(void *opaque, hwaddr offset, uint64_t *data, "size %u\n", __func__, offset, size); trace_gicv3_redist_badread(gicv3_redist_affid(cs), offset, size, attrs.secure); + /* The spec requires that reserved registers are RAZ/WI; + * so use MEMTX_ERROR returns from leaf functions as a way to + * trigger the guest-error logging but don't return it to + * the caller, or we'll cause a spurious guest data abort. + */ + r = MEMTX_OK; + *data = 0; } else { trace_gicv3_redist_read(gicv3_redist_affid(cs), offset, *data, size, attrs.secure); @@ -505,6 +512,12 @@ MemTxResult gicv3_redist_write(void *opaque, hwaddr offset, uint64_t data, "size %u\n", __func__, offset, size); trace_gicv3_redist_badwrite(gicv3_redist_affid(cs), offset, data, size, attrs.secure); + /* The spec requires that reserved registers are RAZ/WI; + * so use MEMTX_ERROR returns from leaf functions as a way to + * trigger the guest-error logging but don't return it to + * the caller, or we'll cause a spurious guest data abort. + */ + r = MEMTX_OK; } else { trace_gicv3_redist_write(gicv3_redist_affid(cs), offset, data, size, attrs.secure); From 0cf09852015e47a5fbb974ff7ac320366afd21ee Mon Sep 17 00:00:00 2001 From: Peter Maydell Date: Thu, 11 Jan 2018 13:25:40 +0000 Subject: [PATCH 26/26] hw/intc/arm_gic: reserved register addresses are RAZ/WI The GICv2 specification says that reserved register addresses must RAZ/WI; now that we implement external abort handling for Arm CPUs this means we must return MEMTX_OK rather than MEMTX_ERROR, to avoid generating a spurious guest data abort. Cc: qemu-stable@nongnu.org Signed-off-by: Peter Maydell Message-id: 1513183941-24300-3-git-send-email-peter.maydell@linaro.org Reviewed-by: Alistair Francis --- hw/intc/arm_gic.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/hw/intc/arm_gic.c b/hw/intc/arm_gic.c index 5a0e2a3c1a..d701e49ff9 100644 --- a/hw/intc/arm_gic.c +++ b/hw/intc/arm_gic.c @@ -1261,7 +1261,8 @@ static MemTxResult gic_cpu_read(GICState *s, int cpu, int offset, default: qemu_log_mask(LOG_GUEST_ERROR, "gic_cpu_read: Bad offset %x\n", (int)offset); - return MEMTX_ERROR; + *data = 0; + break; } return MEMTX_OK; } @@ -1329,7 +1330,7 @@ static MemTxResult gic_cpu_write(GICState *s, int cpu, int offset, default: qemu_log_mask(LOG_GUEST_ERROR, "gic_cpu_write: Bad offset %x\n", (int)offset); - return MEMTX_ERROR; + return MEMTX_OK; } gic_update(s); return MEMTX_OK;