I''ve implemented a grant map for mini-os to support the xc_gnttab_*() functions, the equivalent of gntdev in linux. This is useful for my work in putting xenstored in a stub domain. I think the libxc component is pretty trivial, but it''d be nice to get a few more sets of eyes on the new gntmap.c. Thanks, Diego Signed-off-by: Diego Ongaro <diego.ongaro@citrix.com> --- diff -r 7299346111fb extras/mini-os/gntmap.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/extras/mini-os/gntmap.c Wed Jul 23 18:23:12 2008 +0100 @@ -0,0 +1,250 @@ +/* + * Manages grant mappings from other domains. + * + * Diego Ongaro <diego.ongaro@citrix.com>, July 2008 + * + * Files of type FTYPE_GNTMAP contain a gntmap, which is an array of + * (host address, grant handle) pairs. Grant handles come from a hypervisor map + * operation and are needed for the corresponding unmap. + * + * This is a rather naive implementation in terms of performance. If we start + * using it frequently, there''s definitely some low-hanging fruit here. + * + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to + * deal in the Software without restriction, including without limitation the + * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or + * sell copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + * DEALINGS IN THE SOFTWARE. + */ + +#include <os.h> +#include <xmalloc.h> +#include <errno.h> +#include <xen/grant_table.h> +#include <inttypes.h> +#include "gntmap.h" + +#define DEFAULT_MAX_GRANTS 128 + +struct gntmap_entry { + unsigned long host_addr; + grant_handle_t handle; +}; + +static inline int +gntmap_entry_used(struct gntmap_entry *entry) +{ + return entry->host_addr != 0; +} + +static struct gntmap_entry* +gntmap_find_free_entry(struct gntmap *map) +{ + int i; + + for (i = 0; i < map->nentries; i++) { + if (!gntmap_entry_used(&map->entries[i])) + return &map->entries[i]; + } + +#ifdef GNTMAP_DEBUG + printk("gntmap_find_free_entry(map=%p): all %d entries full\n", + map, map->nentries); +#endif + return NULL; +} + +static struct gntmap_entry* +gntmap_find_entry(struct gntmap *map, unsigned long addr) +{ + int i; + + for (i = 0; i < map->nentries; i++) { + if (map->entries[i].host_addr == addr) + return &map->entries[i]; + } + return NULL; +} + +int +gntmap_set_max_grants(struct gntmap *map, int count) +{ +#ifdef GNTMAP_DEBUG + printk("gntmap_set_max_grants(map=%p, count=%d)\n", map, count); +#endif + + if (map->nentries != 0) + return -EBUSY; + + map->entries = xmalloc_array(struct gntmap_entry, count); + if (map->entries == NULL) + return -ENOMEM; + + memset(map->entries, 0, sizeof(struct gntmap_entry) * count); + map->nentries = count; + return 0; +} + +static int +_gntmap_map_grant_ref(struct gntmap_entry *entry, + unsigned long host_addr, + uint32_t domid, + uint32_t ref, + int writable) +{ + struct gnttab_map_grant_ref op; + int rc; + + op.ref = (grant_ref_t) ref; + op.dom = (domid_t) domid; + op.host_addr = (uint64_t) host_addr; + op.flags = GNTMAP_host_map; + if (!writable) + op.flags |= GNTMAP_readonly; + + rc = HYPERVISOR_grant_table_op(GNTTABOP_map_grant_ref, &op, 1); + if (rc != 0 || op.status != GNTST_okay) { + printk("GNTTABOP_map_grant_ref failed: " + "returned %d, status %d\n", + rc, op.status); + return rc != 0 ? rc : op.status; + } + + entry->host_addr = host_addr; + entry->handle = op.handle; + return 0; +} + +static int +_gntmap_unmap_grant_ref(struct gntmap_entry *entry) +{ + struct gnttab_unmap_grant_ref op; + int rc; + + op.host_addr = (uint64_t) entry->host_addr; + op.handle = entry->handle; + + rc = HYPERVISOR_grant_table_op(GNTTABOP_unmap_grant_ref, &op, 1); + if (rc != 0 || op.status != GNTST_okay) { + printk("GNTTABOP_unmap_grant_ref failed: " + "returned %d, status %d\n", + rc, op.status); + return rc != 0 ? rc : op.status; + } + + entry->host_addr = 0; + return 0; +} + +int +gntmap_munmap(struct gntmap *map, unsigned long start_address, int count) +{ + int i, rc; + struct gntmap_entry *ent; + +#ifdef GNTMAP_DEBUG + printk("gntmap_munmap(map=%p, start_address=%lx, count=%d)\n", + map, start_address, count); +#endif + + for (i = 0; i < count; i++) { + ent = gntmap_find_entry(map, start_address + PAGE_SIZE * i); + if (ent == NULL) { + printk("gntmap: tried to munmap unknown page\n"); + return -EINVAL; + } + + rc = _gntmap_unmap_grant_ref(ent); + if (rc != 0) + return rc; + } + + return 0; +} + +void* +gntmap_map_grant_refs(struct gntmap *map, + uint32_t count, + uint32_t *domids, + int domids_stride, + uint32_t *refs, + int writable) +{ + unsigned long addr; + struct gntmap_entry *ent; + int i; + +#ifdef GNTMAP_DEBUG + printk("gntmap_map_grant_refs(map=%p, count=%" PRIu32 ", " + "domids=%p [%" PRIu32 "...], domids_stride=%d, " + "refs=%p [%" PRIu32 "...], writable=%d)\n", + map, count, domids, domids[0], domids_stride, + refs, refs[0], writable); +#endif + + (void) gntmap_set_max_grants(map, DEFAULT_MAX_GRANTS); + + addr = allocate_ondemand((unsigned long) count, 1); + if (addr == 0) + return NULL; + + for (i = 0; i < count; i++) { + ent = gntmap_find_free_entry(map); + if (ent == NULL || + _gntmap_map_grant_ref(ent, + addr + PAGE_SIZE * i, + domids[i * domids_stride], + refs[i], + writable) != 0) { + + (void) gntmap_munmap(map, addr, i); + return NULL; + } + } + + return (void*) addr; +} + +void +gntmap_init(struct gntmap *map) +{ +#ifdef GNTMAP_DEBUG + printk("gntmap_init(map=%p)\n", map); +#endif + map->nentries = 0; + map->entries = NULL; +} + +void +gntmap_fini(struct gntmap *map) +{ + struct gntmap_entry *ent; + int i; + +#ifdef GNTMAP_DEBUG + printk("gntmap_fini(map=%p)\n", map); +#endif + + for (i = 0; i < map->nentries; i++) { + ent = &map->entries[i]; + if (gntmap_entry_used(ent)) + (void) _gntmap_unmap_grant_ref(ent); + } + + xfree(map->entries); + map->entries = NULL; + map->nentries = 0; +} diff -r 7299346111fb extras/mini-os/include/gntmap.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/extras/mini-os/include/gntmap.h Wed Jul 23 18:23:12 2008 +0100 @@ -0,0 +1,35 @@ +#ifndef __GNTMAP_H__ +#define __GNTMAP_H__ + +#include <os.h> + +/* + * Please consider struct gntmap opaque. If instead you choose to disregard + * this message, I insist that you keep an eye out for raptors. + */ +struct gntmap { + int nentries; + struct gntmap_entry *entries; +}; + +int +gntmap_set_max_grants(struct gntmap *map, int count); + +int +gntmap_munmap(struct gntmap *map, unsigned long start_address, int count); + +void* +gntmap_map_grant_refs(struct gntmap *map, + uint32_t count, + uint32_t *domids, + int domids_stride, + uint32_t *refs, + int writable); + +void +gntmap_init(struct gntmap *map); + +void +gntmap_fini(struct gntmap *map); + +#endif /* !__GNTMAP_H__ */ diff -r 7299346111fb extras/mini-os/include/lib.h --- a/extras/mini-os/include/lib.h Wed Jul 23 16:39:46 2008 +0100 +++ b/extras/mini-os/include/lib.h Wed Jul 23 18:23:12 2008 +0100 @@ -59,6 +59,7 @@ #include <stddef.h> #include <xen/xen.h> #include <xen/event_channel.h> +#include "gntmap.h" #ifdef HAVE_LIBC #include <stdio.h> @@ -138,6 +139,7 @@ enum fd_type { FTYPE_XENBUS, FTYPE_XC, FTYPE_EVTCHN, + FTYPE_GNTMAP, FTYPE_SOCKET, FTYPE_TAP, FTYPE_BLK, @@ -168,6 +170,7 @@ extern struct file { int bound; } ports[MAX_EVTCHN_PORTS]; } evtchn; + struct gntmap gntmap; struct { struct netfront_dev *dev; } tap; diff -r 7299346111fb extras/mini-os/minios.mk --- a/extras/mini-os/minios.mk Wed Jul 23 16:39:46 2008 +0100 +++ b/extras/mini-os/minios.mk Wed Jul 23 18:23:12 2008 +0100 @@ -21,6 +21,7 @@ DEF_CFLAGS += -g #DEF_CFLAGS += -DFS_DEBUG #DEF_CFLAGS += -DLIBC_DEBUG DEF_CFLAGS += -DGNT_DEBUG +DEF_CFLAGS += -DGNTMAP_DEBUG else DEF_CFLAGS += -O3 endif diff -r 7299346111fb tools/libxc/xc_minios.c --- a/tools/libxc/xc_minios.c Wed Jul 23 16:39:46 2008 +0100 +++ b/tools/libxc/xc_minios.c Wed Jul 23 18:23:12 2008 +0100 @@ -15,6 +15,7 @@ #include <os.h> #include <mm.h> #include <lib.h> +#include <gntmap.h> #include <events.h> #include <wait.h> #include <sys/mman.h> @@ -315,6 +316,76 @@ void discard_file_cache(int fd, int flus if (flush) fsync(fd); } + +int xc_gnttab_open(void) +{ + int xcg_handle; + xcg_handle = alloc_fd(FTYPE_GNTMAP); + gntmap_init(&files[xcg_handle].gntmap); + return xcg_handle; +} + +int xc_gnttab_close(int xcg_handle) +{ + gntmap_fini(&files[xcg_handle].gntmap); + files[xcg_handle].type = FTYPE_NONE; + return 0; +} + +void *xc_gnttab_map_grant_ref(int xcg_handle, + uint32_t domid, + uint32_t ref, + int prot) +{ + return gntmap_map_grant_refs(&files[xcg_handle].gntmap, + 1, + &domid, 0, + &ref, + prot & PROT_WRITE); +} + +void *xc_gnttab_map_grant_refs(int xcg_handle, + uint32_t count, + uint32_t *domids, + uint32_t *refs, + int prot) +{ + return gntmap_map_grant_refs(&files[xcg_handle].gntmap, + count, + domids, 1, + refs, + prot & PROT_WRITE); +} + +void *xc_gnttab_map_domain_grant_refs(int xcg_handle, + uint32_t count, + uint32_t domid, + uint32_t *refs, + int prot) +{ + return gntmap_map_grant_refs(&files[xcg_handle].gntmap, + count, + &domid, 0, + refs, + prot & PROT_WRITE); +} + +int xc_gnttab_munmap(int xcg_handle, + void *start_address, + uint32_t count) +{ + return gntmap_munmap(&files[xcg_handle].gntmap, + (unsigned long) start_address, + count); +} + +int xc_gnttab_set_max_grants(int xcg_handle, + uint32_t count) +{ + return gntmap_set_max_grants(&files[xcg_handle].gntmap, + count); +} + /* * Local variables: * mode: C _______________________________________________ Xen-devel mailing list Xen-devel@lists.xensource.com http://lists.xensource.com/xen-devel
Diego Ongaro
2008-Jul-23 18:11 UTC
Re: [Xen-devel] [RFC] grant table map (gntdev) for minios
Diego Ongaro wrote:> I''ve implemented a grant map for mini-os to support the xc_gnttab_*() > functions, the equivalent of gntdev in linux.Adds a close() case for the new file type. Signed-off-by: Diego Ongaro <diego.ongaro@citrix.com> --- diff --git a/extras/mini-os/lib/sys.c b/extras/mini-os/lib/sys.c --- a/extras/mini-os/lib/sys.c +++ b/extras/mini-os/lib/sys.c @@ -401,6 +401,9 @@ int close(int fd) case FTYPE_EVTCHN: xc_evtchn_close(fd); return 0; + case FTYPE_GNTMAP: + xc_gnttab_close(fd); + return 0; case FTYPE_TAP: shutdown_netfront(files[fd].tap.dev); files[fd].type = FTYPE_NONE; _______________________________________________ Xen-devel mailing list Xen-devel@lists.xensource.com http://lists.xensource.com/xen-devel
Diego Ongaro
2008-Jul-24 14:42 UTC
Re: [Xen-devel] [RFC] grant table map (gntdev) for minios
Diego Ongaro wrote:> I''ve implemented a grant map for mini-os to support the xc_gnttab_*() > functions, the equivalent of gntdev in linux.Bug fixes: * Uninitialized dev_bus_addr argument to GNTTABOP_unmap_grant_ref results in an angry hypervisor. * Set errno in libxc and return -1 on error. * op.status is a int16_t, so it should be printed with PRId16. * Don''t print domids[0] or refs[0] if the ptr is NULL. It''s more polite to crash later, after the message has been printed. Signed-off-by: Diego Ongaro <diego.ongaro@citrix.com> --- diff --git a/extras/mini-os/gntmap.c b/extras/mini-os/gntmap.c --- a/extras/mini-os/gntmap.c +++ b/extras/mini-os/gntmap.c @@ -118,7 +118,7 @@ _gntmap_map_grant_ref(struct gntmap_entr rc = HYPERVISOR_grant_table_op(GNTTABOP_map_grant_ref, &op, 1); if (rc != 0 || op.status != GNTST_okay) { printk("GNTTABOP_map_grant_ref failed: " - "returned %d, status %d\n", + "returned %d, status %" PRId16 "\n", rc, op.status); return rc != 0 ? rc : op.status; } @@ -135,12 +135,13 @@ _gntmap_unmap_grant_ref(struct gntmap_en int rc; op.host_addr = (uint64_t) entry->host_addr; + op.dev_bus_addr = 0; op.handle = entry->handle; rc = HYPERVISOR_grant_table_op(GNTTABOP_unmap_grant_ref, &op, 1); if (rc != 0 || op.status != GNTST_okay) { printk("GNTTABOP_unmap_grant_ref failed: " - "returned %d, status %d\n", + "returned %d, status %" PRId16 "\n", rc, op.status); return rc != 0 ? rc : op.status; } @@ -191,8 +192,9 @@ gntmap_map_grant_refs(struct gntmap *map printk("gntmap_map_grant_refs(map=%p, count=%" PRIu32 ", " "domids=%p [%" PRIu32 "...], domids_stride=%d, " "refs=%p [%" PRIu32 "...], writable=%d)\n", - map, count, domids, domids[0], domids_stride, - refs, refs[0], writable); + map, count, + domids, domids == NULL ? 0 : domids[0], domids_stride, + refs, refs == NULL ? 0 : refs[0], writable); #endif (void) gntmap_set_max_grants(map, DEFAULT_MAX_GRANTS); diff --git a/tools/libxc/xc_minios.c b/tools/libxc/xc_minios.c --- a/tools/libxc/xc_minios.c +++ b/tools/libxc/xc_minios.c @@ -383,16 +383,28 @@ int xc_gnttab_munmap(int xcg_handle, void *start_address, uint32_t count) { - return gntmap_munmap(&files[xcg_handle].gntmap, - (unsigned long) start_address, - count); + int ret; + ret = gntmap_munmap(&files[xcg_handle].gntmap, + (unsigned long) start_address, + count); + if (ret < 0) { + errno = -ret; + return -1; + } + return ret; } int xc_gnttab_set_max_grants(int xcg_handle, uint32_t count) { - return gntmap_set_max_grants(&files[xcg_handle].gntmap, - count); + int ret; + ret = gntmap_set_max_grants(&files[xcg_handle].gntmap, + count); + if (ret < 0) { + errno = -ret; + return -1; + } + return ret; } /* _______________________________________________ Xen-devel mailing list Xen-devel@lists.xensource.com http://lists.xensource.com/xen-devel