]>
Commit | Line | Data |
---|---|---|
7c673cae FG |
1 | /*- |
2 | * BSD LICENSE | |
3 | * | |
4 | * Copyright(c) 2010-2014 Intel Corporation. All rights reserved. | |
5 | * All rights reserved. | |
6 | * | |
7 | * Redistribution and use in source and binary forms, with or without | |
8 | * modification, are permitted provided that the following conditions | |
9 | * are met: | |
10 | * | |
11 | * * Redistributions of source code must retain the above copyright | |
12 | * notice, this list of conditions and the following disclaimer. | |
13 | * * Redistributions in binary form must reproduce the above copyright | |
14 | * notice, this list of conditions and the following disclaimer in | |
15 | * the documentation and/or other materials provided with the | |
16 | * distribution. | |
17 | * * Neither the name of Intel Corporation nor the names of its | |
18 | * contributors may be used to endorse or promote products derived | |
19 | * from this software without specific prior written permission. | |
20 | * | |
21 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS | |
22 | * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT | |
23 | * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR | |
24 | * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT | |
25 | * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, | |
26 | * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT | |
27 | * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, | |
28 | * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY | |
29 | * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT | |
30 | * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE | |
31 | * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | |
32 | */ | |
33 | ||
34 | #include <stdint.h> | |
35 | #include <unistd.h> | |
36 | #include <inttypes.h> | |
37 | #include <errno.h> | |
38 | #include <fcntl.h> | |
39 | #include <sys/ioctl.h> | |
40 | #include <sys/mman.h> | |
41 | #include <xen/sys/gntalloc.h> | |
42 | #include <xen/sys/gntdev.h> | |
43 | #include <xen/xen-compat.h> | |
44 | #if __XEN_LATEST_INTERFACE_VERSION__ < 0x00040200 | |
45 | #include <xs.h> | |
46 | #else | |
47 | #include <xenstore.h> | |
48 | #endif | |
49 | ||
50 | #include <rte_common.h> | |
51 | #include <rte_memory.h> | |
52 | #include <rte_eal.h> | |
53 | #include <rte_malloc.h> | |
54 | #include <rte_string_fns.h> | |
55 | #include <rte_log.h> | |
56 | #include <rte_debug.h> | |
57 | ||
58 | #include "xen_vhost.h" | |
59 | ||
60 | /* xenstore handle */ | |
61 | static struct xs_handle *xs = NULL; | |
62 | ||
63 | /* gntdev file descriptor to map grant pages */ | |
64 | static int d_fd = -1; | |
65 | ||
66 | /* | |
67 | * The grant node format in xenstore for vring/mpool is like: | |
68 | * idx#_rx_vring_gref = "gref1#, gref2#, gref3#" | |
69 | * idx#_mempool_gref = "gref1#, gref2#, gref3#" | |
70 | * each gref# is the grant reference for a shared page. | |
71 | * In each shared page, we store the grant_node_item items. | |
72 | */ | |
73 | struct grant_node_item { | |
74 | uint32_t gref; | |
75 | uint32_t pfn; | |
76 | } __attribute__((packed)); | |
77 | ||
78 | int cmdline_parse_etheraddr(void *tk, const char *srcbuf, | |
79 | void *res, unsigned ressize); | |
80 | ||
81 | /* Map grant ref refid at addr_ori*/ | |
82 | static void * | |
83 | xen_grant_mmap(void *addr_ori, int domid, int refid, uint64_t *pindex) | |
84 | { | |
85 | struct ioctl_gntdev_map_grant_ref arg; | |
86 | void *addr = NULL; | |
87 | int pg_sz = getpagesize(); | |
88 | ||
89 | arg.count = 1; | |
90 | arg.refs[0].domid = domid; | |
91 | arg.refs[0].ref = refid; | |
92 | ||
93 | int rv = ioctl(d_fd, IOCTL_GNTDEV_MAP_GRANT_REF, &arg); | |
94 | if (rv) { | |
95 | RTE_LOG(ERR, XENHOST, " %s: (%d,%d) %s (ioctl failed)\n", __func__, | |
96 | domid, refid, strerror(errno)); | |
97 | return NULL; | |
98 | } | |
99 | ||
100 | if (addr_ori == NULL) | |
101 | addr = mmap(addr_ori, pg_sz, PROT_READ|PROT_WRITE, MAP_SHARED, | |
102 | d_fd, arg.index); | |
103 | else | |
104 | addr = mmap(addr_ori, pg_sz, PROT_READ|PROT_WRITE, MAP_SHARED | MAP_FIXED, | |
105 | d_fd, arg.index); | |
106 | ||
107 | if (addr == MAP_FAILED) { | |
108 | RTE_LOG(ERR, XENHOST, " %s: (%d, %d) %s (map failed)\n", __func__, | |
109 | domid, refid, strerror(errno)); | |
110 | return NULL; | |
111 | } | |
112 | ||
113 | if (pindex) | |
114 | *pindex = arg.index; | |
115 | ||
116 | return addr; | |
117 | } | |
118 | ||
119 | /* Unmap one grant ref, and munmap must be called before this */ | |
120 | static int | |
121 | xen_unmap_grant_ref(uint64_t index) | |
122 | { | |
123 | struct ioctl_gntdev_unmap_grant_ref arg; | |
124 | int rv; | |
125 | ||
126 | arg.count = 1; | |
127 | arg.index = index; | |
128 | rv = ioctl(d_fd, IOCTL_GNTDEV_UNMAP_GRANT_REF, &arg); | |
129 | if (rv) { | |
130 | RTE_LOG(ERR, XENHOST, " %s: index 0x%" PRIx64 "unmap failed\n", __func__, index); | |
131 | return -1; | |
132 | } | |
133 | return 0; | |
134 | } | |
135 | ||
136 | /* | |
137 | * Reserve a virtual address space. | |
138 | * On success, returns the pointer. On failure, returns NULL. | |
139 | */ | |
140 | static void * | |
141 | get_xen_virtual(size_t size, size_t page_sz) | |
142 | { | |
143 | void *addr; | |
144 | uintptr_t aligned_addr; | |
145 | ||
146 | addr = mmap(NULL, size + page_sz, PROT_READ, MAP_SHARED | MAP_ANONYMOUS, -1, 0); | |
147 | if (addr == MAP_FAILED) { | |
148 | RTE_LOG(ERR, XENHOST, "failed get a virtual area\n"); | |
149 | return NULL; | |
150 | } | |
151 | ||
152 | aligned_addr = RTE_ALIGN_CEIL((uintptr_t)addr, page_sz); | |
153 | munmap(addr, aligned_addr - (uintptr_t)addr); | |
154 | munmap((void *)(aligned_addr + size), page_sz + (uintptr_t)addr - aligned_addr); | |
155 | addr = (void *)(aligned_addr); | |
156 | ||
157 | return addr; | |
158 | } | |
159 | ||
160 | static void | |
161 | free_xen_virtual(void *addr, size_t size, size_t page_sz __rte_unused) | |
162 | { | |
163 | if (addr) | |
164 | munmap(addr, size); | |
165 | } | |
166 | ||
167 | /* | |
168 | * Returns val str in xenstore. | |
169 | * @param path | |
170 | * Full path string for key | |
171 | * @return | |
172 | * Pointer to Val str, NULL on failure | |
173 | */ | |
174 | static char * | |
175 | xen_read_node(char *path, uint32_t *len) | |
176 | { | |
177 | char *buf; | |
178 | ||
179 | buf = xs_read(xs, XBT_NULL, path, len); | |
180 | return buf; | |
181 | } | |
182 | ||
183 | static int | |
184 | cal_pagenum(struct xen_gnt *gnt) | |
185 | { | |
186 | unsigned int i; | |
187 | /* | |
188 | * the items in the page are in the format of | |
189 | * gref#,pfn#,...,gref#,pfn# | |
190 | * FIXME, 0 is reserved by system, use it as terminator. | |
191 | */ | |
192 | for (i = 0; i < (PAGE_PFNNUM) / 2; i++) { | |
193 | if (gnt->gref_pfn[i * 2].gref <= 0) | |
194 | break; | |
195 | } | |
196 | ||
197 | return i; | |
198 | } | |
199 | ||
200 | /* Frees memory allocated to a grant node */ | |
201 | static void | |
202 | xen_free_gntnode(struct xen_gntnode *gntnode) | |
203 | { | |
204 | if (gntnode == NULL) | |
205 | return; | |
206 | free(gntnode->gnt_info); | |
207 | free(gntnode); | |
208 | } | |
209 | ||
210 | /* | |
211 | * Parse a grant node. | |
212 | * @param domid | |
213 | * Guest domain id. | |
214 | * @param path | |
215 | * Full path string for a grant node, like for the following (key, val) pair | |
216 | * idx#_mempool_gref = "gref#, gref#, gref#" | |
217 | * path = 'local/domain/domid/control/dpdk/idx#_mempool_gref' | |
218 | * gref# is a shared page contain packed (gref,pfn) entries | |
219 | * @return | |
220 | * Returns the pointer to xen_gntnode | |
221 | */ | |
222 | static struct xen_gntnode * | |
223 | parse_gntnode(int dom_id, char *path) | |
224 | { | |
225 | char **gref_list = NULL; | |
226 | uint32_t i, len, gref_num; | |
227 | void *addr = NULL; | |
228 | char *buf = NULL; | |
229 | struct xen_gntnode *gntnode = NULL; | |
230 | struct xen_gnt *gnt = NULL; | |
231 | int pg_sz = getpagesize(); | |
232 | char *end; | |
233 | uint64_t index; | |
234 | ||
235 | if ((buf = xen_read_node(path, &len)) == NULL) | |
236 | goto err; | |
237 | ||
238 | gref_list = malloc(MAX_GREF_PER_NODE * sizeof(char *)); | |
239 | if (gref_list == NULL) | |
240 | goto err; | |
241 | ||
242 | gref_num = rte_strsplit(buf, len, gref_list, MAX_GREF_PER_NODE, | |
243 | XEN_GREF_SPLITTOKEN); | |
244 | if (gref_num == 0) { | |
245 | RTE_LOG(ERR, XENHOST, " %s: invalid grant node format\n", __func__); | |
246 | goto err; | |
247 | } | |
248 | ||
249 | gntnode = calloc(1, sizeof(struct xen_gntnode)); | |
250 | gnt = calloc(gref_num, sizeof(struct xen_gnt)); | |
251 | if (gnt == NULL || gntnode == NULL) | |
252 | goto err; | |
253 | ||
254 | for (i = 0; i < gref_num; i++) { | |
255 | errno = 0; | |
256 | gnt[i].gref = strtol(gref_list[i], &end, 0); | |
257 | if (errno != 0 || end == NULL || end == gref_list[i] || | |
258 | (*end != '\0' && *end != XEN_GREF_SPLITTOKEN)) { | |
259 | RTE_LOG(ERR, XENHOST, " %s: parse grant node item failed\n", __func__); | |
260 | goto err; | |
261 | } | |
262 | addr = xen_grant_mmap(NULL, dom_id, gnt[i].gref, &index); | |
263 | if (addr == NULL) { | |
264 | RTE_LOG(ERR, XENHOST, " %s: map gref %u failed\n", __func__, gnt[i].gref); | |
265 | goto err; | |
266 | } | |
267 | RTE_LOG(INFO, XENHOST, " %s: map gref %u to %p\n", __func__, gnt[i].gref, addr); | |
268 | memcpy(gnt[i].gref_pfn, addr, pg_sz); | |
269 | if (munmap(addr, pg_sz)) { | |
270 | RTE_LOG(INFO, XENHOST, " %s: unmap gref %u failed\n", __func__, gnt[i].gref); | |
271 | goto err; | |
272 | } | |
273 | if (xen_unmap_grant_ref(index)) { | |
274 | RTE_LOG(INFO, XENHOST, " %s: release gref %u failed\n", __func__, gnt[i].gref); | |
275 | goto err; | |
276 | } | |
277 | ||
278 | } | |
279 | ||
280 | gntnode->gnt_num = gref_num; | |
281 | gntnode->gnt_info = gnt; | |
282 | ||
283 | free(buf); | |
284 | free(gref_list); | |
285 | return gntnode; | |
286 | ||
287 | err: | |
288 | free(gnt); | |
289 | free(gntnode); | |
290 | free(gref_list); | |
291 | free(buf); | |
292 | return NULL; | |
293 | } | |
294 | ||
295 | /* | |
296 | * This function maps grant node of vring or mbuf pool to a continous virtual address space, | |
297 | * and returns mapped address, pfn array, index array | |
298 | * @param gntnode | |
299 | * Pointer to grant node | |
300 | * @param domid | |
301 | * Guest domain id | |
302 | * @param ppfn | |
303 | * Pointer to pfn array, caller should free this array | |
304 | * @param pgs | |
305 | * Pointer to number of pages | |
306 | * @param ppindex | |
307 | * Pointer to index array, used to release grefs when to free this node | |
308 | * @return | |
309 | * Pointer to mapped virtual address, NULL on failure | |
310 | */ | |
311 | static void * | |
312 | map_gntnode(struct xen_gntnode *gntnode, int domid, uint32_t **ppfn, uint32_t *pgs, uint64_t **ppindex) | |
313 | { | |
314 | struct xen_gnt *gnt; | |
315 | uint32_t i, j; | |
316 | size_t total_pages = 0; | |
317 | void *addr; | |
318 | uint32_t *pfn; | |
319 | uint64_t *pindex; | |
320 | uint32_t pfn_num = 0; | |
321 | int pg_sz; | |
322 | ||
323 | if (gntnode == NULL) | |
324 | return NULL; | |
325 | ||
326 | pg_sz = getpagesize(); | |
327 | for (i = 0; i < gntnode->gnt_num; i++) { | |
328 | gnt = gntnode->gnt_info + i; | |
329 | total_pages += cal_pagenum(gnt); | |
330 | } | |
331 | if ((addr = get_xen_virtual(total_pages * pg_sz, pg_sz)) == NULL) { | |
332 | RTE_LOG(ERR, XENHOST, " %s: failed get_xen_virtual\n", __func__); | |
333 | return NULL; | |
334 | } | |
335 | pfn = calloc(total_pages, (size_t)sizeof(uint32_t)); | |
336 | pindex = calloc(total_pages, (size_t)sizeof(uint64_t)); | |
337 | if (pfn == NULL || pindex == NULL) { | |
338 | free_xen_virtual(addr, total_pages * pg_sz, pg_sz); | |
339 | free(pfn); | |
340 | free(pindex); | |
341 | return NULL; | |
342 | } | |
343 | ||
344 | RTE_LOG(INFO, XENHOST, " %s: total pages:%zu, map to [%p, %p]\n", __func__, total_pages, addr, RTE_PTR_ADD(addr, total_pages * pg_sz - 1)); | |
345 | for (i = 0; i < gntnode->gnt_num; i++) { | |
346 | gnt = gntnode->gnt_info + i; | |
347 | for (j = 0; j < (PAGE_PFNNUM) / 2; j++) { | |
348 | if ((gnt->gref_pfn[j * 2].gref) <= 0) | |
349 | goto _end; | |
350 | /*alternative: batch map, or through libxc*/ | |
351 | if (xen_grant_mmap(RTE_PTR_ADD(addr, pfn_num * pg_sz), | |
352 | domid, | |
353 | gnt->gref_pfn[j * 2].gref, | |
354 | &pindex[pfn_num]) == NULL) { | |
355 | goto mmap_failed; | |
356 | } | |
357 | pfn[pfn_num] = gnt->gref_pfn[j * 2 + 1].pfn_num; | |
358 | pfn_num++; | |
359 | } | |
360 | } | |
361 | ||
362 | mmap_failed: | |
363 | if (pfn_num) | |
364 | munmap(addr, pfn_num * pg_sz); | |
365 | for (i = 0; i < pfn_num; i++) { | |
366 | xen_unmap_grant_ref(pindex[i]); | |
367 | } | |
368 | free(pindex); | |
369 | free(pfn); | |
370 | return NULL; | |
371 | ||
372 | _end: | |
373 | if (ppindex) | |
374 | *ppindex = pindex; | |
375 | else | |
376 | free(pindex); | |
377 | if (ppfn) | |
378 | *ppfn = pfn; | |
379 | else | |
380 | free(pfn); | |
381 | if (pgs) | |
382 | *pgs = total_pages; | |
383 | ||
384 | return addr; | |
385 | } | |
386 | ||
387 | static int | |
388 | parse_mpool_va(struct xen_mempool *mempool) | |
389 | { | |
390 | char path[PATH_MAX] = {0}; | |
391 | char *buf; | |
392 | uint32_t len; | |
393 | char *end; | |
394 | int ret = -1; | |
395 | ||
396 | errno = 0; | |
397 | snprintf(path, sizeof(path), | |
398 | XEN_VM_ROOTNODE_FMT"/%d_"XEN_GVA_SUFFIX, | |
399 | mempool->dom_id, mempool->pool_idx); | |
400 | ||
401 | if((buf = xen_read_node(path, &len)) == NULL) | |
402 | goto out; | |
403 | mempool->gva = (void *)strtoul(buf, &end, 16); | |
404 | if (errno != 0 || end == NULL || end == buf || *end != '\0') { | |
405 | mempool->gva = NULL; | |
406 | goto out; | |
407 | } | |
408 | ret = 0; | |
409 | out: | |
410 | free(buf); | |
411 | return ret; | |
412 | } | |
413 | ||
414 | /* | |
415 | * map mbuf pool | |
416 | */ | |
417 | static int | |
418 | map_mempoolnode(struct xen_gntnode *gntnode, | |
419 | struct xen_mempool *mempool) | |
420 | { | |
421 | if (gntnode == NULL || mempool == NULL) | |
422 | return -1; | |
423 | ||
424 | mempool->hva = | |
425 | map_gntnode(gntnode, mempool->dom_id, &mempool->mempfn_tbl, &mempool->mempfn_num, &mempool->pindex); | |
426 | ||
427 | RTE_LOG(INFO, XENHOST, " %s: map mempool at %p\n", __func__, (void *)mempool->hva); | |
428 | if (mempool->hva) | |
429 | return 0; | |
430 | else { | |
431 | return -1; | |
432 | } | |
433 | } | |
434 | ||
435 | void | |
436 | cleanup_mempool(struct xen_mempool *mempool) | |
437 | { | |
438 | int pg_sz = getpagesize(); | |
439 | uint32_t i; | |
440 | ||
441 | if (mempool->hva) | |
442 | munmap(mempool->hva, mempool->mempfn_num * pg_sz); | |
443 | mempool->hva = NULL; | |
444 | ||
445 | if (mempool->pindex) { | |
446 | RTE_LOG(INFO, XENHOST, " %s: unmap dom %02u mempool%02u %u grefs\n", | |
447 | __func__, | |
448 | mempool->dom_id, | |
449 | mempool->pool_idx, | |
450 | mempool->mempfn_num); | |
451 | for (i = 0; i < mempool->mempfn_num; i ++) { | |
452 | xen_unmap_grant_ref(mempool->pindex[i]); | |
453 | } | |
454 | } | |
455 | mempool->pindex = NULL; | |
456 | ||
457 | free(mempool->mempfn_tbl); | |
458 | mempool->mempfn_tbl = NULL; | |
459 | } | |
460 | ||
461 | /* | |
462 | * process mempool node idx#_mempool_gref, idx = 0, 1, 2... | |
463 | * untill we encounter a node that doesn't exist. | |
464 | */ | |
465 | int | |
466 | parse_mempoolnode(struct xen_guest *guest) | |
467 | { | |
468 | uint32_t i, len; | |
469 | char path[PATH_MAX] = {0}; | |
470 | struct xen_gntnode *gntnode = NULL; | |
471 | struct xen_mempool *mempool = NULL; | |
472 | char *buf; | |
473 | ||
474 | bzero(&guest->mempool, MAX_XENVIRT_MEMPOOL * sizeof(guest->mempool[0])); | |
475 | guest->pool_num = 0; | |
476 | ||
477 | while (1) { | |
478 | /* check if null terminated */ | |
479 | snprintf(path, sizeof(path), | |
480 | XEN_VM_ROOTNODE_FMT"/%d_"XEN_MEMPOOL_SUFFIX, | |
481 | guest->dom_id, | |
482 | guest->pool_num); | |
483 | ||
484 | if ((buf = xen_read_node(path, &len)) != NULL) { | |
485 | /* this node exists */ | |
486 | free(buf); | |
487 | } else { | |
488 | if (guest->pool_num == 0) { | |
489 | RTE_LOG(ERR, PMD, "no mempool found\n"); | |
490 | return -1; | |
491 | } | |
492 | break; | |
493 | } | |
494 | ||
495 | mempool = &guest->mempool[guest->pool_num]; | |
496 | mempool->dom_id = guest->dom_id; | |
497 | mempool->pool_idx = guest->pool_num; | |
498 | ||
499 | RTE_LOG(INFO, XENHOST, " %s: mempool %u parse gntnode %s\n", __func__, guest->pool_num, path); | |
500 | gntnode = parse_gntnode(guest->dom_id, path); | |
501 | if (gntnode == NULL) | |
502 | goto err; | |
503 | ||
504 | if (parse_mpool_va(mempool)) | |
505 | goto err; | |
506 | ||
507 | RTE_LOG(INFO, XENHOST, " %s: mempool %u map gntnode %s\n", __func__, guest->pool_num, path); | |
508 | if (map_mempoolnode(gntnode, mempool)) | |
509 | goto err; | |
510 | ||
511 | xen_free_gntnode(gntnode); | |
512 | guest->pool_num++; | |
513 | } | |
514 | ||
515 | return 0; | |
516 | err: | |
517 | if (gntnode) | |
518 | xen_free_gntnode(gntnode); | |
519 | for (i = 0; i < MAX_XENVIRT_MEMPOOL ; i++) { | |
520 | cleanup_mempool(&guest->mempool[i]); | |
521 | } | |
522 | /* reinitialise mempool */ | |
523 | bzero(&guest->mempool, MAX_XENVIRT_MEMPOOL * sizeof(guest->mempool[0])); | |
524 | return -1; | |
525 | } | |
526 | ||
527 | static int | |
528 | xen_map_vringflag(struct xen_vring *vring) | |
529 | { | |
530 | char path[PATH_MAX] = {0}; | |
531 | char *buf; | |
532 | uint32_t len,gref; | |
533 | int pg_sz = getpagesize(); | |
534 | char *end; | |
535 | ||
536 | snprintf(path, sizeof(path), | |
537 | XEN_VM_ROOTNODE_FMT"/%d_"XEN_VRINGFLAG_SUFFIX, | |
538 | vring->dom_id, vring->virtio_idx); | |
539 | ||
540 | if((buf = xen_read_node(path, &len)) == NULL) | |
541 | goto err; | |
542 | ||
543 | errno = 0; | |
544 | gref = strtol(buf, &end, 0); | |
545 | if (errno != 0 || end == NULL || end == buf) { | |
546 | goto err; | |
547 | } | |
548 | vring->flag = xen_grant_mmap(0, vring->dom_id, gref, &vring->flag_index); | |
549 | if (vring->flag == NULL || *vring->flag == 0) | |
550 | goto err; | |
551 | ||
552 | free(buf); | |
553 | return 0; | |
554 | err: | |
555 | free(buf); | |
556 | if (vring->flag) { | |
557 | munmap(vring->flag, pg_sz); | |
558 | vring->flag = NULL; | |
559 | xen_unmap_grant_ref(vring->flag_index); | |
560 | } | |
561 | return -1; | |
562 | } | |
563 | ||
564 | ||
565 | static int | |
566 | xen_map_rxvringnode(struct xen_gntnode *gntnode, | |
567 | struct xen_vring *vring) | |
568 | { | |
569 | vring->rxvring_addr = | |
570 | map_gntnode(gntnode, vring->dom_id, &vring->rxpfn_tbl, &vring->rxpfn_num, &vring->rx_pindex); | |
571 | RTE_LOG(INFO, XENHOST, " %s: map rx vring at %p\n", __func__, (void *)vring->rxvring_addr); | |
572 | if (vring->rxvring_addr) | |
573 | return 0; | |
574 | else | |
575 | return -1; | |
576 | } | |
577 | ||
578 | static int | |
579 | xen_map_txvringnode(struct xen_gntnode *gntnode, | |
580 | struct xen_vring *vring) | |
581 | { | |
582 | vring->txvring_addr = | |
583 | map_gntnode(gntnode, vring->dom_id, &vring->txpfn_tbl, &vring->txpfn_num, &vring->tx_pindex); | |
584 | RTE_LOG(INFO, XENHOST, " %s: map tx vring at %p\n", __func__, (void *)vring->txvring_addr); | |
585 | if (vring->txvring_addr) | |
586 | return 0; | |
587 | else | |
588 | return -1; | |
589 | } | |
590 | ||
591 | void | |
592 | cleanup_vring(struct xen_vring *vring) | |
593 | { | |
594 | int pg_sz = getpagesize(); | |
595 | uint32_t i; | |
596 | ||
597 | RTE_LOG(INFO, XENHOST, " %s: cleanup dom %u vring %u\n", __func__, vring->dom_id, vring->virtio_idx); | |
598 | if (vring->rxvring_addr) { | |
599 | munmap(vring->rxvring_addr, vring->rxpfn_num * pg_sz); | |
600 | RTE_LOG(INFO, XENHOST, " %s: unmap rx vring [%p, %p]\n", | |
601 | __func__, | |
602 | vring->rxvring_addr, | |
603 | RTE_PTR_ADD(vring->rxvring_addr, | |
604 | vring->rxpfn_num * pg_sz - 1)); | |
605 | } | |
606 | vring->rxvring_addr = NULL; | |
607 | ||
608 | ||
609 | if (vring->rx_pindex) { | |
610 | RTE_LOG(INFO, XENHOST, " %s: unmap rx vring %u grefs\n", __func__, vring->rxpfn_num); | |
611 | for (i = 0; i < vring->rxpfn_num; i++) { | |
612 | xen_unmap_grant_ref(vring->rx_pindex[i]); | |
613 | } | |
614 | } | |
615 | vring->rx_pindex = NULL; | |
616 | ||
617 | free(vring->rxpfn_tbl); | |
618 | vring->rxpfn_tbl = NULL; | |
619 | ||
620 | if (vring->txvring_addr) { | |
621 | munmap(vring->txvring_addr, vring->txpfn_num * pg_sz); | |
622 | RTE_LOG(INFO, XENHOST, " %s: unmap tx vring [%p, %p]\n", | |
623 | __func__, | |
624 | vring->txvring_addr, | |
625 | RTE_PTR_ADD(vring->txvring_addr, | |
626 | vring->txpfn_num * pg_sz - 1)); | |
627 | } | |
628 | vring->txvring_addr = NULL; | |
629 | ||
630 | if (vring->tx_pindex) { | |
631 | RTE_LOG(INFO, XENHOST, " %s: unmap tx vring %u grefs\n", __func__, vring->txpfn_num); | |
632 | for (i = 0; i < vring->txpfn_num; i++) { | |
633 | xen_unmap_grant_ref(vring->tx_pindex[i]); | |
634 | } | |
635 | } | |
636 | vring->tx_pindex = NULL; | |
637 | ||
638 | free(vring->txpfn_tbl); | |
639 | vring->txpfn_tbl = NULL; | |
640 | ||
641 | if (vring->flag) { | |
642 | if (!munmap((void *)vring->flag, pg_sz)) | |
643 | RTE_LOG(INFO, XENHOST, " %s: unmap flag page at %p\n", __func__, vring->flag); | |
644 | if (!xen_unmap_grant_ref(vring->flag_index)) | |
645 | RTE_LOG(INFO, XENHOST, " %s: release flag ref index 0x%" PRIx64 "\n", __func__, vring->flag_index); | |
646 | } | |
647 | vring->flag = NULL; | |
648 | return; | |
649 | } | |
650 | ||
651 | ||
652 | ||
653 | static int | |
654 | xen_parse_etheraddr(struct xen_vring *vring) | |
655 | { | |
656 | char path[PATH_MAX] = {0}; | |
657 | char *buf; | |
658 | uint32_t len; | |
659 | int ret = -1; | |
660 | ||
661 | snprintf(path, sizeof(path), | |
662 | XEN_VM_ROOTNODE_FMT"/%d_"XEN_ADDR_SUFFIX, | |
663 | vring->dom_id, vring->virtio_idx); | |
664 | ||
665 | if ((buf = xen_read_node(path, &len)) == NULL) | |
666 | goto out; | |
667 | ||
668 | if (cmdline_parse_etheraddr(NULL, buf, &vring->addr, | |
669 | sizeof(vring->addr)) < 0) | |
670 | goto out; | |
671 | ret = 0; | |
672 | out: | |
673 | free(buf); | |
674 | return ret; | |
675 | } | |
676 | ||
677 | ||
678 | int | |
679 | parse_vringnode(struct xen_guest *guest, uint32_t virtio_idx) | |
680 | { | |
681 | char path[PATH_MAX] = {0}; | |
682 | struct xen_gntnode *rx_gntnode = NULL; | |
683 | struct xen_gntnode *tx_gntnode = NULL; | |
684 | struct xen_vring *vring = NULL; | |
685 | ||
686 | /*check if null terminated */ | |
687 | snprintf(path, sizeof(path), | |
688 | XEN_VM_ROOTNODE_FMT"/%d_"XEN_RXVRING_SUFFIX, | |
689 | guest->dom_id, | |
690 | virtio_idx); | |
691 | ||
692 | RTE_LOG(INFO, XENHOST, " %s: virtio %u parse rx gntnode %s\n", __func__, virtio_idx, path); | |
693 | rx_gntnode = parse_gntnode(guest->dom_id, path); | |
694 | if (rx_gntnode == NULL) | |
695 | goto err; | |
696 | ||
697 | /*check if null terminated */ | |
698 | snprintf(path, sizeof(path), | |
699 | XEN_VM_ROOTNODE_FMT"/%d_"XEN_TXVRING_SUFFIX, | |
700 | guest->dom_id, | |
701 | virtio_idx); | |
702 | ||
703 | RTE_LOG(INFO, XENHOST, " %s: virtio %u parse tx gntnode %s\n", __func__, virtio_idx, path); | |
704 | tx_gntnode = parse_gntnode(guest->dom_id, path); | |
705 | if (tx_gntnode == NULL) | |
706 | goto err; | |
707 | ||
708 | vring = &guest->vring[virtio_idx]; | |
709 | bzero(vring, sizeof(*vring)); | |
710 | vring->dom_id = guest->dom_id; | |
711 | vring->virtio_idx = virtio_idx; | |
712 | ||
713 | if (xen_parse_etheraddr(vring) != 0) | |
714 | goto err; | |
715 | ||
716 | RTE_LOG(INFO, XENHOST, " %s: virtio %u map rx gntnode %s\n", __func__, virtio_idx, path); | |
717 | if (xen_map_rxvringnode(rx_gntnode, vring) != 0) | |
718 | goto err; | |
719 | ||
720 | RTE_LOG(INFO, XENHOST, " %s: virtio %u map tx gntnode %s\n", __func__, virtio_idx, path); | |
721 | if (xen_map_txvringnode(tx_gntnode, vring) != 0) | |
722 | goto err; | |
723 | ||
724 | if (xen_map_vringflag(vring) != 0) | |
725 | goto err; | |
726 | ||
727 | guest->vring_num++; | |
728 | ||
729 | xen_free_gntnode(rx_gntnode); | |
730 | xen_free_gntnode(tx_gntnode); | |
731 | ||
732 | return 0; | |
733 | ||
734 | err: | |
735 | if (rx_gntnode) | |
736 | xen_free_gntnode(rx_gntnode); | |
737 | if (tx_gntnode) | |
738 | xen_free_gntnode(tx_gntnode); | |
739 | if (vring) { | |
740 | cleanup_vring(vring); | |
741 | bzero(vring, sizeof(*vring)); | |
742 | } | |
743 | return -1; | |
744 | } | |
745 | ||
746 | /* | |
747 | * Open xen grant dev driver | |
748 | * @return | |
749 | * 0 on success, -1 on failure. | |
750 | */ | |
751 | static int | |
752 | xen_grant_init(void) | |
753 | { | |
754 | d_fd = open(XEN_GNTDEV_FNAME, O_RDWR); | |
755 | ||
756 | return d_fd == -1? (-1): (0); | |
757 | } | |
758 | ||
759 | /* | |
760 | * Initialise xenstore handle and open grant dev driver. | |
761 | * @return | |
762 | * 0 on success, -1 on failure. | |
763 | */ | |
764 | int | |
765 | xenhost_init(void) | |
766 | { | |
767 | xs = xs_daemon_open(); | |
768 | if (xs == NULL) { | |
769 | rte_panic("failed initialize xen daemon handler"); | |
770 | return -1; | |
771 | } | |
772 | if (xen_grant_init()) | |
773 | return -1; | |
774 | return 0; | |
775 | } |