From fb23d693a3e0f22c25fdc2f373ac81d9cbb26680 Mon Sep 17 00:00:00 2001 From: Jerome Forissier Date: Fri, 5 Oct 2018 10:07:29 +0200 Subject: [PATCH 01/17] hw/arm/virt: add DT property /secure-chosen/stdout-path indicating secure UART Bindings for /secure-chosen and /secure-chosen/stdout-path have been proposed 1.5 years ago [1] and implemented in OP-TEE at the same time [2]. They've now been officially agreed on, so we can implement them in QEMU. This patch creates the property when the machine is secure. [1] https://patchwork.kernel.org/patch/9602401/ [2] https://github.com/OP-TEE/optee_os/commit/4dc31c52544a Signed-off-by: Jerome Forissier Message-id: 20181005080729.6480-1-jerome.forissier@linaro.org Reviewed-by: Peter Maydell [PMM: commit message tweak] Signed-off-by: Peter Maydell --- hw/arm/virt.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/hw/arm/virt.c b/hw/arm/virt.c index 96dd4ef10c..9f677825f9 100644 --- a/hw/arm/virt.c +++ b/hw/arm/virt.c @@ -712,6 +712,10 @@ static void create_uart(const VirtMachineState *vms, qemu_irq *pic, int uart, /* Mark as not usable by the normal world */ qemu_fdt_setprop_string(vms->fdt, nodename, "status", "disabled"); qemu_fdt_setprop_string(vms->fdt, nodename, "secure-status", "okay"); + + qemu_fdt_add_subnode(vms->fdt, "/secure-chosen"); + qemu_fdt_setprop_string(vms->fdt, "/secure-chosen", "stdout-path", + nodename); } g_free(nodename); From 9a05f7b67436abdc52bce899f56acfde2e831454 Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Mon, 8 Oct 2018 14:21:56 -0700 Subject: [PATCH 02/17] target/arm: Fix aarch64_sve_change_el wrt EL0 At present we assert: arm_el_is_aa64: Assertion `el >= 1 && el <= 3' failed. The comment in arm_el_is_aa64 explains why asking about EL0 without extra information is impossible. Add an extra argument to provide it from the surrounding context. Fixes: 0ab5953b00b3 Signed-off-by: Richard Henderson Message-id: 20181008212205.17752-2-richard.henderson@linaro.org Reviewed-by: Peter Maydell Signed-off-by: Peter Maydell --- target/arm/cpu.h | 7 +++++-- target/arm/helper.c | 16 ++++++++++++---- target/arm/op_helper.c | 6 +++++- 3 files changed, 22 insertions(+), 7 deletions(-) diff --git a/target/arm/cpu.h b/target/arm/cpu.h index 3a2aff1192..54362ddce8 100644 --- a/target/arm/cpu.h +++ b/target/arm/cpu.h @@ -911,10 +911,13 @@ int arm_cpu_write_elf32_note(WriteCoreDumpFunction f, CPUState *cs, int aarch64_cpu_gdb_read_register(CPUState *cpu, uint8_t *buf, int reg); int aarch64_cpu_gdb_write_register(CPUState *cpu, uint8_t *buf, int reg); void aarch64_sve_narrow_vq(CPUARMState *env, unsigned vq); -void aarch64_sve_change_el(CPUARMState *env, int old_el, int new_el); +void aarch64_sve_change_el(CPUARMState *env, int old_el, + int new_el, bool el0_a64); #else static inline void aarch64_sve_narrow_vq(CPUARMState *env, unsigned vq) { } -static inline void aarch64_sve_change_el(CPUARMState *env, int o, int n) { } +static inline void aarch64_sve_change_el(CPUARMState *env, int o, + int n, bool a) +{ } #endif target_ulong do_arm_semihosting(CPUARMState *env); diff --git a/target/arm/helper.c b/target/arm/helper.c index c83f7c1109..0efbb5c76c 100644 --- a/target/arm/helper.c +++ b/target/arm/helper.c @@ -8374,7 +8374,11 @@ static void arm_cpu_do_interrupt_aarch64(CPUState *cs) unsigned int new_mode = aarch64_pstate_mode(new_el, true); unsigned int cur_el = arm_current_el(env); - aarch64_sve_change_el(env, cur_el, new_el); + /* + * Note that new_el can never be 0. If cur_el is 0, then + * el0_a64 is is_a64(), else el0_a64 is ignored. + */ + aarch64_sve_change_el(env, cur_el, new_el, is_a64(env)); if (cur_el < new_el) { /* Entry vector offset depends on whether the implemented EL @@ -12791,9 +12795,11 @@ void aarch64_sve_narrow_vq(CPUARMState *env, unsigned vq) /* * Notice a change in SVE vector size when changing EL. */ -void aarch64_sve_change_el(CPUARMState *env, int old_el, int new_el) +void aarch64_sve_change_el(CPUARMState *env, int old_el, + int new_el, bool el0_a64) { int old_len, new_len; + bool old_a64, new_a64; /* Nothing to do if no SVE. */ if (!arm_feature(env, ARM_FEATURE_SVE)) { @@ -12817,9 +12823,11 @@ void aarch64_sve_change_el(CPUARMState *env, int old_el, int new_el) * we already have the correct register contents when encountering the * vq0->vq0 transition between EL0->EL1. */ - old_len = (arm_el_is_aa64(env, old_el) && !sve_exception_el(env, old_el) + old_a64 = old_el ? arm_el_is_aa64(env, old_el) : el0_a64; + old_len = (old_a64 && !sve_exception_el(env, old_el) ? sve_zcr_len_for_el(env, old_el) : 0); - new_len = (arm_el_is_aa64(env, new_el) && !sve_exception_el(env, new_el) + new_a64 = new_el ? arm_el_is_aa64(env, new_el) : el0_a64; + new_len = (new_a64 && !sve_exception_el(env, new_el) ? sve_zcr_len_for_el(env, new_el) : 0); /* When changing vector length, clear inaccessible state. */ diff --git a/target/arm/op_helper.c b/target/arm/op_helper.c index fb15a13e6c..d915579712 100644 --- a/target/arm/op_helper.c +++ b/target/arm/op_helper.c @@ -1101,7 +1101,11 @@ void HELPER(exception_return)(CPUARMState *env) "AArch64 EL%d PC 0x%" PRIx64 "\n", cur_el, new_el, env->pc); } - aarch64_sve_change_el(env, cur_el, new_el); + /* + * Note that cur_el can never be 0. If new_el is 0, then + * el0_a64 is return_to_aa64, else el0_a64 is ignored. + */ + aarch64_sve_change_el(env, cur_el, new_el, return_to_aa64); qemu_mutex_lock_iothread(); arm_call_el_change_hook(arm_env_get_cpu(env)); From a62e62af9f26bf655fe95ada796f28a6a16c0561 Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Mon, 8 Oct 2018 14:21:57 -0700 Subject: [PATCH 03/17] target/arm: Define fields of ISAR registers MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Reviewed-by: Philippe Mathieu-Daudé Signed-off-by: Richard Henderson Message-id: 20181008212205.17752-3-richard.henderson@linaro.org Reviewed-by: Peter Maydell Signed-off-by: Peter Maydell --- target/arm/cpu.h | 88 ++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 88 insertions(+) diff --git a/target/arm/cpu.h b/target/arm/cpu.h index 54362ddce8..f00c0444c4 100644 --- a/target/arm/cpu.h +++ b/target/arm/cpu.h @@ -1443,6 +1443,94 @@ FIELD(V7M_CSSELR, LEVEL, 1, 3) */ FIELD(V7M_CSSELR, INDEX, 0, 4) +/* + * System register ID fields. + */ +FIELD(ID_ISAR0, SWAP, 0, 4) +FIELD(ID_ISAR0, BITCOUNT, 4, 4) +FIELD(ID_ISAR0, BITFIELD, 8, 4) +FIELD(ID_ISAR0, CMPBRANCH, 12, 4) +FIELD(ID_ISAR0, COPROC, 16, 4) +FIELD(ID_ISAR0, DEBUG, 20, 4) +FIELD(ID_ISAR0, DIVIDE, 24, 4) + +FIELD(ID_ISAR1, ENDIAN, 0, 4) +FIELD(ID_ISAR1, EXCEPT, 4, 4) +FIELD(ID_ISAR1, EXCEPT_AR, 8, 4) +FIELD(ID_ISAR1, EXTEND, 12, 4) +FIELD(ID_ISAR1, IFTHEN, 16, 4) +FIELD(ID_ISAR1, IMMEDIATE, 20, 4) +FIELD(ID_ISAR1, INTERWORK, 24, 4) +FIELD(ID_ISAR1, JAZELLE, 28, 4) + +FIELD(ID_ISAR2, LOADSTORE, 0, 4) +FIELD(ID_ISAR2, MEMHINT, 4, 4) +FIELD(ID_ISAR2, MULTIACCESSINT, 8, 4) +FIELD(ID_ISAR2, MULT, 12, 4) +FIELD(ID_ISAR2, MULTS, 16, 4) +FIELD(ID_ISAR2, MULTU, 20, 4) +FIELD(ID_ISAR2, PSR_AR, 24, 4) +FIELD(ID_ISAR2, REVERSAL, 28, 4) + +FIELD(ID_ISAR3, SATURATE, 0, 4) +FIELD(ID_ISAR3, SIMD, 4, 4) +FIELD(ID_ISAR3, SVC, 8, 4) +FIELD(ID_ISAR3, SYNCHPRIM, 12, 4) +FIELD(ID_ISAR3, TABBRANCH, 16, 4) +FIELD(ID_ISAR3, T32COPY, 20, 4) +FIELD(ID_ISAR3, TRUENOP, 24, 4) +FIELD(ID_ISAR3, T32EE, 28, 4) + +FIELD(ID_ISAR4, UNPRIV, 0, 4) +FIELD(ID_ISAR4, WITHSHIFTS, 4, 4) +FIELD(ID_ISAR4, WRITEBACK, 8, 4) +FIELD(ID_ISAR4, SMC, 12, 4) +FIELD(ID_ISAR4, BARRIER, 16, 4) +FIELD(ID_ISAR4, SYNCHPRIM_FRAC, 20, 4) +FIELD(ID_ISAR4, PSR_M, 24, 4) +FIELD(ID_ISAR4, SWP_FRAC, 28, 4) + +FIELD(ID_ISAR5, SEVL, 0, 4) +FIELD(ID_ISAR5, AES, 4, 4) +FIELD(ID_ISAR5, SHA1, 8, 4) +FIELD(ID_ISAR5, SHA2, 12, 4) +FIELD(ID_ISAR5, CRC32, 16, 4) +FIELD(ID_ISAR5, RDM, 24, 4) +FIELD(ID_ISAR5, VCMA, 28, 4) + +FIELD(ID_ISAR6, JSCVT, 0, 4) +FIELD(ID_ISAR6, DP, 4, 4) +FIELD(ID_ISAR6, FHM, 8, 4) +FIELD(ID_ISAR6, SB, 12, 4) +FIELD(ID_ISAR6, SPECRES, 16, 4) + +FIELD(ID_AA64ISAR0, AES, 4, 4) +FIELD(ID_AA64ISAR0, SHA1, 8, 4) +FIELD(ID_AA64ISAR0, SHA2, 12, 4) +FIELD(ID_AA64ISAR0, CRC32, 16, 4) +FIELD(ID_AA64ISAR0, ATOMIC, 20, 4) +FIELD(ID_AA64ISAR0, RDM, 28, 4) +FIELD(ID_AA64ISAR0, SHA3, 32, 4) +FIELD(ID_AA64ISAR0, SM3, 36, 4) +FIELD(ID_AA64ISAR0, SM4, 40, 4) +FIELD(ID_AA64ISAR0, DP, 44, 4) +FIELD(ID_AA64ISAR0, FHM, 48, 4) +FIELD(ID_AA64ISAR0, TS, 52, 4) +FIELD(ID_AA64ISAR0, TLB, 56, 4) +FIELD(ID_AA64ISAR0, RNDR, 60, 4) + +FIELD(ID_AA64ISAR1, DPB, 0, 4) +FIELD(ID_AA64ISAR1, APA, 4, 4) +FIELD(ID_AA64ISAR1, API, 8, 4) +FIELD(ID_AA64ISAR1, JSCVT, 12, 4) +FIELD(ID_AA64ISAR1, FCMA, 16, 4) +FIELD(ID_AA64ISAR1, LRCPC, 20, 4) +FIELD(ID_AA64ISAR1, GPA, 24, 4) +FIELD(ID_AA64ISAR1, GPI, 28, 4) +FIELD(ID_AA64ISAR1, FRINTTS, 32, 4) +FIELD(ID_AA64ISAR1, SB, 36, 4) +FIELD(ID_AA64ISAR1, SPECRES, 40, 4) + QEMU_BUILD_BUG_ON(ARRAY_SIZE(((ARMCPU *)0)->ccsidr) <= R_V7M_CSSELR_INDEX_MASK); /* If adding a feature bit which corresponds to a Linux ELF From aaab8f3400ea5ec9c6cce3607ff26f9be89321d6 Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Mon, 8 Oct 2018 14:21:59 -0700 Subject: [PATCH 04/17] target/arm: Align cortex-r5 id_isar0 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The missing nibble made it more difficult to read. Reviewed-by: Philippe Mathieu-Daudé Signed-off-by: Richard Henderson Message-id: 20181008212205.17752-5-richard.henderson@linaro.org Signed-off-by: Peter Maydell --- target/arm/cpu.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/target/arm/cpu.c b/target/arm/cpu.c index b5e61cc177..7ea7e4c131 100644 --- a/target/arm/cpu.c +++ b/target/arm/cpu.c @@ -1397,7 +1397,7 @@ static void cortex_r5_initfn(Object *obj) cpu->id_mmfr1 = 0x00000000; cpu->id_mmfr2 = 0x01200000; cpu->id_mmfr3 = 0x0211; - cpu->id_isar0 = 0x2101111; + cpu->id_isar0 = 0x02101111; cpu->id_isar1 = 0x13112111; cpu->id_isar2 = 0x21232141; cpu->id_isar3 = 0x01112131; From 37bdda89eb7615cb225f781c9fb552e144c68ea7 Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Mon, 8 Oct 2018 14:22:00 -0700 Subject: [PATCH 05/17] target/arm: Fix cortex-a7 id_isar0 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The incorrect value advertised only thumb2 div without arm div. Reviewed-by: Philippe Mathieu-Daudé Signed-off-by: Richard Henderson Message-id: 20181008212205.17752-6-richard.henderson@linaro.org Signed-off-by: Peter Maydell --- target/arm/cpu.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/target/arm/cpu.c b/target/arm/cpu.c index 7ea7e4c131..cd48ad42d8 100644 --- a/target/arm/cpu.c +++ b/target/arm/cpu.c @@ -1587,7 +1587,10 @@ static void cortex_a7_initfn(Object *obj) cpu->id_mmfr1 = 0x40000000; cpu->id_mmfr2 = 0x01240000; cpu->id_mmfr3 = 0x02102211; - cpu->id_isar0 = 0x01101110; + /* a7_mpcore_r0p5_trm, page 4-4 gives 0x01101110; but + * table 4-41 gives 0x02101110, which includes the arm div insns. + */ + cpu->id_isar0 = 0x02101110; cpu->id_isar1 = 0x13112111; cpu->id_isar2 = 0x21232041; cpu->id_isar3 = 0x11112131; From b2d43091b59fc9937e68800b0ec3e76efd73690a Mon Sep 17 00:00:00 2001 From: "Edgar E. Iglesias" Date: Thu, 11 Oct 2018 04:19:20 +0200 Subject: [PATCH 06/17] net: cadence_gem: Disable TSU feature bit Disable the Timestamping Unit feature bit since QEMU does not yet support it. This allows guest SW to correctly probe for its existance. Reviewed-by: Alistair Francis Signed-off-by: Edgar E. Iglesias Message-id: 20181011021931.4249-2-edgar.iglesias@gmail.com Signed-off-by: Peter Maydell --- hw/net/cadence_gem.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/hw/net/cadence_gem.c b/hw/net/cadence_gem.c index 0fa4b0dc44..e560b7a142 100644 --- a/hw/net/cadence_gem.c +++ b/hw/net/cadence_gem.c @@ -1228,7 +1228,7 @@ static void gem_reset(DeviceState *d) s->regs[GEM_MODID] = s->revision; s->regs[GEM_DESCONF] = 0x02500111; s->regs[GEM_DESCONF2] = 0x2ab13fff; - s->regs[GEM_DESCONF5] = 0x002f2145; + s->regs[GEM_DESCONF5] = 0x002f2045; s->regs[GEM_DESCONF6] = 0x00000200; /* Set MAC address */ From f02361822f73f28a4279783fdfb581c500660a36 Mon Sep 17 00:00:00 2001 From: "Edgar E. Iglesias" Date: Thu, 11 Oct 2018 04:19:22 +0200 Subject: [PATCH 07/17] net: cadence_gem: Use uint32_t for 32bit descriptor words MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Use uint32_t instead of unsigned to describe 32bit descriptor words. Reviewed-by: Alistair Francis Reviewed-by: Philippe Mathieu-Daudé Signed-off-by: Edgar E. Iglesias Message-id: 20181011021931.4249-4-edgar.iglesias@gmail.com Signed-off-by: Peter Maydell --- hw/net/cadence_gem.c | 42 ++++++++++++++++++------------------ include/hw/net/cadence_gem.h | 2 +- 2 files changed, 22 insertions(+), 22 deletions(-) diff --git a/hw/net/cadence_gem.c b/hw/net/cadence_gem.c index e560b7a142..d67249393c 100644 --- a/hw/net/cadence_gem.c +++ b/hw/net/cadence_gem.c @@ -302,42 +302,42 @@ #define GEM_MODID_VALUE 0x00020118 -static inline unsigned tx_desc_get_buffer(unsigned *desc) +static inline unsigned tx_desc_get_buffer(uint32_t *desc) { return desc[0]; } -static inline unsigned tx_desc_get_used(unsigned *desc) +static inline unsigned tx_desc_get_used(uint32_t *desc) { return (desc[1] & DESC_1_USED) ? 1 : 0; } -static inline void tx_desc_set_used(unsigned *desc) +static inline void tx_desc_set_used(uint32_t *desc) { desc[1] |= DESC_1_USED; } -static inline unsigned tx_desc_get_wrap(unsigned *desc) +static inline unsigned tx_desc_get_wrap(uint32_t *desc) { return (desc[1] & DESC_1_TX_WRAP) ? 1 : 0; } -static inline unsigned tx_desc_get_last(unsigned *desc) +static inline unsigned tx_desc_get_last(uint32_t *desc) { return (desc[1] & DESC_1_TX_LAST) ? 1 : 0; } -static inline void tx_desc_set_last(unsigned *desc) +static inline void tx_desc_set_last(uint32_t *desc) { desc[1] |= DESC_1_TX_LAST; } -static inline unsigned tx_desc_get_length(unsigned *desc) +static inline unsigned tx_desc_get_length(uint32_t *desc) { return desc[1] & DESC_1_LENGTH; } -static inline void print_gem_tx_desc(unsigned *desc, uint8_t queue) +static inline void print_gem_tx_desc(uint32_t *desc, uint8_t queue) { DB_PRINT("TXDESC (queue %" PRId8 "):\n", queue); DB_PRINT("bufaddr: 0x%08x\n", *desc); @@ -347,58 +347,58 @@ static inline void print_gem_tx_desc(unsigned *desc, uint8_t queue) DB_PRINT("length: %d\n", tx_desc_get_length(desc)); } -static inline unsigned rx_desc_get_buffer(unsigned *desc) +static inline unsigned rx_desc_get_buffer(uint32_t *desc) { return desc[0] & ~0x3UL; } -static inline unsigned rx_desc_get_wrap(unsigned *desc) +static inline unsigned rx_desc_get_wrap(uint32_t *desc) { return desc[0] & DESC_0_RX_WRAP ? 1 : 0; } -static inline unsigned rx_desc_get_ownership(unsigned *desc) +static inline unsigned rx_desc_get_ownership(uint32_t *desc) { return desc[0] & DESC_0_RX_OWNERSHIP ? 1 : 0; } -static inline void rx_desc_set_ownership(unsigned *desc) +static inline void rx_desc_set_ownership(uint32_t *desc) { desc[0] |= DESC_0_RX_OWNERSHIP; } -static inline void rx_desc_set_sof(unsigned *desc) +static inline void rx_desc_set_sof(uint32_t *desc) { desc[1] |= DESC_1_RX_SOF; } -static inline void rx_desc_set_eof(unsigned *desc) +static inline void rx_desc_set_eof(uint32_t *desc) { desc[1] |= DESC_1_RX_EOF; } -static inline void rx_desc_set_length(unsigned *desc, unsigned len) +static inline void rx_desc_set_length(uint32_t *desc, unsigned len) { desc[1] &= ~DESC_1_LENGTH; desc[1] |= len; } -static inline void rx_desc_set_broadcast(unsigned *desc) +static inline void rx_desc_set_broadcast(uint32_t *desc) { desc[1] |= R_DESC_1_RX_BROADCAST; } -static inline void rx_desc_set_unicast_hash(unsigned *desc) +static inline void rx_desc_set_unicast_hash(uint32_t *desc) { desc[1] |= R_DESC_1_RX_UNICAST_HASH; } -static inline void rx_desc_set_multicast_hash(unsigned *desc) +static inline void rx_desc_set_multicast_hash(uint32_t *desc) { desc[1] |= R_DESC_1_RX_MULTICAST_HASH; } -static inline void rx_desc_set_sar(unsigned *desc, int sar_idx) +static inline void rx_desc_set_sar(uint32_t *desc, int sar_idx) { desc[1] = deposit32(desc[1], R_DESC_1_RX_SAR_SHIFT, R_DESC_1_RX_SAR_LENGTH, sar_idx); @@ -1042,7 +1042,7 @@ static void gem_transmit_updatestats(CadenceGEMState *s, const uint8_t *packet, */ static void gem_transmit(CadenceGEMState *s) { - unsigned desc[2]; + uint32_t desc[2]; hwaddr packet_desc_addr; uint8_t tx_packet[2048]; uint8_t *p; @@ -1108,7 +1108,7 @@ static void gem_transmit(CadenceGEMState *s) /* Last descriptor for this packet; hand the whole thing off */ if (tx_desc_get_last(desc)) { - unsigned desc_first[2]; + uint32_t desc_first[2]; /* Modify the 1st descriptor of this packet to be owned by * the processor. diff --git a/include/hw/net/cadence_gem.h b/include/hw/net/cadence_gem.h index 35de622063..633d564dc3 100644 --- a/include/hw/net/cadence_gem.h +++ b/include/hw/net/cadence_gem.h @@ -74,7 +74,7 @@ typedef struct CadenceGEMState { uint8_t can_rx_state; /* Debug only */ - unsigned rx_desc[MAX_PRIORITY_QUEUES][2]; + uint32_t rx_desc[MAX_PRIORITY_QUEUES][2]; bool sar_active[4]; } CadenceGEMState; From 8568313f3bdf4bc1de7ace0eb5b92343fc19f3c8 Mon Sep 17 00:00:00 2001 From: "Edgar E. Iglesias" Date: Thu, 11 Oct 2018 04:19:23 +0200 Subject: [PATCH 08/17] net: cadence_gem: Add macro with max number of descriptor words MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Add macro with max number of DMA descriptor words. No functional change. Reviewed-by: Alistair Francis Reviewed-by: Philippe Mathieu-Daudé Signed-off-by: Edgar E. Iglesias Message-id: 20181011021931.4249-5-edgar.iglesias@gmail.com Signed-off-by: Peter Maydell --- hw/net/cadence_gem.c | 4 ++-- include/hw/net/cadence_gem.h | 5 ++++- 2 files changed, 6 insertions(+), 3 deletions(-) diff --git a/hw/net/cadence_gem.c b/hw/net/cadence_gem.c index d67249393c..a59a36eb5a 100644 --- a/hw/net/cadence_gem.c +++ b/hw/net/cadence_gem.c @@ -1042,7 +1042,7 @@ static void gem_transmit_updatestats(CadenceGEMState *s, const uint8_t *packet, */ static void gem_transmit(CadenceGEMState *s) { - uint32_t desc[2]; + uint32_t desc[DESC_MAX_NUM_WORDS]; hwaddr packet_desc_addr; uint8_t tx_packet[2048]; uint8_t *p; @@ -1108,7 +1108,7 @@ static void gem_transmit(CadenceGEMState *s) /* Last descriptor for this packet; hand the whole thing off */ if (tx_desc_get_last(desc)) { - uint32_t desc_first[2]; + uint32_t desc_first[DESC_MAX_NUM_WORDS]; /* Modify the 1st descriptor of this packet to be owned by * the processor. diff --git a/include/hw/net/cadence_gem.h b/include/hw/net/cadence_gem.h index 633d564dc3..b33ef6513b 100644 --- a/include/hw/net/cadence_gem.h +++ b/include/hw/net/cadence_gem.h @@ -32,6 +32,9 @@ #define CADENCE_GEM_MAXREG (0x00000800 / 4) /* Last valid GEM address */ +/* Max number of words in a DMA descriptor. */ +#define DESC_MAX_NUM_WORDS 2 + #define MAX_PRIORITY_QUEUES 8 #define MAX_TYPE1_SCREENERS 16 #define MAX_TYPE2_SCREENERS 16 @@ -74,7 +77,7 @@ typedef struct CadenceGEMState { uint8_t can_rx_state; /* Debug only */ - uint32_t rx_desc[MAX_PRIORITY_QUEUES][2]; + uint32_t rx_desc[MAX_PRIORITY_QUEUES][DESC_MAX_NUM_WORDS]; bool sar_active[4]; } CadenceGEMState; From e48fdd9d90423d1530b49bbd61b4bbcb49198b33 Mon Sep 17 00:00:00 2001 From: "Edgar E. Iglesias" Date: Thu, 11 Oct 2018 04:19:24 +0200 Subject: [PATCH 09/17] net: cadence_gem: Add support for extended descriptors Add support for extended descriptors with optional 64bit addressing and timestamping. QEMU will not yet provide timestamps (always leaving the valid timestamp bit as zero). Reviewed-by: Alistair Francis Signed-off-by: Edgar E. Iglesias Message-id: 20181011021931.4249-6-edgar.iglesias@gmail.com Signed-off-by: Peter Maydell --- hw/net/cadence_gem.c | 69 ++++++++++++++++++++++++++---------- include/hw/net/cadence_gem.h | 2 +- 2 files changed, 52 insertions(+), 19 deletions(-) diff --git a/hw/net/cadence_gem.c b/hw/net/cadence_gem.c index a59a36eb5a..fa79baf608 100644 --- a/hw/net/cadence_gem.c +++ b/hw/net/cadence_gem.c @@ -207,6 +207,9 @@ #define GEM_NWCFG_BCAST_REJ 0x00000020 /* Reject broadcast packets */ #define GEM_NWCFG_PROMISC 0x00000010 /* Accept all packets */ +#define GEM_DMACFG_ADDR_64B (1U << 30) +#define GEM_DMACFG_TX_BD_EXT (1U << 29) +#define GEM_DMACFG_RX_BD_EXT (1U << 28) #define GEM_DMACFG_RBUFSZ_M 0x00FF0000 /* DMA RX Buffer Size mask */ #define GEM_DMACFG_RBUFSZ_S 16 /* DMA RX Buffer Size shift */ #define GEM_DMACFG_RBUFSZ_MUL 64 /* DMA RX Buffer Size multiplier */ @@ -302,9 +305,14 @@ #define GEM_MODID_VALUE 0x00020118 -static inline unsigned tx_desc_get_buffer(uint32_t *desc) +static inline uint64_t tx_desc_get_buffer(CadenceGEMState *s, uint32_t *desc) { - return desc[0]; + uint64_t ret = desc[0]; + + if (s->regs[GEM_DMACFG] & GEM_DMACFG_ADDR_64B) { + ret |= (uint64_t)desc[2] << 32; + } + return ret; } static inline unsigned tx_desc_get_used(uint32_t *desc) @@ -347,9 +355,30 @@ static inline void print_gem_tx_desc(uint32_t *desc, uint8_t queue) DB_PRINT("length: %d\n", tx_desc_get_length(desc)); } -static inline unsigned rx_desc_get_buffer(uint32_t *desc) +static inline uint64_t rx_desc_get_buffer(CadenceGEMState *s, uint32_t *desc) { - return desc[0] & ~0x3UL; + uint64_t ret = desc[0] & ~0x3UL; + + if (s->regs[GEM_DMACFG] & GEM_DMACFG_ADDR_64B) { + ret |= (uint64_t)desc[2] << 32; + } + return ret; +} + +static inline int gem_get_desc_len(CadenceGEMState *s, bool rx_n_tx) +{ + int ret = 2; + + if (s->regs[GEM_DMACFG] & GEM_DMACFG_ADDR_64B) { + ret += 2; + } + if (s->regs[GEM_DMACFG] & (rx_n_tx ? GEM_DMACFG_RX_BD_EXT + : GEM_DMACFG_TX_BD_EXT)) { + ret += 2; + } + + assert(ret <= DESC_MAX_NUM_WORDS); + return ret; } static inline unsigned rx_desc_get_wrap(uint32_t *desc) @@ -419,7 +448,7 @@ static void gem_init_register_masks(CadenceGEMState *s) memset(&s->regs_ro[0], 0, sizeof(s->regs_ro)); s->regs_ro[GEM_NWCTRL] = 0xFFF80000; s->regs_ro[GEM_NWSTATUS] = 0xFFFFFFFF; - s->regs_ro[GEM_DMACFG] = 0xFE00F000; + s->regs_ro[GEM_DMACFG] = 0x8E00F000; s->regs_ro[GEM_TXSTATUS] = 0xFFFFFE08; s->regs_ro[GEM_RXQBASE] = 0x00000003; s->regs_ro[GEM_TXQBASE] = 0x00000003; @@ -807,7 +836,8 @@ static void gem_get_rx_desc(CadenceGEMState *s, int q) DB_PRINT("read descriptor 0x%x\n", (unsigned)s->rx_desc_addr[q]); /* read current descriptor */ cpu_physical_memory_read(s->rx_desc_addr[q], - (uint8_t *)s->rx_desc[q], sizeof(s->rx_desc[q])); + (uint8_t *)s->rx_desc[q], + sizeof(uint32_t) * gem_get_desc_len(s, true)); /* Descriptor owned by software ? */ if (rx_desc_get_ownership(s->rx_desc[q]) == 1) { @@ -926,9 +956,10 @@ static ssize_t gem_receive(NetClientState *nc, const uint8_t *buf, size_t size) rx_desc_get_buffer(s->rx_desc[q])); /* Copy packet data to emulated DMA buffer */ - cpu_physical_memory_write(rx_desc_get_buffer(s->rx_desc[q]) + - rxbuf_offset, - rxbuf_ptr, MIN(bytes_to_copy, rxbufsize)); + cpu_physical_memory_write(rx_desc_get_buffer(s, s->rx_desc[q]) + + rxbuf_offset, + rxbuf_ptr, + MIN(bytes_to_copy, rxbufsize)); rxbuf_ptr += MIN(bytes_to_copy, rxbufsize); bytes_to_copy -= MIN(bytes_to_copy, rxbufsize); @@ -964,7 +995,7 @@ static ssize_t gem_receive(NetClientState *nc, const uint8_t *buf, size_t size) /* Descriptor write-back. */ cpu_physical_memory_write(s->rx_desc_addr[q], (uint8_t *)s->rx_desc[q], - sizeof(s->rx_desc[q])); + sizeof(uint32_t) * gem_get_desc_len(s, true)); /* Next descriptor */ if (rx_desc_get_wrap(s->rx_desc[q])) { @@ -972,7 +1003,7 @@ static ssize_t gem_receive(NetClientState *nc, const uint8_t *buf, size_t size) s->rx_desc_addr[q] = s->regs[GEM_RXQBASE]; } else { DB_PRINT("incrementing RX descriptor list\n"); - s->rx_desc_addr[q] += 8; + s->rx_desc_addr[q] += 4 * gem_get_desc_len(s, true); } gem_get_rx_desc(s, q); @@ -1069,7 +1100,8 @@ static void gem_transmit(CadenceGEMState *s) DB_PRINT("read descriptor 0x%" HWADDR_PRIx "\n", packet_desc_addr); cpu_physical_memory_read(packet_desc_addr, - (uint8_t *)desc, sizeof(desc)); + (uint8_t *)desc, + sizeof(uint32_t) * gem_get_desc_len(s, false)); /* Handle all descriptors owned by hardware */ while (tx_desc_get_used(desc) == 0) { @@ -1082,7 +1114,7 @@ static void gem_transmit(CadenceGEMState *s) /* The real hardware would eat this (and possibly crash). * For QEMU let's lend a helping hand. */ - if ((tx_desc_get_buffer(desc) == 0) || + if ((tx_desc_get_buffer(s, desc) == 0) || (tx_desc_get_length(desc) == 0)) { DB_PRINT("Invalid TX descriptor @ 0x%x\n", (unsigned)packet_desc_addr); @@ -1101,7 +1133,7 @@ static void gem_transmit(CadenceGEMState *s) /* Gather this fragment of the packet from "dma memory" to our * contig buffer. */ - cpu_physical_memory_read(tx_desc_get_buffer(desc), p, + cpu_physical_memory_read(tx_desc_get_buffer(s, desc), p, tx_desc_get_length(desc)); p += tx_desc_get_length(desc); total_bytes += tx_desc_get_length(desc); @@ -1124,7 +1156,8 @@ static void gem_transmit(CadenceGEMState *s) if (tx_desc_get_wrap(desc)) { s->tx_desc_addr[q] = s->regs[GEM_TXQBASE]; } else { - s->tx_desc_addr[q] = packet_desc_addr + 8; + s->tx_desc_addr[q] = packet_desc_addr + + 4 * gem_get_desc_len(s, false); } DB_PRINT("TX descriptor next: 0x%08x\n", s->tx_desc_addr[q]); @@ -1168,11 +1201,11 @@ static void gem_transmit(CadenceGEMState *s) tx_desc_set_last(desc); packet_desc_addr = s->regs[GEM_TXQBASE]; } else { - packet_desc_addr += 8; + packet_desc_addr += 4 * gem_get_desc_len(s, false); } DB_PRINT("read descriptor 0x%" HWADDR_PRIx "\n", packet_desc_addr); - cpu_physical_memory_read(packet_desc_addr, - (uint8_t *)desc, sizeof(desc)); + cpu_physical_memory_read(packet_desc_addr, (uint8_t *)desc, + sizeof(uint32_t) * gem_get_desc_len(s, false)); } if (tx_desc_get_used(desc)) { diff --git a/include/hw/net/cadence_gem.h b/include/hw/net/cadence_gem.h index b33ef6513b..00dbf4f72e 100644 --- a/include/hw/net/cadence_gem.h +++ b/include/hw/net/cadence_gem.h @@ -33,7 +33,7 @@ #define CADENCE_GEM_MAXREG (0x00000800 / 4) /* Last valid GEM address */ /* Max number of words in a DMA descriptor. */ -#define DESC_MAX_NUM_WORDS 2 +#define DESC_MAX_NUM_WORDS 6 #define MAX_PRIORITY_QUEUES 8 #define MAX_TYPE1_SCREENERS 16 From 84aec8efd62052f6aeda570b328bc3ac484a1d30 Mon Sep 17 00:00:00 2001 From: "Edgar E. Iglesias" Date: Thu, 11 Oct 2018 04:19:25 +0200 Subject: [PATCH 10/17] net: cadence_gem: Add support for selecting the DMA MemoryRegion Add support for selecting the Memory Region that the GEM will do DMA to. Signed-off-by: Edgar E. Iglesias Reviewed-by: Alistair Francis Message-id: 20181011021931.4249-7-edgar.iglesias@gmail.com Signed-off-by: Peter Maydell --- hw/net/cadence_gem.c | 59 ++++++++++++++++++++++-------------- include/hw/net/cadence_gem.h | 2 ++ 2 files changed, 39 insertions(+), 22 deletions(-) diff --git a/hw/net/cadence_gem.c b/hw/net/cadence_gem.c index fa79baf608..3ea20d4b4f 100644 --- a/hw/net/cadence_gem.c +++ b/hw/net/cadence_gem.c @@ -28,6 +28,7 @@ #include "hw/net/cadence_gem.h" #include "qapi/error.h" #include "qemu/log.h" +#include "sysemu/dma.h" #include "net/checksum.h" #ifdef CADENCE_GEM_ERR_DEBUG @@ -835,9 +836,9 @@ static void gem_get_rx_desc(CadenceGEMState *s, int q) { DB_PRINT("read descriptor 0x%x\n", (unsigned)s->rx_desc_addr[q]); /* read current descriptor */ - cpu_physical_memory_read(s->rx_desc_addr[q], - (uint8_t *)s->rx_desc[q], - sizeof(uint32_t) * gem_get_desc_len(s, true)); + address_space_read(&s->dma_as, s->rx_desc_addr[q], MEMTXATTRS_UNSPECIFIED, + (uint8_t *)s->rx_desc[q], + sizeof(uint32_t) * gem_get_desc_len(s, true)); /* Descriptor owned by software ? */ if (rx_desc_get_ownership(s->rx_desc[q]) == 1) { @@ -956,10 +957,10 @@ static ssize_t gem_receive(NetClientState *nc, const uint8_t *buf, size_t size) rx_desc_get_buffer(s->rx_desc[q])); /* Copy packet data to emulated DMA buffer */ - cpu_physical_memory_write(rx_desc_get_buffer(s, s->rx_desc[q]) + + address_space_write(&s->dma_as, rx_desc_get_buffer(s, s->rx_desc[q]) + rxbuf_offset, - rxbuf_ptr, - MIN(bytes_to_copy, rxbufsize)); + MEMTXATTRS_UNSPECIFIED, rxbuf_ptr, + MIN(bytes_to_copy, rxbufsize)); rxbuf_ptr += MIN(bytes_to_copy, rxbufsize); bytes_to_copy -= MIN(bytes_to_copy, rxbufsize); @@ -993,9 +994,10 @@ static ssize_t gem_receive(NetClientState *nc, const uint8_t *buf, size_t size) } /* Descriptor write-back. */ - cpu_physical_memory_write(s->rx_desc_addr[q], - (uint8_t *)s->rx_desc[q], - sizeof(uint32_t) * gem_get_desc_len(s, true)); + address_space_write(&s->dma_as, s->rx_desc_addr[q], + MEMTXATTRS_UNSPECIFIED, + (uint8_t *)s->rx_desc[q], + sizeof(uint32_t) * gem_get_desc_len(s, true)); /* Next descriptor */ if (rx_desc_get_wrap(s->rx_desc[q])) { @@ -1099,9 +1101,9 @@ static void gem_transmit(CadenceGEMState *s) packet_desc_addr = s->tx_desc_addr[q]; DB_PRINT("read descriptor 0x%" HWADDR_PRIx "\n", packet_desc_addr); - cpu_physical_memory_read(packet_desc_addr, - (uint8_t *)desc, - sizeof(uint32_t) * gem_get_desc_len(s, false)); + address_space_read(&s->dma_as, packet_desc_addr, + MEMTXATTRS_UNSPECIFIED, (uint8_t *)desc, + sizeof(uint32_t) * gem_get_desc_len(s, false)); /* Handle all descriptors owned by hardware */ while (tx_desc_get_used(desc) == 0) { @@ -1133,8 +1135,9 @@ static void gem_transmit(CadenceGEMState *s) /* Gather this fragment of the packet from "dma memory" to our * contig buffer. */ - cpu_physical_memory_read(tx_desc_get_buffer(s, desc), p, - tx_desc_get_length(desc)); + address_space_read(&s->dma_as, tx_desc_get_buffer(s, desc), + MEMTXATTRS_UNSPECIFIED, + p, tx_desc_get_length(desc)); p += tx_desc_get_length(desc); total_bytes += tx_desc_get_length(desc); @@ -1145,13 +1148,15 @@ static void gem_transmit(CadenceGEMState *s) /* Modify the 1st descriptor of this packet to be owned by * the processor. */ - cpu_physical_memory_read(s->tx_desc_addr[q], - (uint8_t *)desc_first, - sizeof(desc_first)); + address_space_read(&s->dma_as, s->tx_desc_addr[q], + MEMTXATTRS_UNSPECIFIED, + (uint8_t *)desc_first, + sizeof(desc_first)); tx_desc_set_used(desc_first); - cpu_physical_memory_write(s->tx_desc_addr[q], - (uint8_t *)desc_first, - sizeof(desc_first)); + address_space_write(&s->dma_as, s->tx_desc_addr[q], + MEMTXATTRS_UNSPECIFIED, + (uint8_t *)desc_first, + sizeof(desc_first)); /* Advance the hardware current descriptor past this packet */ if (tx_desc_get_wrap(desc)) { s->tx_desc_addr[q] = s->regs[GEM_TXQBASE]; @@ -1204,8 +1209,9 @@ static void gem_transmit(CadenceGEMState *s) packet_desc_addr += 4 * gem_get_desc_len(s, false); } DB_PRINT("read descriptor 0x%" HWADDR_PRIx "\n", packet_desc_addr); - cpu_physical_memory_read(packet_desc_addr, (uint8_t *)desc, - sizeof(uint32_t) * gem_get_desc_len(s, false)); + address_space_read(&s->dma_as, packet_desc_addr, + MEMTXATTRS_UNSPECIFIED, (uint8_t *)desc, + sizeof(uint32_t) * gem_get_desc_len(s, false)); } if (tx_desc_get_used(desc)) { @@ -1496,6 +1502,9 @@ static void gem_realize(DeviceState *dev, Error **errp) CadenceGEMState *s = CADENCE_GEM(dev); int i; + address_space_init(&s->dma_as, + s->dma_mr ? s->dma_mr : get_system_memory(), "dma"); + if (s->num_priority_queues == 0 || s->num_priority_queues > MAX_PRIORITY_QUEUES) { error_setg(errp, "Invalid num-priority-queues value: %" PRIx8, @@ -1533,6 +1542,12 @@ static void gem_init(Object *obj) "enet", sizeof(s->regs)); sysbus_init_mmio(SYS_BUS_DEVICE(dev), &s->iomem); + + object_property_add_link(obj, "dma", TYPE_MEMORY_REGION, + (Object **)&s->dma_mr, + qdev_prop_allow_set_link_before_realize, + OBJ_PROP_LINK_STRONG, + &error_abort); } static const VMStateDescription vmstate_cadence_gem = { diff --git a/include/hw/net/cadence_gem.h b/include/hw/net/cadence_gem.h index 00dbf4f72e..5426961d91 100644 --- a/include/hw/net/cadence_gem.h +++ b/include/hw/net/cadence_gem.h @@ -45,6 +45,8 @@ typedef struct CadenceGEMState { /*< public >*/ MemoryRegion iomem; + MemoryRegion *dma_mr; + AddressSpace dma_as; NICState *nic; NICConf conf; qemu_irq irq[MAX_PRIORITY_QUEUES]; From 357aa01335bbf715b7ad1ef621e4bc96e2ffbe19 Mon Sep 17 00:00:00 2001 From: "Edgar E. Iglesias" Date: Thu, 11 Oct 2018 04:19:26 +0200 Subject: [PATCH 11/17] net: cadence_gem: Implement support for 64bit descriptor addresses Implement support for 64bit descriptor addresses. Reviewed-by: Alistair Francis Signed-off-by: Edgar E. Iglesias Message-id: 20181011021931.4249-8-edgar.iglesias@gmail.com Signed-off-by: Peter Maydell --- hw/net/cadence_gem.c | 47 ++++++++++++++++++++++++++++++++++++-------- 1 file changed, 39 insertions(+), 8 deletions(-) diff --git a/hw/net/cadence_gem.c b/hw/net/cadence_gem.c index 3ea20d4b4f..1795998928 100644 --- a/hw/net/cadence_gem.c +++ b/hw/net/cadence_gem.c @@ -153,6 +153,9 @@ #define GEM_RECEIVE_Q1_PTR (0x00000480 / 4) #define GEM_RECEIVE_Q7_PTR (GEM_RECEIVE_Q1_PTR + 6) +#define GEM_TBQPH (0x000004C8 / 4) +#define GEM_RBQPH (0x000004D4 / 4) + #define GEM_INT_Q1_ENABLE (0x00000600 / 4) #define GEM_INT_Q7_ENABLE (GEM_INT_Q1_ENABLE + 6) @@ -832,18 +835,42 @@ static int get_queue_from_screen(CadenceGEMState *s, uint8_t *rxbuf_ptr, return 0; } +static hwaddr gem_get_desc_addr(CadenceGEMState *s, bool tx, int q) +{ + hwaddr desc_addr = 0; + + if (s->regs[GEM_DMACFG] & GEM_DMACFG_ADDR_64B) { + desc_addr = s->regs[tx ? GEM_TBQPH : GEM_RBQPH]; + } + desc_addr <<= 32; + desc_addr |= tx ? s->tx_desc_addr[q] : s->rx_desc_addr[q]; + return desc_addr; +} + +static hwaddr gem_get_tx_desc_addr(CadenceGEMState *s, int q) +{ + return gem_get_desc_addr(s, true, q); +} + +static hwaddr gem_get_rx_desc_addr(CadenceGEMState *s, int q) +{ + return gem_get_desc_addr(s, false, q); +} + static void gem_get_rx_desc(CadenceGEMState *s, int q) { - DB_PRINT("read descriptor 0x%x\n", (unsigned)s->rx_desc_addr[q]); + hwaddr desc_addr = gem_get_rx_desc_addr(s, q); + + DB_PRINT("read descriptor 0x%" HWADDR_PRIx "\n", desc_addr); + /* read current descriptor */ - address_space_read(&s->dma_as, s->rx_desc_addr[q], MEMTXATTRS_UNSPECIFIED, + address_space_read(&s->dma_as, desc_addr, MEMTXATTRS_UNSPECIFIED, (uint8_t *)s->rx_desc[q], sizeof(uint32_t) * gem_get_desc_len(s, true)); /* Descriptor owned by software ? */ if (rx_desc_get_ownership(s->rx_desc[q]) == 1) { - DB_PRINT("descriptor 0x%x owned by sw.\n", - (unsigned)s->rx_desc_addr[q]); + DB_PRINT("descriptor 0x%" HWADDR_PRIx " owned by sw.\n", desc_addr); s->regs[GEM_RXSTATUS] |= GEM_RXSTATUS_NOBUF; s->regs[GEM_ISR] |= GEM_INT_RXUSED & ~(s->regs[GEM_IMR]); /* Handle interrupt consequences */ @@ -947,6 +974,8 @@ static ssize_t gem_receive(NetClientState *nc, const uint8_t *buf, size_t size) q = get_queue_from_screen(s, rxbuf_ptr, rxbufsize); while (bytes_to_copy) { + hwaddr desc_addr; + /* Do nothing if receive is not enabled. */ if (!gem_can_receive(nc)) { assert(!first_desc); @@ -994,7 +1023,8 @@ static ssize_t gem_receive(NetClientState *nc, const uint8_t *buf, size_t size) } /* Descriptor write-back. */ - address_space_write(&s->dma_as, s->rx_desc_addr[q], + desc_addr = gem_get_rx_desc_addr(s, q); + address_space_write(&s->dma_as, desc_addr, MEMTXATTRS_UNSPECIFIED, (uint8_t *)s->rx_desc[q], sizeof(uint32_t) * gem_get_desc_len(s, true)); @@ -1098,7 +1128,7 @@ static void gem_transmit(CadenceGEMState *s) for (q = s->num_priority_queues - 1; q >= 0; q--) { /* read current descriptor */ - packet_desc_addr = s->tx_desc_addr[q]; + packet_desc_addr = gem_get_tx_desc_addr(s, q); DB_PRINT("read descriptor 0x%" HWADDR_PRIx "\n", packet_desc_addr); address_space_read(&s->dma_as, packet_desc_addr, @@ -1144,16 +1174,17 @@ static void gem_transmit(CadenceGEMState *s) /* Last descriptor for this packet; hand the whole thing off */ if (tx_desc_get_last(desc)) { uint32_t desc_first[DESC_MAX_NUM_WORDS]; + hwaddr desc_addr = gem_get_tx_desc_addr(s, q); /* Modify the 1st descriptor of this packet to be owned by * the processor. */ - address_space_read(&s->dma_as, s->tx_desc_addr[q], + address_space_read(&s->dma_as, desc_addr, MEMTXATTRS_UNSPECIFIED, (uint8_t *)desc_first, sizeof(desc_first)); tx_desc_set_used(desc_first); - address_space_write(&s->dma_as, s->tx_desc_addr[q], + address_space_write(&s->dma_as, desc_addr, MEMTXATTRS_UNSPECIFIED, (uint8_t *)desc_first, sizeof(desc_first)); From 86278c33d1d71196f5e22ce3ce82a1b34a199754 Mon Sep 17 00:00:00 2001 From: "Edgar E. Iglesias" Date: Thu, 11 Oct 2018 04:19:28 +0200 Subject: [PATCH 12/17] target-arm: powerctl: Enable HVC when starting CPUs to EL2 When QEMU provides the equivalent of the EL3 firmware, we need to enable HVCs in scr_el3 when turning on CPUs that target EL2. Reviewed-by: Peter Maydell Signed-off-by: Edgar E. Iglesias Message-id: 20181011021931.4249-10-edgar.iglesias@gmail.com Signed-off-by: Peter Maydell --- target/arm/arm-powerctl.c | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/target/arm/arm-powerctl.c b/target/arm/arm-powerctl.c index ce55eeb682..2b856930fb 100644 --- a/target/arm/arm-powerctl.c +++ b/target/arm/arm-powerctl.c @@ -103,6 +103,16 @@ static void arm_set_cpu_on_async_work(CPUState *target_cpu_state, } else { /* Processor is not in secure mode */ target_cpu->env.cp15.scr_el3 |= SCR_NS; + + /* + * If QEMU is providing the equivalent of EL3 firmware, then we need + * to make sure a CPU targeting EL2 comes out of reset with a + * functional HVC insn. + */ + if (arm_feature(&target_cpu->env, ARM_FEATURE_EL3) + && info->target_el == 2) { + target_cpu->env.cp15.scr_el3 |= SCR_HCE; + } } /* We check if the started CPU is now at the correct level */ From f11b452b95df4a0fc6561c278721cad03b24098b Mon Sep 17 00:00:00 2001 From: "Edgar E. Iglesias" Date: Thu, 11 Oct 2018 04:19:29 +0200 Subject: [PATCH 13/17] target/arm: Add the Cortex-A72 Add the ARM Cortex-A72. Signed-off-by: Edgar E. Iglesias Message-id: 20181011021931.4249-11-edgar.iglesias@gmail.com Signed-off-by: Peter Maydell --- target/arm/cpu64.c | 66 +++++++++++++++++++++++++++++++++++++++++++--- 1 file changed, 63 insertions(+), 3 deletions(-) diff --git a/target/arm/cpu64.c b/target/arm/cpu64.c index db71504cb5..44fdf0f6fa 100644 --- a/target/arm/cpu64.c +++ b/target/arm/cpu64.c @@ -51,7 +51,7 @@ static uint64_t a57_a53_l2ctlr_read(CPUARMState *env, const ARMCPRegInfo *ri) } #endif -static const ARMCPRegInfo cortex_a57_a53_cp_reginfo[] = { +static const ARMCPRegInfo cortex_a72_a57_a53_cp_reginfo[] = { #ifndef CONFIG_USER_ONLY { .name = "L2CTLR_EL1", .state = ARM_CP_STATE_AA64, .opc0 = 3, .opc1 = 1, .crn = 11, .crm = 0, .opc2 = 2, @@ -156,7 +156,7 @@ static void aarch64_a57_initfn(Object *obj) cpu->gic_num_lrs = 4; cpu->gic_vpribits = 5; cpu->gic_vprebits = 5; - define_arm_cp_regs(cpu, cortex_a57_a53_cp_reginfo); + define_arm_cp_regs(cpu, cortex_a72_a57_a53_cp_reginfo); } static void aarch64_a53_initfn(Object *obj) @@ -215,7 +215,66 @@ static void aarch64_a53_initfn(Object *obj) cpu->gic_num_lrs = 4; cpu->gic_vpribits = 5; cpu->gic_vprebits = 5; - define_arm_cp_regs(cpu, cortex_a57_a53_cp_reginfo); + define_arm_cp_regs(cpu, cortex_a72_a57_a53_cp_reginfo); +} + +static void aarch64_a72_initfn(Object *obj) +{ + ARMCPU *cpu = ARM_CPU(obj); + + cpu->dtb_compatible = "arm,cortex-a72"; + set_feature(&cpu->env, ARM_FEATURE_V8); + set_feature(&cpu->env, ARM_FEATURE_VFP4); + set_feature(&cpu->env, ARM_FEATURE_NEON); + set_feature(&cpu->env, ARM_FEATURE_GENERIC_TIMER); + set_feature(&cpu->env, ARM_FEATURE_AARCH64); + set_feature(&cpu->env, ARM_FEATURE_CBAR_RO); + set_feature(&cpu->env, ARM_FEATURE_V8_AES); + set_feature(&cpu->env, ARM_FEATURE_V8_SHA1); + set_feature(&cpu->env, ARM_FEATURE_V8_SHA256); + set_feature(&cpu->env, ARM_FEATURE_V8_PMULL); + set_feature(&cpu->env, ARM_FEATURE_CRC); + set_feature(&cpu->env, ARM_FEATURE_EL2); + set_feature(&cpu->env, ARM_FEATURE_EL3); + set_feature(&cpu->env, ARM_FEATURE_PMU); + cpu->midr = 0x410fd083; + cpu->revidr = 0x00000000; + cpu->reset_fpsid = 0x41034080; + cpu->mvfr0 = 0x10110222; + cpu->mvfr1 = 0x12111111; + cpu->mvfr2 = 0x00000043; + cpu->ctr = 0x8444c004; + cpu->reset_sctlr = 0x00c50838; + cpu->id_pfr0 = 0x00000131; + cpu->id_pfr1 = 0x00011011; + cpu->id_dfr0 = 0x03010066; + cpu->id_afr0 = 0x00000000; + cpu->id_mmfr0 = 0x10201105; + cpu->id_mmfr1 = 0x40000000; + cpu->id_mmfr2 = 0x01260000; + cpu->id_mmfr3 = 0x02102211; + cpu->id_isar0 = 0x02101110; + cpu->id_isar1 = 0x13112111; + cpu->id_isar2 = 0x21232042; + cpu->id_isar3 = 0x01112131; + cpu->id_isar4 = 0x00011142; + cpu->id_isar5 = 0x00011121; + cpu->id_aa64pfr0 = 0x00002222; + cpu->id_aa64dfr0 = 0x10305106; + cpu->pmceid0 = 0x00000000; + cpu->pmceid1 = 0x00000000; + cpu->id_aa64isar0 = 0x00011120; + cpu->id_aa64mmfr0 = 0x00001124; + cpu->dbgdidr = 0x3516d000; + cpu->clidr = 0x0a200023; + cpu->ccsidr[0] = 0x701fe00a; /* 32KB L1 dcache */ + cpu->ccsidr[1] = 0x201fe012; /* 48KB L1 icache */ + cpu->ccsidr[2] = 0x707fe07a; /* 1MB L2 cache */ + cpu->dcz_blocksize = 4; /* 64 bytes */ + cpu->gic_num_lrs = 4; + cpu->gic_vpribits = 5; + cpu->gic_vprebits = 5; + define_arm_cp_regs(cpu, cortex_a72_a57_a53_cp_reginfo); } static void cpu_max_get_sve_vq(Object *obj, Visitor *v, const char *name, @@ -293,6 +352,7 @@ typedef struct ARMCPUInfo { static const ARMCPUInfo aarch64_cpus[] = { { .name = "cortex-a57", .initfn = aarch64_a57_initfn }, { .name = "cortex-a53", .initfn = aarch64_a53_initfn }, + { .name = "cortex-a72", .initfn = aarch64_a72_initfn }, { .name = "max", .initfn = aarch64_max_initfn }, { .name = NULL } }; From fc5f6856a02168864a5c1a46866a12839322222f Mon Sep 17 00:00:00 2001 From: Aaron Lindsay Date: Wed, 10 Oct 2018 16:37:22 -0400 Subject: [PATCH 14/17] target/arm: Mark PMINTENCLR and PMINTENCLR_EL1 accesses as possibly doing IO I previously fixed this for PMINTENSET_EL1, but missed these. Signed-off-by: Aaron Lindsay Signed-off-by: Aaron Lindsay Reviewed-by: Richard Henderson Message-id: 20181010203735.27918-2-aclindsa@gmail.com Signed-off-by: Peter Maydell --- target/arm/helper.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/target/arm/helper.c b/target/arm/helper.c index 0efbb5c76c..138a1f1540 100644 --- a/target/arm/helper.c +++ b/target/arm/helper.c @@ -1423,12 +1423,14 @@ static const ARMCPRegInfo v7_cp_reginfo[] = { .writefn = pmintenset_write, .raw_writefn = raw_write, .resetvalue = 0x0 }, { .name = "PMINTENCLR", .cp = 15, .crn = 9, .crm = 14, .opc1 = 0, .opc2 = 2, - .access = PL1_RW, .accessfn = access_tpm, .type = ARM_CP_ALIAS, + .access = PL1_RW, .accessfn = access_tpm, + .type = ARM_CP_ALIAS | ARM_CP_IO, .fieldoffset = offsetof(CPUARMState, cp15.c9_pminten), .writefn = pmintenclr_write, }, { .name = "PMINTENCLR_EL1", .state = ARM_CP_STATE_AA64, .opc0 = 3, .opc1 = 0, .crn = 9, .crm = 14, .opc2 = 2, - .access = PL1_RW, .accessfn = access_tpm, .type = ARM_CP_ALIAS, + .access = PL1_RW, .accessfn = access_tpm, + .type = ARM_CP_ALIAS | ARM_CP_IO, .fieldoffset = offsetof(CPUARMState, cp15.c9_pminten), .writefn = pmintenclr_write }, { .name = "CCSIDR", .state = ARM_CP_STATE_BOTH, From 599b71e277ac7e92807191b20b7163a28c5450ad Mon Sep 17 00:00:00 2001 From: Aaron Lindsay Date: Wed, 10 Oct 2018 16:37:23 -0400 Subject: [PATCH 15/17] target/arm: Mask PMOVSR writes based on supported counters This is an amendment to my earlier patch: commit 7ece99b17e832065236c07a158dfac62619ef99b Author: Aaron Lindsay Date: Thu Apr 26 11:04:39 2018 +0100 target/arm: Mask PMU register writes based on PMCR_EL0.N Signed-off-by: Aaron Lindsay Reviewed-by: Richard Henderson Message-id: 20181010203735.27918-3-aclindsa@gmail.com Signed-off-by: Peter Maydell --- target/arm/helper.c | 1 + 1 file changed, 1 insertion(+) diff --git a/target/arm/helper.c b/target/arm/helper.c index 138a1f1540..7a53098888 100644 --- a/target/arm/helper.c +++ b/target/arm/helper.c @@ -1179,6 +1179,7 @@ static void pmcntenclr_write(CPUARMState *env, const ARMCPRegInfo *ri, static void pmovsr_write(CPUARMState *env, const ARMCPRegInfo *ri, uint64_t value) { + value &= pmu_counter_mask(env); env->cp15.c9_pmovsr &= ~value; } From ab44c7b71fa683b9402bea0d367b87c881704188 Mon Sep 17 00:00:00 2001 From: Peter Maydell Date: Thu, 11 Oct 2018 18:20:57 +0100 Subject: [PATCH 16/17] target/arm: Initialize ARMMMUFaultInfo in v7m_stack_read/write The get_phys_addr() functions take a pointer to an ARMMMUFaultInfo struct, which they fill in only if a fault occurs. This means that the caller must always zero-initialize the struct before passing it in. We forgot to do this in v7m_stack_read() and v7m_stack_write(). Correct the error. Signed-off-by: Peter Maydell Reviewed-by: Richard Henderson Message-id: 20181011172057.9466-1-peter.maydell@linaro.org --- target/arm/helper.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/target/arm/helper.c b/target/arm/helper.c index 7a53098888..e3946562aa 100644 --- a/target/arm/helper.c +++ b/target/arm/helper.c @@ -6472,7 +6472,7 @@ static bool v7m_stack_write(ARMCPU *cpu, uint32_t addr, uint32_t value, target_ulong page_size; hwaddr physaddr; int prot; - ARMMMUFaultInfo fi; + ARMMMUFaultInfo fi = {}; bool secure = mmu_idx & ARM_MMU_IDX_M_S; int exc; bool exc_secure; @@ -6534,7 +6534,7 @@ static bool v7m_stack_read(ARMCPU *cpu, uint32_t *dest, uint32_t addr, target_ulong page_size; hwaddr physaddr; int prot; - ARMMMUFaultInfo fi; + ARMMMUFaultInfo fi = {}; bool secure = mmu_idx & ARM_MMU_IDX_M_S; int exc; bool exc_secure; From 2ef297af07196c29446556537861f8e7dfeeae7b Mon Sep 17 00:00:00 2001 From: Peter Maydell Date: Tue, 9 Oct 2018 19:16:12 +0100 Subject: [PATCH 17/17] coccinelle: new inplace-byteswaps.cocci to remove inplace-byteswapping calls Add a new Coccinelle script which replaces uses of the inplace byteswapping functions *_to_cpus() and cpu_to_*s() with their not-in-place equivalents. This is useful for where the swapping is done on members of a packed struct -- taking the address of the member to pass it to an inplace function is undefined behaviour in C. Signed-off-by: Peter Maydell Reviewed-by: Eric Blake Reviewed-by: Richard Henderson Message-id: 20181009181612.10633-1-peter.maydell@linaro.org --- scripts/coccinelle/inplace-byteswaps.cocci | 65 ++++++++++++++++++++++ 1 file changed, 65 insertions(+) create mode 100644 scripts/coccinelle/inplace-byteswaps.cocci diff --git a/scripts/coccinelle/inplace-byteswaps.cocci b/scripts/coccinelle/inplace-byteswaps.cocci new file mode 100644 index 0000000000..a869a90cbf --- /dev/null +++ b/scripts/coccinelle/inplace-byteswaps.cocci @@ -0,0 +1,65 @@ +// Replace uses of in-place byteswapping functions with calls to the +// equivalent not-in-place functions. This is necessary to avoid +// undefined behaviour if the expression being swapped is a field in a +// packed struct. + +@@ +expression E; +@@ +-be16_to_cpus(&E); ++E = be16_to_cpu(E); +@@ +expression E; +@@ +-be32_to_cpus(&E); ++E = be32_to_cpu(E); +@@ +expression E; +@@ +-be64_to_cpus(&E); ++E = be64_to_cpu(E); +@@ +expression E; +@@ +-cpu_to_be16s(&E); ++E = cpu_to_be16(E); +@@ +expression E; +@@ +-cpu_to_be32s(&E); ++E = cpu_to_be32(E); +@@ +expression E; +@@ +-cpu_to_be64s(&E); ++E = cpu_to_be64(E); +@@ +expression E; +@@ +-le16_to_cpus(&E); ++E = le16_to_cpu(E); +@@ +expression E; +@@ +-le32_to_cpus(&E); ++E = le32_to_cpu(E); +@@ +expression E; +@@ +-le64_to_cpus(&E); ++E = le64_to_cpu(E); +@@ +expression E; +@@ +-cpu_to_le16s(&E); ++E = cpu_to_le16(E); +@@ +expression E; +@@ +-cpu_to_le32s(&E); ++E = cpu_to_le32(E); +@@ +expression E; +@@ +-cpu_to_le64s(&E); ++E = cpu_to_le64(E);