mirror of
https://github.com/qemu/qemu.git
synced 2024-11-26 04:13:39 +08:00
* versal: Implement ADMA
* Implement (trivially) ARMv8.2-TTCNP * hw/arm/smmu-common: a fix to smmu_find_smmu_pcibus * Remove unnecessary endianness-handling on some boards * Avoid minor memory leaks from timer_new in some devices * Honour more of the HCR_EL2 trap bits * Complain rather than ignoring bad command line options for cubieboard * Honour TBI for DC ZVA and exception return -----BEGIN PGP SIGNATURE----- iQJNBAABCAA3FiEE4aXFk81BneKOgxXPPCUl7RQ2DN4FAl5hKRkZHHBldGVyLm1h eWRlbGxAbGluYXJvLm9yZwAKCRA8JSXtFDYM3vdjD/wPaX9+d1uKt7PHNQ0+LHQb bzLvBV0Ehz912h2buGaGHlaDA57JD1nkerE1EYgxioZm7vDWl4GEokpRvlFVNjY6 RIT++1/wc3hGidJh5LMLtCv++Phr/fDw5eb4rT8KR4kyyKaHgRg85LIjEw5y1PDS tIVGFmzd8uhfd9oDSLNe2eGAv4qzcvbyGtGzX8+6MunCLnHdPknDJhMwgD5+ebCb bqj2oyBJM1LLtQITjhoM+dHmHcL/o5yb9XbmaqcPFm3zH3sdtP17FYAJl3aezQcH Rn4vod913RipwmrQzaQRotyaZB0p2eoDPlYBud4DwUEMR9yPMc/GBrfdLWGp2LiW 7qMgxdodV0XZeMUEBjdJsBqnOotSNoDdw+R1uttT880/7sA4r5pv/z48dW+FeClx 1WnsVbqI0ayDrJVQ/v4Q/GdszSV+Ixj7RJcrRSBPuTx5yLVz11CvHwyquyX1Ff5s mvrBtkWGJnFuxjHnqqJ1xVxhy9uIaIYAJWdU4Mr9FngAbun+FOv5cT0AtYc+TbjO SoPcbiI9H6t/ax4OPZUD9j8UZOtUnEf5rGOJrr3+YctrmG4oUKcGJdLD4H/KSAFZ MjqmCCqFD4nNgQJ9VsQJD4ykvWWmQxGWTnQeG5NFgGZDrd1ltOZWCnk5nrQ9zOy/ GgKUugOiW7EITNZvyTOzEw== =hT5f -----END PGP SIGNATURE----- Merge remote-tracking branch 'remotes/pmaydell/tags/pull-target-arm-20200305' into staging * versal: Implement ADMA * Implement (trivially) ARMv8.2-TTCNP * hw/arm/smmu-common: a fix to smmu_find_smmu_pcibus * Remove unnecessary endianness-handling on some boards * Avoid minor memory leaks from timer_new in some devices * Honour more of the HCR_EL2 trap bits * Complain rather than ignoring bad command line options for cubieboard * Honour TBI for DC ZVA and exception return # gpg: Signature made Thu 05 Mar 2020 16:30:17 GMT # gpg: using RSA key E1A5C593CD419DE28E8315CF3C2525ED14360CDE # gpg: issuer "peter.maydell@linaro.org" # gpg: Good signature from "Peter Maydell <peter.maydell@linaro.org>" [ultimate] # gpg: aka "Peter Maydell <pmaydell@gmail.com>" [ultimate] # gpg: aka "Peter Maydell <pmaydell@chiark.greenend.org.uk>" [ultimate] # Primary key fingerprint: E1A5 C593 CD41 9DE2 8E83 15CF 3C25 25ED 1436 0CDE * remotes/pmaydell/tags/pull-target-arm-20200305: (37 commits) target/arm: Clean address for DC ZVA target/arm: Use DEF_HELPER_FLAGS for helper_dc_zva target/arm: Move helper_dc_zva to helper-a64.c target/arm: Apply TBI to ESR_ELx in helper_exception_return target/arm: Introduce core_to_aa64_mmu_idx target/arm: Optimize cpu_mmu_index target/arm: Replicate TBI/TBID bits for single range regimes hw/arm/cubieboard: report error when using unsupported -bios argument hw/arm/cubieboard: restrict allowed RAM size to 512MiB and 1GiB hw/arm/cubieboard: restrict allowed CPU type to ARM Cortex-A8 hw/arm/cubieboard: use ARM Cortex-A8 as the default CPU in machine definition tests/tcg/aarch64: Add newline in pauth-1 printf target/arm: Honor the HCR_EL2.TTLB bit target/arm: Honor the HCR_EL2.TPU bit target/arm: Honor the HCR_EL2.TPCP bit target/arm: Honor the HCR_EL2.TACR bit target/arm: Honor the HCR_EL2.TSW bit target/arm: Honor the HCR_EL2.{TVM,TRVM} bits target/arm: Improve masking in arm_hcr_el2_eff target/arm: Remove EL2 and EL3 setup from user-only ... Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
This commit is contained in:
commit
55afdac3b2
@ -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"
|
||||
@ -30,9 +31,30 @@ 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;
|
||||
|
||||
/* 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) {
|
||||
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");
|
||||
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: ");
|
||||
@ -68,8 +90,9 @@ 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->default_ram_size = 1 * GiB;
|
||||
mc->init = cubieboard_init;
|
||||
mc->block_default_type = IF_IDE;
|
||||
mc->units_per_default_bus = 1;
|
||||
|
@ -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);
|
||||
}
|
||||
|
@ -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);
|
||||
}
|
||||
|
@ -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);
|
||||
|
||||
|
@ -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);
|
||||
}
|
||||
|
@ -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 = {
|
||||
|
@ -290,19 +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;
|
||||
if (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;
|
||||
}
|
||||
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 smmu_pci_bus;
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static AddressSpace *smmu_find_add_as(PCIBus *bus, void *opaque, int devfn)
|
||||
|
@ -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 = {
|
||||
|
@ -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,
|
||||
|
@ -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);
|
||||
|
@ -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);
|
||||
|
||||
|
@ -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);
|
||||
}
|
||||
|
@ -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 = {
|
||||
|
@ -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
|
||||
|
||||
|
@ -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
|
||||
@ -1103,11 +1097,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 +1218,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;
|
||||
@ -2702,6 +2698,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
|
||||
|
@ -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)
|
||||
@ -2936,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,
|
||||
@ -3225,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
|
||||
|
@ -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;
|
||||
|
@ -18,6 +18,7 @@
|
||||
*/
|
||||
|
||||
#include "qemu/osdep.h"
|
||||
#include "qemu/units.h"
|
||||
#include "cpu.h"
|
||||
#include "exec/gdbstub.h"
|
||||
#include "exec/helper-proto.h"
|
||||
@ -1031,6 +1032,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 +1041,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);
|
||||
@ -1088,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
|
||||
}
|
||||
|
@ -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_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)
|
||||
|
@ -530,6 +530,49 @@ 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;
|
||||
}
|
||||
|
||||
/* 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;
|
||||
}
|
||||
|
||||
/* 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;
|
||||
}
|
||||
|
||||
/* 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);
|
||||
@ -785,12 +828,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 +848,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 +1041,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 +2253,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 +2279,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 },
|
||||
@ -2245,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
|
||||
};
|
||||
@ -3886,20 +3948,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 +3970,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 +4004,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 +4225,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, },
|
||||
@ -4253,15 +4323,46 @@ 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)
|
||||
static CPAccessResult aa64_cacheop_poc_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;
|
||||
/* 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;
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
@ -4663,86 +4764,89 @@ 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, .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, .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 },
|
||||
.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, .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,
|
||||
.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,
|
||||
.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, .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,
|
||||
.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,
|
||||
@ -4828,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 },
|
||||
@ -4861,34 +4968,34 @@ 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,
|
||||
.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 },
|
||||
.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 },
|
||||
.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 },
|
||||
.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 },
|
||||
.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, .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) } },
|
||||
@ -5086,11 +5193,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 +5215,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 +5257,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 +5275,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));
|
||||
}
|
||||
|
||||
/*
|
||||
@ -5184,14 +5303,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;
|
||||
}
|
||||
@ -6667,7 +6809,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
|
||||
};
|
||||
|
||||
@ -6675,7 +6817,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*/
|
||||
@ -6888,8 +7030,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,
|
||||
@ -7645,8 +7787,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,
|
||||
@ -7730,7 +7872,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,
|
||||
@ -10316,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;
|
||||
}
|
||||
}
|
||||
|
||||
@ -10327,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;
|
||||
}
|
||||
}
|
||||
|
||||
@ -10591,6 +10735,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
|
||||
@ -12126,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)
|
||||
{
|
||||
|
@ -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)
|
||||
|
@ -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);
|
||||
|
||||
/*
|
||||
|
@ -17,7 +17,6 @@
|
||||
* License along with this library; if not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
#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
|
||||
}
|
||||
|
@ -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:
|
||||
@ -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);
|
||||
|
@ -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;
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user