grant table map (gntdev) for minios
RFC 1/1 grant table map (gntdev) for minios
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
---
extras/mini-os/gntmap.c new file +250 -0
@@ -0,0 +1,250 @@ +/* +* Manages grant mappings from other domains. +* +* Diego Ongaro <[email protected]>, 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 ; +}
extras/mini-os/include/gntmap.h new file +35 -0
@@ -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__ */
extras/mini-os/include/lib.h +3 -0
@@ -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;
extras/mini-os/minios.mk +1 -0
@@ -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
tools/libxc/xc_minios.c +71 -0
83 lines not on this page · raw message
Quoted 2 lines · Diego Ongaro
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.
---
extras/mini-os/lib/sys.c +3 -0
@@ -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 ;
Quoted 2 lines · Diego Ongaro
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.
---
extras/mini-os/gntmap.c +6 -4
@@ -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_enint 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 *mapprintk ("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 );
tools/libxc/xc_minios.c +17 -5
@@ -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; }/*