[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
Re: [PATCH v5 01/20] hw: encode accessing CPU index in MemTxAttrs
From: |
Peter Maydell |
Subject: |
Re: [PATCH v5 01/20] hw: encode accessing CPU index in MemTxAttrs |
Date: |
Mon, 21 Nov 2022 18:32:26 +0000 |
On Fri, 11 Nov 2022 at 18:25, Alex Bennée <alex.bennee@linaro.org> wrote:
>
> We currently have hacks across the hw/ to reference current_cpu to
> work out what the current accessing CPU is. This breaks in some cases
> including using gdbstub to access HW state. As we have MemTxAttrs to
> describe details about the access lets extend it so CPU accesses can
> be explicitly marked.
>
> To achieve this we create a new requester_type which indicates to
> consumers how requester_id it to be consumed. We absorb the existing
> unspecified:1 bitfield into this type and also document a potential
> machine specific encoding which will be useful to (currently)
> out-of-tree extensions.
>
> Places that checked to see if things where unspecified now instead
> check the source if what they expected.
>
> There are a number of places we need to fix up including:
>
> CPU helpers directly calling address_space_*() fns
> models in hw/ fishing the data out of current_cpu
> hypervisors offloading device emulation to QEMU
>
> I'll start addressing some of these in following patches.
>
> Signed-off-by: Alex Bennée <alex.bennee@linaro.org>
> include/exec/memattrs.h | 68 ++++++++++++++++++++++++++++++++---------
> hw/i386/amd_iommu.c | 6 ++--
> hw/i386/intel_iommu.c | 2 +-
> hw/misc/tz-mpc.c | 2 +-
> hw/misc/tz-msc.c | 6 ++--
> hw/pci/pci.c | 4 +--
> 6 files changed, 60 insertions(+), 28 deletions(-)
>
> diff --git a/include/exec/memattrs.h b/include/exec/memattrs.h
> index 9fb98bc1ef..8359fc448b 100644
> --- a/include/exec/memattrs.h
> +++ b/include/exec/memattrs.h
> @@ -14,7 +14,32 @@
> #ifndef MEMATTRS_H
> #define MEMATTRS_H
>
> -/* Every memory transaction has associated with it a set of
> +/**
> + * typedef MemTxRequesterType - source of memory transaction
> + *
> + * Every memory transaction comes from a specific place which defines
> + * how requester_id should be handled if at all.
> + *
> + * UNSPECIFIED: the default for otherwise undefined MemTxAttrs
> + * CPU: requester_id is the global cpu_index
> + * This needs further processing if you need to work out which
> + * socket or complex it comes from
> + * PCI: indicates the requester_id is a PCI id
> + * MACHINE: indicates a machine specific encoding
> + * This will require further processing to decode into its
> + * constituent parts.
> + */
> +typedef enum MemTxRequesterType {
> + MTRT_UNSPECIFIED = 0,
> + MTRT_CPU,
> + MTRT_PCI,
> + MTRT_MACHINE
> +} MemTxRequesterType;
This ends up squashing two distinct things into one field:
(1) what are the semantics of the requester_id field?
(2) did the caller explicitly specify their attrs, or
are they using the legacy MEMTXATTRS_UNSPECIFIED macro?
One might reasonably be explicitly specifying tx attrs
and yet not be using any of the 3 listed requester_id field
semantics. (In fact we have various places that do
exactly that, like tulip_desc_read().)
I think that the requester_type field should just be a
discriminator field that tells you how to interpret
requester_id, and nothing more, so the values would
be "CPU", "PCI", "machine" and "none".
I'm not super-enthusiastic about "MACHINE" here, but
I guess we can see how it works out over time.
> +/**
> + * typedef MemTxAttrs - attributes of a memory transaction
> + *
> + * Every memory transaction has associated with it a set of
> * attributes. Some of these are generic (such as the ID of
> * the bus master); some are specific to a particular kind of
> * bus (such as the ARM Secure/NonSecure bit). We define them
> @@ -23,13 +48,12 @@
> * different semantics.
> */
> typedef struct MemTxAttrs {
> - /* Bus masters which don't specify any attributes will get this
> - * (via the MEMTXATTRS_UNSPECIFIED constant), so that we can
> - * distinguish "all attributes deliberately clear" from
> - * "didn't specify" if necessary.
> - */
> - unsigned int unspecified:1;
> - /* ARM/AMBA: TrustZone Secure access
> + /* Requester type (e.g. CPU or PCI MSI) */
> + MemTxRequesterType requester_type:2;
> + /* Requester ID */
> + unsigned int requester_id:16;
> + /*
> + * ARM/AMBA: TrustZone Secure access
> * x86: System Management Mode access
> */
> unsigned int secure:1;
> @@ -43,8 +67,6 @@ typedef struct MemTxAttrs {
> * (see MEMTX_ACCESS_ERROR).
> */
> unsigned int memory:1;
> - /* Requester ID (for MSI for example) */
> - unsigned int requester_id:16;
> /* Invert endianness for this page */
> unsigned int byte_swap:1;
> /*
> @@ -59,12 +81,28 @@ typedef struct MemTxAttrs {
> unsigned int target_tlb_bit2 : 1;
> } MemTxAttrs;
>
> -/* Bus masters which don't specify any attributes will get this,
> - * which has all attribute bits clear except the topmost one
> - * (so that we can distinguish "all attributes deliberately clear"
> - * from "didn't specify" if necessary).
> +/*
> + * Bus masters which don't specify any attributes will get this which
> + * indicates none of the attributes can be used.
> + */
> +#define MEMTXATTRS_UNSPECIFIED ((MemTxAttrs) \
> + { .requester_type = MTRT_UNSPECIFIED })
This isn't the semantics I intended for MEMTXATTRS_UNSPECIFIED --
the recipient of a MEMTXATTRS_UNSPECIFIED is still allowed to look
at the various attribute bits, which should be set to "plausible
defaults". It just means that you can tell, for instance, "non-secure
because sender specifically asked for that" from "non-secure because
sender is an old bit of non-memtxattrs-aware code that doesn't
care to specify". Almost all code that looks at attrs.secure, for
instance, does it without previously checking attrs.unspecified,
because it doesn't have to. There are only a very few places that
do need to check attrs.unspecified:
* the two places changed in this patch, which are really trying
to check "is this a PCI transaction with PCI requester_id"
* tz-mpc.c, which wants to treat MEMTXATTRS_UNSPECIFIED as being
Secure for the reasons described in the comment in
tz_mpc_attrs_to_index()
Perhaps what we should do is address the reason that tz-mpc.c
is trying to use attrs.unspecified in a better way. Specifically,
we could add a MemTxAttrs:is_debug bit that indicates debug
writes, and arrange that code like the rom-image-loader sets
that appropriately. Then tz-mpc.c could say "pass through a
debug transaction regardless of its secure bit, but treat
real transactions the way the hardware does", instead of the
current fudge it does.
> +/*
> + * Helper for setting a basic CPU sourced transaction, it expects a
> + * CPUState *
> + */
> +#define MEMTXATTRS_CPU(cs) ((MemTxAttrs) \
> + {.requester_type = MTRT_CPU, \
> + .requester_id = cs->cpu_index})
> +
> +/*
> + * Helper for setting a basic PCI sourced transaction, it expects a
> + * PCIDevice *
> */
> -#define MEMTXATTRS_UNSPECIFIED ((MemTxAttrs) { .unspecified = 1 })
> +#define MEMTXATTRS_PCI(dev) ((MemTxAttrs) \
> + {.requester_type = MTRT_PCI, \
> + .requester_id = pci_requester_id(dev)})
Indent looks odd.
> /* New-style MMIO accessors can indicate that the transaction failed.
> * A zero (MEMTX_OK) response means success; anything else is a failure
> diff --git a/hw/i386/amd_iommu.c b/hw/i386/amd_iommu.c
> index 725f69095b..284359c16e 100644
> --- a/hw/i386/amd_iommu.c
> +++ b/hw/i386/amd_iommu.c
> @@ -153,9 +153,7 @@ static void amdvi_assign_andq(AMDVIState *s, hwaddr addr,
> uint64_t val)
> static void amdvi_generate_msi_interrupt(AMDVIState *s)
> {
> MSIMessage msg = {};
> - MemTxAttrs attrs = {
> - .requester_id = pci_requester_id(&s->pci.dev)
> - };
> + MemTxAttrs attrs = MEMTXATTRS_PCI(&s->pci.dev);
>
> if (msi_enabled(&s->pci.dev)) {
> msg = msi_get_message(&s->pci.dev, 0);
> @@ -1356,7 +1354,7 @@ static MemTxResult amdvi_mem_ir_write(void *opaque,
> hwaddr addr,
>
> trace_amdvi_mem_ir_write_req(addr, value, size);
>
> - if (!attrs.unspecified) {
> + if (attrs.requester_type == MTRT_PCI) {
> /* We have explicit Source ID */
> sid = attrs.requester_id;
> }
> diff --git a/hw/i386/intel_iommu.c b/hw/i386/intel_iommu.c
> index a08ee85edf..12752413eb 100644
> --- a/hw/i386/intel_iommu.c
> +++ b/hw/i386/intel_iommu.c
> @@ -3517,7 +3517,7 @@ static MemTxResult vtd_mem_ir_write(void *opaque,
> hwaddr addr,
> from.address = (uint64_t) addr + VTD_INTERRUPT_ADDR_FIRST;
> from.data = (uint32_t) value;
>
> - if (!attrs.unspecified) {
> + if (attrs.requester_type == MTRT_PCI) {
> /* We have explicit Source ID */
> sid = attrs.requester_id;
> }
> diff --git a/hw/misc/tz-mpc.c b/hw/misc/tz-mpc.c
> index 30481e1c90..4beb5daa1a 100644
> --- a/hw/misc/tz-mpc.c
> +++ b/hw/misc/tz-mpc.c
> @@ -461,7 +461,7 @@ static int tz_mpc_attrs_to_index(IOMMUMemoryRegion
> *iommu, MemTxAttrs attrs)
> * All the real during-emulation transactions from the CPU will
> * specify attributes.
> */
> - return (attrs.unspecified || attrs.secure) ? IOMMU_IDX_S : IOMMU_IDX_NS;
> + return ((attrs.requester_type == MTRT_UNSPECIFIED) || attrs.secure) ?
> IOMMU_IDX_S : IOMMU_IDX_NS;
> }
>
> static int tz_mpc_num_indexes(IOMMUMemoryRegion *iommu)
> diff --git a/hw/misc/tz-msc.c b/hw/misc/tz-msc.c
> index acbe94400b..e93bfc7083 100644
> --- a/hw/misc/tz-msc.c
> +++ b/hw/misc/tz-msc.c
> @@ -137,11 +137,9 @@ static MemTxResult tz_msc_read(void *opaque, hwaddr
> addr, uint64_t *pdata,
> return MEMTX_OK;
> case MSCAllowSecure:
> attrs.secure = 1;
> - attrs.unspecified = 0;
> break;
> case MSCAllowNonSecure:
> attrs.secure = 0;
> - attrs.unspecified = 0;
> break;
> }
>
> @@ -179,11 +177,11 @@ static MemTxResult tz_msc_write(void *opaque, hwaddr
> addr, uint64_t val,
> return MEMTX_OK;
> case MSCAllowSecure:
> attrs.secure = 1;
> - attrs.unspecified = 0;
> + attrs.requester_type = MTRT_CPU;
> break;
> case MSCAllowNonSecure:
> attrs.secure = 0;
> - attrs.unspecified = 0;
> + attrs.requester_type = MTRT_CPU;
> break;
> }
Whatever we do here, the handling of read and write transactions
should be the same, not different.
Forcing the requester_type to "this is the CPU" looks odd,
because the transaction might not be from the CPU (it could
be from a DMA-capable device).
I think probably the right thing here is "set attrs.secure as
required; don't touch any other fields of the attrs".
> diff --git a/hw/pci/pci.c b/hw/pci/pci.c
> index 2f450f6a72..1d0d8d866f 100644
> --- a/hw/pci/pci.c
> +++ b/hw/pci/pci.c
> @@ -319,9 +319,7 @@ void pci_device_deassert_intx(PCIDevice *dev)
>
> static void pci_msi_trigger(PCIDevice *dev, MSIMessage msg)
> {
> - MemTxAttrs attrs = {};
> -
> - attrs.requester_id = pci_requester_id(dev);
> + MemTxAttrs attrs = MEMTXATTRS_PCI(dev);
> address_space_stl_le(&dev->bus_master_as, msg.address, msg.data,
> attrs, NULL);
> }
> --
> 2.34.1
thanks
-- PMM
- Re: [PATCH v5 05/20] target/arm: ensure m-profile helpers set appropriate MemTxAttrs, (continued)
- [PATCH v5 08/20] hw/timer: convert mptimer access to attrs to derive cpu index, Alex Bennée, 2022/11/11
- [PATCH v5 07/20] hw/intc/gic: use MxTxAttrs to divine accessing CPU, Alex Bennée, 2022/11/11
- [PATCH v5 17/20] hw/intc: properly model IOAPIC MSI messages, Alex Bennée, 2022/11/11
- [PATCH v5 02/20] target/arm: ensure TCG IO accesses set appropriate MemTxAttrs, Alex Bennée, 2022/11/11
- [PATCH v5 01/20] hw: encode accessing CPU index in MemTxAttrs, Alex Bennée, 2022/11/11
- [PATCH v5 15/20] hw/i386: update vapic_write to use MemTxAttrs, Alex Bennée, 2022/11/11
- [PATCH v5 19/20] hw/isa: derive CPUState from MemTxAttrs in apm_ioport_writeb, Alex Bennée, 2022/11/11
- [PATCH v5 06/20] qtest: make read/write operation appear to be from CPU, Alex Bennée, 2022/11/11
- [PATCH v5 09/20] hw/arm: remove current_cpu hack from pxa2xx access, Alex Bennée, 2022/11/11