Hi Peter,
Thank you so much for the information. Can you explain more about “have a PCI device which was an I2C controller” or give me some reference to look at?
Here’s all the modification I’ve done. I also attached my modified virt.c, virt.h and the original ones(from qemu-5.1.0). Just search for “modifyi2c” and there will be all my six modifications. Could you have a look at
them and show me where I did wrong?
In include/hw/arm/virt.h
- Add VIRT_I2C in the first enum
In hw/arm/virt.c
- Add header file and macro
#include "hw/i2c/i2c.h"
#define TYPE_VERSATILE_I2C "versatile_i2c"
- Add address in base_memmap
[VIRT_I2C] = { 0x09100000, 0x00001000 },
- Add IRQ in a15irqmap(This one is not used in create_i2c())
[VIRT_I2C] = 10,
- A create_i2c() function
char *nodename;
DeviceState *dev;
I2CBus *i2c;
int irq = vms->irqmap[VIRT_I2C];
hwaddr base = vms->memmap[VIRT_I2C].base;
hwaddr size = vms->memmap[VIRT_I2C].size;
dev = sysbus_create_simple(TYPE_VERSATILE_I2C, vms->memmap[VIRT_I2C].base, NULL);
i2c = (I2CBus *)qdev_get_child_bus(dev, "i2c");
i2c_slave_create_simple(i2c, "sii9022", 0x39);
nodename = g_strdup_printf("/i2c@%" PRIx64, base);
qemu_fdt_add_subnode(vms->fdt, nodename);
qemu_fdt_setprop_string(vms->fdt, nodename, "compatible", "arm,versatile-i2c");
qemu_fdt_setprop_sized_cells(vms->fdt, nodename, "reg", 1, base, 1, size);
g_free(nodename);
- Call create_i2c() in machvirt_init() after it calls create_platform_bus(vms)
Regards,
Weiqi
On Thu, 22 Oct 2020 at 01:19, root artifice <artifice37@outlook.com> wrote:
> I’d like to add I2C support for aarch64 virt board. So I modified hw/arm/virt.c as follows.
> Add [VIRT_I2C] = { 0x09100000, 0x00001000 } entry in base_memmap to define a memory region
> Use the following to emulate a I2C device
>
> dev = sysbus_create_simple(TYPE_VERSATILE_I2C, vms->memmap[VIRT_I2C].base, NULL);
>
> i2c = (I2CBus *)qdev_get_child_bus(dev, "i2c");
>
> i2c_slave_create_simple(i2c, "sii9022", 0x39);
>
> Use the following to add device tree file entry
>
> nodename = g_strdup_printf("/i2c@%" PRIx64, base);
>
> qemu_fdt_add_subnode(vms->fdt, nodename);
>
> qemu_fdt_setprop_string(vms->fdt, nodename, "compatible", "arm,versatile-i2c");
>
> qemu_fdt_setprop_sized_cells(vms->fdt, nodename, "reg", 1, base, 1, size);
>
>
>
> After modification, QEMU can compile successfully. However, when I run it (qemu-system-aarch64 -M virt -m 2048 -cpu cortex-a53 -kernel ./Image -nographic -hda rootfs.ext2 --append "root=/dev/vda"), I got the following error:
>
> qemu-system-aarch64: qemu-5.1.0/softmmu/memory.c:2388: memory_region_add_subregion_common: Assertion `!subregion->container' failed
>
>
>
> The assertion exists in qemu-5.1.0\softmmu\memory.c: memory_region_add_subregion_common() and is triggered by dev = sysbus_create_simple(TYPE_VERSATILE_I2C, vms->memmap[VIRT_I2C].base, NULL);. I think it means I’m using a memory region that has been used.
But I think the memory region in base_memap I’ve chosen is available. Besides, the assertion “subregion->container” is derived from dev = qdev_new(name) (located in hw/core/sysbus.c), which I have no control over when calling sysbus_create_simple(). Could
someone tell me which part is wrong?
This assertion means "you tried to put a MemoryRegion into a
container twice". It's not related to the specific guest addresses
involved but to what is being done with the MemoryRegion objects.
It shouldn't happen with just the code you quote above, so
my conclusion is that you haven't showed us all your code and
the bug is in something you haven't told us about.
PS: the best way to add I2C support to the virt board would
be to have a PCI device which was an I2C controller. Then
you wouldn't need to modify the virt.c code at all.
thanks
-- PMM