1 /*
2 * Copyright (c) 2010, Citrix Systems, Inc.
3 *
4 * This library is free software; you can redistribute it and/or
5 * modify it under the terms of the GNU Lesser General Public
6 * License as published by the Free Software Foundation;
7 * version 2.1 of the License.
8 *
9 * This library is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 * Lesser General Public License for more details.
13 *
14 * You should have received a copy of the GNU Lesser General Public
15 * License along with this library; If not, see <http://www.gnu.org/licenses/>.
16 */
17
18 #include <stdlib.h>
19 #include <string.h>
20
21 #include "xc_private.h"
22 #include "xg_private.h"
23
24 xc_hypercall_buffer_t XC__HYPERCALL_BUFFER_NAME(HYPERCALL_BUFFER_NULL) = {
25 .hbuf = NULL,
26 .param_shadow = NULL,
27 HYPERCALL_BUFFER_INIT_NO_BOUNCE
28 };
29
xc__hypercall_buffer_alloc_pages(xc_interface * xch,xc_hypercall_buffer_t * b,int nr_pages)30 void *xc__hypercall_buffer_alloc_pages(xc_interface *xch, xc_hypercall_buffer_t *b, int nr_pages)
31 {
32 void *p = xencall_alloc_buffer_pages(xch->xcall, nr_pages);
33
34 if (!p)
35 return NULL;
36
37 b->hbuf = p;
38
39 return b->hbuf;
40 }
41
xc__hypercall_buffer_free_pages(xc_interface * xch,xc_hypercall_buffer_t * b,int nr_pages)42 void xc__hypercall_buffer_free_pages(xc_interface *xch, xc_hypercall_buffer_t *b, int nr_pages)
43 {
44 xencall_free_buffer_pages(xch->xcall, b->hbuf, nr_pages);
45 }
46
xc__hypercall_buffer_alloc(xc_interface * xch,xc_hypercall_buffer_t * b,size_t size)47 void *xc__hypercall_buffer_alloc(xc_interface *xch, xc_hypercall_buffer_t *b, size_t size)
48 {
49 void *p = xencall_alloc_buffer(xch->xcall, size);
50
51 if (!p)
52 return NULL;
53
54 b->hbuf = p;
55
56 return b->hbuf;
57 }
58
xc__hypercall_buffer_free(xc_interface * xch,xc_hypercall_buffer_t * b)59 void xc__hypercall_buffer_free(xc_interface *xch, xc_hypercall_buffer_t *b)
60 {
61 xencall_free_buffer(xch->xcall, b->hbuf);
62 }
63
xc__hypercall_bounce_pre(xc_interface * xch,xc_hypercall_buffer_t * b)64 int xc__hypercall_bounce_pre(xc_interface *xch, xc_hypercall_buffer_t *b)
65 {
66 void *p;
67
68 /*
69 * Catch hypercall buffer declared other than with DECLARE_HYPERCALL_BOUNCE.
70 */
71 if ( b->ubuf == (void *)-1 || b->dir == XC_HYPERCALL_BUFFER_BOUNCE_NONE )
72 abort();
73
74 /*
75 * Don't need to bounce a NULL buffer.
76 */
77 if ( b->ubuf == NULL )
78 {
79 b->hbuf = NULL;
80 return 0;
81 }
82
83 p = xc__hypercall_buffer_alloc(xch, b, b->sz);
84 if ( p == NULL )
85 return -1;
86
87 if ( b->dir == XC_HYPERCALL_BUFFER_BOUNCE_IN || b->dir == XC_HYPERCALL_BUFFER_BOUNCE_BOTH )
88 memcpy(b->hbuf, b->ubuf, b->sz);
89
90 return 0;
91 }
92
xc__hypercall_bounce_post(xc_interface * xch,xc_hypercall_buffer_t * b)93 void xc__hypercall_bounce_post(xc_interface *xch, xc_hypercall_buffer_t *b)
94 {
95 /*
96 * Catch hypercall buffer declared other than with DECLARE_HYPERCALL_BOUNCE.
97 */
98 if ( b->ubuf == (void *)-1 || b->dir == XC_HYPERCALL_BUFFER_BOUNCE_NONE )
99 abort();
100
101 if ( b->hbuf == NULL )
102 return;
103
104 if ( b->dir == XC_HYPERCALL_BUFFER_BOUNCE_OUT || b->dir == XC_HYPERCALL_BUFFER_BOUNCE_BOTH )
105 memcpy(b->ubuf, b->hbuf, b->sz);
106
107 xc__hypercall_buffer_free(xch, b);
108 }
109
110 struct xc_hypercall_buffer_array {
111 unsigned max_bufs;
112 xc_hypercall_buffer_t *bufs;
113 };
114
xc_hypercall_buffer_array_create(xc_interface * xch,unsigned n)115 xc_hypercall_buffer_array_t *xc_hypercall_buffer_array_create(xc_interface *xch,
116 unsigned n)
117 {
118 xc_hypercall_buffer_array_t *array;
119 xc_hypercall_buffer_t *bufs = NULL;
120
121 array = malloc(sizeof(*array));
122 if ( array == NULL )
123 goto error;
124
125 bufs = calloc(n, sizeof(*bufs));
126 if ( bufs == NULL )
127 goto error;
128
129 array->max_bufs = n;
130 array->bufs = bufs;
131
132 return array;
133
134 error:
135 free(bufs);
136 free(array);
137 return NULL;
138 }
139
xc__hypercall_buffer_array_alloc(xc_interface * xch,xc_hypercall_buffer_array_t * array,unsigned index,xc_hypercall_buffer_t * hbuf,size_t size)140 void *xc__hypercall_buffer_array_alloc(xc_interface *xch,
141 xc_hypercall_buffer_array_t *array,
142 unsigned index,
143 xc_hypercall_buffer_t *hbuf,
144 size_t size)
145 {
146 void *buf;
147
148 if ( index >= array->max_bufs || array->bufs[index].hbuf )
149 abort();
150
151 buf = xc__hypercall_buffer_alloc(xch, hbuf, size);
152 if ( buf )
153 array->bufs[index] = *hbuf;
154 return buf;
155 }
156
xc__hypercall_buffer_array_get(xc_interface * xch,xc_hypercall_buffer_array_t * array,unsigned index,xc_hypercall_buffer_t * hbuf)157 void *xc__hypercall_buffer_array_get(xc_interface *xch,
158 xc_hypercall_buffer_array_t *array,
159 unsigned index,
160 xc_hypercall_buffer_t *hbuf)
161 {
162 if ( index >= array->max_bufs || array->bufs[index].hbuf == NULL )
163 abort();
164
165 *hbuf = array->bufs[index];
166 return array->bufs[index].hbuf;
167 }
168
xc_hypercall_buffer_array_destroy(xc_interface * xc,xc_hypercall_buffer_array_t * array)169 void xc_hypercall_buffer_array_destroy(xc_interface *xc,
170 xc_hypercall_buffer_array_t *array)
171 {
172 unsigned i;
173
174 if ( array == NULL )
175 return;
176
177 for (i = 0; i < array->max_bufs; i++ )
178 xc__hypercall_buffer_free(xc, &array->bufs[i]);
179 free(array->bufs);
180 free(array);
181 }
182
183 /*
184 * Local variables:
185 * mode: C
186 * c-file-style: "BSD"
187 * c-basic-offset: 4
188 * tab-width: 4
189 * indent-tabs-mode: nil
190 * End:
191 */
192