target-arm queue:

* more EL2 preparation patches
  * revert a no-longer-necessary workaround for old glib versions
  * add GICv2m support to virt board (MSI support)
  * pl061: fix wrong calculation of GPIOMIS register
  * support MSI via irqfd
  * remove a confusing v8_ prefix from some variable names
  * add dynamic sysbus device support to the virt board
 -----BEGIN PGP SIGNATURE-----
 Version: GnuPG v1
 
 iQIcBAABCAAGBQJVbdouAAoJEDwlJe0UNgzeQSYP/iXkogCzrNAqkcAGNzzVox5o
 54HFUMBFC05hnOBQxxUcGwXDetidYIEFuSt2uUooZapWYzL6ProIDXcgYMoVJTzL
 XaYUzuV3M3pxl8A7DtKRv39e9HTDL4EmT+dd8mNuRHfbhmvlFlWw3TzO/DHxl29e
 iOIrNDaLAPjI4QyFR0k5kHTmijTm13Sd5/Un/8m6bjKtrKst8k2HmqemtsjcrVUK
 +/9k+60+uTYJb4xKKcCY7w0zbbJGvlW9216bf3ccfAvGAbaGDxH+hRn0E1xd2BoR
 JmXofWYL55tT8cQxO7ZjCDMzhiJsQ/hFlo1ds5DkdcYuaYXUHiRB62mleSb2zc+T
 kcLFWCBQp/YWULpngZrnu5bzKUN0BwFtTOoMMv5WGR/N4hAcj6rgIIEaGeRsGrhV
 XrGeLmk25IwrIvn4Nwr0Ve70g6rdL5NauVYq21Bx2GLK18NEXXsUR1Z0X38WSVrN
 HXBNFHFECf0S1CNp8KVcyyfE+XZx2Cb5jFpS2jiy648KoXHgHYZUjCqJd4JzRAQB
 dEjoNKA6yod72UkgpoeaOTHsF9razOpqG+ymJzsVTiDBpg/eE6ZT/0jCBZ+92NqN
 qf2IUwubQH9jAFcxDuzoHDx+XCycdkYVEnoBGtBcS2QfaJd4dwfJkFAOOHR70XkH
 Kvj419eJjO0uhItsEODA
 =s7uF
 -----END PGP SIGNATURE-----

Merge remote-tracking branch 'remotes/pmaydell/tags/pull-target-arm-20150602' into staging

target-arm queue:
 * more EL2 preparation patches
 * revert a no-longer-necessary workaround for old glib versions
 * add GICv2m support to virt board (MSI support)
 * pl061: fix wrong calculation of GPIOMIS register
 * support MSI via irqfd
 * remove a confusing v8_ prefix from some variable names
 * add dynamic sysbus device support to the virt board

# gpg: Signature made Tue Jun  2 17:30:38 2015 BST using RSA key ID 14360CDE
# gpg: Good signature from "Peter Maydell <peter.maydell@linaro.org>"

* remotes/pmaydell/tags/pull-target-arm-20150602: (22 commits)
  hw/arm/virt: change indentation in a15memmap
  hw/arm/virt: add dynamic sysbus device support
  hw/arm/boot: arm_load_kernel implemented as a machine init done notifier
  hw/arm/sysbus-fdt: helpers for platform bus nodes addition
  target-arm: Remove v8_ prefix from names of non-v8-specific cpreg arrays
  arm_gicv2m: set kvm_gsi_direct_mapping and kvm_msi_via_irqfd_allowed
  kvm: introduce kvm_arch_msi_data_to_gsi
  pl061: fix wrong calculation of GPIOMIS register
  target-arm: Add the GICv2m to the virt board
  target-arm: Extend the gic node properties
  arm_gicv2m: Add GICv2m widget to support MSIs
  target-arm: Add GIC phandle to VirtBoardInfo
  Revert "target-arm: Avoid g_hash_table_get_keys()"
  target-arm: Add TLBI_VAE2{IS}
  target-arm: Add TLBI_ALLE2
  target-arm: Add TLBI_ALLE1{IS}
  target-arm: Add TTBR0_EL2
  target-arm: Add TPIDR_EL2
  target-arm: Add SCTLR_EL2
  target-arm: Add TCR_EL2
  ...

Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
This commit is contained in:
Peter Maydell 2015-06-04 10:21:52 +01:00
commit d2ceeb1d68
18 changed files with 723 additions and 61 deletions

View file

@ -5,6 +5,7 @@ obj-y += omap_sx1.o palm.o realview.o spitz.o stellaris.o
obj-y += tosa.o versatilepb.o vexpress.o virt.o xilinx_zynq.o z2.o
obj-$(CONFIG_ACPI) += virt-acpi-build.o
obj-y += netduino2.o
obj-y += sysbus-fdt.o
obj-y += armv7m.o exynos4210.o pxa2xx.o pxa2xx_gpio.o pxa2xx_pic.o
obj-$(CONFIG_DIGIC) += digic.o

View file

@ -557,7 +557,7 @@ static void load_image_to_fw_cfg(FWCfgState *fw_cfg, uint16_t size_key,
fw_cfg_add_bytes(fw_cfg, data_key, data, size);
}
void arm_load_kernel(ARMCPU *cpu, struct arm_boot_info *info)
static void arm_load_kernel_notify(Notifier *notifier, void *data)
{
CPUState *cs;
int kernel_size;
@ -568,6 +568,11 @@ void arm_load_kernel(ARMCPU *cpu, struct arm_boot_info *info)
hwaddr entry, kernel_load_offset;
int big_endian;
static const ARMInsnFixup *primary_loader;
ArmLoadKernelNotifier *n = DO_UPCAST(ArmLoadKernelNotifier,
notifier, notifier);
ARMCPU *cpu = n->cpu;
struct arm_boot_info *info =
container_of(n, struct arm_boot_info, load_kernel_notifier);
/* CPU objects (unlike devices) are not automatically reset on system
* reset, so we must always register a handler to do so. If we're
@ -775,3 +780,10 @@ void arm_load_kernel(ARMCPU *cpu, struct arm_boot_info *info)
ARM_CPU(cs)->env.boot_info = info;
}
}
void arm_load_kernel(ARMCPU *cpu, struct arm_boot_info *info)
{
info->load_kernel_notifier.cpu = cpu;
info->load_kernel_notifier.notifier.notify = arm_load_kernel_notify;
qemu_add_machine_init_done_notifier(&info->load_kernel_notifier.notifier);
}

174
hw/arm/sysbus-fdt.c Normal file
View file

@ -0,0 +1,174 @@
/*
* ARM Platform Bus device tree generation helpers
*
* Copyright (c) 2014 Linaro Limited
*
* Authors:
* Alex Graf <agraf@suse.de>
* Eric Auger <eric.auger@linaro.org>
*
* 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 <http://www.gnu.org/licenses/>.
*
*/
#include "hw/arm/sysbus-fdt.h"
#include "qemu/error-report.h"
#include "sysemu/device_tree.h"
#include "hw/platform-bus.h"
#include "sysemu/sysemu.h"
/*
* internal struct that contains the information to create dynamic
* sysbus device node
*/
typedef struct PlatformBusFDTData {
void *fdt; /* device tree handle */
int irq_start; /* index of the first IRQ usable by platform bus devices */
const char *pbus_node_name; /* name of the platform bus node */
PlatformBusDevice *pbus;
} PlatformBusFDTData;
/*
* struct used when calling the machine init done notifier
* that constructs the fdt nodes of platform bus devices
*/
typedef struct PlatformBusFDTNotifierParams {
Notifier notifier;
ARMPlatformBusFDTParams *fdt_params;
} PlatformBusFDTNotifierParams;
/* struct that associates a device type name and a node creation function */
typedef struct NodeCreationPair {
const char *typename;
int (*add_fdt_node_fn)(SysBusDevice *sbdev, void *opaque);
} NodeCreationPair;
/* list of supported dynamic sysbus devices */
static const NodeCreationPair add_fdt_node_functions[] = {
{"", NULL}, /* last element */
};
/**
* add_fdt_node - add the device tree node of a dynamic sysbus device
*
* @sbdev: handle to the sysbus device
* @opaque: handle to the PlatformBusFDTData
*
* Checks the sysbus type belongs to the list of device types that
* are dynamically instantiable and if so call the node creation
* function.
*/
static int add_fdt_node(SysBusDevice *sbdev, void *opaque)
{
int i, ret;
for (i = 0; i < ARRAY_SIZE(add_fdt_node_functions); i++) {
if (!strcmp(object_get_typename(OBJECT(sbdev)),
add_fdt_node_functions[i].typename)) {
ret = add_fdt_node_functions[i].add_fdt_node_fn(sbdev, opaque);
assert(!ret);
return 0;
}
}
error_report("Device %s can not be dynamically instantiated",
qdev_fw_name(DEVICE(sbdev)));
exit(1);
}
/**
* add_all_platform_bus_fdt_nodes - create all the platform bus nodes
*
* builds the parent platform bus node and all the nodes of dynamic
* sysbus devices attached to it.
*/
static void add_all_platform_bus_fdt_nodes(ARMPlatformBusFDTParams *fdt_params)
{
const char platcomp[] = "qemu,platform\0simple-bus";
PlatformBusDevice *pbus;
DeviceState *dev;
gchar *node;
uint64_t addr, size;
int irq_start, dtb_size;
struct arm_boot_info *info = fdt_params->binfo;
const ARMPlatformBusSystemParams *params = fdt_params->system_params;
const char *intc = fdt_params->intc;
void *fdt = info->get_dtb(info, &dtb_size);
/*
* If the user provided a dtb, we assume the dynamic sysbus nodes
* already are integrated there. This corresponds to a use case where
* the dynamic sysbus nodes are complex and their generation is not yet
* supported. In that case the user can take charge of the guest dt
* while qemu takes charge of the qom stuff.
*/
if (info->dtb_filename) {
return;
}
assert(fdt);
node = g_strdup_printf("/platform@%"PRIx64, params->platform_bus_base);
addr = params->platform_bus_base;
size = params->platform_bus_size;
irq_start = params->platform_bus_first_irq;
/* Create a /platform node that we can put all devices into */
qemu_fdt_add_subnode(fdt, node);
qemu_fdt_setprop(fdt, node, "compatible", platcomp, sizeof(platcomp));
/* Our platform bus region is less than 32bits, so 1 cell is enough for
* address and size
*/
qemu_fdt_setprop_cells(fdt, node, "#size-cells", 1);
qemu_fdt_setprop_cells(fdt, node, "#address-cells", 1);
qemu_fdt_setprop_cells(fdt, node, "ranges", 0, addr >> 32, addr, size);
qemu_fdt_setprop_phandle(fdt, node, "interrupt-parent", intc);
dev = qdev_find_recursive(sysbus_get_default(), TYPE_PLATFORM_BUS_DEVICE);
pbus = PLATFORM_BUS_DEVICE(dev);
/* We can only create dt nodes for dynamic devices when they're ready */
assert(pbus->done_gathering);
PlatformBusFDTData data = {
.fdt = fdt,
.irq_start = irq_start,
.pbus_node_name = node,
.pbus = pbus,
};
/* Loop through all dynamic sysbus devices and create their node */
foreach_dynamic_sysbus_device(add_fdt_node, &data);
g_free(node);
}
static void platform_bus_fdt_notify(Notifier *notifier, void *data)
{
PlatformBusFDTNotifierParams *p = DO_UPCAST(PlatformBusFDTNotifierParams,
notifier, notifier);
add_all_platform_bus_fdt_nodes(p->fdt_params);
g_free(p->fdt_params);
g_free(p);
}
void arm_register_platform_bus_fdt_creator(ARMPlatformBusFDTParams *fdt_params)
{
PlatformBusFDTNotifierParams *p = g_new(PlatformBusFDTNotifierParams, 1);
p->fdt_params = fdt_params;
p->notifier.notify = platform_bus_fdt_notify;
qemu_add_machine_init_done_notifier(&p->notifier);
}

View file

@ -45,9 +45,11 @@
#include "qemu/error-report.h"
#include "hw/pci-host/gpex.h"
#include "hw/arm/virt-acpi-build.h"
#include "hw/arm/sysbus-fdt.h"
#include "hw/platform-bus.h"
/* Number of external interrupt lines to configure the GIC with */
#define NUM_IRQS 128
#define NUM_IRQS 256
#define GIC_FDT_IRQ_TYPE_SPI 0
#define GIC_FDT_IRQ_TYPE_PPI 1
@ -60,6 +62,10 @@
#define GIC_FDT_IRQ_PPI_CPU_START 8
#define GIC_FDT_IRQ_PPI_CPU_WIDTH 8
#define PLATFORM_BUS_NUM_IRQS 64
static ARMPlatformBusSystemParams platform_bus_params;
typedef struct VirtBoardInfo {
struct arm_boot_info bootinfo;
const char *cpu_model;
@ -69,6 +75,8 @@ typedef struct VirtBoardInfo {
void *fdt;
int fdt_size;
uint32_t clock_phandle;
uint32_t gic_phandle;
uint32_t v2m_phandle;
} VirtBoardInfo;
typedef struct {
@ -103,20 +111,22 @@ typedef struct {
*/
static const MemMapEntry a15memmap[] = {
/* Space up to 0x8000000 is reserved for a boot ROM */
[VIRT_FLASH] = { 0, 0x08000000 },
[VIRT_CPUPERIPHS] = { 0x08000000, 0x00020000 },
[VIRT_FLASH] = { 0, 0x08000000 },
[VIRT_CPUPERIPHS] = { 0x08000000, 0x00020000 },
/* GIC distributor and CPU interfaces sit inside the CPU peripheral space */
[VIRT_GIC_DIST] = { 0x08000000, 0x00010000 },
[VIRT_GIC_CPU] = { 0x08010000, 0x00010000 },
[VIRT_UART] = { 0x09000000, 0x00001000 },
[VIRT_RTC] = { 0x09010000, 0x00001000 },
[VIRT_FW_CFG] = { 0x09020000, 0x0000000a },
[VIRT_MMIO] = { 0x0a000000, 0x00000200 },
[VIRT_GIC_DIST] = { 0x08000000, 0x00010000 },
[VIRT_GIC_CPU] = { 0x08010000, 0x00010000 },
[VIRT_GIC_V2M] = { 0x08020000, 0x00001000 },
[VIRT_UART] = { 0x09000000, 0x00001000 },
[VIRT_RTC] = { 0x09010000, 0x00001000 },
[VIRT_FW_CFG] = { 0x09020000, 0x0000000a },
[VIRT_MMIO] = { 0x0a000000, 0x00000200 },
/* ...repeating for a total of NUM_VIRTIO_TRANSPORTS, each of that size */
[VIRT_PCIE_MMIO] = { 0x10000000, 0x2eff0000 },
[VIRT_PCIE_PIO] = { 0x3eff0000, 0x00010000 },
[VIRT_PCIE_ECAM] = { 0x3f000000, 0x01000000 },
[VIRT_MEM] = { 0x40000000, 30ULL * 1024 * 1024 * 1024 },
[VIRT_PLATFORM_BUS] = { 0x0c000000, 0x02000000 },
[VIRT_PCIE_MMIO] = { 0x10000000, 0x2eff0000 },
[VIRT_PCIE_PIO] = { 0x3eff0000, 0x00010000 },
[VIRT_PCIE_ECAM] = { 0x3f000000, 0x01000000 },
[VIRT_MEM] = { 0x40000000, 30ULL * 1024 * 1024 * 1024 },
};
static const int a15irqmap[] = {
@ -124,6 +134,8 @@ static const int a15irqmap[] = {
[VIRT_RTC] = 2,
[VIRT_PCIE] = 3, /* ... to 6 */
[VIRT_MMIO] = 16, /* ...to 16 + NUM_VIRTIO_TRANSPORTS - 1 */
[VIRT_GIC_V2M] = 48, /* ...to 48 + NUM_GICV2M_SPIS - 1 */
[VIRT_PLATFORM_BUS] = 112, /* ...to 112 + PLATFORM_BUS_NUM_IRQS -1 */
};
static VirtBoardInfo machines[] = {
@ -299,12 +311,23 @@ static void fdt_add_cpu_nodes(const VirtBoardInfo *vbi)
}
}
static uint32_t fdt_add_gic_node(const VirtBoardInfo *vbi)
static void fdt_add_v2m_gic_node(VirtBoardInfo *vbi)
{
uint32_t gic_phandle;
vbi->v2m_phandle = qemu_fdt_alloc_phandle(vbi->fdt);
qemu_fdt_add_subnode(vbi->fdt, "/intc/v2m");
qemu_fdt_setprop_string(vbi->fdt, "/intc/v2m", "compatible",
"arm,gic-v2m-frame");
qemu_fdt_setprop(vbi->fdt, "/intc/v2m", "msi-controller", NULL, 0);
qemu_fdt_setprop_sized_cells(vbi->fdt, "/intc/v2m", "reg",
2, vbi->memmap[VIRT_GIC_V2M].base,
2, vbi->memmap[VIRT_GIC_V2M].size);
qemu_fdt_setprop_cell(vbi->fdt, "/intc/v2m", "phandle", vbi->v2m_phandle);
}
gic_phandle = qemu_fdt_alloc_phandle(vbi->fdt);
qemu_fdt_setprop_cell(vbi->fdt, "/", "interrupt-parent", gic_phandle);
static void fdt_add_gic_node(VirtBoardInfo *vbi)
{
vbi->gic_phandle = qemu_fdt_alloc_phandle(vbi->fdt);
qemu_fdt_setprop_cell(vbi->fdt, "/", "interrupt-parent", vbi->gic_phandle);
qemu_fdt_add_subnode(vbi->fdt, "/intc");
/* 'cortex-a15-gic' means 'GIC v2' */
@ -317,12 +340,32 @@ static uint32_t fdt_add_gic_node(const VirtBoardInfo *vbi)
2, vbi->memmap[VIRT_GIC_DIST].size,
2, vbi->memmap[VIRT_GIC_CPU].base,
2, vbi->memmap[VIRT_GIC_CPU].size);
qemu_fdt_setprop_cell(vbi->fdt, "/intc", "phandle", gic_phandle);
return gic_phandle;
qemu_fdt_setprop_cell(vbi->fdt, "/intc", "#address-cells", 0x2);
qemu_fdt_setprop_cell(vbi->fdt, "/intc", "#size-cells", 0x2);
qemu_fdt_setprop(vbi->fdt, "/intc", "ranges", NULL, 0);
qemu_fdt_setprop_cell(vbi->fdt, "/intc", "phandle", vbi->gic_phandle);
}
static uint32_t create_gic(const VirtBoardInfo *vbi, qemu_irq *pic)
static void create_v2m(VirtBoardInfo *vbi, qemu_irq *pic)
{
int i;
int irq = vbi->irqmap[VIRT_GIC_V2M];
DeviceState *dev;
dev = qdev_create(NULL, "arm-gicv2m");
sysbus_mmio_map(SYS_BUS_DEVICE(dev), 0, vbi->memmap[VIRT_GIC_V2M].base);
qdev_prop_set_uint32(dev, "base-spi", irq);
qdev_prop_set_uint32(dev, "num-spi", NUM_GICV2M_SPIS);
qdev_init_nofail(dev);
for (i = 0; i < NUM_GICV2M_SPIS; i++) {
sysbus_connect_irq(SYS_BUS_DEVICE(dev), i, pic[irq + i]);
}
fdt_add_v2m_gic_node(vbi);
}
static void create_gic(VirtBoardInfo *vbi, qemu_irq *pic)
{
/* We create a standalone GIC v2 */
DeviceState *gicdev;
@ -371,7 +414,9 @@ static uint32_t create_gic(const VirtBoardInfo *vbi, qemu_irq *pic)
pic[i] = qdev_get_gpio_in(gicdev, i);
}
return fdt_add_gic_node(vbi);
fdt_add_gic_node(vbi);
create_v2m(vbi, pic);
}
static void create_uart(const VirtBoardInfo *vbi, qemu_irq *pic)
@ -587,7 +632,7 @@ static void create_pcie_irq_map(const VirtBoardInfo *vbi, uint32_t gic_phandle,
int first_irq, const char *nodename)
{
int devfn, pin;
uint32_t full_irq_map[4 * 4 * 8] = { 0 };
uint32_t full_irq_map[4 * 4 * 10] = { 0 };
uint32_t *irq_map = full_irq_map;
for (devfn = 0; devfn <= 0x18; devfn += 0x8) {
@ -600,13 +645,13 @@ static void create_pcie_irq_map(const VirtBoardInfo *vbi, uint32_t gic_phandle,
uint32_t map[] = {
devfn << 8, 0, 0, /* devfn */
pin + 1, /* PCI pin */
gic_phandle, irq_type, irq_nr, irq_level }; /* GIC irq */
gic_phandle, 0, 0, irq_type, irq_nr, irq_level }; /* GIC irq */
/* Convert map to big endian */
for (i = 0; i < 8; i++) {
for (i = 0; i < 10; i++) {
irq_map[i] = cpu_to_be32(map[i]);
}
irq_map += 8;
irq_map += 10;
}
}
@ -618,8 +663,7 @@ static void create_pcie_irq_map(const VirtBoardInfo *vbi, uint32_t gic_phandle,
0x7 /* PCI irq */);
}
static void create_pcie(const VirtBoardInfo *vbi, qemu_irq *pic,
uint32_t gic_phandle)
static void create_pcie(const VirtBoardInfo *vbi, qemu_irq *pic)
{
hwaddr base_mmio = vbi->memmap[VIRT_PCIE_MMIO].base;
hwaddr size_mmio = vbi->memmap[VIRT_PCIE_MMIO].size;
@ -676,6 +720,8 @@ static void create_pcie(const VirtBoardInfo *vbi, qemu_irq *pic,
qemu_fdt_setprop_cells(vbi->fdt, nodename, "bus-range", 0,
nr_pcie_buses - 1);
qemu_fdt_setprop_cells(vbi->fdt, nodename, "msi-parent", vbi->v2m_phandle);
qemu_fdt_setprop_sized_cells(vbi->fdt, nodename, "reg",
2, base_ecam, 2, size_ecam);
qemu_fdt_setprop_sized_cells(vbi->fdt, nodename, "ranges",
@ -685,11 +731,52 @@ static void create_pcie(const VirtBoardInfo *vbi, qemu_irq *pic,
2, base_mmio, 2, size_mmio);
qemu_fdt_setprop_cell(vbi->fdt, nodename, "#interrupt-cells", 1);
create_pcie_irq_map(vbi, gic_phandle, irq, nodename);
create_pcie_irq_map(vbi, vbi->gic_phandle, irq, nodename);
g_free(nodename);
}
static void create_platform_bus(VirtBoardInfo *vbi, qemu_irq *pic)
{
DeviceState *dev;
SysBusDevice *s;
int i;
ARMPlatformBusFDTParams *fdt_params = g_new(ARMPlatformBusFDTParams, 1);
MemoryRegion *sysmem = get_system_memory();
platform_bus_params.platform_bus_base = vbi->memmap[VIRT_PLATFORM_BUS].base;
platform_bus_params.platform_bus_size = vbi->memmap[VIRT_PLATFORM_BUS].size;
platform_bus_params.platform_bus_first_irq = vbi->irqmap[VIRT_PLATFORM_BUS];
platform_bus_params.platform_bus_num_irqs = PLATFORM_BUS_NUM_IRQS;
fdt_params->system_params = &platform_bus_params;
fdt_params->binfo = &vbi->bootinfo;
fdt_params->intc = "/intc";
/*
* register a machine init done notifier that creates the device tree
* nodes of the platform bus and its children dynamic sysbus devices
*/
arm_register_platform_bus_fdt_creator(fdt_params);
dev = qdev_create(NULL, TYPE_PLATFORM_BUS_DEVICE);
dev->id = TYPE_PLATFORM_BUS_DEVICE;
qdev_prop_set_uint32(dev, "num_irqs",
platform_bus_params.platform_bus_num_irqs);
qdev_prop_set_uint32(dev, "mmio_size",
platform_bus_params.platform_bus_size);
qdev_init_nofail(dev);
s = SYS_BUS_DEVICE(dev);
for (i = 0; i < platform_bus_params.platform_bus_num_irqs; i++) {
int irqn = platform_bus_params.platform_bus_first_irq + i;
sysbus_connect_irq(s, i, pic[irqn]);
}
memory_region_add_subregion(sysmem,
platform_bus_params.platform_bus_base,
sysbus_mmio_get_region(s, 0));
}
static void *machvirt_dtb(const struct arm_boot_info *binfo, int *fdt_size)
{
const VirtBoardInfo *board = (const VirtBoardInfo *)binfo;
@ -717,7 +804,6 @@ static void machvirt_init(MachineState *machine)
VirtBoardInfo *vbi;
VirtGuestInfoState *guest_info_state = g_malloc0(sizeof *guest_info_state);
VirtGuestInfo *guest_info = &guest_info_state->info;
uint32_t gic_phandle;
char **cpustr;
if (!cpu_model) {
@ -794,13 +880,13 @@ static void machvirt_init(MachineState *machine)
create_flash(vbi);
gic_phandle = create_gic(vbi, pic);
create_gic(vbi, pic);
create_uart(vbi, pic);
create_rtc(vbi, pic);
create_pcie(vbi, pic, gic_phandle);
create_pcie(vbi, pic);
/* Create mmio transports, so the user can create virtio backends
* (which will be automatically plugged in to the transports). If
@ -828,6 +914,14 @@ static void machvirt_init(MachineState *machine)
vbi->bootinfo.get_dtb = machvirt_dtb;
vbi->bootinfo.firmware_loaded = bios_name || drive_get(IF_PFLASH, 0, 0);
arm_load_kernel(ARM_CPU(first_cpu), &vbi->bootinfo);
/*
* arm_load_kernel machine init done notifier registration must
* happen before the platform_bus_create call. In this latter,
* another notifier is registered which adds platform bus nodes.
* Notifiers are executed in registration reverse order.
*/
create_platform_bus(vbi, pic);
}
static bool virt_get_secure(Object *obj, Error **errp)
@ -866,6 +960,7 @@ static void virt_class_init(ObjectClass *oc, void *data)
mc->desc = "ARM Virtual Machine",
mc->init = machvirt_init;
mc->max_cpus = 8;
mc->has_dynamic_sysbus = true;
}
static const TypeInfo machvirt_info = {

View file

@ -173,7 +173,7 @@ static uint64_t pl061_read(void *opaque, hwaddr offset,
case 0x414: /* Raw interrupt status */
return s->istate;
case 0x418: /* Masked interrupt status */
return s->istate | s->im;
return s->istate & s->im;
case 0x420: /* Alternate function select */
return s->afsel;
case 0x500: /* 2mA drive */

View file

@ -11,6 +11,7 @@ common-obj-$(CONFIG_SLAVIO) += slavio_intctl.o
common-obj-$(CONFIG_IOAPIC) += ioapic_common.o
common-obj-$(CONFIG_ARM_GIC) += arm_gic_common.o
common-obj-$(CONFIG_ARM_GIC) += arm_gic.o
common-obj-$(CONFIG_ARM_GIC) += arm_gicv2m.o
common-obj-$(CONFIG_OPENPIC) += openpic.o
obj-$(CONFIG_APIC) += apic.o apic_common.o

192
hw/intc/arm_gicv2m.c Normal file
View file

@ -0,0 +1,192 @@
/*
* GICv2m extension for MSI/MSI-x support with a GICv2-based system
*
* Copyright (C) 2015 Linaro, All rights reserved.
*
* Author: Christoffer Dall <christoffer.dall@linaro.org>
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2 of the License, or (at your option) any later version.
*
* This library 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
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, see <http://www.gnu.org/licenses/>.
*/
/* This file implements an emulated GICv2m widget as described in the ARM
* Server Base System Architecture (SBSA) specification Version 2.2
* (ARM-DEN-0029 v2.2) pages 35-39 without any optional implementation defined
* identification registers and with a single non-secure MSI register frame.
*/
#include "hw/sysbus.h"
#include "hw/pci/msi.h"
#define TYPE_ARM_GICV2M "arm-gicv2m"
#define ARM_GICV2M(obj) OBJECT_CHECK(ARMGICv2mState, (obj), TYPE_ARM_GICV2M)
#define GICV2M_NUM_SPI_MAX 128
#define V2M_MSI_TYPER 0x008
#define V2M_MSI_SETSPI_NS 0x040
#define V2M_MSI_IIDR 0xFCC
#define V2M_IIDR0 0xFD0
#define V2M_IIDR11 0xFFC
#define PRODUCT_ID_QEMU 0x51 /* ASCII code Q */
typedef struct ARMGICv2mState {
SysBusDevice parent_obj;
MemoryRegion iomem;
qemu_irq spi[GICV2M_NUM_SPI_MAX];
uint32_t base_spi;
uint32_t num_spi;
} ARMGICv2mState;
static void gicv2m_set_irq(void *opaque, int irq)
{
ARMGICv2mState *s = (ARMGICv2mState *)opaque;
qemu_irq_pulse(s->spi[irq]);
}
static uint64_t gicv2m_read(void *opaque, hwaddr offset,
unsigned size)
{
ARMGICv2mState *s = (ARMGICv2mState *)opaque;
uint32_t val;
if (size != 4) {
qemu_log_mask(LOG_GUEST_ERROR, "gicv2m_read: bad size %u\n", size);
return 0;
}
switch (offset) {
case V2M_MSI_TYPER:
val = (s->base_spi + 32) << 16;
val |= s->num_spi;
return val;
case V2M_MSI_IIDR:
/* We don't have any valid implementor so we leave that field as zero
* and we return 0 in the arch revision as per the spec.
*/
return (PRODUCT_ID_QEMU << 20);
case V2M_IIDR0 ... V2M_IIDR11:
/* We do not implement any optional identification registers and the
* mandatory MSI_PIDR2 register reads as 0x0, so we capture all
* implementation defined registers here.
*/
return 0;
default:
qemu_log_mask(LOG_GUEST_ERROR,
"gicv2m_read: Bad offset %x\n", (int)offset);
return 0;
}
}
static void gicv2m_write(void *opaque, hwaddr offset,
uint64_t value, unsigned size)
{
ARMGICv2mState *s = (ARMGICv2mState *)opaque;
if (size != 2 && size != 4) {
qemu_log_mask(LOG_GUEST_ERROR, "gicv2m_write: bad size %u\n", size);
return;
}
switch (offset) {
case V2M_MSI_SETSPI_NS: {
int spi;
spi = (value & 0x3ff) - (s->base_spi + 32);
if (spi >= 0 && spi < s->num_spi) {
gicv2m_set_irq(s, spi);
}
return;
}
default:
qemu_log_mask(LOG_GUEST_ERROR,
"gicv2m_write: Bad offset %x\n", (int)offset);
}
}
static const MemoryRegionOps gicv2m_ops = {
.read = gicv2m_read,
.write = gicv2m_write,
.endianness = DEVICE_LITTLE_ENDIAN,
};
static void gicv2m_realize(DeviceState *dev, Error **errp)
{
ARMGICv2mState *s = ARM_GICV2M(dev);
int i;
if (s->num_spi > GICV2M_NUM_SPI_MAX) {
error_setg(errp,
"requested %u SPIs exceeds GICv2m frame maximum %d",
s->num_spi, GICV2M_NUM_SPI_MAX);
return;
}
if (s->base_spi + 32 > 1020 - s->num_spi) {
error_setg(errp,
"requested base SPI %u+%u exceeds max. number 1020",
s->base_spi + 32, s->num_spi);
return;
}
for (i = 0; i < s->num_spi; i++) {
sysbus_init_irq(SYS_BUS_DEVICE(dev), &s->spi[i]);
}
msi_supported = true;
kvm_gsi_direct_mapping = true;
kvm_msi_via_irqfd_allowed = kvm_irqfds_enabled();
}
static void gicv2m_init(Object *obj)
{
SysBusDevice *sbd = SYS_BUS_DEVICE(obj);
ARMGICv2mState *s = ARM_GICV2M(obj);
memory_region_init_io(&s->iomem, OBJECT(s), &gicv2m_ops, s,
"gicv2m", 0x1000);
sysbus_init_mmio(sbd, &s->iomem);
}
static Property gicv2m_properties[] = {
DEFINE_PROP_UINT32("base-spi", ARMGICv2mState, base_spi, 0),
DEFINE_PROP_UINT32("num-spi", ARMGICv2mState, num_spi, 64),
DEFINE_PROP_END_OF_LIST(),
};
static void gicv2m_class_init(ObjectClass *klass, void *data)
{
DeviceClass *dc = DEVICE_CLASS(klass);
dc->props = gicv2m_properties;
dc->realize = gicv2m_realize;
}
static const TypeInfo gicv2m_info = {
.name = TYPE_ARM_GICV2M,
.parent = TYPE_SYS_BUS_DEVICE,
.instance_size = sizeof(ARMGICv2mState),
.instance_init = gicv2m_init,
.class_init = gicv2m_class_init,
};
static void gicv2m_register_types(void)
{
type_register_static(&gicv2m_info);
}
type_init(gicv2m_register_types)

View file

@ -13,11 +13,21 @@
#include "exec/memory.h"
#include "hw/irq.h"
#include "qemu/notify.h"
/* armv7m.c */
qemu_irq *armv7m_init(MemoryRegion *system_memory, int mem_size, int num_irq,
const char *kernel_filename, const char *cpu_model);
/*
* struct used as a parameter of the arm_load_kernel machine init
* done notifier
*/
typedef struct {
Notifier notifier; /* actual notifier */
ARMCPU *cpu; /* handle to the first cpu object */
} ArmLoadKernelNotifier;
/* arm_boot.c */
struct arm_boot_info {
uint64_t ram_size;
@ -64,6 +74,8 @@ struct arm_boot_info {
* the user it should implement this hook.
*/
void (*modify_dtb)(const struct arm_boot_info *info, void *fdt);
/* machine init done notifier executing arm_load_dtb */
ArmLoadKernelNotifier load_kernel_notifier;
/* Used internally by arm_boot.c */
int is_linux;
hwaddr initrd_start;
@ -75,6 +87,22 @@ struct arm_boot_info {
*/
bool firmware_loaded;
};
/**
* arm_load_kernel - Loads memory with everything needed to boot
*
* @cpu: handle to the first CPU object
* @info: handle to the boot info struct
* Registers a machine init done notifier that copies to memory
* everything needed to boot, depending on machine and user options:
* kernel image, boot loaders, initrd, dtb. Also registers the CPU
* reset handler.
*
* In case the machine file supports the platform bus device and its
* dynamically instantiable sysbus devices, this function must be called
* before sysbus-fdt arm_register_platform_bus_fdt_creator. Indeed the
* machine init done notifiers are called in registration reverse order.
*/
void arm_load_kernel(ARMCPU *cpu, struct arm_boot_info *info);
/* Multiplication factor to convert from system clock ticks to qemu timer

View file

@ -0,0 +1,60 @@
/*
* Dynamic sysbus device tree node generation API
*
* Copyright Linaro Limited, 2014
*
* Authors:
* Alex Graf <agraf@suse.de>
* Eric Auger <eric.auger@linaro.org>
*
* 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 <http://www.gnu.org/licenses/>.
*
*/
#ifndef HW_ARM_SYSBUS_FDT_H
#define HW_ARM_SYSBUS_FDT_H
#include "hw/arm/arm.h"
#include "qemu-common.h"
#include "hw/sysbus.h"
/*
* struct that contains dimensioning parameters of the platform bus
*/
typedef struct {
hwaddr platform_bus_base; /* start address of the bus */
hwaddr platform_bus_size; /* size of the bus */
int platform_bus_first_irq; /* first hwirq assigned to the bus */
int platform_bus_num_irqs; /* number of hwirq assigned to the bus */
} ARMPlatformBusSystemParams;
/*
* struct that contains all relevant info to build the fdt nodes of
* platform bus and attached dynamic sysbus devices
* in the future might be augmented with additional info
* such as PHY, CLK handles ...
*/
typedef struct {
const ARMPlatformBusSystemParams *system_params;
struct arm_boot_info *binfo;
const char *intc; /* parent interrupt controller name */
} ARMPlatformBusFDTParams;
/**
* arm_register_platform_bus_fdt_creator - register a machine init done
* notifier that creates the device tree nodes of the platform bus and
* associated dynamic sysbus devices
*/
void arm_register_platform_bus_fdt_creator(ARMPlatformBusFDTParams *fdt_params);
#endif

View file

@ -32,6 +32,7 @@
#include "qemu-common.h"
#define NUM_GICV2M_SPIS 64
#define NUM_VIRTIO_TRANSPORTS 32
#define ARCH_TIMER_VIRT_IRQ 11
@ -53,6 +54,8 @@ enum {
VIRT_PCIE_MMIO,
VIRT_PCIE_PIO,
VIRT_PCIE_ECAM,
VIRT_GIC_V2M,
VIRT_PLATFORM_BUS,
};
typedef struct MemMapEntry {

View file

@ -287,6 +287,8 @@ void kvm_arch_init_irq_routing(KVMState *s);
int kvm_arch_fixup_msi_route(struct kvm_irq_routing_entry *route,
uint64_t address, uint32_t data);
int kvm_arch_msi_data_to_gsi(uint32_t data);
int kvm_set_irq(KVMState *s, int irq, int level);
int kvm_irqchip_send_msi(KVMState *s, MSIMessage msg);

View file

@ -1228,7 +1228,7 @@ int kvm_irqchip_add_msi_route(KVMState *s, MSIMessage msg)
int virq;
if (kvm_gsi_direct_mapping()) {
return msg.data & 0xffff;
return kvm_arch_msi_data_to_gsi(msg.data);
}
if (!kvm_gsi_routing_enabled()) {

View file

@ -294,23 +294,15 @@ static gint cpreg_key_compare(gconstpointer a, gconstpointer b)
return 0;
}
static void cpreg_make_keylist(gpointer key, gpointer value, gpointer udata)
{
GList **plist = udata;
*plist = g_list_prepend(*plist, key);
}
void init_cpreg_list(ARMCPU *cpu)
{
/* Initialise the cpreg_tuples[] array based on the cp_regs hash.
* Note that we require cpreg_tuples[] to be sorted by key ID.
*/
GList *keys = NULL;
GList *keys;
int arraylen;
g_hash_table_foreach(cpu->cp_regs, cpreg_make_keylist, &keys);
keys = g_hash_table_get_keys(cpu->cp_regs);
keys = g_list_sort(keys, cpreg_key_compare);
cpu->cpreg_array_len = 0;
@ -492,10 +484,16 @@ static const ARMCPRegInfo not_v8_cp_reginfo[] = {
.writefn = dacr_write, .raw_writefn = raw_write,
.bank_fieldoffsets = { offsetoflow32(CPUARMState, cp15.dacr_s),
offsetoflow32(CPUARMState, cp15.dacr_ns) } },
/* ??? This covers not just the impdef TLB lockdown registers but also
* some v7VMSA registers relating to TEX remap, so it is overly broad.
/* ARMv7 allocates a range of implementation defined TLB LOCKDOWN regs.
* For v6 and v5, these mappings are overly broad.
*/
{ .name = "TLB_LOCKDOWN", .cp = 15, .crn = 10, .crm = CP_ANY,
{ .name = "TLB_LOCKDOWN", .cp = 15, .crn = 10, .crm = 0,
.opc1 = CP_ANY, .opc2 = CP_ANY, .access = PL1_RW, .type = ARM_CP_NOP },
{ .name = "TLB_LOCKDOWN", .cp = 15, .crn = 10, .crm = 1,
.opc1 = CP_ANY, .opc2 = CP_ANY, .access = PL1_RW, .type = ARM_CP_NOP },
{ .name = "TLB_LOCKDOWN", .cp = 15, .crn = 10, .crm = 4,
.opc1 = CP_ANY, .opc2 = CP_ANY, .access = PL1_RW, .type = ARM_CP_NOP },
{ .name = "TLB_LOCKDOWN", .cp = 15, .crn = 10, .crm = 8,
.opc1 = CP_ANY, .opc2 = CP_ANY, .access = PL1_RW, .type = ARM_CP_NOP },
/* Cache maintenance ops; some of this space may be overridden later. */
{ .name = "CACHEMAINT", .cp = 15, .crn = 7, .crm = CP_ANY,
@ -555,6 +553,10 @@ static const ARMCPRegInfo not_v7_cp_reginfo[] = {
{ .name = "TLBIMVAA", .cp = 15, .crn = 8, .crm = CP_ANY,
.opc1 = CP_ANY, .opc2 = 3, .access = PL1_W, .writefn = tlbimvaa_write,
.type = ARM_CP_NO_RAW },
{ .name = "PRRR", .cp = 15, .crn = 10, .crm = 2,
.opc1 = 0, .opc2 = 0, .access = PL1_RW, .type = ARM_CP_NOP },
{ .name = "NMRR", .cp = 15, .crn = 10, .crm = 2,
.opc1 = 0, .opc2 = 1, .access = PL1_RW, .type = ARM_CP_NOP },
REGINFO_SENTINEL
};
@ -1021,19 +1023,17 @@ static const ARMCPRegInfo v7_cp_reginfo[] = {
.resetvalue = 0 },
/* For non-long-descriptor page tables these are PRRR and NMRR;
* regardless they still act as reads-as-written for QEMU.
* The override is necessary because of the overly-broad TLB_LOCKDOWN
* definition.
*/
/* MAIR0/1 are defined separately from their 64-bit counterpart which
* allows them to assign the correct fieldoffset based on the endianness
* handled in the field definitions.
*/
{ .name = "MAIR0", .state = ARM_CP_STATE_AA32, .type = ARM_CP_OVERRIDE,
{ .name = "MAIR0", .state = ARM_CP_STATE_AA32,
.cp = 15, .opc1 = 0, .crn = 10, .crm = 2, .opc2 = 0, .access = PL1_RW,
.bank_fieldoffsets = { offsetof(CPUARMState, cp15.mair0_s),
offsetof(CPUARMState, cp15.mair0_ns) },
.resetfn = arm_cp_reset_ignore },
{ .name = "MAIR1", .state = ARM_CP_STATE_AA32, .type = ARM_CP_OVERRIDE,
{ .name = "MAIR1", .state = ARM_CP_STATE_AA32,
.cp = 15, .opc1 = 0, .crn = 10, .crm = 2, .opc2 = 1, .access = PL1_RW,
.bank_fieldoffsets = { offsetof(CPUARMState, cp15.mair1_s),
offsetof(CPUARMState, cp15.mair1_ns) },
@ -2088,16 +2088,14 @@ static const ARMCPRegInfo mpidr_cp_reginfo[] = {
};
static const ARMCPRegInfo lpae_cp_reginfo[] = {
/* NOP AMAIR0/1: the override is because these clash with the rather
* broadly specified TLB_LOCKDOWN entry in the generic cp_reginfo.
*/
/* NOP AMAIR0/1 */
{ .name = "AMAIR0", .state = ARM_CP_STATE_BOTH,
.opc0 = 3, .crn = 10, .crm = 3, .opc1 = 0, .opc2 = 0,
.access = PL1_RW, .type = ARM_CP_CONST | ARM_CP_OVERRIDE,
.access = PL1_RW, .type = ARM_CP_CONST,
.resetvalue = 0 },
/* AMAIR1 is mapped to AMAIR_EL1[63:32] */
{ .name = "AMAIR1", .cp = 15, .crn = 10, .crm = 3, .opc1 = 0, .opc2 = 1,
.access = PL1_RW, .type = ARM_CP_CONST | ARM_CP_OVERRIDE,
.access = PL1_RW, .type = ARM_CP_CONST,
.resetvalue = 0 },
{ .name = "PAR", .cp = 15, .crm = 7, .opc1 = 0,
.access = PL1_RW, .type = ARM_CP_64BIT, .resetvalue = 0,
@ -2362,6 +2360,14 @@ static const ARMCPRegInfo v8_cp_reginfo[] = {
.opc0 = 1, .opc1 = 0, .crn = 7, .crm = 14, .opc2 = 2,
.access = PL1_W, .type = ARM_CP_NOP },
/* TLBI operations */
{ .name = "TLBI_ALLE1", .state = ARM_CP_STATE_AA64,
.opc0 = 1, .opc1 = 4, .crn = 8, .crm = 7, .opc2 = 4,
.access = PL2_W, .type = ARM_CP_NO_RAW,
.writefn = tlbiall_write },
{ .name = "TLBI_ALLE1IS", .state = ARM_CP_STATE_AA64,
.opc0 = 1, .opc1 = 4, .crn = 8, .crm = 3, .opc2 = 4,
.access = PL2_W, .type = ARM_CP_NO_RAW,
.writefn = tlbiall_write },
{ .name = "TLBI_VMALLE1IS", .state = ARM_CP_STATE_AA64,
.opc0 = 1, .opc1 = 0, .crn = 8, .crm = 3, .opc2 = 0,
.access = PL1_W, .type = ARM_CP_NO_RAW,
@ -2498,7 +2504,7 @@ static const ARMCPRegInfo v8_cp_reginfo[] = {
};
/* Used to describe the behaviour of EL2 regs when EL2 does not exist. */
static const ARMCPRegInfo v8_el3_no_el2_cp_reginfo[] = {
static const ARMCPRegInfo el3_no_el2_cp_reginfo[] = {
{ .name = "VBAR_EL2", .state = ARM_CP_STATE_AA64,
.opc0 = 3, .opc1 = 4, .crn = 12, .crm = 0, .opc2 = 0,
.access = PL2_RW,
@ -2511,6 +2517,28 @@ static const ARMCPRegInfo v8_el3_no_el2_cp_reginfo[] = {
{ .name = "CPTR_EL2", .state = ARM_CP_STATE_BOTH,
.opc0 = 3, .opc1 = 4, .crn = 1, .crm = 1, .opc2 = 2,
.access = PL2_RW, .type = ARM_CP_CONST, .resetvalue = 0 },
{ .name = "MAIR_EL2", .state = ARM_CP_STATE_BOTH,
.opc0 = 3, .opc1 = 4, .crn = 10, .crm = 2, .opc2 = 0,
.access = PL2_RW, .type = ARM_CP_CONST,
.resetvalue = 0 },
{ .name = "HMAIR1", .state = ARM_CP_STATE_AA32,
.opc1 = 4, .crn = 10, .crm = 2, .opc2 = 1,
.access = PL2_RW, .type = ARM_CP_CONST, .resetvalue = 0 },
{ .name = "TCR_EL2", .state = ARM_CP_STATE_BOTH,
.opc0 = 3, .opc1 = 4, .crn = 2, .crm = 0, .opc2 = 2,
.access = PL2_RW, .type = ARM_CP_CONST, .resetvalue = 0 },
{ .name = "SCTLR_EL2", .state = ARM_CP_STATE_BOTH,
.opc0 = 3, .opc1 = 4, .crn = 1, .crm = 0, .opc2 = 0,
.access = PL2_RW, .type = ARM_CP_CONST, .resetvalue = 0 },
{ .name = "TPIDR_EL2", .state = ARM_CP_STATE_BOTH,
.opc0 = 3, .opc1 = 4, .crn = 13, .crm = 0, .opc2 = 2,
.access = PL2_RW, .type = ARM_CP_CONST, .resetvalue = 0 },
{ .name = "TTBR0_EL2", .state = ARM_CP_STATE_AA64,
.opc0 = 3, .opc1 = 4, .crn = 2, .crm = 0, .opc2 = 0,
.access = PL2_RW, .type = ARM_CP_CONST, .resetvalue = 0 },
{ .name = "HTTBR", .cp = 15, .opc1 = 4, .crm = 2,
.access = PL2_RW, .type = ARM_CP_64BIT | ARM_CP_CONST,
.resetvalue = 0 },
REGINFO_SENTINEL
};
@ -2539,7 +2567,7 @@ static void hcr_write(CPUARMState *env, const ARMCPRegInfo *ri, uint64_t value)
raw_write(env, ri, value);
}
static const ARMCPRegInfo v8_el2_cp_reginfo[] = {
static const ARMCPRegInfo el2_cp_reginfo[] = {
{ .name = "HCR_EL2", .state = ARM_CP_STATE_AA64,
.opc0 = 3, .opc1 = 4, .crn = 1, .crm = 1, .opc2 = 0,
.access = PL2_RW, .fieldoffset = offsetof(CPUARMState, cp15.hcr_el2),
@ -2582,6 +2610,47 @@ static const ARMCPRegInfo v8_el2_cp_reginfo[] = {
.opc0 = 3, .opc1 = 4, .crn = 1, .crm = 1, .opc2 = 2,
.access = PL2_RW, .accessfn = cptr_access, .resetvalue = 0,
.fieldoffset = offsetof(CPUARMState, cp15.cptr_el[2]) },
{ .name = "MAIR_EL2", .state = ARM_CP_STATE_BOTH,
.opc0 = 3, .opc1 = 4, .crn = 10, .crm = 2, .opc2 = 0,
.access = PL2_RW, .fieldoffset = offsetof(CPUARMState, cp15.mair_el[2]),
.resetvalue = 0 },
{ .name = "HMAIR1", .state = ARM_CP_STATE_AA32,
.opc1 = 4, .crn = 10, .crm = 2, .opc2 = 1,
.access = PL2_RW, .type = ARM_CP_ALIAS,
.fieldoffset = offsetofhigh32(CPUARMState, cp15.mair_el[2]) },
{ .name = "TCR_EL2", .state = ARM_CP_STATE_BOTH,
.opc0 = 3, .opc1 = 4, .crn = 2, .crm = 0, .opc2 = 2,
.access = PL2_RW, .writefn = vmsa_tcr_el1_write,
.resetfn = vmsa_ttbcr_reset, .raw_writefn = raw_write,
.fieldoffset = offsetof(CPUARMState, cp15.tcr_el[2]) },
{ .name = "SCTLR_EL2", .state = ARM_CP_STATE_BOTH,
.opc0 = 3, .opc1 = 4, .crn = 1, .crm = 0, .opc2 = 0,
.access = PL2_RW, .raw_writefn = raw_write, .writefn = sctlr_write,
.fieldoffset = offsetof(CPUARMState, cp15.sctlr_el[2]) },
{ .name = "TPIDR_EL2", .state = ARM_CP_STATE_BOTH,
.opc0 = 3, .opc1 = 4, .crn = 13, .crm = 0, .opc2 = 2,
.access = PL2_RW, .resetvalue = 0,
.fieldoffset = offsetof(CPUARMState, cp15.tpidr_el[2]) },
{ .name = "TTBR0_EL2", .state = ARM_CP_STATE_AA64,
.opc0 = 3, .opc1 = 4, .crn = 2, .crm = 0, .opc2 = 0,
.access = PL2_RW, .resetvalue = 0,
.fieldoffset = offsetof(CPUARMState, cp15.ttbr0_el[2]) },
{ .name = "HTTBR", .cp = 15, .opc1 = 4, .crm = 2,
.access = PL2_RW, .type = ARM_CP_64BIT | ARM_CP_ALIAS,
.resetvalue = 0,
.fieldoffset = offsetof(CPUARMState, cp15.ttbr0_el[2]) },
{ .name = "TLBI_ALLE2", .state = ARM_CP_STATE_AA64,
.opc0 = 1, .opc1 = 4, .crn = 8, .crm = 7, .opc2 = 0,
.type = ARM_CP_NO_RAW, .access = PL2_W,
.writefn = tlbiall_write },
{ .name = "TLBI_VAE2", .state = ARM_CP_STATE_AA64,
.opc0 = 1, .opc1 = 4, .crn = 8, .crm = 7, .opc2 = 1,
.type = ARM_CP_NO_RAW, .access = PL2_W,
.writefn = tlbi_aa64_vaa_write },
{ .name = "TLBI_VAE2IS", .state = ARM_CP_STATE_AA64,
.opc0 = 1, .opc1 = 4, .crn = 8, .crm = 3, .opc2 = 1,
.type = ARM_CP_NO_RAW, .access = PL2_W,
.writefn = tlbi_aa64_vaa_write },
REGINFO_SENTINEL
};
@ -3243,7 +3312,7 @@ void register_cp_regs_for_features(ARMCPU *cpu)
define_arm_cp_regs(cpu, v8_cp_reginfo);
}
if (arm_feature(env, ARM_FEATURE_EL2)) {
define_arm_cp_regs(cpu, v8_el2_cp_reginfo);
define_arm_cp_regs(cpu, el2_cp_reginfo);
/* RVBAR_EL2 is only implemented if EL2 is the highest EL */
if (!arm_feature(env, ARM_FEATURE_EL3)) {
ARMCPRegInfo rvbar = {
@ -3258,7 +3327,7 @@ void register_cp_regs_for_features(ARMCPU *cpu)
* register the no_el2 reginfos.
*/
if (arm_feature(env, ARM_FEATURE_EL3)) {
define_arm_cp_regs(cpu, v8_el3_no_el2_cp_reginfo);
define_arm_cp_regs(cpu, el3_no_el2_cp_reginfo);
}
}
if (arm_feature(env, ARM_FEATURE_EL3)) {

View file

@ -600,3 +600,8 @@ int kvm_arch_fixup_msi_route(struct kvm_irq_routing_entry *route,
{
return 0;
}
int kvm_arch_msi_data_to_gsi(uint32_t data)
{
return (data - 32) & 0xffff;
}

View file

@ -2766,3 +2766,8 @@ int kvm_arch_fixup_msi_route(struct kvm_irq_routing_entry *route,
{
return 0;
}
int kvm_arch_msi_data_to_gsi(uint32_t data)
{
abort();
}

View file

@ -696,3 +696,8 @@ int kvm_arch_fixup_msi_route(struct kvm_irq_routing_entry *route,
{
return 0;
}
int kvm_arch_msi_data_to_gsi(uint32_t data)
{
abort();
}

View file

@ -2410,3 +2410,8 @@ int kvm_arch_fixup_msi_route(struct kvm_irq_routing_entry *route,
{
return 0;
}
int kvm_arch_msi_data_to_gsi(uint32_t data)
{
return data & 0xffff;
}

View file

@ -2216,3 +2216,8 @@ int kvm_arch_fixup_msi_route(struct kvm_irq_routing_entry *route,
route->u.adapter.adapter_id = pbdev->routes.adapter.adapter_id;
return 0;
}
int kvm_arch_msi_data_to_gsi(uint32_t data)
{
abort();
}