fuchsia中virtio 后端实现

================================================涉及的其他类
class PciDevice
PCI设备基类,存储pci设备状态,提供ReadBar、WriteBar虚接口函数。
ReadConfig
    ReadConfigWord //读配置空间寄存器
WriteConfig //写配置寄存器空间
Interrupt //如果有pci pending中断则调用pcibus的中断处理
    bus_->Interrupt
set_capabilities
SetupBarTraps
    guest->CreateMapping //将bar的地址空间加入到guest的IoMappingList中,并设置访问trap为ZX_GUEST_TRAP_MEM(陷出).同时设置IoHandler为PciBar(实现Read和Write函数)
ReadConfigWord //从pci配置空间读取4字节对齐的值
ReadCapability
FindCapability

class PciBus
继承自PlatformDevice,成员变量包含:guest_(虚拟机)、config_addr_(pci配置空间)、device_(包含的pcidevice)、interrupt_controller_(中断控制器)、mmio_base_(mmio基地址)等
Interrupt
    interrupt_controller_->Interrupt //调用中断控制器的中断处理(arm64为gic distributer)
ConfigureDtb //判断dtb中是否与pci-host-ecam-generic兼容的配置

class VirtioPci
VirtioPci //利用传入的VirtioDeviceConfig对象,初始化device_config_成员和父类的Attributes成员
ReadBar //只处理BAR0;
    ConfigBarRead
WriteBar
    ConfigBarWrite //BAR0,pcibar
    NotifyBarWrite //BAR1,notifybar
        device_config_->notify_queue //貌似virtionet中直接返回ZX_OK
add_isr_flags //Sets the given flags in the ISR register
// ISR flag values.
enum IsrFlags : uint8_t {
    // Interrupt is caused by a queue.
    ISR_QUEUE = 1 << 0,
    // Interrupt is caused by a device config change.
    ISR_CONFIG = 1 << 1,
};
ConfigBarRead
    CommonCfgRead //通用配置读取
    value->u8 = isr_status_;//中断状态配置
    kVirtioPciDeviceCfgBase//Device-specific configuration
ConfigBarWrite //对common cfg和device specific cfg进行写配置
CommonCfgRead //通用配置读取,偏移从0x0~0x34
CommonCfgWrite
NotifyBarWrite
SetupCaps
queue_sel

struct VirtioDeviceConfig {
  mutable std::mutex mutex;

  // Virtio device ID.
  const uint16_t device_id = 0;

  // Virtio device features.
  const uint32_t device_features = 0;

  // Pointer to device configuration.
  void* config __TA_GUARDED(mutex) = nullptr;

  // Number of bytes used for this device's configuration space.
  const uint64_t config_size = 0;

  // Virtio queues for this device.
  VirtioQueueConfig* const queue_configs __TA_GUARDED(mutex) = nullptr;

  // Number of Virtio queues.
  const uint16_t num_queues = 0;

  // Invoked when the driver has made a change to the queue configuration.
  using ConfigQueueFn =
      fit::function<zx_status_t(uint16_t queue, uint16_t size, zx_gpaddr_t desc,
                                zx_gpaddr_t avail, zx_gpaddr_t used)>;
  const ConfigQueueFn config_queue;

  // Invoked when the driver sends notifications on a queue to the device.
  using NotifyQueueFn = fit::function<zx_status_t(uint16_t queue)>;
  const NotifyQueueFn notify_queue;

  // Invoked when the driver has made a change to the device configuration.
  using ConfigDeviceFn =
      fit::function<zx_status_t(uint64_t addr, const IoValue& value)>;
  const ConfigDeviceFn config_device;

  // Invoked when the driver has accepted features and set the device into a
  // 'Ready' state.
  using ReadyDeviceFn =
      fit::function<zx_status_t(uint32_t negotiated_features)>;
  const ReadyDeviceFn ready_device;
};

static constexpr uint16_t kDefaultVirtioQueueSize = 128;
struct VirtioQueueConfig
{
  union {
    struct {
      uint64_t desc;
      uint64_t avail;
      uint64_t used;
    };

    // Software will access these using 32 bit operations. Provide a
    // convenience interface for these use cases.
    uint32_t words[6] = {};
  };

  uint16_t size = kDefaultVirtioQueueSize;
}

===========
class VirtioQueue
VirtioQueue::VirtioQueue //创建event_对象
VirtioQueue::Configure //配置ring的size、描述符表、可用ring和已用ring。used_event_addr指向可用ring的后面2字节;avail_event_addr指向已用ring的后面2个字节(event是怎么分配的?与used ring和available ring正好相反!?)
VirtioQueue::NextChain //根据”可用ring项“构造VirtioChain对象返回
VirtioQueue::NextAvailLocked //获取下一个可用ring索引;更新avail_event(什么时候用??);如果没有可用ring,则调用event_.signal(SIGNAL_QUEUE_AVAIL, 0)发送ZX_USER_SIGNAL_0的清除信号(原型:signal(uint32_t clear_mask, uint32_t set_mask))
VirtioQueue::Notify //有可用ring时,调用event_.signal(0, SIGNAL_QUEUE_AVAIL)(通知前端?)
VirtioQueue::ReadDesc //取出guest的desc地址,映射到本地
VirtioQueue::Return //将index和len填入used ring,更新idx+1;如果use_event_index_为0,且ring_.used->flags为0则注入中断,否则如果ring_.used_event有值,且used->idx和used_event值相等则注入中断。

class VirtioChain
VirtioChain::NextDescriptor //调用VirtioQueue的ReadDesc
VirtioChain::Return //调用VirtioQueue的Return

struct VirtioDescriptor:virtio描述符结构体,包含了vring_desc的信息和更高层次的抽象。
// A higher-level API for vring_desc.
struct VirtioDescriptor {
  // Pointer to the buffer in our address space.
  void* addr;
  // Number of bytes at addr.
  uint32_t len;
  // Only valid if has_next is true.
  // TODO(abdulla): Remove this.
  uint16_t next;
  // Is there another buffer after this one?
  // TODO(abdulla): Remove this.
  bool has_next;
  // If true, this buffer must only be written to (no reads). Otherwise this
  // buffer must only be read from (no writes).
  bool writable;
};

struct VirtioRing:包含vring的抽象
// Stores the Virtio queue based on the ring provided by the guest.
// NOTE(abdulla): This structure points to guest-controlled memory.
struct VirtioRing {
  // Number of entries in the descriptor table.
  uint16_t size;
  uint16_t index; //指示当前处理的desc的idx

  const struct vring_desc* desc;  // guest-controlled

  const struct vring_avail* avail;  // guest-controlled
  const uint16_t* used_event;       // guest-controlled

  struct vring_used* used;  // guest-controlled
  uint16_t* avail_event;    // guest-controlled
};

========vring(虚拟队列)
每个虚拟队列由3部分组成:
1.描述符表
2.可用环
3.已用环
说明:描述符表只有一个,但是可以由多个描述符指向的buffer构成一个list(或者叫chain),而这个list可以从描述符表任意一个desc作为head开始(目前实现中list长度为1,并没利用起来)。
struct vring {
    uint32_t num;
    uint32_t num_mask;

    uint16_t free_list; /* head of a free list of descriptors per ring. 0xffff is NULL */
    uint16_t free_count;

    uint16_t last_used;

    struct vring_desc* desc;

    struct vring_avail* avail;

    struct vring_used* used;
};

/* This marks a buffer as continuing via the next field. */
#define VRING_DESC_F_NEXT 1
/* This marks a buffer as write-only (otherwise read-only). */
#define VRING_DESC_F_WRITE 2
/* This means the buffer contains a list of buffer descriptors. */
#define VRING_DESC_F_INDIRECT 4
/* Virtio ring descriptors: 16 bytes.  These can chain together via "next". */
struct vring_desc {
    /* Address (guest-physical). */
    uint64_t addr;
    /* Length. */
    uint32_t len;
    /* The flags as indicated above. */
    uint16_t flags;
    /* We chain unused descriptors via this, too */
    uint16_t next;
};

struct vring_avail {
    uint16_t flags;
    uint16_t idx;
    uint16_t ring[];
};

/* u32 is used here for ids for padding reasons. */
struct vring_used_elem {
    /* Index of start of used descriptor chain. */
    uint32_t id;
    /* Total length of the descriptor chain which was used (written to) */
    uint32_t len;
};
struct vring_used {
    uint16_t flags;
    uint16_t idx;
    struct vring_used_elem ring[];
};

上一篇:使用瑞萨R5F10368做一个简单的温度采集和电流采集


下一篇:http下载1