首页
社区
课程
招聘
[原创] Qemu 源码分析(PCI篇)
发表于: 1天前 1173

[原创] Qemu 源码分析(PCI篇)

1天前
1173

几个月前写的文章了,翻飞书翻到了。可能结构会有点乱,主要是了解一下 PCI,有错误的话请各位大佬指正一下

PCI 设备通过 BAR(Base Address Register,基地址寄存器) 来定义自己的地址空间。一个标准的 PCI 设备最多可以有 6 个 BAR(BAR0-BAR5),每个 BAR 可以映射到两种不同类型的地址空间:

BAR(BASE Address Registers)用来确定设备所需要使用的内存和 I/O 空间的大小,也可以用来存放设备寄存器的地址。

设备可以申请两类的地址空间:

想象 PCI 总线就像是计算机内部的"高速公路系统":

内存和 I/O 设备共享同一个地址空间

端口映射 I/O 通常使用一种特殊的 CPU 指令,专门执行 I/O 操作

I/O 设备有一个与内存不同的地址空间,为了实现地址空间的隔离,要么在 CPU 物理接口上增加一个 I/O 引脚,要么增加一条专用的 I/O 总线。

这里用 edu PCI设备来做解释

EDU = Educational Device(教育用设备)这是QEMU官方提供的一个虚拟PCI设备,专门用于教学目的,帮助学生和开发者学习如何编写设备驱动程序。

FlatView的作用:

我们知道传入的参数为

所以access_fn间接调用memory_region_write_accessor

跳过阶段七(就是正常执行注册的函数)

在后面会仔细解释其含义和实现

一般 Device 与 Function 一起成为 deviceFn

正向和反向运算

deviceFn 为 PCIBus 设备数组的索引

直接查询源代码代码即可

常用的快速查询表

图片描述

然后通过 lspci 获取 pci 设备信息

图片描述

config文件 : PCI 配置空间(原始数据)

256 字节 (标准 PCI) 4096 字节 (PCIe)

图片描述

BAR0 解析

图片描述

解析

每行三个字段:起始地址 结束地址 标志位(最后一位表示类型:偶数=MMIO,奇数=PMIO)

这里可以看见仅仅是用了 BAR0

标识位解析

Bit 0:Region Type,总是为 0,用于区分此类型为 Memory

Bits 2-1:Locatable,为 0 时表示采用 32 位地址,为 2 时表示采用 64 位地址,为 1 时表示区间大小小于 1MB

Bit 3:Prefetchable,为 0 时表示关闭预取,为 1 时表示开启预取

Bits 31-4:Base Address,以 16 字节对齐基址

┌─────────────────────────────────────────────────────────────────┐
│                    QEMU 启动 - main()                            │
└──────────────────────────┬──────────────────────────────────────┘
                           
                           
┌─────────────────────────────────────────────────────────────────┐
│              机器初始化 - pc_init1()                             │
│  (hw/i386/pc_piix.c)                                            │
└──────────────────────────┬──────────────────────────────────────┘
                           
                           
┌─────────────────────────────────────────────────────────────────┐
│  1. 初始化内存区域                                               │
│     - system_memory (系统内存)                                  │
│     - system_io (I/O 地址空间)                                  │
│     - pci_memory (PCI 地址空间)                                 │
│                                                                  │
│     memory_region_init(pci_memory, NULL, "pci", UINT64_MAX)    │
└──────────────────────────┬──────────────────────────────────────┘
                           
                           
┌─────────────────────────────────────────────────────────────────┐
│  2. 创建 PCI Host Bridge                                        │
│     phb = qdev_new(TYPE_I440FX_PCI_HOST_BRIDGE)                │
│                                                                  │
│     设置属性链接:                                               │
│     - RAM_MEM → ram_memory                                     │
│     - PCI_MEM → pci_memory                                     │
│     - SYSTEM_MEM → system_memory                               │
│     - IO_MEM → system_io                                       │
└──────────────────────────┬──────────────────────────────────────┘
                           
                           
┌─────────────────────────────────────────────────────────────────┐
│  3. Realize PCI Host Bridge                                     │
│     sysbus_realize_and_unref(SYS_BUS_DEVICE(phb))              │
│                                                                  │
│     调用: i440fx_pcihost_realize()                              │
│     (hw/pci-host/i440fx.c)                                      │
└──────────────────────────┬──────────────────────────────────────┘
                           
                           
┌─────────────────────────────────────────────────────────────────┐
│  4. 映射 PCI 配置空间端口                                        │
│     - 0xCF8: PCI 配置地址端口 (conf_mem)                       │
│     - 0xCFC: PCI 配置数据端口 (data_mem)                       │
│                                                                  │
│     memory_region_add_subregion(io_memory, 0xcf8, conf_mem)    │
│     memory_region_add_subregion(io_memory, 0xcfc, data_mem)    │
└──────────────────────────┬──────────────────────────────────────┘
                           
                           
┌─────────────────────────────────────────────────────────────────┐
│  5. 创建 PCI 根总线                                              │
│     b = pci_root_bus_new(dev, NULL, pci_address_space,         │
│                          io_memory, 0, TYPE_PCI_BUS)           │
│                                                                  │
│     调用: pci_root_bus_internal_init()                          │
│     (hw/pci/pci.c)                                              │
└──────────────────────────┬──────────────────────────────────────┘
                           
                           
┌─────────────────────────────────────────────────────────────────┐
│  6. 初始化 PCIBus 结构                                           │
│     - bus->address_space_mem = mem                             │
│     - bus->address_space_io = io                               │
│     - bus->flags |= PCI_BUS_IS_ROOT                            │
│     - bus->devices[256] = {NULL}  // 设备数组                  │
│                                                                  │
│     pci_host_bus_register(parent)                              │
└──────────────────────────┬──────────────────────────────────────┘
                           
                           
┌─────────────────────────────────────────────────────────────────┐
│  7. 创建 i440FX PCI 设备(设备号 0)                            │
│     d = pci_create_simple(b, 0, TYPE_I440FX)                   │
│                                                                  │
│     - Vendor ID: 0x8086 (Intel)                                │
│     - Device ID: 0x1237 (82441)                                │
│     - Class: PCI_CLASS_BRIDGE_HOST                             │
└──────────────────────────┬──────────────────────────────────────┘
                           
                           
┌─────────────────────────────────────────────────────────────────┐
│  8. 设置内存映射                                                 │
│     - PCI Hole (3.5G ~ 4G)                                     │
│     - SMRAM 区域                                                │
│     - PAM (可编程属性映射)                                       │
│                                                                  │
│     pc_pci_as_mapping_init(system_memory, pci_address_space)   │
└──────────────────────────┬──────────────────────────────────────┘
                           
                           
┌─────────────────────────────────────────────────────────────────┐
│  9. 设置中断路由                                                 │
│     pci_bus_map_irqs(pcibus, pc_pci_slot_get_pirq)             │
│                                                                  │
│     将 PCI INTx (A/B/C/D) 映射到 PIRQ                          │
└──────────────────────────┬──────────────────────────────────────┘
                           
                           
┌─────────────────────────────────────────────────────────────────┐
│  10. 创建南桥 PCI 设备 (PIIX3/PIIX4)                            │
│      pci_dev = pci_new_multifunction(-1, TYPE_PIIX3)           │
│                                                                  │
│      包含:                                                      │
│      - ISA Bridge                                               │
│      - IDE Controller                                           │
│      - USB Controller (可选)                                    │
│      - ACPI/Power Management                                    │
└──────────────────────────┬──────────────────────────────────────┘
                           
                           
┌─────────────────────────────────────────────────────────────────┐
│  11. PCI 设备实现 (pci_realize_and_unref)                       │
│      调用: pci_qdev_realize() → PCIDeviceClass->realize()      │
│                                                                  │
│      - 分配配置空间 (256/4096 字节)                             │
│      - 初始化 BAR                                                │
│      - 设置中断                                                  │
│      - 添加到 bus->devices[devfn]                               │
└──────────────────────────┬──────────────────────────────────────┘
                           
                           
┌─────────────────────────────────────────────────────────────────┐
│  12. 创建其他 PCI 设备                                           │
│      - VGA 显卡                                                  │
│      - 网卡 (e1000, rtl8139, virtio-net)                       │
│      - 存储控制器 (virtio-blk, nvme)                            │
│      - 声卡等                                                    │
│                                                                  │
│      通过命令行参数 (-device) 或机器默认配置创建                │
└──────────────────────────┬──────────────────────────────────────┘
                           
                           
┌─────────────────────────────────────────────────────────────────┐
│  13. PCI 初始化完成                                              │
│      - PCI 总线就绪                                              │
│      - 客户机可以通过 0xCF8/0xCFC 枚举设备                      │
│      - 设备 MMIO/PMIO 映射到地址空间                            │
│      - 中断路由配置完成                                          │
└─────────────────────────────────────────────────────────────────┘
┌─────────────────────────────────────────────────────────────────┐
│                    QEMU 启动 - main()                            │
└──────────────────────────┬──────────────────────────────────────┘
                           
                           
┌─────────────────────────────────────────────────────────────────┐
│              机器初始化 - pc_init1()                             │
│  (hw/i386/pc_piix.c)                                            │
└──────────────────────────┬──────────────────────────────────────┘
                           
                           
┌─────────────────────────────────────────────────────────────────┐
│  1. 初始化内存区域                                               │
│     - system_memory (系统内存)                                  │
│     - system_io (I/O 地址空间)                                  │
│     - pci_memory (PCI 地址空间)                                 │
│                                                                  │
│     memory_region_init(pci_memory, NULL, "pci", UINT64_MAX)    │
└──────────────────────────┬──────────────────────────────────────┘
                           
                           
┌─────────────────────────────────────────────────────────────────┐
│  2. 创建 PCI Host Bridge                                        │
│     phb = qdev_new(TYPE_I440FX_PCI_HOST_BRIDGE)                │
│                                                                  │
│     设置属性链接:                                               │
│     - RAM_MEM → ram_memory                                     │
│     - PCI_MEM → pci_memory                                     │
│     - SYSTEM_MEM → system_memory                               │
│     - IO_MEM → system_io                                       │
└──────────────────────────┬──────────────────────────────────────┘
                           
                           
┌─────────────────────────────────────────────────────────────────┐
│  3. Realize PCI Host Bridge                                     │
│     sysbus_realize_and_unref(SYS_BUS_DEVICE(phb))              │
│                                                                  │
│     调用: i440fx_pcihost_realize()                              │
│     (hw/pci-host/i440fx.c)                                      │
└──────────────────────────┬──────────────────────────────────────┘
                           
                           
┌─────────────────────────────────────────────────────────────────┐
│  4. 映射 PCI 配置空间端口                                        │
│     - 0xCF8: PCI 配置地址端口 (conf_mem)                       │
│     - 0xCFC: PCI 配置数据端口 (data_mem)                       │
│                                                                  │
│     memory_region_add_subregion(io_memory, 0xcf8, conf_mem)    │
│     memory_region_add_subregion(io_memory, 0xcfc, data_mem)    │
└──────────────────────────┬──────────────────────────────────────┘
                           
                           
┌─────────────────────────────────────────────────────────────────┐
│  5. 创建 PCI 根总线                                              │
│     b = pci_root_bus_new(dev, NULL, pci_address_space,         │
│                          io_memory, 0, TYPE_PCI_BUS)           │
│                                                                  │
│     调用: pci_root_bus_internal_init()                          │
│     (hw/pci/pci.c)                                              │
└──────────────────────────┬──────────────────────────────────────┘
                           
                           
┌─────────────────────────────────────────────────────────────────┐
│  6. 初始化 PCIBus 结构                                           │
│     - bus->address_space_mem = mem                             │
│     - bus->address_space_io = io                               │
│     - bus->flags |= PCI_BUS_IS_ROOT                            │
│     - bus->devices[256] = {NULL}  // 设备数组                  │
│                                                                  │
│     pci_host_bus_register(parent)                              │
└──────────────────────────┬──────────────────────────────────────┘
                           
                           
┌─────────────────────────────────────────────────────────────────┐
│  7. 创建 i440FX PCI 设备(设备号 0)                            │
│     d = pci_create_simple(b, 0, TYPE_I440FX)                   │
│                                                                  │
│     - Vendor ID: 0x8086 (Intel)                                │
│     - Device ID: 0x1237 (82441)                                │
│     - Class: PCI_CLASS_BRIDGE_HOST                             │
└──────────────────────────┬──────────────────────────────────────┘
                           
                           
┌─────────────────────────────────────────────────────────────────┐
│  8. 设置内存映射                                                 │
│     - PCI Hole (3.5G ~ 4G)                                     │
│     - SMRAM 区域                                                │
│     - PAM (可编程属性映射)                                       │
│                                                                  │
│     pc_pci_as_mapping_init(system_memory, pci_address_space)   │
└──────────────────────────┬──────────────────────────────────────┘
                           
                           
┌─────────────────────────────────────────────────────────────────┐
│  9. 设置中断路由                                                 │
│     pci_bus_map_irqs(pcibus, pc_pci_slot_get_pirq)             │
│                                                                  │
│     将 PCI INTx (A/B/C/D) 映射到 PIRQ                          │
└──────────────────────────┬──────────────────────────────────────┘
                           
                           
┌─────────────────────────────────────────────────────────────────┐
│  10. 创建南桥 PCI 设备 (PIIX3/PIIX4)                            │
│      pci_dev = pci_new_multifunction(-1, TYPE_PIIX3)           │
│                                                                  │
│      包含:                                                      │
│      - ISA Bridge                                               │
│      - IDE Controller                                           │
│      - USB Controller (可选)                                    │
│      - ACPI/Power Management                                    │
└──────────────────────────┬──────────────────────────────────────┘
                           
                           
┌─────────────────────────────────────────────────────────────────┐
│  11. PCI 设备实现 (pci_realize_and_unref)                       │
│      调用: pci_qdev_realize() → PCIDeviceClass->realize()      │
│                                                                  │
│      - 分配配置空间 (256/4096 字节)                             │
│      - 初始化 BAR                                                │
│      - 设置中断                                                  │
│      - 添加到 bus->devices[devfn]                               │
└──────────────────────────┬──────────────────────────────────────┘
                           
                           
┌─────────────────────────────────────────────────────────────────┐
│  12. 创建其他 PCI 设备                                           │
│      - VGA 显卡                                                  │
│      - 网卡 (e1000, rtl8139, virtio-net)                       │
│      - 存储控制器 (virtio-blk, nvme)                            │
│      - 声卡等                                                    │
│                                                                  │
│      通过命令行参数 (-device) 或机器默认配置创建                │
└──────────────────────────┬──────────────────────────────────────┘
                           
                           
┌─────────────────────────────────────────────────────────────────┐
│  13. PCI 初始化完成                                              │
│      - PCI 总线就绪                                              │
│      - 客户机可以通过 0xCF8/0xCFC 枚举设备                      │
│      - 设备 MMIO/PMIO 映射到地址空间                            │
│      - 中断路由配置完成                                          │
└─────────────────────────────────────────────────────────────────┘
┌─────────────────────────────────────┐
│         QEMU虚拟机                   │
│  ┌──────────────────────────────┐   │
│  │   Guest Linux (虚拟机OS)      │   │
│  │  ┌────────────────────────┐  │   │
│  │  │  学生编写的EDU驱动      │  │   │  ← 学习目标
│  │  └────────┬───────────────┘  │   │
│  │           │ (MMIO/DMA/IRQ)   │   │
│  │  ┌────────▼───────────────┐  │   │
│  │  │   EDU虚拟PCI设备        │  │   │  ← edu.c模拟的设备
│  │  └────────────────────────┘  │   │
│  └──────────────────────────────┘   │
└─────────────────────────────────────┘
┌─────────────────────────────────────┐
│         QEMU虚拟机                   │
│  ┌──────────────────────────────┐   │
│  │   Guest Linux (虚拟机OS)      │   │
│  │  ┌────────────────────────┐  │   │
│  │  │  学生编写的EDU驱动      │  │   │  ← 学习目标
│  │  └────────┬───────────────┘  │   │
│  │           │ (MMIO/DMA/IRQ)   │   │
│  │  ┌────────▼───────────────┐  │   │
│  │  │   EDU虚拟PCI设备        │  │   │  ← edu.c模拟的设备
│  │  └────────────────────────┘  │   │
│  └──────────────────────────────┘   │
└─────────────────────────────────────┘
EDU设备包含4个教学模块:
┌─────────────────────────────────────┐
│ 1. 基础MMIO读写                      │
│    - 设备识别寄存器 (0x00)          │
│    - 活性检查寄存器 (0x04)          │
│    └→ 学习:基本的寄存器访问        │
├─────────────────────────────────────┤
│ 2. 异步计算 + 中断                   │
│    - 阶乘计算 (0x08)                │
│    - 状态寄存器 (0x20)              │
│    - 中断状态 (0x24)                │
│    └→ 学习:异步操作、中断处理      │
├─────────────────────────────────────┤
│ 3. 中断控制                         │
│    - 触发中断 (0x60)                │
│    - 清除中断 (0x64)                │
│    └→ 学习:中断管理、INTx/MSI      │
├─────────────────────────────────────┤
│ 4. DMA传输                          │
│    - DMA源地址 (0x80)               │
│    - DMA目标地址 (0x88)             │
│    - DMA计数 (0x90)                 │
│    - DMA命令 (0x98)                 │
│    └→ 学习:DMA编程、内存管理       │
└─────────────────────────────────────┘
EDU设备包含4个教学模块:
┌─────────────────────────────────────┐
│ 1. 基础MMIO读写                      │
│    - 设备识别寄存器 (0x00)          │
│    - 活性检查寄存器 (0x04)          │
│    └→ 学习:基本的寄存器访问        │
├─────────────────────────────────────┤
│ 2. 异步计算 + 中断                   │
│    - 阶乘计算 (0x08)                │
│    - 状态寄存器 (0x20)              │
│    - 中断状态 (0x24)                │
│    └→ 学习:异步操作、中断处理      │
├─────────────────────────────────────┤
│ 3. 中断控制                         │
│    - 触发中断 (0x60)                │
│    - 清除中断 (0x64)                │
│    └→ 学习:中断管理、INTx/MSI      │
├─────────────────────────────────────┤
│ 4. DMA传输                          │
│    - DMA源地址 (0x80)               │
│    - DMA目标地址 (0x88)             │
│    - DMA计数 (0x90)                 │
│    - DMA命令 (0x98)                 │
│    └→ 学习:DMA编程、内存管理       │
└─────────────────────────────────────┘
static const TypeInfo edu_types[] = {
    {
        .name          = TYPE_PCI_EDU_DEVICE,
        .parent        = TYPE_PCI_DEVICE,
        .instance_size = sizeof(EduState),
        .instance_init = edu_instance_init,
        .class_init    = edu_class_init,
        .interfaces    = (const InterfaceInfo[]) {
            { INTERFACE_CONVENTIONAL_PCI_DEVICE },
            { },
        },
    }
};
 
DEFINE_TYPES(edu_types)
static const TypeInfo edu_types[] = {
    {
        .name          = TYPE_PCI_EDU_DEVICE,
        .parent        = TYPE_PCI_DEVICE,
        .instance_size = sizeof(EduState),
        .instance_init = edu_instance_init,
        .class_init    = edu_class_init,
        .interfaces    = (const InterfaceInfo[]) {
            { INTERFACE_CONVENTIONAL_PCI_DEVICE },
            { },
        },
    }
};
 
DEFINE_TYPES(edu_types)
// 定义类型名称
#define TYPE_PCI_EDU_DEVICE "edu"
 
// TypeInfo结构体告诉QEMU:
.name          = "edu"                    // 设备类型名(命令行用 -device edu)
.parent        = TYPE_PCI_DEVICE          // 继承自PCIDevice
.instance_size = sizeof(EduState)         // 每个实例的内存大小
.instance_init = edu_instance_init        // 实例初始化函数
.class_init    = edu_class_init          // 类初始化函数
.interfaces    = CONVENTIONAL_PCI_DEVICE  // 实现传统PCI设备接口
// 定义类型名称
#define TYPE_PCI_EDU_DEVICE "edu"
 
// TypeInfo结构体告诉QEMU:
.name          = "edu"                    // 设备类型名(命令行用 -device edu)
.parent        = TYPE_PCI_DEVICE          // 继承自PCIDevice
.instance_size = sizeof(EduState)         // 每个实例的内存大小
.instance_init = edu_instance_init        // 实例初始化函数
.class_init    = edu_class_init          // 类初始化函数
.interfaces    = CONVENTIONAL_PCI_DEVICE  // 实现传统PCI设备接口
static void edu_class_init(ObjectClass *class, const void *data)
{
    DeviceClass *dc = DEVICE_CLASS(class);
    PCIDeviceClass *k = PCI_DEVICE_CLASS(class);
 
    k->realize = pci_edu_realize;
    k->exit = pci_edu_uninit;
    k->vendor_id = PCI_VENDOR_ID_QEMU;
    k->device_id = 0x11e8;
    k->revision = 0x10;
    k->class_id = PCI_CLASS_OTHERS;
    set_bit(DEVICE_CATEGORY_MISC, dc->categories);
}
static void edu_class_init(ObjectClass *class, const void *data)
{
    DeviceClass *dc = DEVICE_CLASS(class);
    PCIDeviceClass *k = PCI_DEVICE_CLASS(class);
 
    k->realize = pci_edu_realize;
    k->exit = pci_edu_uninit;
    k->vendor_id = PCI_VENDOR_ID_QEMU;
    k->device_id = 0x11e8;
    k->revision = 0x10;
    k->class_id = PCI_CLASS_OTHERS;
    set_bit(DEVICE_CATEGORY_MISC, dc->categories);
}
k->realize = pci_edu_realize;         // 设备实现函数(相当于init)
k->exit = pci_edu_uninit;            // 设备退出函数(相当于cleanup)
 
// PCI配置空间的值(用lspci可以看到)
k->vendor_id = PCI_VENDOR_ID_QEMU;   // 厂商ID: 0x1234
k->device_id = 0x11e8;               // 设备ID: 0x11e8
k->revision = 0x10;                  // 版本号
k->class_id = PCI_CLASS_OTHERS;      // PCI设备类别
k->realize = pci_edu_realize;         // 设备实现函数(相当于init)
k->exit = pci_edu_uninit;            // 设备退出函数(相当于cleanup)
 
// PCI配置空间的值(用lspci可以看到)
k->vendor_id = PCI_VENDOR_ID_QEMU;   // 厂商ID: 0x1234
k->device_id = 0x11e8;               // 设备ID: 0x11e8
k->revision = 0x10;                  // 版本号
k->class_id = PCI_CLASS_OTHERS;      // PCI设备类别
static void edu_instance_init(Object *obj)
{
    EduState *edu = EDU(obj);
 
    edu->dma_mask = (1UL << 28) - 1;
    object_property_add_uint64_ptr(obj, "dma_mask",
                                   &edu->dma_mask, OBJ_PROP_FLAG_READWRITE);
}
static void edu_instance_init(Object *obj)
{
    EduState *edu = EDU(obj);
 
    edu->dma_mask = (1UL << 28) - 1;
    object_property_add_uint64_ptr(obj, "dma_mask",
                                   &edu->dma_mask, OBJ_PROP_FLAG_READWRITE);
}
static void pci_edu_realize(PCIDevice *pdev, Error **errp)
{
    EduState *edu = EDU(pdev);
    uint8_t *pci_conf = pdev->config;
 
    pci_config_set_interrupt_pin(pci_conf, 1);
 
    if (msi_init(pdev, 0, 1, true, false, errp)) {
        return;
    }
 
    timer_init_ms(&edu->dma_timer, QEMU_CLOCK_VIRTUAL, edu_dma_timer, edu);
 
    qemu_mutex_init(&edu->thr_mutex);
    qemu_cond_init(&edu->thr_cond);
    qemu_thread_create(&edu->thread, "edu", edu_fact_thread,
                       edu, QEMU_THREAD_JOINABLE);
 
    memory_region_init_io(&edu->mmio, OBJECT(edu), &edu_mmio_ops, edu,
                    "edu-mmio", 1 * MiB);
    pci_register_bar(pdev, 0, PCI_BASE_ADDRESS_SPACE_MEMORY, &edu->mmio);
}
static void pci_edu_realize(PCIDevice *pdev, Error **errp)
{
    EduState *edu = EDU(pdev);
    uint8_t *pci_conf = pdev->config;
 
    pci_config_set_interrupt_pin(pci_conf, 1);
 
    if (msi_init(pdev, 0, 1, true, false, errp)) {
        return;
    }
 
    timer_init_ms(&edu->dma_timer, QEMU_CLOCK_VIRTUAL, edu_dma_timer, edu);
 
    qemu_mutex_init(&edu->thr_mutex);
    qemu_cond_init(&edu->thr_cond);
    qemu_thread_create(&edu->thread, "edu", edu_fact_thread,
                       edu, QEMU_THREAD_JOINABLE);
 
    memory_region_init_io(&edu->mmio, OBJECT(edu), &edu_mmio_ops, edu,
                    "edu-mmio", 1 * MiB);
    pci_register_bar(pdev, 0, PCI_BASE_ADDRESS_SPACE_MEMORY, &edu->mmio);
}
// 1. 配置PCI中断引脚(INTA#)
pci_config_set_interrupt_pin(pci_conf, 1);
 
// 2. 初始化MSI(Message Signaled Interrupts)支持
//    参数:设备,偏移量,中断数量,支持64位地址,支持per-vector屏蔽
msi_init(pdev, 0, 1, true, false, errp);
 
// 3. 初始化DMA定时器(模拟DMA传输延迟)
timer_init_ms(&edu->dma_timer, QEMU_CLOCK_VIRTUAL, edu_dma_timer, edu);
 
// 4. 创建后台线程(计算阶乘)
qemu_thread_create(&edu->thread, "edu", edu_fact_thread, edu, ...);
 
// 5. 创建MMIO内存区域(这是核心!)
memory_region_init_io(
    &edu->mmio,              // MemoryRegion对象
    OBJECT(edu),             // 所有者
    &edu_mmio_ops,           // 读写操作回调
    edu,                     // opaque指针
    "edu-mmio",              // 名称
    1 * MiB                  // 大小:1MB
);
 
// 6. 注册为PCI BAR0(重要!)
pci_register_bar(
    pdev,                             // PCI设备
    0,                                // BAR编号:0
    PCI_BASE_ADDRESS_SPACE_MEMORY,   // MMIO类型(不是PMIO)
    &edu->mmio                        // 内存区域
);
// 1. 配置PCI中断引脚(INTA#)
pci_config_set_interrupt_pin(pci_conf, 1);
 
// 2. 初始化MSI(Message Signaled Interrupts)支持
//    参数:设备,偏移量,中断数量,支持64位地址,支持per-vector屏蔽
msi_init(pdev, 0, 1, true, false, errp);
 
// 3. 初始化DMA定时器(模拟DMA传输延迟)
timer_init_ms(&edu->dma_timer, QEMU_CLOCK_VIRTUAL, edu_dma_timer, edu);
 
// 4. 创建后台线程(计算阶乘)
qemu_thread_create(&edu->thread, "edu", edu_fact_thread, edu, ...);
 
// 5. 创建MMIO内存区域(这是核心!)
memory_region_init_io(
    &edu->mmio,              // MemoryRegion对象
    OBJECT(edu),             // 所有者
    &edu_mmio_ops,           // 读写操作回调
    edu,                     // opaque指针
    "edu-mmio",              // 名称
    1 * MiB                  // 大小:1MB
);
 
// 6. 注册为PCI BAR0(重要!)
pci_register_bar(
    pdev,                             // PCI设备
    0,                                // BAR编号:0
    PCI_BASE_ADDRESS_SPACE_MEMORY,   // MMIO类型(不是PMIO)
    &edu->mmio                        // 内存区域
);
uint64_t (*read)(void *opaque, hwaddr addr, unsigned size);
uint64_t (*read)(void *opaque, hwaddr addr, unsigned size);
static const MemoryRegionOps edu_mmio_ops = {
    .read = edu_mmio_read,
    .write = edu_mmio_write,
    .endianness = DEVICE_NATIVE_ENDIAN,
    .valid = {
        .min_access_size = 4,
        .max_access_size = 8,
    },
    .impl = {
        .min_access_size = 4,
        .max_access_size = 8,
    },
 
};
static const MemoryRegionOps edu_mmio_ops = {
    .read = edu_mmio_read,
    .write = edu_mmio_write,
    .endianness = DEVICE_NATIVE_ENDIAN,
    .valid = {
        .min_access_size = 4,
        .max_access_size = 8,
    },
    .impl = {
        .min_access_size = 4,
        .max_access_size = 8,
    },
 
};
Guest: mov [0xFEBF1000], 1337
    ↓ (VM Exit)
KVM捕获访问
    
传递给QEMU
    
QEMU内存系统查找对应的MemoryRegion
    
找到edu->mmio
    
调用 edu_mmio_write(edu, 0x00, 1337, 4)
    
设备逻辑处理
Guest: mov [0xFEBF1000], 1337
    ↓ (VM Exit)
KVM捕获访问
    
传递给QEMU
    
QEMU内存系统查找对应的MemoryRegion
    
找到edu->mmio
    
调用 edu_mmio_write(edu, 0x00, 1337, 4)
    
设备逻辑处理
┌─────────────────────────────────────────────────────────────────────┐
│                        Guest OS (虚拟机)                             │
│                                                                       │
│    用户驱动或应用程序                                                 │
│         │                                                             │
│         ▼                                                             │
│    uint32_t val = *(uint32_t*)(mmio_mem + 0x08);                    │
│                   │                                                   │
│                   ▼                                                   │
│    CPU执行: MOV EAX, [0xFEBF1008]  ← EDU设备BAR0 + 0x08            │
│                   │                                                   │
└───────────────────┼───────────────────────────────────────────────────┘
                    
                    ▼ (VM Exit - EPT Violation 或 MMIO访问)
┌─────────────────────────────────────────────────────────────────────┐
│                    Linux Kernel (Host)                               │
│                                                                       │
│    KVM模块                                                           │
│         │                                                             │
│         ▼                                                             │
│    检测到Guest访问设备地址 (0xFEBF1008)                             │
│         │                                                             │
│         ▼                                                             │
│    填充 kvm_run 结构体:                                              │
│         run->exit_reason = KVM_EXIT_MMIO                             │
│         run->mmio.phys_addr = 0xFEBF1008                            │
│         run->mmio.len = 4                                            │
│         run->mmio.is_write = 0                                       │
│         │                                                             │
│         ▼                                                             │
│    return to userspace (ioctl返回)                                  │
│                                                                       │
└───────────────────┼───────────────────────────────────────────────────┘
                    
                    
┌─────────────────────────────────────────────────────────────────────┐
│                    QEMU进程 (用户态)                                 │
│                                                                       │
│    [1] kvm_cpu_exec()                                                │
│         ↓                                                             │
│    [2] run_ret = kvm_vcpu_ioctl(cpu, KVM_RUN, 0)                    │
│         ↓ (ioctl阻塞,直到VM Exit)                                   │
│    [3] switch(run->exit_reason)                                      │
│         ↓                                                             │
│    [4] case KVM_EXIT_MMIO:                                           │
│         ↓                                                             │
│    [5] address_space_rw(&address_space_memory,                       │
│                         run->mmio.phys_addr,                         │
│                         attrs,                                       │
│                         run->mmio.data,                              │
│                         run->mmio.len,                               │
│                         run->mmio.is_write)                          │
│         ↓                                                             │
│    [6] address_space_read_full()                                     │
│         ↓                                                             │
│    [7] fv = address_space_to_flatview(as)                           │
│         ↓                                                             │
│    [8] flatview_read(fv, addr, attrs, buf, len)                     │
│         ↓                                                             │
│    [9] mr = flatview_translate(fv, addr, ...)                       │
│         ↓                                                             │
│    [10] flatview_read_continue()                                     │
│         ↓                                                             │
│    [11] flatview_read_continue_step()                                │
│         ↓                                                             │
│    [12] memory_region_dispatch_read(mr, mr_addr, &val, ...)         │
│         ↓                                                             │
│    [13] memory_region_dispatch_read1()                               │
│         ↓                                                             │
│    [14] access_with_adjusted_size()                                  │
│         ↓                                                             │
│    [15] memory_region_read_accessor()                                │
│         ↓                                                             │
│    [16] tmp = mr->ops->read(mr->opaque, addr, size)                 │
│         ↓                                                             │
│    [17] edu_mmio_read(edu, 0x08, 4)  ← 最终调用!                   │
│         ↓                                                             │
│    [18] switch(addr) { case 0x08: return edu->fact; }               │
│         ↓                                                             │
│    [19] 返回值逐层返回到 run->mmio.data                              │
│         ↓                                                             │
│    [20] VM Enter,Guest继续执行                                      │
│                                                                       │
└─────────────────────────────────────────────────────────────────────┘
┌─────────────────────────────────────────────────────────────────────┐
│                        Guest OS (虚拟机)                             │
│                                                                       │
│    用户驱动或应用程序                                                 │
│         │                                                             │
│         ▼                                                             │
│    uint32_t val = *(uint32_t*)(mmio_mem + 0x08);                    │
│                   │                                                   │
│                   ▼                                                   │
│    CPU执行: MOV EAX, [0xFEBF1008]  ← EDU设备BAR0 + 0x08            │
│                   │                                                   │
└───────────────────┼───────────────────────────────────────────────────┘
                    
                    ▼ (VM Exit - EPT Violation 或 MMIO访问)
┌─────────────────────────────────────────────────────────────────────┐
│                    Linux Kernel (Host)                               │
│                                                                       │
│    KVM模块                                                           │
│         │                                                             │
│         ▼                                                             │
│    检测到Guest访问设备地址 (0xFEBF1008)                             │
│         │                                                             │
│         ▼                                                             │
│    填充 kvm_run 结构体:                                              │
│         run->exit_reason = KVM_EXIT_MMIO                             │
│         run->mmio.phys_addr = 0xFEBF1008                            │
│         run->mmio.len = 4                                            │
│         run->mmio.is_write = 0                                       │
│         │                                                             │
│         ▼                                                             │
│    return to userspace (ioctl返回)                                  │
│                                                                       │
└───────────────────┼───────────────────────────────────────────────────┘
                    
                    
┌─────────────────────────────────────────────────────────────────────┐
│                    QEMU进程 (用户态)                                 │
│                                                                       │
│    [1] kvm_cpu_exec()                                                │
│         ↓                                                             │
│    [2] run_ret = kvm_vcpu_ioctl(cpu, KVM_RUN, 0)                    │
│         ↓ (ioctl阻塞,直到VM Exit)                                   │
│    [3] switch(run->exit_reason)                                      │
│         ↓                                                             │
│    [4] case KVM_EXIT_MMIO:                                           │
│         ↓                                                             │
│    [5] address_space_rw(&address_space_memory,                       │
│                         run->mmio.phys_addr,                         │
│                         attrs,                                       │
│                         run->mmio.data,                              │
│                         run->mmio.len,                               │
│                         run->mmio.is_write)                          │
│         ↓                                                             │
│    [6] address_space_read_full()                                     │
│         ↓                                                             │
│    [7] fv = address_space_to_flatview(as)                           │
│         ↓                                                             │
│    [8] flatview_read(fv, addr, attrs, buf, len)                     │
│         ↓                                                             │
│    [9] mr = flatview_translate(fv, addr, ...)                       │
│         ↓                                                             │
│    [10] flatview_read_continue()                                     │
│         ↓                                                             │
│    [11] flatview_read_continue_step()                                │
│         ↓                                                             │
│    [12] memory_region_dispatch_read(mr, mr_addr, &val, ...)         │
│         ↓                                                             │
│    [13] memory_region_dispatch_read1()                               │
│         ↓                                                             │
│    [14] access_with_adjusted_size()                                  │
│         ↓                                                             │
│    [15] memory_region_read_accessor()                                │
│         ↓                                                             │
│    [16] tmp = mr->ops->read(mr->opaque, addr, size)                 │
│         ↓                                                             │
│    [17] edu_mmio_read(edu, 0x08, 4)  ← 最终调用!                   │
│         ↓                                                             │
│    [18] switch(addr) { case 0x08: return edu->fact; }               │
│         ↓                                                             │
│    [19] 返回值逐层返回到 run->mmio.data                              │
│         ↓                                                             │
│    [20] VM Enter,Guest继续执行                                      │
│                                                                       │
└─────────────────────────────────────────────────────────────────────┘
Guest vCPU          KVM (Kernel)        QEMU (Userspace)        EDU Device
    │                    │                      │                     │
    │ MOV [0xFEBF1008]   │                      │                     │
    ├───────────────────>│                      │                     │
    │                    │ EPT Violation        │                     │
    │                    │ (设备地址)            │                     │
    │                    │                      │                     │
    │                    │ 填充kvm_run          │                     │
    │                    │ exit_reason=MMIO     │                     │
    │                    │                      │                     │
    │                    │ ioctl返回            │                     │
    │                    ├─────────────────────>│                     │
    │                    │                      │                     │
    │                    │                      │ address_space_rw    │
    │                    │                      │ flatview_translate  │
    │                    │                      │ 查找MemoryRegion    │
    │                    │                      │                     │
    │                    │                      │ dispatch_read       │
    │                    │                      ├────────────────────>│
    │                    │                      │                     │ edu_mmio_read
    │                    │                      │                     │ switch(0x08)
    │                    │                      │                     │ return fact
    │                    │                      │<────────────────────┤
    │                    │                      │                     │
    │                    │ 数据写入run->mmio    │                     │
    │                    │ KVM_RUN ioctl        │                     │
    │                    │<─────────────────────┤                     │
    │                    │                      │                     │
    │                    │ VM Enter             │                     │
    │                    │ 注入读取结果到EAX     │                     │
    │<───────────────────┤                      │                     │
    │ 继续执行            │                      │                     │
    │                    │                      │                     │
Guest vCPU          KVM (Kernel)        QEMU (Userspace)        EDU Device
    │                    │                      │                     │
    │ MOV [0xFEBF1008]   │                      │                     │
    ├───────────────────>│                      │                     │
    │                    │ EPT Violation        │                     │
    │                    │ (设备地址)            │                     │
    │                    │                      │                     │
    │                    │ 填充kvm_run          │                     │
    │                    │ exit_reason=MMIO     │                     │
    │                    │                      │                     │
    │                    │ ioctl返回            │                     │
    │                    ├─────────────────────>│                     │
    │                    │                      │                     │
    │                    │                      │ address_space_rw    │
    │                    │                      │ flatview_translate  │
    │                    │                      │ 查找MemoryRegion    │
    │                    │                      │                     │
    │                    │                      │ dispatch_read       │
    │                    │                      ├────────────────────>│
    │                    │                      │                     │ edu_mmio_read
    │                    │                      │                     │ switch(0x08)
    │                    │                      │                     │ return fact
    │                    │                      │<────────────────────┤
    │                    │                      │                     │
    │                    │ 数据写入run->mmio    │                     │
    │                    │ KVM_RUN ioctl        │                     │
    │                    │<─────────────────────┤                     │
    │                    │                      │                     │
    │                    │ VM Enter             │                     │
    │                    │ 注入读取结果到EAX     │                     │
    │<───────────────────┤                      │                     │
    │ 继续执行            │                      │                     │
    │                    │                      │                     │
// 位置: accel/kvm/kvm-all.c:3154
int kvm_cpu_exec(CPUState *cpu)
{
    struct kvm_run *run = cpu->kvm_run;  // 共享内存页
     
    do {
        // 进入Guest执行
        run_ret = kvm_vcpu_ioctl(cpu, KVM_RUN, 0);  // [Step 2]
         
        // Guest发生VM Exit后返回
        switch (run->exit_reason) {
        case KVM_EXIT_MMIO:  // [Step 4]
            // 处理MMIO访问
            address_space_rw(&address_space_memory,   // [Step 5]
                             run->mmio.phys_addr,     // 0xFEBF1008
                             attrs,
                             run->mmio.data,          // 数据缓冲区
                             run->mmio.len,           // 4字节
                             run->mmio.is_write);     // 0 (读操作)
            break;
        }
    } while (ret == 0);
}
// 位置: accel/kvm/kvm-all.c:3154
int kvm_cpu_exec(CPUState *cpu)
{
    struct kvm_run *run = cpu->kvm_run;  // 共享内存页
     
    do {
        // 进入Guest执行
        run_ret = kvm_vcpu_ioctl(cpu, KVM_RUN, 0);  // [Step 2]
         
        // Guest发生VM Exit后返回
        switch (run->exit_reason) {
        case KVM_EXIT_MMIO:  // [Step 4]
            // 处理MMIO访问
            address_space_rw(&address_space_memory,   // [Step 5]
                             run->mmio.phys_addr,     // 0xFEBF1008
                             attrs,
                             run->mmio.data,          // 数据缓冲区
                             run->mmio.len,           // 4字节
                             run->mmio.is_write);     // 0 (读操作)
            break;
        }
    } while (ret == 0);
}
/* for KVM_RUN, returned by mmap(vcpu_fd, offset=0) */
struct kvm_run {
    /* in */
    __u8 request_interrupt_window;
    __u8 HINT_UNSAFE_IN_KVM(immediate_exit);
    __u8 padding1[6];
 
    /* out */
    __u32 exit_reason;
    __u8 ready_for_interrupt_injection;
    __u8 if_flag;
    __u16 flags;
 
    /* in (pre_kvm_run), out (post_kvm_run) */
    __u64 cr8;
    __u64 apic_base;
    // ...
    // union 结构,这里简化一下,我们选择我们要用的表达。
    struct {
        __u64 phys_addr;        // Guest物理地址: 0xFEBF1008
        __u8 data[8];           // 数据缓冲区
        __u32 len;              // 访问长度: 4
        __u8 is_write;          // 0=读, 1=写
    } mmio;
}
/* for KVM_RUN, returned by mmap(vcpu_fd, offset=0) */
struct kvm_run {
    /* in */
    __u8 request_interrupt_window;
    __u8 HINT_UNSAFE_IN_KVM(immediate_exit);
    __u8 padding1[6];
 
    /* out */
    __u32 exit_reason;
    __u8 ready_for_interrupt_injection;
    __u8 if_flag;
    __u16 flags;
 
    /* in (pre_kvm_run), out (post_kvm_run) */
    __u64 cr8;
    __u64 apic_base;
    // ...
    // union 结构,这里简化一下,我们选择我们要用的表达。
    struct {
        __u64 phys_addr;        // Guest物理地址: 0xFEBF1008
        __u8 data[8];           // 数据缓冲区
        __u32 len;              // 访问长度: 4
        __u8 is_write;          // 0=读, 1=写
    } mmio;
}
/* Called from RCU critical section */
MemoryRegion *flatview_translate(FlatView *fv, hwaddr addr, hwaddr *xlat,
                                 hwaddr *plen, bool is_write,
                                 MemTxAttrs attrs)
{
    MemoryRegion *mr;
    MemoryRegionSection section;
    AddressSpace *as = NULL;
 
    /* This can be MMIO, so setup MMIO bit. */
    section = flatview_do_translate(fv, addr, xlat, plen, NULL,
                                    is_write, true, &as, attrs);
    mr = section.mr;
 
    if (xen_enabled() && memory_access_is_direct(mr, is_write, attrs)) {
        hwaddr page = ((addr & TARGET_PAGE_MASK) + TARGET_PAGE_SIZE) - addr;
        *plen = MIN(page, *plen);
    }
 
    return mr;
}
/* Called from RCU critical section */
MemoryRegion *flatview_translate(FlatView *fv, hwaddr addr, hwaddr *xlat,
                                 hwaddr *plen, bool is_write,
                                 MemTxAttrs attrs)
{
    MemoryRegion *mr;
    MemoryRegionSection section;
    AddressSpace *as = NULL;
 
    /* This can be MMIO, so setup MMIO bit. */
    section = flatview_do_translate(fv, addr, xlat, plen, NULL,
                                    is_write, true, &as, attrs);
    mr = section.mr;
 
    if (xen_enabled() && memory_access_is_direct(mr, is_write, attrs)) {
        hwaddr page = ((addr & TARGET_PAGE_MASK) + TARGET_PAGE_SIZE) - addr;
        *plen = MIN(page, *plen);
    }
 
    return mr;
}
【层次化视图】MemoryRegion树形结构
system_memory (容器)
├── ram_below_4g (RAM, 0x00000000-0x7FFFFFFF, 2GB)
├── pci_memory (容器, 0x80000000-0xFFFFFFFF)
│   ├── vga_mmio (VGA设备, 0xA0000000, 16MB)
│   ├── edu_mmio (EDU设备, 0xFEBF1000, 1MB)  ← 我们的设备
│   └── e1000_mmio (网卡, 0xFEBD0000, 128KB)
└── ram_above_4g (RAM, 0x100000000+)
 
【扁平化视图】FlatView - 线性地址映射
FlatRange数组 (按地址排序):
[0] 0x00000000-0x7FFFFFFF → ram_below_4g
[1] 0x80000000-0x9FFFFFFF → (未分配)
[2] 0xA0000000-0xA0FFFFFF → vga_mmio
[3] 0xA1000000-0xFEBCFFFF → (未分配)
[4] 0xFEBD0000-0xFEBEFFFF → e1000_mmio
[5] 0xFEBF0000-0xFEBF0FFF → (gap)
[6] 0xFEBF1000-0xFEBF1FFF → edu_mmio      ← 查找目标
[7] 0xFEBF2000-0xFFFFFFFF → (未分配)
[8] 0x100000000-...       → ram_above_4g
【层次化视图】MemoryRegion树形结构
system_memory (容器)
├── ram_below_4g (RAM, 0x00000000-0x7FFFFFFF, 2GB)
├── pci_memory (容器, 0x80000000-0xFFFFFFFF)
│   ├── vga_mmio (VGA设备, 0xA0000000, 16MB)
│   ├── edu_mmio (EDU设备, 0xFEBF1000, 1MB)  ← 我们的设备
│   └── e1000_mmio (网卡, 0xFEBD0000, 128KB)
└── ram_above_4g (RAM, 0x100000000+)
 
【扁平化视图】FlatView - 线性地址映射
FlatRange数组 (按地址排序):
[0] 0x00000000-0x7FFFFFFF → ram_below_4g
[1] 0x80000000-0x9FFFFFFF → (未分配)
[2] 0xA0000000-0xA0FFFFFF → vga_mmio
[3] 0xA1000000-0xFEBCFFFF → (未分配)
[4] 0xFEBD0000-0xFEBEFFFF → e1000_mmio
[5] 0xFEBF0000-0xFEBF0FFF → (gap)
[6] 0xFEBF1000-0xFEBF1FFF → edu_mmio      ← 查找目标
[7] 0xFEBF2000-0xFFFFFFFF → (未分配)
[8] 0x100000000-...       → ram_above_4g
MemTxResult memory_region_dispatch_read(MemoryRegion *mr,
                                        hwaddr addr,
                                        uint64_t *pval,
                                        MemOp op,
                                        MemTxAttrs attrs)
{
    unsigned size = memop_size(op);
    MemTxResult r;
 
    if (mr->alias) {
        return memory_region_dispatch_read(mr->alias,
                                           mr->alias_offset + addr,
                                           pval, op, attrs);
    }
    if (!memory_region_access_valid(mr, addr, size, false, attrs)) {
        *pval = unassigned_mem_read(mr, addr, size);
        return MEMTX_DECODE_ERROR;
    }
 
    r = memory_region_dispatch_read1(mr, addr, pval, size, attrs);
    adjust_endianness(mr, pval, op);
    return r;
}
 
static MemTxResult memory_region_dispatch_read1(MemoryRegion *mr,
                                                hwaddr addr,
                                                uint64_t *pval,
                                                unsigned size,
                                                MemTxAttrs attrs)
{
    *pval = 0;
 
    if (mr->ops->read) {
        // [Step 14] 调用access_with_adjusted_size
        return access_with_adjusted_size(addr, pval, size,
                                         mr->ops->impl.min_access_size,
                                         mr->ops->impl.max_access_size,
                                         memory_region_read_accessor,
                                         mr, attrs);
    } else {
        return access_with_adjusted_size(addr, pval, size,
                                         mr->ops->impl.min_access_size,
                                         mr->ops->impl.max_access_size,
                                         memory_region_read_with_attrs_accessor,
                                         mr, attrs);
    }
}
MemTxResult memory_region_dispatch_read(MemoryRegion *mr,
                                        hwaddr addr,
                                        uint64_t *pval,
                                        MemOp op,
                                        MemTxAttrs attrs)
{
    unsigned size = memop_size(op);
    MemTxResult r;
 
    if (mr->alias) {
        return memory_region_dispatch_read(mr->alias,
                                           mr->alias_offset + addr,
                                           pval, op, attrs);
    }
    if (!memory_region_access_valid(mr, addr, size, false, attrs)) {
        *pval = unassigned_mem_read(mr, addr, size);
        return MEMTX_DECODE_ERROR;
    }
 
    r = memory_region_dispatch_read1(mr, addr, pval, size, attrs);
    adjust_endianness(mr, pval, op);
    return r;
}
 
static MemTxResult memory_region_dispatch_read1(MemoryRegion *mr,
                                                hwaddr addr,
                                                uint64_t *pval,
                                                unsigned size,
                                                MemTxAttrs attrs)
{
    *pval = 0;
 
    if (mr->ops->read) {
        // [Step 14] 调用access_with_adjusted_size
        return access_with_adjusted_size(addr, pval, size,
                                         mr->ops->impl.min_access_size,
                                         mr->ops->impl.max_access_size,
                                         memory_region_read_accessor,
                                         mr, attrs);
    } else {
        return access_with_adjusted_size(addr, pval, size,
                                         mr->ops->impl.min_access_size,
                                         mr->ops->impl.max_access_size,
                                         memory_region_read_with_attrs_accessor,
                                         mr, attrs);
    }
}
static MemTxResult access_with_adjusted_size(hwaddr addr,
                                      uint64_t *value,
                                      unsigned size,
                                      unsigned access_size_min,
                                      unsigned access_size_max,
                                      MemTxResult (*access_fn)
                                                  (MemoryRegion *mr,
                                                   hwaddr addr,
                                                   uint64_t *value,
                                                   unsigned size,
                                                   signed shift,
                                                   uint64_t mask,
                                                   MemTxAttrs attrs),
                                      MemoryRegion *mr,
                                      MemTxAttrs attrs)
{
    uint64_t access_mask;
    unsigned access_size;
    unsigned i;
    MemTxResult r = MEMTX_OK;
    bool reentrancy_guard_applied = false;
 
    if (!access_size_min) {
        access_size_min = 1;
    }
    if (!access_size_max) {
        access_size_max = 4;
    }
 
    /* Do not allow more than one simultaneous access to a device's IO Regions */
    if (mr->dev && !mr->disable_reentrancy_guard &&
        !mr->ram_device && !mr->ram && !mr->rom_device && !mr->readonly) {
        if (mr->dev->mem_reentrancy_guard.engaged_in_io) {
            warn_report_once("Blocked re-entrant IO on MemoryRegion: "
                             "%s at addr: 0x%" HWADDR_PRIX,
                             memory_region_name(mr), addr);
            return MEMTX_ACCESS_ERROR;
        }
        mr->dev->mem_reentrancy_guard.engaged_in_io = true;
        reentrancy_guard_applied = true;
    }
 
    /* FIXME: support unaligned access? */
    // 处理访问大小调整
    // 可能需要多次访问
    access_size = MAX(MIN(size, access_size_max), access_size_min);
    access_mask = MAKE_64BIT_MASK(0, access_size * 8);
    if (devend_big_endian(mr->ops->endianness)) {
        for (i = 0; i < size; i += access_size) {
             // [Step 15] 调用访问器函数
            r |= access_fn(mr, addr + i, value, access_size,
                        (size - access_size - i) * 8, access_mask, attrs);
        }
    } else {
        for (i = 0; i < size; i += access_size) {
            r |= access_fn(mr, addr + i, value, access_size, i * 8,
                        access_mask, attrs);
        }
    }
    if (mr->dev && reentrancy_guard_applied) {
        mr->dev->mem_reentrancy_guard.engaged_in_io = false;
    }
    return r;
}
static MemTxResult access_with_adjusted_size(hwaddr addr,
                                      uint64_t *value,
                                      unsigned size,
                                      unsigned access_size_min,
                                      unsigned access_size_max,
                                      MemTxResult (*access_fn)
                                                  (MemoryRegion *mr,
                                                   hwaddr addr,
                                                   uint64_t *value,
                                                   unsigned size,
                                                   signed shift,
                                                   uint64_t mask,
                                                   MemTxAttrs attrs),
                                      MemoryRegion *mr,
                                      MemTxAttrs attrs)
{
    uint64_t access_mask;
    unsigned access_size;
    unsigned i;
    MemTxResult r = MEMTX_OK;
    bool reentrancy_guard_applied = false;
 
    if (!access_size_min) {
        access_size_min = 1;
    }
    if (!access_size_max) {
        access_size_max = 4;
    }
 
    /* Do not allow more than one simultaneous access to a device's IO Regions */
    if (mr->dev && !mr->disable_reentrancy_guard &&
        !mr->ram_device && !mr->ram && !mr->rom_device && !mr->readonly) {
        if (mr->dev->mem_reentrancy_guard.engaged_in_io) {
            warn_report_once("Blocked re-entrant IO on MemoryRegion: "
                             "%s at addr: 0x%" HWADDR_PRIX,
                             memory_region_name(mr), addr);
            return MEMTX_ACCESS_ERROR;
        }
        mr->dev->mem_reentrancy_guard.engaged_in_io = true;
        reentrancy_guard_applied = true;
    }
 
    /* FIXME: support unaligned access? */
    // 处理访问大小调整
    // 可能需要多次访问
    access_size = MAX(MIN(size, access_size_max), access_size_min);
    access_mask = MAKE_64BIT_MASK(0, access_size * 8);
    if (devend_big_endian(mr->ops->endianness)) {
        for (i = 0; i < size; i += access_size) {
             // [Step 15] 调用访问器函数
            r |= access_fn(mr, addr + i, value, access_size,

[培训]Windows内核深度攻防:从Hook技术到Rootkit实战!

收藏
免费 5
支持
分享
最新回复 (3)
雪    币: 2794
活跃值: (10870)
能力值: (RANK:438 )
在线值:
发帖
回帖
粉丝
2
感谢分享
1天前
0
雪    币: 104
活跃值: (7531)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
3
tql
1天前
0
雪    币: 5784
活跃值: (9937)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
4
年底干货文章很多呀。 火钳刘明
10小时前
0
游客
登录 | 注册 方可回帖
返回