1 /* SPDX-License-Identifier: LGPL-2.1 */
2 /*
3 * xc_version.c
4 *
5 * Wrappers aound XENVER_* hypercalls
6 */
7
8 #include "xc_private.h"
9 #include <assert.h>
10
do_xen_version(xc_interface * xch,int cmd,xc_hypercall_buffer_t * dest)11 static int do_xen_version(xc_interface *xch, int cmd,
12 xc_hypercall_buffer_t *dest)
13 {
14 DECLARE_HYPERCALL_BUFFER_ARGUMENT(dest);
15 return xencall2(xch->xcall, __HYPERVISOR_xen_version,
16 cmd, HYPERCALL_BUFFER_AS_ARG(dest));
17 }
18
xc_version(xc_interface * xch,int cmd,void * arg)19 int xc_version(xc_interface *xch, int cmd, void *arg)
20 {
21 DECLARE_HYPERCALL_BOUNCE(arg, 0, XC_HYPERCALL_BUFFER_BOUNCE_OUT); /* Size unknown until cmd decoded */
22 size_t sz;
23 int rc;
24
25 switch ( cmd )
26 {
27 case XENVER_version:
28 sz = 0;
29 break;
30 case XENVER_extraversion:
31 sz = sizeof(xen_extraversion_t);
32 break;
33 case XENVER_compile_info:
34 sz = sizeof(xen_compile_info_t);
35 break;
36 case XENVER_capabilities:
37 sz = sizeof(xen_capabilities_info_t);
38 break;
39 case XENVER_changeset:
40 sz = sizeof(xen_changeset_info_t);
41 break;
42 case XENVER_platform_parameters:
43 sz = sizeof(xen_platform_parameters_t);
44 break;
45 case XENVER_get_features:
46 sz = sizeof(xen_feature_info_t);
47 break;
48 case XENVER_pagesize:
49 sz = 0;
50 break;
51 case XENVER_guest_handle:
52 sz = sizeof(xen_domain_handle_t);
53 break;
54 case XENVER_commandline:
55 sz = sizeof(xen_commandline_t);
56 break;
57 case XENVER_build_id:
58 {
59 xen_build_id_t *build_id = (xen_build_id_t *)arg;
60 sz = sizeof(*build_id) + build_id->len;
61 HYPERCALL_BOUNCE_SET_DIR(arg, XC_HYPERCALL_BUFFER_BOUNCE_BOTH);
62 break;
63 }
64 default:
65 ERROR("xc_version: unknown command %d\n", cmd);
66 return -EINVAL;
67 }
68
69 HYPERCALL_BOUNCE_SET_SIZE(arg, sz);
70
71 if ( (sz != 0) && xc_hypercall_bounce_pre(xch, arg) )
72 {
73 PERROR("Could not bounce buffer for version hypercall");
74 return -ENOMEM;
75 }
76
77 rc = do_xen_version(xch, cmd, HYPERCALL_BUFFER(arg));
78
79 if ( sz != 0 )
80 xc_hypercall_bounce_post(xch, arg);
81
82 return rc;
83 }
84
85 /*
86 * Raw hypercall wrapper, letting us pass NULL and things which aren't of
87 * xc_hypercall_buffer_t *.
88 */
do_xen_version_raw(xc_interface * xch,int cmd,void * hbuf)89 static int do_xen_version_raw(xc_interface *xch, int cmd, void *hbuf)
90 {
91 return xencall2(xch->xcall, __HYPERVISOR_xen_version,
92 cmd, (unsigned long)hbuf);
93 }
94
95 /*
96 * Issues a xen_varbuf_t subop, using manual hypercall buffer handling to
97 * avoid unnecessary buffering.
98 *
99 * On failure, returns NULL. errno probably useful.
100 * On success, returns a pointer which must be freed with xencall_free_buffer().
101 */
varbuf_op(xc_interface * xch,unsigned int subop)102 static xen_varbuf_t *varbuf_op(xc_interface *xch, unsigned int subop)
103 {
104 xen_varbuf_t *hbuf = NULL;
105 ssize_t sz;
106
107 sz = do_xen_version_raw(xch, subop, NULL);
108 if ( sz < 0 )
109 return NULL;
110
111 hbuf = xencall_alloc_buffer(xch->xcall, sizeof(*hbuf) + sz);
112 if ( !hbuf )
113 return NULL;
114
115 hbuf->len = sz;
116
117 sz = do_xen_version_raw(xch, subop, hbuf);
118 if ( sz < 0 )
119 {
120 xencall_free_buffer(xch->xcall, hbuf);
121 return NULL;
122 }
123
124 hbuf->len = sz;
125 return hbuf;
126 }
127
128 /*
129 * Wrap varbuf_op() to obtain a simple string. Copy out of the hypercall
130 * buffer, stripping the xen_varbuf_t header and appending a NUL terminator.
131 *
132 * On failure, returns NULL, errno probably useful.
133 * On success, returns a pointer which must be free()'d.
134 */
varbuf_simple_string(xc_interface * xch,unsigned int subop)135 static char *varbuf_simple_string(xc_interface *xch, unsigned int subop)
136 {
137 xen_varbuf_t *hbuf = varbuf_op(xch, subop);
138 char *res;
139
140 if ( !hbuf )
141 return NULL;
142
143 res = malloc(hbuf->len + 1);
144 if ( res )
145 {
146 memcpy(res, hbuf->buf, hbuf->len);
147 res[hbuf->len] = '\0';
148 }
149
150 xencall_free_buffer(xch->xcall, hbuf);
151
152 return res;
153 }
154
xc_xenver_extraversion(xc_interface * xch)155 char *xc_xenver_extraversion(xc_interface *xch)
156 {
157 return varbuf_simple_string(xch, XENVER_extraversion2);
158 }
159
xc_xenver_capabilities(xc_interface * xch)160 char *xc_xenver_capabilities(xc_interface *xch)
161 {
162 return varbuf_simple_string(xch, XENVER_capabilities2);
163 }
164
xc_xenver_changeset(xc_interface * xch)165 char *xc_xenver_changeset(xc_interface *xch)
166 {
167 return varbuf_simple_string(xch, XENVER_changeset2);
168 }
169
xc_xenver_commandline(xc_interface * xch)170 char *xc_xenver_commandline(xc_interface *xch)
171 {
172 return varbuf_simple_string(xch, XENVER_commandline2);
173 }
174
str2hex(char * dst,const unsigned char * src,size_t n)175 static void str2hex(char *dst, const unsigned char *src, size_t n)
176 {
177 static const unsigned char hex[] = "0123456789abcdef";
178
179 for ( ; n; n-- )
180 {
181 unsigned char c = *src++;
182
183 *dst++ = hex[c >> 4];
184 *dst++ = hex[c & 0xf];
185 }
186 }
187
xc_xenver_buildid(xc_interface * xch)188 char *xc_xenver_buildid(xc_interface *xch)
189 {
190 xen_varbuf_t *hbuf = varbuf_op(xch, XENVER_build_id);
191 char *res;
192
193 if ( !hbuf )
194 return NULL;
195
196 res = malloc((hbuf->len * 2) + 1);
197 if ( res )
198 {
199 str2hex(res, hbuf->buf, hbuf->len);
200 res[hbuf->len * 2] = '\0';
201 }
202
203 xencall_free_buffer(xch->xcall, hbuf);
204
205 return res;
206 }
207