On Sun, 4 Oct 2026 at 10:05, Bin Meng <[email protected]> wrote:
>
> U-Boot's shared i.MX6 identification code reads PERIPHBASE + 0x4 on
> MCIMX6UL-EVK. The first private peripheral page is currently unmapped,
> so that access causes a data abort before the console is ready.
>
> The GIC-400 register map reserves offsets 0x0000 through 0x0fff and
> specifies read-as-zero, write-ignored accesses to reserved locations.
> Model that page in the private peripheral device.
>
> Reference: GIC-400 TRM (ARM DDI 0471B), sections 3.1 and 3.2
> https://documentation-service.arm.com/static/5e8f15e27100066a414f7424
>
> Signed-off-by: Bin Meng <[email protected]>
In the interests of un-stalling this, let's trust the in-practice
observed by u-boot behaviour over the TRMs. I have some code
review comments below on the specifics.
> +#define TYPE_A15MPCORE_RESERVED "a15mpcore-reserved"
> +DECLARE_INSTANCE_CHECKER(A15MPReservedState, A15MPCORE_RESERVED,
> + TYPE_A15MPCORE_RESERVED)
> +
> +static uint64_t a15mp_reserved_read(void *opaque, hwaddr offset, unsigned
> size)
> +{
> + return 0;
> +}
> +
> +static void a15mp_reserved_write(void *opaque, hwaddr offset, uint64_t value,
> + unsigned size)
> +{
> +}
We should make these read and write functions do a
qemu_log_mask(LOG_GUEST_ERROR, ...) since guests accessing
the region is a bug.
> +
> +static const MemoryRegionOps a15mp_reserved_ops = {
> + .read = a15mp_reserved_read,
> + .write = a15mp_reserved_write,
> + .endianness = DEVICE_LITTLE_ENDIAN,
> +};
> +
> +static void a15mp_reserved_initfn(Object *obj)
> +{
> + A15MPReservedState *s = A15MPCORE_RESERVED(obj);
> +
> + memory_region_init_io(&s->iomem, obj, &a15mp_reserved_ops, s,
> + "a15mp-reserved", 0x1000);
> + sysbus_init_mmio(SYS_BUS_DEVICE(obj), &s->iomem);
> +}
> +
> +static void a15mp_reserved_class_init(ObjectClass *klass, const void *data)
> +{
> + DeviceClass *dc = DEVICE_CLASS(klass);
> +
> + dc->desc = "Reserved private peripheral page";
> + /* This device is an internal child of a15mpcore_priv */
> + dc->user_creatable = false;
> +}
Defining a whole new class is overkill; just init the memory region
in the a15mp_priv_initfn() (it doesn't need to be a sysbus MR).
> static void a15mp_priv_set_irq(void *opaque, int irq, int level)
> {
> A15MPPrivState *s = (A15MPPrivState *)opaque;
> @@ -43,6 +81,8 @@ static void a15mp_priv_initfn(Object *obj)
> memory_region_init(&s->container, obj, "a15mp-priv-container", 0x8000);
> sysbus_init_mmio(sbd, &s->container);
>
> + object_initialize_child(obj, "reserved", &s->reserved,
> + TYPE_A15MPCORE_RESERVED);
> object_initialize_child(obj, "gic", &s->gic, gic_class_name());
> qdev_prop_set_uint32(DEVICE(&s->gic), "revision", 2);
> }
> @@ -131,6 +171,12 @@ static void a15mp_priv_realize(DeviceState *dev, Error
> **errp)
> * 0x5600-0x57ff -- GIC virtual interface control for CPU 3
> * 0x6000-0x7fff -- GIC virtual CPU interface
> */
We should extend this comment to mention why we model the reserved area
the way we do, e.g.
The Cortex-A15 and A7 TRMs suggest that the reserved region at offset 0
either will (A15) or "can" (A7) trigger a bus error; the TRM for the
related GIC-400 documents RAZ/WI behaviour. In practice, u-boot for the
A7-based i.MX6 boards tries to access this space, and does not fall over
on the real hardware. So we model them as RAZ/WI.
thanks
-- PMM