【XEN学习笔记】学习授权表(Grant Tables)

【XEN学习笔记】学习授权表(Grant Tables)

分类: XEN 179人阅读 评论(0) 收藏 举报

这篇文章会用-小段代码描述以下的内容:

- 两个Domain之间的内存页共享, Doamin0和DomainU
- 在这个页中设置一个共享ring
- 为共享ring设置event channel
- 在Dom0和DomU之间来回传递一些信息

介绍

在xen中的虚拟机被称为Domain. Domain0(Dom0)是特别的并拥有与正实设备交互的设备驱动, 例如网卡.这个驱动被称为后端驱动. 在我们的例子中这被称为后端domain.

在被称为 DomainU(DomU)的用户Domain有一个相应的前端驱动, 其是虚拟设备的接口,为和真实设备通信在DomU中前端驱动要连接后端驱动. 在我们以下的例子中, 这个DomU被称为前端Domain.

Xen为共享Domain间的内存提供了授权表(Grant Tables). 设备驱动使用授权表工作. 每个Domain有它自己的授权表, 并与xen共享. 在这个表中的条目由授权引用(grant references)所标识. 授权引用在Domain间传递, 且所引用的共享页由授权表所指向, domain也设置一个共享环结构(ring structure), 其用于在domain间有郊共享数据.
对于分离前/后端驱动, 前端分配一个用于共享通信 ring 的内存页, 授权它给后端domain, 并放授权引用到xenstore,
这样后端就能 map 这个页. 有共享ring这个页是一个主页, 用于传递更多的授权引用. 共享页由块设备和其它同步接收数
据的设备所使用, 异步接收数据的网络设备, 使用已知的 page flipping 方法, 这个页的所有权在Domain 间转移.
以上图展示了这个共享ring, 这个ring所有的公有和私有指针. "Request Producer" 和 "Responser Producer"是两个公共变量, 其会被共享这个页面的两者都看到. "Response Consumer" 是一个在前端(由前端设备所维护, 即DomU) ring 结构中指针. "Request Consumer" 是一个在后端(由后端设备维护, 即Dom0) ring 结构中的指针.

API 使用

在DomU kerenl中的前端驱动广告一个页面用于共享, 这通过 hypervisor 函数调用("hypercall"), (gnttab_grant_foreign_access 系统调用)完成.  hypercall 通知 hypervisor 其它 domain 允许访问这个页. DomU然后传递引用 ID 给远端的 Domain 它是"授权"可访问的. 在我们的代码中, 这个访问授权给了 Dom0. 一但远端 domain 完成操作, 那么本地 domain 应调用gnttab_end_foreign_access删除授权.
网络设备和类似接收异步接收数据的其它设备. 使用已知的 page flipping 方法. 当 页翻转时, 在本地 domain kernel中的驱动会广告一个用于转移的页, 经由 gnttab_grant_foregin_transfer 调用完成. 这个调用会通知 hypervisor其它domain可以接收这个页. 转移给远程domain的这个本地domain执行 free page. (经由producer/consumer ring).


Domain U Code

[cpp] view plain copy
  1.   1 /* This file is run in the DomU Kernel. 
  2.   2  * It grants a page with a shared ring structure on it to the Dom0. 
  3.   3  * The grant reference and Event Channel is passed manually. Should be done via XenStore 
  4.   4  * or some other out of band mechanism. 
  5.   5  * Compile the code using 
  6.   6  * make -C /lib/modules/$(shell uname -r)/build M=$(PWD) modules 
  7.   7  * Run it as follows 
  8.   8  * insmod xen-eg.ko 
  9.   9  * Pick up the grant ref and event channel that comes out in /var/log/messages and pass as 
  10.  10  * insmod parameters in the Dom0 module. 
  11.  11  * Run the Dom0 program as follows 
  12.  12  * insmod dom0.ko domid=<domid> gref=<gref> 
  13.  13  * <domid> is the domainid of DomU as seen in "xm list" 
  14.  14  * <gref> is grant refefrence when xen.ko is insmod 
  15.  15  */  
  16.  16 #include <linux/module.h>  
  17.  17 #include <linux/kernel.h>  
  18.  18 #include <linux/types.h>  
  19.  19 #include <xen/interface/xen.h>  
  20.  20 #include <xen/interface/io/ring.h>   
  21.  21 #include <xen/grant_table.h>  
  22.  22 #include <asm/pgtable.h>  
  23.  23 #include <asm/sync_bitops.h>  
  24.  24 #include <xen/gnttab.h>  
  25.  25 #include <xen/evtchn.h>  
  26.  26 #include <asm/uaccess.h>  
  27.  27 #include <linux/proc_fs.h>  
  28.  28 int page;  
  29.  29 struct as_request {  
  30.  30     unsigned int id; /* private guest value echoed in resp */  
  31.  31     unsigned int status;  
  32.  32     unsigned int operation;  
  33.  33 };  
  34.  34 struct as_response {  
  35.  35     unsigned int  id; /* copied from request */  
  36.  36     unsigned int  status;  
  37.  37     unsigned int  operation; /* copied from request */  
  38.  38 };  
  39.  39 // The following makes the as_sring, as_back_ring, as_back_ring "types"  
  40.  40 DEFINE_RING_TYPES(as, struct as_request, struct as_response);  
  41.  41 struct info_t {  
  42.  42     struct as_front_ring   ring;  
  43.  43     grant_ref_t gref;  
  44.  44     int irq;  
  45.  45     int port;  
  46.  46 } info;  
  47.  47 #define DOM0_ID 0  
  48.  48 // Related the proc fs entries  
  49.  49 static struct proc_dir_entry *proc_dir = NULL;  
  50.  50 static struct proc_dir_entry *proc_file = NULL;  
  51.  51 char proc_data[20];  
  52.  52 /* Send an request via the shared ring to Dom0, following by an INT */  
  53.  53 int send_request_to_dom0() {  
  54.  54     struct as_request *ring_req;  
  55.  55     int notify;  
  56.  56     static int reqid=9;  
  57.  57     /* Write a request into the ring and update the req-prod pointer */  
  58.  58     ring_req = RING_GET_REQUEST(&(info.ring), info.ring.req_prod_pvt);  
  59.  59     ring_req->id = reqid;  
  60.  60     ring_req->operation = reqid;  
  61.  61     ring_req->status = reqid;  
  62.  62     printk("\nxen:DomU: Fill in IDX-%d, with id=%d, op=%d, st=%d",  
  63.  63            info.ring.req_prod_pvt, ring_req->id, ring_req->operation,  
  64.  64            ring_req->status);  
  65.  65     reqid++;  
  66.  66     info.ring.req_prod_pvt += 1;  
  67.  67     // Send a reqest to backend followed by an int if needed  
  68.  68     RING_PUSH_REQUESTS_AND_CHECK_NOTIFY(&(info.ring), notify);  
  69.  69     if (notify) {  
  70.  70         printk("\nxen:DomU: Sent a req to Dom0");  
  71.  71         notify_remote_via_irq(info.irq);  
  72.  72     } else {  
  73.  73         printk("\nxen:DomU: No notify req to Dom0");  
  74.  74         notify_remote_via_irq(info.irq);  
  75.  75     }  
  76.  76     printk("...\n");  
  77.  77     return 0;  
  78.  78 }  
  79.  79 ssize_t file_write (struct file *filp, const char __user *buff,  
  80.  80                     unsigned long len, void *data) {  
  81.  81     int value;  
  82.  82     printk("\nxen:domU: file_write %lu bytes", len);  
  83.  83     if (copy_from_user(&proc_data[0], buff, len))  
  84.  84         return -EFAULT;  
  85.  85     proc_data[len] = '\x0';  
  86.  86     // printk(" ,%s", &proc_data[0]);  
  87.  87     value = simple_strtol(proc_data, 0, 10);  
  88.  88     switch(value) {  
  89.  89         case 1:  
  90.  90             send_request_to_dom0();  
  91.  91             printk(" ,value = %d", value);  
  92.  92             break;  
  93.  93         default:  
  94.  94             printk(" ,value not recognized !");  
  95.  95     }  
  96.  96     return len;  
  97.  97 }  
  98.  98 int file_read (char* page, char**start, off_t off,  
  99.  99                int count, int *eof, void *data) {  
  100. 100     sprintf(page, "%s", proc_data);  
  101. 101     return strlen(page);  
  102. 102 }  
  103. 103    
  104. 104 /* We create a /proc/demo/file entry. When we write a "1" ino this file once 
  105. 105  * the module is loaded, the file_write function() above is called and this 
  106. 106  * sends a requesst on the shared ring to the Dom0. This way we test the 
  107. 107  * event channel and shared ring routines. 
  108. 108  */  
  109. 109 int create_procfs_entry() {  
  110. 110     int ret = 0;  
  111. 111     proc_dir = proc_mkdir("demo", NULL);  
  112. 112     if (!proc_dir) {  
  113. 113         printk("\nxen:domU Could not create demo entry in procfs");  
  114. 114         ret = -EAGAIN;  
  115. 115         return ret;  
  116. 116     }  
  117. 117     proc_file = create_proc_entry("file", 0600, proc_dir);  
  118. 118     if (proc_file) {  
  119. 119         proc_file->read_proc = file_read;  
  120. 120         proc_file->write_proc = file_write;  
  121. 121         proc_file->owner = THIS_MODULE;  
  122. 122     } else {  
  123. 123         printk("\nxen:domU Could not create /proc/demo/file");  
  124. 124         ret = -EAGAIN;  
  125. 125         return ret;  
  126. 126     }  
  127. 127     return ret;  
  128. 128 }  
  129. 129 /* Our interrupt handler for event channel that we set up */  
  130. 130 static irqreturn_t as_int (int irq, void *dev_id) {  
  131. 131     struct as_response *ring_resp;  
  132. 132     RING_IDX i, rp;  
  133. 133    
  134. 134     printk("\nxen:DomU: as_int called");  
  135. 135 again:  
  136. 136     rp = info.ring.sring->rsp_prod;  
  137. 137     printk("\nxen:DomU: ring pointers %d to %d", info.ring.rsp_cons, rp);  
  138. 138     for(i=info.ring.rsp_cons; i != rp; i++) {  
  139. 139         unsigned long id;  
  140. 140         // what did we get from Dom0  
  141. 141         ring_resp = RING_GET_RESPONSE(&(info.ring), i);  
  142. 142         printk("\nxen:DomU: Recvd in IDX-%d, with id=%d, op=%d, st=%d",  
  143. 143                i, ring_resp->id, ring_resp->operation, ring_resp->status);  
  144. 144         id = ring_resp->id;  
  145. 145         switch(ring_resp->operation) {  
  146. 146             case 0:  
  147. 147                 printk("\nxen:DomU: operation:0");  
  148. 148                 break;  
  149. 149             default:  
  150. 150                 break;  
  151. 151         }  
  152. 152     }  
  153. 153     info.ring.rsp_cons = i;  
  154. 154     if (i != info.ring.req_prod_pvt) {  
  155. 155         int more_to_do;  
  156. 156         RING_FINAL_CHECK_FOR_RESPONSES(&info.ring, more_to_do);  
  157. 157         if(more_to_do)  
  158. 158             goto again;  
  159. 159     } else  
  160. 160         info.ring.sring->rsp_event = i+1;  
  161. 161     return IRQ_HANDLED;  
  162. 162 }  
  163. 163 int init_module(void) {  
  164. 164     int mfn;  
  165. 165     int err;  
  166. 166     struct as_sring *sring;  
  167. 167     /* Allocates and returns a pointer to the first byte of a memory area 
  168. 168      * that is several physically contiguous pages long, and doesn't zero 
  169. 169      * out the area. 
  170. 170      * GFP_KERNEL - process may sleep 
  171. 171      */  
  172. 172       
  173. 173     page = __get_free_pages(GFP_KERNEL, 1);  
  174. 174     if (page == 0) {  
  175. 175         printk("\nxen:DomU: could not get free page");  
  176. 176         return 0;  
  177. 177     }  
  178. 178     /* Put a shared ring structure on this page */  
  179. 179     sring = (struct as_sring*) page;  
  180. 180     SHARED_RING_INIT(sring);       
  181. 181     /* info.ring is the front_ring structure */  
  182. 182     FRONT_RING_INIT(&(info.ring), sring, PAGE_SIZE);  
  183. 183     mfn = virt_to_mfn(page);  
  184. 184     /* The following grant table func is in drivers/xen/grant-table.c 
  185. 185      * For shared pages, used for synchronous data, advertise a page to 
  186. 186      * be shared via the hypervisor function call gnttab_grant_foreign_access. 
  187. 187      * This call notifies the hypervisor that other domains are allowed to 
  188. 188      * access this page. 
  189. 189      * gnttab_map() has been called earlier to setup gnttable_setup_table 
  190. 190      * during init phase, with a call to HYPERVISOR_grant_table_op( 
  191. 191      * GNTTAB_setup_table...) and 
  192. 192      * "shared" pages have been malloc'ed. This "shared" page is then used 
  193. 193      * below later during the actual grant of a ref by this DOM. 
  194. 194      * gnttab_grant_foreign_access() 
  195. 195      * => get_free_entries 
  196. 196      * gnttab_free_head - points to the ref of the head 
  197. 197      * gnttab_free_count- keeps number of free refs 
  198. 198      * Get a ref id by calling gnttab_entry(head) 
  199. 199      * gnttab_list[entry/RPP][entry%RPP] 
  200. 200      * => gnttab_grat_foreign_access_ref 
  201. 201      * => update_grant_entry 
  202. 202      * shared[ref].frame/domid/flags are updated 
  203. 203      * "shared" above is a pointer to struct grant_entry (flags/domid/frame) 
  204. 204      */  
  205. 205       
  206. 206     info.gref = gnttab_grant_foreign_access(DOM0_ID, mfn, 0);  
  207. 207     if (info.gref < 0) {  
  208. 208         printk("\nxen: could not grant foreign access");  
  209. 209         free_page((unsigned long)page);  
  210. 210         return 0;  
  211. 211     }  
  212. 212     /* The following strcpy is commented out, but was used initally to test 
  213. 213      * is the memory page is indeed shared with Dom0, when in Dom0, we do a 
  214. 214      * sprintf of the same memory location and get the same characters. 
  215. 215      */  
  216. 216     // strcpy((char*)page, "aseem sethi");  
  217. 217     /* TBD: Save gref to be sent via Xenstore to dom-0. As of now both the 
  218. 218      * gref and the event channel port id is sent manually during insmod 
  219. 219      * in the dom0 module. 
  220. 220      */  
  221. 221     printk("\n gref = %d", info.gref);  
  222. 222     /* Setup an event channel to Dom0 */  
  223. 223     err = bind_listening_port_to_irqhandler(DOM0_ID, as_int, 0, "xen-eg", &info);  
  224. 224     if (err < 0) {  
  225. 225         printk("\nxen:DomU failed to setup evtchn !");  
  226. 226         gnttab_end_foreign_access(info.gref, 0, page);  
  227. 227         return 0;  
  228. 228     }  
  229. 229     info.irq = err;  
  230. 230     info.port = irq_to_evtchn_port(info.irq);  
  231. 231     printk("   interupt = %d, local-port = %d", info.irq, info.port);  
  232. 232     printk("....\n...");  
  233. 233     create_procfs_entry();  
  234. 234     return 0;  
  235. 235 }  
  236. 236 void cleanup_module(void) {  
  237. 237     printk("\nCleanup grant ref:");  
  238. 238     if (gnttab_query_foreign_access(info.gref) == 0) {  
  239. 239         //Remove the grant to the page  
  240. 240         printk("\n xen: No one has mapped this frame");  
  241. 241         // If 3rd param is non NULL, page has to be freed  
  242. 242         gnttab_end_foreign_access(info.gref, 0, page);  
  243. 243         // free_pages(page,1);  
  244. 244     } else {  
  245. 245         printk("\n xen: Someone has mapped this frame");  
  246. 246         // Guess, we still free the page, since we are rmmod-ed  
  247. 247         gnttab_end_foreign_access(info.gref, 0, page);  
  248. 248     }  
  249. 249     /* Cleanup proc entry */  
  250. 250     remove_proc_entry("file", proc_dir);  
  251. 251     remove_proc_entry("demo", NULL);  
  252. 252     printk("....\n...");  
  253. 253 }  
  254. 254 MODULE_LICENSE("GPL");  
  255. 255   

Domain 0 Code
[cpp] view plain copy
  1.  1 /* This is the module in Dom0. Compile it using 
  2.   2  * make -C /lib/modules/$(shell uname -r)/build M=$(PWD) modules 
  3.   3  * Change the grant_ref below in the code to the one seen in DomU before compilation. 
  4.   4  * Insmod the module using "insmod dom-.ko gref=<vaue> port=<event channel port> 
  5.   5  * <value> is taken from the dmesg output in DomU when xen.eg.ko is insmod there. 
  6.   6  * This will map the page that the DomU has shared with the Dom0. 
  7.   7  */  
  8.   8 #include <linux/module.h>  
  9.   9 #include <linux/moduleparam.h>  
  10.  10 #include <linux/kernel.h>  
  11.  11 #include <xen/interface/grant_table.h>  
  12.  12 #include <xen/interface/io/blkif.h>  // for definition of blkif_sring_t  
  13.  13 #include <xen/gnttab.h>  
  14.  14 #include <linux/vmalloc.h>  
  15.  15 #include <asm-x86/xen/hypervisor.h>  
  16.  16 #include <xen/evtchn.h>  
  17.  17 struct gnttab_map_grant_ref   ops;  
  18.  18 struct gnttab_unmap_grant_ref unmap_ops;  
  19.  19 struct as_request {  
  20.  20     unsigned int  id;           /* private guest value, echoed in resp  */  
  21.  21     unsigned int  status;   
  22.  22     unsigned int  operation;     
  23.  23 };  
  24.  24 struct as_response {  
  25.  25     unsigned int  id;              /* copied from request */  
  26.  26     unsigned int  status;   
  27.  27     unsigned int  operation;       /* copied from request */  
  28.  28 };  
  29.  29 typedef struct as_request as_request_t;  
  30.  30 typedef struct as_response as_response_t;  
  31.  31 // From /include/xen/interface/io/ring.h  
  32.  32 // The following makes the as_sring, as_back_ring, as_back_ring "types"  
  33.  33 DEFINE_RING_TYPES(as, struct as_request, struct as_response);  
  34.  34 struct info_t {  
  35.  35     int irq;  
  36.  36     int gref;  
  37.  37     int remoteDomain;  
  38.  38     int evtchn;  
  39.  39     struct as_back_ring ring;  
  40.  40 } info;  
  41.  41 int gref;  
  42.  42 int port;  
  43.  43 module_param(gref, int, 0644);  
  44.  44 module_param(port, int, 0644);  
  45.  45 static irqreturn_t as_int (int irq, void *dev_id) {  
  46.  46     RING_IDX rc, rp;  
  47.  47     as_request_t req;  
  48.  48     as_response_t resp;  
  49.  49     int more_to_do, notify;  
  50.  50     // dev_id is a pointer to the info structure  
  51.  51     printk("\nxen:Dom0: as_int called with dev_id %x info=%x",  
  52.  52            (unsigned int)dev_id, (unsigned int)&info);  
  53.  53     rc = info.ring.req_cons;  
  54.  54     rp = info.ring.sring->req_prod;  
  55.  55     printk("  rc =%d rp =%d", rc, rp);  
  56.  56     while(rc!=rp) {  
  57.  57         if(RING_REQUEST_CONS_OVERFLOW(&info.ring, rc))  
  58.  58             break;  
  59.  59         // what did we get from the frontend at index rc  
  60.  60         memcpy(&req, RING_GET_REQUEST(&info.ring, rc), sizeof(req));  
  61.  61         resp.id = req.id;  
  62.  62         resp.operation = req.operation;  
  63.  63         resp.status = req.status+1; // Send back a status +1 of what was recvd  
  64.  64         printk("\nxen:Dom0: Recvd at IDX-%d: id=%d, op=%d, status=%d",  
  65.  65                rc, req.id, req.operation, req.status);  
  66.  66         // update the req-consumer  
  67.  67         info.ring.req_cons = ++rc;  
  68.  68         barrier();  
  69.  69         switch (req.operation) {  
  70.  70             case 0:  
  71.  71                 printk("\nxen:Dom0: req.operation = 0");  
  72.  72                 break;  
  73.  73             default:  
  74.  74                 printk("\nxen:Dom0: req.operation = %d", req.operation);  
  75.  75                 break;  
  76.  76         }  
  77.  77         memcpy(RING_GET_RESPONSE(&info.ring, info.ring.rsp_prod_pvt),  
  78.  78                &resp, sizeof(resp));  
  79.  79         info.ring.rsp_prod_pvt++;  
  80.  80         RING_PUSH_RESPONSES_AND_CHECK_NOTIFY(&info.ring, notify);  
  81.  81         if(info.ring.rsp_prod_pvt == info.ring.req_cons) {  
  82.  82             RING_FINAL_CHECK_FOR_REQUESTS(&info.ring, more_to_do);  
  83.  83         } else if (RING_HAS_UNCONSUMED_REQUESTS(&info.ring)) {  
  84.  84             more_to_do = 1;  
  85.  85         }  
  86.  86         if(notify) {  
  87.  87             printk("\nxen:Dom0: Send notify to DomU");  
  88.  88             notify_remote_via_irq(info.irq);  
  89.  89         }  
  90.  90     }  
  91.  91     return IRQ_HANDLED;  
  92.  92 }  
  93.  93 int init_module(void) {  
  94.  94     struct vm_struct *v_start;  
  95.  95     as_sring_t *sring;  
  96.  96     int err;  
  97.  97     info.gref = gref;  
  98.  98     info.remoteDomain = 1;  
  99.  99     info.evtchn = port;  
  100. 100     printk("\nxen: dom0: init_module with gref = %d", info.gref);  
  101. 101     // The following function reserves a range of kernel address space and  
  102. 102     // allocates pagetables to map that range. No actual mappings are created.  
  103. 103     v_start = alloc_vm_area(PAGE_SIZE);  
  104. 104     if (v_start == 0) {  
  105. 105         free_vm_area(v_start);  
  106. 106         printk("\nxen: dom0: could not allocate page");  
  107. 107         return -EFAULT;  
  108. 108     }  
  109. 109     /* ops struct in paramaeres 
  110. 110      * host_addr, flags, ref 
  111. 111      * ops struct out parameters 
  112. 112      * status (zero if OK), handle (used to unmap later), dev_bus_addr 
  113. 113      */  
  114. 114     gnttab_set_map_op(&ops, (unsigned long)v_start->addr, GNTMAP_host_map,  
  115. 115                       info.gref, info.remoteDomain); /* flags, ref, domID */  
  116. 116     if (HYPERVISOR_grant_table_op(GNTTABOP_map_grant_ref, &ops, 1)) {  
  117. 117         printk("\nxen: dom0: HYPERVISOR map grant ref failed");  
  118. 118         return -EFAULT;  
  119. 119     }  
  120. 120     if (ops.status) {  
  121. 121         printk("\nxen: dom0: HYPERVISOR map grant ref failed status = %d",  
  122. 122                ops.status);  
  123. 123         return -EFAULT;  
  124. 124     }  
  125. 125     printk("\nxen: dom0: shared_page = %x, handle = %x, status = %x",  
  126. 126            (unsigned int)v_start->addr, ops.handle, ops.status);  
  127. 127     // Used for unmapping  
  128. 128     unmap_ops.host_addr = (unsigned long)(v_start->addr);  
  129. 129     unmap_ops.handle = ops.handle;  
  130. 130     /* printk("\nBytes in page "); 
  131. 131        for(i=0;i<=10;i++) { 
  132. 132        printk("%c", ((char*)(v_start->addr))[i]); 
  133. 133        } */  
  134. 134     sring = (as_sring_t*)v_start->addr;  
  135. 135     BACK_RING_INIT(&info.ring, sring, PAGE_SIZE);  
  136. 136     /* Seetup an event channel to the frontend */  
  137. 137     err = bind_interdomain_evtchn_to_irqhandler(info.remoteDomain,  
  138. 138                                                 info.evtchn, as_int, 0, "dom0-backend", &info);  
  139. 139     if (err < 0) {  
  140. 140         printk("\nxen: dom0: init_module failed binding to evtchn !");  
  141. 141         err = HYPERVISOR_grant_table_op(GNTTABOP_unmap_grant_ref,  
  142. 142                                         &unmap_ops, 1);  
  143. 143         return -EFAULT;  
  144. 144     }  
  145. 145     info.irq = err;  
  146. 146     printk("\nxen: dom0: end init_module: int = %d", info.irq);  
  147. 147     return 0;  
  148. 148 }  
  149. 149 void cleanup_module(void) {  
  150. 150     int ret;  
  151. 151     printk("\nxen: dom0: cleanup_module");  
  152. 152     // Unmap foreign frames  
  153. 153     // ops.handle points to the pages that were initially mapped. Set in the  
  154. 154     // __init() function  
  155. 155     //ops.host_addr ponts to the heap where the pages were mapped  
  156. 156     ret = HYPERVISOR_grant_table_op(GNTTABOP_unmap_grant_ref, &unmap_ops, 1);  
  157. 157     if (ret == 0) {  
  158. 158         printk(" cleanup_module: unmapped shared frame");  
  159. 159     } else {  
  160. 160         printk(" cleanup_module: unmapped shared frame failed");  
  161. 161     }  
  162. 162     printk("...\n");  
  163. 163 }  
  164. 164 MODULE_LICENSE("GPL");  
  165. 165   

转自:http://blog.csdn.net/zouzhongyu/archive/2010/02/03/5283619.aspx

原文地址: http://knol.google.com/k/learning-grant-tables#


注意以上代码中的注释,这些代码并不是由特定应用程序来使用的,而是作为Domain U内核的一部分。

你可能感兴趣的:(Module,File,table,domain,Access,xen,xen)