diff --git a/hw/arm/ast2400.c b/hw/arm/ast2400.c index 5510a8a374..4a9de0e10c 100644 --- a/hw/arm/ast2400.c +++ b/hw/arm/ast2400.c @@ -18,12 +18,14 @@ #include "hw/arm/ast2400.h" #include "hw/char/serial.h" #include "qemu/log.h" +#include "hw/i2c/aspeed_i2c.h" #define AST2400_UART_5_BASE 0x00184000 #define AST2400_IOMEM_SIZE 0x00200000 #define AST2400_IOMEM_BASE 0x1E600000 #define AST2400_VIC_BASE 0x1E6C0000 #define AST2400_TIMER_BASE 0x1E782000 +#define AST2400_I2C_BASE 0x1E78A000 static const int uart_irqs[] = { 9, 32, 33, 34, 10 }; static const int timer_irqs[] = { 16, 17, 18, 35, 36, 37, 38, 39, }; @@ -66,6 +68,10 @@ static void ast2400_init(Object *obj) object_initialize(&s->timerctrl, sizeof(s->timerctrl), TYPE_ASPEED_TIMER); object_property_add_child(obj, "timerctrl", OBJECT(&s->timerctrl), NULL); qdev_set_parent_bus(DEVICE(&s->timerctrl), sysbus_get_default()); + + object_initialize(&s->i2c, sizeof(s->i2c), TYPE_ASPEED_I2C); + object_property_add_child(obj, "i2c", OBJECT(&s->i2c), NULL); + qdev_set_parent_bus(DEVICE(&s->i2c), sysbus_get_default()); } static void ast2400_realize(DeviceState *dev, Error **errp) @@ -110,6 +116,16 @@ static void ast2400_realize(DeviceState *dev, Error **errp) serial_mm_init(&s->iomem, AST2400_UART_5_BASE, 2, uart5, 38400, serial_hds[0], DEVICE_LITTLE_ENDIAN); } + + /* I2C */ + object_property_set_bool(OBJECT(&s->i2c), true, "realized", &err); + if (err) { + error_propagate(errp, err); + return; + } + sysbus_mmio_map(SYS_BUS_DEVICE(&s->i2c), 0, AST2400_I2C_BASE); + sysbus_connect_irq(SYS_BUS_DEVICE(&s->i2c), 0, + qdev_get_gpio_in(DEVICE(&s->vic), 12)); } static void ast2400_class_init(ObjectClass *oc, void *data) diff --git a/hw/arm/bcm2835_peripherals.c b/hw/arm/bcm2835_peripherals.c index 234d518430..2e641a3989 100644 --- a/hw/arm/bcm2835_peripherals.c +++ b/hw/arm/bcm2835_peripherals.c @@ -14,6 +14,7 @@ #include "hw/misc/bcm2835_mbox_defs.h" #include "hw/arm/raspi_platform.h" #include "sysemu/char.h" +#include "sysemu/sysemu.h" /* Peripheral base address on the VC (GPU) system bus */ #define BCM2835_VC_PERI_BASE 0x7e000000 @@ -106,7 +107,6 @@ static void bcm2835_peripherals_realize(DeviceState *dev, Error **errp) MemoryRegion *ram; Error *err = NULL; uint32_t ram_size, vcram_size; - CharDriverState *chr; int n; obj = object_property_get_link(OBJECT(dev), "ram", &err); @@ -147,6 +147,7 @@ static void bcm2835_peripherals_realize(DeviceState *dev, Error **errp) sysbus_pass_irq(SYS_BUS_DEVICE(s), SYS_BUS_DEVICE(&s->ic)); /* UART0 */ + qdev_prop_set_chr(DEVICE(s->uart0), "chardev", serial_hds[0]); object_property_set_bool(OBJECT(s->uart0), true, "realized", &err); if (err) { error_propagate(errp, err); @@ -158,17 +159,8 @@ static void bcm2835_peripherals_realize(DeviceState *dev, Error **errp) sysbus_connect_irq(s->uart0, 0, qdev_get_gpio_in_named(DEVICE(&s->ic), BCM2835_IC_GPU_IRQ, INTERRUPT_UART)); - /* AUX / UART1 */ - /* TODO: don't call qemu_char_get_next_serial() here, instead set - * chardev properties for each uart at the board level, once pl011 - * (uart0) has been updated to avoid qemu_char_get_next_serial() - */ - chr = qemu_char_get_next_serial(); - if (chr == NULL) { - chr = qemu_chr_new("bcm2835.uart1", "null", NULL); - } - qdev_prop_set_chr(DEVICE(&s->aux), "chardev", chr); + qdev_prop_set_chr(DEVICE(&s->aux), "chardev", serial_hds[1]); object_property_set_bool(OBJECT(&s->aux), true, "realized", &err); if (err) { @@ -292,8 +284,6 @@ static void bcm2835_peripherals_class_init(ObjectClass *oc, void *data) DeviceClass *dc = DEVICE_CLASS(oc); dc->realize = bcm2835_peripherals_realize; - /* Reason: realize() method uses qemu_char_get_next_serial() */ - dc->cannot_instantiate_with_device_add_yet = true; } static const TypeInfo bcm2835_peripherals_type_info = { diff --git a/hw/arm/digic.c b/hw/arm/digic.c index e0f9730325..d60ea395f4 100644 --- a/hw/arm/digic.c +++ b/hw/arm/digic.c @@ -23,6 +23,7 @@ #include "qemu/osdep.h" #include "qapi/error.h" #include "hw/arm/digic.h" +#include "sysemu/sysemu.h" #define DIGIC4_TIMER_BASE(n) (0xc0210000 + (n) * 0x100) @@ -84,6 +85,7 @@ static void digic_realize(DeviceState *dev, Error **errp) sysbus_mmio_map(sbd, 0, DIGIC4_TIMER_BASE(i)); } + qdev_prop_set_chr(DEVICE(&s->uart), "chardev", serial_hds[0]); object_property_set_bool(OBJECT(&s->uart), true, "realized", &err); if (err != NULL) { error_propagate(errp, err); diff --git a/hw/arm/highbank.c b/hw/arm/highbank.c index 41029a651d..80e5fd458b 100644 --- a/hw/arm/highbank.c +++ b/hw/arm/highbank.c @@ -30,6 +30,7 @@ #include "sysemu/block-backend.h" #include "exec/address-spaces.h" #include "qemu/error-report.h" +#include "hw/char/pl011.h" #define SMP_BOOT_ADDR 0x100 #define SMP_BOOT_REG 0x40 @@ -326,7 +327,7 @@ static void calxeda_init(MachineState *machine, enum cxmachines machine_id) busdev = SYS_BUS_DEVICE(dev); sysbus_mmio_map(busdev, 0, 0xfff34000); sysbus_connect_irq(busdev, 0, pic[18]); - sysbus_create_simple("pl011", 0xfff36000, pic[20]); + pl011_create(0xfff36000, pic[20], serial_hds[0]); dev = qdev_create(NULL, "highbank-regs"); qdev_init_nofail(dev); diff --git a/hw/arm/integratorcp.c b/hw/arm/integratorcp.c index 24f16874f9..96dc150025 100644 --- a/hw/arm/integratorcp.c +++ b/hw/arm/integratorcp.c @@ -20,6 +20,7 @@ #include "exec/address-spaces.h" #include "sysemu/sysemu.h" #include "qemu/error-report.h" +#include "hw/char/pl011.h" #define TYPE_INTEGRATOR_CM "integrator_core" #define INTEGRATOR_CM(obj) \ @@ -588,8 +589,8 @@ static void integratorcp_init(MachineState *machine) sysbus_create_varargs("integrator_pit", 0x13000000, pic[5], pic[6], pic[7], NULL); sysbus_create_simple("pl031", 0x15000000, pic[8]); - sysbus_create_simple("pl011", 0x16000000, pic[1]); - sysbus_create_simple("pl011", 0x17000000, pic[2]); + pl011_create(0x16000000, pic[1], serial_hds[0]); + pl011_create(0x17000000, pic[2], serial_hds[1]); icp = sysbus_create_simple(TYPE_ICP_CONTROL_REGS, 0xcb000000, qdev_get_gpio_in(sic, 3)); sysbus_create_simple("pl050_keyboard", 0x18000000, pic[3]); diff --git a/hw/arm/realview.c b/hw/arm/realview.c index 3222b360e4..7d0aa6ff4f 100644 --- a/hw/arm/realview.c +++ b/hw/arm/realview.c @@ -23,6 +23,7 @@ #include "sysemu/block-backend.h" #include "exec/address-spaces.h" #include "qemu/error-report.h" +#include "hw/char/pl011.h" #define SMP_BOOT_ADDR 0xe0000000 #define SMP_BOOTREG_ADDR 0x10000030 @@ -202,10 +203,10 @@ static void realview_init(MachineState *machine, sysbus_create_simple("pl050_keyboard", 0x10006000, pic[20]); sysbus_create_simple("pl050_mouse", 0x10007000, pic[21]); - sysbus_create_simple("pl011", 0x10009000, pic[12]); - sysbus_create_simple("pl011", 0x1000a000, pic[13]); - sysbus_create_simple("pl011", 0x1000b000, pic[14]); - sysbus_create_simple("pl011", 0x1000c000, pic[15]); + pl011_create(0x10009000, pic[12], serial_hds[0]); + pl011_create(0x1000a000, pic[13], serial_hds[1]); + pl011_create(0x1000b000, pic[14], serial_hds[2]); + pl011_create(0x1000c000, pic[15], serial_hds[3]); /* DMA controller is optional, apparently. */ sysbus_create_simple("pl081", 0x10030000, pic[24]); diff --git a/hw/arm/stellaris.c b/hw/arm/stellaris.c index 44591716fe..794a3ada71 100644 --- a/hw/arm/stellaris.c +++ b/hw/arm/stellaris.c @@ -20,6 +20,7 @@ #include "qemu/log.h" #include "exec/address-spaces.h" #include "sysemu/sysemu.h" +#include "hw/char/pl011.h" #define GPIO_A 0 #define GPIO_B 1 @@ -1303,8 +1304,9 @@ static void stellaris_init(const char *kernel_filename, const char *cpu_model, for (i = 0; i < 4; i++) { if (board->dc2 & (1 << i)) { - sysbus_create_simple("pl011_luminary", 0x4000c000 + i * 0x1000, - qdev_get_gpio_in(nvic, uart_irq[i])); + pl011_luminary_create(0x4000c000 + i * 0x1000, + qdev_get_gpio_in(nvic, uart_irq[i]), + serial_hds[i]); } } if (board->dc2 & (1 << 4)) { diff --git a/hw/arm/stm32f205_soc.c b/hw/arm/stm32f205_soc.c index 9c1dafbb19..de26b8caff 100644 --- a/hw/arm/stm32f205_soc.c +++ b/hw/arm/stm32f205_soc.c @@ -107,6 +107,7 @@ static void stm32f205_soc_realize(DeviceState *dev_soc, Error **errp) /* Attach UART (uses USART registers) and USART controllers */ for (i = 0; i < STM_NUM_USARTS; i++) { usartdev = DEVICE(&(s->usart[i])); + qdev_prop_set_chr(usartdev, "chardev", i < MAX_SERIAL_PORTS ? serial_hds[i] : NULL); object_property_set_bool(OBJECT(&s->usart[i]), true, "realized", &err); if (err != NULL) { error_propagate(errp, err); diff --git a/hw/arm/versatilepb.c b/hw/arm/versatilepb.c index d079bc9e82..20dd3561c8 100644 --- a/hw/arm/versatilepb.c +++ b/hw/arm/versatilepb.c @@ -23,6 +23,7 @@ #include "exec/address-spaces.h" #include "hw/block/flash.h" #include "qemu/error-report.h" +#include "hw/char/pl011.h" #define VERSATILE_FLASH_ADDR 0x34000000 #define VERSATILE_FLASH_SIZE (64 * 1024 * 1024) @@ -284,10 +285,10 @@ static void versatile_init(MachineState *machine, int board_id) n--; } - sysbus_create_simple("pl011", 0x101f1000, pic[12]); - sysbus_create_simple("pl011", 0x101f2000, pic[13]); - sysbus_create_simple("pl011", 0x101f3000, pic[14]); - sysbus_create_simple("pl011", 0x10009000, sic[6]); + pl011_create(0x101f1000, pic[12], serial_hds[0]); + pl011_create(0x101f2000, pic[13], serial_hds[1]); + pl011_create(0x101f3000, pic[14], serial_hds[2]); + pl011_create(0x10009000, sic[6], serial_hds[3]); sysbus_create_simple("pl080", 0x10130000, pic[17]); sysbus_create_simple("sp804", 0x101e2000, pic[4]); diff --git a/hw/arm/vexpress.c b/hw/arm/vexpress.c index 70b3e701e0..58760f40ca 100644 --- a/hw/arm/vexpress.c +++ b/hw/arm/vexpress.c @@ -39,6 +39,7 @@ #include "sysemu/device_tree.h" #include "qemu/error-report.h" #include +#include "hw/char/pl011.h" #define VEXPRESS_BOARD_ID 0x8e0 #define VEXPRESS_FLASH_SIZE (64 * 1024 * 1024) @@ -631,10 +632,10 @@ static void vexpress_common_init(MachineState *machine) sysbus_create_simple("pl050_keyboard", map[VE_KMI0], pic[12]); sysbus_create_simple("pl050_mouse", map[VE_KMI1], pic[13]); - sysbus_create_simple("pl011", map[VE_UART0], pic[5]); - sysbus_create_simple("pl011", map[VE_UART1], pic[6]); - sysbus_create_simple("pl011", map[VE_UART2], pic[7]); - sysbus_create_simple("pl011", map[VE_UART3], pic[8]); + pl011_create(map[VE_UART0], pic[5], serial_hds[0]); + pl011_create(map[VE_UART1], pic[6], serial_hds[1]); + pl011_create(map[VE_UART2], pic[7], serial_hds[2]); + pl011_create(map[VE_UART3], pic[8], serial_hds[3]); sysbus_create_simple("sp804", map[VE_TIMER01], pic[2]); sysbus_create_simple("sp804", map[VE_TIMER23], pic[3]); diff --git a/hw/arm/virt-acpi-build.c b/hw/arm/virt-acpi-build.c index 26a7bac48f..83a54203b8 100644 --- a/hw/arm/virt-acpi-build.c +++ b/hw/arm/virt-acpi-build.c @@ -231,7 +231,8 @@ static void acpi_dsdt_add_pci(Aml *scope, const MemMapEntry *memmap, aml_append(rbuf, aml_qword_memory(AML_POS_DECODE, AML_MIN_FIXED, AML_MAX_FIXED, AML_NON_CACHEABLE, AML_READ_WRITE, 0x0000, - base_mmio_high, base_mmio_high, 0x0000, + base_mmio_high, + base_mmio_high + size_mmio_high - 1, 0x0000, size_mmio_high)); } diff --git a/hw/arm/virt.c b/hw/arm/virt.c index e77ed88afb..8e46137e9b 100644 --- a/hw/arm/virt.c +++ b/hw/arm/virt.c @@ -536,6 +536,7 @@ static void create_uart(const VirtBoardInfo *vbi, qemu_irq *pic, int uart, DeviceState *dev = qdev_create(NULL, "pl011"); SysBusDevice *s = SYS_BUS_DEVICE(dev); + qdev_prop_set_chr(dev, "chardev", serial_hds[0]); qdev_init_nofail(dev); memory_region_add_subregion(mem, base, sysbus_mmio_get_region(s, 0)); @@ -1122,10 +1123,14 @@ static void machvirt_init(MachineState *machine) * KVM is not available yet */ if (!gic_version) { + if (!kvm_enabled()) { + error_report("gic-version=host requires KVM"); + exit(1); + } + gic_version = kvm_arm_vgic_probe(); if (!gic_version) { error_report("Unable to determine GIC version supported by host"); - error_printf("KVM acceleration is probably not supported\n"); exit(1); } } diff --git a/hw/arm/xilinx_zynq.c b/hw/arm/xilinx_zynq.c index 98b17c9aed..aefebcfa6d 100644 --- a/hw/arm/xilinx_zynq.c +++ b/hw/arm/xilinx_zynq.c @@ -32,6 +32,7 @@ #include "hw/ssi/ssi.h" #include "qemu/error-report.h" #include "hw/sd/sd.h" +#include "hw/char/cadence_uart.h" #define NUM_SPI_FLASHES 4 #define NUM_QSPI_FLASHES 2 @@ -235,8 +236,8 @@ static void zynq_init(MachineState *machine) sysbus_create_simple("xlnx,ps7-usb", 0xE0002000, pic[53-IRQ_OFFSET]); sysbus_create_simple("xlnx,ps7-usb", 0xE0003000, pic[76-IRQ_OFFSET]); - sysbus_create_simple("cadence_uart", 0xE0000000, pic[59-IRQ_OFFSET]); - sysbus_create_simple("cadence_uart", 0xE0001000, pic[82-IRQ_OFFSET]); + cadence_uart_create(0xE0000000, pic[59 - IRQ_OFFSET], serial_hds[0]); + cadence_uart_create(0xE0001000, pic[82 - IRQ_OFFSET], serial_hds[1]); sysbus_create_varargs("cadence_ttc", 0xF8001000, pic[42-IRQ_OFFSET], pic[43-IRQ_OFFSET], pic[44-IRQ_OFFSET], NULL); diff --git a/hw/arm/xlnx-ep108.c b/hw/arm/xlnx-ep108.c index 40f7cc1425..34b4641712 100644 --- a/hw/arm/xlnx-ep108.c +++ b/hw/arm/xlnx-ep108.c @@ -114,3 +114,11 @@ static void xlnx_ep108_machine_init(MachineClass *mc) } DEFINE_MACHINE("xlnx-ep108", xlnx_ep108_machine_init) + +static void xlnx_zcu102_machine_init(MachineClass *mc) +{ + mc->desc = "Xilinx ZynqMP ZCU102 board"; + mc->init = xlnx_ep108_init; +} + +DEFINE_MACHINE("xlnx-zcu102", xlnx_zcu102_machine_init) diff --git a/hw/arm/xlnx-zynqmp.c b/hw/arm/xlnx-zynqmp.c index 4d504da643..308d6770c0 100644 --- a/hw/arm/xlnx-zynqmp.c +++ b/hw/arm/xlnx-zynqmp.c @@ -22,6 +22,8 @@ #include "hw/arm/xlnx-zynqmp.h" #include "hw/intc/arm_gic_common.h" #include "exec/address-spaces.h" +#include "sysemu/kvm.h" +#include "kvm_arm.h" #define GIC_NUM_SPI_INTR 160 @@ -83,6 +85,41 @@ static inline int arm_gic_ppi_index(int cpu_nr, int ppi_index) return GIC_NUM_SPI_INTR + cpu_nr * GIC_INTERNAL + ppi_index; } +static void xlnx_zynqmp_create_rpu(XlnxZynqMPState *s, const char *boot_cpu, + Error **errp) +{ + Error *err = NULL; + int i; + + for (i = 0; i < XLNX_ZYNQMP_NUM_RPU_CPUS; i++) { + char *name; + + object_initialize(&s->rpu_cpu[i], sizeof(s->rpu_cpu[i]), + "cortex-r5-" TYPE_ARM_CPU); + object_property_add_child(OBJECT(s), "rpu-cpu[*]", + OBJECT(&s->rpu_cpu[i]), &error_abort); + + name = object_get_canonical_path_component(OBJECT(&s->rpu_cpu[i])); + if (strcmp(name, boot_cpu)) { + /* Secondary CPUs start in PSCI powered-down state */ + object_property_set_bool(OBJECT(&s->rpu_cpu[i]), true, + "start-powered-off", &error_abort); + } else { + s->boot_cpu_ptr = &s->rpu_cpu[i]; + } + g_free(name); + + object_property_set_bool(OBJECT(&s->rpu_cpu[i]), true, "reset-hivecs", + &error_abort); + object_property_set_bool(OBJECT(&s->rpu_cpu[i]), true, "realized", + &err); + if (err) { + error_propagate(errp, err); + return; + } + } +} + static void xlnx_zynqmp_init(Object *obj) { XlnxZynqMPState *s = XLNX_ZYNQMP(obj); @@ -95,19 +132,12 @@ static void xlnx_zynqmp_init(Object *obj) &error_abort); } - for (i = 0; i < XLNX_ZYNQMP_NUM_RPU_CPUS; i++) { - object_initialize(&s->rpu_cpu[i], sizeof(s->rpu_cpu[i]), - "cortex-r5-" TYPE_ARM_CPU); - object_property_add_child(obj, "rpu-cpu[*]", OBJECT(&s->rpu_cpu[i]), - &error_abort); - } - object_property_add_link(obj, "ddr-ram", TYPE_MEMORY_REGION, (Object **)&s->ddr_ram, qdev_prop_allow_set_link_before_realize, OBJ_PROP_LINK_UNREF_ON_RELEASE, &error_abort); - object_initialize(&s->gic, sizeof(s->gic), TYPE_ARM_GIC); + object_initialize(&s->gic, sizeof(s->gic), gic_class_name()); qdev_set_parent_bus(DEVICE(&s->gic), sysbus_get_default()); for (i = 0; i < XLNX_ZYNQMP_NUM_GEMS; i++) { @@ -196,11 +226,42 @@ static void xlnx_zynqmp_realize(DeviceState *dev, Error **errp) qdev_prop_set_uint32(DEVICE(&s->gic), "num-irq", GIC_NUM_SPI_INTR + 32); qdev_prop_set_uint32(DEVICE(&s->gic), "revision", 2); qdev_prop_set_uint32(DEVICE(&s->gic), "num-cpu", XLNX_ZYNQMP_NUM_APU_CPUS); + + /* Realize APUs before realizing the GIC. KVM requires this. */ + for (i = 0; i < XLNX_ZYNQMP_NUM_APU_CPUS; i++) { + char *name; + + object_property_set_int(OBJECT(&s->apu_cpu[i]), QEMU_PSCI_CONDUIT_SMC, + "psci-conduit", &error_abort); + + name = object_get_canonical_path_component(OBJECT(&s->apu_cpu[i])); + if (strcmp(name, boot_cpu)) { + /* Secondary CPUs start in PSCI powered-down state */ + object_property_set_bool(OBJECT(&s->apu_cpu[i]), true, + "start-powered-off", &error_abort); + } else { + s->boot_cpu_ptr = &s->apu_cpu[i]; + } + g_free(name); + + object_property_set_bool(OBJECT(&s->apu_cpu[i]), + s->secure, "has_el3", NULL); + object_property_set_int(OBJECT(&s->apu_cpu[i]), GIC_BASE_ADDR, + "reset-cbar", &error_abort); + object_property_set_bool(OBJECT(&s->apu_cpu[i]), true, "realized", + &err); + if (err) { + error_propagate(errp, err); + return; + } + } + object_property_set_bool(OBJECT(&s->gic), true, "realized", &err); if (err) { error_propagate(errp, err); return; } + assert(ARRAY_SIZE(xlnx_zynqmp_gic_regions) == XLNX_ZYNQMP_GIC_REGIONS); for (i = 0; i < XLNX_ZYNQMP_GIC_REGIONS; i++) { SysBusDevice *gic = SYS_BUS_DEVICE(&s->gic); @@ -223,29 +284,6 @@ static void xlnx_zynqmp_realize(DeviceState *dev, Error **errp) for (i = 0; i < XLNX_ZYNQMP_NUM_APU_CPUS; i++) { qemu_irq irq; - char *name; - - object_property_set_int(OBJECT(&s->apu_cpu[i]), QEMU_PSCI_CONDUIT_SMC, - "psci-conduit", &error_abort); - - name = object_get_canonical_path_component(OBJECT(&s->apu_cpu[i])); - if (strcmp(name, boot_cpu)) { - /* Secondary CPUs start in PSCI powered-down state */ - object_property_set_bool(OBJECT(&s->apu_cpu[i]), true, - "start-powered-off", &error_abort); - } else { - s->boot_cpu_ptr = &s->apu_cpu[i]; - } - g_free(name); - - object_property_set_int(OBJECT(&s->apu_cpu[i]), GIC_BASE_ADDR, - "reset-cbar", &error_abort); - object_property_set_bool(OBJECT(&s->apu_cpu[i]), true, "realized", - &err); - if (err) { - error_propagate(errp, err); - return; - } sysbus_connect_irq(SYS_BUS_DEVICE(&s->gic), i, qdev_get_gpio_in(DEVICE(&s->apu_cpu[i]), @@ -258,23 +296,8 @@ static void xlnx_zynqmp_realize(DeviceState *dev, Error **errp) qdev_connect_gpio_out(DEVICE(&s->apu_cpu[i]), 1, irq); } - for (i = 0; i < XLNX_ZYNQMP_NUM_RPU_CPUS; i++) { - char *name; - - name = object_get_canonical_path_component(OBJECT(&s->rpu_cpu[i])); - if (strcmp(name, boot_cpu)) { - /* Secondary CPUs start in PSCI powered-down state */ - object_property_set_bool(OBJECT(&s->rpu_cpu[i]), true, - "start-powered-off", &error_abort); - } else { - s->boot_cpu_ptr = &s->rpu_cpu[i]; - } - g_free(name); - - object_property_set_bool(OBJECT(&s->rpu_cpu[i]), true, "reset-hivecs", - &error_abort); - object_property_set_bool(OBJECT(&s->rpu_cpu[i]), true, "realized", - &err); + if (s->has_rpu) { + xlnx_zynqmp_create_rpu(s, boot_cpu, &err); if (err) { error_propagate(errp, err); return; @@ -308,6 +331,7 @@ static void xlnx_zynqmp_realize(DeviceState *dev, Error **errp) } for (i = 0; i < XLNX_ZYNQMP_NUM_UARTS; i++) { + qdev_prop_set_chr(DEVICE(&s->uart[i]), "chardev", serial_hds[i]); object_property_set_bool(OBJECT(&s->uart[i]), true, "realized", &err); if (err) { error_propagate(errp, err); @@ -370,6 +394,8 @@ static void xlnx_zynqmp_realize(DeviceState *dev, Error **errp) static Property xlnx_zynqmp_props[] = { DEFINE_PROP_STRING("boot-cpu", XlnxZynqMPState, boot_cpu), + DEFINE_PROP_BOOL("secure", XlnxZynqMPState, secure, false), + DEFINE_PROP_BOOL("has_rpu", XlnxZynqMPState, has_rpu, false), DEFINE_PROP_END_OF_LIST() }; diff --git a/hw/char/cadence_uart.c b/hw/char/cadence_uart.c index 442dac52cf..c856fc30b2 100644 --- a/hw/char/cadence_uart.c +++ b/hw/char/cadence_uart.c @@ -468,9 +468,6 @@ static void cadence_uart_realize(DeviceState *dev, Error **errp) s->fifo_trigger_handle = timer_new_ns(QEMU_CLOCK_VIRTUAL, fifo_trigger_update, s); - /* FIXME use a qdev chardev prop instead of qemu_char_get_next_serial() */ - s->chr = qemu_char_get_next_serial(); - if (s->chr) { qemu_chr_add_handlers(s->chr, uart_can_receive, uart_receive, uart_event, s); @@ -517,6 +514,11 @@ static const VMStateDescription vmstate_cadence_uart = { } }; +static Property cadence_uart_properties[] = { + DEFINE_PROP_CHR("chardev", CadenceUARTState, chr), + DEFINE_PROP_END_OF_LIST(), +}; + static void cadence_uart_class_init(ObjectClass *klass, void *data) { DeviceClass *dc = DEVICE_CLASS(klass); @@ -524,9 +526,8 @@ static void cadence_uart_class_init(ObjectClass *klass, void *data) dc->realize = cadence_uart_realize; dc->vmsd = &vmstate_cadence_uart; dc->reset = cadence_uart_reset; - /* Reason: realize() method uses qemu_char_get_next_serial() */ - dc->cannot_instantiate_with_device_add_yet = true; -} + dc->props = cadence_uart_properties; + } static const TypeInfo cadence_uart_info = { .name = TYPE_CADENCE_UART, diff --git a/hw/char/digic-uart.c b/hw/char/digic-uart.c index 0e44878405..c7604e6766 100644 --- a/hw/char/digic-uart.c +++ b/hw/char/digic-uart.c @@ -145,8 +145,6 @@ static void digic_uart_realize(DeviceState *dev, Error **errp) { DigicUartState *s = DIGIC_UART(dev); - /* FIXME use a qdev chardev prop instead of qemu_char_get_next_serial() */ - s->chr = qemu_char_get_next_serial(); if (s->chr) { qemu_chr_add_handlers(s->chr, uart_can_rx, uart_rx, uart_event, s); } @@ -172,6 +170,11 @@ static const VMStateDescription vmstate_digic_uart = { } }; +static Property digic_uart_properties[] = { + DEFINE_PROP_CHR("chardev", DigicUartState, chr), + DEFINE_PROP_END_OF_LIST(), +}; + static void digic_uart_class_init(ObjectClass *klass, void *data) { DeviceClass *dc = DEVICE_CLASS(klass); @@ -179,8 +182,7 @@ static void digic_uart_class_init(ObjectClass *klass, void *data) dc->realize = digic_uart_realize; dc->reset = digic_uart_reset; dc->vmsd = &vmstate_digic_uart; - /* Reason: realize() method uses qemu_char_get_next_serial() */ - dc->cannot_instantiate_with_device_add_yet = true; + dc->props = digic_uart_properties; } static const TypeInfo digic_uart_info = { diff --git a/hw/char/pl011.c b/hw/char/pl011.c index 6876ea6eef..c0fbf8a874 100644 --- a/hw/char/pl011.c +++ b/hw/char/pl011.c @@ -274,6 +274,11 @@ static const VMStateDescription vmstate_pl011 = { } }; +static Property pl011_properties[] = { + DEFINE_PROP_CHR("chardev", PL011State, chr), + DEFINE_PROP_END_OF_LIST(), +}; + static void pl011_init(Object *obj) { SysBusDevice *sbd = SYS_BUS_DEVICE(obj); @@ -295,9 +300,6 @@ static void pl011_realize(DeviceState *dev, Error **errp) { PL011State *s = PL011(dev); - /* FIXME use a qdev chardev prop instead of qemu_char_get_next_serial() */ - s->chr = qemu_char_get_next_serial(); - if (s->chr) { qemu_chr_add_handlers(s->chr, pl011_can_receive, pl011_receive, pl011_event, s); @@ -310,8 +312,7 @@ static void pl011_class_init(ObjectClass *oc, void *data) dc->realize = pl011_realize; dc->vmsd = &vmstate_pl011; - /* Reason: realize() method uses qemu_char_get_next_serial() */ - dc->cannot_instantiate_with_device_add_yet = true; + dc->props = pl011_properties; } static const TypeInfo pl011_arm_info = { diff --git a/hw/char/stm32f2xx_usart.c b/hw/char/stm32f2xx_usart.c index 72305ec5d4..15657abda9 100644 --- a/hw/char/stm32f2xx_usart.c +++ b/hw/char/stm32f2xx_usart.c @@ -190,6 +190,11 @@ static const MemoryRegionOps stm32f2xx_usart_ops = { .endianness = DEVICE_NATIVE_ENDIAN, }; +static Property stm32f2xx_usart_properties[] = { + DEFINE_PROP_CHR("chardev", STM32F2XXUsartState, chr), + DEFINE_PROP_END_OF_LIST(), +}; + static void stm32f2xx_usart_init(Object *obj) { STM32F2XXUsartState *s = STM32F2XX_USART(obj); @@ -199,9 +204,11 @@ static void stm32f2xx_usart_init(Object *obj) memory_region_init_io(&s->mmio, obj, &stm32f2xx_usart_ops, s, TYPE_STM32F2XX_USART, 0x2000); sysbus_init_mmio(SYS_BUS_DEVICE(obj), &s->mmio); +} - /* FIXME use a qdev chardev prop instead of qemu_char_get_next_serial() */ - s->chr = qemu_char_get_next_serial(); +static void stm32f2xx_usart_realize(DeviceState *dev, Error **errp) +{ + STM32F2XXUsartState *s = STM32F2XX_USART(dev); if (s->chr) { qemu_chr_add_handlers(s->chr, stm32f2xx_usart_can_receive, @@ -214,8 +221,8 @@ static void stm32f2xx_usart_class_init(ObjectClass *klass, void *data) DeviceClass *dc = DEVICE_CLASS(klass); dc->reset = stm32f2xx_usart_reset; - /* Reason: instance_init() method uses qemu_char_get_next_serial() */ - dc->cannot_instantiate_with_device_add_yet = true; + dc->props = stm32f2xx_usart_properties; + dc->realize = stm32f2xx_usart_realize; } static const TypeInfo stm32f2xx_usart_info = { diff --git a/hw/char/xilinx_uartlite.c b/hw/char/xilinx_uartlite.c index 911af4a0d7..4847efb29f 100644 --- a/hw/char/xilinx_uartlite.c +++ b/hw/char/xilinx_uartlite.c @@ -172,6 +172,11 @@ static const MemoryRegionOps uart_ops = { } }; +static Property xilinx_uartlite_properties[] = { + DEFINE_PROP_CHR("chardev", XilinxUARTLite, chr), + DEFINE_PROP_END_OF_LIST(), +}; + static void uart_rx(void *opaque, const uint8_t *buf, int size) { XilinxUARTLite *s = opaque; @@ -206,8 +211,6 @@ static void xilinx_uartlite_realize(DeviceState *dev, Error **errp) { XilinxUARTLite *s = XILINX_UARTLITE(dev); - /* FIXME use a qdev chardev prop instead of qemu_char_get_next_serial() */ - s->chr = qemu_char_get_next_serial(); if (s->chr) qemu_chr_add_handlers(s->chr, uart_can_rx, uart_rx, uart_event, s); } @@ -229,8 +232,7 @@ static void xilinx_uartlite_class_init(ObjectClass *klass, void *data) dc->reset = xilinx_uartlite_reset; dc->realize = xilinx_uartlite_realize; - /* Reason: realize() method uses qemu_char_get_next_serial() */ - dc->cannot_instantiate_with_device_add_yet = true; + dc->props = xilinx_uartlite_properties; } static const TypeInfo xilinx_uartlite_info = { diff --git a/hw/core/ptimer.c b/hw/core/ptimer.c index 153c835136..05b0c276eb 100644 --- a/hw/core/ptimer.c +++ b/hw/core/ptimer.c @@ -35,6 +35,9 @@ static void ptimer_trigger(ptimer_state *s) static void ptimer_reload(ptimer_state *s) { + uint32_t period_frac = s->period_frac; + uint64_t period = s->period; + if (s->delta == 0) { ptimer_trigger(s); s->delta = s->limit; @@ -45,10 +48,24 @@ static void ptimer_reload(ptimer_state *s) return; } + /* + * Artificially limit timeout rate to something + * achievable under QEMU. Otherwise, QEMU spends all + * its time generating timer interrupts, and there + * is no forward progress. + * About ten microseconds is the fastest that really works + * on the current generation of host machines. + */ + + if (s->enabled == 1 && (s->delta * period < 10000) && !use_icount) { + period = 10000 / s->delta; + period_frac = 0; + } + s->last_event = s->next_event; - s->next_event = s->last_event + s->delta * s->period; - if (s->period_frac) { - s->next_event += ((int64_t)s->period_frac * s->delta) >> 32; + s->next_event = s->last_event + s->delta * period; + if (period_frac) { + s->next_event += ((int64_t)period_frac * s->delta) >> 32; } timer_mod(s->timer, s->next_event); } @@ -67,14 +84,16 @@ static void ptimer_tick(void *opaque) uint64_t ptimer_get_count(ptimer_state *s) { - int64_t now; uint64_t counter; if (s->enabled) { - now = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL); + int64_t now = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL); + int64_t next = s->next_event; + bool expired = (now - next >= 0); + bool oneshot = (s->enabled == 2); + /* Figure out the current counter value. */ - if (now - s->next_event > 0 - || s->period == 0) { + if (s->period == 0 || (expired && (oneshot || use_icount))) { /* Prevent timer underflowing if it should already have triggered. */ counter = 0; @@ -83,6 +102,13 @@ uint64_t ptimer_get_count(ptimer_state *s) uint64_t div; int clz1, clz2; int shift; + uint32_t period_frac = s->period_frac; + uint64_t period = s->period; + + if (!oneshot && (s->delta * period < 10000) && !use_icount) { + period = 10000 / s->delta; + period_frac = 0; + } /* We need to divide time by period, where time is stored in rem (64-bit integer) and period is stored in period/period_frac @@ -94,8 +120,8 @@ uint64_t ptimer_get_count(ptimer_state *s) backwards. */ - rem = s->next_event - now; - div = s->period; + rem = expired ? now - next : next - now; + div = period; clz1 = clz64(rem); clz2 = clz64(div); @@ -104,16 +130,21 @@ uint64_t ptimer_get_count(ptimer_state *s) rem <<= shift; div <<= shift; if (shift >= 32) { - div |= ((uint64_t)s->period_frac << (shift - 32)); + div |= ((uint64_t)period_frac << (shift - 32)); } else { if (shift != 0) - div |= (s->period_frac >> (32 - shift)); + div |= (period_frac >> (32 - shift)); /* Look at remaining bits of period_frac and round div up if necessary. */ - if ((uint32_t)(s->period_frac << shift)) + if ((uint32_t)(period_frac << shift)) div += 1; } counter = rem / div; + + if (expired && counter != 0) { + /* Wrap around periodic counter. */ + counter = s->limit - (counter - 1) % s->limit; + } } } else { counter = s->delta; @@ -132,16 +163,17 @@ void ptimer_set_count(ptimer_state *s, uint64_t count) void ptimer_run(ptimer_state *s, int oneshot) { - if (s->enabled) { - return; - } - if (s->period == 0) { + bool was_disabled = !s->enabled; + + if (was_disabled && s->period == 0) { fprintf(stderr, "Timer with period zero, disabling\n"); return; } s->enabled = oneshot ? 2 : 1; - s->next_event = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL); - ptimer_reload(s); + if (was_disabled) { + s->next_event = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL); + ptimer_reload(s); + } } /* Pause a timer. Note that this may cause it to "lose" time, even if it @@ -159,6 +191,7 @@ void ptimer_stop(ptimer_state *s) /* Set counter increment interval in nanoseconds. */ void ptimer_set_period(ptimer_state *s, int64_t period) { + s->delta = ptimer_get_count(s); s->period = period; s->period_frac = 0; if (s->enabled) { @@ -170,6 +203,7 @@ void ptimer_set_period(ptimer_state *s, int64_t period) /* Set counter frequency in Hz. */ void ptimer_set_freq(ptimer_state *s, uint32_t freq) { + s->delta = ptimer_get_count(s); s->period = 1000000000ll / freq; s->period_frac = (1000000000ll << 32) / freq; if (s->enabled) { @@ -182,19 +216,6 @@ void ptimer_set_freq(ptimer_state *s, uint32_t freq) count = limit. */ void ptimer_set_limit(ptimer_state *s, uint64_t limit, int reload) { - /* - * Artificially limit timeout rate to something - * achievable under QEMU. Otherwise, QEMU spends all - * its time generating timer interrupts, and there - * is no forward progress. - * About ten microseconds is the fastest that really works - * on the current generation of host machines. - */ - - if (!use_icount && limit * s->period < 10000 && s->period) { - limit = 10000 / s->period; - } - s->limit = limit; if (reload) s->delta = limit; @@ -204,6 +225,11 @@ void ptimer_set_limit(ptimer_state *s, uint64_t limit, int reload) } } +uint64_t ptimer_get_limit(ptimer_state *s) +{ + return s->limit; +} + const VMStateDescription vmstate_ptimer = { .name = "ptimer", .version_id = 1, diff --git a/hw/i2c/Makefile.objs b/hw/i2c/Makefile.objs index aeb8f38d70..1fd54edf4c 100644 --- a/hw/i2c/Makefile.objs +++ b/hw/i2c/Makefile.objs @@ -5,4 +5,5 @@ common-obj-$(CONFIG_APM) += pm_smbus.o common-obj-$(CONFIG_BITBANG_I2C) += bitbang_i2c.o common-obj-$(CONFIG_EXYNOS4) += exynos4210_i2c.o common-obj-$(CONFIG_IMX_I2C) += imx_i2c.o +common-obj-$(CONFIG_ASPEED_SOC) += aspeed_i2c.o obj-$(CONFIG_OMAP) += omap_i2c.o diff --git a/hw/i2c/aspeed_i2c.c b/hw/i2c/aspeed_i2c.c new file mode 100644 index 0000000000..ce5b1f0fa4 --- /dev/null +++ b/hw/i2c/aspeed_i2c.c @@ -0,0 +1,440 @@ +/* + * ARM Aspeed I2C controller + * + * Copyright (C) 2016 IBM Corp. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see . + * + */ + +#include "qemu/osdep.h" +#include "hw/sysbus.h" +#include "qemu/log.h" +#include "hw/i2c/aspeed_i2c.h" + +/* I2C Global Register */ + +#define I2C_CTRL_STATUS 0x00 /* Device Interrupt Status */ +#define I2C_CTRL_ASSIGN 0x08 /* Device Interrupt Target + Assignment */ + +/* I2C Device (Bus) Register */ + +#define I2CD_FUN_CTRL_REG 0x00 /* I2CD Function Control */ +#define I2CD_BUFF_SEL_MASK (0x7 << 20) +#define I2CD_BUFF_SEL(x) (x << 20) +#define I2CD_M_SDA_LOCK_EN (0x1 << 16) +#define I2CD_MULTI_MASTER_DIS (0x1 << 15) +#define I2CD_M_SCL_DRIVE_EN (0x1 << 14) +#define I2CD_MSB_STS (0x1 << 9) +#define I2CD_SDA_DRIVE_1T_EN (0x1 << 8) +#define I2CD_M_SDA_DRIVE_1T_EN (0x1 << 7) +#define I2CD_M_HIGH_SPEED_EN (0x1 << 6) +#define I2CD_DEF_ADDR_EN (0x1 << 5) +#define I2CD_DEF_ALERT_EN (0x1 << 4) +#define I2CD_DEF_ARP_EN (0x1 << 3) +#define I2CD_DEF_GCALL_EN (0x1 << 2) +#define I2CD_SLAVE_EN (0x1 << 1) +#define I2CD_MASTER_EN (0x1) + +#define I2CD_AC_TIMING_REG1 0x04 /* Clock and AC Timing Control #1 */ +#define I2CD_AC_TIMING_REG2 0x08 /* Clock and AC Timing Control #1 */ +#define I2CD_INTR_CTRL_REG 0x0c /* I2CD Interrupt Control */ +#define I2CD_INTR_STS_REG 0x10 /* I2CD Interrupt Status */ +#define I2CD_INTR_SDA_DL_TIMEOUT (0x1 << 14) +#define I2CD_INTR_BUS_RECOVER_DONE (0x1 << 13) +#define I2CD_INTR_SMBUS_ALERT (0x1 << 12) /* Bus [0-3] only */ +#define I2CD_INTR_SMBUS_ARP_ADDR (0x1 << 11) /* Removed */ +#define I2CD_INTR_SMBUS_DEV_ALERT_ADDR (0x1 << 10) /* Removed */ +#define I2CD_INTR_SMBUS_DEF_ADDR (0x1 << 9) /* Removed */ +#define I2CD_INTR_GCALL_ADDR (0x1 << 8) /* Removed */ +#define I2CD_INTR_SLAVE_MATCH (0x1 << 7) /* use RX_DONE */ +#define I2CD_INTR_SCL_TIMEOUT (0x1 << 6) +#define I2CD_INTR_ABNORMAL (0x1 << 5) +#define I2CD_INTR_NORMAL_STOP (0x1 << 4) +#define I2CD_INTR_ARBIT_LOSS (0x1 << 3) +#define I2CD_INTR_RX_DONE (0x1 << 2) +#define I2CD_INTR_TX_NAK (0x1 << 1) +#define I2CD_INTR_TX_ACK (0x1 << 0) + +#define I2CD_CMD_REG 0x14 /* I2CD Command/Status */ +#define I2CD_SDA_OE (0x1 << 28) +#define I2CD_SDA_O (0x1 << 27) +#define I2CD_SCL_OE (0x1 << 26) +#define I2CD_SCL_O (0x1 << 25) +#define I2CD_TX_TIMING (0x1 << 24) +#define I2CD_TX_STATUS (0x1 << 23) + +#define I2CD_TX_STATE_SHIFT 19 /* Tx State Machine */ +#define I2CD_TX_STATE_MASK 0xf +#define I2CD_IDLE 0x0 +#define I2CD_MACTIVE 0x8 +#define I2CD_MSTART 0x9 +#define I2CD_MSTARTR 0xa +#define I2CD_MSTOP 0xb +#define I2CD_MTXD 0xc +#define I2CD_MRXACK 0xd +#define I2CD_MRXD 0xe +#define I2CD_MTXACK 0xf +#define I2CD_SWAIT 0x1 +#define I2CD_SRXD 0x4 +#define I2CD_STXACK 0x5 +#define I2CD_STXD 0x6 +#define I2CD_SRXACK 0x7 +#define I2CD_RECOVER 0x3 + +#define I2CD_SCL_LINE_STS (0x1 << 18) +#define I2CD_SDA_LINE_STS (0x1 << 17) +#define I2CD_BUS_BUSY_STS (0x1 << 16) +#define I2CD_SDA_OE_OUT_DIR (0x1 << 15) +#define I2CD_SDA_O_OUT_DIR (0x1 << 14) +#define I2CD_SCL_OE_OUT_DIR (0x1 << 13) +#define I2CD_SCL_O_OUT_DIR (0x1 << 12) +#define I2CD_BUS_RECOVER_CMD_EN (0x1 << 11) +#define I2CD_S_ALT_EN (0x1 << 10) +#define I2CD_RX_DMA_ENABLE (0x1 << 9) +#define I2CD_TX_DMA_ENABLE (0x1 << 8) + +/* Command Bit */ +#define I2CD_M_STOP_CMD (0x1 << 5) +#define I2CD_M_S_RX_CMD_LAST (0x1 << 4) +#define I2CD_M_RX_CMD (0x1 << 3) +#define I2CD_S_TX_CMD (0x1 << 2) +#define I2CD_M_TX_CMD (0x1 << 1) +#define I2CD_M_START_CMD (0x1) + +#define I2CD_DEV_ADDR_REG 0x18 /* Slave Device Address */ +#define I2CD_BUF_CTRL_REG 0x1c /* Pool Buffer Control */ +#define I2CD_BYTE_BUF_REG 0x20 /* Transmit/Receive Byte Buffer */ +#define I2CD_BYTE_BUF_TX_SHIFT 0 +#define I2CD_BYTE_BUF_TX_MASK 0xff +#define I2CD_BYTE_BUF_RX_SHIFT 8 +#define I2CD_BYTE_BUF_RX_MASK 0xff + + +static inline bool aspeed_i2c_bus_is_master(AspeedI2CBus *bus) +{ + return bus->ctrl & I2CD_MASTER_EN; +} + +static inline bool aspeed_i2c_bus_is_enabled(AspeedI2CBus *bus) +{ + return bus->ctrl & (I2CD_MASTER_EN | I2CD_SLAVE_EN); +} + +static inline void aspeed_i2c_bus_raise_interrupt(AspeedI2CBus *bus) +{ + bus->intr_status &= bus->intr_ctrl; + if (bus->intr_status) { + bus->controller->intr_status |= 1 << bus->id; + qemu_irq_raise(bus->controller->irq); + } +} + +static uint64_t aspeed_i2c_bus_read(void *opaque, hwaddr offset, + unsigned size) +{ + AspeedI2CBus *bus = opaque; + + switch (offset) { + case I2CD_FUN_CTRL_REG: + return bus->ctrl; + case I2CD_AC_TIMING_REG1: + return bus->timing[0]; + case I2CD_AC_TIMING_REG2: + return bus->timing[1]; + case I2CD_INTR_CTRL_REG: + return bus->intr_ctrl; + case I2CD_INTR_STS_REG: + return bus->intr_status; + case I2CD_BYTE_BUF_REG: + return bus->buf; + case I2CD_CMD_REG: + return bus->cmd | (i2c_bus_busy(bus->bus) << 16); + default: + qemu_log_mask(LOG_GUEST_ERROR, + "%s: Bad offset 0x%" HWADDR_PRIx "\n", __func__, offset); + return -1; + } +} + +static void aspeed_i2c_bus_handle_cmd(AspeedI2CBus *bus, uint64_t value) +{ + bus->cmd |= value & 0xFFFF; + bus->intr_status = 0; + + if (bus->cmd & I2CD_M_START_CMD) { + if (i2c_start_transfer(bus->bus, extract32(bus->buf, 1, 7), + extract32(bus->buf, 0, 1))) { + bus->intr_status |= I2CD_INTR_TX_NAK; + } else { + bus->intr_status |= I2CD_INTR_TX_ACK; + } + + } else if (bus->cmd & I2CD_M_TX_CMD) { + if (i2c_send(bus->bus, bus->buf)) { + bus->intr_status |= (I2CD_INTR_TX_NAK | I2CD_INTR_ABNORMAL); + i2c_end_transfer(bus->bus); + } else { + bus->intr_status |= I2CD_INTR_TX_ACK; + } + + } else if (bus->cmd & I2CD_M_RX_CMD) { + int ret = i2c_recv(bus->bus); + if (ret < 0) { + qemu_log_mask(LOG_GUEST_ERROR, "%s: read failed\n", __func__); + ret = 0xff; + } else { + bus->intr_status |= I2CD_INTR_RX_DONE; + } + bus->buf = (ret & I2CD_BYTE_BUF_RX_MASK) << I2CD_BYTE_BUF_RX_SHIFT; + } + + if (bus->cmd & (I2CD_M_STOP_CMD | I2CD_M_S_RX_CMD_LAST)) { + if (!i2c_bus_busy(bus->bus)) { + bus->intr_status |= I2CD_INTR_ABNORMAL; + } else { + i2c_end_transfer(bus->bus); + bus->intr_status |= I2CD_INTR_NORMAL_STOP; + } + } + + /* command is handled, reset it and check for interrupts */ + bus->cmd &= ~0xFFFF; + aspeed_i2c_bus_raise_interrupt(bus); +} + +static void aspeed_i2c_bus_write(void *opaque, hwaddr offset, + uint64_t value, unsigned size) +{ + AspeedI2CBus *bus = opaque; + + switch (offset) { + case I2CD_FUN_CTRL_REG: + if (value & I2CD_SLAVE_EN) { + qemu_log_mask(LOG_UNIMP, "%s: slave mode not implemented\n", + __func__); + break; + } + bus->ctrl = value & 0x0071C3FF; + break; + case I2CD_AC_TIMING_REG1: + bus->timing[0] = value & 0xFFFFF0F; + break; + case I2CD_AC_TIMING_REG2: + bus->timing[1] = value & 0x7; + break; + case I2CD_INTR_CTRL_REG: + bus->intr_ctrl = value & 0x7FFF; + break; + case I2CD_INTR_STS_REG: + bus->intr_status &= ~(value & 0x7FFF); + bus->controller->intr_status &= ~(1 << bus->id); + qemu_irq_lower(bus->controller->irq); + break; + case I2CD_DEV_ADDR_REG: + qemu_log_mask(LOG_UNIMP, "%s: slave mode not implemented\n", + __func__); + break; + case I2CD_BYTE_BUF_REG: + bus->buf = (value & I2CD_BYTE_BUF_TX_MASK) << I2CD_BYTE_BUF_TX_SHIFT; + break; + case I2CD_CMD_REG: + if (!aspeed_i2c_bus_is_enabled(bus)) { + break; + } + + if (!aspeed_i2c_bus_is_master(bus)) { + qemu_log_mask(LOG_UNIMP, "%s: slave mode not implemented\n", + __func__); + break; + } + + aspeed_i2c_bus_handle_cmd(bus, value); + break; + + default: + qemu_log_mask(LOG_GUEST_ERROR, "%s: Bad offset 0x%" HWADDR_PRIx "\n", + __func__, offset); + } +} + +static uint64_t aspeed_i2c_ctrl_read(void *opaque, hwaddr offset, + unsigned size) +{ + AspeedI2CState *s = opaque; + + switch (offset) { + case I2C_CTRL_STATUS: + return s->intr_status; + default: + qemu_log_mask(LOG_GUEST_ERROR, "%s: Bad offset 0x%" HWADDR_PRIx "\n", + __func__, offset); + break; + } + + return -1; +} + +static void aspeed_i2c_ctrl_write(void *opaque, hwaddr offset, + uint64_t value, unsigned size) +{ + switch (offset) { + case I2C_CTRL_STATUS: + default: + qemu_log_mask(LOG_GUEST_ERROR, "%s: Bad offset 0x%" HWADDR_PRIx "\n", + __func__, offset); + break; + } +} + +static const MemoryRegionOps aspeed_i2c_bus_ops = { + .read = aspeed_i2c_bus_read, + .write = aspeed_i2c_bus_write, + .endianness = DEVICE_LITTLE_ENDIAN, +}; + +static const MemoryRegionOps aspeed_i2c_ctrl_ops = { + .read = aspeed_i2c_ctrl_read, + .write = aspeed_i2c_ctrl_write, + .endianness = DEVICE_LITTLE_ENDIAN, +}; + +static const VMStateDescription aspeed_i2c_bus_vmstate = { + .name = TYPE_ASPEED_I2C, + .version_id = 1, + .minimum_version_id = 1, + .fields = (VMStateField[]) { + VMSTATE_UINT8(id, AspeedI2CBus), + VMSTATE_UINT32(ctrl, AspeedI2CBus), + VMSTATE_UINT32_ARRAY(timing, AspeedI2CBus, 2), + VMSTATE_UINT32(intr_ctrl, AspeedI2CBus), + VMSTATE_UINT32(intr_status, AspeedI2CBus), + VMSTATE_UINT32(cmd, AspeedI2CBus), + VMSTATE_UINT32(buf, AspeedI2CBus), + VMSTATE_END_OF_LIST() + } +}; + +static const VMStateDescription aspeed_i2c_vmstate = { + .name = TYPE_ASPEED_I2C, + .version_id = 1, + .minimum_version_id = 1, + .fields = (VMStateField[]) { + VMSTATE_UINT32(intr_status, AspeedI2CState), + VMSTATE_STRUCT_ARRAY(busses, AspeedI2CState, + ASPEED_I2C_NR_BUSSES, 1, aspeed_i2c_bus_vmstate, + AspeedI2CBus), + VMSTATE_END_OF_LIST() + } +}; + +static void aspeed_i2c_reset(DeviceState *dev) +{ + int i; + AspeedI2CState *s = ASPEED_I2C(dev); + + s->intr_status = 0; + + for (i = 0; i < ASPEED_I2C_NR_BUSSES; i++) { + s->busses[i].intr_ctrl = 0; + s->busses[i].intr_status = 0; + s->busses[i].cmd = 0; + s->busses[i].buf = 0; + i2c_end_transfer(s->busses[i].bus); + } +} + +/* + * Address Definitions + * + * 0x000 ... 0x03F: Global Register + * 0x040 ... 0x07F: Device 1 + * 0x080 ... 0x0BF: Device 2 + * 0x0C0 ... 0x0FF: Device 3 + * 0x100 ... 0x13F: Device 4 + * 0x140 ... 0x17F: Device 5 + * 0x180 ... 0x1BF: Device 6 + * 0x1C0 ... 0x1FF: Device 7 + * 0x200 ... 0x2FF: Buffer Pool (unused in linux driver) + * 0x300 ... 0x33F: Device 8 + * 0x340 ... 0x37F: Device 9 + * 0x380 ... 0x3BF: Device 10 + * 0x3C0 ... 0x3FF: Device 11 + * 0x400 ... 0x43F: Device 12 + * 0x440 ... 0x47F: Device 13 + * 0x480 ... 0x4BF: Device 14 + * 0x800 ... 0xFFF: Buffer Pool (unused in linux driver) + */ +static void aspeed_i2c_realize(DeviceState *dev, Error **errp) +{ + int i; + SysBusDevice *sbd = SYS_BUS_DEVICE(dev); + AspeedI2CState *s = ASPEED_I2C(dev); + + sysbus_init_irq(sbd, &s->irq); + memory_region_init_io(&s->iomem, OBJECT(s), &aspeed_i2c_ctrl_ops, s, + "aspeed.i2c", 0x1000); + sysbus_init_mmio(sbd, &s->iomem); + + for (i = 0; i < ASPEED_I2C_NR_BUSSES; i++) { + char name[16]; + int offset = i < 7 ? 1 : 5; + snprintf(name, sizeof(name), "aspeed.i2c.%d", i); + s->busses[i].controller = s; + s->busses[i].id = i; + s->busses[i].bus = i2c_init_bus(dev, name); + memory_region_init_io(&s->busses[i].mr, OBJECT(dev), + &aspeed_i2c_bus_ops, &s->busses[i], name, 0x40); + memory_region_add_subregion(&s->iomem, 0x40 * (i + offset), + &s->busses[i].mr); + } +} + +static void aspeed_i2c_class_init(ObjectClass *klass, void *data) +{ + DeviceClass *dc = DEVICE_CLASS(klass); + + dc->vmsd = &aspeed_i2c_vmstate; + dc->reset = aspeed_i2c_reset; + dc->realize = aspeed_i2c_realize; + dc->desc = "Aspeed I2C Controller"; +} + +static const TypeInfo aspeed_i2c_info = { + .name = TYPE_ASPEED_I2C, + .parent = TYPE_SYS_BUS_DEVICE, + .instance_size = sizeof(AspeedI2CState), + .class_init = aspeed_i2c_class_init, +}; + +static void aspeed_i2c_register_types(void) +{ + type_register_static(&aspeed_i2c_info); +} + +type_init(aspeed_i2c_register_types) + + +I2CBus *aspeed_i2c_get_bus(DeviceState *dev, int busnr) +{ + AspeedI2CState *s = ASPEED_I2C(dev); + I2CBus *bus = NULL; + + if (busnr >= 0 && busnr < ASPEED_I2C_NR_BUSSES) { + bus = s->busses[busnr].bus; + } + + return bus; +} diff --git a/hw/intc/arm_gic.c b/hw/intc/arm_gic.c index 06a22e0aaf..b30cc91745 100644 --- a/hw/intc/arm_gic.c +++ b/hw/intc/arm_gic.c @@ -661,6 +661,11 @@ static uint32_t gic_dist_readb(void *opaque, hwaddr offset, MemTxAttrs attrs) goto bad_reg; res = 0; for (i = 0; i < 8; i++) { + if (s->security_extn && !attrs.secure && + !GIC_TEST_GROUP(irq + i, 1 << cpu)) { + continue; /* Ignore Non-secure access of Group0 IRQ */ + } + if (GIC_TEST_ENABLED(irq + i, cm)) { res |= (1 << i); } @@ -677,6 +682,11 @@ static uint32_t gic_dist_readb(void *opaque, hwaddr offset, MemTxAttrs attrs) res = 0; mask = (irq < GIC_INTERNAL) ? cm : ALL_CPU_MASK; for (i = 0; i < 8; i++) { + if (s->security_extn && !attrs.secure && + !GIC_TEST_GROUP(irq + i, 1 << cpu)) { + continue; /* Ignore Non-secure access of Group0 IRQ */ + } + if (gic_test_pending(s, irq + i, mask)) { res |= (1 << i); } @@ -689,6 +699,11 @@ static uint32_t gic_dist_readb(void *opaque, hwaddr offset, MemTxAttrs attrs) res = 0; mask = (irq < GIC_INTERNAL) ? cm : ALL_CPU_MASK; for (i = 0; i < 8; i++) { + if (s->security_extn && !attrs.secure && + !GIC_TEST_GROUP(irq + i, 1 << cpu)) { + continue; /* Ignore Non-secure access of Group0 IRQ */ + } + if (GIC_TEST_ACTIVE(irq + i, mask)) { res |= (1 << i); } @@ -722,6 +737,11 @@ static uint32_t gic_dist_readb(void *opaque, hwaddr offset, MemTxAttrs attrs) goto bad_reg; res = 0; for (i = 0; i < 4; i++) { + if (s->security_extn && !attrs.secure && + !GIC_TEST_GROUP(irq + i, 1 << cpu)) { + continue; /* Ignore Non-secure access of Group0 IRQ */ + } + if (GIC_TEST_MODEL(irq + i)) res |= (1 << (i * 2)); if (GIC_TEST_EDGE_TRIGGER(irq + i)) @@ -742,7 +762,12 @@ static uint32_t gic_dist_readb(void *opaque, hwaddr offset, MemTxAttrs attrs) /* GICD_SPENDSGIRn */ } - res = s->sgi_pending[irq][cpu]; + if (s->security_extn && !attrs.secure && + !GIC_TEST_GROUP(irq, 1 << cpu)) { + res = 0; /* Ignore Non-secure access of Group0 IRQ */ + } else { + res = s->sgi_pending[irq][cpu]; + } } else if (offset < 0xfd0) { goto bad_reg; } else if (offset < 0x1000) { @@ -862,6 +887,11 @@ static void gic_dist_writeb(void *opaque, hwaddr offset, (irq < GIC_INTERNAL) ? (1 << cpu) : GIC_TARGET(irq + i); int cm = (irq < GIC_INTERNAL) ? (1 << cpu) : ALL_CPU_MASK; + if (s->security_extn && !attrs.secure && + !GIC_TEST_GROUP(irq + i, 1 << cpu)) { + continue; /* Ignore Non-secure access of Group0 IRQ */ + } + if (!GIC_TEST_ENABLED(irq + i, cm)) { DPRINTF("Enabled IRQ %d\n", irq + i); trace_gic_enable_irq(irq + i); @@ -889,6 +919,11 @@ static void gic_dist_writeb(void *opaque, hwaddr offset, if (value & (1 << i)) { int cm = (irq < GIC_INTERNAL) ? (1 << cpu) : ALL_CPU_MASK; + if (s->security_extn && !attrs.secure && + !GIC_TEST_GROUP(irq + i, 1 << cpu)) { + continue; /* Ignore Non-secure access of Group0 IRQ */ + } + if (GIC_TEST_ENABLED(irq + i, cm)) { DPRINTF("Disabled IRQ %d\n", irq + i); trace_gic_disable_irq(irq + i); @@ -907,6 +942,11 @@ static void gic_dist_writeb(void *opaque, hwaddr offset, for (i = 0; i < 8; i++) { if (value & (1 << i)) { + if (s->security_extn && !attrs.secure && + !GIC_TEST_GROUP(irq + i, 1 << cpu)) { + continue; /* Ignore Non-secure access of Group0 IRQ */ + } + GIC_SET_PENDING(irq + i, GIC_TARGET(irq + i)); } } @@ -920,6 +960,11 @@ static void gic_dist_writeb(void *opaque, hwaddr offset, } for (i = 0; i < 8; i++) { + if (s->security_extn && !attrs.secure && + !GIC_TEST_GROUP(irq + i, 1 << cpu)) { + continue; /* Ignore Non-secure access of Group0 IRQ */ + } + /* ??? This currently clears the pending bit for all CPUs, even for per-CPU interrupts. It's unclear whether this is the corect behavior. */ @@ -960,6 +1005,11 @@ static void gic_dist_writeb(void *opaque, hwaddr offset, if (irq < GIC_NR_SGIS) value |= 0xaa; for (i = 0; i < 4; i++) { + if (s->security_extn && !attrs.secure && + !GIC_TEST_GROUP(irq + i, 1 << cpu)) { + continue; /* Ignore Non-secure access of Group0 IRQ */ + } + if (s->revision == REV_11MPCORE || s->revision == REV_NVIC) { if (value & (1 << (i * 2))) { GIC_SET_MODEL(irq + i); @@ -983,9 +1033,12 @@ static void gic_dist_writeb(void *opaque, hwaddr offset, } irq = (offset - 0xf10); - s->sgi_pending[irq][cpu] &= ~value; - if (s->sgi_pending[irq][cpu] == 0) { - GIC_CLEAR_PENDING(irq, 1 << cpu); + if (!s->security_extn || attrs.secure || + GIC_TEST_GROUP(irq, 1 << cpu)) { + s->sgi_pending[irq][cpu] &= ~value; + if (s->sgi_pending[irq][cpu] == 0) { + GIC_CLEAR_PENDING(irq, 1 << cpu); + } } } else if (offset < 0xf30) { /* GICD_SPENDSGIRn */ @@ -994,8 +1047,11 @@ static void gic_dist_writeb(void *opaque, hwaddr offset, } irq = (offset - 0xf20); - GIC_SET_PENDING(irq, 1 << cpu); - s->sgi_pending[irq][cpu] |= value; + if (!s->security_extn || attrs.secure || + GIC_TEST_GROUP(irq, 1 << cpu)) { + GIC_SET_PENDING(irq, 1 << cpu); + s->sgi_pending[irq][cpu] |= value; + } } else { goto bad_reg; } diff --git a/hw/microblaze/petalogix_s3adsp1800_mmu.c b/hw/microblaze/petalogix_s3adsp1800_mmu.c index f821e1cfef..423bcd7f6c 100644 --- a/hw/microblaze/petalogix_s3adsp1800_mmu.c +++ b/hw/microblaze/petalogix_s3adsp1800_mmu.c @@ -36,6 +36,7 @@ #include "hw/boards.h" #include "sysemu/block-backend.h" #include "exec/address-spaces.h" +#include "hw/char/xilinx_uartlite.h" #include "boot.h" @@ -103,8 +104,8 @@ petalogix_s3adsp1800_init(MachineState *machine) irq[i] = qdev_get_gpio_in(dev, i); } - sysbus_create_simple("xlnx.xps-uartlite", UARTLITE_BASEADDR, - irq[UARTLITE_IRQ]); + xilinx_uartlite_create(UARTLITE_BASEADDR, irq[UARTLITE_IRQ], + serial_hds[0]); /* 2 timers at irq 2 @ 62 Mhz. */ dev = qdev_create(NULL, "xlnx.xps-timer"); diff --git a/include/hw/arm/ast2400.h b/include/hw/arm/ast2400.h index f16a1ed25c..c05ed53767 100644 --- a/include/hw/arm/ast2400.h +++ b/include/hw/arm/ast2400.h @@ -15,6 +15,7 @@ #include "hw/arm/arm.h" #include "hw/intc/aspeed_vic.h" #include "hw/timer/aspeed_timer.h" +#include "hw/i2c/aspeed_i2c.h" typedef struct AST2400State { /*< private >*/ @@ -25,6 +26,7 @@ typedef struct AST2400State { MemoryRegion iomem; AspeedVICState vic; AspeedTimerCtrlState timerctrl; + AspeedI2CState i2c; } AST2400State; #define TYPE_AST2400 "ast2400" diff --git a/include/hw/arm/xlnx-zynqmp.h b/include/hw/arm/xlnx-zynqmp.h index 2332596b40..68f6eb0c4d 100644 --- a/include/hw/arm/xlnx-zynqmp.h +++ b/include/hw/arm/xlnx-zynqmp.h @@ -84,6 +84,11 @@ typedef struct XlnxZynqMPState { char *boot_cpu; ARMCPU *boot_cpu_ptr; + + /* Has the ARM Security extensions? */ + bool secure; + /* Has the RPU subsystem? */ + bool has_rpu; } XlnxZynqMPState; #define XLNX_ZYNQMP_H diff --git a/include/hw/char/cadence_uart.h b/include/hw/char/cadence_uart.h index 6310f52512..a12773c076 100644 --- a/include/hw/char/cadence_uart.h +++ b/include/hw/char/cadence_uart.h @@ -49,5 +49,22 @@ typedef struct { QEMUTimer *fifo_trigger_handle; } CadenceUARTState; +static inline DeviceState *cadence_uart_create(hwaddr addr, + qemu_irq irq, + CharDriverState *chr) +{ + DeviceState *dev; + SysBusDevice *s; + + dev = qdev_create(NULL, TYPE_CADENCE_UART); + s = SYS_BUS_DEVICE(dev); + qdev_prop_set_chr(dev, "chardev", chr); + qdev_init_nofail(dev); + sysbus_mmio_map(s, 0, addr); + sysbus_connect_irq(s, 0, irq); + + return dev; +} + #define CADENCE_UART_H #endif diff --git a/include/hw/char/pl011.h b/include/hw/char/pl011.h new file mode 100644 index 0000000000..93bd7ee83e --- /dev/null +++ b/include/hw/char/pl011.h @@ -0,0 +1,52 @@ +/* + * This program is free software; you can redistribute it and/or modify it + * under the terms and conditions of the GNU General Public License, + * version 2 or later, as published by the Free Software Foundation. + * + * This program is distributed in the hope it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License along with + * this program. If not, see . + */ + +#ifndef PL011_UART_H +#define PL011_UART_H + +static inline DeviceState *pl011_create(hwaddr addr, + qemu_irq irq, + CharDriverState *chr) +{ + DeviceState *dev; + SysBusDevice *s; + + dev = qdev_create(NULL, "pl011"); + s = SYS_BUS_DEVICE(dev); + qdev_prop_set_chr(dev, "chardev", chr); + qdev_init_nofail(dev); + sysbus_mmio_map(s, 0, addr); + sysbus_connect_irq(s, 0, irq); + + return dev; +} + +static inline DeviceState *pl011_luminary_create(hwaddr addr, + qemu_irq irq, + CharDriverState *chr) +{ + DeviceState *dev; + SysBusDevice *s; + + dev = qdev_create(NULL, "pl011_luminary"); + s = SYS_BUS_DEVICE(dev); + qdev_prop_set_chr(dev, "chardev", chr); + qdev_init_nofail(dev); + sysbus_mmio_map(s, 0, addr); + sysbus_connect_irq(s, 0, irq); + + return dev; +} + +#endif diff --git a/include/hw/char/xilinx_uartlite.h b/include/hw/char/xilinx_uartlite.h new file mode 100644 index 0000000000..8b4fc54953 --- /dev/null +++ b/include/hw/char/xilinx_uartlite.h @@ -0,0 +1,35 @@ +/* + * This program is free software; you can redistribute it and/or modify it + * under the terms and conditions of the GNU General Public License, + * version 2 or later, as published by the Free Software Foundation. + * + * This program is distributed in the hope it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License along with + * this program. If not, see . + */ + +#ifndef XILINX_UARTLITE_H +#define XILINX_UARTLITE_H + +static inline DeviceState *xilinx_uartlite_create(hwaddr addr, + qemu_irq irq, + CharDriverState *chr) +{ + DeviceState *dev; + SysBusDevice *s; + + dev = qdev_create(NULL, "xlnx.xps-uartlite"); + s = SYS_BUS_DEVICE(dev); + qdev_prop_set_chr(dev, "chardev", chr); + qdev_init_nofail(dev); + sysbus_mmio_map(s, 0, addr); + sysbus_connect_irq(s, 0, irq); + + return dev; +} + +#endif diff --git a/include/hw/i2c/aspeed_i2c.h b/include/hw/i2c/aspeed_i2c.h new file mode 100644 index 0000000000..f9020acdef --- /dev/null +++ b/include/hw/i2c/aspeed_i2c.h @@ -0,0 +1,62 @@ +/* + * ASPEED AST2400 I2C Controller + * + * Copyright (C) 2016 IBM Corp. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ +#ifndef ASPEED_I2C_H +#define ASPEED_I2C_H + +#include "hw/i2c/i2c.h" + +#define TYPE_ASPEED_I2C "aspeed.i2c" +#define ASPEED_I2C(obj) \ + OBJECT_CHECK(AspeedI2CState, (obj), TYPE_ASPEED_I2C) + +#define ASPEED_I2C_NR_BUSSES 14 + +struct AspeedI2CState; + +typedef struct AspeedI2CBus { + struct AspeedI2CState *controller; + + MemoryRegion mr; + + I2CBus *bus; + uint8_t id; + + uint32_t ctrl; + uint32_t timing[2]; + uint32_t intr_ctrl; + uint32_t intr_status; + uint32_t cmd; + uint32_t buf; +} AspeedI2CBus; + +typedef struct AspeedI2CState { + SysBusDevice parent_obj; + + MemoryRegion iomem; + qemu_irq irq; + + uint32_t intr_status; + + AspeedI2CBus busses[ASPEED_I2C_NR_BUSSES]; +} AspeedI2CState; + +I2CBus *aspeed_i2c_get_bus(DeviceState *dev, int busnr); + +#endif /* ASPEED_I2C_H */ diff --git a/include/hw/ptimer.h b/include/hw/ptimer.h index 8ebacbbda0..e397db5bdb 100644 --- a/include/hw/ptimer.h +++ b/include/hw/ptimer.h @@ -19,6 +19,7 @@ typedef void (*ptimer_cb)(void *opaque); ptimer_state *ptimer_init(QEMUBH *bh); void ptimer_set_period(ptimer_state *s, int64_t period); void ptimer_set_freq(ptimer_state *s, uint32_t freq); +uint64_t ptimer_get_limit(ptimer_state *s); void ptimer_set_limit(ptimer_state *s, uint64_t limit, int reload); uint64_t ptimer_get_count(ptimer_state *s); void ptimer_set_count(ptimer_state *s, uint64_t count); diff --git a/include/sysemu/char.h b/include/sysemu/char.h index 307fd8fde4..372a6fd40b 100644 --- a/include/sysemu/char.h +++ b/include/sysemu/char.h @@ -403,7 +403,6 @@ void register_char_driver(const char *name, ChardevBackendKind kind, extern int term_escape_char; -CharDriverState *qemu_char_get_next_serial(void); /* console.c */ typedef CharDriverState *(VcHandler)(ChardevVC *vc, Error **errp); diff --git a/qemu-char.c b/qemu-char.c index b597ee19ca..b13ecbb025 100644 --- a/qemu-char.c +++ b/qemu-char.c @@ -4088,22 +4088,6 @@ CharDriverState *qemu_chr_find(const char *name) return NULL; } -/* Get a character (serial) device interface. */ -CharDriverState *qemu_char_get_next_serial(void) -{ - static int next_serial; - CharDriverState *chr; - - /* FIXME: This function needs to go away: use chardev properties! */ - - while (next_serial < MAX_SERIAL_PORTS && serial_hds[next_serial]) { - chr = serial_hds[next_serial++]; - qemu_chr_fe_claim_no_fail(chr); - return chr; - } - return NULL; -} - QemuOptsList qemu_chardev_opts = { .name = "chardev", .implied_opt_name = "backend", diff --git a/target-arm/cpu.h b/target-arm/cpu.h index c741b53ad4..401955f825 100644 --- a/target-arm/cpu.h +++ b/target-arm/cpu.h @@ -93,7 +93,19 @@ #define ARM_CPU_VFIQ 3 #define NB_MMU_MODES 7 -#define TARGET_INSN_START_EXTRA_WORDS 1 +/* ARM-specific extra insn start words: + * 1: Conditional execution bits + * 2: Partial exception syndrome for data aborts + */ +#define TARGET_INSN_START_EXTRA_WORDS 2 + +/* The 2nd extra word holding syndrome info for data aborts does not use + * the upper 6 bits nor the lower 14 bits. We mask and shift it down to + * help the sleb128 encoder do a better job. + * When restoring the CPU state, we shift it back up. + */ +#define ARM_INSN_START_WORD2_MASK ((1 << 26) - 1) +#define ARM_INSN_START_WORD2_SHIFT 14 /* We currently assume float and double are IEEE single and double precision respectively. @@ -278,6 +290,7 @@ typedef struct CPUARMState { uint64_t far_el[4]; }; uint64_t hpfar_el2; + uint64_t hstr_el2; union { /* Translation result. */ struct { uint64_t _unused_par_0; diff --git a/target-arm/helper.c b/target-arm/helper.c index e3ea26f8c8..862e7808a2 100644 --- a/target-arm/helper.c +++ b/target-arm/helper.c @@ -3471,6 +3471,9 @@ static const ARMCPRegInfo el3_no_el2_cp_reginfo[] = { .opc0 = 3, .opc1 = 4, .crn = 6, .crm = 0, .opc2 = 4, .access = PL2_RW, .accessfn = access_el3_aa32ns_aa64any, .type = ARM_CP_CONST, .resetvalue = 0 }, + { .name = "HSTR_EL2", .state = ARM_CP_STATE_BOTH, + .opc0 = 3, .opc1 = 4, .crn = 1, .crm = 1, .opc2 = 3, + .access = PL2_RW, .type = ARM_CP_CONST, .resetvalue = 0 }, REGINFO_SENTINEL }; @@ -3706,6 +3709,10 @@ static const ARMCPRegInfo el2_cp_reginfo[] = { .opc0 = 3, .opc1 = 4, .crn = 6, .crm = 0, .opc2 = 4, .access = PL2_RW, .fieldoffset = offsetof(CPUARMState, cp15.hpfar_el2) }, + { .name = "HSTR_EL2", .state = ARM_CP_STATE_BOTH, + .cp = 15, .opc0 = 3, .opc1 = 4, .crn = 1, .crm = 1, .opc2 = 3, + .access = PL2_RW, + .fieldoffset = offsetof(CPUARMState, cp15.hstr_el2) }, REGINFO_SENTINEL }; @@ -6358,9 +6365,6 @@ static void arm_cpu_do_interrupt_aarch64(CPUState *cs) env->elr_el[new_el] = env->pc; } else { env->banked_spsr[aarch64_banked_spsr_index(new_el)] = cpsr_read(env); - if (!env->thumb) { - env->cp15.esr_el[new_el] |= 1 << 25; - } env->elr_el[new_el] = env->regs[15]; aarch64_sync_32_to_64(env); @@ -7275,7 +7279,7 @@ static bool get_phys_addr_lpae(CPUARMState *env, target_ulong address, target_ulong page_size; uint32_t attrs; int32_t stride = 9; - int32_t va_size; + int32_t addrsize; int inputsize; int32_t tbi = 0; TCR *tcr = regime_tcr(env, mmu_idx); @@ -7283,6 +7287,7 @@ static bool get_phys_addr_lpae(CPUARMState *env, target_ulong address, uint32_t el = regime_el(env, mmu_idx); bool ttbr1_valid = true; uint64_t descaddrmask; + bool aarch64 = arm_el_is_aa64(env, el); /* TODO: * This code does not handle the different format TCR for VTCR_EL2. @@ -7290,9 +7295,9 @@ static bool get_phys_addr_lpae(CPUARMState *env, target_ulong address, * Attribute and permission bit handling should also be checked when adding * support for those page table walks. */ - if (arm_el_is_aa64(env, el)) { + if (aarch64) { level = 0; - va_size = 64; + addrsize = 64; if (el > 1) { if (mmu_idx != ARMMMUIdx_S2NS) { tbi = extract64(tcr->raw_tcr, 20, 1); @@ -7314,7 +7319,7 @@ static bool get_phys_addr_lpae(CPUARMState *env, target_ulong address, } } else { level = 1; - va_size = 32; + addrsize = 32; /* There is no TTBR1 for EL2 */ if (el == 2) { ttbr1_valid = false; @@ -7326,7 +7331,7 @@ static bool get_phys_addr_lpae(CPUARMState *env, target_ulong address, * This is a Non-secure PL0/1 stage 1 translation, so controlled by * TTBCR/TTBR0/TTBR1 in accordance with ARM ARM DDI0406C table B-32: */ - if (va_size == 64) { + if (aarch64) { /* AArch64 translation. */ t0sz = extract32(tcr->raw_tcr, 0, 6); t0sz = MIN(t0sz, 39); @@ -7338,7 +7343,12 @@ static bool get_phys_addr_lpae(CPUARMState *env, target_ulong address, /* AArch32 stage 2 translation. */ bool sext = extract32(tcr->raw_tcr, 4, 1); bool sign = extract32(tcr->raw_tcr, 3, 1); - t0sz = sextract32(tcr->raw_tcr, 0, 4); + /* Address size is 40-bit for a stage 2 translation, + * and t0sz can be negative (from -8 to 7), + * so we need to adjust it to use the TTBR selecting logic below. + */ + addrsize = 40; + t0sz = sextract32(tcr->raw_tcr, 0, 4) + 8; /* If the sign-extend bit is not the same as t0sz[3], the result * is unpredictable. Flag this as a guest error. */ @@ -7348,15 +7358,15 @@ static bool get_phys_addr_lpae(CPUARMState *env, target_ulong address, } } t1sz = extract32(tcr->raw_tcr, 16, 6); - if (va_size == 64) { + if (aarch64) { t1sz = MIN(t1sz, 39); t1sz = MAX(t1sz, 16); } - if (t0sz && !extract64(address, va_size - t0sz, t0sz - tbi)) { + if (t0sz && !extract64(address, addrsize - t0sz, t0sz - tbi)) { /* there is a ttbr0 region and we are in it (high bits all zero) */ ttbr_select = 0; } else if (ttbr1_valid && t1sz && - !extract64(~address, va_size - t1sz, t1sz - tbi)) { + !extract64(~address, addrsize - t1sz, t1sz - tbi)) { /* there is a ttbr1 region and we are in it (high bits all one) */ ttbr_select = 1; } else if (!t0sz) { @@ -7383,7 +7393,7 @@ static bool get_phys_addr_lpae(CPUARMState *env, target_ulong address, if (el < 2) { epd = extract32(tcr->raw_tcr, 7, 1); } - inputsize = va_size - t0sz; + inputsize = addrsize - t0sz; tg = extract32(tcr->raw_tcr, 14, 2); if (tg == 1) { /* 64KB pages */ @@ -7398,7 +7408,7 @@ static bool get_phys_addr_lpae(CPUARMState *env, target_ulong address, ttbr = regime_ttbr(env, mmu_idx, 1); epd = extract32(tcr->raw_tcr, 23, 1); - inputsize = va_size - t1sz; + inputsize = addrsize - t1sz; tg = extract32(tcr->raw_tcr, 30, 2); if (tg == 3) { /* 64KB pages */ @@ -7410,7 +7420,7 @@ static bool get_phys_addr_lpae(CPUARMState *env, target_ulong address, } /* Here we should have set up all the parameters for the translation: - * va_size, inputsize, ttbr, epd, stride, tbi + * inputsize, ttbr, epd, stride, tbi */ if (epd) { @@ -7441,7 +7451,7 @@ static bool get_phys_addr_lpae(CPUARMState *env, target_ulong address, uint32_t startlevel; bool ok; - if (va_size == 32 || stride == 9) { + if (!aarch64 || stride == 9) { /* AArch32 or 4KB pages */ startlevel = 2 - sl0; } else { @@ -7450,7 +7460,7 @@ static bool get_phys_addr_lpae(CPUARMState *env, target_ulong address, } /* Check that the starting level is valid. */ - ok = check_s2_mmu_setup(cpu, va_size == 64, startlevel, + ok = check_s2_mmu_setup(cpu, aarch64, startlevel, inputsize, stride); if (!ok) { fault_type = translation_fault; @@ -7471,7 +7481,7 @@ static bool get_phys_addr_lpae(CPUARMState *env, target_ulong address, * up to bit 39 for AArch32, because we don't need other bits in that case * to construct next descriptor address (anyway they should be all zeroes). */ - descaddrmask = ((1ull << (va_size == 64 ? 48 : 40)) - 1) & + descaddrmask = ((1ull << (aarch64 ? 48 : 40)) - 1) & ~indexmask_grainsize; /* Secure accesses start with the page table in secure memory and @@ -7554,7 +7564,7 @@ static bool get_phys_addr_lpae(CPUARMState *env, target_ulong address, } else { ns = extract32(attrs, 3, 1); pxn = extract32(attrs, 11, 1); - *prot = get_S1prot(env, mmu_idx, va_size == 64, ap, ns, xn, pxn); + *prot = get_S1prot(env, mmu_idx, aarch64, ap, ns, xn, pxn); } fault_type = permission_fault; diff --git a/target-arm/internals.h b/target-arm/internals.h index a1258738d9..728ecbab6d 100644 --- a/target-arm/internals.h +++ b/target-arm/internals.h @@ -367,7 +367,7 @@ static inline uint32_t syn_fp_access_trap(int cv, int cond, bool is_16bit) static inline uint32_t syn_insn_abort(int same_el, int ea, int s1ptw, int fsc) { return (EC_INSNABORT << ARM_EL_EC_SHIFT) | (same_el << ARM_EL_EC_SHIFT) - | (ea << 9) | (s1ptw << 7) | fsc; + | ARM_EL_IL | (ea << 9) | (s1ptw << 7) | fsc; } static inline uint32_t syn_data_abort_no_iss(int same_el, @@ -396,13 +396,13 @@ static inline uint32_t syn_data_abort_with_iss(int same_el, static inline uint32_t syn_swstep(int same_el, int isv, int ex) { return (EC_SOFTWARESTEP << ARM_EL_EC_SHIFT) | (same_el << ARM_EL_EC_SHIFT) - | (isv << 24) | (ex << 6) | 0x22; + | ARM_EL_IL | (isv << 24) | (ex << 6) | 0x22; } static inline uint32_t syn_watchpoint(int same_el, int cm, int wnr) { return (EC_WATCHPOINT << ARM_EL_EC_SHIFT) | (same_el << ARM_EL_EC_SHIFT) - | (cm << 8) | (wnr << 6) | 0x22; + | ARM_EL_IL | (cm << 8) | (wnr << 6) | 0x22; } static inline uint32_t syn_breakpoint(int same_el) diff --git a/target-arm/op_helper.c b/target-arm/op_helper.c index 0b29b9dbf2..35912a1192 100644 --- a/target-arm/op_helper.c +++ b/target-arm/op_helper.c @@ -76,6 +76,43 @@ uint32_t HELPER(neon_tbl)(CPUARMState *env, uint32_t ireg, uint32_t def, #if !defined(CONFIG_USER_ONLY) +static inline uint32_t merge_syn_data_abort(uint32_t template_syn, + unsigned int target_el, + bool same_el, + bool s1ptw, int is_write, + int fsc) +{ + uint32_t syn; + + /* ISV is only set for data aborts routed to EL2 and + * never for stage-1 page table walks faulting on stage 2. + * + * Furthermore, ISV is only set for certain kinds of load/stores. + * If the template syndrome does not have ISV set, we should leave + * it cleared. + * + * See ARMv8 specs, D7-1974: + * ISS encoding for an exception from a Data Abort, the + * ISV field. + */ + if (!(template_syn & ARM_EL_ISV) || target_el != 2 || s1ptw) { + syn = syn_data_abort_no_iss(same_el, + 0, 0, s1ptw, is_write == 1, fsc); + } else { + /* Fields: IL, ISV, SAS, SSE, SRT, SF and AR come from the template + * syndrome created at translation time. + * Now we create the runtime syndrome with the remaining fields. + */ + syn = syn_data_abort_with_iss(same_el, + 0, 0, 0, 0, 0, + 0, 0, s1ptw, is_write == 1, fsc, + false); + /* Merge the runtime syndrome with the template syndrome. */ + syn |= template_syn; + } + return syn; +} + /* try to fill the TLB and return an exception if error. If retaddr is * NULL, it means that the function was called in C code (i.e. not * from generated code or from helper.c) @@ -116,8 +153,8 @@ void tlb_fill(CPUState *cs, target_ulong addr, int is_write, int mmu_idx, syn = syn_insn_abort(same_el, 0, fi.s1ptw, syn); exc = EXCP_PREFETCH_ABORT; } else { - syn = syn_data_abort_no_iss(same_el, - 0, 0, fi.s1ptw, is_write == 1, syn); + syn = merge_syn_data_abort(env->exception.syndrome, target_el, + same_el, fi.s1ptw, is_write, syn); if (is_write == 1 && arm_feature(env, ARM_FEATURE_V6)) { fsr |= (1 << 11); } @@ -138,6 +175,7 @@ void arm_cpu_do_unaligned_access(CPUState *cs, vaddr vaddr, int is_write, CPUARMState *env = &cpu->env; int target_el; bool same_el; + uint32_t syn; if (retaddr) { /* now we have a real cpu fault */ @@ -162,10 +200,9 @@ void arm_cpu_do_unaligned_access(CPUState *cs, vaddr vaddr, int is_write, env->exception.fsr |= (1 << 11); } - raise_exception(env, EXCP_DATA_ABORT, - syn_data_abort_no_iss(same_el, - 0, 0, 0, is_write == 1, 0x21), - target_el); + syn = merge_syn_data_abort(env->exception.syndrome, target_el, + same_el, 0, is_write, 0x21); + raise_exception(env, EXCP_DATA_ABORT, syn, target_el); } #endif /* !defined(CONFIG_USER_ONLY) */ diff --git a/target-arm/translate-a64.c b/target-arm/translate-a64.c index ce8141a442..f5e29d20a1 100644 --- a/target-arm/translate-a64.c +++ b/target-arm/translate-a64.c @@ -308,6 +308,20 @@ static inline void gen_goto_tb(DisasContext *s, int n, uint64_t dest) } } +static void disas_set_insn_syndrome(DisasContext *s, uint32_t syn) +{ + /* We don't need to save all of the syndrome so we mask and shift + * out uneeded bits to help the sleb128 encoder do a better job. + */ + syn &= ARM_INSN_START_WORD2_MASK; + syn >>= ARM_INSN_START_WORD2_SHIFT; + + /* We check and clear insn_start_idx to catch multiple updates. */ + assert(s->insn_start_idx != 0); + tcg_set_insn_param(s->insn_start_idx, 2, syn); + s->insn_start_idx = 0; +} + static void unallocated_encoding(DisasContext *s) { /* Unallocated and reserved encodings are uncategorized */ @@ -723,23 +737,47 @@ static void gen_adc_CC(int sf, TCGv_i64 dest, TCGv_i64 t0, TCGv_i64 t1) * Store from GPR register to memory. */ static void do_gpr_st_memidx(DisasContext *s, TCGv_i64 source, - TCGv_i64 tcg_addr, int size, int memidx) + TCGv_i64 tcg_addr, int size, int memidx, + bool iss_valid, + unsigned int iss_srt, + bool iss_sf, bool iss_ar) { g_assert(size <= 3); tcg_gen_qemu_st_i64(source, tcg_addr, memidx, s->be_data + size); + + if (iss_valid) { + uint32_t syn; + + syn = syn_data_abort_with_iss(0, + size, + false, + iss_srt, + iss_sf, + iss_ar, + 0, 0, 0, 0, 0, false); + disas_set_insn_syndrome(s, syn); + } } static void do_gpr_st(DisasContext *s, TCGv_i64 source, - TCGv_i64 tcg_addr, int size) + TCGv_i64 tcg_addr, int size, + bool iss_valid, + unsigned int iss_srt, + bool iss_sf, bool iss_ar) { - do_gpr_st_memidx(s, source, tcg_addr, size, get_mem_index(s)); + do_gpr_st_memidx(s, source, tcg_addr, size, get_mem_index(s), + iss_valid, iss_srt, iss_sf, iss_ar); } /* * Load from memory to GPR register */ -static void do_gpr_ld_memidx(DisasContext *s, TCGv_i64 dest, TCGv_i64 tcg_addr, - int size, bool is_signed, bool extend, int memidx) +static void do_gpr_ld_memidx(DisasContext *s, + TCGv_i64 dest, TCGv_i64 tcg_addr, + int size, bool is_signed, + bool extend, int memidx, + bool iss_valid, unsigned int iss_srt, + bool iss_sf, bool iss_ar) { TCGMemOp memop = s->be_data + size; @@ -755,13 +793,30 @@ static void do_gpr_ld_memidx(DisasContext *s, TCGv_i64 dest, TCGv_i64 tcg_addr, g_assert(size < 3); tcg_gen_ext32u_i64(dest, dest); } + + if (iss_valid) { + uint32_t syn; + + syn = syn_data_abort_with_iss(0, + size, + is_signed, + iss_srt, + iss_sf, + iss_ar, + 0, 0, 0, 0, 0, false); + disas_set_insn_syndrome(s, syn); + } } -static void do_gpr_ld(DisasContext *s, TCGv_i64 dest, TCGv_i64 tcg_addr, - int size, bool is_signed, bool extend) +static void do_gpr_ld(DisasContext *s, + TCGv_i64 dest, TCGv_i64 tcg_addr, + int size, bool is_signed, bool extend, + bool iss_valid, unsigned int iss_srt, + bool iss_sf, bool iss_ar) { do_gpr_ld_memidx(s, dest, tcg_addr, size, is_signed, extend, - get_mem_index(s)); + get_mem_index(s), + iss_valid, iss_srt, iss_sf, iss_ar); } /* @@ -1817,6 +1872,22 @@ static void gen_store_exclusive(DisasContext *s, int rd, int rt, int rt2, } #endif +/* Update the Sixty-Four bit (SF) registersize. This logic is derived + * from the ARMv8 specs for LDR (Shared decode for all encodings). + */ +static bool disas_ldst_compute_iss_sf(int size, bool is_signed, int opc) +{ + int opc0 = extract32(opc, 0, 1); + int regsize; + + if (is_signed) { + regsize = opc0 ? 32 : 64; + } else { + regsize = size == 3 ? 64 : 32; + } + return regsize == 64; +} + /* C3.3.6 Load/store exclusive * * 31 30 29 24 23 22 21 20 16 15 14 10 9 5 4 0 @@ -1868,10 +1939,15 @@ static void disas_ldst_excl(DisasContext *s, uint32_t insn) } } else { TCGv_i64 tcg_rt = cpu_reg(s, rt); + bool iss_sf = disas_ldst_compute_iss_sf(size, false, 0); + + /* Generate ISS for non-exclusive accesses including LASR. */ if (is_store) { - do_gpr_st(s, tcg_rt, tcg_addr, size); + do_gpr_st(s, tcg_rt, tcg_addr, size, + true, rt, iss_sf, is_lasr); } else { - do_gpr_ld(s, tcg_rt, tcg_addr, size, false, false); + do_gpr_ld(s, tcg_rt, tcg_addr, size, false, false, + true, rt, iss_sf, is_lasr); } } } @@ -1923,7 +1999,11 @@ static void disas_ld_lit(DisasContext *s, uint32_t insn) if (is_vector) { do_fp_ld(s, rt, tcg_addr, size); } else { - do_gpr_ld(s, tcg_rt, tcg_addr, size, is_signed, false); + /* Only unsigned 32bit loads target 32bit registers. */ + bool iss_sf = opc == 0 ? 32 : 64; + + do_gpr_ld(s, tcg_rt, tcg_addr, size, is_signed, false, + true, rt, iss_sf, false); } tcg_temp_free_i64(tcg_addr); } @@ -2042,9 +2122,11 @@ static void disas_ldst_pair(DisasContext *s, uint32_t insn) } else { TCGv_i64 tcg_rt = cpu_reg(s, rt); if (is_load) { - do_gpr_ld(s, tcg_rt, tcg_addr, size, is_signed, false); + do_gpr_ld(s, tcg_rt, tcg_addr, size, is_signed, false, + false, 0, false, false); } else { - do_gpr_st(s, tcg_rt, tcg_addr, size); + do_gpr_st(s, tcg_rt, tcg_addr, size, + false, 0, false, false); } } tcg_gen_addi_i64(tcg_addr, tcg_addr, 1 << size); @@ -2057,9 +2139,11 @@ static void disas_ldst_pair(DisasContext *s, uint32_t insn) } else { TCGv_i64 tcg_rt2 = cpu_reg(s, rt2); if (is_load) { - do_gpr_ld(s, tcg_rt2, tcg_addr, size, is_signed, false); + do_gpr_ld(s, tcg_rt2, tcg_addr, size, is_signed, false, + false, 0, false, false); } else { - do_gpr_st(s, tcg_rt2, tcg_addr, size); + do_gpr_st(s, tcg_rt2, tcg_addr, size, + false, 0, false, false); } } @@ -2102,6 +2186,7 @@ static void disas_ldst_reg_imm9(DisasContext *s, uint32_t insn, bool is_store = false; bool is_extended = false; bool is_unpriv = (idx == 2); + bool iss_valid = !is_vector; bool post_index; bool writeback; @@ -2169,12 +2254,15 @@ static void disas_ldst_reg_imm9(DisasContext *s, uint32_t insn, } else { TCGv_i64 tcg_rt = cpu_reg(s, rt); int memidx = is_unpriv ? get_a64_user_mem_index(s) : get_mem_index(s); + bool iss_sf = disas_ldst_compute_iss_sf(size, is_signed, opc); if (is_store) { - do_gpr_st_memidx(s, tcg_rt, tcg_addr, size, memidx); + do_gpr_st_memidx(s, tcg_rt, tcg_addr, size, memidx, + iss_valid, rt, iss_sf, false); } else { do_gpr_ld_memidx(s, tcg_rt, tcg_addr, size, - is_signed, is_extended, memidx); + is_signed, is_extended, memidx, + iss_valid, rt, iss_sf, false); } } @@ -2272,10 +2360,14 @@ static void disas_ldst_reg_roffset(DisasContext *s, uint32_t insn, } } else { TCGv_i64 tcg_rt = cpu_reg(s, rt); + bool iss_sf = disas_ldst_compute_iss_sf(size, is_signed, opc); if (is_store) { - do_gpr_st(s, tcg_rt, tcg_addr, size); + do_gpr_st(s, tcg_rt, tcg_addr, size, + true, rt, iss_sf, false); } else { - do_gpr_ld(s, tcg_rt, tcg_addr, size, is_signed, is_extended); + do_gpr_ld(s, tcg_rt, tcg_addr, size, + is_signed, is_extended, + true, rt, iss_sf, false); } } } @@ -2352,10 +2444,13 @@ static void disas_ldst_reg_unsigned_imm(DisasContext *s, uint32_t insn, } } else { TCGv_i64 tcg_rt = cpu_reg(s, rt); + bool iss_sf = disas_ldst_compute_iss_sf(size, is_signed, opc); if (is_store) { - do_gpr_st(s, tcg_rt, tcg_addr, size); + do_gpr_st(s, tcg_rt, tcg_addr, size, + true, rt, iss_sf, false); } else { - do_gpr_ld(s, tcg_rt, tcg_addr, size, is_signed, is_extended); + do_gpr_ld(s, tcg_rt, tcg_addr, size, is_signed, is_extended, + true, rt, iss_sf, false); } } } @@ -11102,7 +11197,8 @@ void gen_intermediate_code_a64(ARMCPU *cpu, TranslationBlock *tb) tcg_clear_temp_count(); do { - tcg_gen_insn_start(dc->pc, 0); + dc->insn_start_idx = tcg_op_buf_count(); + tcg_gen_insn_start(dc->pc, 0, 0); num_insns++; if (unlikely(!QTAILQ_EMPTY(&cs->breakpoints))) { diff --git a/target-arm/translate.c b/target-arm/translate.c index e525f1eb4e..6815bc1a79 100644 --- a/target-arm/translate.c +++ b/target-arm/translate.c @@ -11732,7 +11732,8 @@ void gen_intermediate_code(CPUARMState *env, TranslationBlock *tb) } do { tcg_gen_insn_start(dc->pc, - (dc->condexec_cond << 4) | (dc->condexec_mask >> 1)); + (dc->condexec_cond << 4) | (dc->condexec_mask >> 1), + 0); num_insns++; #ifdef CONFIG_USER_ONLY @@ -12049,8 +12050,10 @@ void restore_state_to_opc(CPUARMState *env, TranslationBlock *tb, if (is_a64(env)) { env->pc = data[0]; env->condexec_bits = 0; + env->exception.syndrome = data[2] << ARM_INSN_START_WORD2_SHIFT; } else { env->regs[15] = data[0]; env->condexec_bits = data[1]; + env->exception.syndrome = data[2] << ARM_INSN_START_WORD2_SHIFT; } } diff --git a/target-arm/translate.h b/target-arm/translate.h index 6a18d7badc..dbd7ac83d5 100644 --- a/target-arm/translate.h +++ b/target-arm/translate.h @@ -59,6 +59,8 @@ typedef struct DisasContext { bool ss_same_el; /* Bottom two bits of XScale c15_cpar coprocessor access control reg */ int c15_cpar; + /* TCG op index of the current insn_start. */ + int insn_start_idx; #define TMP_A64_MAX 16 int tmp_a64_count; TCGv_i64 tmp_a64[TMP_A64_MAX];