设为首页 收藏本站
查看: 1265|回复: 0

[经验分享] xen的事件通道

[复制链接]

尚未签到

发表于 2015-10-12 07:35:02 | 显示全部楼层 |阅读模式
  在我的理解,xen的事件通道是每个guest都会拥有的一个事件的数组.
  evtchn的定义是
  

struct evtchn
{
#define ECS_FREE         0 /* Channel is available for use.                  */
#define ECS_RESERVED     1 /* Channel is reserved.                           */
#define ECS_UNBOUND      2 /* Channel is waiting to bind to a remote domain. */
#define ECS_INTERDOMAIN  3 /* Channel is bound to another domain.            */
#define ECS_PIRQ         4 /* Channel is bound to a physical IRQ line.       */
#define ECS_VIRQ         5 /* Channel is bound to a virtual IRQ line.        */
#define ECS_IPI          6 /* Channel is bound to a virtual IPI line.        */
u8  state;             /* ECS_* */
u8  xen_consumer;      /* Consumer in Xen, if any? (0 = send to guest) */
u16 notify_vcpu_id;    /* VCPU for local delivery notification */
u32 port;
union {
struct {
domid_t remote_domid;
} unbound;     /* state == ECS_UNBOUND */
struct {
u16            remote_port;
struct domain *remote_dom;
} interdomain; /* state == ECS_INTERDOMAIN */
struct {
u16            irq;
u16            next_port;
u16            prev_port;
} pirq;        /* state == ECS_PIRQ */
u16 virq;      /* state == ECS_VIRQ */
} u;
u8 priority;
u8 pending:1;
u16 last_vcpu_id;
u8 last_priority;
#ifdef FLASK_ENABLE
void *ssid;
#endif

事件通道的这个结构中,主要的参数是state(0-6),然后是与state对应的u.事件通道的作用就像它名字一样,用于通知guest有一个事件到达,u就是事件到达的一些参数(比如谁的哪个端口引起了这个事件).事件通道仅仅是达到了一种异步通知,域间通知的效果.其他具体的事情还需要其他机制来完成.  
  每个domain都会有一个事件通道数组结构
  

    /* Event channel information. */
struct evtchn   *evtchn;                         /* first bucket only */
struct evtchn  **evtchn_group[NR_EVTCHN_GROUPS]; /* all other buckets */
unsigned int     max_evtchns;
unsigned int     max_evtchn_port;
spinlock_t       event_lock;
const struct evtchn_port_ops *evtchn_port_ops;
struct evtchn_fifo_domain *evtchn_fifo;

#define BUCKETS_PER_GROUP  (PAGE_SIZE/sizeof(struct evtchn *))
/* Round size of struct evtchn up to power of 2 size */
#define __RDU2(x)   (       (x) | (   (x) >> 1))
#define __RDU4(x)   ( __RDU2(x) | ( __RDU2(x) >> 2))
#define __RDU8(x)   ( __RDU4(x) | ( __RDU4(x) >> 4))
#define __RDU16(x)  ( __RDU8(x) | ( __RDU8(x) >> 8))
#define __RDU32(x)  (__RDU16(x) | (__RDU16(x) >>16))
#define next_power_of_2(x)      (__RDU32((x)-1) + 1)
/* Maximum number of event channels for any ABI. */
#define MAX_NR_EVTCHNS MAX(EVTCHN_2L_NR_CHANNELS, EVTCHN_FIFO_NR_CHANNELS)
#define EVTCHNS_PER_BUCKET (PAGE_SIZE / next_power_of_2(sizeof(struct evtchn)))
#define EVTCHNS_PER_GROUP  (BUCKETS_PER_GROUP * EVTCHNS_PER_BUCKET)
#define NR_EVTCHN_GROUPS   DIV_ROUND_UP(MAX_NR_EVTCHNS, EVTCHNS_PER_GROUP)

MAX_NR_EVTCHNS=sizeof(ulong)^2*64=2^10  
  next_power_of_2(24)=32
  所以EVTCHNS_PER_BUCKET=4096/32=2^7
  BUCKETS_PER_GROUP=2^12/2^2=2^10
  所以现在的情况应该是总共只有一个group的事件通道.上面这些计算都是我自己弄的好玩,不一定对,可以自己动手算一算.
  只有这个结构还打不到通知的效果,还需要有一个标志位,这个标志位就在shared_info中,前面介绍共享信息页的时候介绍过了
  evtchn_pending 和evtchn_mask  表示有事件到来和这个dom屏蔽了什么时间  
  一个事件通道的大小sizeof(xen_ulong_t)*8个xen_ulong_t 刚好是2^10个bit,每个bit对应于一个事件通道.这就很合情合理了,表示其中一个事件到来这个标志位就设置为1.mask同样,如果要屏蔽相应的事件通道,设置为1.mask的设置只是影响是否通知domain,不影响evtchn_pending的设置.


  每个vcpu也有事件通道相关的结构
  
  evtchn_upcall_pending 被设置表示有事件通道需要处理 u8
  evtchn_upcall_mask  表示屏蔽所有时间通 u8
  evtchn_pending_sel 选择一组事件通道进行处理,这个值作为evtchn_pending的下标 来指示cpu去处理那一组事件 ulong
  事件通道整个结构的初始化过程在domain_create的时候进行
  int evtchn_init(struct domain *d)
{
evtchn_2l_init(d);<span style=&quot;white-space:pre&quot;></span>//设置了evtchn的端口的操作函数集合,和最多的evtchn的数量
d->max_evtchn_port = INT_MAX;
d->evtchn = alloc_evtchn_bucket(d, 0);<span style=&quot;white-space:pre&quot;></span>//分配一个组的evtchn
if ( !d->evtchn )
return -ENOMEM;
spin_lock_init(&d->event_lock);<span style=&quot;white-space:pre&quot;></span>//把第一个事件通道保留,并且设置poll_mask的cpu为所有vcpu
if ( get_free_port(d) != 0 )
{
free_evtchn_bucket(d, d->evtchn);
return -EINVAL;
}
evtchn_from_port(d, 0)->state = ECS_RESERVED;
#if MAX_VIRT_CPUS > BITS_PER_LONG
d->poll_mask = xmalloc_array(unsigned long, BITS_TO_LONGS(MAX_VIRT_CPUS));
if ( !d->poll_mask )
{
free_evtchn_bucket(d, d->evtchn);
return -ENOMEM;
}
bitmap_zero(d->poll_mask, MAX_VIRT_CPUS);
#endif
return 0;
}

这个结构就建立 起来了,然后怎么利用事件通道来通知.
  首先我们必须按事件通道的用途来给事件通道的结构填充内容(初始化只是分配了内存,这个结构还是空的)
  填充这个结构是采用超级调用HYPERVISOR_event_channel_op的方式,这是为什么说超级调用是xen的基础,不详细介绍这个超级调用,它的作用就是填写evtchn结构,即将evtchn的结构设置为0-6中的一种,并设置对应的联合体u中的&#20540;,u的&#20540;一般都是用来指示事件通道的绑定的dom的id和port,或者虚拟或物理中断号等.
  这个结构填写完了,我们就可以说说怎么来实现异步通知的了.
  任何一个dom想知道的事情,它都可以来分配一个事件通道,并且绑定这个事情.如果这个事情发生了,比如中断,会把shared_info中到达为设置为1,如果没有被屏蔽evtchn_mask没有设置为1,xen会调用一个upcall函数来设置,vcpu_info的upcall,sel位置,来指示vcpu去处理这个事情,vcpu只知道evtchn_pending的某一位需要处理,它就需要查询这个位对应的evtchn结构,它发现是某个中断发生了,中断号记录在里面,然后它就可以调用中断处理程序来处理这个中断了.xen中所有的事情(粒度至少大于cpu)的异步通知都是通过事件通道来完成的.
  这个机制并不复杂,我们只需要分配一个事件通道(需要将事件的具体描述填入这个evtchn中)
  然后事件发生就会设置事件通道的pending位表示事件发生了,dom读取pending位对应的事件来选择不同的处理方式.
  现在为止我们通过超级调用建立起了事件的通知机制
  事件通道
  ---------------------------
  超级调用

版权声明:本文为博主原创文章,未经博主允许不得转载。

运维网声明 1、欢迎大家加入本站运维交流群:群②:261659950 群⑤:202807635 群⑦870801961 群⑧679858003
2、本站所有主题由该帖子作者发表,该帖子作者与运维网享有帖子相关版权
3、所有作品的著作权均归原作者享有,请您和我们一样尊重他人的著作权等合法权益。如果您对作品感到满意,请购买正版
4、禁止制作、复制、发布和传播具有反动、淫秽、色情、暴力、凶杀等内容的信息,一经发现立即删除。若您因此触犯法律,一切后果自负,我们对此不承担任何责任
5、所有资源均系网友上传或者通过网络收集,我们仅提供一个展示、介绍、观摩学习的平台,我们不对其内容的准确性、可靠性、正当性、安全性、合法性等负责,亦不承担任何法律责任
6、所有作品仅供您个人学习、研究或欣赏,不得用于商业或者其他用途,否则,一切后果均由您自己承担,我们对此不承担任何法律责任
7、如涉及侵犯版权等问题,请您及时通知我们,我们将立即采取措施予以解决
8、联系人Email:admin@iyunv.com 网址:www.yunweiku.com

所有资源均系网友上传或者通过网络收集,我们仅提供一个展示、介绍、观摩学习的平台,我们不对其承担任何法律责任,如涉及侵犯版权等问题,请您及时通知我们,我们将立即处理,联系人Email:kefu@iyunv.com,QQ:1061981298 本贴地址:https://www.yunweiku.com/thread-125581-1-1.html 上篇帖子: Xen-network 学习笔记-2 (TechDiary-20110226) 下篇帖子: 虚拟化原理之xen-io虚拟化
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

扫码加入运维网微信交流群X

扫码加入运维网微信交流群

扫描二维码加入运维网微信交流群,最新一手资源尽在官方微信交流群!快快加入我们吧...

扫描微信二维码查看详情

客服E-mail:kefu@iyunv.com 客服QQ:1061981298


QQ群⑦:运维网交流群⑦ QQ群⑧:运维网交流群⑧ k8s群:运维网kubernetes交流群


提醒:禁止发布任何违反国家法律、法规的言论与图片等内容;本站内容均来自个人观点与网络等信息,非本站认同之观点.


本站大部分资源是网友从网上搜集分享而来,其版权均归原作者及其网站所有,我们尊重他人的合法权益,如有内容侵犯您的合法权益,请及时与我们联系进行核实删除!



合作伙伴: 青云cloud

快速回复 返回顶部 返回列表