diff options
author | Peter Maydell <peter.maydell@linaro.org> | 2018-01-16 14:18:20 +0000 |
---|---|---|
committer | Peter Maydell <peter.maydell@linaro.org> | 2018-01-16 14:18:20 +0000 |
commit | aae39d24a387a273deab3eb930dbf730aa379e22 (patch) | |
tree | 271be0e66c2ee70a42a16a39e0a6326c2c6aab13 | |
parent | f521eeee3bd060b460c99e605472b7e03967db43 (diff) | |
parent | 60765b6ceeb4998a0d4220b3a53f1f185061da77 (diff) |
Merge remote-tracking branch 'remotes/pmaydell/tags/pull-target-arm-20180116' into staging
target-arm queue:
* SDHCI: cleanups and minor bug fixes
* target/arm: minor refactor preparatory to fp16 support
* omap_ssd, ssi-sd, pl181, milkymist-memcard: reset the SD
card on controller reset (fixes migration failures)
* target/arm: Handle page table walk load failures correctly
* hw/arm/virt: Add virt-2.12 machine type
* get_phys_addr_pmsav7: Support AP=0b111 for v7M
* hw/intc/armv7m: Support byte and halfword accesses to CFSR
# gpg: Signature made Tue 16 Jan 2018 13:33:31 GMT
# gpg: using RSA key 0x3C2525ED14360CDE
# gpg: Good signature from "Peter Maydell <peter.maydell@linaro.org>"
# gpg: aka "Peter Maydell <pmaydell@gmail.com>"
# gpg: aka "Peter Maydell <pmaydell@chiark.greenend.org.uk>"
# Primary key fingerprint: E1A5 C593 CD41 9DE2 8E83 15CF 3C25 25ED 1436 0CDE
* remotes/pmaydell/tags/pull-target-arm-20180116: (24 commits)
sdhci: add a 'dma' property to the sysbus devices
sdhci: fix the PCI device, using the PCI address space for DMA
sdhci: Implement write method of ACMD12ERRSTS register
sdhci: fix CAPAB/MAXCURR registers, both are 64bit and read-only
sdhci: rename the SDHC_CAPAB register
sdhci: move MASK_TRNMOD with other SDHC_TRN* defines in "sd-internal.h"
sdhci: convert the DPRINT() calls into trace events
sdhci: use qemu_log_mask(UNIMP) instead of fprintf()
sdhci: refactor common sysbus/pci unrealize() into sdhci_common_unrealize()
sdhci: refactor common sysbus/pci realize() into sdhci_common_realize()
sdhci: refactor common sysbus/pci class_init() into sdhci_common_class_init()
sdhci: use DEFINE_SDHCI_COMMON_PROPERTIES() for common sysbus/pci properties
sdhci: remove dead code
sdhci: clean up includes
target/arm: Add fp16 support to vfp_expand_imm
target/arm: Split out vfp_expand_imm
hw/sd/omap_mmc: Reset SD card on controller reset
hw/sd/ssi-sd: Reset SD card on controller reset
hw/sd/milkymist-memcard: Reset SD card on controller reset
hw/sd/pl181: Reset SD card on controller reset
...
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
-rw-r--r-- | hw/arm/virt.c | 19 | ||||
-rw-r--r-- | hw/intc/armv7m_nvic.c | 38 | ||||
-rw-r--r-- | hw/sd/milkymist-memcard.c | 4 | ||||
-rw-r--r-- | hw/sd/omap_mmc.c | 14 | ||||
-rw-r--r-- | hw/sd/pl181.c | 4 | ||||
-rw-r--r-- | hw/sd/sdhci-internal.h | 7 | ||||
-rw-r--r-- | hw/sd/sdhci.c | 266 | ||||
-rw-r--r-- | hw/sd/ssi-sd.c | 25 | ||||
-rw-r--r-- | hw/sd/trace-events | 14 | ||||
-rw-r--r-- | include/hw/sd/sdhci.h | 19 | ||||
-rw-r--r-- | target/arm/helper.c | 53 | ||||
-rw-r--r-- | target/arm/internals.h | 10 | ||||
-rw-r--r-- | target/arm/op_helper.c | 7 | ||||
-rw-r--r-- | target/arm/translate-a64.c | 49 |
14 files changed, 362 insertions, 167 deletions
diff --git a/hw/arm/virt.c b/hw/arm/virt.c index 151592b1e5..543f9bd6cc 100644 --- a/hw/arm/virt.c +++ b/hw/arm/virt.c @@ -1618,7 +1618,7 @@ static void machvirt_machine_init(void) } type_init(machvirt_machine_init); -static void virt_2_11_instance_init(Object *obj) +static void virt_2_12_instance_init(Object *obj) { VirtMachineState *vms = VIRT_MACHINE(obj); VirtMachineClass *vmc = VIRT_MACHINE_GET_CLASS(vms); @@ -1678,10 +1678,25 @@ static void virt_2_11_instance_init(Object *obj) vms->irqmap = a15irqmap; } +static void virt_machine_2_12_options(MachineClass *mc) +{ +} +DEFINE_VIRT_MACHINE_AS_LATEST(2, 12) + +#define VIRT_COMPAT_2_11 \ + HW_COMPAT_2_11 + +static void virt_2_11_instance_init(Object *obj) +{ + virt_2_12_instance_init(obj); +} + static void virt_machine_2_11_options(MachineClass *mc) { + virt_machine_2_12_options(mc); + SET_MACHINE_COMPAT(mc, VIRT_COMPAT_2_11); } -DEFINE_VIRT_MACHINE_AS_LATEST(2, 11) +DEFINE_VIRT_MACHINE(2, 11) #define VIRT_COMPAT_2_10 \ HW_COMPAT_2_10 diff --git a/hw/intc/armv7m_nvic.c b/hw/intc/armv7m_nvic.c index dd49b6c335..8ca6ceeb9b 100644 --- a/hw/intc/armv7m_nvic.c +++ b/hw/intc/armv7m_nvic.c @@ -896,13 +896,6 @@ static uint32_t nvic_readl(NVICState *s, uint32_t offset, MemTxAttrs attrs) val |= (1 << 8); } return val; - case 0xd28: /* Configurable Fault Status. */ - /* The BFSR bits [15:8] are shared between security states - * and we store them in the NS copy - */ - val = cpu->env.v7m.cfsr[attrs.secure]; - val |= cpu->env.v7m.cfsr[M_REG_NS] & R_V7M_CFSR_BFSR_MASK; - return val; case 0xd2c: /* Hard Fault Status. */ return cpu->env.v7m.hfsr; case 0xd30: /* Debug Fault Status. */ @@ -1280,15 +1273,6 @@ static void nvic_writel(NVICState *s, uint32_t offset, uint32_t value, s->vectors[ARMV7M_EXCP_DEBUG].active = (value & (1 << 8)) != 0; nvic_irq_update(s); break; - case 0xd28: /* Configurable Fault Status. */ - cpu->env.v7m.cfsr[attrs.secure] &= ~value; /* W1C */ - if (attrs.secure) { - /* The BFSR bits [15:8] are shared between security states - * and we store them in the NS copy. - */ - cpu->env.v7m.cfsr[M_REG_NS] &= ~(value & R_V7M_CFSR_BFSR_MASK); - } - break; case 0xd2c: /* Hard Fault Status. */ cpu->env.v7m.hfsr &= ~value; /* W1C */ break; @@ -1667,6 +1651,14 @@ static MemTxResult nvic_sysreg_read(void *opaque, hwaddr addr, val = deposit32(val, i * 8, 8, get_prio(s, hdlidx, sbank)); } break; + case 0xd28 ... 0xd2b: /* Configurable Fault Status (CFSR) */ + /* The BFSR bits [15:8] are shared between security states + * and we store them in the NS copy + */ + val = s->cpu->env.v7m.cfsr[attrs.secure]; + val |= s->cpu->env.v7m.cfsr[M_REG_NS] & R_V7M_CFSR_BFSR_MASK; + val = extract32(val, (offset - 0xd28) * 8, size * 8); + break; case 0xfe0 ... 0xfff: /* ID. */ if (offset & 3) { val = 0; @@ -1765,6 +1757,20 @@ static MemTxResult nvic_sysreg_write(void *opaque, hwaddr addr, } nvic_irq_update(s); return MEMTX_OK; + case 0xd28 ... 0xd2b: /* Configurable Fault Status (CFSR) */ + /* All bits are W1C, so construct 32 bit value with 0s in + * the parts not written by the access size + */ + value <<= ((offset - 0xd28) * 8); + + s->cpu->env.v7m.cfsr[attrs.secure] &= ~value; + if (attrs.secure) { + /* The BFSR bits [15:8] are shared between security states + * and we store them in the NS copy. + */ + s->cpu->env.v7m.cfsr[M_REG_NS] &= ~(value & R_V7M_CFSR_BFSR_MASK); + } + return MEMTX_OK; } if (size == 4) { nvic_writel(s, offset, value, attrs); diff --git a/hw/sd/milkymist-memcard.c b/hw/sd/milkymist-memcard.c index 4008c81002..341da88552 100644 --- a/hw/sd/milkymist-memcard.c +++ b/hw/sd/milkymist-memcard.c @@ -248,6 +248,10 @@ static void milkymist_memcard_reset(DeviceState *d) for (i = 0; i < R_MAX; i++) { s->regs[i] = 0; } + /* Since we're still using the legacy SD API the card is not plugged + * into any bus, and we must reset it manually. + */ + device_reset(DEVICE(s->card)); } static int milkymist_memcard_init(SysBusDevice *dev) diff --git a/hw/sd/omap_mmc.c b/hw/sd/omap_mmc.c index e934cd3656..5b47cadf11 100644 --- a/hw/sd/omap_mmc.c +++ b/hw/sd/omap_mmc.c @@ -305,6 +305,12 @@ void omap_mmc_reset(struct omap_mmc_s *host) host->cdet_enable = 0; qemu_set_irq(host->coverswitch, host->cdet_state); host->clkdiv = 0; + + /* Since we're still using the legacy SD API the card is not plugged + * into any bus, and we must reset it manually. When omap_mmc is + * QOMified this must move into the QOM reset function. + */ + device_reset(DEVICE(host->card)); } static uint64_t omap_mmc_read(void *opaque, hwaddr offset, @@ -587,8 +593,6 @@ struct omap_mmc_s *omap_mmc_init(hwaddr base, s->lines = 1; /* TODO: needs to be settable per-board */ s->rev = 1; - omap_mmc_reset(s); - memory_region_init_io(&s->iomem, NULL, &omap_mmc_ops, s, "omap.mmc", 0x800); memory_region_add_subregion(sysmem, base, &s->iomem); @@ -598,6 +602,8 @@ struct omap_mmc_s *omap_mmc_init(hwaddr base, exit(1); } + omap_mmc_reset(s); + return s; } @@ -613,8 +619,6 @@ struct omap_mmc_s *omap2_mmc_init(struct omap_target_agent_s *ta, s->lines = 4; s->rev = 2; - omap_mmc_reset(s); - memory_region_init_io(&s->iomem, NULL, &omap_mmc_ops, s, "omap.mmc", omap_l4_region_size(ta, 0)); omap_l4_attach(ta, 0, &s->iomem); @@ -628,6 +632,8 @@ struct omap_mmc_s *omap2_mmc_init(struct omap_target_agent_s *ta, s->cdet = qemu_allocate_irq(omap_mmc_cover_cb, s, 0); sd_set_cb(s->card, NULL, s->cdet); + omap_mmc_reset(s); + return s; } diff --git a/hw/sd/pl181.c b/hw/sd/pl181.c index 55c8098ecd..3ba1f7dd23 100644 --- a/hw/sd/pl181.c +++ b/hw/sd/pl181.c @@ -480,6 +480,10 @@ static void pl181_reset(DeviceState *d) /* We can assume our GPIO outputs have been wired up now */ sd_set_cb(s->card, s->cardstatus[0], s->cardstatus[1]); + /* Since we're still using the legacy SD API the card is not plugged + * into any bus, and we must reset it manually. + */ + device_reset(DEVICE(s->card)); } static void pl181_init(Object *obj) diff --git a/hw/sd/sdhci-internal.h b/hw/sd/sdhci-internal.h index 161177cf39..fc807f08f3 100644 --- a/hw/sd/sdhci-internal.h +++ b/hw/sd/sdhci-internal.h @@ -24,8 +24,6 @@ #ifndef SDHCI_INTERNAL_H #define SDHCI_INTERNAL_H -#include "hw/sd/sdhci.h" - /* R/W SDMA System Address register 0x0 */ #define SDHC_SYSAD 0x00 @@ -45,6 +43,7 @@ #define SDHC_TRNS_ACMD12 0x0004 #define SDHC_TRNS_READ 0x0010 #define SDHC_TRNS_MULTI 0x0020 +#define SDHC_TRNMOD_MASK 0x0037 /* R/W Command Register 0x0 */ #define SDHC_CMDREG 0x0E @@ -175,7 +174,7 @@ #define SDHC_ACMD12ERRSTS 0x3C /* HWInit Capabilities Register 0x05E80080 */ -#define SDHC_CAPAREG 0x40 +#define SDHC_CAPAB 0x40 #define SDHC_CAN_DO_DMA 0x00400000 #define SDHC_CAN_DO_ADMA2 0x00080000 #define SDHC_CAN_DO_ADMA1 0x00100000 @@ -227,6 +226,4 @@ enum { sdhc_gap_write = 2 /* SDHC stopped at block gap during write operation */ }; -extern const VMStateDescription sdhci_vmstate; - #endif diff --git a/hw/sd/sdhci.c b/hw/sd/sdhci.c index b064a087c9..f9264d3be5 100644 --- a/hw/sd/sdhci.c +++ b/hw/sd/sdhci.c @@ -23,38 +23,18 @@ */ #include "qemu/osdep.h" +#include "qapi/error.h" #include "hw/hw.h" #include "sysemu/block-backend.h" #include "sysemu/blockdev.h" #include "sysemu/dma.h" #include "qemu/timer.h" #include "qemu/bitops.h" +#include "hw/sd/sdhci.h" #include "sdhci-internal.h" +#include "qapi/error.h" #include "qemu/log.h" - -/* host controller debug messages */ -#ifndef SDHC_DEBUG -#define SDHC_DEBUG 0 -#endif - -#define DPRINT_L1(fmt, args...) \ - do { \ - if (SDHC_DEBUG) { \ - fprintf(stderr, "QEMU SDHC: " fmt, ## args); \ - } \ - } while (0) -#define DPRINT_L2(fmt, args...) \ - do { \ - if (SDHC_DEBUG > 1) { \ - fprintf(stderr, "QEMU SDHC: " fmt, ## args); \ - } \ - } while (0) -#define ERRPRINT(fmt, args...) \ - do { \ - if (SDHC_DEBUG) { \ - fprintf(stderr, "QEMU SDHC ERROR: " fmt, ## args); \ - } \ - } while (0) +#include "trace.h" #define TYPE_SDHCI_BUS "sdhci-bus" #define SDHCI_BUS(obj) OBJECT_CHECK(SDBus, (obj), TYPE_SDHCI_BUS) @@ -119,7 +99,6 @@ (SDHC_CAPAB_BASECLKFREQ << 8) | (SDHC_CAPAB_TOUNIT << 7) | \ (SDHC_CAPAB_TOCLKFREQ)) -#define MASK_TRNMOD 0x0037 #define MASKED_WRITE(reg, mask, val) (reg = (reg & (mask)) | (val)) static uint8_t sdhci_slotint(SDHCIState *s) @@ -153,8 +132,8 @@ static void sdhci_raise_insertion_irq(void *opaque) static void sdhci_set_inserted(DeviceState *dev, bool level) { SDHCIState *s = (SDHCIState *)dev; - DPRINT_L1("Card state changed: %s!\n", level ? "insert" : "eject"); + trace_sdhci_set_inserted(level ? "insert" : "eject"); if ((s->norintsts & SDHC_NIS_REMOVE) && level) { /* Give target some time to notice card ejection */ timer_mod(s->insert_timer, @@ -236,7 +215,8 @@ static void sdhci_send_command(SDHCIState *s) s->acmd12errsts = 0; request.cmd = s->cmdreg >> 8; request.arg = s->argument; - DPRINT_L1("sending CMD%u ARG[0x%08x]\n", request.cmd, request.arg); + + trace_sdhci_send_command(request.cmd, request.arg); rlen = sdbus_do_command(&s->sdbus, &request, response); if (s->cmdreg & SDHC_CMD_RESPONSE) { @@ -244,7 +224,7 @@ static void sdhci_send_command(SDHCIState *s) s->rspreg[0] = (response[0] << 24) | (response[1] << 16) | (response[2] << 8) | response[3]; s->rspreg[1] = s->rspreg[2] = s->rspreg[3] = 0; - DPRINT_L1("Response: RSPREG[31..0]=0x%08x\n", s->rspreg[0]); + trace_sdhci_response4(s->rspreg[0]); } else if (rlen == 16) { s->rspreg[0] = (response[11] << 24) | (response[12] << 16) | (response[13] << 8) | response[14]; @@ -254,11 +234,10 @@ static void sdhci_send_command(SDHCIState *s) (response[5] << 8) | response[6]; s->rspreg[3] = (response[0] << 16) | (response[1] << 8) | response[2]; - DPRINT_L1("Response received:\n RSPREG[127..96]=0x%08x, RSPREG[95.." - "64]=0x%08x,\n RSPREG[63..32]=0x%08x, RSPREG[31..0]=0x%08x\n", - s->rspreg[3], s->rspreg[2], s->rspreg[1], s->rspreg[0]); + trace_sdhci_response16(s->rspreg[3], s->rspreg[2], + s->rspreg[1], s->rspreg[0]); } else { - ERRPRINT("Timeout waiting for command response\n"); + trace_sdhci_error("timeout waiting for command response"); if (s->errintstsen & SDHC_EISEN_CMDTIMEOUT) { s->errintsts |= SDHC_EIS_CMDTIMEOUT; s->norintsts |= SDHC_NIS_ERR; @@ -292,7 +271,7 @@ static void sdhci_end_transfer(SDHCIState *s) request.cmd = 0x0C; request.arg = 0; - DPRINT_L1("Automatically issue CMD%d %08x\n", request.cmd, request.arg); + trace_sdhci_end_transfer(request.cmd, request.arg); sdbus_do_command(&s->sdbus, &request, response); /* Auto CMD12 response goes to the upper Response register */ s->rspreg[3] = (response[0] << 24) | (response[1] << 16) | @@ -361,7 +340,7 @@ static uint32_t sdhci_read_dataport(SDHCIState *s, unsigned size) /* first check that a valid data exists in host controller input buffer */ if ((s->prnsts & SDHC_DATA_AVAILABLE) == 0) { - ERRPRINT("Trying to read from empty buffer\n"); + trace_sdhci_error("read from empty buffer"); return 0; } @@ -370,8 +349,7 @@ static uint32_t sdhci_read_dataport(SDHCIState *s, unsigned size) s->data_count++; /* check if we've read all valid data (blksize bytes) from buffer */ if ((s->data_count) >= (s->blksize & 0x0fff)) { - DPRINT_L2("All %u bytes of data have been read from input buffer\n", - s->data_count); + trace_sdhci_read_dataport(s->data_count); s->prnsts &= ~SDHC_DATA_AVAILABLE; /* no more data in a buffer */ s->data_count = 0; /* next buff read must start at position [0] */ @@ -454,7 +432,7 @@ static void sdhci_write_dataport(SDHCIState *s, uint32_t value, unsigned size) /* Check that there is free space left in a buffer */ if (!(s->prnsts & SDHC_SPACE_AVAILABLE)) { - ERRPRINT("Can't write to data buffer: buffer full\n"); + trace_sdhci_error("Can't write to data buffer: buffer full"); return; } @@ -463,8 +441,7 @@ static void sdhci_write_dataport(SDHCIState *s, uint32_t value, unsigned size) s->data_count++; value >>= 8; if (s->data_count >= (s->blksize & 0x0fff)) { - DPRINT_L2("write buffer filled with %u bytes of data\n", - s->data_count); + trace_sdhci_write_dataport(s->data_count); s->data_count = 0; s->prnsts &= ~SDHC_SPACE_AVAILABLE; if (s->prnsts & SDHC_DOING_WRITE) { @@ -519,7 +496,7 @@ static void sdhci_sdma_transfer_multi_blocks(SDHCIState *s) s->blkcnt--; } } - dma_memory_write(&address_space_memory, s->sdmasysad, + dma_memory_write(s->dma_as, s->sdmasysad, &s->fifo_buffer[begin], s->data_count - begin); s->sdmasysad += s->data_count - begin; if (s->data_count == block_size) { @@ -541,7 +518,7 @@ static void sdhci_sdma_transfer_multi_blocks(SDHCIState *s) s->data_count = block_size; boundary_count -= block_size - begin; } - dma_memory_read(&address_space_memory, s->sdmasysad, + dma_memory_read(s->dma_as, s->sdmasysad, &s->fifo_buffer[begin], s->data_count - begin); s->sdmasysad += s->data_count - begin; if (s->data_count == block_size) { @@ -579,11 +556,9 @@ static void sdhci_sdma_transfer_single_block(SDHCIState *s) for (n = 0; n < datacnt; n++) { s->fifo_buffer[n] = sdbus_read_data(&s->sdbus); } - dma_memory_write(&address_space_memory, s->sdmasysad, s->fifo_buffer, - datacnt); + dma_memory_write(s->dma_as, s->sdmasysad, s->fifo_buffer, datacnt); } else { - dma_memory_read(&address_space_memory, s->sdmasysad, s->fifo_buffer, - datacnt); + dma_memory_read(s->dma_as, s->sdmasysad, s->fifo_buffer, datacnt); for (n = 0; n < datacnt; n++) { sdbus_write_data(&s->sdbus, s->fifo_buffer[n]); } @@ -607,7 +582,7 @@ static void get_adma_description(SDHCIState *s, ADMADescr *dscr) hwaddr entry_addr = (hwaddr)s->admasysaddr; switch (SDHC_DMA_TYPE(s->hostctl)) { case SDHC_CTRL_ADMA2_32: - dma_memory_read(&address_space_memory, entry_addr, (uint8_t *)&adma2, + dma_memory_read(s->dma_as, entry_addr, (uint8_t *)&adma2, sizeof(adma2)); adma2 = le64_to_cpu(adma2); /* The spec does not specify endianness of descriptor table. @@ -619,7 +594,7 @@ static void get_adma_description(SDHCIState *s, ADMADescr *dscr) dscr->incr = 8; break; case SDHC_CTRL_ADMA1_32: - dma_memory_read(&address_space_memory, entry_addr, (uint8_t *)&adma1, + dma_memory_read(s->dma_as, entry_addr, (uint8_t *)&adma1, sizeof(adma1)); adma1 = le32_to_cpu(adma1); dscr->addr = (hwaddr)(adma1 & 0xFFFFF000); @@ -632,12 +607,12 @@ static void get_adma_description(SDHCIState *s, ADMADescr *dscr) } break; case SDHC_CTRL_ADMA2_64: - dma_memory_read(&address_space_memory, entry_addr, + dma_memory_read(s->dma_as, entry_addr, (uint8_t *)(&dscr->attr), 1); - dma_memory_read(&address_space_memory, entry_addr + 2, + dma_memory_read(s->dma_as, entry_addr + 2, (uint8_t *)(&dscr->length), 2); dscr->length = le16_to_cpu(dscr->length); - dma_memory_read(&address_space_memory, entry_addr + 4, + dma_memory_read(s->dma_as, entry_addr + 4, (uint8_t *)(&dscr->addr), 8); dscr->attr = le64_to_cpu(dscr->attr); dscr->attr &= 0xfffffff8; @@ -652,15 +627,14 @@ static void sdhci_do_adma(SDHCIState *s) { unsigned int n, begin, length; const uint16_t block_size = s->blksize & 0x0fff; - ADMADescr dscr; + ADMADescr dscr = {}; int i; for (i = 0; i < SDHC_ADMA_DESCS_PER_DELAY; ++i) { s->admaerr &= ~SDHC_ADMAERR_LENGTH_MISMATCH; get_adma_description(s, &dscr); - DPRINT_L2("ADMA loop: addr=" TARGET_FMT_plx ", len=%d, attr=%x\n", - dscr.addr, dscr.length, dscr.attr); + trace_sdhci_adma_loop(dscr.addr, dscr.length, dscr.attr); if ((dscr.attr & SDHC_ADMA_ATTR_VALID) == 0) { /* Indicate that error occurred in ST_FDS state */ @@ -697,7 +671,7 @@ static void sdhci_do_adma(SDHCIState *s) s->data_count = block_size; length -= block_size - begin; } - dma_memory_write(&address_space_memory, dscr.addr, + dma_memory_write(s->dma_as, dscr.addr, &s->fifo_buffer[begin], s->data_count - begin); dscr.addr += s->data_count - begin; @@ -721,7 +695,7 @@ static void sdhci_do_adma(SDHCIState *s) s->data_count = block_size; length -= block_size - begin; } - dma_memory_read(&address_space_memory, dscr.addr, + dma_memory_read(s->dma_as, dscr.addr, &s->fifo_buffer[begin], s->data_count - begin); dscr.addr += s->data_count - begin; @@ -743,8 +717,7 @@ static void sdhci_do_adma(SDHCIState *s) break; case SDHC_ADMA_ATTR_ACT_LINK: /* link to next descriptor table */ s->admasysaddr = dscr.addr; - DPRINT_L1("ADMA link: admasysaddr=0x%" PRIx64 "\n", - s->admasysaddr); + trace_sdhci_adma("link", s->admasysaddr); break; default: s->admasysaddr += dscr.incr; @@ -752,8 +725,7 @@ static void sdhci_do_adma(SDHCIState *s) } if (dscr.attr & SDHC_ADMA_ATTR_INT) { - DPRINT_L1("ADMA interrupt: admasysaddr=0x%" PRIx64 "\n", - s->admasysaddr); + trace_sdhci_adma("interrupt", s->admasysaddr); if (s->norintstsen & SDHC_NISEN_DMA) { s->norintsts |= SDHC_NIS_DMA; } @@ -764,15 +736,15 @@ static void sdhci_do_adma(SDHCIState *s) /* ADMA transfer terminates if blkcnt == 0 or by END attribute */ if (((s->trnmod & SDHC_TRNS_BLK_CNT_EN) && (s->blkcnt == 0)) || (dscr.attr & SDHC_ADMA_ATTR_END)) { - DPRINT_L2("ADMA transfer completed\n"); + trace_sdhci_adma_transfer_completed(); if (length || ((dscr.attr & SDHC_ADMA_ATTR_END) && (s->trnmod & SDHC_TRNS_BLK_CNT_EN) && s->blkcnt != 0)) { - ERRPRINT("SD/MMC host ADMA length mismatch\n"); + trace_sdhci_error("SD/MMC host ADMA length mismatch"); s->admaerr |= SDHC_ADMAERR_LENGTH_MISMATCH | SDHC_ADMAERR_STATE_ST_TFR; if (s->errintstsen & SDHC_EISEN_ADMAERR) { - ERRPRINT("Set ADMA error flag\n"); + trace_sdhci_error("Set ADMA error flag"); s->errintsts |= SDHC_EIS_ADMAERR; s->norintsts |= SDHC_NIS_ERR; } @@ -808,7 +780,7 @@ static void sdhci_data_transfer(void *opaque) break; case SDHC_CTRL_ADMA1_32: if (!(s->capareg & SDHC_CAN_DO_ADMA1)) { - ERRPRINT("ADMA1 not supported\n"); + trace_sdhci_error("ADMA1 not supported"); break; } @@ -816,7 +788,7 @@ static void sdhci_data_transfer(void *opaque) break; case SDHC_CTRL_ADMA2_32: if (!(s->capareg & SDHC_CAN_DO_ADMA2)) { - ERRPRINT("ADMA2 not supported\n"); + trace_sdhci_error("ADMA2 not supported"); break; } @@ -825,14 +797,14 @@ static void sdhci_data_transfer(void *opaque) case SDHC_CTRL_ADMA2_64: if (!(s->capareg & SDHC_CAN_DO_ADMA2) || !(s->capareg & SDHC_64_BIT_BUS_SUPPORT)) { - ERRPRINT("64 bit ADMA not supported\n"); + trace_sdhci_error("64 bit ADMA not supported"); break; } sdhci_do_adma(s); break; default: - ERRPRINT("Unsupported DMA type\n"); + trace_sdhci_error("Unsupported DMA type"); break; } } else { @@ -867,8 +839,8 @@ static inline bool sdhci_buff_access_is_sequential(SDHCIState *s, unsigned byte_num) { if ((s->data_count & 0x3) != byte_num) { - ERRPRINT("Non-sequential access to Buffer Data Port register" - "is prohibited\n"); + trace_sdhci_error("Non-sequential access to Buffer Data Port register" + "is prohibited\n"); return false; } return true; @@ -898,8 +870,7 @@ static uint64_t sdhci_read(void *opaque, hwaddr offset, unsigned size) case SDHC_BDATA: if (sdhci_buff_access_is_sequential(s, offset - SDHC_BDATA)) { ret = sdhci_read_dataport(s, size); - DPRINT_L2("read %ub: addr[0x%04x] -> %u(0x%x)\n", size, (int)offset, - ret, ret); + trace_sdhci_access("rd", size << 3, offset, "->", ret, ret); return ret; } break; @@ -925,11 +896,17 @@ static uint64_t sdhci_read(void *opaque, hwaddr offset, unsigned size) case SDHC_ACMD12ERRSTS: ret = s->acmd12errsts; break; - case SDHC_CAPAREG: - ret = s->capareg; + case SDHC_CAPAB: + ret = (uint32_t)s->capareg; + break; + case SDHC_CAPAB + 4: + ret = (uint32_t)(s->capareg >> 32); break; case SDHC_MAXCURR: - ret = s->maxcurr; + ret = (uint32_t)s->maxcurr; + break; + case SDHC_MAXCURR + 4: + ret = (uint32_t)(s->maxcurr >> 32); break; case SDHC_ADMAERR: ret = s->admaerr; @@ -944,13 +921,14 @@ static uint64_t sdhci_read(void *opaque, hwaddr offset, unsigned size) ret = (SD_HOST_SPECv2_VERS << 16) | sdhci_slotint(s); break; default: - ERRPRINT("bad %ub read: addr[0x%04x]\n", size, (int)offset); + qemu_log_mask(LOG_UNIMP, "SDHC rd_%ub @0x%02" HWADDR_PRIx " " + "not implemented\n", size, offset); break; } ret >>= (offset & 0x3) * 8; ret &= (1ULL << (size * 8)) - 1; - DPRINT_L2("read %ub: addr[0x%04x] -> %u(0x%x)\n", size, (int)offset, ret, ret); + trace_sdhci_access("rd", size << 3, offset, "->", ret, ret); return ret; } @@ -1051,7 +1029,7 @@ sdhci_write(void *opaque, hwaddr offset, uint64_t val, unsigned size) if (!(s->capareg & SDHC_CAN_DO_DMA)) { value &= ~SDHC_TRNS_DMA; } - MASKED_WRITE(s->trnmod, mask, value & MASK_TRNMOD); + MASKED_WRITE(s->trnmod, mask, value & SDHC_TRNMOD_MASK); MASKED_WRITE(s->cmdreg, mask >> 16, value >> 16); /* Writing to the upper byte of CMDREG triggers SD command generation */ @@ -1149,13 +1127,25 @@ sdhci_write(void *opaque, hwaddr offset, uint64_t val, unsigned size) } sdhci_update_irq(s); break; + case SDHC_ACMD12ERRSTS: + MASKED_WRITE(s->acmd12errsts, mask, value); + break; + + case SDHC_CAPAB: + case SDHC_CAPAB + 4: + case SDHC_MAXCURR: + case SDHC_MAXCURR + 4: + qemu_log_mask(LOG_GUEST_ERROR, "SDHC wr_%ub @0x%02" HWADDR_PRIx + " <- 0x%08x read-only\n", size, offset, value >> shift); + break; + default: - ERRPRINT("bad %ub write offset: addr[0x%04x] <- %u(0x%x)\n", - size, (int)offset, value >> shift, value >> shift); + qemu_log_mask(LOG_UNIMP, "SDHC wr_%ub @0x%02" HWADDR_PRIx " <- 0x%08x " + "not implemented\n", size, offset, value >> shift); break; } - DPRINT_L2("write %ub: addr[0x%04x] <- %u(0x%x)\n", - size, (int)offset, value >> shift, value >> shift); + trace_sdhci_access("wr", size << 3, offset, "<-", + value >> shift, value >> shift); } static const MemoryRegionOps sdhci_mmio_ops = { @@ -1184,6 +1174,14 @@ static inline unsigned int sdhci_get_fifolen(SDHCIState *s) } } +/* --- qdev common --- */ + +#define DEFINE_SDHCI_COMMON_PROPERTIES(_state) \ + /* Capabilities registers provide information on supported features + * of this specific host controller implementation */ \ + DEFINE_PROP_UINT64("capareg", _state, capareg, SDHC_CAPAB_REG_DEFAULT), \ + DEFINE_PROP_UINT64("maxcurr", _state, maxcurr, 0) + static void sdhci_initfn(SDHCIState *s) { qbus_create_inplace(&s->sdbus, sizeof(s->sdbus), @@ -1199,13 +1197,31 @@ static void sdhci_uninitfn(SDHCIState *s) timer_free(s->insert_timer); timer_del(s->transfer_timer); timer_free(s->transfer_timer); - qemu_free_irq(s->eject_cb); - qemu_free_irq(s->ro_cb); g_free(s->fifo_buffer); s->fifo_buffer = NULL; } +static void sdhci_common_realize(SDHCIState *s, Error **errp) +{ + s->buf_maxsz = sdhci_get_fifolen(s); + s->fifo_buffer = g_malloc0(s->buf_maxsz); + + memory_region_init_io(&s->iomem, OBJECT(s), &sdhci_mmio_ops, s, "sdhci", + SDHC_REGISTERS_MAP_SIZE); +} + +static void sdhci_common_unrealize(SDHCIState *s, Error **errp) +{ + /* This function is expected to be called only once for each class: + * - SysBus: via DeviceClass->unrealize(), + * - PCI: via PCIDeviceClass->exit(). + * However to avoid double-free and/or use-after-free we still nullify + * this variable (better safe than sorry!). */ + g_free(s->fifo_buffer); + s->fifo_buffer = NULL; +} + static bool sdhci_pending_insert_vmstate_needed(void *opaque) { SDHCIState *s = opaque; @@ -1265,32 +1281,44 @@ const VMStateDescription sdhci_vmstate = { }, }; -/* Capabilities registers provide information on supported features of this - * specific host controller implementation */ +static void sdhci_common_class_init(ObjectClass *klass, void *data) +{ + DeviceClass *dc = DEVICE_CLASS(klass); + + set_bit(DEVICE_CATEGORY_STORAGE, dc->categories); + dc->vmsd = &sdhci_vmstate; + dc->reset = sdhci_poweron_reset; +} + +/* --- qdev PCI --- */ + static Property sdhci_pci_properties[] = { - DEFINE_PROP_UINT32("capareg", SDHCIState, capareg, - SDHC_CAPAB_REG_DEFAULT), - DEFINE_PROP_UINT32("maxcurr", SDHCIState, maxcurr, 0), + DEFINE_SDHCI_COMMON_PROPERTIES(SDHCIState), DEFINE_PROP_END_OF_LIST(), }; static void sdhci_pci_realize(PCIDevice *dev, Error **errp) { SDHCIState *s = PCI_SDHCI(dev); + + sdhci_initfn(s); + sdhci_common_realize(s, errp); + if (errp && *errp) { + return; + } + dev->config[PCI_CLASS_PROG] = 0x01; /* Standard Host supported DMA */ dev->config[PCI_INTERRUPT_PIN] = 0x01; /* interrupt pin A */ - sdhci_initfn(s); - s->buf_maxsz = sdhci_get_fifolen(s); - s->fifo_buffer = g_malloc0(s->buf_maxsz); s->irq = pci_allocate_irq(dev); - memory_region_init_io(&s->iomem, OBJECT(s), &sdhci_mmio_ops, s, "sdhci", - SDHC_REGISTERS_MAP_SIZE); - pci_register_bar(dev, 0, 0, &s->iomem); + s->dma_as = pci_get_address_space(dev); + pci_register_bar(dev, 0, PCI_BASE_ADDRESS_SPACE_MEMORY, &s->iomem); } static void sdhci_pci_exit(PCIDevice *dev) { SDHCIState *s = PCI_SDHCI(dev); + + sdhci_common_unrealize(s, &error_abort); sdhci_uninitfn(s); } @@ -1304,10 +1332,9 @@ static void sdhci_pci_class_init(ObjectClass *klass, void *data) k->vendor_id = PCI_VENDOR_ID_REDHAT; k->device_id = PCI_DEVICE_ID_REDHAT_SDHCI; k->class_id = PCI_CLASS_SYSTEM_SDHCI; - set_bit(DEVICE_CATEGORY_STORAGE, dc->categories); - dc->vmsd = &sdhci_vmstate; dc->props = sdhci_pci_properties; - dc->reset = sdhci_poweron_reset; + + sdhci_common_class_init(klass, data); } static const TypeInfo sdhci_pci_info = { @@ -1321,12 +1348,14 @@ static const TypeInfo sdhci_pci_info = { }, }; +/* --- qdev SysBus --- */ + static Property sdhci_sysbus_properties[] = { - DEFINE_PROP_UINT32("capareg", SDHCIState, capareg, - SDHC_CAPAB_REG_DEFAULT), - DEFINE_PROP_UINT32("maxcurr", SDHCIState, maxcurr, 0), + DEFINE_SDHCI_COMMON_PROPERTIES(SDHCIState), DEFINE_PROP_BOOL("pending-insert-quirk", SDHCIState, pending_insert_quirk, false), + DEFINE_PROP_LINK("dma", SDHCIState, + dma_mr, TYPE_MEMORY_REGION, MemoryRegion *), DEFINE_PROP_END_OF_LIST(), }; @@ -1340,6 +1369,11 @@ static void sdhci_sysbus_init(Object *obj) static void sdhci_sysbus_finalize(Object *obj) { SDHCIState *s = SYSBUS_SDHCI(obj); + + if (s->dma_mr) { + object_unparent(OBJECT(s->dma_mr)); + } + sdhci_uninitfn(s); } @@ -1348,22 +1382,42 @@ static void sdhci_sysbus_realize(DeviceState *dev, Error ** errp) SDHCIState *s = SYSBUS_SDHCI(dev); SysBusDevice *sbd = SYS_BUS_DEVICE(dev); - s->buf_maxsz = sdhci_get_fifolen(s); - s->fifo_buffer = g_malloc0(s->buf_maxsz); + sdhci_common_realize(s, errp); + if (errp && *errp) { + return; + } + + if (s->dma_mr) { + address_space_init(s->dma_as, s->dma_mr, "sdhci-dma"); + } else { + /* use system_memory() if property "dma" not set */ + s->dma_as = &address_space_memory; + } + sysbus_init_irq(sbd, &s->irq); - memory_region_init_io(&s->iomem, OBJECT(s), &sdhci_mmio_ops, s, "sdhci", - SDHC_REGISTERS_MAP_SIZE); sysbus_init_mmio(sbd, &s->iomem); } +static void sdhci_sysbus_unrealize(DeviceState *dev, Error **errp) +{ + SDHCIState *s = SYSBUS_SDHCI(dev); + + sdhci_common_unrealize(s, &error_abort); + + if (s->dma_mr) { + address_space_destroy(s->dma_as); + } +} + static void sdhci_sysbus_class_init(ObjectClass *klass, void *data) { DeviceClass *dc = DEVICE_CLASS(klass); - dc->vmsd = &sdhci_vmstate; dc->props = sdhci_sysbus_properties; dc->realize = sdhci_sysbus_realize; - dc->reset = sdhci_poweron_reset; + dc->unrealize = sdhci_sysbus_unrealize; + + sdhci_common_class_init(klass, data); } static const TypeInfo sdhci_sysbus_info = { @@ -1375,6 +1429,8 @@ static const TypeInfo sdhci_sysbus_info = { .class_init = sdhci_sysbus_class_init, }; +/* --- qdev bus master --- */ + static void sdhci_bus_class_init(ObjectClass *klass, void *data) { SDBusClass *sbc = SD_BUS_CLASS(klass); diff --git a/hw/sd/ssi-sd.c b/hw/sd/ssi-sd.c index 24001dc3e6..f88f509e0a 100644 --- a/hw/sd/ssi-sd.c +++ b/hw/sd/ssi-sd.c @@ -50,6 +50,9 @@ typedef struct { SDState *sd; } ssi_sd_state; +#define TYPE_SSI_SD "ssi-sd" +#define SSI_SD(obj) OBJECT_CHECK(ssi_sd_state, (obj), TYPE_SSI_SD) + /* State word bits. */ #define SSI_SDR_LOCKED 0x0001 #define SSI_SDR_WP_ERASE 0x0002 @@ -241,7 +244,6 @@ static void ssi_sd_realize(SSISlave *d, Error **errp) ssi_sd_state *s = FROM_SSI_SLAVE(ssi_sd_state, d); DriveInfo *dinfo; - s->mode = SSI_SD_CMD; /* FIXME use a qdev drive property instead of drive_get_next() */ dinfo = drive_get_next(IF_SD); s->sd = sd_init(dinfo ? blk_by_legacy_dinfo(dinfo) : NULL, true); @@ -251,6 +253,24 @@ static void ssi_sd_realize(SSISlave *d, Error **errp) } } +static void ssi_sd_reset(DeviceState *dev) +{ + ssi_sd_state *s = SSI_SD(dev); + + s->mode = SSI_SD_CMD; + s->cmd = 0; + memset(s->cmdarg, 0, sizeof(s->cmdarg)); + memset(s->response, 0, sizeof(s->response)); + s->arglen = 0; + s->response_pos = 0; + s->stopping = 0; + + /* Since we're still using the legacy SD API the card is not plugged + * into any bus, and we must reset it manually. + */ + device_reset(DEVICE(s->sd)); +} + static void ssi_sd_class_init(ObjectClass *klass, void *data) { DeviceClass *dc = DEVICE_CLASS(klass); @@ -260,10 +280,11 @@ static void ssi_sd_class_init(ObjectClass *klass, void *data) k->transfer = ssi_sd_transfer; k->cs_polarity = SSI_CS_LOW; dc->vmsd = &vmstate_ssi_sd; + dc->reset = ssi_sd_reset; } static const TypeInfo ssi_sd_info = { - .name = "ssi-sd", + .name = TYPE_SSI_SD, .parent = TYPE_SSI_SLAVE, .instance_size = sizeof(ssi_sd_state), .class_init = ssi_sd_class_init, diff --git a/hw/sd/trace-events b/hw/sd/trace-events index 6eca3470e2..0a121156a3 100644 --- a/hw/sd/trace-events +++ b/hw/sd/trace-events @@ -1,5 +1,19 @@ # See docs/devel/tracing.txt for syntax documentation. +# hw/sd/sdhci.c +sdhci_set_inserted(const char *level) "card state changed: %s" +sdhci_send_command(uint8_t cmd, uint32_t arg) "CMD%02u ARG[0x%08x]" +sdhci_error(const char *msg) "%s" +sdhci_response4(uint32_t r0) "RSPREG[31..0]=0x%08x" +sdhci_response16(uint32_t r3, uint32_t r2, uint32_t r1, uint32_t r0) "RSPREG[127..96]=0x%08x, RSPREG[95..64]=0x%08x, RSPREG[63..32]=0x%08x, RSPREG[31..0]=0x%08x" +sdhci_end_transfer(uint8_t cmd, uint32_t arg) "Automatically issue CMD%02u 0x%08x" +sdhci_adma(const char *desc, uint32_t sysad) "%s: admasysaddr=0x%" PRIx32 +sdhci_adma_loop(uint64_t addr, uint16_t length, uint8_t attr) "addr=0x%08" PRIx64 ", len=%d, attr=0x%x" +sdhci_adma_transfer_completed(void) "" +sdhci_access(const char *access, unsigned int size, uint64_t offset, const char *dir, uint64_t val, uint64_t val2) "%s%u: addr[0x%04" PRIx64 "] %s 0x%08" PRIx64 " (%" PRIu64 ")" +sdhci_read_dataport(uint16_t data_count) "all %u bytes of data have been read from input buffer" +sdhci_write_dataport(uint16_t data_count) "write buffer filled with %u bytes of data" + # 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" diff --git a/include/hw/sd/sdhci.h b/include/hw/sd/sdhci.h index 0f0c3f1e64..cb37182536 100644 --- a/include/hw/sd/sdhci.h +++ b/include/hw/sd/sdhci.h @@ -26,26 +26,29 @@ #define SDHCI_H #include "qemu-common.h" -#include "hw/block/block.h" #include "hw/pci/pci.h" #include "hw/sysbus.h" #include "hw/sd/sd.h" /* SD/MMC host controller state */ typedef struct SDHCIState { + /*< private >*/ union { PCIDevice pcidev; SysBusDevice busdev; }; + + /*< public >*/ SDBus sdbus; MemoryRegion iomem; + AddressSpace *dma_as; + MemoryRegion *dma_mr; QEMUTimer *insert_timer; /* timer for 'changing' sd card. */ QEMUTimer *transfer_timer; - qemu_irq eject_cb; - qemu_irq ro_cb; qemu_irq irq; + /* Registers cleared on reset */ uint32_t sdmasysad; /* SDMA System Address register */ uint16_t blksize; /* Host DMA Buff Boundary and Transfer BlkSize Reg */ uint16_t blkcnt; /* Blocks count for current transfer */ @@ -70,19 +73,23 @@ typedef struct SDHCIState { uint16_t acmd12errsts; /* Auto CMD12 error status register */ uint64_t admasysaddr; /* ADMA System Address Register */ - uint32_t capareg; /* Capabilities Register */ - uint32_t maxcurr; /* Maximum Current Capabilities Register */ + /* Read-only registers */ + uint64_t capareg; /* Capabilities Register */ + uint64_t maxcurr; /* Maximum Current Capabilities Register */ + uint8_t *fifo_buffer; /* SD host i/o FIFO buffer */ uint32_t buf_maxsz; uint16_t data_count; /* current element in FIFO buffer */ uint8_t stopped_state;/* Current SDHC state */ - bool pending_insert_quirk;/* Quirk for Raspberry Pi card insert int */ bool pending_insert_state; /* Buffer Data Port Register - virtual access point to R and W buffers */ /* Software Reset Register - always reads as 0 */ /* Force Event Auto CMD12 Error Interrupt Reg - write only */ /* Force Event Error Interrupt Register- write only */ /* RO Host Controller Version Register always reads as 0x2401 */ + + /* Configurable properties */ + bool pending_insert_quirk; /* Quirk for Raspberry Pi card insert int */ } SDHCIState; #define TYPE_PCI_SDHCI "sdhci-pci" diff --git a/target/arm/helper.c b/target/arm/helper.c index d1395f9b73..c83c901a86 100644 --- a/target/arm/helper.c +++ b/target/arm/helper.c @@ -8305,6 +8305,7 @@ static hwaddr S1_ptw_translate(CPUARMState *env, ARMMMUIdx mmu_idx, ret = get_phys_addr_lpae(env, addr, 0, ARMMMUIdx_S2NS, &s2pa, &txattrs, &s2prot, &s2size, fi, NULL); if (ret) { + assert(fi->type != ARMFault_None); fi->s2addr = addr; fi->stage2 = true; fi->s1ptw = true; @@ -8328,7 +8329,9 @@ static uint32_t arm_ldl_ptw(CPUState *cs, hwaddr addr, bool is_secure, ARMCPU *cpu = ARM_CPU(cs); CPUARMState *env = &cpu->env; MemTxAttrs attrs = {}; + MemTxResult result = MEMTX_OK; AddressSpace *as; + uint32_t data; attrs.secure = is_secure; as = arm_addressspace(cs, attrs); @@ -8337,10 +8340,16 @@ static uint32_t arm_ldl_ptw(CPUState *cs, hwaddr addr, bool is_secure, return 0; } if (regime_translation_big_endian(env, mmu_idx)) { - return address_space_ldl_be(as, addr, attrs, NULL); + data = address_space_ldl_be(as, addr, attrs, &result); } else { - return address_space_ldl_le(as, addr, attrs, NULL); + data = address_space_ldl_le(as, addr, attrs, &result); } + if (result == MEMTX_OK) { + return data; + } + fi->type = ARMFault_SyncExternalOnWalk; + fi->ea = arm_extabort_type(result); + return 0; } static uint64_t arm_ldq_ptw(CPUState *cs, hwaddr addr, bool is_secure, @@ -8349,7 +8358,9 @@ static uint64_t arm_ldq_ptw(CPUState *cs, hwaddr addr, bool is_secure, ARMCPU *cpu = ARM_CPU(cs); CPUARMState *env = &cpu->env; MemTxAttrs attrs = {}; + MemTxResult result = MEMTX_OK; AddressSpace *as; + uint32_t data; attrs.secure = is_secure; as = arm_addressspace(cs, attrs); @@ -8358,10 +8369,16 @@ static uint64_t arm_ldq_ptw(CPUState *cs, hwaddr addr, bool is_secure, return 0; } if (regime_translation_big_endian(env, mmu_idx)) { - return address_space_ldq_be(as, addr, attrs, NULL); + data = address_space_ldq_be(as, addr, attrs, &result); } else { - return address_space_ldq_le(as, addr, attrs, NULL); + data = address_space_ldq_le(as, addr, attrs, &result); + } + if (result == MEMTX_OK) { + return data; } + fi->type = ARMFault_SyncExternalOnWalk; + fi->ea = arm_extabort_type(result); + return 0; } static bool get_phys_addr_v5(CPUARMState *env, uint32_t address, @@ -8390,6 +8407,9 @@ static bool get_phys_addr_v5(CPUARMState *env, uint32_t address, } desc = arm_ldl_ptw(cs, table, regime_is_secure(env, mmu_idx), mmu_idx, fi); + if (fi->type != ARMFault_None) { + goto do_fault; + } type = (desc & 3); domain = (desc >> 5) & 0x0f; if (regime_el(env, mmu_idx) == 1) { @@ -8426,6 +8446,9 @@ static bool get_phys_addr_v5(CPUARMState *env, uint32_t address, } desc = arm_ldl_ptw(cs, table, regime_is_secure(env, mmu_idx), mmu_idx, fi); + if (fi->type != ARMFault_None) { + goto do_fault; + } switch (desc & 3) { case 0: /* Page translation fault. */ fi->type = ARMFault_Translation; @@ -8508,6 +8531,9 @@ static bool get_phys_addr_v6(CPUARMState *env, uint32_t address, } desc = arm_ldl_ptw(cs, table, regime_is_secure(env, mmu_idx), mmu_idx, fi); + if (fi->type != ARMFault_None) { + goto do_fault; + } type = (desc & 3); if (type == 0 || (type == 3 && !arm_feature(env, ARM_FEATURE_PXN))) { /* Section translation fault, or attempt to use the encoding @@ -8559,6 +8585,9 @@ static bool get_phys_addr_v6(CPUARMState *env, uint32_t address, table = (desc & 0xfffffc00) | ((address >> 10) & 0x3fc); desc = arm_ldl_ptw(cs, table, regime_is_secure(env, mmu_idx), mmu_idx, fi); + if (fi->type != ARMFault_None) { + goto do_fault; + } ap = ((desc >> 4) & 3) | ((desc >> 7) & 4); switch (desc & 3) { case 0: /* Page translation fault. */ @@ -8964,7 +8993,7 @@ static bool get_phys_addr_lpae(CPUARMState *env, target_ulong address, descaddr &= ~7ULL; nstable = extract32(tableattrs, 4, 1); descriptor = arm_ldq_ptw(cs, descaddr, !nstable, mmu_idx, fi); - if (fi->s1ptw) { + if (fi->type != ARMFault_None) { goto do_fault; } @@ -9272,6 +9301,13 @@ static bool get_phys_addr_pmsav7(CPUARMState *env, uint32_t address, case 6: *prot |= PAGE_READ | PAGE_EXEC; break; + case 7: + /* for v7M, same as 6; for R profile a reserved value */ + if (arm_feature(env, ARM_FEATURE_M)) { + *prot |= PAGE_READ | PAGE_EXEC; + break; + } + /* fall through */ default: qemu_log_mask(LOG_GUEST_ERROR, "DRACR[%d]: Bad value for AP bits: 0x%" @@ -9290,6 +9326,13 @@ static bool get_phys_addr_pmsav7(CPUARMState *env, uint32_t address, case 6: *prot |= PAGE_READ | PAGE_EXEC; break; + case 7: + /* for v7M, same as 6; for R profile a reserved value */ + if (arm_feature(env, ARM_FEATURE_M)) { + *prot |= PAGE_READ | PAGE_EXEC; + break; + } + /* fall through */ default: qemu_log_mask(LOG_GUEST_ERROR, "DRACR[%d]: Bad value for AP bits: 0x%" diff --git a/target/arm/internals.h b/target/arm/internals.h index 876854d876..89f5d2fe12 100644 --- a/target/arm/internals.h +++ b/target/arm/internals.h @@ -687,6 +687,16 @@ static inline uint32_t arm_fi_to_lfsc(ARMMMUFaultInfo *fi) return fsc; } +static inline bool arm_extabort_type(MemTxResult result) +{ + /* The EA bit in syndromes and fault status registers is an + * IMPDEF classification of external aborts. ARM implementations + * usually use this to indicate AXI bus Decode error (0) or + * Slave error (1); in QEMU we follow that. + */ + return result != MEMTX_DECODE_ERROR; +} + /* Do a page table walk and add page to TLB if possible */ bool arm_tlb_fill(CPUState *cpu, vaddr address, MMUAccessType access_type, int mmu_idx, diff --git a/target/arm/op_helper.c b/target/arm/op_helper.c index b36206343d..712c5c55b6 100644 --- a/target/arm/op_helper.c +++ b/target/arm/op_helper.c @@ -220,12 +220,7 @@ void arm_cpu_do_transaction_failed(CPUState *cs, hwaddr physaddr, /* now we have a real cpu fault */ cpu_restore_state(cs, retaddr); - /* The EA bit in syndromes and fault status registers is an - * IMPDEF classification of external aborts. ARM implementations - * usually use this to indicate AXI bus Decode error (0) or - * Slave error (1); in QEMU we follow that. - */ - fi.ea = (response != MEMTX_DECODE_ERROR); + fi.ea = arm_extabort_type(response); fi.type = ARMFault_SyncExternal; deliver_fault(cpu, addr, access_type, mmu_idx, &fi); } diff --git a/target/arm/translate-a64.c b/target/arm/translate-a64.c index ba94f7d045..cf537e9d9b 100644 --- a/target/arm/translate-a64.c +++ b/target/arm/translate-a64.c @@ -4985,6 +4985,38 @@ static void disas_fp_3src(DisasContext *s, uint32_t insn) } } +/* The imm8 encodes the sign bit, enough bits to represent an exponent in + * the range 01....1xx to 10....0xx, and the most significant 4 bits of + * the mantissa; see VFPExpandImm() in the v8 ARM ARM. + */ +static uint64_t vfp_expand_imm(int size, uint8_t imm8) +{ + uint64_t imm; + + switch (size) { + case MO_64: + imm = (extract32(imm8, 7, 1) ? 0x8000 : 0) | + (extract32(imm8, 6, 1) ? 0x3fc0 : 0x4000) | + extract32(imm8, 0, 6); + imm <<= 48; + break; + case MO_32: + imm = (extract32(imm8, 7, 1) ? 0x8000 : 0) | + (extract32(imm8, 6, 1) ? 0x3e00 : 0x4000) | + (extract32(imm8, 0, 6) << 3); + imm <<= 16; + break; + case MO_16: + imm = (extract32(imm8, 7, 1) ? 0x8000 : 0) | + (extract32(imm8, 6, 1) ? 0x3000 : 0x4000) | + (extract32(imm8, 0, 6) << 6); + break; + default: + g_assert_not_reached(); + } + return imm; +} + /* Floating point immediate * 31 30 29 28 24 23 22 21 20 13 12 10 9 5 4 0 * +---+---+---+-----------+------+---+------------+-------+------+------+ @@ -5008,22 +5040,7 @@ static void disas_fp_imm(DisasContext *s, uint32_t insn) return; } - /* The imm8 encodes the sign bit, enough bits to represent - * an exponent in the range 01....1xx to 10....0xx, - * and the most significant 4 bits of the mantissa; see - * VFPExpandImm() in the v8 ARM ARM. - */ - if (is_double) { - imm = (extract32(imm8, 7, 1) ? 0x8000 : 0) | - (extract32(imm8, 6, 1) ? 0x3fc0 : 0x4000) | - extract32(imm8, 0, 6); - imm <<= 48; - } else { - imm = (extract32(imm8, 7, 1) ? 0x8000 : 0) | - (extract32(imm8, 6, 1) ? 0x3e00 : 0x4000) | - (extract32(imm8, 0, 6) << 3); - imm <<= 16; - } + imm = vfp_expand_imm(MO_32 + is_double, imm8); tcg_res = tcg_const_i64(imm); write_fp_dreg(s, rd, tcg_res); |