• Virtio Over MMIO


    该文是通过对virtio-1.2官方文档翻译生成的,文档的下载地址为: http://docs.oasis-open.org/virtio/virtio/v1.2/

    4.2 Virtio Over MMIO

    Virtual environments without PCI support (a common situation in embedded devices models) might use simple memory mapped device (“virtio-mmio”) instead of the PCI device.
    不支持PCI的虚拟环境(嵌入式设备模型中的常见情况)可能使用简单的内存映射设备(“virtio-mmio”)取代PCI设备。
    The memory mapped virtio device behaviour is based on the PCI device specification. Therefore most operations including device initialization, queues configuration and buffer transfers are nearly identical. Existing differences are described in the following sections.
    内存映射的virtio设备行为是基于PCI设备规范的。因此,包括设备初始化、队列配置和缓冲区传输在内的大多数操作几乎都是相同的。现有的差异将在下面的部分中进行描述。

    4.2.1 MMIO Device Discovery

    Unlike PCI, MMIO provides no generic device discovery mechanism. For each device, the guest OS will need to know the location of the registers and interrupt(s) used. The suggested binding for systems using flattened device trees is shown in this example:
    与PCI不同,MMIO不提供通用的设备发现机制。对于每个设备,guest操作系统将需要知道所使用的寄存器和中断的位置。使用扁平设备树的系统的建议绑定如下:

    // EXAMPLE: virtio_block device taking 512 bytes at 0x1e000, interrupt 42.
    virtio_block@1e000 {
            compatible = "virtio,mmio";
    		reg = <0x1e000 0x200>;
    		interrupts = <42>;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6

    4.2.2 MMIO Device Register Layout

    MMIO virtio devices provide a set of memory mapped control registers followed by a device-specific configuration space, described in the table 4.1.
    MMIO virtio设备提供了一组内存映射的控制寄存器,然后是一组设备特定的配置空间,详见表4.1。
    All register values are organized as Little Endian.
    所有的寄存器值都被组织为小端。
    MagicValue 0x000: Magic value 0x74726976 (a Little Endian equivalent of the “virt” string)
    Version 0x004:Device version number 0x2
    Note: Legacy devices (see 4.2.4 Legacy interface) used 0x1.
    遗留设备(见4.2.4遗留接口)使用了0x1。
    DeviceID 0x008:Virtio Subsystem Device ID
    See 5 Device Types for possible values. Value zero (0x0) is used to define a system memory map with placeholder devices at static, well known addresses, assigning functions to them depending on user’s needs
    有关可能的值,请参见5个设备类型。值0(0x0)用于定义一个系统内存映射,其中具有静态占位符设备的知名地址,并根据用户的需要为它们分配函数。
    VendorID 0x00c:Virtio Subsystem Vendor ID
    DeviceFeatures 0x010:Flags representing features the device supports
    Reading from this register returns 32 consecutive flag bits, the least significant bit depending on the last value written to DeviceFeaturesSel. Access to this register returns bits DeviceFeaturesSel * 32 to (DeviceFeaturesSel * 32)+31, eg. feature bits 0 to 31 if DeviceFeaturesSel is set to 0 and features
    bits 32 to 63 if DeviceFeaturesSel is set to 1. Also see 2.2 Feature Bits.
    DeviceFeaturesSel 0x014:Device (host) features word selection.
    Writing to this register selects a set of 32 device feature bits accessible by reading from DeviceFeatures.
    DriverFeatures 0x020:Flags representing device features understood and activated by the
    driver
    Writing to this register sets 32 consecutive flag bits, the least significant bit depending on the last value written to DriverFeaturesSel. Access to this register sets bits DriverFeaturesSel ∗ 32 to (DriverFeaturesSel ∗ 32) + 31, eg. feature bits 0 to 31 if DriverFeaturesSel is set to 0 and features bits 32 to 63 if DriverFeaturesSel is set to 1. Also see 2.2 Feature Bits.
    DriverFeaturesSel 0x024:Activated (guest) features word selection
    Writing to this register selects a set of 32 activated feature bits accessible by writing to DriverFeatures.
    QueueSel 0x030:Virtual queue index
    Writing to this register selects the virtual queue that the following operations on QueueNumMax, QueueNum, QueueReady, QueueDescLow, QueueDescHigh, QueueDriverlLow, QueueDriverHigh, QueueDeviceLow, QueueDeviceHigh and QueueReset apply to. The index number of the first queue is zero (0x0).
    QueueNumMax 0x034:Maximum virtual queue size
    Reading from the register returns the maximum size (number of elements) of the queue the device is ready to process or zero (0x0) if the queue is not available. This applies to the queue selected by writing to QueueSel.
    QueueNum 0x038:Virtual queue size
    Queue size is the number of elements in the queue. Writing to this register notifies the device what size of the queue the driver will use. This applies to the queue selected by writing to QueueSel.
    QueueReady 0x044:Virtual queue ready bit
    Writing one (0x1) to this register notifies the device that it can execute re- quests from this virtual queue. Reading from this register returns the last value written to it. Both read and write accesses apply to the queue selected by writing to QueueSel.
    QueueNotify 0x050:Queue notifier
    Writing a value to this register notifies the device that there are new buffers to process in a queue.
    When VIRTIO_F_NOTIFICATION_DATA has not been negotiated, the value written is the queue index.
    When VIRTIO_F_NOTIFICATION_DATA has been negotiated, the Notifi- cation data value has the following format:

    le32 {
    	vqn : 16;
    	next_off : 15;
    	next_wrap : 1;
    };
    
    • 1
    • 2
    • 3
    • 4
    • 5

    See 2.9 Driver Notifications for the definition of the components.
    InterruptStatus 0x60:Interrupt status
    Reading from this register returns a bit mask of events that caused the de- vice interrupt to be asserted. The following events are possible:
    Used Buffer Notification - bit 0 - the interrupt was asserted because the device has used a buffer in at least one of the active virtual queues.
    Configuration Change Notification - bit 1 - the interrupt was asserted be- cause the configuration of the device has changed.
    InterruptACK 0x064:Interrupt acknowledge
    Writing a value with bits set as defined in InterruptStatus to this register notifies the device that events causing the interrupt have been handled.
    Status 0x070:Device status
    Reading from this register returns the current device status flags. Writing non-zero values to this register sets the status flags, indicating the driver progress. Writing zero (0x0) to this register triggers a device reset. See also p. 4.2.3.1 Device Initialization.
    QueueDescLow 0x080
    QueueDescHigh 0x084:Virtual queue’s Descriptor Area 64 bit long physical address
    Writing to these two registers (lower 32 bits of the address to QueueDescLow, higher 32 bits to QueueDescHigh) notifies the device about location of the Descriptor Area of the queue selected by writing to QueueSel register.
    QueueDriverLow 0x090
    QueueDriverHigh 0x094:Virtual queue’s Driver Area 64 bit long physical address
    Writing to these two registers (lower 32 bits of the address to QueueDriver- Low, higher 32 bits to QueueDriverHigh) notifies the device about location of the Driver Area of the queue selected by writing to QueueSel.
    QueueDeviceLow 0x0a0
    QueueDeviceHigh 0x0a4:Virtual queue’s Device Area 64 bit long physical address
    Writing to these two registers (lower 32 bits of the address to QueueDe- viceLow, higher 32 bits to QueueDeviceHigh) notifies the device about lo- cation of the Device Area of the queue selected by writing to QueueSel.
    SHMSel 0x0ac:Shared memory id
    Writing to this register selects the shared memory region 2.10 following op- erations on SHMLenLow, SHMLenHigh, SHMBaseLow and SHMBaseHigh apply to.
    SHMLenLow 0x0b0
    SHMLenHigh 0x0b4:Shared memory region 64 bit long length
    These registers return the length of the shared memory region in bytes, as defined by the device for the region selected by the SHMSel register. The lower 32 bits of the length are read from SHMLenLow and the higher 32 bits from SHMLenHigh. Reading from a non-existent region (i.e. where the ID written to SHMSel is unused) results in a length of - 1.
    SHMBaseLow 0x0b8
    SHMBaseHigh 0x0bc:Shared memory region 64 bit long physical address
    The driver reads these registers to discover the base address of the region in physical address space. This address is chosen by the device (or other part of the VMM). The lower 32 bits of the address are read from SHMBaseLow with the higher 32 bits from SHMBaseHigh. Reading from a non-existent region (i.e. where the ID written to SHMSel is unused) results in a base
    address of 0xffffffffffffffff.
    QueueReset 0x0c0:Virtual queue reset bit
    If VIRTIO_F_RING_RESET has been negotiated, writing one (0x1) to this register selectively resets the queue. Both read and write accesses apply to the queue selected by writing to QueueSel.
    ConfigGeneration 0x0fc:Configuration atomicity value
    Reading from this register returns a value describing a version of the device- specific configuration space (see Config). The driver can then access the configuration space and, when finished, read ConfigGeneration again. If no part of the configuration space has changed between these two ConfigGen- eration reads, the returned values are identical. If the values are different, the configuration space accesses were not atomic and the driver has to perform the operations again. See also 2.5.
    Config 0x100:Configuration space
    Device-specific configuration space starts at the offset 0x100 and is ac- cessed with byte alignment. Its meaning and size depend on the device and the driver.

    4.2.2.1 Device Requirements: MMIO Device Register Layout

    The device MUST return 0x74726976 in MagicValue.
    The device MUST return value 0x2 in Version.
    The device MUST present each event by setting the corresponding bit in InterruptStatus from the moment it takes place, until the driver acknowledges the interrupt by writing a corresponding bit mask to the Inter- ruptACK register. Bits which do not represent events which took place MUST be zero.
    Upon reset, the device MUST clear all bits in InterruptStatus and ready bits in the QueueReady register for all queues in the device.
    The device MUST change value returned in ConfigGeneration if there is any risk of a driver seeing an inconsistent configuration state.
    The device MUST NOT access virtual queue contents when QueueReady is zero (0x0). If VIRTIO_F_RING_RESET has been negotiated, the device MUST present a 0 in QueueReset on reset.
    If VIRTIO_F_RING_RESET has been negotiated, The device MUST present a 0 in QueueReset after the virtqueue is enabled with QueueReady.
    The device MUST reset the queue when 1 is written to QueueReset. The device MUST continue to present 1 in QueueReset as long as the queue reset is ongoing. The device MUST present 0 in both QueueReset and QueueReady when queue reset has completed. (see 2.6.1).

    4.2.2.2 Driver Requirements: MMIO Device Register Layout

    The driver MUST NOT access memory locations not described in the table 4.1 (or, in case of the configuration space, described in the device specification), MUST NOT write to the read-only registers (direction R) and MUST NOT read from the write-only registers (direction W).
    The driver MUST only use 32 bit wide and aligned reads and writes to access the control registers described in table 4.1. For the device-specific configuration space, the driver MUST use 8 bit wide accesses for 8 bit
    wide fields, 16 bit wide and aligned accesses for 16 bit wide fields and 32 bit wide and aligned accesses for 32 and 64 bit wide fields.
    The driver MUST ignore a device with MagicValue which is not 0x74726976, although it MAY report an error. The driver MUST ignore a device with Version which is not 0x2, although it MAY report an error. The driver MUST ignore a device with DeviceID 0x0, but MUST NOT report any error.
    Before reading from DeviceFeatures, the driver MUST write a value to DeviceFeaturesSel.
    Before writing to the DriverFeatures register, the driver MUST write a value to the DriverFeaturesSel register.
    The driver MUST write a value to QueueNum which is less than or equal to the value presented by the device in QueueNumMax.
    When QueueReady is not zero, the driver MUST NOT access QueueNum, QueueDescLow, QueueDescHigh, QueueDriverLow, QueueDriverHigh, QueueDeviceLow, QueueDeviceHigh.
    To stop using the queue the driver MUST write zero (0x0) to this QueueReady and MUST read the value back to ensure synchronization.
    The driver MUST ignore undefined bits in InterruptStatus.
    The driver MUST write a value with a bit mask describing events it handled into InterruptACK when it finishes handling an interrupt and MUST NOT set any of the undefined bits in the value.
    If VIRTIO_F_RING_RESET has been negotiated, after the driver writes 1 to QueueReset to reset the queue, the driver MUST NOT consider queue reset to be complete until it reads back 0 in QueueReset. The driver MAY re-enable the queue by writing 1 to QueueReady after ensuring that other virtqueue fields have been set up correctly. The driver MAY set driver-writeable queue configuration values to different values than those that were used before the queue reset. (see 2.6.1).

    4.2.3 MMIO-specific Initialization And Device Operation

    4.2.3.1 Device Initialization

    4.2.3.1.1 Driver Requirements: Device Initialization

    The driver MUST start the device initialization by reading and checking values from MagicValue and Version. If both values are valid, it MUST read DeviceID and if its value is zero (0x0) MUST abort initialization and MUST NOT access any other register.
    Drivers not expecting shared memory MUST NOT use the shared memory registers.
    Further initialization MUST follow the procedure described in 3.1 Device Initialization.

    4.2.3.2 Virtqueue Configuration

    The driver will typically initialize the virtual queue in the following way:

    1. Select the queue writing its index (first queue is 0) to QueueSel.
    2. Check if the queue is not already in use: read QueueReady, and expect a returned value of zero (0x0).
    3. Read maximum queue size (number of elements) from QueueNumMax. If the returned value is zero (0x0) the queue is not available.
    4. Allocate and zero the queue memory, making sure the memory is physically contiguous.
    5. Notify the device about the queue size by writing the size to QueueNum.
    6. Write physical addresses of the queue’s Descriptor Area, Driver Area and Device Area to (respectively) the QueueDescLow/QueueDescHigh, QueueDriverLow/QueueDriverHigh and QueueDeviceLow/QueueDeviceHigh register pairs.
    7. Write 0x1 to QueueReady.

    4.2.3.3 Available Buffer Notifications

    When VIRTIO_F_NOTIFICATION_DATA has not been negotiated, the driver sends an available buffer no- tification to the device by writing the 16-bit virtqueue index of the queue to be notified to QueueNotify.
    When VIRTIO_F_NOTIFICATION_DATA has been negotiated, the driver sends an available buffer notifica- tion to the device by writing the following 32-bit value to QueueNotify:

    le32 {
    	vqn : 16;
    	next_off : 15;
    	next_wrap : 1;
    };
    
    • 1
    • 2
    • 3
    • 4
    • 5

    See 2.9 Driver Notifications for the definition of the components.

    4.2.3.4 Notifications From The Device

    The memory mapped virtio device is using a single, dedicated interrupt signal, which is asserted when at least one of the bits described in the description of InterruptStatus is set. This is how the device sends a used buffer notification or a configuration change notification to the device.

    4.2.3.4.1 Driver Requirements: Notifications From The Device

    After receiving an interrupt, the driver MUST read InterruptStatus to check what caused the interrupt (see the register description). The used buffer notification bit being set SHOULD be interpreted as a used buffer notification for each active virtqueue. After the interrupt is handled, the driver MUST acknowledge it by writing a bit mask corresponding to the handled events to the InterruptACK register.

    4.2.4 Legacy interface

    The legacy MMIO transport used page-based addressing, resulting in a slightly different control register layout, the device initialization and the virtual queue configuration procedure.
    Table 4.2 presents control registers layout, omitting descriptions of registers which did not change their function nor behaviour:
    在这里插入图片描述
    在这里插入图片描述
    The virtual queue page size is defined by writing to GuestPageSize, as written by the guest. The driver does this before the virtual queues are configured.
    The virtual queue layout follows p. 2.7.2 Legacy Interfaces: A Note on Virtqueue Layout, with the alignment defined in QueueAlign.
    The virtual queue is configured as follows:

    1. Select the queue writing its index (first queue is 0) to QueueSel.
    2. Check if the queue is not already in use: read QueuePFN, expecting a returned value of zero (0x0).
    3. Read maximum queue size (number of elements) from QueueNumMax. If the returned value is zero (0x0) the queue is not available.
    4. Allocate and zero the queue pages in contiguous virtual memory, aligning the Used Ring to an opti- mal boundary (usually page size). The driver should choose a queue size smaller than or equal to QueueNumMax.
    5. Notify the device about the queue size by writing the size to QueueNum.
    6. Notify the device about the used alignment by writing its value in bytes to QueueAlign.
    7. Write the physical number of the first page of the queue to the QueuePFN register.
      Notification mechanisms did not change.
  • 相关阅读:
    pytorch案例代码-2
    阿里开源的Java诊断利器Arthas
    Hadoop中的MapReduce框架原理、Job提交流程源码断点在哪断并且介绍相关源码、切片与MapTask并行度决定机制、MapTask并行度决定机制
    鸡尾酒学习——环游世界
    简易介绍如何使用淘宝商品详情 API(关键词搜索商品列表API)
    如何看待PMP的2022年11月新考纲?
    使用U3D、pico开发VR(一)——将unity的场景在设备中呈现
    这些软件可以快速实现图片翻译文字
    前端 JS 安全对抗原理与实践
    服务器重置实例后的部署工作
  • 原文地址:https://blog.csdn.net/u014100559/article/details/126755023