target-arm queue:

* virt: Don't enable MTE emulation by default
  * virt: Diagnose attempts to use MTE with memory-hotplug or KVM
    (rather than silently not working correctly)
  * util: Implement qemu_get_thread_id() for OpenBSD
  * qdev: Add doc comments for qdev_unrealize and GPIO functions,
    and standardize on doc-comments-in-header-file
  * hw/arm/armsse: Assert info->num_cpus is in-bounds in armsse_realize()
  * docs/system: Document canon-a1100, collie, gumstix, virt boards
 -----BEGIN PGP SIGNATURE-----
 
 iQJNBAABCAA3FiEE4aXFk81BneKOgxXPPCUl7RQ2DN4FAl8VlEgZHHBldGVyLm1h
 eWRlbGxAbGluYXJvLm9yZwAKCRA8JSXtFDYM3u4dD/9YxtaKEbpQRk1FeZJPZwxO
 /UL/B91nKrKUiJ+1ep4vfotx02UF90k0U95nm/bMGof/Yb6BAYs3hHIK7YlVutcM
 +E2PGptcZn1MIuzvI/kxEWuzm0Z2oIqpqlpvC+poXhlCoIytUSFVF3jDMkJrQgUs
 aN/i8owTSI/VvkHpxz0DB5ELof6fME1zO7YuXSBV6aupmeVj8iVVLSuOOZznyg4/
 7Lx+J/0YP3jdmTYNF4nx/g4UTr67049PTjsZ9VjInX3qdU1XNfyQglukm/DwWPEb
 7+l7KphPfviLsQaKeRvpEdn1+XnydQgKRf/gjdf8AMKYzAokCjTGOaXihtNcmbMz
 lCQEZrm4eZqV5eQq9zaguorwBB/+WmCGSE8FXDo+MDmAIzY8qQxqIfN1gaCl9a2f
 xiObgjj+CAqsoylHdtTlrctGkG0rWH28ZV8h6qf1w3ol4D/Zzx/T1e46M96UNJYR
 lsZb+BGlkSD7MJLiNOy/XIWXrEzXV2gqtvNCCPnHHkLFG1yGxYnqo/WvIteAD8zI
 dh8gycxF40l/0Sqd8vR0yJQ0VJio7Cn4ZU+vl7eN3SNgqH9YxxRx+urCZ2C81e9y
 gWFJv5XUSCjw/cJUAjgSRQKfJw0FUmGRAxs4zna154PO+J1I52cXV2r5qNThPxPB
 zvLyJTDI34cnK7EcqSBXfg==
 =yuLi
 -----END PGP SIGNATURE-----

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

target-arm queue:
 * virt: Don't enable MTE emulation by default
 * virt: Diagnose attempts to use MTE with memory-hotplug or KVM
   (rather than silently not working correctly)
 * util: Implement qemu_get_thread_id() for OpenBSD
 * qdev: Add doc comments for qdev_unrealize and GPIO functions,
   and standardize on doc-comments-in-header-file
 * hw/arm/armsse: Assert info->num_cpus is in-bounds in armsse_realize()
 * docs/system: Document canon-a1100, collie, gumstix, virt boards

# gpg: Signature made Mon 20 Jul 2020 13:55:36 BST
# gpg:                using RSA key E1A5C593CD419DE28E8315CF3C2525ED14360CDE
# gpg:                issuer "peter.maydell@linaro.org"
# gpg: Good signature from "Peter Maydell <peter.maydell@linaro.org>" [ultimate]
# gpg:                 aka "Peter Maydell <pmaydell@gmail.com>" [ultimate]
# gpg:                 aka "Peter Maydell <pmaydell@chiark.greenend.org.uk>" [ultimate]
# Primary key fingerprint: E1A5 C593 CD41 9DE2 8E83  15CF 3C25 25ED 1436 0CDE

* remotes/pmaydell/tags/pull-target-arm-20200720:
  docs/system: Document the arm virt board
  docs/system: Briefly document gumstix boards
  docs/system: Briefly document collie board
  docs/system: Briefly document canon-a1100 board
  hw/arm/armsse: Assert info->num_cpus is in-bounds in armsse_realize()
  qdev: Document GPIO related functions
  qdev: Document qdev_unrealize()
  qdev: Move doc comments from qdev.c to qdev-core.h
  util: Implement qemu_get_thread_id() for OpenBSD
  hw/arm/virt: Disable memory hotplug when MTE is enabled
  hw/arm/virt: Error for MTE enabled with KVM
  hw/arm/virt: Enable MTE via a machine property

Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
This commit is contained in:
Peter Maydell 2020-07-20 15:58:07 +01:00
commit af3d69058e
15 changed files with 559 additions and 50 deletions

View File

@ -636,6 +636,7 @@ F: include/hw/arm/digic.h
F: hw/*/digic*
F: include/hw/*/digic*
F: tests/acceptance/machine_arm_canona1100.py
F: docs/system/arm/digic.rst
Goldfish RTC
M: Anup Patel <anup.patel@wdc.com>
@ -651,6 +652,7 @@ R: Philippe Mathieu-Daudé <f4bug@amsat.org>
L: qemu-arm@nongnu.org
S: Odd Fixes
F: hw/arm/gumstix.c
F: docs/system/arm/gumstix.rst
i.MX25 PDK
M: Peter Maydell <peter.maydell@linaro.org>
@ -846,6 +848,7 @@ L: qemu-arm@nongnu.org
S: Odd Fixes
F: hw/arm/collie.c
F: hw/arm/strongarm*
F: docs/system/arm/collie.rst
Stellaris
M: Peter Maydell <peter.maydell@linaro.org>
@ -877,6 +880,7 @@ L: qemu-arm@nongnu.org
S: Maintained
F: hw/arm/virt*
F: include/hw/arm/virt.h
F: docs/system/arm/virt.rst
Xilinx Zynq
M: Edgar E. Iglesias <edgar.iglesias@gmail.com>

View File

@ -0,0 +1,16 @@
Sharp Zaurus SL-5500 (``collie``)
=================================
This machine is a model of the Sharp Zaurus SL-5500, which was
a 1990s PDA based on the StrongARM SA1110.
Implemented devices:
* NOR flash
* Interrupt controller
* Timer
* RTC
* GPIO
* Peripheral Pin Controller (PPC)
* UARTs
* Synchronous Serial Ports (SSP)

11
docs/system/arm/digic.rst Normal file
View File

@ -0,0 +1,11 @@
Canon A1100 (``canon-a1100``)
=============================
This machine is a model of the Canon PowerShot A1100 camera, which
uses the DIGIC SoC. This model is based on reverse engineering efforts
by the contributors to the `CHDK <http://chdk.wikia.com/>`_ and
`Magic Lantern <http://www.magiclantern.fm/>`_ projects.
The emulation is incomplete. In particular it can't be used
to run the original camera firmware, but it can successfully run
an experimental version of the `barebox bootloader <http://www.barebox.org/>`_.

View File

@ -0,0 +1,21 @@
Gumstix Connex and Verdex (``connex``, ``verdex``)
==================================================
These machines model the Gumstix Connex and Verdex boards.
The Connex has a PXA255 CPU and the Verdex has a PXA270.
Implemented devices:
* NOR flash
* SMC91C111 ethernet
* Interrupt controller
* DMA
* Timer
* GPIO
* MMC/SD card
* Fast infra-red communications port (FIR)
* LCD controller
* Synchronous serial ports (SPI)
* PCMCIA interface
* I2C
* I2S

161
docs/system/arm/virt.rst Normal file
View File

@ -0,0 +1,161 @@
'virt' generic virtual platform (``virt``)
==========================================
The `virt` board is a platform which does not correspond to any
real hardware; it is designed for use in virtual machines.
It is the recommended board type if you simply want to run
a guest such as Linux and do not care about reproducing the
idiosyncrasies and limitations of a particular bit of real-world
hardware.
This is a "versioned" board model, so as well as the ``virt`` machine
type itself (which may have improvements, bugfixes and other minor
changes between QEMU versions) a version is provided that guarantees
to have the same behaviour as that of previous QEMU releases, so
that VM migration will work between QEMU versions. For instance the
``virt-5.0`` machine type will behave like the ``virt`` machine from
the QEMU 5.0 release, and migration should work between ``virt-5.0``
of the 5.0 release and ``virt-5.0`` of the 5.1 release. Migration
is not guaranteed to work between different QEMU releases for
the non-versioned ``virt`` machine type.
Supported devices
"""""""""""""""""
The virt board supports:
- PCI/PCIe devices
- Flash memory
- One PL011 UART
- An RTC
- The fw_cfg device that allows a guest to obtain data from QEMU
- A PL061 GPIO controller
- An optional SMMUv3 IOMMU
- hotpluggable DIMMs
- hotpluggable NVDIMMs
- An MSI controller (GICv2M or ITS). GICv2M is selected by default along
with GICv2. ITS is selected by default with GICv3 (>= virt-2.7). Note
that ITS is not modeled in TCG mode.
- 32 virtio-mmio transport devices
- running guests using the KVM accelerator on aarch64 hardware
- large amounts of RAM (at least 255GB, and more if using highmem)
- many CPUs (up to 512 if using a GICv3 and highmem)
- Secure-World-only devices if the CPU has TrustZone:
- A second PL011 UART
- A secure flash memory
- 16MB of secure RAM
Supported guest CPU types:
- ``cortex-a7`` (32-bit)
- ``cortex-a15`` (32-bit; the default)
- ``cortex-a53`` (64-bit)
- ``cortex-a57`` (64-bit)
- ``cortex-a72`` (64-bit)
- ``host`` (with KVM only)
- ``max`` (same as ``host`` for KVM; best possible emulation with TCG)
Note that the default is ``cortex-a15``, so for an AArch64 guest you must
specify a CPU type.
Graphics output is available, but unlike the x86 PC machine types
there is no default display device enabled: you should select one from
the Display devices section of "-device help". The recommended option
is ``virtio-gpu-pci``; this is the only one which will work correctly
with KVM. You may also need to ensure your guest kernel is configured
with support for this; see below.
Machine-specific options
""""""""""""""""""""""""
The following machine-specific options are supported:
secure
Set ``on``/``off`` to enable/disable emulating a guest CPU which implements the
Arm Security Extensions (TrustZone). The default is ``off``.
virtualization
Set ``on``/``off`` to enable/disable emulating a guest CPU which implements the
Arm Virtualization Extensions. The default is ``off``.
highmem
Set ``on``/``off`` to enable/disable placing devices and RAM in physical
address space above 32 bits. The default is ``on`` for machine types
later than ``virt-2.12``.
gic-version
Specify the version of the Generic Interrupt Controller (GIC) to provide.
Valid values are:
``2``
GICv2
``3``
GICv3
``host``
Use the same GIC version the host provides, when using KVM
``max``
Use the best GIC version possible (same as host when using KVM;
currently same as ``3``` for TCG, but this may change in future)
its
Set ``on``/``off`` to enable/disable ITS instantiation. The default is ``on``
for machine types later than ``virt-2.7``.
iommu
Set the IOMMU type to create for the guest. Valid values are:
``none``
Don't create an IOMMU (the default)
``smmuv3``
Create an SMMUv3
ras
Set ``on``/``off`` to enable/disable reporting host memory errors to a guest
using ACPI and guest external abort exceptions. The default is off.
Linux guest kernel configuration
""""""""""""""""""""""""""""""""
The 'defconfig' for Linux arm and arm64 kernels should include the
right device drivers for virtio and the PCI controller; however some older
kernel versions, especially for 32-bit Arm, did not have everything
enabled by default. If you're not seeing PCI devices that you expect,
then check that your guest config has::
CONFIG_PCI=y
CONFIG_VIRTIO_PCI=y
CONFIG_PCI_HOST_GENERIC=y
If you want to use the ``virtio-gpu-pci`` graphics device you will also
need::
CONFIG_DRM=y
CONFIG_DRM_VIRTIO_GPU=y
Hardware configuration information for bare-metal programming
"""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""
The ``virt`` board automatically generates a device tree blob ("dtb")
which it passes to the guest. This provides information about the
addresses, interrupt lines and other configuration of the various devices
in the system. Guest code can rely on and hard-code the following
addresses:
- Flash memory starts at address 0x0000_0000
- RAM starts at 0x4000_0000
All other information about device locations may change between
QEMU versions, so guest code must look in the DTB.
QEMU supports two types of guest image boot for ``virt``, and
the way for the guest code to locate the dtb binary differs:
- For guests using the Linux kernel boot protocol (this means any
non-ELF file passed to the QEMU ``-kernel`` option) the address
of the DTB is passed in a register (``r2`` for 32-bit guests,
or ``x0`` for 64-bit guests)
- For guests booting as "bare-metal" (any other kind of boot),
the DTB is at the start of RAM (0x4000_0000)

View File

@ -82,13 +82,17 @@ undocumented; you can get a complete list by running
arm/versatile
arm/vexpress
arm/aspeed
arm/digic
arm/musicpal
arm/gumstix
arm/nseries
arm/orangepi
arm/palm
arm/xscale
arm/collie
arm/sx1
arm/stellaris
arm/virt
Arm CPU features
================

View File

@ -452,6 +452,8 @@ static void armsse_realize(DeviceState *dev, Error **errp)
return;
}
assert(info->num_cpus <= SSE_MAX_CPUS);
/* max SRAM_ADDR_WIDTH: 24 - log2(SRAM_NUM_BANK) */
assert(is_power_of_2(info->sram_banks));
addr_width_max = 24 - ctz32(info->sram_banks);

View File

@ -1773,6 +1773,12 @@ static void machvirt_init(MachineState *machine)
exit(1);
}
if (vms->mte && kvm_enabled()) {
error_report("mach-virt: KVM does not support providing "
"MTE to the guest CPU");
exit(1);
}
create_fdt(vms);
possible_cpus = mc->possible_cpu_arch_ids(machine);
@ -1837,12 +1843,19 @@ static void machvirt_init(MachineState *machine)
OBJECT(secure_sysmem), &error_abort);
}
/*
* The cpu adds the property if and only if MemTag is supported.
* If it is, we must allocate the ram to back that up.
*/
if (object_property_find(cpuobj, "tag-memory", NULL)) {
if (vms->mte) {
/* Create the memory region only once, but link to all cpus. */
if (!tag_sysmem) {
/*
* The property exists only if MemTag is supported.
* If it is, we must allocate the ram to back that up.
*/
if (!object_property_find(cpuobj, "tag-memory", NULL)) {
error_report("MTE requested, but not supported "
"by the guest CPU");
exit(1);
}
tag_sysmem = g_new(MemoryRegion, 1);
memory_region_init(tag_sysmem, OBJECT(machine),
"tag-memory", UINT64_MAX / 32);
@ -2061,6 +2074,20 @@ static void virt_set_ras(Object *obj, bool value, Error **errp)
vms->ras = value;
}
static bool virt_get_mte(Object *obj, Error **errp)
{
VirtMachineState *vms = VIRT_MACHINE(obj);
return vms->mte;
}
static void virt_set_mte(Object *obj, bool value, Error **errp)
{
VirtMachineState *vms = VIRT_MACHINE(obj);
vms->mte = value;
}
static char *virt_get_gic_version(Object *obj, Error **errp)
{
VirtMachineState *vms = VIRT_MACHINE(obj);
@ -2167,6 +2194,11 @@ static void virt_memory_pre_plug(HotplugHandler *hotplug_dev, DeviceState *dev,
return;
}
if (vms->mte) {
error_setg(errp, "memory hotplug is not enabled: MTE is enabled");
return;
}
if (is_nvdimm && !ms->nvdimms_state->is_enabled) {
error_setg(errp, "nvdimm is not enabled: add 'nvdimm=on' to '-M'");
return;
@ -2481,6 +2513,14 @@ static void virt_instance_init(Object *obj)
"Set on/off to enable/disable reporting host memory errors "
"to a KVM guest using ACPI and guest external abort exceptions");
/* MTE is disabled by default. */
vms->mte = false;
object_property_add_bool(obj, "mte", virt_get_mte, virt_set_mte);
object_property_set_description(obj, "mte",
"Set on/off to enable/disable emulating a "
"guest CPU which implements the ARM "
"Memory Tagging Extension");
vms->irqmap = a15irqmap;
virt_flash_create(vms);

View File

@ -128,13 +128,6 @@ void qdev_set_parent_bus(DeviceState *dev, BusState *bus)
}
}
/*
* Create a device on the heap.
* A type @name must exist.
* This only initializes the device state structure and allows
* properties to be set. The device still needs to be realized. See
* qdev-core.h.
*/
DeviceState *qdev_new(const char *name)
{
if (!object_class_by_name(name)) {
@ -143,11 +136,6 @@ DeviceState *qdev_new(const char *name)
return DEVICE(object_new(name));
}
/*
* Try to create a device on the heap.
* This is like qdev_new(), except it returns %NULL when type @name
* does not exist.
*/
DeviceState *qdev_try_new(const char *name)
{
if (!module_object_class_by_name(name)) {
@ -378,14 +366,6 @@ void qdev_simple_device_unplug_cb(HotplugHandler *hotplug_dev,
qdev_unrealize(dev);
}
/*
* Realize @dev.
* @dev must not be plugged into a bus.
* If @bus, plug @dev into @bus. This takes a reference to @dev.
* If @dev has no QOM parent, make one up, taking another reference.
* On success, return true.
* On failure, store an error through @errp and return false.
*/
bool qdev_realize(DeviceState *dev, BusState *bus, Error **errp)
{
assert(!dev->realized && !dev->parent_bus);
@ -399,16 +379,6 @@ bool qdev_realize(DeviceState *dev, BusState *bus, Error **errp)
return object_property_set_bool(OBJECT(dev), "realized", true, errp);
}
/*
* Realize @dev and drop a reference.
* This is like qdev_realize(), except the caller must hold a
* (private) reference, which is dropped on return regardless of
* success or failure. Intended use:
* dev = qdev_new();
* [...]
* qdev_realize_and_unref(dev, bus, errp);
* Now @dev can go away without further ado.
*/
bool qdev_realize_and_unref(DeviceState *dev, BusState *bus, Error **errp)
{
bool ret;
@ -814,9 +784,6 @@ static void qdev_class_add_property(DeviceClass *klass, Property *prop)
prop->info->description);
}
/* @qdev_alias_all_properties - Add alias properties to the source object for
* all qdev properties on the target DeviceState.
*/
void qdev_alias_all_properties(DeviceState *target, Object *source)
{
ObjectClass *class;

View File

@ -140,6 +140,7 @@ typedef struct {
bool its;
bool virt;
bool ras;
bool mte;
OnOffAuto acpi;
VirtGICType gic_version;
VirtIOMMUType iommu;

View File

@ -320,10 +320,86 @@ compat_props_add(GPtrArray *arr,
/*** Board API. This should go away once we have a machine config file. ***/
/**
* qdev_new: Create a device on the heap
* @name: device type to create (we assert() that this type exists)
*
* This only allocates the memory and initializes the device state
* structure, ready for the caller to set properties if they wish.
* The device still needs to be realized.
* The returned object has a reference count of 1.
*/
DeviceState *qdev_new(const char *name);
/**
* qdev_try_new: Try to create a device on the heap
* @name: device type to create
*
* This is like qdev_new(), except it returns %NULL when type @name
* does not exist, rather than asserting.
*/
DeviceState *qdev_try_new(const char *name);
/**
* qdev_realize: Realize @dev.
* @dev: device to realize
* @bus: bus to plug it into (may be NULL)
* @errp: pointer to error object
*
* "Realize" the device, i.e. perform the second phase of device
* initialization.
* @dev must not be plugged into a bus already.
* If @bus, plug @dev into @bus. This takes a reference to @dev.
* If @dev has no QOM parent, make one up, taking another reference.
* On success, return true.
* On failure, store an error through @errp and return false.
*
* If you created @dev using qdev_new(), you probably want to use
* qdev_realize_and_unref() instead.
*/
bool qdev_realize(DeviceState *dev, BusState *bus, Error **errp);
/**
* qdev_realize_and_unref: Realize @dev and drop a reference
* @dev: device to realize
* @bus: bus to plug it into (may be NULL)
* @errp: pointer to error object
*
* Realize @dev and drop a reference.
* This is like qdev_realize(), except the caller must hold a
* (private) reference, which is dropped on return regardless of
* success or failure. Intended use::
*
* dev = qdev_new();
* [...]
* qdev_realize_and_unref(dev, bus, errp);
*
* Now @dev can go away without further ado.
*
* If you are embedding the device into some other QOM device and
* initialized it via some variant on object_initialize_child() then
* do not use this function, because that family of functions arrange
* for the only reference to the child device to be held by the parent
* via the child<> property, and so the reference-count-drop done here
* would be incorrect. For that use case you want qdev_realize().
*/
bool qdev_realize_and_unref(DeviceState *dev, BusState *bus, Error **errp);
/**
* qdev_unrealize: Unrealize a device
* @dev: device to unrealize
*
* This function will "unrealize" a device, which is the first phase
* of correctly destroying a device that has been realized. It will:
*
* - unrealize any child buses by calling qbus_unrealize()
* (this will recursively unrealize any devices on those buses)
* - call the the unrealize method of @dev
*
* The device can then be freed by causing its reference count to go
* to zero.
*
* Warning: most devices in QEMU do not expect to be unrealized. Only
* devices which are hot-unpluggable should be unrealized (as part of
* the unplugging process); all other devices are expected to last for
* the life of the simulation and should not be unrealized and freed.
*/
void qdev_unrealize(DeviceState *dev);
void qdev_set_legacy_instance_id(DeviceState *dev, int alias_id,
int required_for_version);
@ -348,13 +424,132 @@ void qdev_simple_device_unplug_cb(HotplugHandler *hotplug_dev,
void qdev_machine_creation_done(void);
bool qdev_machine_modified(void);
/**
* qdev_get_gpio_in: Get one of a device's anonymous input GPIO lines
* @dev: Device whose GPIO we want
* @n: Number of the anonymous GPIO line (which must be in range)
*
* Returns the qemu_irq corresponding to an anonymous input GPIO line
* (which the device has set up with qdev_init_gpio_in()). The index
* @n of the GPIO line must be valid (i.e. be at least 0 and less than
* the total number of anonymous input GPIOs the device has); this
* function will assert() if passed an invalid index.
*
* This function is intended to be used by board code or SoC "container"
* device models to wire up the GPIO lines; usually the return value
* will be passed to qdev_connect_gpio_out() or a similar function to
* connect another device's output GPIO line to this input.
*
* For named input GPIO lines, use qdev_get_gpio_in_named().
*/
qemu_irq qdev_get_gpio_in(DeviceState *dev, int n);
/**
* qdev_get_gpio_in_named: Get one of a device's named input GPIO lines
* @dev: Device whose GPIO we want
* @name: Name of the input GPIO array
* @n: Number of the GPIO line in that array (which must be in range)
*
* Returns the qemu_irq corresponding to a named input GPIO line
* (which the device has set up with qdev_init_gpio_in_named()).
* The @name string must correspond to an input GPIO array which exists on
* the device, and the index @n of the GPIO line must be valid (i.e.
* be at least 0 and less than the total number of input GPIOs in that
* array); this function will assert() if passed an invalid name or index.
*
* For anonymous input GPIO lines, use qdev_get_gpio_in().
*/
qemu_irq qdev_get_gpio_in_named(DeviceState *dev, const char *name, int n);
/**
* qdev_connect_gpio_out: Connect one of a device's anonymous output GPIO lines
* @dev: Device whose GPIO to connect
* @n: Number of the anonymous output GPIO line (which must be in range)
* @pin: qemu_irq to connect the output line to
*
* This function connects an anonymous output GPIO line on a device
* up to an arbitrary qemu_irq, so that when the device asserts that
* output GPIO line, the qemu_irq's callback is invoked.
* The index @n of the GPIO line must be valid (i.e. be at least 0 and
* less than the total number of anonymous output GPIOs the device has
* created with qdev_init_gpio_out()); otherwise this function will assert().
*
* Outbound GPIO lines can be connected to any qemu_irq, but the common
* case is connecting them to another device's inbound GPIO line, using
* the qemu_irq returned by qdev_get_gpio_in() or qdev_get_gpio_in_named().
*
* It is not valid to try to connect one outbound GPIO to multiple
* qemu_irqs at once, or to connect multiple outbound GPIOs to the
* same qemu_irq. (Warning: there is no assertion or other guard to
* catch this error: the model will just not do the right thing.)
* Instead, for fan-out you can use the TYPE_IRQ_SPLIT device: connect
* a device's outbound GPIO to the splitter's input, and connect each
* of the splitter's outputs to a different device. For fan-in you
* can use the TYPE_OR_IRQ device, which is a model of a logical OR
* gate with multiple inputs and one output.
*
* For named output GPIO lines, use qdev_connect_gpio_out_named().
*/
void qdev_connect_gpio_out(DeviceState *dev, int n, qemu_irq pin);
/**
* qdev_connect_gpio_out: Connect one of a device's anonymous output GPIO lines
* @dev: Device whose GPIO to connect
* @name: Name of the output GPIO array
* @n: Number of the anonymous output GPIO line (which must be in range)
* @pin: qemu_irq to connect the output line to
*
* This function connects an anonymous output GPIO line on a device
* up to an arbitrary qemu_irq, so that when the device asserts that
* output GPIO line, the qemu_irq's callback is invoked.
* The @name string must correspond to an output GPIO array which exists on
* the device, and the index @n of the GPIO line must be valid (i.e.
* be at least 0 and less than the total number of input GPIOs in that
* array); this function will assert() if passed an invalid name or index.
*
* Outbound GPIO lines can be connected to any qemu_irq, but the common
* case is connecting them to another device's inbound GPIO line, using
* the qemu_irq returned by qdev_get_gpio_in() or qdev_get_gpio_in_named().
*
* It is not valid to try to connect one outbound GPIO to multiple
* qemu_irqs at once, or to connect multiple outbound GPIOs to the
* same qemu_irq; see qdev_connect_gpio_out() for details.
*
* For named output GPIO lines, use qdev_connect_gpio_out_named().
*/
void qdev_connect_gpio_out_named(DeviceState *dev, const char *name, int n,
qemu_irq pin);
/**
* qdev_get_gpio_out_connector: Get the qemu_irq connected to an output GPIO
* @dev: Device whose output GPIO we are interested in
* @name: Name of the output GPIO array
* @n: Number of the output GPIO line within that array
*
* Returns whatever qemu_irq is currently connected to the specified
* output GPIO line of @dev. This will be NULL if the output GPIO line
* has never been wired up to the anything. Note that the qemu_irq
* returned does not belong to @dev -- it will be the input GPIO or
* IRQ of whichever device the board code has connected up to @dev's
* output GPIO.
*
* You probably don't need to use this function -- it is used only
* by the platform-bus subsystem.
*/
qemu_irq qdev_get_gpio_out_connector(DeviceState *dev, const char *name, int n);
/**
* qdev_intercept_gpio_out: Intercept an existing GPIO connection
* @dev: Device to intercept the outbound GPIO line from
* @icpt: New qemu_irq to connect instead
* @name: Name of the output GPIO array
* @n: Number of the GPIO line in the array
*
* This function is provided only for use by the qtest testing framework
* and is not suitable for use in non-testing parts of QEMU.
*
* This function breaks an existing connection of an outbound GPIO
* line from @dev, and replaces it with the new qemu_irq @icpt, as if
* ``qdev_connect_gpio_out_named(dev, icpt, name, n)`` had been called.
* The previously connected qemu_irq is returned, so it can be restored
* by a second call to qdev_intercept_gpio_out() if desired.
*/
qemu_irq qdev_intercept_gpio_out(DeviceState *dev, qemu_irq icpt,
const char *name, int n);
@ -362,10 +557,59 @@ BusState *qdev_get_child_bus(DeviceState *dev, const char *name);
/*** Device API. ***/
/* Register device properties. */
/* GPIO inputs also double as IRQ sinks. */
/**
* qdev_init_gpio_in: create an array of anonymous input GPIO lines
* @dev: Device to create input GPIOs for
* @handler: Function to call when GPIO line value is set
* @n: Number of GPIO lines to create
*
* Devices should use functions in the qdev_init_gpio_in* family in
* their instance_init or realize methods to create any input GPIO
* lines they need. There is no functional difference between
* anonymous and named GPIO lines. Stylistically, named GPIOs are
* preferable (easier to understand at callsites) unless a device
* has exactly one uniform kind of GPIO input whose purpose is obvious.
* Note that input GPIO lines can serve as 'sinks' for IRQ lines.
*
* See qdev_get_gpio_in() for how code that uses such a device can get
* hold of an input GPIO line to manipulate it.
*/
void qdev_init_gpio_in(DeviceState *dev, qemu_irq_handler handler, int n);
/**
* qdev_init_gpio_out: create an array of anonymous output GPIO lines
* @dev: Device to create output GPIOs for
* @pins: Pointer to qemu_irq or qemu_irq array for the GPIO lines
* @n: Number of GPIO lines to create
*
* Devices should use functions in the qdev_init_gpio_out* family
* in their instance_init or realize methods to create any output
* GPIO lines they need. There is no functional difference between
* anonymous and named GPIO lines. Stylistically, named GPIOs are
* preferable (easier to understand at callsites) unless a device
* has exactly one uniform kind of GPIO output whose purpose is obvious.
*
* The @pins argument should be a pointer to either a "qemu_irq"
* (if @n == 1) or a "qemu_irq []" array (if @n > 1) in the device's
* state structure. The device implementation can then raise and
* lower the GPIO line by calling qemu_set_irq(). (If anything is
* connected to the other end of the GPIO this will cause the handler
* function for that input GPIO to be called.)
*
* See qdev_connect_gpio_out() for how code that uses such a device
* can connect to one of its output GPIO lines.
*/
void qdev_init_gpio_out(DeviceState *dev, qemu_irq *pins, int n);
/**
* qdev_init_gpio_out: create an array of named output GPIO lines
* @dev: Device to create output GPIOs for
* @pins: Pointer to qemu_irq or qemu_irq array for the GPIO lines
* @name: Name to give this array of GPIO lines
* @n: Number of GPIO lines to create
*
* Like qdev_init_gpio_out(), but creates an array of GPIO output lines
* with a name. Code using the device can then connect these GPIO lines
* using qdev_connect_gpio_out_named().
*/
void qdev_init_gpio_out_named(DeviceState *dev, qemu_irq *pins,
const char *name, int n);
/**
@ -397,6 +641,25 @@ static inline void qdev_init_gpio_in_named(DeviceState *dev,
qdev_init_gpio_in_named_with_opaque(dev, handler, dev, name, n);
}
/**
* qdev_pass_gpios: create GPIO lines on container which pass through to device
* @dev: Device which has GPIO lines
* @container: Container device which needs to expose them
* @name: Name of GPIO array to pass through (NULL for the anonymous GPIO array)
*
* In QEMU, complicated devices like SoCs are often modelled with a
* "container" QOM device which itself contains other QOM devices and
* which wires them up appropriately. This function allows the container
* to create GPIO arrays on itself which simply pass through to a GPIO
* array of one of its internal devices.
*
* If @dev has both input and output GPIOs named @name then both will
* be passed through. It is not possible to pass a subset of the array
* with this function.
*
* To users of the container device, the GPIO array created on @container
* behaves exactly like any other.
*/
void qdev_pass_gpios(DeviceState *dev, DeviceState *container,
const char *name);

View File

@ -282,6 +282,19 @@ void error_set_from_qdev_prop_error(Error **errp, int ret, DeviceState *dev,
*/
void qdev_property_add_static(DeviceState *dev, Property *prop);
/**
* qdev_alias_all_properties: Create aliases on source for all target properties
* @target: Device which has properties to be aliased
* @source: Object to add alias properties to
*
* Add alias properties to the @source object for all qdev properties on
* the @target DeviceState.
*
* This is useful when @target is an internal implementation object
* owned by @source, and you want to expose all the properties of that
* implementation object as properties on the @source object so that users
* of @source can set them.
*/
void qdev_alias_all_properties(DeviceState *target, Object *source);
/**

View File

@ -1698,6 +1698,17 @@ static void arm_cpu_realizefn(DeviceState *dev, Error **errp)
cpu->id_pfr1 &= ~0xf000;
}
#ifndef CONFIG_USER_ONLY
if (cpu->tag_memory == NULL && cpu_isar_feature(aa64_mte, cpu)) {
/*
* Disable the MTE feature bits if we do not have tag-memory
* provided by the machine.
*/
cpu->isar.id_aa64pfr1 =
FIELD_DP64(cpu->isar.id_aa64pfr1, ID_AA64PFR1, MTE, 0);
}
#endif
/* MPU can be configured out of a PMSA CPU either by setting has-mpu
* to false or by setting pmsav7-dregion to 0.
*/
@ -1787,14 +1798,6 @@ static void arm_cpu_realizefn(DeviceState *dev, Error **errp)
cpu_address_space_init(cs, ARMASIdx_TagS, "cpu-tag-memory",
cpu->secure_tag_memory);
}
} else if (cpu_isar_feature(aa64_mte, cpu)) {
/*
* Since there is no tag memory, we can't meaningfully support MTE
* to its fullest. To avoid problems later, when we would come to
* use the tag memory, downgrade support to insns only.
*/
cpu->isar.id_aa64pfr1 =
FIELD_DP64(cpu->isar.id_aa64pfr1, ID_AA64PFR1, MTE, 1);
}
cpu_address_space_init(cs, ARMASIdx_NS, "cpu-memory", cs->memory);

View File

@ -646,8 +646,9 @@ static void aarch64_max_initfn(Object *obj)
t = cpu->isar.id_aa64pfr1;
t = FIELD_DP64(t, ID_AA64PFR1, BT, 1);
/*
* Begin with full support for MTE; will be downgraded to MTE=1
* during realize if the board provides no tag memory.
* Begin with full support for MTE. This will be downgraded to MTE=0
* during realize if the board provides no tag memory, much like
* we do for EL2 with the virtualization=on property.
*/
t = FIELD_DP64(t, ID_AA64PFR1, MTE, 2);
cpu->isar.id_aa64pfr1 = t;

View File

@ -100,6 +100,8 @@ int qemu_get_thread_id(void)
return (int)tid;
#elif defined(__NetBSD__)
return _lwp_self();
#elif defined(__OpenBSD__)
return getthrid();
#else
return getpid();
#endif