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