分类: LINUX
2010-01-27 10:30:25
本章主要讲Xen分离设备模型中,设备的注册过程。涉及到Xenbus的具体使用方法。
1. 总线的注册
2. 驱动的注册
3. 设备的注册
Xenstore的读写。
总线的注册:
Xenbus有两种类型,前端总线和后端总线,分别为xenbus_frontend和xenbus_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()到xenstore的evtchn
Ø 创建内核线程[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的初始化,即没有evtchn和mfn
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_interface。xb_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);
}
}
{
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,并将xenstore的evtchn绑定到它。
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;
}