Chinaunix首页 | 论坛 | 博客
  • 博客访问: 103437
  • 博文数量: 41
  • 博客积分: 2520
  • 博客等级: 少校
  • 技术积分: 440
  • 用 户 组: 普通用户
  • 注册时间: 2010-01-22 16:25
文章分类

全部博文(41)

文章存档

2010年(41)

我的朋友

分类: LINUX

2010-01-27 10:30:25

本章主要讲Xen分离设备模型中,设备的注册过程。涉及到Xenbus的具体使用方法。

1.         总线的注册

2.         驱动的注册

3.         设备的注册

 

 

Xenstore的读写。

 


 

总线的注册:

 

Xenbus有两种类型,前端总线和后端总线,分别为xenbus_frontendxenbus_backend

 

Xenbus的初始化过程:

1.         注册总线

Ø         前端总线

Ø         后端总线

2.         初始化xenstore的共享内存

3.         初始化xenstore的事件通道

4.         建立proc文件

Ø         /proc/xen/xsd_kva

Ø         /proc/xen/xsd_port

Ø         /proc/xen/xenbus

5.         初始化xenstore的接口xs_init()

Ø         绑定中断处理函数wake_waiting()xenstoreevtchn

Ø         创建内核线程[xenwatch]

Ø         创建内核线程[xenbus]

6.         注册xenbus设备 (用处?)

Ø         前端设备

Ø         后端设备

 

 

 

#ifdef CONFIG_XEN

postcore_initcall(xenbus_probe_init);

MODULE_LICENSE("Dual BSD/GPL");

#else

int xenbus_init(void)

{

                   return xenbus_probe_init();

}

#endif

 

static int xenbus_probe_init(void)

{

                   int err = 0;

                   unsigned long page = 0;

 

                   DPRINTK("");

 

                   if (!is_running_on_xen())

                                     return -ENODEV;

 

                   /* Register ourselves with the kernel bus subsystem */

                   xenbus_frontend.error = bus_register(&xenbus_frontend.bus);    // 注册前端bus_type

                   if (xenbus_frontend.error)

                                     printk(KERN_WARNING

                                            "XENBUS: Error registering frontend bus: %i\n",

                                            xenbus_frontend.error);

              xenbus_backend_bus_register();                                                            // 注册后端bus_type

 

                   /*

                    * Domain0 doesn't have a store_evtchn or store_mfn yet.

                    */ 在这时,dom0还没有进行xenstore的初始化,即没有evtchnmfn

                   if (is_initial_xendomain()) {

                                     struct evtchn_alloc_unbound alloc_unbound;

 

                                     /* Allocate page. */

                                     page = get_zeroed_page(GFP_KERNEL);                   // 分配页面

                                     if (!page)

                                                        return -ENOMEM;

 

                                     xen_store_mfn = xen_start_info->store_mfn = // 初始化xenstore的共享内存

以后用xenstore表现为xen_store_interfacexb_read()/xb_write()

 

三个全局变量需要设置:xen_store_evtchn, xen_store_mfn, xen_store_interface

                                                        pfn_to_mfn(virt_to_phys((void *)page) >>                  // 1.虚拟地址转换为物理地址

                                                                              PAGE_SHIFT);                      // 2.获得物理页框

                                                                                                                                                     // 3.转换为机器页框

                                     /* Next allocate a local port which xenstored can bind to */

                                     alloc_unbound.dom        = DOMID_SELF;          // 从自己分配一个port

                                     alloc_unbound.remote_dom = 0;                                                      // 开放给dom0

 

                                     err = HYPERVISOR_event_channel_op(EVTCHNOP_alloc_unbound,

                                                                                                                  &alloc_unbound); // hypercall分配

                                     if (err == -ENOSYS)

                                                        goto err;

                                     BUG_ON(err);

                                     xen_store_evtchn = xen_start_info->store_evtchn =

                                                        alloc_unbound.port;

 

#if defined(CONFIG_PROC_FS) && defined(CONFIG_XEN_PRIVILEGED_GUEST)

                                     /* And finally publish the above info in /proc/xen */

                                     xsd_kva_intf = create_xen_proc_entry("xsd_kva", 0600);

                                     if (xsd_kva_intf) {

                                                        memcpy(&xsd_kva_fops, xsd_kva_intf->proc_fops,

                                                               sizeof(xsd_kva_fops));

                                                        xsd_kva_fops.mmap = xsd_kva_mmap;

                                                        xsd_kva_intf->proc_fops = &xsd_kva_fops;

                                                        xsd_kva_intf->read_proc = xsd_kva_read;

                                     }

                                     xsd_port_intf = create_xen_proc_entry("xsd_port", 0400);

                                     if (xsd_port_intf)

                                                        xsd_port_intf->read_proc = xsd_port_read;

#endif

                            xen_store_interface = mfn_to_virt(xen_store_mfn);  // xenstore虚拟地址

                   } else {

                                     xenstored_ready = 1;                  // 如果不是初始化

#ifdef CONFIG_XEN

                                     xen_store_evtchn = xen_start_info->store_evtchn;

                                     xen_store_mfn = xen_start_info->store_mfn;

                                     xen_store_interface = mfn_to_virt(xen_store_mfn);

#else

                                     xen_store_evtchn = hvm_get_parameter(HVM_PARAM_STORE_EVTCHN);

                                     xen_store_mfn = hvm_get_parameter(HVM_PARAM_STORE_PFN);

                                     xen_store_interface = ioremap(xen_store_mfn << PAGE_SHIFT,

                                                                                                   PAGE_SIZE);

#endif

                   }

 

 

                   xenbus_dev_init();    // 创建/proc/xen/xenbus

 

                   /* Initialize the interface to xenstore. */

                   err = xs_init();

                   if (err) {

                                     printk(KERN_WARNING

                                            "XENBUS: Error initializing xenstore comms: %i\n", err);

                                     goto err;

                   }

 

                   /* Register ourselves with the kernel device subsystem */

                   if (!xenbus_frontend.error) {

                            xenbus_frontend.error = device_register(&xenbus_frontend.dev);

                                     if (xenbus_frontend.error) {

                                                        bus_unregister(&xenbus_frontend.bus);

                                                        printk(KERN_WARNING

                                                               "XENBUS: Error registering frontend device: %i\n",

                                                               xenbus_frontend.error);

                                     }

                   }

              xenbus_backend_device_register();

 

                   if (!is_initial_xendomain())

                                     xenbus_probe(NULL);

 

                   return 0;

 

 err:

                   if (page)

                                     free_page(page);

 

                   /*

                    * Do not unregister the xenbus front/backend buses here. The buses

                    * must exist because front/backend drivers will use them when they are

                    * registered.

                    */

 

                   return err;

}

 

void xenbus_backend_bus_register(void)

{

                   xenbus_backend.error = bus_register(&xenbus_backend.bus);

                   if (xenbus_backend.error)

                                     printk(KERN_WARNING

                                            "XENBUS: Error registering backend bus: %i\n",

                                            xenbus_backend.error);

}

 

void xenbus_backend_device_register(void)

{

                   if (xenbus_backend.error)

                                     return;

 

                   xenbus_backend.error = device_register(&xenbus_backend.dev);

                   if (xenbus_backend.error) {

                                     bus_unregister(&xenbus_backend.bus);

                                     printk(KERN_WARNING

                                            "XENBUS: Error registering backend device: %i\n",

                                            xenbus_backend.error);

                   }

}

 

int xenbus_dev_init(void)

{

                   xenbus_dev_intf = create_xen_proc_entry("xenbus", 0400);

                   if (xenbus_dev_intf)

                                     xenbus_dev_intf->proc_fops = &xenbus_dev_file_ops;

 

                   return 0;

}

 


 

int xs_init(void)

{

                   int err;

                   struct task_struct *task;

 

                   INIT_LIST_HEAD(&xs_state.reply_list);

                   spin_lock_init(&xs_state.reply_lock);

                   init_waitqueue_head(&xs_state.reply_waitq);

 

                   mutex_init(&xs_state.request_mutex);

                   mutex_init(&xs_state.response_mutex);

                   init_rwsem(&xs_state.transaction_mutex);

                   init_rwsem(&xs_state.watch_mutex);

 

                   /* Initialize the shared memory rings to talk to xenstored */

                   err = xb_init_comms();

                   if (err)

                                     return err;

 

                   task = kthread_run(xenwatch_thread, NULL, "xenwatch");    // 创建内核线程[xenwatch]

                   if (IS_ERR(task))

                                     return PTR_ERR(task);

                   xenwatch_pid = task->pid;

 

                   task = kthread_run(xenbus_thread, NULL, "xenbus");             // 创建内核线程[xenbus]

                   if (IS_ERR(task))

                                     return PTR_ERR(task);

 

                   return 0;

}

 

/* Set up interrupt handler off store event channel. */

int xb_init_comms(void)

{

                   struct xenstore_domain_interface *intf = xen_store_interface; // xenstore内存页虚拟地址

                   int err;

 

                   if (intf->req_prod != intf->req_cons)

                                     printk(KERN_ERR "XENBUS request ring is not quiescent "

                                            "(%08x:%08x)!\n", intf->req_cons, intf->req_prod);

                                                                           // 如果请求的生产者和消费者不等,为什么不重新设置为相等?

                   if (intf->rsp_prod != intf->rsp_cons) {

                                     printk(KERN_WARNING "XENBUS response ring is not quiescent "

                                            "(%08x:%08x): fixing up\n",

                                            intf->rsp_cons, intf->rsp_prod);

                                     intf->rsp_cons = intf->rsp_prod;                // 消费的生产者和消费者可能会重新设置。

                   }

 

                   if (xenbus_irq)

                                     unbind_from_irqhandler(xenbus_irq, &xb_waitq);

 

                   err = bind_caller_port_to_irqhandler(

                                     xen_store_evtchn, wake_waiting,     // wake_waiting将唤醒xb_waitq

                                     0, "xenbus", &xb_waitq);

                   if (err <= 0) {

                                     printk(KERN_ERR "XENBUS request irq failed %i\n", err);

                                     return err;

                   }

 

                   xenbus_irq = err;

 

                   return 0;

}

 

int bind_caller_port_to_irqhandler(

                   unsigned int caller_port,

                   irqreturn_t (*handler)(int, void *, struct pt_regs *),

                   unsigned long irqflags,

                   const char *devname,

                   void *dev_id)

1.         分配一个随机的IRQ,并将xenstoreevtchn绑定到它。

2.         设置此IRQ的中断处理函数。

{

                   int irq, retval;

 

                   irq = bind_caller_port_to_irq(caller_port);

                   if (irq < 0)

                                     return irq;

 

                   retval = request_irq(irq, handler, irqflags, devname, dev_id);

                   if (retval != 0) {

                                     unbind_from_irq(irq);

                                     return retval;

                   }

 

                   return irq;

}

 

static int bind_caller_port_to_irq(unsigned int caller_port)

{

                   int irq;

 

                   spin_lock(&irq_mapping_update_lock);

 

                   if ((irq = evtchn_to_irq[caller_port]) == -1) {

                                     if ((irq = find_unbound_irq()) < 0)

                                                        goto out;

 

                                     evtchn_to_irq[caller_port] = irq;            // 设置全局的evtchn <-> IRQ映射表

                                     irq_info[irq] = mk_irq_info(IRQT_CALLER_PORT, 0, caller_port);

                   }

 

                   irq_bindcount[irq]++;

 

 out:

                   spin_unlock(&irq_mapping_update_lock);

                   return irq;

}

 

static int find_unbound_irq(void)

{

                   static int warned;

                   int irq;

 

                   for (irq = DYNIRQ_BASE; irq < (DYNIRQ_BASE + NR_DYNIRQS); irq++)

                                     if (irq_bindcount[irq] == 0)       // 寻找一个未使用的随机IRQ

                                                        return irq;

 

                   if (!warned) {

                                     warned = 1;

                                     printk(KERN_WARNING "No available IRQ to bind to: "

                                            "increase NR_DYNIRQS.\n");

                   }

 

                   return -ENOSPC;

}

 

/* IRQ <-> event-channel mappings. */

static int evtchn_to_irq[NR_EVENT_CHANNELS] = {

                   [0 ...  NR_EVENT_CHANNELS-1] = -1 };

 

 

 

 

static irqreturn_t wake_waiting(int irq, void *unused, struct pt_regs *regs)

{

                   if (unlikely(xenstored_ready == 0)) {

                                     xenstored_ready = 1;

                                     schedule_work(&probe_work);

                   }

 

              wake_up(&xb_waitq);                     // 唤醒等待队列xb_waitq上的处理

                   return IRQ_HANDLED;

}

阅读(1762) | 评论(0) | 转发(0) |
0

上一篇:Xen Event Channel (3)

下一篇:Xenbus (2)

给主人留下些什么吧!~~