aboutsummaryrefslogtreecommitdiffstats
path: root/tools/libxc/xc_hcall_buf.c
diff options
context:
space:
mode:
authorIan Campbell <ian.campbell@citrix.com>2010-10-26 12:11:37 +0100
committerIan Campbell <ian.campbell@citrix.com>2010-10-26 12:11:37 +0100
commitb545e27bc6994b901c5611a8fea9b0cca648b7dc (patch)
tree66bbd9daf45ca63a4ea58485ffd0df0432568932 /tools/libxc/xc_hcall_buf.c
parent26d4c59a0b5eadf7e03a9e7fba737c220a5a4811 (diff)
downloadxen-b545e27bc6994b901c5611a8fea9b0cca648b7dc.tar.gz
xen-b545e27bc6994b901c5611a8fea9b0cca648b7dc.tar.bz2
xen-b545e27bc6994b901c5611a8fea9b0cca648b7dc.zip
libxc: infrastructure for hypercall safe data buffers.
(Modified version of this patch, with updated #includes in xc_hcall_buf.c to fix stubdomain build.) Signed-off-by: Ian Campbell <ian.campbell@citrix.com> Signed-off-by: Ian Jackson <ian.jackson@eu.citrix.com>
Diffstat (limited to 'tools/libxc/xc_hcall_buf.c')
-rw-r--r--tools/libxc/xc_hcall_buf.c162
1 files changed, 162 insertions, 0 deletions
diff --git a/tools/libxc/xc_hcall_buf.c b/tools/libxc/xc_hcall_buf.c
new file mode 100644
index 0000000000..032997f125
--- /dev/null
+++ b/tools/libxc/xc_hcall_buf.c
@@ -0,0 +1,162 @@
+/*
+ * Copyright (c) 2010, Citrix Systems, Inc.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation;
+ * version 2.1 of the License.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#include <stdlib.h>
+#include <malloc.h>
+
+#include "xc_private.h"
+#include "xg_private.h"
+
+xc_hypercall_buffer_t XC__HYPERCALL_BUFFER_NAME(HYPERCALL_BUFFER_NULL) = {
+ .hbuf = NULL,
+ .param_shadow = NULL,
+ HYPERCALL_BUFFER_INIT_NO_BOUNCE
+};
+
+void *xc__hypercall_buffer_alloc_pages(xc_interface *xch, xc_hypercall_buffer_t *b, int nr_pages)
+{
+ size_t size = nr_pages * PAGE_SIZE;
+ void *p;
+#if defined(_POSIX_C_SOURCE) && !defined(__sun__)
+ int ret;
+ ret = posix_memalign(&p, PAGE_SIZE, size);
+ if (ret != 0)
+ return NULL;
+#elif defined(__NetBSD__) || defined(__OpenBSD__)
+ p = valloc(size);
+#else
+ p = memalign(PAGE_SIZE, size);
+#endif
+
+ if (!p)
+ return NULL;
+
+#ifndef __sun__
+ if ( mlock(p, size) < 0 )
+ {
+ free(p);
+ return NULL;
+ }
+#endif
+
+ b->hbuf = p;
+
+ memset(p, 0, size);
+ return b->hbuf;
+}
+
+void xc__hypercall_buffer_free_pages(xc_interface *xch, xc_hypercall_buffer_t *b, int nr_pages)
+{
+ if ( b->hbuf == NULL )
+ return;
+
+#ifndef __sun__
+ (void) munlock(b->hbuf, nr_pages * PAGE_SIZE);
+#endif
+
+ free(b->hbuf);
+}
+
+struct allocation_header {
+ int nr_pages;
+};
+
+void *xc__hypercall_buffer_alloc(xc_interface *xch, xc_hypercall_buffer_t *b, size_t size)
+{
+ size_t actual_size = ROUNDUP(size + sizeof(struct allocation_header), PAGE_SHIFT);
+ int nr_pages = actual_size >> PAGE_SHIFT;
+ struct allocation_header *hdr;
+
+ hdr = xc__hypercall_buffer_alloc_pages(xch, b, nr_pages);
+ if ( hdr == NULL )
+ return NULL;
+
+ b->hbuf = (void *)(hdr+1);
+
+ hdr->nr_pages = nr_pages;
+ return b->hbuf;
+}
+
+void xc__hypercall_buffer_free(xc_interface *xch, xc_hypercall_buffer_t *b)
+{
+ struct allocation_header *hdr;
+
+ if (b->hbuf == NULL)
+ return;
+
+ hdr = b->hbuf;
+ b->hbuf = --hdr;
+
+ xc__hypercall_buffer_free_pages(xch, b, hdr->nr_pages);
+}
+
+int xc__hypercall_bounce_pre(xc_interface *xch, xc_hypercall_buffer_t *b)
+{
+ void *p;
+
+ /*
+ * Catch hypercall buffer declared other than with DECLARE_HYPERCALL_BOUNCE.
+ */
+ if ( b->ubuf == (void *)-1 || b->dir == XC_HYPERCALL_BUFFER_BOUNCE_NONE )
+ abort();
+
+ /*
+ * Do need to bounce a NULL buffer.
+ */
+ if ( b->ubuf == NULL )
+ {
+ b->hbuf = NULL;
+ return 0;
+ }
+
+ p = xc__hypercall_buffer_alloc(xch, b, b->sz);
+ if ( p == NULL )
+ return -1;
+
+ if ( b->dir == XC_HYPERCALL_BUFFER_BOUNCE_IN || b->dir == XC_HYPERCALL_BUFFER_BOUNCE_BOTH )
+ memcpy(b->hbuf, b->ubuf, b->sz);
+
+ return 0;
+}
+
+void xc__hypercall_bounce_post(xc_interface *xch, xc_hypercall_buffer_t *b)
+{
+ /*
+ * Catch hypercall buffer declared other than with DECLARE_HYPERCALL_BOUNCE.
+ */
+ if ( b->ubuf == (void *)-1 || b->dir == XC_HYPERCALL_BUFFER_BOUNCE_NONE )
+ abort();
+
+ if ( b->hbuf == NULL )
+ return;
+
+ if ( b->dir == XC_HYPERCALL_BUFFER_BOUNCE_OUT || b->dir == XC_HYPERCALL_BUFFER_BOUNCE_BOTH )
+ memcpy(b->ubuf, b->hbuf, b->sz);
+
+ xc__hypercall_buffer_free(xch, b);
+}
+
+/*
+ * Local variables:
+ * mode: C
+ * c-set-style: "BSD"
+ * c-basic-offset: 4
+ * tab-width: 4
+ * indent-tabs-mode: nil
+ * End:
+ */