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 
23 xc_hypercall_buffer_t XC__HYPERCALL_BUFFER_NAME(HYPERCALL_BUFFER_NULL) = {
24     .hbuf = NULL,
25     .param_shadow = NULL,
26     HYPERCALL_BUFFER_INIT_NO_BOUNCE
27 };
28 
xc__hypercall_buffer_alloc_pages(xc_interface * xch,xc_hypercall_buffer_t * b,int nr_pages)29 void *xc__hypercall_buffer_alloc_pages(xc_interface *xch, xc_hypercall_buffer_t *b, int nr_pages)
30 {
31     void *p = xencall_alloc_buffer_pages(xch->xcall, nr_pages);
32 
33     if (!p)
34         return NULL;
35 
36     b->hbuf = p;
37 
38     return b->hbuf;
39 }
40 
xc__hypercall_buffer_free_pages(xc_interface * xch,xc_hypercall_buffer_t * b,int nr_pages)41 void xc__hypercall_buffer_free_pages(xc_interface *xch, xc_hypercall_buffer_t *b, int nr_pages)
42 {
43     xencall_free_buffer_pages(xch->xcall, b->hbuf, nr_pages);
44 }
45 
xc__hypercall_buffer_alloc(xc_interface * xch,xc_hypercall_buffer_t * b,size_t size)46 void *xc__hypercall_buffer_alloc(xc_interface *xch, xc_hypercall_buffer_t *b, size_t size)
47 {
48     void *p = xencall_alloc_buffer(xch->xcall, size);
49 
50     if (!p)
51         return NULL;
52 
53     b->hbuf = p;
54 
55     return b->hbuf;
56 }
57 
xc__hypercall_buffer_free(xc_interface * xch,xc_hypercall_buffer_t * b)58 void xc__hypercall_buffer_free(xc_interface *xch, xc_hypercall_buffer_t *b)
59 {
60     xencall_free_buffer(xch->xcall, b->hbuf);
61 }
62 
xc__hypercall_bounce_pre(xc_interface * xch,xc_hypercall_buffer_t * b)63 int xc__hypercall_bounce_pre(xc_interface *xch, xc_hypercall_buffer_t *b)
64 {
65     void *p;
66 
67     /*
68      * Catch hypercall buffer declared other than with DECLARE_HYPERCALL_BOUNCE.
69      */
70     if ( b->ubuf == (void *)-1 || b->dir == XC_HYPERCALL_BUFFER_BOUNCE_NONE )
71         abort();
72 
73     /*
74      * Don't need to bounce a NULL buffer.
75      */
76     if ( b->ubuf == NULL )
77     {
78         b->hbuf = NULL;
79         return 0;
80     }
81 
82     p = xc__hypercall_buffer_alloc(xch, b, b->sz);
83     if ( p == NULL )
84         return -1;
85 
86     if ( b->dir == XC_HYPERCALL_BUFFER_BOUNCE_IN || b->dir == XC_HYPERCALL_BUFFER_BOUNCE_BOTH )
87         memcpy(b->hbuf, b->ubuf, b->sz);
88 
89     return 0;
90 }
91 
xc__hypercall_bounce_post(xc_interface * xch,xc_hypercall_buffer_t * b)92 void xc__hypercall_bounce_post(xc_interface *xch, xc_hypercall_buffer_t *b)
93 {
94     /*
95      * Catch hypercall buffer declared other than with DECLARE_HYPERCALL_BOUNCE.
96      */
97     if ( b->ubuf == (void *)-1 || b->dir == XC_HYPERCALL_BUFFER_BOUNCE_NONE )
98         abort();
99 
100     if ( b->hbuf == NULL )
101         return;
102 
103     if ( b->dir == XC_HYPERCALL_BUFFER_BOUNCE_OUT || b->dir == XC_HYPERCALL_BUFFER_BOUNCE_BOTH )
104         memcpy(b->ubuf, b->hbuf, b->sz);
105 
106     xc__hypercall_buffer_free(xch, b);
107 }
108 
109 struct xc_hypercall_buffer_array {
110     unsigned max_bufs;
111     xc_hypercall_buffer_t *bufs;
112 };
113 
xc_hypercall_buffer_array_create(xc_interface * xch,unsigned n)114 xc_hypercall_buffer_array_t *xc_hypercall_buffer_array_create(xc_interface *xch,
115                                                               unsigned n)
116 {
117     xc_hypercall_buffer_array_t *array;
118     xc_hypercall_buffer_t *bufs = NULL;
119 
120     array = malloc(sizeof(*array));
121     if ( array == NULL )
122         goto error;
123 
124     bufs = calloc(n, sizeof(*bufs));
125     if ( bufs == NULL )
126         goto error;
127 
128     array->max_bufs = n;
129     array->bufs     = bufs;
130 
131     return array;
132 
133 error:
134     free(bufs);
135     free(array);
136     return NULL;
137 }
138 
xc__hypercall_buffer_array_alloc(xc_interface * xch,xc_hypercall_buffer_array_t * array,unsigned index,xc_hypercall_buffer_t * hbuf,size_t size)139 void *xc__hypercall_buffer_array_alloc(xc_interface *xch,
140                                        xc_hypercall_buffer_array_t *array,
141                                        unsigned index,
142                                        xc_hypercall_buffer_t *hbuf,
143                                        size_t size)
144 {
145     void *buf;
146 
147     if ( index >= array->max_bufs || array->bufs[index].hbuf )
148         abort();
149 
150     buf = xc__hypercall_buffer_alloc(xch, hbuf, size);
151     if ( buf )
152         array->bufs[index] = *hbuf;
153     return buf;
154 }
155 
xc__hypercall_buffer_array_get(xc_interface * xch,xc_hypercall_buffer_array_t * array,unsigned index,xc_hypercall_buffer_t * hbuf)156 void *xc__hypercall_buffer_array_get(xc_interface *xch,
157                                      xc_hypercall_buffer_array_t *array,
158                                      unsigned index,
159                                      xc_hypercall_buffer_t *hbuf)
160 {
161     if ( index >= array->max_bufs || array->bufs[index].hbuf == NULL )
162         abort();
163 
164     *hbuf = array->bufs[index];
165     return array->bufs[index].hbuf;
166 }
167 
xc_hypercall_buffer_array_destroy(xc_interface * xc,xc_hypercall_buffer_array_t * array)168 void xc_hypercall_buffer_array_destroy(xc_interface *xc,
169                                        xc_hypercall_buffer_array_t *array)
170 {
171     unsigned i;
172 
173     if ( array == NULL )
174         return;
175 
176     for (i = 0; i < array->max_bufs; i++ )
177         xc__hypercall_buffer_free(xc, &array->bufs[i]);
178     free(array->bufs);
179     free(array);
180 }
181 
182 /*
183  * Local variables:
184  * mode: C
185  * c-file-style: "BSD"
186  * c-basic-offset: 4
187  * tab-width: 4
188  * indent-tabs-mode: nil
189  * End:
190  */
191