From 8a21865157b4d234f0ea1a5862feb913813e9409 Mon Sep 17 00:00:00 2001 From: "Edgar E. Iglesias" Date: Thu, 5 Mar 2020 16:09:13 +0000 Subject: [PATCH 01/37] hw/arm: versal: Add support for the LPD ADMAs Add support for the Versal LPD ADMAs. Signed-off-by: Edgar E. Iglesias Reviewed-by: Francisco Iglesias Reviewed-by: KONRAD Frederic Reviewed-by: Luc Michel Signed-off-by: Peter Maydell --- hw/arm/xlnx-versal.c | 24 ++++++++++++++++++++++++ include/hw/arm/xlnx-versal.h | 6 ++++++ 2 files changed, 30 insertions(+) diff --git a/hw/arm/xlnx-versal.c b/hw/arm/xlnx-versal.c index 403fc7b881..cb0122a3a6 100644 --- a/hw/arm/xlnx-versal.c +++ b/hw/arm/xlnx-versal.c @@ -194,6 +194,29 @@ static void versal_create_gems(Versal *s, qemu_irq *pic) } } +static void versal_create_admas(Versal *s, qemu_irq *pic) +{ + int i; + + for (i = 0; i < ARRAY_SIZE(s->lpd.iou.adma); i++) { + char *name = g_strdup_printf("adma%d", i); + DeviceState *dev; + MemoryRegion *mr; + + dev = qdev_create(NULL, "xlnx.zdma"); + s->lpd.iou.adma[i] = SYS_BUS_DEVICE(dev); + object_property_add_child(OBJECT(s), name, OBJECT(dev), &error_fatal); + qdev_init_nofail(dev); + + mr = sysbus_mmio_get_region(s->lpd.iou.adma[i], 0); + memory_region_add_subregion(&s->mr_ps, + MM_ADMA_CH0 + i * MM_ADMA_CH0_SIZE, mr); + + sysbus_connect_irq(s->lpd.iou.adma[i], 0, pic[VERSAL_ADMA_IRQ_0 + i]); + g_free(name); + } +} + /* This takes the board allocated linear DDR memory and creates aliases * for each split DDR range/aperture on the Versal address map. */ @@ -275,6 +298,7 @@ static void versal_realize(DeviceState *dev, Error **errp) versal_create_apu_gic(s, pic); versal_create_uarts(s, pic); versal_create_gems(s, pic); + versal_create_admas(s, pic); versal_map_ddr(s); versal_unimp(s); diff --git a/include/hw/arm/xlnx-versal.h b/include/hw/arm/xlnx-versal.h index d844c4ffe4..6c0a692b2f 100644 --- a/include/hw/arm/xlnx-versal.h +++ b/include/hw/arm/xlnx-versal.h @@ -22,6 +22,7 @@ #define XLNX_VERSAL_NR_ACPUS 2 #define XLNX_VERSAL_NR_UARTS 2 #define XLNX_VERSAL_NR_GEMS 2 +#define XLNX_VERSAL_NR_ADMAS 8 #define XLNX_VERSAL_NR_IRQS 192 typedef struct Versal { @@ -50,6 +51,7 @@ typedef struct Versal { struct { SysBusDevice *uart[XLNX_VERSAL_NR_UARTS]; SysBusDevice *gem[XLNX_VERSAL_NR_GEMS]; + SysBusDevice *adma[XLNX_VERSAL_NR_ADMAS]; } iou; } lpd; @@ -74,6 +76,7 @@ typedef struct Versal { #define VERSAL_GEM0_WAKE_IRQ_0 57 #define VERSAL_GEM1_IRQ_0 58 #define VERSAL_GEM1_WAKE_IRQ_0 59 +#define VERSAL_ADMA_IRQ_0 60 /* Architecturally reserved IRQs suitable for virtualization. */ #define VERSAL_RSVD_IRQ_FIRST 111 @@ -96,6 +99,9 @@ typedef struct Versal { #define MM_GEM1 0xff0d0000U #define MM_GEM1_SIZE 0x10000 +#define MM_ADMA_CH0 0xffa80000U +#define MM_ADMA_CH0_SIZE 0x10000 + #define MM_OCM 0xfffc0000U #define MM_OCM_SIZE 0x40000 From ce5f4f01116b2002925877930d603690296be519 Mon Sep 17 00:00:00 2001 From: "Edgar E. Iglesias" Date: Thu, 5 Mar 2020 16:09:14 +0000 Subject: [PATCH 02/37] hw/arm: versal: Generate xlnx-versal-virt zdma FDT nodes Generate xlnx-versal-virt zdma FDT nodes. Signed-off-by: Edgar E. Iglesias Reviewed-by: Francisco Iglesias Reviewed-by: KONRAD Frederic Reviewed-by: Luc Michel Signed-off-by: Peter Maydell --- hw/arm/xlnx-versal-virt.c | 28 ++++++++++++++++++++++++++++ 1 file changed, 28 insertions(+) diff --git a/hw/arm/xlnx-versal-virt.c b/hw/arm/xlnx-versal-virt.c index e7f4ca8bf9..878a275140 100644 --- a/hw/arm/xlnx-versal-virt.c +++ b/hw/arm/xlnx-versal-virt.c @@ -229,6 +229,33 @@ static void fdt_add_gem_nodes(VersalVirt *s) } } +static void fdt_add_zdma_nodes(VersalVirt *s) +{ + const char clocknames[] = "clk_main\0clk_apb"; + const char compat[] = "xlnx,zynqmp-dma-1.0"; + int i; + + for (i = XLNX_VERSAL_NR_ADMAS - 1; i >= 0; i--) { + uint64_t addr = MM_ADMA_CH0 + MM_ADMA_CH0_SIZE * i; + char *name = g_strdup_printf("/dma@%" PRIx64, addr); + + qemu_fdt_add_subnode(s->fdt, name); + + qemu_fdt_setprop_cell(s->fdt, name, "xlnx,bus-width", 64); + qemu_fdt_setprop_cells(s->fdt, name, "clocks", + s->phandle.clk_25Mhz, s->phandle.clk_25Mhz); + qemu_fdt_setprop(s->fdt, name, "clock-names", + clocknames, sizeof(clocknames)); + qemu_fdt_setprop_cells(s->fdt, name, "interrupts", + GIC_FDT_IRQ_TYPE_SPI, VERSAL_ADMA_IRQ_0 + i, + GIC_FDT_IRQ_FLAGS_LEVEL_HI); + qemu_fdt_setprop_sized_cells(s->fdt, name, "reg", + 2, addr, 2, 0x1000); + qemu_fdt_setprop(s->fdt, name, "compatible", compat, sizeof(compat)); + g_free(name); + } +} + static void fdt_nop_memory_nodes(void *fdt, Error **errp) { Error *err = NULL; @@ -427,6 +454,7 @@ static void versal_virt_init(MachineState *machine) fdt_add_uart_nodes(s); fdt_add_gic_nodes(s); fdt_add_timer_nodes(s); + fdt_add_zdma_nodes(s); fdt_add_cpu_nodes(s, psci_conduit); fdt_add_clk_node(s, "/clk125", 125000000, s->phandle.clk_125Mhz); fdt_add_clk_node(s, "/clk25", 25000000, s->phandle.clk_25Mhz); From 41a4bf1feab098da4cd5495cd56a99b0339e2275 Mon Sep 17 00:00:00 2001 From: Peter Maydell Date: Thu, 5 Mar 2020 16:09:14 +0000 Subject: [PATCH 03/37] target/arm: Implement (trivially) ARMv8.2-TTCNP The ARMv8.2-TTCNP extension allows an implementation to optimize by sharing TLB entries between multiple cores, provided that software declares that it's ready to deal with this by setting a CnP bit in the TTBRn_ELx. It is mandatory from ARMv8.2 onward. For QEMU's TLB implementation, sharing TLB entries between different cores would not really benefit us and would be a lot of work to implement. So we implement this extension in the "trivial" manner: we allow the guest to set and read back the CnP bit, but don't change our behaviour (this is an architecturally valid implementation choice). The only code path which looks at the TTBRn_ELx values for the long-descriptor format where the CnP bit is defined is already doing enough masking to not get confused when the CnP bit at the bottom of the register is set, so we can simply add a comment noting why we're relying on that mask. Signed-off-by: Peter Maydell Reviewed-by: Richard Henderson Message-id: 20200225193822.18874-1-peter.maydell@linaro.org --- target/arm/cpu.c | 1 + target/arm/cpu64.c | 2 ++ target/arm/helper.c | 4 ++++ 3 files changed, 7 insertions(+) diff --git a/target/arm/cpu.c b/target/arm/cpu.c index e6016e33ce..de00a45e90 100644 --- a/target/arm/cpu.c +++ b/target/arm/cpu.c @@ -2702,6 +2702,7 @@ static void arm_max_initfn(Object *obj) t = cpu->isar.id_mmfr4; t = FIELD_DP32(t, ID_MMFR4, HPDS, 1); /* AA32HPD */ t = FIELD_DP32(t, ID_MMFR4, AC2, 1); /* ACTLR2, HACTLR2 */ + t = FIELD_DP32(t, ID_MMFR4, CNP, 1); /* TTCNP */ cpu->isar.id_mmfr4 = t; } #endif diff --git a/target/arm/cpu64.c b/target/arm/cpu64.c index b842e2b664..62d36f9e8d 100644 --- a/target/arm/cpu64.c +++ b/target/arm/cpu64.c @@ -677,6 +677,7 @@ static void aarch64_max_initfn(Object *obj) t = cpu->isar.id_aa64mmfr2; t = FIELD_DP64(t, ID_AA64MMFR2, UAO, 1); + t = FIELD_DP64(t, ID_AA64MMFR2, CNP, 1); /* TTCNP */ cpu->isar.id_aa64mmfr2 = t; /* Replicate the same data to the 32-bit id registers. */ @@ -704,6 +705,7 @@ static void aarch64_max_initfn(Object *obj) u = cpu->isar.id_mmfr4; u = FIELD_DP32(u, ID_MMFR4, HPDS, 1); /* AA32HPD */ u = FIELD_DP32(u, ID_MMFR4, AC2, 1); /* ACTLR2, HACTLR2 */ + u = FIELD_DP32(t, ID_MMFR4, CNP, 1); /* TTCNP */ cpu->isar.id_mmfr4 = u; u = cpu->isar.id_aa64dfr0; diff --git a/target/arm/helper.c b/target/arm/helper.c index 6be9ffa09e..4eaf7333c7 100644 --- a/target/arm/helper.c +++ b/target/arm/helper.c @@ -10591,6 +10591,10 @@ static bool get_phys_addr_lpae(CPUARMState *env, target_ulong address, /* Now we can extract the actual base address from the TTBR */ descaddr = extract64(ttbr, 0, 48); + /* + * We rely on this masking to clear the RES0 bits at the bottom of the TTBR + * and also to mask out CnP (bit 0) which could validly be non-zero. + */ descaddr &= ~indexmask; /* The address field in the descriptor goes up to bit 39 for ARMv7 From a2d3b8f24c53b3c7d4cf07cb92b2db42abf804d0 Mon Sep 17 00:00:00 2001 From: Eric Auger Date: Thu, 5 Mar 2020 16:09:14 +0000 Subject: [PATCH 04/37] hw/arm/smmu-common: a fix to smmu_find_smmu_pcibus MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Make sure a null SMMUPciBus is returned in case we were not able to identify a pci bus matching the @bus_num. This matches the fix done on intel iommu in commit: a2e1cd41ccfe796529abfd1b6aeb1dd4393762a2 Signed-off-by: Eric Auger Reviewed-by: Peter Xu Message-Id: <20200226172628.17449-1-eric.auger@redhat.com> Reviewed-by: Philippe Mathieu-Daudé Signed-off-by: Philippe Mathieu-Daudé Signed-off-by: Peter Maydell --- hw/arm/smmu-common.c | 1 + 1 file changed, 1 insertion(+) diff --git a/hw/arm/smmu-common.c b/hw/arm/smmu-common.c index 0f2573f004..67d7b2d0fd 100644 --- a/hw/arm/smmu-common.c +++ b/hw/arm/smmu-common.c @@ -301,6 +301,7 @@ SMMUPciBus *smmu_find_smmu_pcibus(SMMUState *s, uint8_t bus_num) return smmu_pci_bus; } } + smmu_pci_bus = NULL; } return smmu_pci_bus; } From 5ca0e6fec591fd07add84f1f28b5c95a494b8401 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Philippe=20Mathieu-Daud=C3=A9?= Date: Thu, 5 Mar 2020 16:09:14 +0000 Subject: [PATCH 05/37] hw/arm/smmu-common: Simplify smmu_find_smmu_pcibus() logic MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The smmu_find_smmu_pcibus() function was introduced (in commit cac994ef43b) in a code format that could return an incorrect pointer, which was then fixed by the previous commit. We could have avoided this by writing the if() statement differently. Do it now, in case this function is re-used. The code is easier to review (harder to miss bugs). Acked-by: Eric Auger Reviewed-by: Peter Xu Signed-off-by: Philippe Mathieu-Daudé Signed-off-by: Peter Maydell --- hw/arm/smmu-common.c | 25 +++++++++++++------------ 1 file changed, 13 insertions(+), 12 deletions(-) diff --git a/hw/arm/smmu-common.c b/hw/arm/smmu-common.c index 67d7b2d0fd..e13a5f4a7c 100644 --- a/hw/arm/smmu-common.c +++ b/hw/arm/smmu-common.c @@ -290,20 +290,21 @@ inline int smmu_ptw(SMMUTransCfg *cfg, dma_addr_t iova, IOMMUAccessFlags perm, SMMUPciBus *smmu_find_smmu_pcibus(SMMUState *s, uint8_t bus_num) { SMMUPciBus *smmu_pci_bus = s->smmu_pcibus_by_bus_num[bus_num]; + GHashTableIter iter; - if (!smmu_pci_bus) { - GHashTableIter iter; - - g_hash_table_iter_init(&iter, s->smmu_pcibus_by_busptr); - while (g_hash_table_iter_next(&iter, NULL, (void **)&smmu_pci_bus)) { - if (pci_bus_num(smmu_pci_bus->bus) == bus_num) { - s->smmu_pcibus_by_bus_num[bus_num] = smmu_pci_bus; - return smmu_pci_bus; - } - } - smmu_pci_bus = NULL; + if (smmu_pci_bus) { + return smmu_pci_bus; } - return smmu_pci_bus; + + g_hash_table_iter_init(&iter, s->smmu_pcibus_by_busptr); + while (g_hash_table_iter_next(&iter, NULL, (void **)&smmu_pci_bus)) { + if (pci_bus_num(smmu_pci_bus->bus) == bus_num) { + s->smmu_pcibus_by_bus_num[bus_num] = smmu_pci_bus; + return smmu_pci_bus; + } + } + + return NULL; } static AddressSpace *smmu_find_add_as(PCIBus *bus, void *opaque, int devfn) From b6cb2453da92e983ba99d1c7a39a629595e04bf6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Philippe=20Mathieu-Daud=C3=A9?= Date: Thu, 5 Mar 2020 16:09:14 +0000 Subject: [PATCH 06/37] hw/arm/gumstix: Simplify since the machines are little-endian only MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit As the Connex and Verdex machines only boot in little-endian, we can simplify the code. Reviewed-by: Peter Maydell Signed-off-by: Philippe Mathieu-Daudé Reviewed-by: Richard Henderson Signed-off-by: Peter Maydell --- hw/arm/gumstix.c | 16 ++-------------- 1 file changed, 2 insertions(+), 14 deletions(-) diff --git a/hw/arm/gumstix.c b/hw/arm/gumstix.c index f26a0e8010..3a4bc332c4 100644 --- a/hw/arm/gumstix.c +++ b/hw/arm/gumstix.c @@ -51,7 +51,6 @@ static void connex_init(MachineState *machine) { PXA2xxState *cpu; DriveInfo *dinfo; - int be; MemoryRegion *address_space_mem = get_system_memory(); uint32_t connex_rom = 0x01000000; @@ -66,14 +65,9 @@ static void connex_init(MachineState *machine) exit(1); } -#ifdef TARGET_WORDS_BIGENDIAN - be = 1; -#else - be = 0; -#endif if (!pflash_cfi01_register(0x00000000, "connext.rom", connex_rom, dinfo ? blk_by_legacy_dinfo(dinfo) : NULL, - sector_len, 2, 0, 0, 0, 0, be)) { + sector_len, 2, 0, 0, 0, 0, 0)) { error_report("Error registering flash memory"); exit(1); } @@ -87,7 +81,6 @@ static void verdex_init(MachineState *machine) { PXA2xxState *cpu; DriveInfo *dinfo; - int be; MemoryRegion *address_space_mem = get_system_memory(); uint32_t verdex_rom = 0x02000000; @@ -102,14 +95,9 @@ static void verdex_init(MachineState *machine) exit(1); } -#ifdef TARGET_WORDS_BIGENDIAN - be = 1; -#else - be = 0; -#endif if (!pflash_cfi01_register(0x00000000, "verdex.rom", verdex_rom, dinfo ? blk_by_legacy_dinfo(dinfo) : NULL, - sector_len, 2, 0, 0, 0, 0, be)) { + sector_len, 2, 0, 0, 0, 0, 0)) { error_report("Error registering flash memory"); exit(1); } From 8ad1b683fd5ef7334c32c3d17b7f11cbc24e2758 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Philippe=20Mathieu-Daud=C3=A9?= Date: Thu, 5 Mar 2020 16:09:15 +0000 Subject: [PATCH 07/37] hw/arm/mainstone: Simplify since the machines are little-endian only MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit We only build the little-endian softmmu configurations. Checking for big endian is pointless, remove the unused code. Signed-off-by: Philippe Mathieu-Daudé Reviewed-by: Richard Henderson Signed-off-by: Peter Maydell --- hw/arm/mainstone.c | 8 +------- 1 file changed, 1 insertion(+), 7 deletions(-) diff --git a/hw/arm/mainstone.c b/hw/arm/mainstone.c index 6e64dfab50..1042017086 100644 --- a/hw/arm/mainstone.c +++ b/hw/arm/mainstone.c @@ -119,7 +119,6 @@ static void mainstone_common_init(MemoryRegion *address_space_mem, DeviceState *mst_irq; DriveInfo *dinfo; int i; - int be; MemoryRegion *rom = g_new(MemoryRegion, 1); /* Setup CPU & memory */ @@ -130,11 +129,6 @@ static void mainstone_common_init(MemoryRegion *address_space_mem, memory_region_set_readonly(rom, true); memory_region_add_subregion(address_space_mem, 0, rom); -#ifdef TARGET_WORDS_BIGENDIAN - be = 1; -#else - be = 0; -#endif /* There are two 32MiB flash devices on the board */ for (i = 0; i < 2; i ++) { dinfo = drive_get(IF_PFLASH, 0, i); @@ -142,7 +136,7 @@ static void mainstone_common_init(MemoryRegion *address_space_mem, i ? "mainstone.flash1" : "mainstone.flash0", MAINSTONE_FLASH, dinfo ? blk_by_legacy_dinfo(dinfo) : NULL, - sector_len, 4, 0, 0, 0, 0, be)) { + sector_len, 4, 0, 0, 0, 0, 0)) { error_report("Error registering flash memory"); exit(1); } From 88e68dfcc5f72dc18b9ca82a69902cc3a3a80fd9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Philippe=20Mathieu-Daud=C3=A9?= Date: Thu, 5 Mar 2020 16:09:15 +0000 Subject: [PATCH 08/37] hw/arm/omap_sx1: Simplify since the machines are little-endian only MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit We only build the little-endian softmmu configurations. Checking for big endian is pointless, remove the unused code. Signed-off-by: Philippe Mathieu-Daudé Reviewed-by: Richard Henderson Signed-off-by: Peter Maydell --- hw/arm/omap_sx1.c | 11 ++--------- 1 file changed, 2 insertions(+), 9 deletions(-) diff --git a/hw/arm/omap_sx1.c b/hw/arm/omap_sx1.c index 2bebab4171..de5ff447dc 100644 --- a/hw/arm/omap_sx1.c +++ b/hw/arm/omap_sx1.c @@ -114,7 +114,6 @@ static void sx1_init(MachineState *machine, const int version) DriveInfo *dinfo; int fl_idx; uint32_t flash_size = flash0_size; - int be; if (machine->ram_size != mc->default_ram_size) { char *sz = size_to_str(mc->default_ram_size); @@ -154,17 +153,11 @@ static void sx1_init(MachineState *machine, const int version) OMAP_CS2_BASE, &cs[3]); fl_idx = 0; -#ifdef TARGET_WORDS_BIGENDIAN - be = 1; -#else - be = 0; -#endif - if ((dinfo = drive_get(IF_PFLASH, 0, fl_idx)) != NULL) { if (!pflash_cfi01_register(OMAP_CS0_BASE, "omap_sx1.flash0-1", flash_size, blk_by_legacy_dinfo(dinfo), - sector_size, 4, 0, 0, 0, 0, be)) { + sector_size, 4, 0, 0, 0, 0, 0)) { fprintf(stderr, "qemu: Error registering flash memory %d.\n", fl_idx); } @@ -187,7 +180,7 @@ static void sx1_init(MachineState *machine, const int version) if (!pflash_cfi01_register(OMAP_CS1_BASE, "omap_sx1.flash1-1", flash1_size, blk_by_legacy_dinfo(dinfo), - sector_size, 4, 0, 0, 0, 0, be)) { + sector_size, 4, 0, 0, 0, 0, 0)) { fprintf(stderr, "qemu: Error registering flash memory %d.\n", fl_idx); } From 56329e38e6572bc6714282ff9f9ac0d1ed4ff55a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Philippe=20Mathieu-Daud=C3=A9?= Date: Thu, 5 Mar 2020 16:09:15 +0000 Subject: [PATCH 09/37] hw/arm/z2: Simplify since the machines are little-endian only MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit We only build the little-endian softmmu configurations. Checking for big endian is pointless, remove the unused code. Signed-off-by: Philippe Mathieu-Daudé Reviewed-by: Richard Henderson Signed-off-by: Peter Maydell --- hw/arm/z2.c | 8 +------- 1 file changed, 1 insertion(+), 7 deletions(-) diff --git a/hw/arm/z2.c b/hw/arm/z2.c index 4bb237f22d..a0f4095990 100644 --- a/hw/arm/z2.c +++ b/hw/arm/z2.c @@ -300,7 +300,6 @@ static void z2_init(MachineState *machine) uint32_t sector_len = 0x10000; PXA2xxState *mpu; DriveInfo *dinfo; - int be; void *z2_lcd; I2CBus *bus; DeviceState *wm; @@ -308,15 +307,10 @@ static void z2_init(MachineState *machine) /* Setup CPU & memory */ mpu = pxa270_init(address_space_mem, z2_binfo.ram_size, machine->cpu_type); -#ifdef TARGET_WORDS_BIGENDIAN - be = 1; -#else - be = 0; -#endif dinfo = drive_get(IF_PFLASH, 0, 0); if (!pflash_cfi01_register(Z2_FLASH_BASE, "z2.flash0", Z2_FLASH_SIZE, dinfo ? blk_by_legacy_dinfo(dinfo) : NULL, - sector_len, 4, 0, 0, 0, 0, be)) { + sector_len, 4, 0, 0, 0, 0, 0)) { error_report("Error registering flash memory"); exit(1); } From 98335f61794d96e57dbd3f3f529b8c4c7d188ba3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Philippe=20Mathieu-Daud=C3=A9?= Date: Thu, 5 Mar 2020 16:09:15 +0000 Subject: [PATCH 10/37] hw/arm/musicpal: Simplify since the machines are little-endian only MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit We only build the little-endian softmmu configurations. Checking for big endian is pointless, remove the unused code. Signed-off-by: Philippe Mathieu-Daudé Reviewed-by: Richard Henderson Signed-off-by: Peter Maydell --- hw/arm/musicpal.c | 10 ---------- 1 file changed, 10 deletions(-) diff --git a/hw/arm/musicpal.c b/hw/arm/musicpal.c index db8b03cb83..b2d0cfdac8 100644 --- a/hw/arm/musicpal.c +++ b/hw/arm/musicpal.c @@ -1645,22 +1645,12 @@ static void musicpal_init(MachineState *machine) * 0xFF800000 (if there is 8 MB flash). So remap flash access if the * image is smaller than 32 MB. */ -#ifdef TARGET_WORDS_BIGENDIAN - pflash_cfi02_register(0x100000000ULL - MP_FLASH_SIZE_MAX, - "musicpal.flash", flash_size, - blk, 0x10000, - MP_FLASH_SIZE_MAX / flash_size, - 2, 0x00BF, 0x236D, 0x0000, 0x0000, - 0x5555, 0x2AAA, 1); -#else pflash_cfi02_register(0x100000000ULL - MP_FLASH_SIZE_MAX, "musicpal.flash", flash_size, blk, 0x10000, MP_FLASH_SIZE_MAX / flash_size, 2, 0x00BF, 0x236D, 0x0000, 0x0000, 0x5555, 0x2AAA, 0); -#endif - } sysbus_create_simple(TYPE_MV88W8618_FLASHCFG, MP_FLASHCFG_BASE, NULL); From 1afaadb592f3eeb7043a9fb7ae507862579ebf9d Mon Sep 17 00:00:00 2001 From: Pan Nengyuan Date: Thu, 5 Mar 2020 16:09:15 +0000 Subject: [PATCH 11/37] hw/arm/pxa2xx: move timer_new from init() into realize() to avoid memleaks There are some memleaks when we call 'device_list_properties'. This patch move timer_new from init into realize to fix it. Reported-by: Euler Robot Signed-off-by: Pan Nengyuan Message-id: 20200227025055.14341-3-pannengyuan@huawei.com Reviewed-by: Peter Maydell Signed-off-by: Peter Maydell --- hw/arm/pxa2xx.c | 17 +++++++++++------ 1 file changed, 11 insertions(+), 6 deletions(-) diff --git a/hw/arm/pxa2xx.c b/hw/arm/pxa2xx.c index b33f8f1351..56a36202d7 100644 --- a/hw/arm/pxa2xx.c +++ b/hw/arm/pxa2xx.c @@ -1134,18 +1134,22 @@ static void pxa2xx_rtc_init(Object *obj) s->last_rtcpicr = 0; s->last_hz = s->last_sw = s->last_pi = qemu_clock_get_ms(rtc_clock); + sysbus_init_irq(dev, &s->rtc_irq); + + memory_region_init_io(&s->iomem, obj, &pxa2xx_rtc_ops, s, + "pxa2xx-rtc", 0x10000); + sysbus_init_mmio(dev, &s->iomem); +} + +static void pxa2xx_rtc_realize(DeviceState *dev, Error **errp) +{ + PXA2xxRTCState *s = PXA2XX_RTC(dev); s->rtc_hz = timer_new_ms(rtc_clock, pxa2xx_rtc_hz_tick, s); s->rtc_rdal1 = timer_new_ms(rtc_clock, pxa2xx_rtc_rdal1_tick, s); s->rtc_rdal2 = timer_new_ms(rtc_clock, pxa2xx_rtc_rdal2_tick, s); s->rtc_swal1 = timer_new_ms(rtc_clock, pxa2xx_rtc_swal1_tick, s); s->rtc_swal2 = timer_new_ms(rtc_clock, pxa2xx_rtc_swal2_tick, s); s->rtc_pi = timer_new_ms(rtc_clock, pxa2xx_rtc_pi_tick, s); - - sysbus_init_irq(dev, &s->rtc_irq); - - memory_region_init_io(&s->iomem, obj, &pxa2xx_rtc_ops, s, - "pxa2xx-rtc", 0x10000); - sysbus_init_mmio(dev, &s->iomem); } static int pxa2xx_rtc_pre_save(void *opaque) @@ -1203,6 +1207,7 @@ static void pxa2xx_rtc_sysbus_class_init(ObjectClass *klass, void *data) dc->desc = "PXA2xx RTC Controller"; dc->vmsd = &vmstate_pxa2xx_rtc_regs; + dc->realize = pxa2xx_rtc_realize; } static const TypeInfo pxa2xx_rtc_sysbus_info = { From 5719f9745ef54c1b644e3df0bc69869be70cf810 Mon Sep 17 00:00:00 2001 From: Pan Nengyuan Date: Thu, 5 Mar 2020 16:09:16 +0000 Subject: [PATCH 12/37] hw/arm/spitz: move timer_new from init() into realize() to avoid memleaks There are some memleaks when we call 'device_list_properties'. This patch move timer_new from init into realize to fix it. Reported-by: Euler Robot Signed-off-by: Pan Nengyuan Message-id: 20200227025055.14341-4-pannengyuan@huawei.com Reviewed-by: Peter Maydell Signed-off-by: Peter Maydell --- hw/arm/spitz.c | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/hw/arm/spitz.c b/hw/arm/spitz.c index e001088103..cbfa6934cf 100644 --- a/hw/arm/spitz.c +++ b/hw/arm/spitz.c @@ -524,11 +524,16 @@ static void spitz_keyboard_init(Object *obj) spitz_keyboard_pre_map(s); - s->kbdtimer = timer_new_ns(QEMU_CLOCK_VIRTUAL, spitz_keyboard_tick, s); qdev_init_gpio_in(dev, spitz_keyboard_strobe, SPITZ_KEY_STROBE_NUM); qdev_init_gpio_out(dev, s->sense, SPITZ_KEY_SENSE_NUM); } +static void spitz_keyboard_realize(DeviceState *dev, Error **errp) +{ + SpitzKeyboardState *s = SPITZ_KEYBOARD(dev); + s->kbdtimer = timer_new_ns(QEMU_CLOCK_VIRTUAL, spitz_keyboard_tick, s); +} + /* LCD backlight controller */ #define LCDTG_RESCTL 0x00 @@ -1115,6 +1120,7 @@ static void spitz_keyboard_class_init(ObjectClass *klass, void *data) DeviceClass *dc = DEVICE_CLASS(klass); dc->vmsd = &vmstate_spitz_kbd; + dc->realize = spitz_keyboard_realize; } static const TypeInfo spitz_keyboard_info = { From efb27a49af974baaad602ed26ef999f567063f12 Mon Sep 17 00:00:00 2001 From: Pan Nengyuan Date: Thu, 5 Mar 2020 16:09:16 +0000 Subject: [PATCH 13/37] hw/arm/strongarm: move timer_new from init() into realize() to avoid memleaks There are some memleaks when we call 'device_list_properties'. This patch move timer_new from init into realize to fix it. Reported-by: Euler Robot Signed-off-by: Pan Nengyuan Message-id: 20200227025055.14341-5-pannengyuan@huawei.com Reviewed-by: Peter Maydell Signed-off-by: Peter Maydell --- hw/arm/strongarm.c | 18 ++++++++++++------ 1 file changed, 12 insertions(+), 6 deletions(-) diff --git a/hw/arm/strongarm.c b/hw/arm/strongarm.c index cd8a99aaf2..3010d765bb 100644 --- a/hw/arm/strongarm.c +++ b/hw/arm/strongarm.c @@ -399,9 +399,6 @@ static void strongarm_rtc_init(Object *obj) s->last_rcnr = (uint32_t) mktimegm(&tm); s->last_hz = qemu_clock_get_ms(rtc_clock); - s->rtc_alarm = timer_new_ms(rtc_clock, strongarm_rtc_alarm_tick, s); - s->rtc_hz = timer_new_ms(rtc_clock, strongarm_rtc_hz_tick, s); - sysbus_init_irq(dev, &s->rtc_irq); sysbus_init_irq(dev, &s->rtc_hz_irq); @@ -410,6 +407,13 @@ static void strongarm_rtc_init(Object *obj) sysbus_init_mmio(dev, &s->iomem); } +static void strongarm_rtc_realize(DeviceState *dev, Error **errp) +{ + StrongARMRTCState *s = STRONGARM_RTC(dev); + s->rtc_alarm = timer_new_ms(rtc_clock, strongarm_rtc_alarm_tick, s); + s->rtc_hz = timer_new_ms(rtc_clock, strongarm_rtc_hz_tick, s); +} + static int strongarm_rtc_pre_save(void *opaque) { StrongARMRTCState *s = opaque; @@ -451,6 +455,7 @@ static void strongarm_rtc_sysbus_class_init(ObjectClass *klass, void *data) dc->desc = "StrongARM RTC Controller"; dc->vmsd = &vmstate_strongarm_rtc_regs; + dc->realize = strongarm_rtc_realize; } static const TypeInfo strongarm_rtc_sysbus_info = { @@ -1240,15 +1245,16 @@ static void strongarm_uart_init(Object *obj) "uart", 0x10000); sysbus_init_mmio(dev, &s->iomem); sysbus_init_irq(dev, &s->irq); - - s->rx_timeout_timer = timer_new_ns(QEMU_CLOCK_VIRTUAL, strongarm_uart_rx_to, s); - s->tx_timer = timer_new_ns(QEMU_CLOCK_VIRTUAL, strongarm_uart_tx, s); } static void strongarm_uart_realize(DeviceState *dev, Error **errp) { StrongARMUARTState *s = STRONGARM_UART(dev); + s->rx_timeout_timer = timer_new_ns(QEMU_CLOCK_VIRTUAL, + strongarm_uart_rx_to, + s); + s->tx_timer = timer_new_ns(QEMU_CLOCK_VIRTUAL, strongarm_uart_tx, s); qemu_chr_fe_set_handlers(&s->chr, strongarm_uart_can_receive, strongarm_uart_receive, From f4228077e80cb30811e185d5330d2df778e667b3 Mon Sep 17 00:00:00 2001 From: Pan Nengyuan Date: Thu, 5 Mar 2020 16:09:16 +0000 Subject: [PATCH 14/37] hw/timer/cadence_ttc: move timer_new from init() into realize() to avoid memleaks There are some memleaks when we call 'device_list_properties'. This patch move timer_new from init into realize to fix it. Reported-by: Euler Robot Signed-off-by: Pan Nengyuan Reviewed-by: Alistair Francis Message-id: 20200227025055.14341-7-pannengyuan@huawei.com Reviewed-by: Peter Maydell Signed-off-by: Peter Maydell --- hw/timer/cadence_ttc.c | 18 ++++++++++++------ 1 file changed, 12 insertions(+), 6 deletions(-) diff --git a/hw/timer/cadence_ttc.c b/hw/timer/cadence_ttc.c index 5e3128c1e3..b0ba6b2bba 100644 --- a/hw/timer/cadence_ttc.c +++ b/hw/timer/cadence_ttc.c @@ -412,18 +412,23 @@ static void cadence_timer_init(uint32_t freq, CadenceTimerState *s) static void cadence_ttc_init(Object *obj) { CadenceTTCState *s = CADENCE_TTC(obj); - int i; - - for (i = 0; i < 3; ++i) { - cadence_timer_init(133000000, &s->timer[i]); - sysbus_init_irq(SYS_BUS_DEVICE(obj), &s->timer[i].irq); - } memory_region_init_io(&s->iomem, obj, &cadence_ttc_ops, s, "timer", 0x1000); sysbus_init_mmio(SYS_BUS_DEVICE(obj), &s->iomem); } +static void cadence_ttc_realize(DeviceState *dev, Error **errp) +{ + CadenceTTCState *s = CADENCE_TTC(dev); + int i; + + for (i = 0; i < 3; ++i) { + cadence_timer_init(133000000, &s->timer[i]); + sysbus_init_irq(SYS_BUS_DEVICE(dev), &s->timer[i].irq); + } +} + static int cadence_timer_pre_save(void *opaque) { cadence_timer_sync((CadenceTimerState *)opaque); @@ -479,6 +484,7 @@ static void cadence_ttc_class_init(ObjectClass *klass, void *data) DeviceClass *dc = DEVICE_CLASS(klass); dc->vmsd = &vmstate_cadence_ttc; + dc->realize = cadence_ttc_realize; } static const TypeInfo cadence_ttc_info = { From d1fb4da208411ce7b3dafb9f9e7726ebcec14edb Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Thu, 5 Mar 2020 16:09:16 +0000 Subject: [PATCH 15/37] target/arm: Improve masking of HCR/HCR2 RES0 bits Don't merely start with v8.0, handle v7VE as well. Ensure that writes from aarch32 mode do not change bits in the other half of the register. Protect reads of aa64 id registers with ARM_FEATURE_AARCH64. Suggested-by: Peter Maydell Signed-off-by: Richard Henderson Message-id: 20200229012811.24129-2-richard.henderson@linaro.org Reviewed-by: Peter Maydell Signed-off-by: Peter Maydell --- target/arm/helper.c | 38 +++++++++++++++++++++++++------------- 1 file changed, 25 insertions(+), 13 deletions(-) diff --git a/target/arm/helper.c b/target/arm/helper.c index 4eaf7333c7..19a8be8493 100644 --- a/target/arm/helper.c +++ b/target/arm/helper.c @@ -5086,11 +5086,15 @@ static const ARMCPRegInfo el3_no_el2_v8_cp_reginfo[] = { REGINFO_SENTINEL }; -static void hcr_write(CPUARMState *env, const ARMCPRegInfo *ri, uint64_t value) +static void do_hcr_write(CPUARMState *env, uint64_t value, uint64_t valid_mask) { ARMCPU *cpu = env_archcpu(env); - /* Begin with bits defined in base ARMv8.0. */ - uint64_t valid_mask = MAKE_64BIT_MASK(0, 34); + + if (arm_feature(env, ARM_FEATURE_V8)) { + valid_mask |= MAKE_64BIT_MASK(0, 34); /* ARMv8.0 */ + } else { + valid_mask |= MAKE_64BIT_MASK(0, 28); /* ARMv7VE */ + } if (arm_feature(env, ARM_FEATURE_EL3)) { valid_mask &= ~HCR_HCD; @@ -5104,14 +5108,17 @@ static void hcr_write(CPUARMState *env, const ARMCPRegInfo *ri, uint64_t value) */ valid_mask &= ~HCR_TSC; } - if (cpu_isar_feature(aa64_vh, cpu)) { - valid_mask |= HCR_E2H; - } - if (cpu_isar_feature(aa64_lor, cpu)) { - valid_mask |= HCR_TLOR; - } - if (cpu_isar_feature(aa64_pauth, cpu)) { - valid_mask |= HCR_API | HCR_APK; + + if (arm_feature(env, ARM_FEATURE_AARCH64)) { + if (cpu_isar_feature(aa64_vh, cpu)) { + valid_mask |= HCR_E2H; + } + if (cpu_isar_feature(aa64_lor, cpu)) { + valid_mask |= HCR_TLOR; + } + if (cpu_isar_feature(aa64_pauth, cpu)) { + valid_mask |= HCR_API | HCR_APK; + } } /* Clear RES0 bits. */ @@ -5143,12 +5150,17 @@ static void hcr_write(CPUARMState *env, const ARMCPRegInfo *ri, uint64_t value) arm_cpu_update_vfiq(cpu); } +static void hcr_write(CPUARMState *env, const ARMCPRegInfo *ri, uint64_t value) +{ + do_hcr_write(env, value, 0); +} + static void hcr_writehigh(CPUARMState *env, const ARMCPRegInfo *ri, uint64_t value) { /* Handle HCR2 write, i.e. write to high half of HCR_EL2 */ value = deposit64(env->cp15.hcr_el2, 32, 32, value); - hcr_write(env, NULL, value); + do_hcr_write(env, value, MAKE_64BIT_MASK(0, 32)); } static void hcr_writelow(CPUARMState *env, const ARMCPRegInfo *ri, @@ -5156,7 +5168,7 @@ static void hcr_writelow(CPUARMState *env, const ARMCPRegInfo *ri, { /* Handle HCR write, i.e. write to low half of HCR_EL2 */ value = deposit64(env->cp15.hcr_el2, 0, 32, value); - hcr_write(env, NULL, value); + do_hcr_write(env, value, MAKE_64BIT_MASK(32, 32)); } /* From e0a38bb35aa930c2d3b9982914297f0c0e8fd5c8 Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Thu, 5 Mar 2020 16:09:16 +0000 Subject: [PATCH 16/37] target/arm: Add HCR_EL2 bit definitions from ARMv8.6 Signed-off-by: Richard Henderson Message-id: 20200229012811.24129-3-richard.henderson@linaro.org Reviewed-by: Peter Maydell Signed-off-by: Peter Maydell --- target/arm/cpu.h | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/target/arm/cpu.h b/target/arm/cpu.h index 0b84742b66..0ae07a72e4 100644 --- a/target/arm/cpu.h +++ b/target/arm/cpu.h @@ -1410,6 +1410,7 @@ static inline void xpsr_write(CPUARMState *env, uint32_t val, uint32_t mask) #define HCR_TERR (1ULL << 36) #define HCR_TEA (1ULL << 37) #define HCR_MIOCNCE (1ULL << 38) +/* RES0 bit 39 */ #define HCR_APK (1ULL << 40) #define HCR_API (1ULL << 41) #define HCR_NV (1ULL << 42) @@ -1418,13 +1419,19 @@ static inline void xpsr_write(CPUARMState *env, uint32_t val, uint32_t mask) #define HCR_NV2 (1ULL << 45) #define HCR_FWB (1ULL << 46) #define HCR_FIEN (1ULL << 47) +/* RES0 bit 48 */ #define HCR_TID4 (1ULL << 49) #define HCR_TICAB (1ULL << 50) +#define HCR_AMVOFFEN (1ULL << 51) #define HCR_TOCU (1ULL << 52) +#define HCR_ENSCXT (1ULL << 53) #define HCR_TTLBIS (1ULL << 54) #define HCR_TTLBOS (1ULL << 55) #define HCR_ATA (1ULL << 56) #define HCR_DCT (1ULL << 57) +#define HCR_TID5 (1ULL << 58) +#define HCR_TWEDEN (1ULL << 59) +#define HCR_TWEDEL MAKE_64BIT_MASK(60, 4) #define SCR_NS (1U << 0) #define SCR_IRQ (1U << 1) From 45ca3a14081e069722a12db1c12facb3a73ed562 Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Thu, 5 Mar 2020 16:09:17 +0000 Subject: [PATCH 17/37] target/arm: Disable has_el2 and has_el3 for user-only In arm_cpu_reset, we configure many system registers so that user-only behaves as it should with a minimum of ifdefs. However, we do not set all of the system registers as required for a cpu with EL2 and EL3. Disabling EL2 and EL3 mean that we will not look at those registers, which means that we don't have to worry about configuring them. Signed-off-by: Richard Henderson Message-id: 20200229012811.24129-4-richard.henderson@linaro.org Reviewed-by: Peter Maydell Signed-off-by: Peter Maydell --- target/arm/cpu.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/target/arm/cpu.c b/target/arm/cpu.c index de00a45e90..185a46f5ab 100644 --- a/target/arm/cpu.c +++ b/target/arm/cpu.c @@ -1103,11 +1103,13 @@ static Property arm_cpu_reset_hivecs_property = static Property arm_cpu_rvbar_property = DEFINE_PROP_UINT64("rvbar", ARMCPU, rvbar, 0); +#ifndef CONFIG_USER_ONLY static Property arm_cpu_has_el2_property = DEFINE_PROP_BOOL("has_el2", ARMCPU, has_el2, true); static Property arm_cpu_has_el3_property = DEFINE_PROP_BOOL("has_el3", ARMCPU, has_el3, true); +#endif static Property arm_cpu_cfgend_property = DEFINE_PROP_BOOL("cfgend", ARMCPU, cfgend, false); @@ -1222,25 +1224,25 @@ void arm_cpu_post_init(Object *obj) qdev_property_add_static(DEVICE(obj), &arm_cpu_rvbar_property); } +#ifndef CONFIG_USER_ONLY if (arm_feature(&cpu->env, ARM_FEATURE_EL3)) { /* Add the has_el3 state CPU property only if EL3 is allowed. This will * prevent "has_el3" from existing on CPUs which cannot support EL3. */ qdev_property_add_static(DEVICE(obj), &arm_cpu_has_el3_property); -#ifndef CONFIG_USER_ONLY object_property_add_link(obj, "secure-memory", TYPE_MEMORY_REGION, (Object **)&cpu->secure_memory, qdev_prop_allow_set_link_before_realize, OBJ_PROP_LINK_STRONG, &error_abort); -#endif } if (arm_feature(&cpu->env, ARM_FEATURE_EL2)) { qdev_property_add_static(DEVICE(obj), &arm_cpu_has_el2_property); } +#endif if (arm_feature(&cpu->env, ARM_FEATURE_PMU)) { cpu->has_pmu = true; From a6c2b338113a710dbd97e5c35baf66354d615d1f Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Thu, 5 Mar 2020 16:09:17 +0000 Subject: [PATCH 18/37] target/arm: Remove EL2 and EL3 setup from user-only We have disabled EL2 and EL3 for user-only, which means that these registers "don't exist" and should not be set. Signed-off-by: Richard Henderson Message-id: 20200229012811.24129-5-richard.henderson@linaro.org Reviewed-by: Peter Maydell Signed-off-by: Peter Maydell --- target/arm/cpu.c | 6 ------ 1 file changed, 6 deletions(-) diff --git a/target/arm/cpu.c b/target/arm/cpu.c index 185a46f5ab..3623ecefbd 100644 --- a/target/arm/cpu.c +++ b/target/arm/cpu.c @@ -191,19 +191,13 @@ static void arm_cpu_reset(CPUState *s) /* Enable all PAC keys. */ env->cp15.sctlr_el[1] |= (SCTLR_EnIA | SCTLR_EnIB | SCTLR_EnDA | SCTLR_EnDB); - /* Enable all PAC instructions */ - env->cp15.hcr_el2 |= HCR_API; - env->cp15.scr_el3 |= SCR_API; /* and to the FP/Neon instructions */ env->cp15.cpacr_el1 = deposit64(env->cp15.cpacr_el1, 20, 2, 3); /* and to the SVE instructions */ env->cp15.cpacr_el1 = deposit64(env->cp15.cpacr_el1, 16, 2, 3); - env->cp15.cptr_el[3] |= CPTR_EZ; /* with maximum vector length */ env->vfp.zcr_el[1] = cpu_isar_feature(aa64_sve, cpu) ? cpu->sve_max_vq - 1 : 0; - env->vfp.zcr_el[2] = env->vfp.zcr_el[1]; - env->vfp.zcr_el[3] = env->vfp.zcr_el[1]; /* * Enable TBI0 and TBI1. While the real kernel only enables TBI0, * turning on both here will produce smaller code and otherwise From 4990e1d3c128580dd2fa0bbb1a42b6d63ba1ac28 Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Thu, 5 Mar 2020 16:09:17 +0000 Subject: [PATCH 19/37] target/arm: Improve masking in arm_hcr_el2_eff Update the {TGE,E2H} == '11' masking to ARMv8.6. If EL2 is configured for aarch32, disable all of the bits that are RES0 in aarch32 mode. Signed-off-by: Richard Henderson Message-id: 20200229012811.24129-6-richard.henderson@linaro.org Reviewed-by: Peter Maydell Signed-off-by: Peter Maydell --- target/arm/helper.c | 31 +++++++++++++++++++++++++++---- 1 file changed, 27 insertions(+), 4 deletions(-) diff --git a/target/arm/helper.c b/target/arm/helper.c index 19a8be8493..4ddb9443fb 100644 --- a/target/arm/helper.c +++ b/target/arm/helper.c @@ -5196,14 +5196,37 @@ uint64_t arm_hcr_el2_eff(CPUARMState *env) * Since the v8.4 language applies to the entire register, and * appears to be backward compatible, use that. */ - ret = 0; - } else if (ret & HCR_TGE) { - /* These bits are up-to-date as of ARMv8.4. */ + return 0; + } + + /* + * For a cpu that supports both aarch64 and aarch32, we can set bits + * in HCR_EL2 (e.g. via EL3) that are RES0 when we enter EL2 as aa32. + * Ignore all of the bits in HCR+HCR2 that are not valid for aarch32. + */ + if (!arm_el_is_aa64(env, 2)) { + uint64_t aa32_valid; + + /* + * These bits are up-to-date as of ARMv8.6. + * For HCR, it's easiest to list just the 2 bits that are invalid. + * For HCR2, list those that are valid. + */ + aa32_valid = MAKE_64BIT_MASK(0, 32) & ~(HCR_RW | HCR_TDZ); + aa32_valid |= (HCR_CD | HCR_ID | HCR_TERR | HCR_TEA | HCR_MIOCNCE | + HCR_TID4 | HCR_TICAB | HCR_TOCU | HCR_TTLBIS); + ret &= aa32_valid; + } + + if (ret & HCR_TGE) { + /* These bits are up-to-date as of ARMv8.6. */ if (ret & HCR_E2H) { ret &= ~(HCR_VM | HCR_FMO | HCR_IMO | HCR_AMO | HCR_BSU_MASK | HCR_DC | HCR_TWI | HCR_TWE | HCR_TID0 | HCR_TID2 | HCR_TPCP | HCR_TPU | - HCR_TDZ | HCR_CD | HCR_ID | HCR_MIOCNCE); + HCR_TDZ | HCR_CD | HCR_ID | HCR_MIOCNCE | + HCR_TID4 | HCR_TICAB | HCR_TOCU | HCR_ENSCXT | + HCR_TTLBIS | HCR_TTLBOS | HCR_TID5); } else { ret |= HCR_FMO | HCR_IMO | HCR_AMO; } From 84929218512c19ec9a296fbfd7b39219e0c592ae Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Thu, 5 Mar 2020 16:09:17 +0000 Subject: [PATCH 20/37] target/arm: Honor the HCR_EL2.{TVM,TRVM} bits These bits trap EL1 access to various virtual memory controls. Buglink: https://bugs.launchpad.net/bugs/1855072 Reviewed-by: Peter Maydell Signed-off-by: Richard Henderson Message-id: 20200229012811.24129-7-richard.henderson@linaro.org Signed-off-by: Peter Maydell --- target/arm/helper.c | 82 ++++++++++++++++++++++++++++++--------------- 1 file changed, 55 insertions(+), 27 deletions(-) diff --git a/target/arm/helper.c b/target/arm/helper.c index 4ddb9443fb..c78429bca2 100644 --- a/target/arm/helper.c +++ b/target/arm/helper.c @@ -530,6 +530,19 @@ static CPAccessResult access_tpm(CPUARMState *env, const ARMCPRegInfo *ri, return CP_ACCESS_OK; } +/* Check for traps from EL1 due to HCR_EL2.TVM and HCR_EL2.TRVM. */ +static CPAccessResult access_tvm_trvm(CPUARMState *env, const ARMCPRegInfo *ri, + bool isread) +{ + if (arm_current_el(env) == 1) { + uint64_t trap = isread ? HCR_TRVM : HCR_TVM; + if (arm_hcr_el2_eff(env) & trap) { + return CP_ACCESS_TRAP_EL2; + } + } + return CP_ACCESS_OK; +} + static void dacr_write(CPUARMState *env, const ARMCPRegInfo *ri, uint64_t value) { ARMCPU *cpu = env_archcpu(env); @@ -785,12 +798,14 @@ static const ARMCPRegInfo cp_reginfo[] = { */ { .name = "CONTEXTIDR_EL1", .state = ARM_CP_STATE_BOTH, .opc0 = 3, .opc1 = 0, .crn = 13, .crm = 0, .opc2 = 1, - .access = PL1_RW, .secure = ARM_CP_SECSTATE_NS, + .access = PL1_RW, .accessfn = access_tvm_trvm, + .secure = ARM_CP_SECSTATE_NS, .fieldoffset = offsetof(CPUARMState, cp15.contextidr_el[1]), .resetvalue = 0, .writefn = contextidr_write, .raw_writefn = raw_write, }, { .name = "CONTEXTIDR_S", .state = ARM_CP_STATE_AA32, .cp = 15, .opc1 = 0, .crn = 13, .crm = 0, .opc2 = 1, - .access = PL1_RW, .secure = ARM_CP_SECSTATE_S, + .access = PL1_RW, .accessfn = access_tvm_trvm, + .secure = ARM_CP_SECSTATE_S, .fieldoffset = offsetof(CPUARMState, cp15.contextidr_s), .resetvalue = 0, .writefn = contextidr_write, .raw_writefn = raw_write, }, REGINFO_SENTINEL @@ -803,7 +818,7 @@ static const ARMCPRegInfo not_v8_cp_reginfo[] = { /* MMU Domain access control / MPU write buffer control */ { .name = "DACR", .cp = 15, .opc1 = CP_ANY, .crn = 3, .crm = CP_ANY, .opc2 = CP_ANY, - .access = PL1_RW, .resetvalue = 0, + .access = PL1_RW, .accessfn = access_tvm_trvm, .resetvalue = 0, .writefn = dacr_write, .raw_writefn = raw_write, .bank_fieldoffsets = { offsetoflow32(CPUARMState, cp15.dacr_s), offsetoflow32(CPUARMState, cp15.dacr_ns) } }, @@ -996,7 +1011,7 @@ static const ARMCPRegInfo v6_cp_reginfo[] = { { .name = "DMB", .cp = 15, .crn = 7, .crm = 10, .opc1 = 0, .opc2 = 5, .access = PL0_W, .type = ARM_CP_NOP }, { .name = "IFAR", .cp = 15, .crn = 6, .crm = 0, .opc1 = 0, .opc2 = 2, - .access = PL1_RW, + .access = PL1_RW, .accessfn = access_tvm_trvm, .bank_fieldoffsets = { offsetof(CPUARMState, cp15.ifar_s), offsetof(CPUARMState, cp15.ifar_ns) }, .resetvalue = 0, }, @@ -2208,16 +2223,19 @@ static const ARMCPRegInfo v7_cp_reginfo[] = { */ { .name = "AFSR0_EL1", .state = ARM_CP_STATE_BOTH, .opc0 = 3, .opc1 = 0, .crn = 5, .crm = 1, .opc2 = 0, - .access = PL1_RW, .type = ARM_CP_CONST, .resetvalue = 0 }, + .access = PL1_RW, .accessfn = access_tvm_trvm, + .type = ARM_CP_CONST, .resetvalue = 0 }, { .name = "AFSR1_EL1", .state = ARM_CP_STATE_BOTH, .opc0 = 3, .opc1 = 0, .crn = 5, .crm = 1, .opc2 = 1, - .access = PL1_RW, .type = ARM_CP_CONST, .resetvalue = 0 }, + .access = PL1_RW, .accessfn = access_tvm_trvm, + .type = ARM_CP_CONST, .resetvalue = 0 }, /* MAIR can just read-as-written because we don't implement caches * and so don't need to care about memory attributes. */ { .name = "MAIR_EL1", .state = ARM_CP_STATE_AA64, .opc0 = 3, .opc1 = 0, .crn = 10, .crm = 2, .opc2 = 0, - .access = PL1_RW, .fieldoffset = offsetof(CPUARMState, cp15.mair_el[1]), + .access = PL1_RW, .accessfn = access_tvm_trvm, + .fieldoffset = offsetof(CPUARMState, cp15.mair_el[1]), .resetvalue = 0 }, { .name = "MAIR_EL3", .state = ARM_CP_STATE_AA64, .opc0 = 3, .opc1 = 6, .crn = 10, .crm = 2, .opc2 = 0, @@ -2231,12 +2249,14 @@ static const ARMCPRegInfo v7_cp_reginfo[] = { * handled in the field definitions. */ { .name = "MAIR0", .state = ARM_CP_STATE_AA32, - .cp = 15, .opc1 = 0, .crn = 10, .crm = 2, .opc2 = 0, .access = PL1_RW, + .cp = 15, .opc1 = 0, .crn = 10, .crm = 2, .opc2 = 0, + .access = PL1_RW, .accessfn = access_tvm_trvm, .bank_fieldoffsets = { offsetof(CPUARMState, cp15.mair0_s), offsetof(CPUARMState, cp15.mair0_ns) }, .resetfn = arm_cp_reset_ignore }, { .name = "MAIR1", .state = ARM_CP_STATE_AA32, - .cp = 15, .opc1 = 0, .crn = 10, .crm = 2, .opc2 = 1, .access = PL1_RW, + .cp = 15, .opc1 = 0, .crn = 10, .crm = 2, .opc2 = 1, + .access = PL1_RW, .accessfn = access_tvm_trvm, .bank_fieldoffsets = { offsetof(CPUARMState, cp15.mair1_s), offsetof(CPUARMState, cp15.mair1_ns) }, .resetfn = arm_cp_reset_ignore }, @@ -3886,20 +3906,21 @@ static void vttbr_write(CPUARMState *env, const ARMCPRegInfo *ri, static const ARMCPRegInfo vmsa_pmsa_cp_reginfo[] = { { .name = "DFSR", .cp = 15, .crn = 5, .crm = 0, .opc1 = 0, .opc2 = 0, - .access = PL1_RW, .type = ARM_CP_ALIAS, + .access = PL1_RW, .accessfn = access_tvm_trvm, .type = ARM_CP_ALIAS, .bank_fieldoffsets = { offsetoflow32(CPUARMState, cp15.dfsr_s), offsetoflow32(CPUARMState, cp15.dfsr_ns) }, }, { .name = "IFSR", .cp = 15, .crn = 5, .crm = 0, .opc1 = 0, .opc2 = 1, - .access = PL1_RW, .resetvalue = 0, + .access = PL1_RW, .accessfn = access_tvm_trvm, .resetvalue = 0, .bank_fieldoffsets = { offsetoflow32(CPUARMState, cp15.ifsr_s), offsetoflow32(CPUARMState, cp15.ifsr_ns) } }, { .name = "DFAR", .cp = 15, .opc1 = 0, .crn = 6, .crm = 0, .opc2 = 0, - .access = PL1_RW, .resetvalue = 0, + .access = PL1_RW, .accessfn = access_tvm_trvm, .resetvalue = 0, .bank_fieldoffsets = { offsetof(CPUARMState, cp15.dfar_s), offsetof(CPUARMState, cp15.dfar_ns) } }, { .name = "FAR_EL1", .state = ARM_CP_STATE_AA64, .opc0 = 3, .crn = 6, .crm = 0, .opc1 = 0, .opc2 = 0, - .access = PL1_RW, .fieldoffset = offsetof(CPUARMState, cp15.far_el[1]), + .access = PL1_RW, .accessfn = access_tvm_trvm, + .fieldoffset = offsetof(CPUARMState, cp15.far_el[1]), .resetvalue = 0, }, REGINFO_SENTINEL }; @@ -3907,25 +3928,29 @@ static const ARMCPRegInfo vmsa_pmsa_cp_reginfo[] = { static const ARMCPRegInfo vmsa_cp_reginfo[] = { { .name = "ESR_EL1", .state = ARM_CP_STATE_AA64, .opc0 = 3, .crn = 5, .crm = 2, .opc1 = 0, .opc2 = 0, - .access = PL1_RW, + .access = PL1_RW, .accessfn = access_tvm_trvm, .fieldoffset = offsetof(CPUARMState, cp15.esr_el[1]), .resetvalue = 0, }, { .name = "TTBR0_EL1", .state = ARM_CP_STATE_BOTH, .opc0 = 3, .opc1 = 0, .crn = 2, .crm = 0, .opc2 = 0, - .access = PL1_RW, .writefn = vmsa_ttbr_write, .resetvalue = 0, + .access = PL1_RW, .accessfn = access_tvm_trvm, + .writefn = vmsa_ttbr_write, .resetvalue = 0, .bank_fieldoffsets = { offsetof(CPUARMState, cp15.ttbr0_s), offsetof(CPUARMState, cp15.ttbr0_ns) } }, { .name = "TTBR1_EL1", .state = ARM_CP_STATE_BOTH, .opc0 = 3, .opc1 = 0, .crn = 2, .crm = 0, .opc2 = 1, - .access = PL1_RW, .writefn = vmsa_ttbr_write, .resetvalue = 0, + .access = PL1_RW, .accessfn = access_tvm_trvm, + .writefn = vmsa_ttbr_write, .resetvalue = 0, .bank_fieldoffsets = { offsetof(CPUARMState, cp15.ttbr1_s), offsetof(CPUARMState, cp15.ttbr1_ns) } }, { .name = "TCR_EL1", .state = ARM_CP_STATE_AA64, .opc0 = 3, .crn = 2, .crm = 0, .opc1 = 0, .opc2 = 2, - .access = PL1_RW, .writefn = vmsa_tcr_el12_write, + .access = PL1_RW, .accessfn = access_tvm_trvm, + .writefn = vmsa_tcr_el12_write, .resetfn = vmsa_ttbcr_reset, .raw_writefn = raw_write, .fieldoffset = offsetof(CPUARMState, cp15.tcr_el[1]) }, { .name = "TTBCR", .cp = 15, .crn = 2, .crm = 0, .opc1 = 0, .opc2 = 2, - .access = PL1_RW, .type = ARM_CP_ALIAS, .writefn = vmsa_ttbcr_write, + .access = PL1_RW, .accessfn = access_tvm_trvm, + .type = ARM_CP_ALIAS, .writefn = vmsa_ttbcr_write, .raw_writefn = vmsa_ttbcr_raw_write, .bank_fieldoffsets = { offsetoflow32(CPUARMState, cp15.tcr_el[3]), offsetoflow32(CPUARMState, cp15.tcr_el[1])} }, @@ -3937,7 +3962,8 @@ static const ARMCPRegInfo vmsa_cp_reginfo[] = { */ static const ARMCPRegInfo ttbcr2_reginfo = { .name = "TTBCR2", .cp = 15, .opc1 = 0, .crn = 2, .crm = 0, .opc2 = 3, - .access = PL1_RW, .type = ARM_CP_ALIAS, + .access = PL1_RW, .accessfn = access_tvm_trvm, + .type = ARM_CP_ALIAS, .bank_fieldoffsets = { offsetofhigh32(CPUARMState, cp15.tcr_el[3]), offsetofhigh32(CPUARMState, cp15.tcr_el[1]) }, }; @@ -4157,23 +4183,25 @@ static const ARMCPRegInfo lpae_cp_reginfo[] = { /* NOP AMAIR0/1 */ { .name = "AMAIR0", .state = ARM_CP_STATE_BOTH, .opc0 = 3, .crn = 10, .crm = 3, .opc1 = 0, .opc2 = 0, - .access = PL1_RW, .type = ARM_CP_CONST, - .resetvalue = 0 }, + .access = PL1_RW, .accessfn = access_tvm_trvm, + .type = ARM_CP_CONST, .resetvalue = 0 }, /* AMAIR1 is mapped to AMAIR_EL1[63:32] */ { .name = "AMAIR1", .cp = 15, .crn = 10, .crm = 3, .opc1 = 0, .opc2 = 1, - .access = PL1_RW, .type = ARM_CP_CONST, - .resetvalue = 0 }, + .access = PL1_RW, .accessfn = access_tvm_trvm, + .type = ARM_CP_CONST, .resetvalue = 0 }, { .name = "PAR", .cp = 15, .crm = 7, .opc1 = 0, .access = PL1_RW, .type = ARM_CP_64BIT, .resetvalue = 0, .bank_fieldoffsets = { offsetof(CPUARMState, cp15.par_s), offsetof(CPUARMState, cp15.par_ns)} }, { .name = "TTBR0", .cp = 15, .crm = 2, .opc1 = 0, - .access = PL1_RW, .type = ARM_CP_64BIT | ARM_CP_ALIAS, + .access = PL1_RW, .accessfn = access_tvm_trvm, + .type = ARM_CP_64BIT | ARM_CP_ALIAS, .bank_fieldoffsets = { offsetof(CPUARMState, cp15.ttbr0_s), offsetof(CPUARMState, cp15.ttbr0_ns) }, .writefn = vmsa_ttbr_write, }, { .name = "TTBR1", .cp = 15, .crm = 2, .opc1 = 1, - .access = PL1_RW, .type = ARM_CP_64BIT | ARM_CP_ALIAS, + .access = PL1_RW, .accessfn = access_tvm_trvm, + .type = ARM_CP_64BIT | ARM_CP_ALIAS, .bank_fieldoffsets = { offsetof(CPUARMState, cp15.ttbr1_s), offsetof(CPUARMState, cp15.ttbr1_ns) }, .writefn = vmsa_ttbr_write, }, @@ -4888,7 +4916,7 @@ static const ARMCPRegInfo v8_cp_reginfo[] = { .type = ARM_CP_NOP, .access = PL1_W }, /* MMU Domain access control / MPU write buffer control */ { .name = "DACR", .cp = 15, .opc1 = 0, .crn = 3, .crm = 0, .opc2 = 0, - .access = PL1_RW, .resetvalue = 0, + .access = PL1_RW, .accessfn = access_tvm_trvm, .resetvalue = 0, .writefn = dacr_write, .raw_writefn = raw_write, .bank_fieldoffsets = { offsetoflow32(CPUARMState, cp15.dacr_s), offsetoflow32(CPUARMState, cp15.dacr_ns) } }, @@ -7765,7 +7793,7 @@ void register_cp_regs_for_features(ARMCPU *cpu) ARMCPRegInfo sctlr = { .name = "SCTLR", .state = ARM_CP_STATE_BOTH, .opc0 = 3, .opc1 = 0, .crn = 1, .crm = 0, .opc2 = 0, - .access = PL1_RW, + .access = PL1_RW, .accessfn = access_tvm_trvm, .bank_fieldoffsets = { offsetof(CPUARMState, cp15.sctlr_s), offsetof(CPUARMState, cp15.sctlr_ns) }, .writefn = sctlr_write, .resetvalue = cpu->reset_sctlr, From 1803d2713b29d85031cc964d545036bda9880f26 Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Thu, 5 Mar 2020 16:09:18 +0000 Subject: [PATCH 21/37] target/arm: Honor the HCR_EL2.TSW bit These bits trap EL1 access to set/way cache maintenance insns. Buglink: https://bugs.launchpad.net/bugs/1863685 Reviewed-by: Peter Maydell Signed-off-by: Richard Henderson Message-id: 20200229012811.24129-8-richard.henderson@linaro.org Signed-off-by: Peter Maydell --- target/arm/helper.c | 22 ++++++++++++++++------ 1 file changed, 16 insertions(+), 6 deletions(-) diff --git a/target/arm/helper.c b/target/arm/helper.c index c78429bca2..feb279f44e 100644 --- a/target/arm/helper.c +++ b/target/arm/helper.c @@ -543,6 +543,16 @@ static CPAccessResult access_tvm_trvm(CPUARMState *env, const ARMCPRegInfo *ri, return CP_ACCESS_OK; } +/* Check for traps from EL1 due to HCR_EL2.TSW. */ +static CPAccessResult access_tsw(CPUARMState *env, const ARMCPRegInfo *ri, + bool isread) +{ + if (arm_current_el(env) == 1 && (arm_hcr_el2_eff(env) & HCR_TSW)) { + return CP_ACCESS_TRAP_EL2; + } + return CP_ACCESS_OK; +} + static void dacr_write(CPUARMState *env, const ARMCPRegInfo *ri, uint64_t value) { ARMCPU *cpu = env_archcpu(env); @@ -4704,14 +4714,14 @@ static const ARMCPRegInfo v8_cp_reginfo[] = { .access = PL1_W, .type = ARM_CP_NOP }, { .name = "DC_ISW", .state = ARM_CP_STATE_AA64, .opc0 = 1, .opc1 = 0, .crn = 7, .crm = 6, .opc2 = 2, - .access = PL1_W, .type = ARM_CP_NOP }, + .access = PL1_W, .accessfn = access_tsw, .type = ARM_CP_NOP }, { .name = "DC_CVAC", .state = ARM_CP_STATE_AA64, .opc0 = 1, .opc1 = 3, .crn = 7, .crm = 10, .opc2 = 1, .access = PL0_W, .type = ARM_CP_NOP, .accessfn = aa64_cacheop_access }, { .name = "DC_CSW", .state = ARM_CP_STATE_AA64, .opc0 = 1, .opc1 = 0, .crn = 7, .crm = 10, .opc2 = 2, - .access = PL1_W, .type = ARM_CP_NOP }, + .access = PL1_W, .accessfn = access_tsw, .type = ARM_CP_NOP }, { .name = "DC_CVAU", .state = ARM_CP_STATE_AA64, .opc0 = 1, .opc1 = 3, .crn = 7, .crm = 11, .opc2 = 1, .access = PL0_W, .type = ARM_CP_NOP, @@ -4722,7 +4732,7 @@ static const ARMCPRegInfo v8_cp_reginfo[] = { .accessfn = aa64_cacheop_access }, { .name = "DC_CISW", .state = ARM_CP_STATE_AA64, .opc0 = 1, .opc1 = 0, .crn = 7, .crm = 14, .opc2 = 2, - .access = PL1_W, .type = ARM_CP_NOP }, + .access = PL1_W, .accessfn = access_tsw, .type = ARM_CP_NOP }, /* TLBI operations */ { .name = "TLBI_VMALLE1IS", .state = ARM_CP_STATE_AA64, .opc0 = 1, .opc1 = 0, .crn = 8, .crm = 3, .opc2 = 0, @@ -4903,17 +4913,17 @@ static const ARMCPRegInfo v8_cp_reginfo[] = { { .name = "DCIMVAC", .cp = 15, .opc1 = 0, .crn = 7, .crm = 6, .opc2 = 1, .type = ARM_CP_NOP, .access = PL1_W }, { .name = "DCISW", .cp = 15, .opc1 = 0, .crn = 7, .crm = 6, .opc2 = 2, - .type = ARM_CP_NOP, .access = PL1_W }, + .type = ARM_CP_NOP, .access = PL1_W, .accessfn = access_tsw }, { .name = "DCCMVAC", .cp = 15, .opc1 = 0, .crn = 7, .crm = 10, .opc2 = 1, .type = ARM_CP_NOP, .access = PL1_W }, { .name = "DCCSW", .cp = 15, .opc1 = 0, .crn = 7, .crm = 10, .opc2 = 2, - .type = ARM_CP_NOP, .access = PL1_W }, + .type = ARM_CP_NOP, .access = PL1_W, .accessfn = access_tsw }, { .name = "DCCMVAU", .cp = 15, .opc1 = 0, .crn = 7, .crm = 11, .opc2 = 1, .type = ARM_CP_NOP, .access = PL1_W }, { .name = "DCCIMVAC", .cp = 15, .opc1 = 0, .crn = 7, .crm = 14, .opc2 = 1, .type = ARM_CP_NOP, .access = PL1_W }, { .name = "DCCISW", .cp = 15, .opc1 = 0, .crn = 7, .crm = 14, .opc2 = 2, - .type = ARM_CP_NOP, .access = PL1_W }, + .type = ARM_CP_NOP, .access = PL1_W, .accessfn = access_tsw }, /* MMU Domain access control / MPU write buffer control */ { .name = "DACR", .cp = 15, .opc1 = 0, .crn = 3, .crm = 0, .opc2 = 0, .access = PL1_RW, .accessfn = access_tvm_trvm, .resetvalue = 0, From 9960237769ada2faaaf1898b96da7a55e1691cf4 Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Thu, 5 Mar 2020 16:09:18 +0000 Subject: [PATCH 22/37] target/arm: Honor the HCR_EL2.TACR bit This bit traps EL1 access to the auxiliary control registers. Reviewed-by: Peter Maydell Signed-off-by: Richard Henderson Message-id: 20200229012811.24129-9-richard.henderson@linaro.org Signed-off-by: Peter Maydell --- target/arm/helper.c | 18 ++++++++++++++---- 1 file changed, 14 insertions(+), 4 deletions(-) diff --git a/target/arm/helper.c b/target/arm/helper.c index feb279f44e..e362d420eb 100644 --- a/target/arm/helper.c +++ b/target/arm/helper.c @@ -553,6 +553,16 @@ static CPAccessResult access_tsw(CPUARMState *env, const ARMCPRegInfo *ri, return CP_ACCESS_OK; } +/* Check for traps from EL1 due to HCR_EL2.TACR. */ +static CPAccessResult access_tacr(CPUARMState *env, const ARMCPRegInfo *ri, + bool isread) +{ + if (arm_current_el(env) == 1 && (arm_hcr_el2_eff(env) & HCR_TACR)) { + return CP_ACCESS_TRAP_EL2; + } + return CP_ACCESS_OK; +} + static void dacr_write(CPUARMState *env, const ARMCPRegInfo *ri, uint64_t value) { ARMCPU *cpu = env_archcpu(env); @@ -6961,8 +6971,8 @@ static const ARMCPRegInfo ats1cp_reginfo[] = { static const ARMCPRegInfo actlr2_hactlr2_reginfo[] = { { .name = "ACTLR2", .state = ARM_CP_STATE_AA32, .cp = 15, .opc1 = 0, .crn = 1, .crm = 0, .opc2 = 3, - .access = PL1_RW, .type = ARM_CP_CONST, - .resetvalue = 0 }, + .access = PL1_RW, .accessfn = access_tacr, + .type = ARM_CP_CONST, .resetvalue = 0 }, { .name = "HACTLR2", .state = ARM_CP_STATE_AA32, .cp = 15, .opc1 = 4, .crn = 1, .crm = 0, .opc2 = 3, .access = PL2_RW, .type = ARM_CP_CONST, @@ -7718,8 +7728,8 @@ void register_cp_regs_for_features(ARMCPU *cpu) ARMCPRegInfo auxcr_reginfo[] = { { .name = "ACTLR_EL1", .state = ARM_CP_STATE_BOTH, .opc0 = 3, .opc1 = 0, .crn = 1, .crm = 0, .opc2 = 1, - .access = PL1_RW, .type = ARM_CP_CONST, - .resetvalue = cpu->reset_auxcr }, + .access = PL1_RW, .accessfn = access_tacr, + .type = ARM_CP_CONST, .resetvalue = cpu->reset_auxcr }, { .name = "ACTLR_EL2", .state = ARM_CP_STATE_BOTH, .opc0 = 3, .opc1 = 4, .crn = 1, .crm = 0, .opc2 = 1, .access = PL2_RW, .type = ARM_CP_CONST, From 1bed4d2e55459129c19f5952bcfc65bd0c70db5b Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Thu, 5 Mar 2020 16:09:18 +0000 Subject: [PATCH 23/37] target/arm: Honor the HCR_EL2.TPCP bit This bit traps EL1 access to cache maintenance insns that operate to the point of coherency or persistence. Reviewed-by: Peter Maydell Signed-off-by: Richard Henderson Message-id: 20200229012811.24129-10-richard.henderson@linaro.org Signed-off-by: Peter Maydell --- target/arm/helper.c | 39 +++++++++++++++++++++++++++++++-------- 1 file changed, 31 insertions(+), 8 deletions(-) diff --git a/target/arm/helper.c b/target/arm/helper.c index e362d420eb..e6eaec8ad3 100644 --- a/target/arm/helper.c +++ b/target/arm/helper.c @@ -4314,6 +4314,28 @@ static CPAccessResult aa64_cacheop_access(CPUARMState *env, return CP_ACCESS_OK; } +static CPAccessResult aa64_cacheop_poc_access(CPUARMState *env, + const ARMCPRegInfo *ri, + bool isread) +{ + /* Cache invalidate/clean to Point of Coherency or Persistence... */ + switch (arm_current_el(env)) { + case 0: + /* ... EL0 must UNDEF unless SCTLR_EL1.UCI is set. */ + if (!(arm_sctlr(env, 0) & SCTLR_UCI)) { + return CP_ACCESS_TRAP; + } + /* fall through */ + case 1: + /* ... EL1 must trap to EL2 if HCR_EL2.TPCP is set. */ + if (arm_hcr_el2_eff(env) & HCR_TPCP) { + return CP_ACCESS_TRAP_EL2; + } + break; + } + return CP_ACCESS_OK; +} + /* See: D4.7.2 TLB maintenance requirements and the TLB maintenance instructions * Page D4-1736 (DDI0487A.b) */ @@ -4721,14 +4743,15 @@ static const ARMCPRegInfo v8_cp_reginfo[] = { .accessfn = aa64_cacheop_access }, { .name = "DC_IVAC", .state = ARM_CP_STATE_AA64, .opc0 = 1, .opc1 = 0, .crn = 7, .crm = 6, .opc2 = 1, - .access = PL1_W, .type = ARM_CP_NOP }, + .access = PL1_W, .accessfn = aa64_cacheop_poc_access, + .type = ARM_CP_NOP }, { .name = "DC_ISW", .state = ARM_CP_STATE_AA64, .opc0 = 1, .opc1 = 0, .crn = 7, .crm = 6, .opc2 = 2, .access = PL1_W, .accessfn = access_tsw, .type = ARM_CP_NOP }, { .name = "DC_CVAC", .state = ARM_CP_STATE_AA64, .opc0 = 1, .opc1 = 3, .crn = 7, .crm = 10, .opc2 = 1, .access = PL0_W, .type = ARM_CP_NOP, - .accessfn = aa64_cacheop_access }, + .accessfn = aa64_cacheop_poc_access }, { .name = "DC_CSW", .state = ARM_CP_STATE_AA64, .opc0 = 1, .opc1 = 0, .crn = 7, .crm = 10, .opc2 = 2, .access = PL1_W, .accessfn = access_tsw, .type = ARM_CP_NOP }, @@ -4739,7 +4762,7 @@ static const ARMCPRegInfo v8_cp_reginfo[] = { { .name = "DC_CIVAC", .state = ARM_CP_STATE_AA64, .opc0 = 1, .opc1 = 3, .crn = 7, .crm = 14, .opc2 = 1, .access = PL0_W, .type = ARM_CP_NOP, - .accessfn = aa64_cacheop_access }, + .accessfn = aa64_cacheop_poc_access }, { .name = "DC_CISW", .state = ARM_CP_STATE_AA64, .opc0 = 1, .opc1 = 0, .crn = 7, .crm = 14, .opc2 = 2, .access = PL1_W, .accessfn = access_tsw, .type = ARM_CP_NOP }, @@ -4921,17 +4944,17 @@ static const ARMCPRegInfo v8_cp_reginfo[] = { { .name = "BPIMVA", .cp = 15, .opc1 = 0, .crn = 7, .crm = 5, .opc2 = 7, .type = ARM_CP_NOP, .access = PL1_W }, { .name = "DCIMVAC", .cp = 15, .opc1 = 0, .crn = 7, .crm = 6, .opc2 = 1, - .type = ARM_CP_NOP, .access = PL1_W }, + .type = ARM_CP_NOP, .access = PL1_W, .accessfn = aa64_cacheop_poc_access }, { .name = "DCISW", .cp = 15, .opc1 = 0, .crn = 7, .crm = 6, .opc2 = 2, .type = ARM_CP_NOP, .access = PL1_W, .accessfn = access_tsw }, { .name = "DCCMVAC", .cp = 15, .opc1 = 0, .crn = 7, .crm = 10, .opc2 = 1, - .type = ARM_CP_NOP, .access = PL1_W }, + .type = ARM_CP_NOP, .access = PL1_W, .accessfn = aa64_cacheop_poc_access }, { .name = "DCCSW", .cp = 15, .opc1 = 0, .crn = 7, .crm = 10, .opc2 = 2, .type = ARM_CP_NOP, .access = PL1_W, .accessfn = access_tsw }, { .name = "DCCMVAU", .cp = 15, .opc1 = 0, .crn = 7, .crm = 11, .opc2 = 1, .type = ARM_CP_NOP, .access = PL1_W }, { .name = "DCCIMVAC", .cp = 15, .opc1 = 0, .crn = 7, .crm = 14, .opc2 = 1, - .type = ARM_CP_NOP, .access = PL1_W }, + .type = ARM_CP_NOP, .access = PL1_W, .accessfn = aa64_cacheop_poc_access }, { .name = "DCCISW", .cp = 15, .opc1 = 0, .crn = 7, .crm = 14, .opc2 = 2, .type = ARM_CP_NOP, .access = PL1_W, .accessfn = access_tsw }, /* MMU Domain access control / MPU write buffer control */ @@ -6750,7 +6773,7 @@ static const ARMCPRegInfo dcpop_reg[] = { { .name = "DC_CVAP", .state = ARM_CP_STATE_AA64, .opc0 = 1, .opc1 = 3, .crn = 7, .crm = 12, .opc2 = 1, .access = PL0_W, .type = ARM_CP_NO_RAW | ARM_CP_SUPPRESS_TB_END, - .accessfn = aa64_cacheop_access, .writefn = dccvap_writefn }, + .accessfn = aa64_cacheop_poc_access, .writefn = dccvap_writefn }, REGINFO_SENTINEL }; @@ -6758,7 +6781,7 @@ static const ARMCPRegInfo dcpodp_reg[] = { { .name = "DC_CVADP", .state = ARM_CP_STATE_AA64, .opc0 = 1, .opc1 = 3, .crn = 7, .crm = 13, .opc2 = 1, .access = PL0_W, .type = ARM_CP_NO_RAW | ARM_CP_SUPPRESS_TB_END, - .accessfn = aa64_cacheop_access, .writefn = dccvap_writefn }, + .accessfn = aa64_cacheop_poc_access, .writefn = dccvap_writefn }, REGINFO_SENTINEL }; #endif /*CONFIG_USER_ONLY*/ From 38262d8a732f8bd0e9ca3dc064f6e73d00c08b9a Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Thu, 5 Mar 2020 16:09:18 +0000 Subject: [PATCH 24/37] target/arm: Honor the HCR_EL2.TPU bit This bit traps EL1 access to cache maintenance insns that operate to the point of unification. There are no longer any references to plain aa64_cacheop_access, so remove it. Reviewed-by: Peter Maydell Signed-off-by: Richard Henderson Message-id: 20200229012811.24129-11-richard.henderson@linaro.org Signed-off-by: Peter Maydell --- target/arm/helper.c | 53 +++++++++++++++++++++++++++------------------ 1 file changed, 32 insertions(+), 21 deletions(-) diff --git a/target/arm/helper.c b/target/arm/helper.c index e6eaec8ad3..09b5022919 100644 --- a/target/arm/helper.c +++ b/target/arm/helper.c @@ -4301,19 +4301,6 @@ static const ARMCPRegInfo uao_reginfo = { .readfn = aa64_uao_read, .writefn = aa64_uao_write }; -static CPAccessResult aa64_cacheop_access(CPUARMState *env, - const ARMCPRegInfo *ri, - bool isread) -{ - /* Cache invalidate/clean: NOP, but EL0 must UNDEF unless - * SCTLR_EL1.UCI is set. - */ - if (arm_current_el(env) == 0 && !(arm_sctlr(env, 0) & SCTLR_UCI)) { - return CP_ACCESS_TRAP; - } - return CP_ACCESS_OK; -} - static CPAccessResult aa64_cacheop_poc_access(CPUARMState *env, const ARMCPRegInfo *ri, bool isread) @@ -4336,6 +4323,28 @@ static CPAccessResult aa64_cacheop_poc_access(CPUARMState *env, return CP_ACCESS_OK; } +static CPAccessResult aa64_cacheop_pou_access(CPUARMState *env, + const ARMCPRegInfo *ri, + bool isread) +{ + /* Cache invalidate/clean to Point of Unification... */ + switch (arm_current_el(env)) { + case 0: + /* ... EL0 must UNDEF unless SCTLR_EL1.UCI is set. */ + if (!(arm_sctlr(env, 0) & SCTLR_UCI)) { + return CP_ACCESS_TRAP; + } + /* fall through */ + case 1: + /* ... EL1 must trap to EL2 if HCR_EL2.TPU is set. */ + if (arm_hcr_el2_eff(env) & HCR_TPU) { + return CP_ACCESS_TRAP_EL2; + } + break; + } + return CP_ACCESS_OK; +} + /* See: D4.7.2 TLB maintenance requirements and the TLB maintenance instructions * Page D4-1736 (DDI0487A.b) */ @@ -4733,14 +4742,16 @@ static const ARMCPRegInfo v8_cp_reginfo[] = { /* Cache ops: all NOPs since we don't emulate caches */ { .name = "IC_IALLUIS", .state = ARM_CP_STATE_AA64, .opc0 = 1, .opc1 = 0, .crn = 7, .crm = 1, .opc2 = 0, - .access = PL1_W, .type = ARM_CP_NOP }, + .access = PL1_W, .type = ARM_CP_NOP, + .accessfn = aa64_cacheop_pou_access }, { .name = "IC_IALLU", .state = ARM_CP_STATE_AA64, .opc0 = 1, .opc1 = 0, .crn = 7, .crm = 5, .opc2 = 0, - .access = PL1_W, .type = ARM_CP_NOP }, + .access = PL1_W, .type = ARM_CP_NOP, + .accessfn = aa64_cacheop_pou_access }, { .name = "IC_IVAU", .state = ARM_CP_STATE_AA64, .opc0 = 1, .opc1 = 3, .crn = 7, .crm = 5, .opc2 = 1, .access = PL0_W, .type = ARM_CP_NOP, - .accessfn = aa64_cacheop_access }, + .accessfn = aa64_cacheop_pou_access }, { .name = "DC_IVAC", .state = ARM_CP_STATE_AA64, .opc0 = 1, .opc1 = 0, .crn = 7, .crm = 6, .opc2 = 1, .access = PL1_W, .accessfn = aa64_cacheop_poc_access, @@ -4758,7 +4769,7 @@ static const ARMCPRegInfo v8_cp_reginfo[] = { { .name = "DC_CVAU", .state = ARM_CP_STATE_AA64, .opc0 = 1, .opc1 = 3, .crn = 7, .crm = 11, .opc2 = 1, .access = PL0_W, .type = ARM_CP_NOP, - .accessfn = aa64_cacheop_access }, + .accessfn = aa64_cacheop_pou_access }, { .name = "DC_CIVAC", .state = ARM_CP_STATE_AA64, .opc0 = 1, .opc1 = 3, .crn = 7, .crm = 14, .opc2 = 1, .access = PL0_W, .type = ARM_CP_NOP, @@ -4932,13 +4943,13 @@ static const ARMCPRegInfo v8_cp_reginfo[] = { .writefn = tlbiipas2_is_write }, /* 32 bit cache operations */ { .name = "ICIALLUIS", .cp = 15, .opc1 = 0, .crn = 7, .crm = 1, .opc2 = 0, - .type = ARM_CP_NOP, .access = PL1_W }, + .type = ARM_CP_NOP, .access = PL1_W, .accessfn = aa64_cacheop_pou_access }, { .name = "BPIALLUIS", .cp = 15, .opc1 = 0, .crn = 7, .crm = 1, .opc2 = 6, .type = ARM_CP_NOP, .access = PL1_W }, { .name = "ICIALLU", .cp = 15, .opc1 = 0, .crn = 7, .crm = 5, .opc2 = 0, - .type = ARM_CP_NOP, .access = PL1_W }, + .type = ARM_CP_NOP, .access = PL1_W, .accessfn = aa64_cacheop_pou_access }, { .name = "ICIMVAU", .cp = 15, .opc1 = 0, .crn = 7, .crm = 5, .opc2 = 1, - .type = ARM_CP_NOP, .access = PL1_W }, + .type = ARM_CP_NOP, .access = PL1_W, .accessfn = aa64_cacheop_pou_access }, { .name = "BPIALL", .cp = 15, .opc1 = 0, .crn = 7, .crm = 5, .opc2 = 6, .type = ARM_CP_NOP, .access = PL1_W }, { .name = "BPIMVA", .cp = 15, .opc1 = 0, .crn = 7, .crm = 5, .opc2 = 7, @@ -4952,7 +4963,7 @@ static const ARMCPRegInfo v8_cp_reginfo[] = { { .name = "DCCSW", .cp = 15, .opc1 = 0, .crn = 7, .crm = 10, .opc2 = 2, .type = ARM_CP_NOP, .access = PL1_W, .accessfn = access_tsw }, { .name = "DCCMVAU", .cp = 15, .opc1 = 0, .crn = 7, .crm = 11, .opc2 = 1, - .type = ARM_CP_NOP, .access = PL1_W }, + .type = ARM_CP_NOP, .access = PL1_W, .accessfn = aa64_cacheop_pou_access }, { .name = "DCCIMVAC", .cp = 15, .opc1 = 0, .crn = 7, .crm = 14, .opc2 = 1, .type = ARM_CP_NOP, .access = PL1_W, .accessfn = aa64_cacheop_poc_access }, { .name = "DCCISW", .cp = 15, .opc1 = 0, .crn = 7, .crm = 14, .opc2 = 2, From 30881b7353b5bb41210c32cd8e00421da757808c Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Thu, 5 Mar 2020 16:09:18 +0000 Subject: [PATCH 25/37] target/arm: Honor the HCR_EL2.TTLB bit This bit traps EL1 access to tlb maintenance insns. Reviewed-by: Peter Maydell Signed-off-by: Richard Henderson Message-id: 20200229012811.24129-12-richard.henderson@linaro.org Signed-off-by: Peter Maydell --- target/arm/helper.c | 85 +++++++++++++++++++++++++++++---------------- 1 file changed, 55 insertions(+), 30 deletions(-) diff --git a/target/arm/helper.c b/target/arm/helper.c index 09b5022919..6abf52db66 100644 --- a/target/arm/helper.c +++ b/target/arm/helper.c @@ -563,6 +563,16 @@ static CPAccessResult access_tacr(CPUARMState *env, const ARMCPRegInfo *ri, return CP_ACCESS_OK; } +/* Check for traps from EL1 due to HCR_EL2.TTLB. */ +static CPAccessResult access_ttlb(CPUARMState *env, const ARMCPRegInfo *ri, + bool isread) +{ + if (arm_current_el(env) == 1 && (arm_hcr_el2_eff(env) & HCR_TTLB)) { + return CP_ACCESS_TRAP_EL2; + } + return CP_ACCESS_OK; +} + static void dacr_write(CPUARMState *env, const ARMCPRegInfo *ri, uint64_t value) { ARMCPU *cpu = env_archcpu(env); @@ -2285,41 +2295,53 @@ static const ARMCPRegInfo v7_cp_reginfo[] = { .type = ARM_CP_NO_RAW, .access = PL1_R, .readfn = isr_read }, /* 32 bit ITLB invalidates */ { .name = "ITLBIALL", .cp = 15, .opc1 = 0, .crn = 8, .crm = 5, .opc2 = 0, - .type = ARM_CP_NO_RAW, .access = PL1_W, .writefn = tlbiall_write }, + .type = ARM_CP_NO_RAW, .access = PL1_W, .accessfn = access_ttlb, + .writefn = tlbiall_write }, { .name = "ITLBIMVA", .cp = 15, .opc1 = 0, .crn = 8, .crm = 5, .opc2 = 1, - .type = ARM_CP_NO_RAW, .access = PL1_W, .writefn = tlbimva_write }, + .type = ARM_CP_NO_RAW, .access = PL1_W, .accessfn = access_ttlb, + .writefn = tlbimva_write }, { .name = "ITLBIASID", .cp = 15, .opc1 = 0, .crn = 8, .crm = 5, .opc2 = 2, - .type = ARM_CP_NO_RAW, .access = PL1_W, .writefn = tlbiasid_write }, + .type = ARM_CP_NO_RAW, .access = PL1_W, .accessfn = access_ttlb, + .writefn = tlbiasid_write }, /* 32 bit DTLB invalidates */ { .name = "DTLBIALL", .cp = 15, .opc1 = 0, .crn = 8, .crm = 6, .opc2 = 0, - .type = ARM_CP_NO_RAW, .access = PL1_W, .writefn = tlbiall_write }, + .type = ARM_CP_NO_RAW, .access = PL1_W, .accessfn = access_ttlb, + .writefn = tlbiall_write }, { .name = "DTLBIMVA", .cp = 15, .opc1 = 0, .crn = 8, .crm = 6, .opc2 = 1, - .type = ARM_CP_NO_RAW, .access = PL1_W, .writefn = tlbimva_write }, + .type = ARM_CP_NO_RAW, .access = PL1_W, .accessfn = access_ttlb, + .writefn = tlbimva_write }, { .name = "DTLBIASID", .cp = 15, .opc1 = 0, .crn = 8, .crm = 6, .opc2 = 2, - .type = ARM_CP_NO_RAW, .access = PL1_W, .writefn = tlbiasid_write }, + .type = ARM_CP_NO_RAW, .access = PL1_W, .accessfn = access_ttlb, + .writefn = tlbiasid_write }, /* 32 bit TLB invalidates */ { .name = "TLBIALL", .cp = 15, .opc1 = 0, .crn = 8, .crm = 7, .opc2 = 0, - .type = ARM_CP_NO_RAW, .access = PL1_W, .writefn = tlbiall_write }, + .type = ARM_CP_NO_RAW, .access = PL1_W, .accessfn = access_ttlb, + .writefn = tlbiall_write }, { .name = "TLBIMVA", .cp = 15, .opc1 = 0, .crn = 8, .crm = 7, .opc2 = 1, - .type = ARM_CP_NO_RAW, .access = PL1_W, .writefn = tlbimva_write }, + .type = ARM_CP_NO_RAW, .access = PL1_W, .accessfn = access_ttlb, + .writefn = tlbimva_write }, { .name = "TLBIASID", .cp = 15, .opc1 = 0, .crn = 8, .crm = 7, .opc2 = 2, - .type = ARM_CP_NO_RAW, .access = PL1_W, .writefn = tlbiasid_write }, + .type = ARM_CP_NO_RAW, .access = PL1_W, .accessfn = access_ttlb, + .writefn = tlbiasid_write }, { .name = "TLBIMVAA", .cp = 15, .opc1 = 0, .crn = 8, .crm = 7, .opc2 = 3, - .type = ARM_CP_NO_RAW, .access = PL1_W, .writefn = tlbimvaa_write }, + .type = ARM_CP_NO_RAW, .access = PL1_W, .accessfn = access_ttlb, + .writefn = tlbimvaa_write }, REGINFO_SENTINEL }; static const ARMCPRegInfo v7mp_cp_reginfo[] = { /* 32 bit TLB invalidates, Inner Shareable */ { .name = "TLBIALLIS", .cp = 15, .opc1 = 0, .crn = 8, .crm = 3, .opc2 = 0, - .type = ARM_CP_NO_RAW, .access = PL1_W, .writefn = tlbiall_is_write }, + .type = ARM_CP_NO_RAW, .access = PL1_W, .accessfn = access_ttlb, + .writefn = tlbiall_is_write }, { .name = "TLBIMVAIS", .cp = 15, .opc1 = 0, .crn = 8, .crm = 3, .opc2 = 1, - .type = ARM_CP_NO_RAW, .access = PL1_W, .writefn = tlbimva_is_write }, + .type = ARM_CP_NO_RAW, .access = PL1_W, .accessfn = access_ttlb, + .writefn = tlbimva_is_write }, { .name = "TLBIASIDIS", .cp = 15, .opc1 = 0, .crn = 8, .crm = 3, .opc2 = 2, - .type = ARM_CP_NO_RAW, .access = PL1_W, + .type = ARM_CP_NO_RAW, .access = PL1_W, .accessfn = access_ttlb, .writefn = tlbiasid_is_write }, { .name = "TLBIMVAAIS", .cp = 15, .opc1 = 0, .crn = 8, .crm = 3, .opc2 = 3, - .type = ARM_CP_NO_RAW, .access = PL1_W, + .type = ARM_CP_NO_RAW, .access = PL1_W, .accessfn = access_ttlb, .writefn = tlbimvaa_is_write }, REGINFO_SENTINEL }; @@ -4780,51 +4802,51 @@ static const ARMCPRegInfo v8_cp_reginfo[] = { /* TLBI operations */ { .name = "TLBI_VMALLE1IS", .state = ARM_CP_STATE_AA64, .opc0 = 1, .opc1 = 0, .crn = 8, .crm = 3, .opc2 = 0, - .access = PL1_W, .type = ARM_CP_NO_RAW, + .access = PL1_W, .accessfn = access_ttlb, .type = ARM_CP_NO_RAW, .writefn = tlbi_aa64_vmalle1is_write }, { .name = "TLBI_VAE1IS", .state = ARM_CP_STATE_AA64, .opc0 = 1, .opc1 = 0, .crn = 8, .crm = 3, .opc2 = 1, - .access = PL1_W, .type = ARM_CP_NO_RAW, + .access = PL1_W, .accessfn = access_ttlb, .type = ARM_CP_NO_RAW, .writefn = tlbi_aa64_vae1is_write }, { .name = "TLBI_ASIDE1IS", .state = ARM_CP_STATE_AA64, .opc0 = 1, .opc1 = 0, .crn = 8, .crm = 3, .opc2 = 2, - .access = PL1_W, .type = ARM_CP_NO_RAW, + .access = PL1_W, .accessfn = access_ttlb, .type = ARM_CP_NO_RAW, .writefn = tlbi_aa64_vmalle1is_write }, { .name = "TLBI_VAAE1IS", .state = ARM_CP_STATE_AA64, .opc0 = 1, .opc1 = 0, .crn = 8, .crm = 3, .opc2 = 3, - .access = PL1_W, .type = ARM_CP_NO_RAW, + .access = PL1_W, .accessfn = access_ttlb, .type = ARM_CP_NO_RAW, .writefn = tlbi_aa64_vae1is_write }, { .name = "TLBI_VALE1IS", .state = ARM_CP_STATE_AA64, .opc0 = 1, .opc1 = 0, .crn = 8, .crm = 3, .opc2 = 5, - .access = PL1_W, .type = ARM_CP_NO_RAW, + .access = PL1_W, .accessfn = access_ttlb, .type = ARM_CP_NO_RAW, .writefn = tlbi_aa64_vae1is_write }, { .name = "TLBI_VAALE1IS", .state = ARM_CP_STATE_AA64, .opc0 = 1, .opc1 = 0, .crn = 8, .crm = 3, .opc2 = 7, - .access = PL1_W, .type = ARM_CP_NO_RAW, + .access = PL1_W, .accessfn = access_ttlb, .type = ARM_CP_NO_RAW, .writefn = tlbi_aa64_vae1is_write }, { .name = "TLBI_VMALLE1", .state = ARM_CP_STATE_AA64, .opc0 = 1, .opc1 = 0, .crn = 8, .crm = 7, .opc2 = 0, - .access = PL1_W, .type = ARM_CP_NO_RAW, + .access = PL1_W, .accessfn = access_ttlb, .type = ARM_CP_NO_RAW, .writefn = tlbi_aa64_vmalle1_write }, { .name = "TLBI_VAE1", .state = ARM_CP_STATE_AA64, .opc0 = 1, .opc1 = 0, .crn = 8, .crm = 7, .opc2 = 1, - .access = PL1_W, .type = ARM_CP_NO_RAW, + .access = PL1_W, .accessfn = access_ttlb, .type = ARM_CP_NO_RAW, .writefn = tlbi_aa64_vae1_write }, { .name = "TLBI_ASIDE1", .state = ARM_CP_STATE_AA64, .opc0 = 1, .opc1 = 0, .crn = 8, .crm = 7, .opc2 = 2, - .access = PL1_W, .type = ARM_CP_NO_RAW, + .access = PL1_W, .accessfn = access_ttlb, .type = ARM_CP_NO_RAW, .writefn = tlbi_aa64_vmalle1_write }, { .name = "TLBI_VAAE1", .state = ARM_CP_STATE_AA64, .opc0 = 1, .opc1 = 0, .crn = 8, .crm = 7, .opc2 = 3, - .access = PL1_W, .type = ARM_CP_NO_RAW, + .access = PL1_W, .accessfn = access_ttlb, .type = ARM_CP_NO_RAW, .writefn = tlbi_aa64_vae1_write }, { .name = "TLBI_VALE1", .state = ARM_CP_STATE_AA64, .opc0 = 1, .opc1 = 0, .crn = 8, .crm = 7, .opc2 = 5, - .access = PL1_W, .type = ARM_CP_NO_RAW, + .access = PL1_W, .accessfn = access_ttlb, .type = ARM_CP_NO_RAW, .writefn = tlbi_aa64_vae1_write }, { .name = "TLBI_VAALE1", .state = ARM_CP_STATE_AA64, .opc0 = 1, .opc1 = 0, .crn = 8, .crm = 7, .opc2 = 7, - .access = PL1_W, .type = ARM_CP_NO_RAW, + .access = PL1_W, .accessfn = access_ttlb, .type = ARM_CP_NO_RAW, .writefn = tlbi_aa64_vae1_write }, { .name = "TLBI_IPAS2E1IS", .state = ARM_CP_STATE_AA64, .opc0 = 1, .opc1 = 4, .crn = 8, .crm = 0, .opc2 = 1, @@ -4910,14 +4932,17 @@ static const ARMCPRegInfo v8_cp_reginfo[] = { #endif /* TLB invalidate last level of translation table walk */ { .name = "TLBIMVALIS", .cp = 15, .opc1 = 0, .crn = 8, .crm = 3, .opc2 = 5, - .type = ARM_CP_NO_RAW, .access = PL1_W, .writefn = tlbimva_is_write }, + .type = ARM_CP_NO_RAW, .access = PL1_W, .accessfn = access_ttlb, + .writefn = tlbimva_is_write }, { .name = "TLBIMVAALIS", .cp = 15, .opc1 = 0, .crn = 8, .crm = 3, .opc2 = 7, - .type = ARM_CP_NO_RAW, .access = PL1_W, + .type = ARM_CP_NO_RAW, .access = PL1_W, .accessfn = access_ttlb, .writefn = tlbimvaa_is_write }, { .name = "TLBIMVAL", .cp = 15, .opc1 = 0, .crn = 8, .crm = 7, .opc2 = 5, - .type = ARM_CP_NO_RAW, .access = PL1_W, .writefn = tlbimva_write }, + .type = ARM_CP_NO_RAW, .access = PL1_W, .accessfn = access_ttlb, + .writefn = tlbimva_write }, { .name = "TLBIMVAAL", .cp = 15, .opc1 = 0, .crn = 8, .crm = 7, .opc2 = 7, - .type = ARM_CP_NO_RAW, .access = PL1_W, .writefn = tlbimvaa_write }, + .type = ARM_CP_NO_RAW, .access = PL1_W, .accessfn = access_ttlb, + .writefn = tlbimvaa_write }, { .name = "TLBIMVALH", .cp = 15, .opc1 = 4, .crn = 8, .crm = 7, .opc2 = 5, .type = ARM_CP_NO_RAW, .access = PL2_W, .writefn = tlbimva_hyp_write }, From e2d30df9079a277c7c98a55be91dd28a7f1b8e1c Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Thu, 5 Mar 2020 16:09:19 +0000 Subject: [PATCH 26/37] tests/tcg/aarch64: Add newline in pauth-1 printf MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Make the output just a bit prettier when running by hand. Cc: Alex Bennée Signed-off-by: Richard Henderson Message-id: 20200229012811.24129-13-richard.henderson@linaro.org Reviewed-by: Peter Maydell Signed-off-by: Peter Maydell --- tests/tcg/aarch64/pauth-1.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/tcg/aarch64/pauth-1.c b/tests/tcg/aarch64/pauth-1.c index ea0984ea82..d3878cbeb6 100644 --- a/tests/tcg/aarch64/pauth-1.c +++ b/tests/tcg/aarch64/pauth-1.c @@ -29,7 +29,7 @@ int main() } perc = (float) count / (float) (TESTS * 2); - printf("Ptr Check: %0.2f%%", perc * 100.0); + printf("Ptr Check: %0.2f%%\n", perc * 100.0); assert(perc > 0.95); return 0; } From 2104df2a1fbf44b2564427aa72fd58d66ce290a7 Mon Sep 17 00:00:00 2001 From: Niek Linnenbank Date: Thu, 5 Mar 2020 16:09:19 +0000 Subject: [PATCH 27/37] hw/arm/cubieboard: use ARM Cortex-A8 as the default CPU in machine definition MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The Cubieboard is a singleboard computer with an Allwinner A10 System-on-Chip [1]. As documented in the Allwinner A10 User Manual V1.5 [2], the SoC has an ARM Cortex-A8 processor. Currently the Cubieboard machine definition specifies the ARM Cortex-A9 in its description and as the default CPU. This patch corrects the Cubieboard machine definition to use the ARM Cortex-A8. The only user-visible effect is that our textual description of the machine was wrong, because hw/arm/allwinner-a10.c always creates a Cortex-A8 CPU regardless of the default value in the MachineClass struct. [1] http://docs.cubieboard.org/products/start#cubieboard1 [2] https://linux-sunxi.org/File:Allwinner_A10_User_manual_V1.5.pdf Fixes: 8a863c8120994981a099 Signed-off-by: Niek Linnenbank Message-id: 20200227220149.6845-2-nieklinnenbank@gmail.com Reviewed-by: Philippe Mathieu-Daudé Reviewed-by: Peter Maydell [note in commit message that the bug didn't have much visible effect] Signed-off-by: Peter Maydell --- hw/arm/cubieboard.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/hw/arm/cubieboard.c b/hw/arm/cubieboard.c index 089f9a30c1..0195925c73 100644 --- a/hw/arm/cubieboard.c +++ b/hw/arm/cubieboard.c @@ -68,8 +68,8 @@ static void cubieboard_init(MachineState *machine) static void cubieboard_machine_init(MachineClass *mc) { - mc->desc = "cubietech cubieboard (Cortex-A9)"; - mc->default_cpu_type = ARM_CPU_TYPE_NAME("cortex-a9"); + mc->desc = "cubietech cubieboard (Cortex-A8)"; + mc->default_cpu_type = ARM_CPU_TYPE_NAME("cortex-a8"); mc->init = cubieboard_init; mc->block_default_type = IF_IDE; mc->units_per_default_bus = 1; From 17c7576263339f20d77964083704f3da4e4b8c91 Mon Sep 17 00:00:00 2001 From: Niek Linnenbank Date: Thu, 5 Mar 2020 16:09:19 +0000 Subject: [PATCH 28/37] hw/arm/cubieboard: restrict allowed CPU type to ARM Cortex-A8 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The Cubieboard has an ARM Cortex-A8. Instead of simply ignoring a bogus -cpu option provided by the user, give them an error message so they know their command line is wrong. Signed-off-by: Niek Linnenbank Message-id: 20200227220149.6845-3-nieklinnenbank@gmail.com Reviewed-by: Philippe Mathieu-Daudé Reviewed-by: Peter Maydell [PMM: tweaked commit message] Signed-off-by: Peter Maydell --- hw/arm/cubieboard.c | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/hw/arm/cubieboard.c b/hw/arm/cubieboard.c index 0195925c73..010375f0a8 100644 --- a/hw/arm/cubieboard.c +++ b/hw/arm/cubieboard.c @@ -30,9 +30,17 @@ static struct arm_boot_info cubieboard_binfo = { static void cubieboard_init(MachineState *machine) { - AwA10State *a10 = AW_A10(object_new(TYPE_AW_A10)); + AwA10State *a10; Error *err = NULL; + /* Only allow Cortex-A8 for this board */ + if (strcmp(machine->cpu_type, ARM_CPU_TYPE_NAME("cortex-a8")) != 0) { + error_report("This board can only be used with cortex-a8 CPU"); + exit(1); + } + + a10 = AW_A10(object_new(TYPE_AW_A10)); + object_property_set_int(OBJECT(&a10->emac), 1, "phy-addr", &err); if (err != NULL) { error_reportf_err(err, "Couldn't set phy address: "); From e207245fc20aab00faf4d9c4c63fcc170e7a3ba7 Mon Sep 17 00:00:00 2001 From: Niek Linnenbank Date: Thu, 5 Mar 2020 16:09:19 +0000 Subject: [PATCH 29/37] hw/arm/cubieboard: restrict allowed RAM size to 512MiB and 1GiB MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The Cubieboard contains either 512MiB or 1GiB of onboard RAM [1]. Prevent changing RAM to a different size which could break user programs. [1] http://linux-sunxi.org/Cubieboard Signed-off-by: Niek Linnenbank Message-id: 20200227220149.6845-4-nieklinnenbank@gmail.com Reviewed-by: Philippe Mathieu-Daudé Reviewed-by: Peter Maydell Signed-off-by: Peter Maydell --- hw/arm/cubieboard.c | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/hw/arm/cubieboard.c b/hw/arm/cubieboard.c index 010375f0a8..6c55d9056f 100644 --- a/hw/arm/cubieboard.c +++ b/hw/arm/cubieboard.c @@ -33,6 +33,13 @@ static void cubieboard_init(MachineState *machine) AwA10State *a10; Error *err = NULL; + /* This board has fixed size RAM (512MiB or 1GiB) */ + if (machine->ram_size != 512 * MiB && + machine->ram_size != 1 * GiB) { + error_report("This machine can only be used with 512MiB or 1GiB RAM"); + exit(1); + } + /* Only allow Cortex-A8 for this board */ if (strcmp(machine->cpu_type, ARM_CPU_TYPE_NAME("cortex-a8")) != 0) { error_report("This board can only be used with cortex-a8 CPU"); @@ -78,6 +85,7 @@ static void cubieboard_machine_init(MachineClass *mc) { mc->desc = "cubietech cubieboard (Cortex-A8)"; mc->default_cpu_type = ARM_CPU_TYPE_NAME("cortex-a8"); + mc->default_ram_size = 1 * GiB; mc->init = cubieboard_init; mc->block_default_type = IF_IDE; mc->units_per_default_bus = 1; From 3c2fb21ad2a02186bec986001ae1f1eefdfdb549 Mon Sep 17 00:00:00 2001 From: Niek Linnenbank Date: Thu, 5 Mar 2020 16:09:19 +0000 Subject: [PATCH 30/37] hw/arm/cubieboard: report error when using unsupported -bios argument MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The Cubieboard machine does not support the -bios argument. Report an error when -bios is used and exit immediately. Signed-off-by: Niek Linnenbank Message-id: 20200227220149.6845-5-nieklinnenbank@gmail.com Reviewed-by: Philippe Mathieu-Daudé Reviewed-by: Peter Maydell Signed-off-by: Peter Maydell --- hw/arm/cubieboard.c | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/hw/arm/cubieboard.c b/hw/arm/cubieboard.c index 6c55d9056f..871b1beef4 100644 --- a/hw/arm/cubieboard.c +++ b/hw/arm/cubieboard.c @@ -19,6 +19,7 @@ #include "exec/address-spaces.h" #include "qapi/error.h" #include "cpu.h" +#include "sysemu/sysemu.h" #include "hw/sysbus.h" #include "hw/boards.h" #include "hw/arm/allwinner-a10.h" @@ -33,6 +34,12 @@ static void cubieboard_init(MachineState *machine) AwA10State *a10; Error *err = NULL; + /* BIOS is not supported by this board */ + if (bios_name) { + error_report("BIOS not supported for this machine"); + exit(1); + } + /* This board has fixed size RAM (512MiB or 1GiB) */ if (machine->ram_size != 512 * MiB && machine->ram_size != 1 * GiB) { From 3e270f67f0f05277021763af119a6ce195f8ed51 Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Thu, 5 Mar 2020 16:09:20 +0000 Subject: [PATCH 31/37] target/arm: Replicate TBI/TBID bits for single range regimes MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Replicate the single TBI bit from TCR_EL2 and TCR_EL3 so that we can unconditionally use pointer bit 55 to index into our composite TBI1:TBI0 field. Reviewed-by: Peter Maydell Signed-off-by: Richard Henderson Reviewed-by: Philippe Mathieu-Daudé Message-id: 20200302175829.2183-2-richard.henderson@linaro.org 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 6abf52db66..f7ba34bbf6 100644 --- a/target/arm/helper.c +++ b/target/arm/helper.c @@ -10458,7 +10458,8 @@ static int aa64_va_parameter_tbi(uint64_t tcr, ARMMMUIdx mmu_idx) } else if (mmu_idx == ARMMMUIdx_Stage2) { return 0; /* VTCR_EL2 */ } else { - return extract32(tcr, 20, 1); + /* Replicate the single TBI bit so we always have 2 bits. */ + return extract32(tcr, 20, 1) * 3; } } @@ -10469,7 +10470,8 @@ static int aa64_va_parameter_tbid(uint64_t tcr, ARMMMUIdx mmu_idx) } else if (mmu_idx == ARMMMUIdx_Stage2) { return 0; /* VTCR_EL2 */ } else { - return extract32(tcr, 29, 1); + /* Replicate the single TBID bit so we always have 2 bits. */ + return extract32(tcr, 29, 1) * 3; } } From fb901c905dc34254f3edfbee86143460594c564b Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Thu, 5 Mar 2020 16:09:20 +0000 Subject: [PATCH 32/37] target/arm: Optimize cpu_mmu_index We now cache the core mmu_idx in env->hflags. Rather than recompute from scratch, extract the field. All of the uses of cpu_mmu_index within target/arm are within helpers, and env->hflags is always stable within a translation block from whence helpers are called. Signed-off-by: Richard Henderson Reviewed-by: Peter Maydell Message-id: 20200302175829.2183-3-richard.henderson@linaro.org Signed-off-by: Peter Maydell --- target/arm/cpu.h | 23 +++++++++++++---------- target/arm/helper.c | 5 ----- 2 files changed, 13 insertions(+), 15 deletions(-) diff --git a/target/arm/cpu.h b/target/arm/cpu.h index 0ae07a72e4..4ffd991b6f 100644 --- a/target/arm/cpu.h +++ b/target/arm/cpu.h @@ -2943,16 +2943,6 @@ typedef enum ARMMMUIdxBit { #define MMU_USER_IDX 0 -/** - * cpu_mmu_index: - * @env: The cpu environment - * @ifetch: True for code access, false for data access. - * - * Return the core mmu index for the current translation regime. - * This function is used by generic TCG code paths. - */ -int cpu_mmu_index(CPUARMState *env, bool ifetch); - /* Indexes used when registering address spaces with cpu_address_space_init */ typedef enum ARMASIdx { ARMASIdx_NS = 0, @@ -3232,6 +3222,19 @@ FIELD(TBFLAG_A64, BTYPE, 10, 2) /* Not cached. */ FIELD(TBFLAG_A64, TBID, 12, 2) FIELD(TBFLAG_A64, UNPRIV, 14, 1) +/** + * cpu_mmu_index: + * @env: The cpu environment + * @ifetch: True for code access, false for data access. + * + * Return the core mmu index for the current translation regime. + * This function is used by generic TCG code paths. + */ +static inline int cpu_mmu_index(CPUARMState *env, bool ifetch) +{ + return FIELD_EX32(env->hflags, TBFLAG_ANY, MMUIDX); +} + static inline bool bswap_code(bool sctlr_b) { #ifdef CONFIG_USER_ONLY diff --git a/target/arm/helper.c b/target/arm/helper.c index f7ba34bbf6..f91e5d5345 100644 --- a/target/arm/helper.c +++ b/target/arm/helper.c @@ -12274,11 +12274,6 @@ ARMMMUIdx arm_mmu_idx(CPUARMState *env) return arm_mmu_idx_el(env, arm_current_el(env)); } -int cpu_mmu_index(CPUARMState *env, bool ifetch) -{ - return arm_to_core_mmu_idx(arm_mmu_idx(env)); -} - #ifndef CONFIG_USER_ONLY ARMMMUIdx arm_stage1_mmu_idx(CPUARMState *env) { From 20dc67c947a691fa9df05e76aec6df50204b4b94 Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Thu, 5 Mar 2020 16:09:20 +0000 Subject: [PATCH 33/37] target/arm: Introduce core_to_aa64_mmu_idx MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit If by context we know that we're in AArch64 mode, we need not test for M-profile when reconstructing the full ARMMMUIdx. Signed-off-by: Richard Henderson Reviewed-by: Philippe Mathieu-Daudé Reviewed-by: Peter Maydell Message-id: 20200302175829.2183-4-richard.henderson@linaro.org Signed-off-by: Peter Maydell --- target/arm/internals.h | 6 ++++++ target/arm/translate-a64.c | 2 +- 2 files changed, 7 insertions(+), 1 deletion(-) diff --git a/target/arm/internals.h b/target/arm/internals.h index 9f96a2359f..e633aff36e 100644 --- a/target/arm/internals.h +++ b/target/arm/internals.h @@ -783,6 +783,12 @@ static inline ARMMMUIdx core_to_arm_mmu_idx(CPUARMState *env, int mmu_idx) } } +static inline ARMMMUIdx core_to_aa64_mmu_idx(int mmu_idx) +{ + /* AArch64 is always a-profile. */ + return mmu_idx | ARM_MMU_IDX_A; +} + int arm_mmu_idx_to_el(ARMMMUIdx mmu_idx); /* diff --git a/target/arm/translate-a64.c b/target/arm/translate-a64.c index 579180af0a..c910a49b4e 100644 --- a/target/arm/translate-a64.c +++ b/target/arm/translate-a64.c @@ -14300,7 +14300,7 @@ static void aarch64_tr_init_disas_context(DisasContextBase *dcbase, dc->condexec_mask = 0; dc->condexec_cond = 0; core_mmu_idx = FIELD_EX32(tb_flags, TBFLAG_ANY, MMUIDX); - dc->mmu_idx = core_to_arm_mmu_idx(env, core_mmu_idx); + dc->mmu_idx = core_to_aa64_mmu_idx(core_mmu_idx); dc->tbii = FIELD_EX32(tb_flags, TBFLAG_A64, TBII); dc->tbid = FIELD_EX32(tb_flags, TBFLAG_A64, TBID); dc->current_el = arm_mmu_idx_to_el(dc->mmu_idx); From d4564afe14708a09684ca417f7dc8e8c328658f5 Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Thu, 5 Mar 2020 16:09:20 +0000 Subject: [PATCH 34/37] target/arm: Apply TBI to ESR_ELx in helper_exception_return We missed this case within AArch64.ExceptionReturn. Signed-off-by: Richard Henderson Reviewed-by: Peter Maydell Message-id: 20200302175829.2183-5-richard.henderson@linaro.org Signed-off-by: Peter Maydell --- target/arm/helper-a64.c | 23 ++++++++++++++++++++++- 1 file changed, 22 insertions(+), 1 deletion(-) diff --git a/target/arm/helper-a64.c b/target/arm/helper-a64.c index 509ae93069..123ce50e7a 100644 --- a/target/arm/helper-a64.c +++ b/target/arm/helper-a64.c @@ -1031,6 +1031,8 @@ void HELPER(exception_return)(CPUARMState *env, uint64_t new_pc) "AArch32 EL%d PC 0x%" PRIx32 "\n", cur_el, new_el, env->regs[15]); } else { + int tbii; + env->aarch64 = 1; spsr &= aarch64_pstate_valid_mask(&env_archcpu(env)->isar); pstate_write(env, spsr); @@ -1038,8 +1040,27 @@ void HELPER(exception_return)(CPUARMState *env, uint64_t new_pc) env->pstate &= ~PSTATE_SS; } aarch64_restore_sp(env, new_el); - env->pc = new_pc; helper_rebuild_hflags_a64(env, new_el); + + /* + * Apply TBI to the exception return address. We had to delay this + * until after we selected the new EL, so that we could select the + * correct TBI+TBID bits. This is made easier by waiting until after + * the hflags rebuild, since we can pull the composite TBII field + * from there. + */ + tbii = FIELD_EX32(env->hflags, TBFLAG_A64, TBII); + if ((tbii >> extract64(new_pc, 55, 1)) & 1) { + /* TBI is enabled. */ + int core_mmu_idx = cpu_mmu_index(env, false); + if (regime_has_2_ranges(core_to_aa64_mmu_idx(core_mmu_idx))) { + new_pc = sextract64(new_pc, 0, 56); + } else { + new_pc = extract64(new_pc, 0, 56); + } + } + env->pc = new_pc; + qemu_log_mask(CPU_LOG_INT, "Exception return from AArch64 EL%d to " "AArch64 EL%d PC 0x%" PRIx64 "\n", cur_el, new_el, env->pc); From 7b182eb2467af6c47c9c77c64bbbeed8ed53c330 Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Thu, 5 Mar 2020 16:09:20 +0000 Subject: [PATCH 35/37] target/arm: Move helper_dc_zva to helper-a64.c MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This is an aarch64-only function. Move it out of the shared file. This patch is code movement only. Reviewed-by: Peter Maydell Signed-off-by: Richard Henderson Reviewed-by: Philippe Mathieu-Daudé Message-id: 20200302175829.2183-6-richard.henderson@linaro.org Signed-off-by: Peter Maydell --- target/arm/helper-a64.c | 91 ++++++++++++++++++++++++++++++++++++++++ target/arm/helper-a64.h | 1 + target/arm/helper.h | 1 - target/arm/op_helper.c | 93 ----------------------------------------- 4 files changed, 92 insertions(+), 94 deletions(-) diff --git a/target/arm/helper-a64.c b/target/arm/helper-a64.c index 123ce50e7a..bc0649a44a 100644 --- a/target/arm/helper-a64.c +++ b/target/arm/helper-a64.c @@ -18,6 +18,7 @@ */ #include "qemu/osdep.h" +#include "qemu/units.h" #include "cpu.h" #include "exec/gdbstub.h" #include "exec/helper-proto.h" @@ -1109,4 +1110,94 @@ uint32_t HELPER(sqrt_f16)(uint32_t a, void *fpstp) return float16_sqrt(a, s); } +void HELPER(dc_zva)(CPUARMState *env, uint64_t vaddr_in) +{ + /* + * Implement DC ZVA, which zeroes a fixed-length block of memory. + * Note that we do not implement the (architecturally mandated) + * alignment fault for attempts to use this on Device memory + * (which matches the usual QEMU behaviour of not implementing either + * alignment faults or any memory attribute handling). + */ + ARMCPU *cpu = env_archcpu(env); + uint64_t blocklen = 4 << cpu->dcz_blocksize; + uint64_t vaddr = vaddr_in & ~(blocklen - 1); + +#ifndef CONFIG_USER_ONLY + { + /* + * Slightly awkwardly, QEMU's TARGET_PAGE_SIZE may be less than + * the block size so we might have to do more than one TLB lookup. + * We know that in fact for any v8 CPU the page size is at least 4K + * and the block size must be 2K or less, but TARGET_PAGE_SIZE is only + * 1K as an artefact of legacy v5 subpage support being present in the + * same QEMU executable. So in practice the hostaddr[] array has + * two entries, given the current setting of TARGET_PAGE_BITS_MIN. + */ + int maxidx = DIV_ROUND_UP(blocklen, TARGET_PAGE_SIZE); + void *hostaddr[DIV_ROUND_UP(2 * KiB, 1 << TARGET_PAGE_BITS_MIN)]; + int try, i; + unsigned mmu_idx = cpu_mmu_index(env, false); + TCGMemOpIdx oi = make_memop_idx(MO_UB, mmu_idx); + + assert(maxidx <= ARRAY_SIZE(hostaddr)); + + for (try = 0; try < 2; try++) { + + for (i = 0; i < maxidx; i++) { + hostaddr[i] = tlb_vaddr_to_host(env, + vaddr + TARGET_PAGE_SIZE * i, + 1, mmu_idx); + if (!hostaddr[i]) { + break; + } + } + if (i == maxidx) { + /* + * If it's all in the TLB it's fair game for just writing to; + * we know we don't need to update dirty status, etc. + */ + for (i = 0; i < maxidx - 1; i++) { + memset(hostaddr[i], 0, TARGET_PAGE_SIZE); + } + memset(hostaddr[i], 0, blocklen - (i * TARGET_PAGE_SIZE)); + return; + } + /* + * OK, try a store and see if we can populate the tlb. This + * might cause an exception if the memory isn't writable, + * in which case we will longjmp out of here. We must for + * this purpose use the actual register value passed to us + * so that we get the fault address right. + */ + helper_ret_stb_mmu(env, vaddr_in, 0, oi, GETPC()); + /* Now we can populate the other TLB entries, if any */ + for (i = 0; i < maxidx; i++) { + uint64_t va = vaddr + TARGET_PAGE_SIZE * i; + if (va != (vaddr_in & TARGET_PAGE_MASK)) { + helper_ret_stb_mmu(env, va, 0, oi, GETPC()); + } + } + } + + /* + * Slow path (probably attempt to do this to an I/O device or + * similar, or clearing of a block of code we have translations + * cached for). Just do a series of byte writes as the architecture + * demands. It's not worth trying to use a cpu_physical_memory_map(), + * memset(), unmap() sequence here because: + * + we'd need to account for the blocksize being larger than a page + * + the direct-RAM access case is almost always going to be dealt + * with in the fastpath code above, so there's no speed benefit + * + we would have to deal with the map returning NULL because the + * bounce buffer was in use + */ + for (i = 0; i < blocklen; i++) { + helper_ret_stb_mmu(env, vaddr + i, 0, oi, GETPC()); + } + } +#else + memset(g2h(vaddr), 0, blocklen); +#endif +} diff --git a/target/arm/helper-a64.h b/target/arm/helper-a64.h index a915c1247f..b1a5935f61 100644 --- a/target/arm/helper-a64.h +++ b/target/arm/helper-a64.h @@ -90,6 +90,7 @@ DEF_HELPER_2(advsimd_f16touinth, i32, f16, ptr) DEF_HELPER_2(sqrt_f16, f16, f16, ptr) DEF_HELPER_2(exception_return, void, env, i64) +DEF_HELPER_2(dc_zva, void, env, i64) DEF_HELPER_FLAGS_3(pacia, TCG_CALL_NO_WG, i64, env, i64, i64) DEF_HELPER_FLAGS_3(pacib, TCG_CALL_NO_WG, i64, env, i64, i64) diff --git a/target/arm/helper.h b/target/arm/helper.h index fcbf504121..72eb9e6a1a 100644 --- a/target/arm/helper.h +++ b/target/arm/helper.h @@ -559,7 +559,6 @@ DEF_HELPER_FLAGS_3(crypto_sm4ekey, TCG_CALL_NO_RWG, void, ptr, ptr, ptr) DEF_HELPER_FLAGS_3(crc32, TCG_CALL_NO_RWG_SE, i32, i32, i32, i32) DEF_HELPER_FLAGS_3(crc32c, TCG_CALL_NO_RWG_SE, i32, i32, i32, i32) -DEF_HELPER_2(dc_zva, void, env, i64) DEF_HELPER_FLAGS_5(gvec_qrdmlah_s16, TCG_CALL_NO_RWG, void, ptr, ptr, ptr, ptr, i32) diff --git a/target/arm/op_helper.c b/target/arm/op_helper.c index af3020b78f..eb0de080f1 100644 --- a/target/arm/op_helper.c +++ b/target/arm/op_helper.c @@ -17,7 +17,6 @@ * License along with this library; if not, see . */ #include "qemu/osdep.h" -#include "qemu/units.h" #include "qemu/log.h" #include "qemu/main-loop.h" #include "cpu.h" @@ -936,95 +935,3 @@ uint32_t HELPER(ror_cc)(CPUARMState *env, uint32_t x, uint32_t i) return ((uint32_t)x >> shift) | (x << (32 - shift)); } } - -void HELPER(dc_zva)(CPUARMState *env, uint64_t vaddr_in) -{ - /* - * Implement DC ZVA, which zeroes a fixed-length block of memory. - * Note that we do not implement the (architecturally mandated) - * alignment fault for attempts to use this on Device memory - * (which matches the usual QEMU behaviour of not implementing either - * alignment faults or any memory attribute handling). - */ - - ARMCPU *cpu = env_archcpu(env); - uint64_t blocklen = 4 << cpu->dcz_blocksize; - uint64_t vaddr = vaddr_in & ~(blocklen - 1); - -#ifndef CONFIG_USER_ONLY - { - /* - * Slightly awkwardly, QEMU's TARGET_PAGE_SIZE may be less than - * the block size so we might have to do more than one TLB lookup. - * We know that in fact for any v8 CPU the page size is at least 4K - * and the block size must be 2K or less, but TARGET_PAGE_SIZE is only - * 1K as an artefact of legacy v5 subpage support being present in the - * same QEMU executable. So in practice the hostaddr[] array has - * two entries, given the current setting of TARGET_PAGE_BITS_MIN. - */ - int maxidx = DIV_ROUND_UP(blocklen, TARGET_PAGE_SIZE); - void *hostaddr[DIV_ROUND_UP(2 * KiB, 1 << TARGET_PAGE_BITS_MIN)]; - int try, i; - unsigned mmu_idx = cpu_mmu_index(env, false); - TCGMemOpIdx oi = make_memop_idx(MO_UB, mmu_idx); - - assert(maxidx <= ARRAY_SIZE(hostaddr)); - - for (try = 0; try < 2; try++) { - - for (i = 0; i < maxidx; i++) { - hostaddr[i] = tlb_vaddr_to_host(env, - vaddr + TARGET_PAGE_SIZE * i, - 1, mmu_idx); - if (!hostaddr[i]) { - break; - } - } - if (i == maxidx) { - /* - * If it's all in the TLB it's fair game for just writing to; - * we know we don't need to update dirty status, etc. - */ - for (i = 0; i < maxidx - 1; i++) { - memset(hostaddr[i], 0, TARGET_PAGE_SIZE); - } - memset(hostaddr[i], 0, blocklen - (i * TARGET_PAGE_SIZE)); - return; - } - /* - * OK, try a store and see if we can populate the tlb. This - * might cause an exception if the memory isn't writable, - * in which case we will longjmp out of here. We must for - * this purpose use the actual register value passed to us - * so that we get the fault address right. - */ - helper_ret_stb_mmu(env, vaddr_in, 0, oi, GETPC()); - /* Now we can populate the other TLB entries, if any */ - for (i = 0; i < maxidx; i++) { - uint64_t va = vaddr + TARGET_PAGE_SIZE * i; - if (va != (vaddr_in & TARGET_PAGE_MASK)) { - helper_ret_stb_mmu(env, va, 0, oi, GETPC()); - } - } - } - - /* - * Slow path (probably attempt to do this to an I/O device or - * similar, or clearing of a block of code we have translations - * cached for). Just do a series of byte writes as the architecture - * demands. It's not worth trying to use a cpu_physical_memory_map(), - * memset(), unmap() sequence here because: - * + we'd need to account for the blocksize being larger than a page - * + the direct-RAM access case is almost always going to be dealt - * with in the fastpath code above, so there's no speed benefit - * + we would have to deal with the map returning NULL because the - * bounce buffer was in use - */ - for (i = 0; i < blocklen; i++) { - helper_ret_stb_mmu(env, vaddr + i, 0, oi, GETPC()); - } - } -#else - memset(g2h(vaddr), 0, blocklen); -#endif -} From 1371b02c5a060e423e70560dbca769b54e471ba9 Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Thu, 5 Mar 2020 16:09:21 +0000 Subject: [PATCH 36/37] target/arm: Use DEF_HELPER_FLAGS for helper_dc_zva MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The function does not write registers, and only reads them by implication via the exception path. Reviewed-by: Peter Maydell Signed-off-by: Richard Henderson Reviewed-by: Philippe Mathieu-Daudé Message-id: 20200302175829.2183-7-richard.henderson@linaro.org Signed-off-by: Peter Maydell --- target/arm/helper-a64.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/target/arm/helper-a64.h b/target/arm/helper-a64.h index b1a5935f61..3df7c185aa 100644 --- a/target/arm/helper-a64.h +++ b/target/arm/helper-a64.h @@ -90,7 +90,7 @@ DEF_HELPER_2(advsimd_f16touinth, i32, f16, ptr) DEF_HELPER_2(sqrt_f16, f16, f16, ptr) DEF_HELPER_2(exception_return, void, env, i64) -DEF_HELPER_2(dc_zva, void, env, i64) +DEF_HELPER_FLAGS_2(dc_zva, TCG_CALL_NO_WG, void, env, i64) DEF_HELPER_FLAGS_3(pacia, TCG_CALL_NO_WG, i64, env, i64, i64) DEF_HELPER_FLAGS_3(pacib, TCG_CALL_NO_WG, i64, env, i64, i64) From 597d61a3b1f94c53a3aaa77671697c0c5f797dbf Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Thu, 5 Mar 2020 16:09:21 +0000 Subject: [PATCH 37/37] target/arm: Clean address for DC ZVA This data access was forgotten when we added support for cleaning addresses of TBI information. Fixes: 3a471103ac1823ba Reviewed-by: Peter Maydell Signed-off-by: Richard Henderson Message-id: 20200302175829.2183-8-richard.henderson@linaro.org Signed-off-by: Peter Maydell --- target/arm/translate-a64.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/target/arm/translate-a64.c b/target/arm/translate-a64.c index c910a49b4e..fefe8af7f5 100644 --- a/target/arm/translate-a64.c +++ b/target/arm/translate-a64.c @@ -1784,7 +1784,7 @@ static void handle_sys(DisasContext *s, uint32_t insn, bool isread, return; case ARM_CP_DC_ZVA: /* Writes clear the aligned block of memory which rt points into. */ - tcg_rt = cpu_reg(s, rt); + tcg_rt = clean_data_tbi(s, cpu_reg(s, rt)); gen_helper_dc_zva(cpu_env, tcg_rt); return; default: