1 /*
2 * Copyright (C) 2012 Michael Brown <mbrown@fensystems.co.uk>.
3 *
4 * This program is free software; you can redistribute it and/or
5 * modify it under the terms of the GNU General Public License as
6 * published by the Free Software Foundation; either version 2 of the
7 * License, or any later version.
8 *
9 * This program is distributed in the hope that it will be useful, but
10 * WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 * General Public License for more details.
13 *
14 * You should have received a copy of the GNU General Public License
15 * along with this program; if not, write to the Free Software
16 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
17 * 02110-1301, USA.
18 *
19 * You can also choose to distribute this program under the terms of
20 * the Unmodified Binary Distribution Licence (as given in the file
21 * COPYING.UBDL), provided that you have satisfied its requirements.
22 */
23
24 FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
25
26 /** @file
27 *
28 * VMware GuestRPC mechanism
29 *
30 */
31
32 #include <stdint.h>
33 #include <string.h>
34 #include <errno.h>
35 #include <assert.h>
36 #include <ipxe/vmware.h>
37 #include <ipxe/guestrpc.h>
38
39 /* Disambiguate the various error causes */
40 #define EPROTO_OPEN __einfo_error ( EINFO_EPROTO_OPEN )
41 #define EINFO_EPROTO_OPEN \
42 __einfo_uniqify ( EINFO_EPROTO, 0x00, "GuestRPC open failed" )
43 #define EPROTO_COMMAND_LEN __einfo_error ( EINFO_EPROTO_COMMAND_LEN )
44 #define EINFO_EPROTO_COMMAND_LEN \
45 __einfo_uniqify ( EINFO_EPROTO, 0x01, "GuestRPC command length failed" )
46 #define EPROTO_COMMAND_DATA __einfo_error ( EINFO_EPROTO_COMMAND_DATA )
47 #define EINFO_EPROTO_COMMAND_DATA \
48 __einfo_uniqify ( EINFO_EPROTO, 0x02, "GuestRPC command data failed" )
49 #define EPROTO_REPLY_LEN __einfo_error ( EINFO_EPROTO_REPLY_LEN )
50 #define EINFO_EPROTO_REPLY_LEN \
51 __einfo_uniqify ( EINFO_EPROTO, 0x03, "GuestRPC reply length failed" )
52 #define EPROTO_REPLY_DATA __einfo_error ( EINFO_EPROTO_REPLY_DATA )
53 #define EINFO_EPROTO_REPLY_DATA \
54 __einfo_uniqify ( EINFO_EPROTO, 0x04, "GuestRPC reply data failed" )
55 #define EPROTO_REPLY_FINISH __einfo_error ( EINFO_EPROTO_REPLY_FINISH )
56 #define EINFO_EPROTO_REPLY_FINISH \
57 __einfo_uniqify ( EINFO_EPROTO, 0x05, "GuestRPC reply finish failed" )
58 #define EPROTO_CLOSE __einfo_error ( EINFO_EPROTO_CLOSE )
59 #define EINFO_EPROTO_CLOSE \
60 __einfo_uniqify ( EINFO_EPROTO, 0x06, "GuestRPC close failed" )
61
62 /**
63 * Open GuestRPC channel
64 *
65 * @ret channel Channel number, or negative error
66 */
guestrpc_open(void)67 int guestrpc_open ( void ) {
68 uint16_t channel;
69 uint32_t discard_b;
70 uint32_t status;
71
72 /* Issue GuestRPC command */
73 status = vmware_cmd_guestrpc ( 0, GUESTRPC_OPEN, GUESTRPC_MAGIC,
74 &channel, &discard_b );
75 if ( status != GUESTRPC_OPEN_SUCCESS ) {
76 DBGC ( GUESTRPC_MAGIC, "GuestRPC open failed: status %08x\n",
77 status );
78 return -EPROTO_OPEN;
79 }
80
81 DBGC ( GUESTRPC_MAGIC, "GuestRPC channel %d opened\n", channel );
82 return channel;
83 }
84
85 /**
86 * Send GuestRPC command length
87 *
88 * @v channel Channel number
89 * @v len Command length
90 * @ret rc Return status code
91 */
guestrpc_command_len(int channel,size_t len)92 static int guestrpc_command_len ( int channel, size_t len ) {
93 uint16_t discard_d;
94 uint32_t discard_b;
95 uint32_t status;
96
97 /* Issue GuestRPC command */
98 status = vmware_cmd_guestrpc ( channel, GUESTRPC_COMMAND_LEN, len,
99 &discard_d, &discard_b );
100 if ( status != GUESTRPC_COMMAND_LEN_SUCCESS ) {
101 DBGC ( GUESTRPC_MAGIC, "GuestRPC channel %d send command "
102 "length %zd failed: status %08x\n",
103 channel, len, status );
104 return -EPROTO_COMMAND_LEN;
105 }
106
107 return 0;
108 }
109
110 /**
111 * Send GuestRPC command data
112 *
113 * @v channel Channel number
114 * @v data Command data
115 * @ret rc Return status code
116 */
guestrpc_command_data(int channel,uint32_t data)117 static int guestrpc_command_data ( int channel, uint32_t data ) {
118 uint16_t discard_d;
119 uint32_t discard_b;
120 uint32_t status;
121
122 /* Issue GuestRPC command */
123 status = vmware_cmd_guestrpc ( channel, GUESTRPC_COMMAND_DATA, data,
124 &discard_d, &discard_b );
125 if ( status != GUESTRPC_COMMAND_DATA_SUCCESS ) {
126 DBGC ( GUESTRPC_MAGIC, "GuestRPC channel %d send command "
127 "data %08x failed: status %08x\n",
128 channel, data, status );
129 return -EPROTO_COMMAND_DATA;
130 }
131
132 return 0;
133 }
134
135 /**
136 * Receive GuestRPC reply length
137 *
138 * @v channel Channel number
139 * @ret reply_id Reply ID
140 * @ret len Reply length, or negative error
141 */
guestrpc_reply_len(int channel,uint16_t * reply_id)142 static int guestrpc_reply_len ( int channel, uint16_t *reply_id ) {
143 uint32_t len;
144 uint32_t status;
145
146 /* Issue GuestRPC command */
147 status = vmware_cmd_guestrpc ( channel, GUESTRPC_REPLY_LEN, 0,
148 reply_id, &len );
149 if ( status != GUESTRPC_REPLY_LEN_SUCCESS ) {
150 DBGC ( GUESTRPC_MAGIC, "GuestRPC channel %d receive reply "
151 "length failed: status %08x\n", channel, status );
152 return -EPROTO_REPLY_LEN;
153 }
154
155 return len;
156 }
157
158 /**
159 * Receive GuestRPC reply data
160 *
161 * @v channel Channel number
162 * @v reply_id Reply ID
163 * @ret data Reply data
164 * @ret rc Return status code
165 */
guestrpc_reply_data(int channel,uint16_t reply_id,uint32_t * data)166 static int guestrpc_reply_data ( int channel, uint16_t reply_id,
167 uint32_t *data ) {
168 uint16_t discard_d;
169 uint32_t status;
170
171 /* Issue GuestRPC command */
172 status = vmware_cmd_guestrpc ( channel, GUESTRPC_REPLY_DATA, reply_id,
173 &discard_d, data );
174 if ( status != GUESTRPC_REPLY_DATA_SUCCESS ) {
175 DBGC ( GUESTRPC_MAGIC, "GuestRPC channel %d receive reply "
176 "%d data failed: status %08x\n",
177 channel, reply_id, status );
178 return -EPROTO_REPLY_DATA;
179 }
180
181 return 0;
182 }
183
184 /**
185 * Finish receiving GuestRPC reply
186 *
187 * @v channel Channel number
188 * @v reply_id Reply ID
189 * @ret rc Return status code
190 */
guestrpc_reply_finish(int channel,uint16_t reply_id)191 static int guestrpc_reply_finish ( int channel, uint16_t reply_id ) {
192 uint16_t discard_d;
193 uint32_t discard_b;
194 uint32_t status;
195
196 /* Issue GuestRPC command */
197 status = vmware_cmd_guestrpc ( channel, GUESTRPC_REPLY_FINISH, reply_id,
198 &discard_d, &discard_b );
199 if ( status != GUESTRPC_REPLY_FINISH_SUCCESS ) {
200 DBGC ( GUESTRPC_MAGIC, "GuestRPC channel %d finish reply %d "
201 "failed: status %08x\n", channel, reply_id, status );
202 return -EPROTO_REPLY_FINISH;
203 }
204
205 return 0;
206 }
207
208 /**
209 * Close GuestRPC channel
210 *
211 * @v channel Channel number
212 */
guestrpc_close(int channel)213 void guestrpc_close ( int channel ) {
214 uint16_t discard_d;
215 uint32_t discard_b;
216 uint32_t status;
217
218 /* Issue GuestRPC command */
219 status = vmware_cmd_guestrpc ( channel, GUESTRPC_CLOSE, 0,
220 &discard_d, &discard_b );
221 if ( status != GUESTRPC_CLOSE_SUCCESS ) {
222 DBGC ( GUESTRPC_MAGIC, "GuestRPC channel %d close failed: "
223 "status %08x\n", channel, status );
224 return;
225 }
226
227 DBGC ( GUESTRPC_MAGIC, "GuestRPC channel %d closed\n", channel );
228 }
229
230 /**
231 * Issue GuestRPC command
232 *
233 * @v channel Channel number
234 * @v command Command
235 * @v reply Reply buffer
236 * @v reply_len Length of reply buffer
237 * @ret len Length of reply, or negative error
238 *
239 * The actual length of the reply will be returned even if the buffer
240 * was too small.
241 */
guestrpc_command(int channel,const char * command,char * reply,size_t reply_len)242 int guestrpc_command ( int channel, const char *command, char *reply,
243 size_t reply_len ) {
244 const uint8_t *command_bytes = ( ( const void * ) command );
245 uint8_t *reply_bytes = ( ( void * ) reply );
246 size_t command_len = strlen ( command );
247 int orig_reply_len = reply_len;
248 uint16_t status;
249 uint8_t *status_bytes = ( ( void * ) &status );
250 size_t status_len = sizeof ( status );
251 uint32_t data;
252 uint16_t reply_id;
253 int len;
254 int remaining;
255 unsigned int i;
256 int rc;
257
258 DBGC2 ( GUESTRPC_MAGIC, "GuestRPC channel %d issuing command:\n",
259 channel );
260 DBGC2_HDA ( GUESTRPC_MAGIC, 0, command, command_len );
261
262 /* Sanity check */
263 assert ( ( reply != NULL ) || ( reply_len == 0 ) );
264
265 /* Send command length */
266 if ( ( rc = guestrpc_command_len ( channel, command_len ) ) < 0 )
267 return rc;
268
269 /* Send command data */
270 while ( command_len ) {
271 data = 0;
272 for ( i = sizeof ( data ) ; i ; i-- ) {
273 if ( command_len ) {
274 data = ( ( data & ~0xff ) |
275 *(command_bytes++) );
276 command_len--;
277 }
278 data = ( ( data << 24 ) | ( data >> 8 ) );
279 }
280 if ( ( rc = guestrpc_command_data ( channel, data ) ) < 0 )
281 return rc;
282 }
283
284 /* Receive reply length */
285 if ( ( len = guestrpc_reply_len ( channel, &reply_id ) ) < 0 ) {
286 rc = len;
287 return rc;
288 }
289
290 /* Receive reply */
291 for ( remaining = len ; remaining > 0 ; remaining -= sizeof ( data ) ) {
292 if ( ( rc = guestrpc_reply_data ( channel, reply_id,
293 &data ) ) < 0 ) {
294 return rc;
295 }
296 for ( i = sizeof ( data ) ; i ; i-- ) {
297 if ( status_len ) {
298 *(status_bytes++) = ( data & 0xff );
299 status_len--;
300 len--;
301 } else if ( reply_len ) {
302 *(reply_bytes++) = ( data & 0xff );
303 reply_len--;
304 }
305 data = ( ( data << 24 ) | ( data >> 8 ) );
306 }
307 }
308
309 /* Finish receiving RPC reply */
310 if ( ( rc = guestrpc_reply_finish ( channel, reply_id ) ) < 0 )
311 return rc;
312
313 DBGC2 ( GUESTRPC_MAGIC, "GuestRPC channel %d received reply (id %d, "
314 "length %d):\n", channel, reply_id, len );
315 DBGC2_HDA ( GUESTRPC_MAGIC, 0, &status, sizeof ( status ) );
316 DBGC2_HDA ( GUESTRPC_MAGIC, sizeof ( status ), reply,
317 ( ( len < orig_reply_len ) ? len : orig_reply_len ) );
318
319 /* Check reply status */
320 if ( status != GUESTRPC_SUCCESS ) {
321 DBGC ( GUESTRPC_MAGIC, "GuestRPC channel %d command failed "
322 "(status %04x, reply id %d, reply length %d):\n",
323 channel, status, reply_id, len );
324 DBGC_HDA ( GUESTRPC_MAGIC, 0, command, command_len );
325 DBGC_HDA ( GUESTRPC_MAGIC, 0, &status, sizeof ( status ) );
326 DBGC_HDA ( GUESTRPC_MAGIC, sizeof ( status ), reply,
327 ( ( len < orig_reply_len ) ? len : orig_reply_len ));
328 return -EIO;
329 }
330
331 return len;
332 }
333