cfi01 driver initializes a rom device with ops represented by pflash_cfi01_ops.
static const MemoryRegionOps pflash_cfi01_ops = { .read_with_attrs = pflash_mem_read_with_attrs, .write_with_attrs = pflash_mem_write_with_attrs, .endianness = DEVICE_NATIVE_ENDIAN, }; memory_region_init_rom_device( &pfl->mem, OBJECT(dev), &pflash_cfi01_ops, pfl, pfl->name, total_len, errp); This region is also mapped in guest address space. For ex: hw/arm/virt.c does that by: virt_flash_map1() { memory_region_add_subregion(sysmem, base, sysbus_mmio_get_region(SYS_BUS_DEVICE(dev), 0)); } It is not clear to me under what circumstance would the callbacks listed in pflash_cfi01_ops be invoked. Is rom device memory supposed to be of trap/emulate type, so that guest read of that memory will get trapped and handled by ops listed in pflash_cfi01_ops? I see that a hypervisor accelerator's memory listener callback gets notified of that memory range and appears to be registering that as "read-only" memory. A read of that memory range from guest need not necessarily cause a trap for example, in which case when would pflash_mem_read_with_attrs get invoked? - vatsa