These changes are the raw update to qemu-2.6.
[kvmfornfv.git] / qemu / roms / ipxe / src / arch / i386 / interface / vmware / guestrpc.c
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  */
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  */
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  */
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  */
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  */
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  */
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  */
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  */
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 }