diff --git a/default-configs/aarch64-softmmu.mak b/default-configs/aarch64-softmmu.mak index 6d3b5c7a46..96dd994b3c 100644 --- a/default-configs/aarch64-softmmu.mak +++ b/default-configs/aarch64-softmmu.mak @@ -3,4 +3,4 @@ # We support all the 32 bit boards so need all their config include arm-softmmu.mak -# Currently no 64-bit specific config requirements +CONFIG_XLNX_ZYNQMP=y diff --git a/hw/arm/Makefile.objs b/hw/arm/Makefile.objs index 2577f68097..a75a182f9b 100644 --- a/hw/arm/Makefile.objs +++ b/hw/arm/Makefile.objs @@ -10,3 +10,4 @@ obj-$(CONFIG_DIGIC) += digic.o obj-y += omap1.o omap2.o strongarm.o obj-$(CONFIG_ALLWINNER_A10) += allwinner-a10.o cubieboard.o obj-$(CONFIG_STM32F205_SOC) += stm32f205_soc.o +obj-$(CONFIG_XLNX_ZYNQMP) += xlnx-zynqmp.o xlnx-ep108.o diff --git a/hw/arm/xlnx-ep108.c b/hw/arm/xlnx-ep108.c new file mode 100644 index 0000000000..b924f5eca5 --- /dev/null +++ b/hw/arm/xlnx-ep108.c @@ -0,0 +1,82 @@ +/* + * Xilinx ZynqMP EP108 board + * + * Copyright (C) 2015 Xilinx Inc + * Written by Peter Crosthwaite + * + * 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. + */ + +#include "hw/arm/xlnx-zynqmp.h" +#include "hw/boards.h" +#include "qemu/error-report.h" +#include "exec/address-spaces.h" + +typedef struct XlnxEP108 { + XlnxZynqMPState soc; + MemoryRegion ddr_ram; +} XlnxEP108; + +/* Max 2GB RAM */ +#define EP108_MAX_RAM_SIZE 0x80000000ull + +static struct arm_boot_info xlnx_ep108_binfo; + +static void xlnx_ep108_init(MachineState *machine) +{ + XlnxEP108 *s = g_new0(XlnxEP108, 1); + Error *err = NULL; + + object_initialize(&s->soc, sizeof(s->soc), TYPE_XLNX_ZYNQMP); + object_property_add_child(OBJECT(machine), "soc", OBJECT(&s->soc), + &error_abort); + + object_property_set_bool(OBJECT(&s->soc), true, "realized", &err); + if (err) { + error_report("%s", error_get_pretty(err)); + exit(1); + } + + if (machine->ram_size > EP108_MAX_RAM_SIZE) { + error_report("WARNING: RAM size " RAM_ADDR_FMT " above max supported, " + "reduced to %llx", machine->ram_size, EP108_MAX_RAM_SIZE); + machine->ram_size = EP108_MAX_RAM_SIZE; + } + + if (machine->ram_size <= 0x08000000) { + qemu_log("WARNING: RAM size " RAM_ADDR_FMT " is small for EP108", + machine->ram_size); + } + + memory_region_allocate_system_memory(&s->ddr_ram, NULL, "ddr-ram", + machine->ram_size); + memory_region_add_subregion(get_system_memory(), 0, &s->ddr_ram); + + xlnx_ep108_binfo.ram_size = machine->ram_size; + xlnx_ep108_binfo.kernel_filename = machine->kernel_filename; + xlnx_ep108_binfo.kernel_cmdline = machine->kernel_cmdline; + xlnx_ep108_binfo.initrd_filename = machine->initrd_filename; + xlnx_ep108_binfo.loader_start = 0; + arm_load_kernel(&s->soc.cpu[0], &xlnx_ep108_binfo); +} + +static QEMUMachine xlnx_ep108_machine = { + .name = "xlnx-ep108", + .desc = "Xilinx ZynqMP EP108 board", + .init = xlnx_ep108_init, +}; + +static void xlnx_ep108_machine_init(void) +{ + qemu_register_machine(&xlnx_ep108_machine); +} + +machine_init(xlnx_ep108_machine_init); diff --git a/hw/arm/xlnx-zynqmp.c b/hw/arm/xlnx-zynqmp.c new file mode 100644 index 0000000000..6b019651ac --- /dev/null +++ b/hw/arm/xlnx-zynqmp.c @@ -0,0 +1,211 @@ +/* + * Xilinx Zynq MPSoC emulation + * + * Copyright (C) 2015 Xilinx Inc + * Written by Peter Crosthwaite + * + * 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. + */ + +#include "hw/arm/xlnx-zynqmp.h" +#include "hw/intc/arm_gic_common.h" +#include "exec/address-spaces.h" + +#define GIC_NUM_SPI_INTR 160 + +#define ARM_PHYS_TIMER_PPI 30 +#define ARM_VIRT_TIMER_PPI 27 + +#define GIC_BASE_ADDR 0xf9000000 +#define GIC_DIST_ADDR 0xf9010000 +#define GIC_CPU_ADDR 0xf9020000 + +static const uint64_t gem_addr[XLNX_ZYNQMP_NUM_GEMS] = { + 0xFF0B0000, 0xFF0C0000, 0xFF0D0000, 0xFF0E0000, +}; + +static const int gem_intr[XLNX_ZYNQMP_NUM_GEMS] = { + 57, 59, 61, 63, +}; + +static const uint64_t uart_addr[XLNX_ZYNQMP_NUM_UARTS] = { + 0xFF000000, 0xFF010000, +}; + +static const int uart_intr[XLNX_ZYNQMP_NUM_UARTS] = { + 21, 22, +}; + +typedef struct XlnxZynqMPGICRegion { + int region_index; + uint32_t address; +} XlnxZynqMPGICRegion; + +static const XlnxZynqMPGICRegion xlnx_zynqmp_gic_regions[] = { + { .region_index = 0, .address = GIC_DIST_ADDR, }, + { .region_index = 1, .address = GIC_CPU_ADDR, }, +}; + +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_init(Object *obj) +{ + XlnxZynqMPState *s = XLNX_ZYNQMP(obj); + int i; + + for (i = 0; i < XLNX_ZYNQMP_NUM_CPUS; i++) { + object_initialize(&s->cpu[i], sizeof(s->cpu[i]), + "cortex-a53-" TYPE_ARM_CPU); + object_property_add_child(obj, "cpu[*]", OBJECT(&s->cpu[i]), + &error_abort); + } + + object_initialize(&s->gic, sizeof(s->gic), TYPE_ARM_GIC); + qdev_set_parent_bus(DEVICE(&s->gic), sysbus_get_default()); + + for (i = 0; i < XLNX_ZYNQMP_NUM_GEMS; i++) { + object_initialize(&s->gem[i], sizeof(s->gem[i]), TYPE_CADENCE_GEM); + qdev_set_parent_bus(DEVICE(&s->gem[i]), sysbus_get_default()); + } + + for (i = 0; i < XLNX_ZYNQMP_NUM_UARTS; i++) { + object_initialize(&s->uart[i], sizeof(s->uart[i]), TYPE_CADENCE_UART); + qdev_set_parent_bus(DEVICE(&s->uart[i]), sysbus_get_default()); + } +} + +static void xlnx_zynqmp_realize(DeviceState *dev, Error **errp) +{ + XlnxZynqMPState *s = XLNX_ZYNQMP(dev); + MemoryRegion *system_memory = get_system_memory(); + uint8_t i; + qemu_irq gic_spi[GIC_NUM_SPI_INTR]; + Error *err = NULL; + + 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_CPUS); + 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); + const XlnxZynqMPGICRegion *r = &xlnx_zynqmp_gic_regions[i]; + MemoryRegion *mr = sysbus_mmio_get_region(gic, r->region_index); + uint32_t addr = r->address; + int j; + + sysbus_mmio_map(gic, r->region_index, addr); + + for (j = 0; j < XLNX_ZYNQMP_GIC_ALIASES; j++) { + MemoryRegion *alias = &s->gic_mr[i][j]; + + addr += XLNX_ZYNQMP_GIC_REGION_SIZE; + memory_region_init_alias(alias, OBJECT(s), "zynqmp-gic-alias", mr, + 0, XLNX_ZYNQMP_GIC_REGION_SIZE); + memory_region_add_subregion(system_memory, addr, alias); + } + } + + for (i = 0; i < XLNX_ZYNQMP_NUM_CPUS; i++) { + qemu_irq irq; + + object_property_set_int(OBJECT(&s->cpu[i]), QEMU_PSCI_CONDUIT_SMC, + "psci-conduit", &error_abort); + if (i > 0) { + /* Secondary CPUs start in PSCI powered-down state */ + object_property_set_bool(OBJECT(&s->cpu[i]), true, + "start-powered-off", &error_abort); + } + + object_property_set_int(OBJECT(&s->cpu[i]), GIC_BASE_ADDR, + "reset-cbar", &err); + if (err) { + error_propagate((errp), (err)); + return; + } + + object_property_set_bool(OBJECT(&s->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->cpu[i]), ARM_CPU_IRQ)); + irq = qdev_get_gpio_in(DEVICE(&s->gic), + arm_gic_ppi_index(i, ARM_PHYS_TIMER_PPI)); + qdev_connect_gpio_out(DEVICE(&s->cpu[i]), 0, irq); + irq = qdev_get_gpio_in(DEVICE(&s->gic), + arm_gic_ppi_index(i, ARM_VIRT_TIMER_PPI)); + qdev_connect_gpio_out(DEVICE(&s->cpu[i]), 1, irq); + } + + for (i = 0; i < GIC_NUM_SPI_INTR; i++) { + gic_spi[i] = qdev_get_gpio_in(DEVICE(&s->gic), i); + } + + for (i = 0; i < XLNX_ZYNQMP_NUM_GEMS; i++) { + NICInfo *nd = &nd_table[i]; + + if (nd->used) { + qemu_check_nic_model(nd, TYPE_CADENCE_GEM); + qdev_set_nic_properties(DEVICE(&s->gem[i]), nd); + } + object_property_set_bool(OBJECT(&s->gem[i]), true, "realized", &err); + if (err) { + error_propagate((errp), (err)); + return; + } + sysbus_mmio_map(SYS_BUS_DEVICE(&s->gem[i]), 0, gem_addr[i]); + sysbus_connect_irq(SYS_BUS_DEVICE(&s->gem[i]), 0, + gic_spi[gem_intr[i]]); + } + + for (i = 0; i < XLNX_ZYNQMP_NUM_UARTS; i++) { + object_property_set_bool(OBJECT(&s->uart[i]), true, "realized", &err); + if (err) { + error_propagate((errp), (err)); + return; + } + sysbus_mmio_map(SYS_BUS_DEVICE(&s->uart[i]), 0, uart_addr[i]); + sysbus_connect_irq(SYS_BUS_DEVICE(&s->uart[i]), 0, + gic_spi[uart_intr[i]]); + } +} + +static void xlnx_zynqmp_class_init(ObjectClass *oc, void *data) +{ + DeviceClass *dc = DEVICE_CLASS(oc); + + dc->realize = xlnx_zynqmp_realize; +} + +static const TypeInfo xlnx_zynqmp_type_info = { + .name = TYPE_XLNX_ZYNQMP, + .parent = TYPE_DEVICE, + .instance_size = sizeof(XlnxZynqMPState), + .instance_init = xlnx_zynqmp_init, + .class_init = xlnx_zynqmp_class_init, +}; + +static void xlnx_zynqmp_register_types(void) +{ + type_register_static(&xlnx_zynqmp_type_info); +} + +type_init(xlnx_zynqmp_register_types) diff --git a/hw/char/cadence_uart.c b/hw/char/cadence_uart.c index d1453782a7..9d379e5b15 100644 --- a/hw/char/cadence_uart.c +++ b/hw/char/cadence_uart.c @@ -16,9 +16,7 @@ * with this program; if not, see . */ -#include "hw/sysbus.h" -#include "sysemu/char.h" -#include "qemu/timer.h" +#include "hw/char/cadence_uart.h" #ifdef CADENCE_UART_ERR_DEBUG #define DB_PRINT(...) do { \ @@ -85,8 +83,6 @@ #define LOCAL_LOOPBACK (0x2 << UART_MR_CHMODE_SH) #define REMOTE_LOOPBACK (0x3 << UART_MR_CHMODE_SH) -#define RX_FIFO_SIZE 16 -#define TX_FIFO_SIZE 16 #define UART_INPUT_CLK 50000000 #define R_CR (0x00/4) @@ -108,38 +104,18 @@ #define R_PWID (0x40/4) #define R_TTRIG (0x44/4) -#define R_MAX (R_TTRIG + 1) -#define TYPE_CADENCE_UART "cadence_uart" -#define CADENCE_UART(obj) OBJECT_CHECK(UartState, (obj), TYPE_CADENCE_UART) - -typedef struct { - /*< private >*/ - SysBusDevice parent_obj; - /*< public >*/ - - MemoryRegion iomem; - uint32_t r[R_MAX]; - uint8_t rx_fifo[RX_FIFO_SIZE]; - uint8_t tx_fifo[TX_FIFO_SIZE]; - uint32_t rx_wpos; - uint32_t rx_count; - uint32_t tx_count; - uint64_t char_tx_time; - CharDriverState *chr; - qemu_irq irq; - QEMUTimer *fifo_trigger_handle; -} UartState; - -static void uart_update_status(UartState *s) +static void uart_update_status(CadenceUARTState *s) { s->r[R_SR] = 0; - s->r[R_SR] |= s->rx_count == RX_FIFO_SIZE ? UART_SR_INTR_RFUL : 0; + s->r[R_SR] |= s->rx_count == CADENCE_UART_RX_FIFO_SIZE ? UART_SR_INTR_RFUL + : 0; s->r[R_SR] |= !s->rx_count ? UART_SR_INTR_REMPTY : 0; s->r[R_SR] |= s->rx_count >= s->r[R_RTRIG] ? UART_SR_INTR_RTRIG : 0; - s->r[R_SR] |= s->tx_count == TX_FIFO_SIZE ? UART_SR_INTR_TFUL : 0; + s->r[R_SR] |= s->tx_count == CADENCE_UART_TX_FIFO_SIZE ? UART_SR_INTR_TFUL + : 0; s->r[R_SR] |= !s->tx_count ? UART_SR_INTR_TEMPTY : 0; s->r[R_SR] |= s->tx_count >= s->r[R_TTRIG] ? UART_SR_TTRIG : 0; @@ -150,14 +126,14 @@ static void uart_update_status(UartState *s) static void fifo_trigger_update(void *opaque) { - UartState *s = (UartState *)opaque; + CadenceUARTState *s = opaque; s->r[R_CISR] |= UART_INTR_TIMEOUT; uart_update_status(s); } -static void uart_rx_reset(UartState *s) +static void uart_rx_reset(CadenceUARTState *s) { s->rx_wpos = 0; s->rx_count = 0; @@ -166,12 +142,12 @@ static void uart_rx_reset(UartState *s) } } -static void uart_tx_reset(UartState *s) +static void uart_tx_reset(CadenceUARTState *s) { s->tx_count = 0; } -static void uart_send_breaks(UartState *s) +static void uart_send_breaks(CadenceUARTState *s) { int break_enabled = 1; @@ -181,7 +157,7 @@ static void uart_send_breaks(UartState *s) } } -static void uart_parameters_setup(UartState *s) +static void uart_parameters_setup(CadenceUARTState *s) { QEMUSerialSetParams ssp; unsigned int baud_rate, packet_size; @@ -236,20 +212,20 @@ static void uart_parameters_setup(UartState *s) static int uart_can_receive(void *opaque) { - UartState *s = (UartState *)opaque; - int ret = MAX(RX_FIFO_SIZE, TX_FIFO_SIZE); + CadenceUARTState *s = opaque; + int ret = MAX(CADENCE_UART_RX_FIFO_SIZE, CADENCE_UART_TX_FIFO_SIZE); uint32_t ch_mode = s->r[R_MR] & UART_MR_CHMODE; if (ch_mode == NORMAL_MODE || ch_mode == ECHO_MODE) { - ret = MIN(ret, RX_FIFO_SIZE - s->rx_count); + ret = MIN(ret, CADENCE_UART_RX_FIFO_SIZE - s->rx_count); } if (ch_mode == REMOTE_LOOPBACK || ch_mode == ECHO_MODE) { - ret = MIN(ret, TX_FIFO_SIZE - s->tx_count); + ret = MIN(ret, CADENCE_UART_TX_FIFO_SIZE - s->tx_count); } return ret; } -static void uart_ctrl_update(UartState *s) +static void uart_ctrl_update(CadenceUARTState *s) { if (s->r[R_CR] & UART_CR_TXRST) { uart_tx_reset(s); @@ -268,7 +244,7 @@ static void uart_ctrl_update(UartState *s) static void uart_write_rx_fifo(void *opaque, const uint8_t *buf, int size) { - UartState *s = (UartState *)opaque; + CadenceUARTState *s = opaque; uint64_t new_rx_time = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL); int i; @@ -276,12 +252,12 @@ static void uart_write_rx_fifo(void *opaque, const uint8_t *buf, int size) return; } - if (s->rx_count == RX_FIFO_SIZE) { + if (s->rx_count == CADENCE_UART_RX_FIFO_SIZE) { s->r[R_CISR] |= UART_INTR_ROVR; } else { for (i = 0; i < size; i++) { s->rx_fifo[s->rx_wpos] = buf[i]; - s->rx_wpos = (s->rx_wpos + 1) % RX_FIFO_SIZE; + s->rx_wpos = (s->rx_wpos + 1) % CADENCE_UART_RX_FIFO_SIZE; s->rx_count++; } timer_mod(s->fifo_trigger_handle, new_rx_time + @@ -293,7 +269,7 @@ static void uart_write_rx_fifo(void *opaque, const uint8_t *buf, int size) static gboolean cadence_uart_xmit(GIOChannel *chan, GIOCondition cond, void *opaque) { - UartState *s = opaque; + CadenceUARTState *s = opaque; int ret; /* instant drain the fifo when there's no back-end */ @@ -320,14 +296,15 @@ static gboolean cadence_uart_xmit(GIOChannel *chan, GIOCondition cond, return FALSE; } -static void uart_write_tx_fifo(UartState *s, const uint8_t *buf, int size) +static void uart_write_tx_fifo(CadenceUARTState *s, const uint8_t *buf, + int size) { if ((s->r[R_CR] & UART_CR_TX_DIS) || !(s->r[R_CR] & UART_CR_TX_EN)) { return; } - if (size > TX_FIFO_SIZE - s->tx_count) { - size = TX_FIFO_SIZE - s->tx_count; + if (size > CADENCE_UART_TX_FIFO_SIZE - s->tx_count) { + size = CADENCE_UART_TX_FIFO_SIZE - s->tx_count; /* * This can only be a guest error via a bad tx fifo register push, * as can_receive() should stop remote loop and echo modes ever getting @@ -345,7 +322,7 @@ static void uart_write_tx_fifo(UartState *s, const uint8_t *buf, int size) static void uart_receive(void *opaque, const uint8_t *buf, int size) { - UartState *s = (UartState *)opaque; + CadenceUARTState *s = opaque; uint32_t ch_mode = s->r[R_MR] & UART_MR_CHMODE; if (ch_mode == NORMAL_MODE || ch_mode == ECHO_MODE) { @@ -358,7 +335,7 @@ static void uart_receive(void *opaque, const uint8_t *buf, int size) static void uart_event(void *opaque, int event) { - UartState *s = (UartState *)opaque; + CadenceUARTState *s = opaque; uint8_t buf = '\0'; if (event == CHR_EVENT_BREAK) { @@ -368,15 +345,15 @@ static void uart_event(void *opaque, int event) uart_update_status(s); } -static void uart_read_rx_fifo(UartState *s, uint32_t *c) +static void uart_read_rx_fifo(CadenceUARTState *s, uint32_t *c) { if ((s->r[R_CR] & UART_CR_RX_DIS) || !(s->r[R_CR] & UART_CR_RX_EN)) { return; } if (s->rx_count) { - uint32_t rx_rpos = - (RX_FIFO_SIZE + s->rx_wpos - s->rx_count) % RX_FIFO_SIZE; + uint32_t rx_rpos = (CADENCE_UART_RX_FIFO_SIZE + s->rx_wpos - + s->rx_count) % CADENCE_UART_RX_FIFO_SIZE; *c = s->rx_fifo[rx_rpos]; s->rx_count--; @@ -393,7 +370,7 @@ static void uart_read_rx_fifo(UartState *s, uint32_t *c) static void uart_write(void *opaque, hwaddr offset, uint64_t value, unsigned size) { - UartState *s = (UartState *)opaque; + CadenceUARTState *s = opaque; DB_PRINT(" offset:%x data:%08x\n", (unsigned)offset, (unsigned)value); offset >>= 2; @@ -437,11 +414,11 @@ static void uart_write(void *opaque, hwaddr offset, static uint64_t uart_read(void *opaque, hwaddr offset, unsigned size) { - UartState *s = (UartState *)opaque; + CadenceUARTState *s = opaque; uint32_t c = 0; offset >>= 2; - if (offset >= R_MAX) { + if (offset >= CADENCE_UART_R_MAX) { c = 0; } else if (offset == R_TX_RX) { uart_read_rx_fifo(s, &c); @@ -461,7 +438,7 @@ static const MemoryRegionOps uart_ops = { static void cadence_uart_reset(DeviceState *dev) { - UartState *s = CADENCE_UART(dev); + CadenceUARTState *s = CADENCE_UART(dev); s->r[R_CR] = 0x00000128; s->r[R_IMR] = 0; @@ -478,7 +455,7 @@ static void cadence_uart_reset(DeviceState *dev) static void cadence_uart_realize(DeviceState *dev, Error **errp) { - UartState *s = CADENCE_UART(dev); + CadenceUARTState *s = CADENCE_UART(dev); s->fifo_trigger_handle = timer_new_ns(QEMU_CLOCK_VIRTUAL, fifo_trigger_update, s); @@ -495,7 +472,7 @@ static void cadence_uart_realize(DeviceState *dev, Error **errp) static void cadence_uart_init(Object *obj) { SysBusDevice *sbd = SYS_BUS_DEVICE(obj); - UartState *s = CADENCE_UART(obj); + CadenceUARTState *s = CADENCE_UART(obj); memory_region_init_io(&s->iomem, obj, &uart_ops, s, "uart", 0x1000); sysbus_init_mmio(sbd, &s->iomem); @@ -506,7 +483,7 @@ static void cadence_uart_init(Object *obj) static int cadence_uart_post_load(void *opaque, int version_id) { - UartState *s = opaque; + CadenceUARTState *s = opaque; uart_parameters_setup(s); uart_update_status(s); @@ -519,13 +496,15 @@ static const VMStateDescription vmstate_cadence_uart = { .minimum_version_id = 2, .post_load = cadence_uart_post_load, .fields = (VMStateField[]) { - VMSTATE_UINT32_ARRAY(r, UartState, R_MAX), - VMSTATE_UINT8_ARRAY(rx_fifo, UartState, RX_FIFO_SIZE), - VMSTATE_UINT8_ARRAY(tx_fifo, UartState, RX_FIFO_SIZE), - VMSTATE_UINT32(rx_count, UartState), - VMSTATE_UINT32(tx_count, UartState), - VMSTATE_UINT32(rx_wpos, UartState), - VMSTATE_TIMER_PTR(fifo_trigger_handle, UartState), + VMSTATE_UINT32_ARRAY(r, CadenceUARTState, CADENCE_UART_R_MAX), + VMSTATE_UINT8_ARRAY(rx_fifo, CadenceUARTState, + CADENCE_UART_RX_FIFO_SIZE), + VMSTATE_UINT8_ARRAY(tx_fifo, CadenceUARTState, + CADENCE_UART_TX_FIFO_SIZE), + VMSTATE_UINT32(rx_count, CadenceUARTState), + VMSTATE_UINT32(tx_count, CadenceUARTState), + VMSTATE_UINT32(rx_wpos, CadenceUARTState), + VMSTATE_TIMER_PTR(fifo_trigger_handle, CadenceUARTState), VMSTATE_END_OF_LIST() } }; @@ -544,7 +523,7 @@ static void cadence_uart_class_init(ObjectClass *klass, void *data) static const TypeInfo cadence_uart_info = { .name = TYPE_CADENCE_UART, .parent = TYPE_SYS_BUS_DEVICE, - .instance_size = sizeof(UartState), + .instance_size = sizeof(CadenceUARTState), .instance_init = cadence_uart_init, .class_init = cadence_uart_class_init, }; diff --git a/hw/net/cadence_gem.c b/hw/net/cadence_gem.c index 55b629387c..dafe91421b 100644 --- a/hw/net/cadence_gem.c +++ b/hw/net/cadence_gem.c @@ -24,8 +24,7 @@ #include /* For crc32 */ -#include "hw/sysbus.h" -#include "net/net.h" +#include "hw/net/cadence_gem.h" #include "net/checksum.h" #ifdef CADENCE_GEM_ERR_DEBUG @@ -141,8 +140,6 @@ #define GEM_DESCONF6 (0x00000294/4) #define GEM_DESCONF7 (0x00000298/4) -#define GEM_MAXREG (0x00000640/4) /* Last valid GEM address */ - /*****************************************/ #define GEM_NWCTRL_TXSTART 0x00000200 /* Transmit Enable */ #define GEM_NWCTRL_TXENA 0x00000008 /* Transmit Enable */ @@ -349,44 +346,6 @@ static inline void rx_desc_set_sar(unsigned *desc, int sar_idx) desc[1] |= R_DESC_1_RX_SAR_MATCH; } -#define TYPE_CADENCE_GEM "cadence_gem" -#define GEM(obj) OBJECT_CHECK(GemState, (obj), TYPE_CADENCE_GEM) - -typedef struct GemState { - SysBusDevice parent_obj; - - MemoryRegion iomem; - NICState *nic; - NICConf conf; - qemu_irq irq; - - /* GEM registers backing store */ - uint32_t regs[GEM_MAXREG]; - /* Mask of register bits which are write only */ - uint32_t regs_wo[GEM_MAXREG]; - /* Mask of register bits which are read only */ - uint32_t regs_ro[GEM_MAXREG]; - /* Mask of register bits which are clear on read */ - uint32_t regs_rtc[GEM_MAXREG]; - /* Mask of register bits which are write 1 to clear */ - uint32_t regs_w1c[GEM_MAXREG]; - - /* PHY registers backing store */ - uint16_t phy_regs[32]; - - uint8_t phy_loop; /* Are we in phy loopback? */ - - /* The current DMA descriptor pointers */ - uint32_t rx_desc_addr; - uint32_t tx_desc_addr; - - uint8_t can_rx_state; /* Debug only */ - - unsigned rx_desc[2]; - - bool sar_active[4]; -} GemState; - /* The broadcast MAC address: 0xFFFFFFFFFFFF */ static const uint8_t broadcast_addr[] = { 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF }; @@ -395,7 +354,7 @@ static const uint8_t broadcast_addr[] = { 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF }; * One time initialization. * Set masks to identify which register bits have magical clear properties */ -static void gem_init_register_masks(GemState *s) +static void gem_init_register_masks(CadenceGEMState *s) { /* Mask of register bits which are read only */ memset(&s->regs_ro[0], 0, sizeof(s->regs_ro)); @@ -430,7 +389,7 @@ static void gem_init_register_masks(GemState *s) * phy_update_link: * Make the emulated PHY link state match the QEMU "interface" state. */ -static void phy_update_link(GemState *s) +static void phy_update_link(CadenceGEMState *s) { DB_PRINT("down %d\n", qemu_get_queue(s->nic)->link_down); @@ -450,7 +409,7 @@ static void phy_update_link(GemState *s) static int gem_can_receive(NetClientState *nc) { - GemState *s; + CadenceGEMState *s; s = qemu_get_nic_opaque(nc); @@ -483,7 +442,7 @@ static int gem_can_receive(NetClientState *nc) * gem_update_int_status: * Raise or lower interrupt based on current status. */ -static void gem_update_int_status(GemState *s) +static void gem_update_int_status(CadenceGEMState *s) { if (s->regs[GEM_ISR]) { DB_PRINT("asserting int. (0x%08x)\n", s->regs[GEM_ISR]); @@ -495,7 +454,7 @@ static void gem_update_int_status(GemState *s) * gem_receive_updatestats: * Increment receive statistics. */ -static void gem_receive_updatestats(GemState *s, const uint8_t *packet, +static void gem_receive_updatestats(CadenceGEMState *s, const uint8_t *packet, unsigned bytes) { uint64_t octets; @@ -586,7 +545,7 @@ static unsigned calc_mac_hash(const uint8_t *mac) * GEM_RM_PROMISCUOUS_ACCEPT, GEM_RX_BROADCAST_ACCEPT, * GEM_RX_MULTICAST_HASH_ACCEPT or GEM_RX_UNICAST_HASH_ACCEPT */ -static int gem_mac_address_filter(GemState *s, const uint8_t *packet) +static int gem_mac_address_filter(CadenceGEMState *s, const uint8_t *packet) { uint8_t *gem_spaddr; int i; @@ -636,7 +595,7 @@ static int gem_mac_address_filter(GemState *s, const uint8_t *packet) return GEM_RX_REJECT; } -static void gem_get_rx_desc(GemState *s) +static void gem_get_rx_desc(CadenceGEMState *s) { DB_PRINT("read descriptor 0x%x\n", (unsigned)s->rx_desc_addr); /* read current descriptor */ @@ -660,7 +619,7 @@ static void gem_get_rx_desc(GemState *s) */ static ssize_t gem_receive(NetClientState *nc, const uint8_t *buf, size_t size) { - GemState *s; + CadenceGEMState *s; unsigned rxbufsize, bytes_to_copy; unsigned rxbuf_offset; uint8_t rxbuf[2048]; @@ -810,7 +769,7 @@ static ssize_t gem_receive(NetClientState *nc, const uint8_t *buf, size_t size) * gem_transmit_updatestats: * Increment transmit statistics. */ -static void gem_transmit_updatestats(GemState *s, const uint8_t *packet, +static void gem_transmit_updatestats(CadenceGEMState *s, const uint8_t *packet, unsigned bytes) { uint64_t octets; @@ -856,7 +815,7 @@ static void gem_transmit_updatestats(GemState *s, const uint8_t *packet, * gem_transmit: * Fish packets out of the descriptor ring and feed them to QEMU */ -static void gem_transmit(GemState *s) +static void gem_transmit(CadenceGEMState *s) { unsigned desc[2]; hwaddr packet_desc_addr; @@ -976,7 +935,7 @@ static void gem_transmit(GemState *s) } } -static void gem_phy_reset(GemState *s) +static void gem_phy_reset(CadenceGEMState *s) { memset(&s->phy_regs[0], 0, sizeof(s->phy_regs)); s->phy_regs[PHY_REG_CONTROL] = 0x1140; @@ -1004,7 +963,7 @@ static void gem_phy_reset(GemState *s) static void gem_reset(DeviceState *d) { int i; - GemState *s = GEM(d); + CadenceGEMState *s = CADENCE_GEM(d); DB_PRINT("\n"); @@ -1032,13 +991,13 @@ static void gem_reset(DeviceState *d) gem_update_int_status(s); } -static uint16_t gem_phy_read(GemState *s, unsigned reg_num) +static uint16_t gem_phy_read(CadenceGEMState *s, unsigned reg_num) { DB_PRINT("reg: %d value: 0x%04x\n", reg_num, s->phy_regs[reg_num]); return s->phy_regs[reg_num]; } -static void gem_phy_write(GemState *s, unsigned reg_num, uint16_t val) +static void gem_phy_write(CadenceGEMState *s, unsigned reg_num, uint16_t val) { DB_PRINT("reg: %d value: 0x%04x\n", reg_num, val); @@ -1072,10 +1031,10 @@ static void gem_phy_write(GemState *s, unsigned reg_num, uint16_t val) */ static uint64_t gem_read(void *opaque, hwaddr offset, unsigned size) { - GemState *s; + CadenceGEMState *s; uint32_t retval; - s = (GemState *)opaque; + s = (CadenceGEMState *)opaque; offset >>= 2; retval = s->regs[offset]; @@ -1120,7 +1079,7 @@ static uint64_t gem_read(void *opaque, hwaddr offset, unsigned size) static void gem_write(void *opaque, hwaddr offset, uint64_t val, unsigned size) { - GemState *s = (GemState *)opaque; + CadenceGEMState *s = (CadenceGEMState *)opaque; uint32_t readonly; DB_PRINT("offset: 0x%04x write: 0x%08x ", (unsigned)offset, (unsigned)val); @@ -1226,7 +1185,7 @@ static NetClientInfo net_gem_info = { static int gem_init(SysBusDevice *sbd) { DeviceState *dev = DEVICE(sbd); - GemState *s = GEM(dev); + CadenceGEMState *s = CADENCE_GEM(dev); DB_PRINT("\n"); @@ -1248,18 +1207,18 @@ static const VMStateDescription vmstate_cadence_gem = { .version_id = 2, .minimum_version_id = 2, .fields = (VMStateField[]) { - VMSTATE_UINT32_ARRAY(regs, GemState, GEM_MAXREG), - VMSTATE_UINT16_ARRAY(phy_regs, GemState, 32), - VMSTATE_UINT8(phy_loop, GemState), - VMSTATE_UINT32(rx_desc_addr, GemState), - VMSTATE_UINT32(tx_desc_addr, GemState), - VMSTATE_BOOL_ARRAY(sar_active, GemState, 4), + VMSTATE_UINT32_ARRAY(regs, CadenceGEMState, CADENCE_GEM_MAXREG), + VMSTATE_UINT16_ARRAY(phy_regs, CadenceGEMState, 32), + VMSTATE_UINT8(phy_loop, CadenceGEMState), + VMSTATE_UINT32(rx_desc_addr, CadenceGEMState), + VMSTATE_UINT32(tx_desc_addr, CadenceGEMState), + VMSTATE_BOOL_ARRAY(sar_active, CadenceGEMState, 4), VMSTATE_END_OF_LIST(), } }; static Property gem_properties[] = { - DEFINE_NIC_PROPERTIES(GemState, conf), + DEFINE_NIC_PROPERTIES(CadenceGEMState, conf), DEFINE_PROP_END_OF_LIST(), }; @@ -1277,7 +1236,7 @@ static void gem_class_init(ObjectClass *klass, void *data) static const TypeInfo gem_info = { .name = TYPE_CADENCE_GEM, .parent = TYPE_SYS_BUS_DEVICE, - .instance_size = sizeof(GemState), + .instance_size = sizeof(CadenceGEMState), .class_init = gem_class_init, }; diff --git a/include/hw/arm/xlnx-zynqmp.h b/include/hw/arm/xlnx-zynqmp.h new file mode 100644 index 0000000000..79c2b0b865 --- /dev/null +++ b/include/hw/arm/xlnx-zynqmp.h @@ -0,0 +1,58 @@ +/* + * Xilinx Zynq MPSoC emulation + * + * Copyright (C) 2015 Xilinx Inc + * Written by Peter Crosthwaite + * + * 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. + */ + +#ifndef XLNX_ZYNQMP_H + +#include "qemu-common.h" +#include "hw/arm/arm.h" +#include "hw/intc/arm_gic.h" +#include "hw/net/cadence_gem.h" +#include "hw/char/cadence_uart.h" + +#define TYPE_XLNX_ZYNQMP "xlnx,zynqmp" +#define XLNX_ZYNQMP(obj) OBJECT_CHECK(XlnxZynqMPState, (obj), \ + TYPE_XLNX_ZYNQMP) + +#define XLNX_ZYNQMP_NUM_CPUS 4 +#define XLNX_ZYNQMP_NUM_GEMS 4 +#define XLNX_ZYNQMP_NUM_UARTS 2 + +#define XLNX_ZYNQMP_GIC_REGIONS 2 + +/* ZynqMP maps the ARM GIC regions (GICC, GICD ...) at consecutive 64k offsets + * and under-decodes the 64k region. This mirrors the 4k regions to every 4k + * aligned address in the 64k region. To implement each GIC region needs a + * number of memory region aliases. + */ + +#define XLNX_ZYNQMP_GIC_REGION_SIZE 0x4000 +#define XLNX_ZYNQMP_GIC_ALIASES (0x10000 / XLNX_ZYNQMP_GIC_REGION_SIZE - 1) + +typedef struct XlnxZynqMPState { + /*< private >*/ + DeviceState parent_obj; + + /*< public >*/ + ARMCPU cpu[XLNX_ZYNQMP_NUM_CPUS]; + GICState gic; + MemoryRegion gic_mr[XLNX_ZYNQMP_GIC_REGIONS][XLNX_ZYNQMP_GIC_ALIASES]; + CadenceGEMState gem[XLNX_ZYNQMP_NUM_GEMS]; + CadenceUARTState uart[XLNX_ZYNQMP_NUM_UARTS]; +} XlnxZynqMPState; + +#define XLNX_ZYNQMP_H +#endif diff --git a/include/hw/char/cadence_uart.h b/include/hw/char/cadence_uart.h new file mode 100644 index 0000000000..6310f52512 --- /dev/null +++ b/include/hw/char/cadence_uart.h @@ -0,0 +1,53 @@ +/* + * Device model for Cadence UART + * + * Copyright (c) 2010 Xilinx Inc. + * Copyright (c) 2012 Peter A.G. Crosthwaite (peter.crosthwaite@petalogix.com) + * Copyright (c) 2012 PetaLogix Pty Ltd. + * Written by Haibing Ma + * M.Habib + * + * 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. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, see . + */ + +#ifndef CADENCE_UART_H + +#include "hw/sysbus.h" +#include "sysemu/char.h" +#include "qemu/timer.h" + +#define CADENCE_UART_RX_FIFO_SIZE 16 +#define CADENCE_UART_TX_FIFO_SIZE 16 + +#define CADENCE_UART_R_MAX (0x48/4) + +#define TYPE_CADENCE_UART "cadence_uart" +#define CADENCE_UART(obj) OBJECT_CHECK(CadenceUARTState, (obj), \ + TYPE_CADENCE_UART) + +typedef struct { + /*< private >*/ + SysBusDevice parent_obj; + + /*< public >*/ + MemoryRegion iomem; + uint32_t r[CADENCE_UART_R_MAX]; + uint8_t rx_fifo[CADENCE_UART_RX_FIFO_SIZE]; + uint8_t tx_fifo[CADENCE_UART_TX_FIFO_SIZE]; + uint32_t rx_wpos; + uint32_t rx_count; + uint32_t tx_count; + uint64_t char_tx_time; + CharDriverState *chr; + qemu_irq irq; + QEMUTimer *fifo_trigger_handle; +} CadenceUARTState; + +#define CADENCE_UART_H +#endif diff --git a/include/hw/net/cadence_gem.h b/include/hw/net/cadence_gem.h new file mode 100644 index 0000000000..f2e08e3575 --- /dev/null +++ b/include/hw/net/cadence_gem.h @@ -0,0 +1,73 @@ +/* + * QEMU Cadence GEM emulation + * + * Copyright (c) 2011 Xilinx, Inc. + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +#ifndef CADENCE_GEM_H + +#define TYPE_CADENCE_GEM "cadence_gem" +#define CADENCE_GEM(obj) OBJECT_CHECK(CadenceGEMState, (obj), TYPE_CADENCE_GEM) + +#include "net/net.h" +#include "hw/sysbus.h" + +#define CADENCE_GEM_MAXREG (0x00000640/4) /* Last valid GEM address */ + +typedef struct CadenceGEMState { + /*< private >*/ + SysBusDevice parent_obj; + + /*< public >*/ + MemoryRegion iomem; + NICState *nic; + NICConf conf; + qemu_irq irq; + + /* GEM registers backing store */ + uint32_t regs[CADENCE_GEM_MAXREG]; + /* Mask of register bits which are write only */ + uint32_t regs_wo[CADENCE_GEM_MAXREG]; + /* Mask of register bits which are read only */ + uint32_t regs_ro[CADENCE_GEM_MAXREG]; + /* Mask of register bits which are clear on read */ + uint32_t regs_rtc[CADENCE_GEM_MAXREG]; + /* Mask of register bits which are write 1 to clear */ + uint32_t regs_w1c[CADENCE_GEM_MAXREG]; + + /* PHY registers backing store */ + uint16_t phy_regs[32]; + + uint8_t phy_loop; /* Are we in phy loopback? */ + + /* The current DMA descriptor pointers */ + uint32_t rx_desc_addr; + uint32_t tx_desc_addr; + + uint8_t can_rx_state; /* Debug only */ + + unsigned rx_desc[2]; + + bool sar_active[4]; +} CadenceGEMState; + +#define CADENCE_GEM_H +#endif diff --git a/linux-user/arm/syscall_nr.h b/linux-user/arm/syscall_nr.h index 7d7be7cfe9..53552beabf 100644 --- a/linux-user/arm/syscall_nr.h +++ b/linux-user/arm/syscall_nr.h @@ -354,7 +354,7 @@ #define TARGET_NR_kexec_load (347) #define TARGET_NR_utimensat (348) #define TARGET_NR_signalfd (349) -#define TARGET_NR_timerfd (350) +#define TARGET_NR_timerfd_create (350) #define TARGET_NR_eventfd (351) #define TARGET_NR_fallocate (352) #define TARGET_NR_timerfd_settime (353) diff --git a/target-arm/cpu64.c b/target-arm/cpu64.c index 270bc2fec7..bf7dd685f8 100644 --- a/target-arm/cpu64.c +++ b/target-arm/cpu64.c @@ -38,22 +38,22 @@ static inline void unset_feature(CPUARMState *env, int feature) } #ifndef CONFIG_USER_ONLY -static uint64_t a57_l2ctlr_read(CPUARMState *env, const ARMCPRegInfo *ri) +static uint64_t a57_a53_l2ctlr_read(CPUARMState *env, const ARMCPRegInfo *ri) { /* Number of processors is in [25:24]; otherwise we RAZ */ return (smp_cpus - 1) << 24; } #endif -static const ARMCPRegInfo cortexa57_cp_reginfo[] = { +static const ARMCPRegInfo cortex_a57_a53_cp_reginfo[] = { #ifndef CONFIG_USER_ONLY { .name = "L2CTLR_EL1", .state = ARM_CP_STATE_AA64, .opc0 = 3, .opc1 = 1, .crn = 11, .crm = 0, .opc2 = 2, - .access = PL1_RW, .readfn = a57_l2ctlr_read, + .access = PL1_RW, .readfn = a57_a53_l2ctlr_read, .writefn = arm_cp_write_ignore }, { .name = "L2CTLR", .cp = 15, .opc1 = 1, .crn = 9, .crm = 0, .opc2 = 2, - .access = PL1_RW, .readfn = a57_l2ctlr_read, + .access = PL1_RW, .readfn = a57_a53_l2ctlr_read, .writefn = arm_cp_write_ignore }, #endif { .name = "L2ECTLR_EL1", .state = ARM_CP_STATE_AA64, @@ -140,7 +140,57 @@ static void aarch64_a57_initfn(Object *obj) cpu->ccsidr[1] = 0x201fe012; /* 48KB L1 icache */ cpu->ccsidr[2] = 0x70ffe07a; /* 2048KB L2 cache */ cpu->dcz_blocksize = 4; /* 64 bytes */ - define_arm_cp_regs(cpu, cortexa57_cp_reginfo); + define_arm_cp_regs(cpu, cortex_a57_a53_cp_reginfo); +} + +static void aarch64_a53_initfn(Object *obj) +{ + ARMCPU *cpu = ARM_CPU(obj); + + cpu->dtb_compatible = "arm,cortex-a53"; + set_feature(&cpu->env, ARM_FEATURE_V8); + set_feature(&cpu->env, ARM_FEATURE_VFP4); + set_feature(&cpu->env, ARM_FEATURE_NEON); + set_feature(&cpu->env, ARM_FEATURE_GENERIC_TIMER); + set_feature(&cpu->env, ARM_FEATURE_AARCH64); + set_feature(&cpu->env, ARM_FEATURE_CBAR_RO); + set_feature(&cpu->env, ARM_FEATURE_V8_AES); + set_feature(&cpu->env, ARM_FEATURE_V8_SHA1); + set_feature(&cpu->env, ARM_FEATURE_V8_SHA256); + set_feature(&cpu->env, ARM_FEATURE_V8_PMULL); + set_feature(&cpu->env, ARM_FEATURE_CRC); + cpu->midr = 0x410fd034; + cpu->reset_fpsid = 0x41034070; + cpu->mvfr0 = 0x10110222; + cpu->mvfr1 = 0x12111111; + cpu->mvfr2 = 0x00000043; + cpu->ctr = 0x84448004; /* L1Ip = VIPT */ + cpu->reset_sctlr = 0x00c50838; + cpu->id_pfr0 = 0x00000131; + cpu->id_pfr1 = 0x00011011; + cpu->id_dfr0 = 0x03010066; + cpu->id_afr0 = 0x00000000; + cpu->id_mmfr0 = 0x10101105; + cpu->id_mmfr1 = 0x40000000; + cpu->id_mmfr2 = 0x01260000; + cpu->id_mmfr3 = 0x02102211; + cpu->id_isar0 = 0x02101110; + cpu->id_isar1 = 0x13112111; + cpu->id_isar2 = 0x21232042; + cpu->id_isar3 = 0x01112131; + cpu->id_isar4 = 0x00011142; + cpu->id_isar5 = 0x00011121; + cpu->id_aa64pfr0 = 0x00002222; + cpu->id_aa64dfr0 = 0x10305106; + cpu->id_aa64isar0 = 0x00011120; + cpu->id_aa64mmfr0 = 0x00001122; /* 40 bit physical addr */ + cpu->dbgdidr = 0x3516d000; + cpu->clidr = 0x0a200023; + cpu->ccsidr[0] = 0x700fe01a; /* 32KB L1 dcache */ + cpu->ccsidr[1] = 0x201fe00a; /* 32KB L1 icache */ + cpu->ccsidr[2] = 0x707fe07a; /* 1024KB L2 cache */ + cpu->dcz_blocksize = 4; /* 64 bytes */ + define_arm_cp_regs(cpu, cortex_a57_a53_cp_reginfo); } #ifdef CONFIG_USER_ONLY @@ -170,6 +220,7 @@ typedef struct ARMCPUInfo { static const ARMCPUInfo aarch64_cpus[] = { { .name = "cortex-a57", .initfn = aarch64_a57_initfn }, + { .name = "cortex-a53", .initfn = aarch64_a53_initfn }, #ifdef CONFIG_USER_ONLY { .name = "any", .initfn = aarch64_any_initfn }, #endif diff --git a/target-arm/helper.c b/target-arm/helper.c index 2a68318cf5..5d0f01182a 100644 --- a/target-arm/helper.c +++ b/target-arm/helper.c @@ -1249,7 +1249,7 @@ static void gt_tval_write(CPUARMState *env, const ARMCPRegInfo *ri, int timeridx = ri->crm & 1; env->cp15.c14_timer[timeridx].cval = gt_get_countervalue(env) + - + sextract64(value, 0, 32); + sextract64(value, 0, 32); gt_recalc_timer(arm_env_get_cpu(env), timeridx); } @@ -1353,6 +1353,7 @@ static const ARMCPRegInfo generic_timer_cp_reginfo[] = { { .name = "CNTP_TVAL_EL0", .state = ARM_CP_STATE_AA64, .opc0 = 3, .opc1 = 3, .crn = 14, .crm = 2, .opc2 = 0, .type = ARM_CP_NO_RAW | ARM_CP_IO, .access = PL1_RW | PL0_R, + .accessfn = gt_ptimer_access, .readfn = gt_tval_read, .writefn = gt_tval_write, }, { .name = "CNTV_TVAL", .cp = 15, .crn = 14, .crm = 3, .opc1 = 0, .opc2 = 0, @@ -1363,6 +1364,7 @@ static const ARMCPRegInfo generic_timer_cp_reginfo[] = { { .name = "CNTV_TVAL_EL0", .state = ARM_CP_STATE_AA64, .opc0 = 3, .opc1 = 3, .crn = 14, .crm = 3, .opc2 = 0, .type = ARM_CP_NO_RAW | ARM_CP_IO, .access = PL1_RW | PL0_R, + .accessfn = gt_vtimer_access, .readfn = gt_tval_read, .writefn = gt_tval_write, }, /* The counter itself */ @@ -1401,7 +1403,7 @@ static const ARMCPRegInfo generic_timer_cp_reginfo[] = { .access = PL1_RW | PL0_R, .type = ARM_CP_IO, .fieldoffset = offsetof(CPUARMState, cp15.c14_timer[GTIMER_PHYS].cval), - .resetvalue = 0, .accessfn = gt_vtimer_access, + .resetvalue = 0, .accessfn = gt_ptimer_access, .writefn = gt_cval_write, .raw_writefn = raw_write, }, { .name = "CNTV_CVAL", .cp = 15, .crm = 14, .opc1 = 3, @@ -4913,6 +4915,21 @@ static inline TCR *regime_tcr(CPUARMState *env, ARMMMUIdx mmu_idx) return &env->cp15.tcr_el[regime_el(env, mmu_idx)]; } +/* Return the TTBR associated with this translation regime */ +static inline uint64_t regime_ttbr(CPUARMState *env, ARMMMUIdx mmu_idx, + int ttbrn) +{ + if (mmu_idx == ARMMMUIdx_S2NS) { + /* TODO: return VTTBR_EL2 */ + g_assert_not_reached(); + } + if (ttbrn == 0) { + return env->cp15.ttbr0_el[regime_el(env, mmu_idx)]; + } else { + return env->cp15.ttbr1_el[regime_el(env, mmu_idx)]; + } +} + /* Return true if the translation regime is using LPAE format page tables */ static inline bool regime_using_lpae_format(CPUARMState *env, ARMMMUIdx mmu_idx) @@ -5111,7 +5128,6 @@ static bool get_level1_table_address(CPUARMState *env, ARMMMUIdx mmu_idx, uint32_t *table, uint32_t address) { /* Note that we can only get here for an AArch32 PL0/PL1 lookup */ - int el = regime_el(env, mmu_idx); TCR *tcr = regime_tcr(env, mmu_idx); if (address & tcr->mask) { @@ -5119,13 +5135,13 @@ static bool get_level1_table_address(CPUARMState *env, ARMMMUIdx mmu_idx, /* Translation table walk disabled for TTBR1 */ return false; } - *table = env->cp15.ttbr1_el[el] & 0xffffc000; + *table = regime_ttbr(env, mmu_idx, 1) & 0xffffc000; } else { if (tcr->raw_tcr & TTBCR_PD0) { /* Translation table walk disabled for TTBR0 */ return false; } - *table = env->cp15.ttbr0_el[el] & tcr->base_mask; + *table = regime_ttbr(env, mmu_idx, 0) & tcr->base_mask; } *table |= (address >> 18) & 0x3ffc; return true; @@ -5431,21 +5447,34 @@ static int get_phys_addr_lpae(CPUARMState *env, target_ulong address, int32_t tbi = 0; TCR *tcr = regime_tcr(env, mmu_idx); int ap, ns, xn, pxn; + uint32_t el = regime_el(env, mmu_idx); + bool ttbr1_valid = true; /* TODO: - * This code assumes we're either a 64-bit EL1 or a 32-bit PL1; - * it doesn't handle the different format TCR for TCR_EL2, TCR_EL3, - * and VTCR_EL2, or the fact that those regimes don't have a split - * TTBR0/TTBR1. Attribute and permission bit handling should also - * be checked when adding support for those page table walks. + * This code does not handle the different format TCR for VTCR_EL2. + * This code also does not support shareability levels. + * Attribute and permission bit handling should also be checked when adding + * support for those page table walks. */ - if (arm_el_is_aa64(env, regime_el(env, mmu_idx))) { + if (arm_el_is_aa64(env, el)) { va_size = 64; - if (extract64(address, 55, 1)) - tbi = extract64(tcr->raw_tcr, 38, 1); - else - tbi = extract64(tcr->raw_tcr, 37, 1); + if (el > 1) { + tbi = extract64(tcr->raw_tcr, 20, 1); + } else { + if (extract64(address, 55, 1)) { + tbi = extract64(tcr->raw_tcr, 38, 1); + } else { + tbi = extract64(tcr->raw_tcr, 37, 1); + } + } tbi *= 8; + + /* If we are in 64-bit EL2 or EL3 then there is no TTBR1, so mark it + * invalid. + */ + if (el > 1) { + ttbr1_valid = false; + } } /* Determine whether this address is in the region controlled by @@ -5466,13 +5495,14 @@ static int get_phys_addr_lpae(CPUARMState *env, target_ulong address, if (t0sz && !extract64(address, va_size - t0sz, t0sz - tbi)) { /* there is a ttbr0 region and we are in it (high bits all zero) */ ttbr_select = 0; - } else if (t1sz && !extract64(~address, va_size - t1sz, t1sz - tbi)) { + } else if (ttbr1_valid && t1sz && + !extract64(~address, va_size - t1sz, t1sz - tbi)) { /* there is a ttbr1 region and we are in it (high bits all one) */ ttbr_select = 1; } else if (!t0sz) { /* ttbr0 region is "everything not in the ttbr1 region" */ ttbr_select = 0; - } else if (!t1sz) { + } else if (!t1sz && ttbr1_valid) { /* ttbr1 region is "everything not in the ttbr0 region" */ ttbr_select = 1; } else { @@ -5489,7 +5519,7 @@ static int get_phys_addr_lpae(CPUARMState *env, target_ulong address, * we will always flush the TLB any time the ASID is changed). */ if (ttbr_select == 0) { - ttbr = A32_BANKED_CURRENT_REG_GET(env, ttbr0); + ttbr = regime_ttbr(env, mmu_idx, 0); epd = extract32(tcr->raw_tcr, 7, 1); tsz = t0sz; @@ -5501,7 +5531,10 @@ static int get_phys_addr_lpae(CPUARMState *env, target_ulong address, granule_sz = 11; } } else { - ttbr = A32_BANKED_CURRENT_REG_GET(env, ttbr1); + /* We should only be here if TTBR1 is valid */ + assert(ttbr1_valid); + + ttbr = regime_ttbr(env, mmu_idx, 1); epd = extract32(tcr->raw_tcr, 23, 1); tsz = t1sz; @@ -5519,7 +5552,9 @@ static int get_phys_addr_lpae(CPUARMState *env, target_ulong address, */ if (epd) { - /* Translation table walk disabled => Translation fault on TLB miss */ + /* Translation table walk disabled => Translation fault on TLB miss + * Note: This is always 0 on 64-bit EL2 and EL3. + */ goto do_fault; } diff --git a/target-arm/internals.h b/target-arm/internals.h index 2cc301762c..de0a9c177d 100644 --- a/target-arm/internals.h +++ b/target-arm/internals.h @@ -347,6 +347,12 @@ static inline uint32_t syn_breakpoint(int same_el) | ARM_EL_IL | 0x22; } +static inline uint32_t syn_wfx(int cv, int cond, int ti) +{ + return (EC_WFX_TRAP << ARM_EL_EC_SHIFT) | + (cv << 24) | (cond << 20) | ti; +} + /* Update a QEMU watchpoint based on the information the guest has set in the * DBGWCR_EL1 and DBGWVR_EL1 registers. */