QEMU 源码分析-外设模拟(以 GPIO 为例)

QEMU 模拟外设的原理

QEMU 主要是实现了 CPU 核的模拟,可以读写某个地址。
QEMU 的模拟外设的原理很简单:硬件即内存
要在 QEMU 上模拟某个外设,思路就是:

  • CPU 读某个地址时,QEMU 模拟外设的行为,把数据返回给 CPU
  • CPU 写某个地址时,QEMU 获得数据,用来模拟外设的行为。
    即:要模拟外设备,我们只需要针对外设的地址提供对应的读写函数即可。

以 GPIO 为例:

QEMU 为GPIO内存地址提供读写回调函数,

1
2
3
static void sifive_gpio_write(void *opaque, hwaddr offset, uint64_t value, unsigned int size)

static uint64_t sifive_gpio_read(void *opaque, hwaddr offset, unsigned int size)

给外设地址提供读写函数

怎么描述某段地址:基地址、大小?如何给这段地址提供读写函数呢?这段地址设置好后,如何添加进system_memory去?有 2 种方法。

法 1:memory_region_init_io/memory_region_add_subregion
SIFIVE_UART为例,

1
2
3
memory_region_init_io(&s->mmio, NULL, &uart_ops, s,
TYPE_SIFIVE_UART, 0x2000);
memory_region_add_subregion(address_space, base, &s->mmio);

memory_region_init_io函数初始化iomem,读写函数,大小。
memory_region_add_subregion函数s->iomem指定了基地址,并添加进system_memory中。
以后,客户机上的程序读写这块地址时,就会导致对应的读写函数被调用。

法 2:memory_region_init_io/sysbus_init_mmio/sysbus_mmio_map
SIFIVE_GPIO为例,

1
2
3
memory_region_init_io(&s->mmio, OBJECT(dev), &gpio_ops, s, TYPE_SIFIVE_GPIO, SIFIVE_GPIO_SIZE);

sysbus_init_mmio(SYS_BUS_DEVICE(dev), &s->mmio);

memory_region_init_io函数初始化iomem,读写函数,大小。
sysbus_init_mmiommin传给设备;

1
sysbus_mmio_map(SYS_BUS_DEVICE(&s->gpio), 0, memmap[SIFIVE_E_DEV_GPIO0].base);

sysbus_mmio_map从设备中吧mmio添加进system_memory并指定基地址。

解决 expected identifier before‘(’token QEMU 源码分析 - 虚拟外设创建
You need to set install_url to use ShareThis. Please set it in _config.yml.

评论

Your browser is out-of-date!

Update your browser to view this website correctly. Update my browser now

×