ICode9

精准搜索请尝试: 精确搜索
首页 > 其他分享> 文章详细

fuchsia中virtio 后端实现

2019-08-24 10:08:30  阅读:355  来源: 互联网

标签:virtio struct 实现 fuchsia vring uint16 used device ring


================================================涉及的其他类
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[];
};

标签:virtio,struct,实现,fuchsia,vring,uint16,used,device,ring
来源: https://blog.csdn.net/gaojy19881225/article/details/100049077

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有