这篇文章会用-小段代码描述以下的内容:
在xen中的虚拟机被称为Domain. Domain0(Dom0)是特别的并拥有与正实设备交互的设备驱动, 例如网卡.这个驱动被称为后端驱动. 在我们的例子中这被称为后端domain.
在被称为 DomainU(DomU)的用户Domain有一个相应的前端驱动, 其是虚拟设备的接口,为和真实设备通信在DomU中前端驱动要连接后端驱动. 在我们以下的例子中, 这个DomU被称为前端Domain.
Domain U Code
1 /* This file is run in the DomU Kernel. 2 * It grants a page with a shared ring structure on it to the Dom0. 3 * The grant reference and Event Channel is passed manually. Should be done via XenStore 4 * or some other out of band mechanism. 5 * Compile the code using 6 * make -C /lib/modules/$(shell uname -r)/build M=$(PWD) modules 7 * Run it as follows 8 * insmod xen-eg.ko 9 * Pick up the grant ref and event channel that comes out in /var/log/messages and pass as 10 * insmod parameters in the Dom0 module. 11 * Run the Dom0 program as follows 12 * insmod dom0.ko domid=<domid> gref=<gref> 13 * <domid> is the domainid of DomU as seen in "xm list" 14 * <gref> is grant refefrence when xen.ko is insmod 15 */ 16 #include <linux/module.h> 17 #include <linux/kernel.h> 18 #include <linux/types.h> 19 #include <xen/interface/xen.h> 20 #include <xen/interface/io/ring.h> 21 #include <xen/grant_table.h> 22 #include <asm/pgtable.h> 23 #include <asm/sync_bitops.h> 24 #include <xen/gnttab.h> 25 #include <xen/evtchn.h> 26 #include <asm/uaccess.h> 27 #include <linux/proc_fs.h> 28 int page; 29 struct as_request { 30 unsigned int id; /* private guest value echoed in resp */ 31 unsigned int status; 32 unsigned int operation; 33 }; 34 struct as_response { 35 unsigned int id; /* copied from request */ 36 unsigned int status; 37 unsigned int operation; /* copied from request */ 38 }; 39 // The following makes the as_sring, as_back_ring, as_back_ring "types" 40 DEFINE_RING_TYPES(as, struct as_request, struct as_response); 41 struct info_t { 42 struct as_front_ring ring; 43 grant_ref_t gref; 44 int irq; 45 int port; 46 } info; 47 #define DOM0_ID 0 48 // Related the proc fs entries 49 static struct proc_dir_entry *proc_dir = NULL; 50 static struct proc_dir_entry *proc_file = NULL; 51 char proc_data[20]; 52 /* Send an request via the shared ring to Dom0, following by an INT */ 53 int send_request_to_dom0() { 54 struct as_request *ring_req; 55 int notify; 56 static int reqid=9; 57 /* Write a request into the ring and update the req-prod pointer */ 58 ring_req = RING_GET_REQUEST(&(info.ring), info.ring.req_prod_pvt); 59 ring_req->id = reqid; 60 ring_req->operation = reqid; 61 ring_req->status = reqid; 62 printk("\nxen:DomU: Fill in IDX-%d, with id=%d, op=%d, st=%d", 63 info.ring.req_prod_pvt, ring_req->id, ring_req->operation, 64 ring_req->status); 65 reqid++; 66 info.ring.req_prod_pvt += 1; 67 // Send a reqest to backend followed by an int if needed 68 RING_PUSH_REQUESTS_AND_CHECK_NOTIFY(&(info.ring), notify); 69 if (notify) { 70 printk("\nxen:DomU: Sent a req to Dom0"); 71 notify_remote_via_irq(info.irq); 72 } else { 73 printk("\nxen:DomU: No notify req to Dom0"); 74 notify_remote_via_irq(info.irq); 75 } 76 printk("...\n"); 77 return 0; 78 } 79 ssize_t file_write (struct file *filp, const char __user *buff, 80 unsigned long len, void *data) { 81 int value; 82 printk("\nxen:domU: file_write %lu bytes", len); 83 if (copy_from_user(&proc_data[0], buff, len)) 84 return -EFAULT; 85 proc_data[len] = '\x0'; 86 // printk(" ,%s", &proc_data[0]); 87 value = simple_strtol(proc_data, 0, 10); 88 switch(value) { 89 case 1: 90 send_request_to_dom0(); 91 printk(" ,value = %d", value); 92 break; 93 default: 94 printk(" ,value not recognized !"); 95 } 96 return len; 97 } 98 int file_read (char* page, char**start, off_t off, 99 int count, int *eof, void *data) { 100 sprintf(page, "%s", proc_data); 101 return strlen(page); 102 } 103 104 /* We create a /proc/demo/file entry. When we write a "1" ino this file once 105 * the module is loaded, the file_write function() above is called and this 106 * sends a requesst on the shared ring to the Dom0. This way we test the 107 * event channel and shared ring routines. 108 */ 109 int create_procfs_entry() { 110 int ret = 0; 111 proc_dir = proc_mkdir("demo", NULL); 112 if (!proc_dir) { 113 printk("\nxen:domU Could not create demo entry in procfs"); 114 ret = -EAGAIN; 115 return ret; 116 } 117 proc_file = create_proc_entry("file", 0600, proc_dir); 118 if (proc_file) { 119 proc_file->read_proc = file_read; 120 proc_file->write_proc = file_write; 121 proc_file->owner = THIS_MODULE; 122 } else { 123 printk("\nxen:domU Could not create /proc/demo/file"); 124 ret = -EAGAIN; 125 return ret; 126 } 127 return ret; 128 } 129 /* Our interrupt handler for event channel that we set up */ 130 static irqreturn_t as_int (int irq, void *dev_id) { 131 struct as_response *ring_resp; 132 RING_IDX i, rp; 133 134 printk("\nxen:DomU: as_int called"); 135 again: 136 rp = info.ring.sring->rsp_prod; 137 printk("\nxen:DomU: ring pointers %d to %d", info.ring.rsp_cons, rp); 138 for(i=info.ring.rsp_cons; i != rp; i++) { 139 unsigned long id; 140 // what did we get from Dom0 141 ring_resp = RING_GET_RESPONSE(&(info.ring), i); 142 printk("\nxen:DomU: Recvd in IDX-%d, with id=%d, op=%d, st=%d", 143 i, ring_resp->id, ring_resp->operation, ring_resp->status); 144 id = ring_resp->id; 145 switch(ring_resp->operation) { 146 case 0: 147 printk("\nxen:DomU: operation:0"); 148 break; 149 default: 150 break; 151 } 152 } 153 info.ring.rsp_cons = i; 154 if (i != info.ring.req_prod_pvt) { 155 int more_to_do; 156 RING_FINAL_CHECK_FOR_RESPONSES(&info.ring, more_to_do); 157 if(more_to_do) 158 goto again; 159 } else 160 info.ring.sring->rsp_event = i+1; 161 return IRQ_HANDLED; 162 } 163 int init_module(void) { 164 int mfn; 165 int err; 166 struct as_sring *sring; 167 /* Allocates and returns a pointer to the first byte of a memory area 168 * that is several physically contiguous pages long, and doesn't zero 169 * out the area. 170 * GFP_KERNEL - process may sleep 171 */ 172 173 page = __get_free_pages(GFP_KERNEL, 1); 174 if (page == 0) { 175 printk("\nxen:DomU: could not get free page"); 176 return 0; 177 } 178 /* Put a shared ring structure on this page */ 179 sring = (struct as_sring*) page; 180 SHARED_RING_INIT(sring); 181 /* info.ring is the front_ring structure */ 182 FRONT_RING_INIT(&(info.ring), sring, PAGE_SIZE); 183 mfn = virt_to_mfn(page); 184 /* The following grant table func is in drivers/xen/grant-table.c 185 * For shared pages, used for synchronous data, advertise a page to 186 * be shared via the hypervisor function call gnttab_grant_foreign_access. 187 * This call notifies the hypervisor that other domains are allowed to 188 * access this page. 189 * gnttab_map() has been called earlier to setup gnttable_setup_table 190 * during init phase, with a call to HYPERVISOR_grant_table_op( 191 * GNTTAB_setup_table...) and 192 * "shared" pages have been malloc'ed. This "shared" page is then used 193 * below later during the actual grant of a ref by this DOM. 194 * gnttab_grant_foreign_access() 195 * => get_free_entries 196 * gnttab_free_head - points to the ref of the head 197 * gnttab_free_count- keeps number of free refs 198 * Get a ref id by calling gnttab_entry(head) 199 * gnttab_list[entry/RPP][entry%RPP] 200 * => gnttab_grat_foreign_access_ref 201 * => update_grant_entry 202 * shared[ref].frame/domid/flags are updated 203 * "shared" above is a pointer to struct grant_entry (flags/domid/frame) 204 */ 205 206 info.gref = gnttab_grant_foreign_access(DOM0_ID, mfn, 0); 207 if (info.gref < 0) { 208 printk("\nxen: could not grant foreign access"); 209 free_page((unsigned long)page); 210 return 0; 211 } 212 /* The following strcpy is commented out, but was used initally to test 213 * is the memory page is indeed shared with Dom0, when in Dom0, we do a 214 * sprintf of the same memory location and get the same characters. 215 */ 216 // strcpy((char*)page, "aseem sethi"); 217 /* TBD: Save gref to be sent via Xenstore to dom-0. As of now both the 218 * gref and the event channel port id is sent manually during insmod 219 * in the dom0 module. 220 */ 221 printk("\n gref = %d", info.gref); 222 /* Setup an event channel to Dom0 */ 223 err = bind_listening_port_to_irqhandler(DOM0_ID, as_int, 0, "xen-eg", &info); 224 if (err < 0) { 225 printk("\nxen:DomU failed to setup evtchn !"); 226 gnttab_end_foreign_access(info.gref, 0, page); 227 return 0; 228 } 229 info.irq = err; 230 info.port = irq_to_evtchn_port(info.irq); 231 printk(" interupt = %d, local-port = %d", info.irq, info.port); 232 printk("....\n..."); 233 create_procfs_entry(); 234 return 0; 235 } 236 void cleanup_module(void) { 237 printk("\nCleanup grant ref:"); 238 if (gnttab_query_foreign_access(info.gref) == 0) { 239 //Remove the grant to the page 240 printk("\n xen: No one has mapped this frame"); 241 // If 3rd param is non NULL, page has to be freed 242 gnttab_end_foreign_access(info.gref, 0, page); 243 // free_pages(page,1); 244 } else { 245 printk("\n xen: Someone has mapped this frame"); 246 // Guess, we still free the page, since we are rmmod-ed 247 gnttab_end_foreign_access(info.gref, 0, page); 248 } 249 /* Cleanup proc entry */ 250 remove_proc_entry("file", proc_dir); 251 remove_proc_entry("demo", NULL); 252 printk("....\n..."); 253 } 254 MODULE_LICENSE("GPL"); 255
1 /* This is the module in Dom0. Compile it using 2 * make -C /lib/modules/$(shell uname -r)/build M=$(PWD) modules 3 * Change the grant_ref below in the code to the one seen in DomU before compilation. 4 * Insmod the module using "insmod dom-.ko gref=<vaue> port=<event channel port> 5 * <value> is taken from the dmesg output in DomU when xen.eg.ko is insmod there. 6 * This will map the page that the DomU has shared with the Dom0. 7 */ 8 #include <linux/module.h> 9 #include <linux/moduleparam.h> 10 #include <linux/kernel.h> 11 #include <xen/interface/grant_table.h> 12 #include <xen/interface/io/blkif.h> // for definition of blkif_sring_t 13 #include <xen/gnttab.h> 14 #include <linux/vmalloc.h> 15 #include <asm-x86/xen/hypervisor.h> 16 #include <xen/evtchn.h> 17 struct gnttab_map_grant_ref ops; 18 struct gnttab_unmap_grant_ref unmap_ops; 19 struct as_request { 20 unsigned int id; /* private guest value, echoed in resp */ 21 unsigned int status; 22 unsigned int operation; 23 }; 24 struct as_response { 25 unsigned int id; /* copied from request */ 26 unsigned int status; 27 unsigned int operation; /* copied from request */ 28 }; 29 typedef struct as_request as_request_t; 30 typedef struct as_response as_response_t; 31 // From /include/xen/interface/io/ring.h 32 // The following makes the as_sring, as_back_ring, as_back_ring "types" 33 DEFINE_RING_TYPES(as, struct as_request, struct as_response); 34 struct info_t { 35 int irq; 36 int gref; 37 int remoteDomain; 38 int evtchn; 39 struct as_back_ring ring; 40 } info; 41 int gref; 42 int port; 43 module_param(gref, int, 0644); 44 module_param(port, int, 0644); 45 static irqreturn_t as_int (int irq, void *dev_id) { 46 RING_IDX rc, rp; 47 as_request_t req; 48 as_response_t resp; 49 int more_to_do, notify; 50 // dev_id is a pointer to the info structure 51 printk("\nxen:Dom0: as_int called with dev_id %x info=%x", 52 (unsigned int)dev_id, (unsigned int)&info); 53 rc = info.ring.req_cons; 54 rp = info.ring.sring->req_prod; 55 printk(" rc =%d rp =%d", rc, rp); 56 while(rc!=rp) { 57 if(RING_REQUEST_CONS_OVERFLOW(&info.ring, rc)) 58 break; 59 // what did we get from the frontend at index rc 60 memcpy(&req, RING_GET_REQUEST(&info.ring, rc), sizeof(req)); 61 resp.id = req.id; 62 resp.operation = req.operation; 63 resp.status = req.status+1; // Send back a status +1 of what was recvd 64 printk("\nxen:Dom0: Recvd at IDX-%d: id=%d, op=%d, status=%d", 65 rc, req.id, req.operation, req.status); 66 // update the req-consumer 67 info.ring.req_cons = ++rc; 68 barrier(); 69 switch (req.operation) { 70 case 0: 71 printk("\nxen:Dom0: req.operation = 0"); 72 break; 73 default: 74 printk("\nxen:Dom0: req.operation = %d", req.operation); 75 break; 76 } 77 memcpy(RING_GET_RESPONSE(&info.ring, info.ring.rsp_prod_pvt), 78 &resp, sizeof(resp)); 79 info.ring.rsp_prod_pvt++; 80 RING_PUSH_RESPONSES_AND_CHECK_NOTIFY(&info.ring, notify); 81 if(info.ring.rsp_prod_pvt == info.ring.req_cons) { 82 RING_FINAL_CHECK_FOR_REQUESTS(&info.ring, more_to_do); 83 } else if (RING_HAS_UNCONSUMED_REQUESTS(&info.ring)) { 84 more_to_do = 1; 85 } 86 if(notify) { 87 printk("\nxen:Dom0: Send notify to DomU"); 88 notify_remote_via_irq(info.irq); 89 } 90 } 91 return IRQ_HANDLED; 92 } 93 int init_module(void) { 94 struct vm_struct *v_start; 95 as_sring_t *sring; 96 int err; 97 info.gref = gref; 98 info.remoteDomain = 1; 99 info.evtchn = port; 100 printk("\nxen: dom0: init_module with gref = %d", info.gref); 101 // The following function reserves a range of kernel address space and 102 // allocates pagetables to map that range. No actual mappings are created. 103 v_start = alloc_vm_area(PAGE_SIZE); 104 if (v_start == 0) { 105 free_vm_area(v_start); 106 printk("\nxen: dom0: could not allocate page"); 107 return -EFAULT; 108 } 109 /* ops struct in paramaeres 110 * host_addr, flags, ref 111 * ops struct out parameters 112 * status (zero if OK), handle (used to unmap later), dev_bus_addr 113 */ 114 gnttab_set_map_op(&ops, (unsigned long)v_start->addr, GNTMAP_host_map, 115 info.gref, info.remoteDomain); /* flags, ref, domID */ 116 if (HYPERVISOR_grant_table_op(GNTTABOP_map_grant_ref, &ops, 1)) { 117 printk("\nxen: dom0: HYPERVISOR map grant ref failed"); 118 return -EFAULT; 119 } 120 if (ops.status) { 121 printk("\nxen: dom0: HYPERVISOR map grant ref failed status = %d", 122 ops.status); 123 return -EFAULT; 124 } 125 printk("\nxen: dom0: shared_page = %x, handle = %x, status = %x", 126 (unsigned int)v_start->addr, ops.handle, ops.status); 127 // Used for unmapping 128 unmap_ops.host_addr = (unsigned long)(v_start->addr); 129 unmap_ops.handle = ops.handle; 130 /* printk("\nBytes in page "); 131 for(i=0;i<=10;i++) { 132 printk("%c", ((char*)(v_start->addr))[i]); 133 } */ 134 sring = (as_sring_t*)v_start->addr; 135 BACK_RING_INIT(&info.ring, sring, PAGE_SIZE); 136 /* Seetup an event channel to the frontend */ 137 err = bind_interdomain_evtchn_to_irqhandler(info.remoteDomain, 138 info.evtchn, as_int, 0, "dom0-backend", &info); 139 if (err < 0) { 140 printk("\nxen: dom0: init_module failed binding to evtchn !"); 141 err = HYPERVISOR_grant_table_op(GNTTABOP_unmap_grant_ref, 142 &unmap_ops, 1); 143 return -EFAULT; 144 } 145 info.irq = err; 146 printk("\nxen: dom0: end init_module: int = %d", info.irq); 147 return 0; 148 } 149 void cleanup_module(void) { 150 int ret; 151 printk("\nxen: dom0: cleanup_module"); 152 // Unmap foreign frames 153 // ops.handle points to the pages that were initially mapped. Set in the 154 // __init() function 155 //ops.host_addr ponts to the heap where the pages were mapped 156 ret = HYPERVISOR_grant_table_op(GNTTABOP_unmap_grant_ref, &unmap_ops, 1); 157 if (ret == 0) { 158 printk(" cleanup_module: unmapped shared frame"); 159 } else { 160 printk(" cleanup_module: unmapped shared frame failed"); 161 } 162 printk("...\n"); 163 } 164 MODULE_LICENSE("GPL"); 165
转自:http://blog.csdn.net/zouzhongyu/archive/2010/02/03/5283619.aspx
注意以上代码中的注释,这些代码并不是由特定应用程序来使用的,而是作为Domain U内核的一部分。