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