From 4d027afeb3a9781bf15ad30d43d07a02c2b08c73 Mon Sep 17 00:00:00 2001 From: Zhaoshenglong Date: Thu, 11 Jan 2018 13:25:34 +0000 Subject: 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(-) (limited to 'hw') diff --git a/hw/arm/virt-acpi-build.c b/hw/arm/virt-acpi-build.c index 3d78ff6..f7fa795 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 */ -- cgit v1.1 From 1fdde6537ecec4a6b416bc232c868b64d645cc62 Mon Sep 17 00:00:00 2001 From: Andrey Smirnov Date: Thu, 11 Jan 2018 13:25:34 +0000 Subject: 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(-) (limited to 'hw') diff --git a/hw/arm/fsl-imx6.c b/hw/arm/fsl-imx6.c index 59ef33e..b0d4088 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 90e6ee3..88b4b04 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); -- cgit v1.1 From a6383e99ffc3b615d8465aebbd5d48f1fa9b2949 Mon Sep 17 00:00:00 2001 From: Andrey Smirnov Date: Thu, 11 Jan 2018 13:25:35 +0000 Subject: 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(-) (limited to 'hw') diff --git a/hw/net/imx_fec.c b/hw/net/imx_fec.c index 88b4b04..8b2e4b8 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) -- cgit v1.1 From b2b012afdd9c03ba8a1619f45301d34f358d367b Mon Sep 17 00:00:00 2001 From: Andrey Smirnov Date: Thu, 11 Jan 2018 13:25:35 +0000 Subject: 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(-) (limited to 'hw') diff --git a/hw/net/imx_fec.c b/hw/net/imx_fec.c index 8b2e4b8..eb034ff 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; } -- cgit v1.1 From 7bac20dc5111963083686743dee00e0ae4fd976b Mon Sep 17 00:00:00 2001 From: Andrey Smirnov Date: Thu, 11 Jan 2018 13:25:35 +0000 Subject: 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 +++++++++++----------- 1 file changed, 11 insertions(+), 11 deletions(-) (limited to 'hw') diff --git a/hw/net/imx_fec.c b/hw/net/imx_fec.c index eb034ff..56cb722 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; -- cgit v1.1 From ff9a7feeab59323d70a9377e9196f042b0647d66 Mon Sep 17 00:00:00 2001 From: Andrey Smirnov Date: Thu, 11 Jan 2018 13:25:36 +0000 Subject: 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 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'hw') diff --git a/hw/net/imx_fec.c b/hw/net/imx_fec.c index 56cb722..50da91b 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; } -- cgit v1.1 From 4c5e7a6cdae78ed823042375824ced09cccefbdb Mon Sep 17 00:00:00 2001 From: Andrey Smirnov Date: Thu, 11 Jan 2018 13:25:36 +0000 Subject: 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(-) (limited to 'hw') diff --git a/hw/net/imx_fec.c b/hw/net/imx_fec.c index 50da91b..6feda18 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; -- cgit v1.1 From ebdd8cddb9e657ef75024b4cc9057dd4ce397a55 Mon Sep 17 00:00:00 2001 From: Andrey Smirnov Date: Thu, 11 Jan 2018 13:25:37 +0000 Subject: 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 +++++++++++++++++++++++ 1 file changed, 23 insertions(+) (limited to 'hw') diff --git a/hw/net/imx_fec.c b/hw/net/imx_fec.c index 6feda18..825c879 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) { -- cgit v1.1 From f93f961c40a31228e3f66e66d99a68937aa242c5 Mon Sep 17 00:00:00 2001 From: Andrey Smirnov Date: Thu, 11 Jan 2018 13:25:37 +0000 Subject: 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 +++++++++++++++++++++++++++++++++++++++++++++++-------- 1 file changed, 114 insertions(+), 19 deletions(-) (limited to 'hw') diff --git a/hw/net/imx_fec.c b/hw/net/imx_fec.c index 825c879..77d27f7 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(), }; -- cgit v1.1 From 52cfd5846b8979805077ce7608aa36c18a2a9f32 Mon Sep 17 00:00:00 2001 From: Andrey Smirnov Date: Thu, 11 Jan 2018 13:25:37 +0000 Subject: 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(-) (limited to 'hw') diff --git a/hw/net/imx_fec.c b/hw/net/imx_fec.c index 77d27f7..6cb9e2e 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; -- cgit v1.1 From 894d74cc4f2fa577765bae711b9dc9ac9309521e Mon Sep 17 00:00:00 2001 From: Andrey Smirnov Date: Thu, 11 Jan 2018 13:25:38 +0000 Subject: 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(-) (limited to 'hw') diff --git a/hw/net/imx_fec.c b/hw/net/imx_fec.c index 6cb9e2e..c1cf7f9 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; -- cgit v1.1 From 831858ad9da7eccf4c260c60ed56cff0f1666424 Mon Sep 17 00:00:00 2001 From: Andrey Smirnov Date: Thu, 11 Jan 2018 13:25:38 +0000 Subject: 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 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'hw') diff --git a/hw/net/imx_fec.c b/hw/net/imx_fec.c index c1cf7f9..4fb48f6 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]); -- cgit v1.1 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: 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(-) (limited to 'hw') diff --git a/hw/timer/pxa2xx_timer.c b/hw/timer/pxa2xx_timer.c index 68ba5a7..a489bf5 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); } } -- cgit v1.1 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: 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(-) (limited to 'hw') diff --git a/hw/sd/pxa2xx_mmci.c b/hw/sd/pxa2xx_mmci.c index 3deccf0..82f8ec0 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 1fc0bcf..6eca347 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" -- cgit v1.1 From f1945632b43e36bd9f3e0c2feb0e5b152be7ed91 Mon Sep 17 00:00:00 2001 From: Peter Maydell Date: Thu, 11 Jan 2018 13:25:40 +0000 Subject: 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(-) (limited to 'hw') diff --git a/hw/intc/arm_gicv3_dist.c b/hw/intc/arm_gicv3_dist.c index 3ea3dd0..93fe936 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 2bd2f0f..284c0a7 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 77e5cfa..8a8684d 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); -- cgit v1.1 From 0cf09852015e47a5fbb974ff7ac320366afd21ee Mon Sep 17 00:00:00 2001 From: Peter Maydell Date: Thu, 11 Jan 2018 13:25:40 +0000 Subject: 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(-) (limited to 'hw') diff --git a/hw/intc/arm_gic.c b/hw/intc/arm_gic.c index 5a0e2a3..d701e49 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; -- cgit v1.1