vbus机制分析

 

1.概述

moe通过解析uvmm.tmgr来启动io进程和vm虚拟机进程。在uvmm.tmgr脚本中会将io.cfg和vm_pass.vbus文件(双虚拟机会有两个vbus文件)作为参数传递给io进程解析;另外,会将与vm虚拟机对应的vbus的能力权限传递给vm虚拟机。Uvmm在初始化时,会获取对应的vbus能力权限,通过IPC与io server服务端通信来获取整个vbus总线设备,并保存在本地变量_devices中。在uvmm解析dtb文件,并尝试与vbus总线设备进行匹配时,还会通过IPC与io server进行交互,来获取设备资源、兼容性等信息。下面分三个小节分别讲述io.cfg文件、vm_pass.vbus文件的解析过程以及uvmm中vbus总线初始化。

2.构建物理设备树(io.cfg文件解析)

Io进程中构建的物理设备树,是一个两层结构,如下图:

根节点是一个名字为“System Bus”的Hw::Root_bus类型的设备,其子节点为Hw::Device类型的各个设备,如VGIC、VSPI等。每个子节点又包含一系列的属性和资源。相关类图如下:

根节点类Hw::Root_bus继承自Hw::Device,其在构造函数里会初始化根节点的irq、mmio及io资源,同时注册各种资源类型的request和alloc方法。

子节点是Hw::Device类型,它从Device_tree_mixin类继承了设备树相关成员及方法(包括增加子节点、获取next节点、遍历设备树等),从Generic_device类继承了属性(Property)、资源(Resource)的相关方法及成员。

Device_factory是一个工厂类,用于收集各种设备创建的方法,保存在静态变量_factories中,其定义如下:

typedef cxx::Avl_map<std::string, Device_factory *> Name_map;

static Name_map _factories;

Device_factory_t类继承自Device_factory,用于注册工厂方法,并提供了create接口用于创建设备。目前,zeos中注册了如下工厂方法:

static Device_factory_t<Device> __hw_pf_factory("Device");

static Hw::Device_factory_t<Gpio_bcm2835_chip> __hw_pf_factory("Gpio_bcm2835_chip");

static Hw::Device_factory_t<Scm_omap> __hw_scm_factory("Scm_omap");

static Hw::Device_factory_t<Pci_iomem_root_bridge>

              __hw_pci_root_bridge_factory("Pci_iomem_root_bridge");

 

static Hw::Device_factory_t<Gpio_omap_chip<Omap3_gpio>>

       __hw_gpio_omap35x_factory("Gpio_omap35x_chip");

static Hw::Device_factory_t<Gpio_omap_chip<Omap4_gpio>>

       __hw_gpio_omap44x_factory("Gpio_omap44x_chip");

static Hw::Device_factory_t<Gpio_omap_chip<Omap5_gpio>>

       __hw_gpio_omap54x_factory("Gpio_omap54x_chip");

 

物理设备树的构造过程主要分为以下几步:

  1. 构建根节点“System Bus”

Io进程会解析io.cfg文件,通过解释执行其中的lua代码来构建一颗完整的物理设备树。其中根节点的构建是通过Io.system_bus()函数实现的。其调用关系如下:

Io.system_bus()——》_wrap_system_bus——》(Hw::Device *)system_bus()——》Hw::Root_bus *hw_system_bus()——》Hw::Root_bus _sb("System Bus")

  1. 依次创建各子节点,如VGIC、VSPI等

子节点的构建则通过Io.Hw.Device函数。系统中并没有直接定义Io.Hw.Device函数,而是定义了table——Io.Hw = {},并把table(Io.Hw)的元表的__index属性设置为function,如下表:

Io.Hw = {}

setmetatable(Io.Hw, { __index = function (self, t)

  return function (data)

    local b = check_device(Io.Hw_dev_factory_create(t), 3, "could not create device: " .. t)  //创建设备

    if type(data) == "function" then

      add_children(b, data)     //添加叶节点

    end

    return b                  //返回带资源信息的Device节点

  end

end})

这样,Device会作为实参传给t;更进一步使用“Io.Hw.Device(function()”调用时,Device的参数function会作为其内部闭包“function (data)”的data参数传入。

设备创建

调用关系为:Io.Hw_dev_factory_create——》_wrap_Hw_dev_factory_create——》

_wrap_Hw_dev_factory_create__SWIG_1——》Hw::Device_factory::create(“Device”),最终会调用静态注册好的工厂——“__hw_pf_factory”创建好设备并赋值给本地变量b。

添加叶节点

通过调用add_children函数(同Io.Dt.add_children函数),将设备的Property和Resource 填充到本地变量d。然后,调用Io.Dt.add_device_data函数将d添加到上一步创建的设备的叶节点中。

  1. 将各子节点加入根节点“System Bus”

通过调用Io.Dt.add_children函数,将各子节点(VGIC、VSPI等)加入根节点“System Bus”。这一步的lua脚本中还涉及到一个lua的关键语法“upvalue”的概念,详请参考我的另一个文档——“vbus机制之lua代码注释.docx”。

至此,物理设备树已经构建完成。

3.Vbus虚拟设备树构建(vm_pass.vbus文件解析)

Vbus虚拟设备树可以有1条或者多条,其子节点通过字符串(可以提供多个)与物理设备树的hid属性进行匹配,返回所有匹配的设备,加入根节点。一个字符串同样可以匹配多个设备。其结构图大致如下:

注意:vm_pass.vbus中定义的子节点名(如VGIC、VSPI等)同io.cfg中定义的子节点名(如VGIC、VSPI等)一样,都只是别名,并不必须存在一一对应关系。而真正的对应关系是通过hid属性匹配的结果。

Vbus虚拟设备树创建过程涉及的类图如下:

根节点类Virtual_sbus继承自Vi::System_bus,其主要作用是通过物理设备树构建一个静态的Platform_control类实例pfc,在将pfc传给Vi::System_bus的构造函数,完成自身的构造。Platform_control类是一个电源管理类,这里不讨论。

Vbus的核心类是Vi::System_bus,它继承了众多类的属性,如Device(虚拟设备类,包含了设备和树节点的相关属性和方法)、Dev_feature(提供设备feature的虚拟接口)、L4::Epiface_t(IPC相关接口类,这里不讨论)、Inhibitor_provider(为vbus之间通信提供接口)和Vbus_event_source(vbus事件机制)。另外,它还包含几个内部类:Root_resource_factory(提供创建root资源对象的工厂)、Root_resource_factory_t(继承自Root_resource_factory,实现create方法)和Res_cmp(资源比较)。

Dev_factory类为一个工厂类,其Name_map类型的静态变量_name_map用于搜集创建Vbus的根节点的工厂方法。其两个子类,则用于注册工厂方法,并分别实现其do_match和vcreate方法。目前系统中静态变量 _name_map中定义的工厂有:

static Vi::Dev_factory_t<Virtual_sbus> __sb_root_factory("System_bus");

static Dev_factory_t<Gpio, Hw::Gpio_device> __gpio_factory;

static Dev_factory_t<Pci_dummy> __pci_dummy_factory("PCI_dummy_device");

static Dev_factory_t<Pci_to_pci_bridge> __pci_to_pci_factory("PCI_PCI_bridge");

static Dev_factory_t<Pci_vroot> __pci_root_factory("PCI_bus");

static Dev_factory_t<Proxy_dev, Hw::Device> __ghwdf;

 

Vbus虚拟设备树创建步骤大致如下:

  1. 创建根节点“System_bus

在vm_pass.vbus脚本文件中,通过Io.Vi.System_bus(function()…end)函数创建根节点。Io.Vi.System_bus的定义同样使用了元表,参见io.cfg解析过程:

Io.Vi = {}

setmetatable(Io.Vi, { __index = function (self, t)  //System_bus作为t传入,其后“function()…end”作为data传入

  return function (data)

    local b = Io.Vi_dev_factory_create(t)  //创建虚拟设备(System_bus)

    if type(data) == "function" then

      add_children(b, data)             //添加子节点

    elseif type(data) == "table" then

      set_dev_data(b, data)

    end

    return b

  end

end})

其调用关系为:Io.Vi_dev_factory_create(System_bus)——》_wrap_Vi_dev_factory_create——》_wrap_Vi_dev_factory_create__SWIG_0——》Vi::Dev_factory::create(System_bus)。此处create函数会调用系统中静态注册的工厂—— __sb_root_factory”,创建Virtual_sbus类型的根节点。

  1. 创建子节点如VGIC、VSPI等

这一步会遍历io.cfg解析过程中生成的硬件设备树,调用其match_cid方法,找到与提供的字符串(如"arm-gicc")匹配的所有设备(如果有多个匹配,则将其命名为类似VGIC[1]、VGIC[2]),并生成一个table返回。详细lua流程可参见“vbus机制之lua代码注释.docx”。

  1. 将各子节点加入根节点“System_bus

调用add_children将各子节点依次加入到根节点。

  1. 将vbus注册到server列表中

Vbus注册到server列表后就可以为uvmm提供服务了。

4.uvmm中vbus总线初始化:

Uvmm中在解析dtb文件之前会调用create_default_devices函数,创建一些默认设备,其中就包括vbus的初始化,主要步骤如下:

  1. 获取vbus能力权限
  2. 创建vbus对象,构造函数中会通过IPC获取vbus所有设备,并保存在本地变量_devices中。

在uvmm中根据dtb创建设备流程中,查找匹配设备会调用Virt_bus::find_unassigned_dev方法,还会涉及与Io Server的IPC交互过程。

 

 

  • 0
    点赞
  • 8
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值