2 * Copyright (C) 2012 Michael Brown <mbrown@fensystems.co.uk>.
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.
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.
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
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.
24 FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
28 * VMware GuestRPC mechanism
36 #include <ipxe/vmware.h>
37 #include <ipxe/guestrpc.h>
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" )
63 * Open GuestRPC channel
65 * @ret channel Channel number, or negative error
67 int guestrpc_open ( void ) {
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",
81 DBGC ( GUESTRPC_MAGIC, "GuestRPC channel %d opened\n", channel );
86 * Send GuestRPC command length
88 * @v channel Channel number
89 * @v len Command length
90 * @ret rc Return status code
92 static int guestrpc_command_len ( int channel, size_t len ) {
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;
111 * Send GuestRPC command data
113 * @v channel Channel number
114 * @v data Command data
115 * @ret rc Return status code
117 static int guestrpc_command_data ( int channel, uint32_t data ) {
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;
136 * Receive GuestRPC reply length
138 * @v channel Channel number
139 * @ret reply_id Reply ID
140 * @ret len Reply length, or negative error
142 static int guestrpc_reply_len ( int channel, uint16_t *reply_id ) {
146 /* Issue GuestRPC command */
147 status = vmware_cmd_guestrpc ( channel, GUESTRPC_REPLY_LEN, 0,
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;
159 * Receive GuestRPC reply data
161 * @v channel Channel number
162 * @v reply_id Reply ID
163 * @ret data Reply data
164 * @ret rc Return status code
166 static int guestrpc_reply_data ( int channel, uint16_t reply_id,
171 /* Issue GuestRPC command */
172 status = vmware_cmd_guestrpc ( channel, GUESTRPC_REPLY_DATA, reply_id,
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;
185 * Finish receiving GuestRPC reply
187 * @v channel Channel number
188 * @v reply_id Reply ID
189 * @ret rc Return status code
191 static int guestrpc_reply_finish ( int channel, uint16_t reply_id ) {
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;
209 * Close GuestRPC channel
211 * @v channel Channel number
213 void guestrpc_close ( int channel ) {
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 );
227 DBGC ( GUESTRPC_MAGIC, "GuestRPC channel %d closed\n", channel );
231 * Issue GuestRPC command
233 * @v channel Channel number
235 * @v reply Reply buffer
236 * @v reply_len Length of reply buffer
237 * @ret len Length of reply, or negative error
239 * The actual length of the reply will be returned even if the buffer
242 int guestrpc_command ( int channel, const char *command, char *reply,
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;
249 uint8_t *status_bytes = ( ( void * ) &status );
250 size_t status_len = sizeof ( status );
258 DBGC2 ( GUESTRPC_MAGIC, "GuestRPC channel %d issuing command:\n",
260 DBGC2_HDA ( GUESTRPC_MAGIC, 0, command, command_len );
263 assert ( ( reply != NULL ) || ( reply_len == 0 ) );
265 /* Send command length */
266 if ( ( rc = guestrpc_command_len ( channel, command_len ) ) < 0 )
269 /* Send command data */
270 while ( command_len ) {
272 for ( i = sizeof ( data ) ; i ; i-- ) {
274 data = ( ( data & ~0xff ) |
275 *(command_bytes++) );
278 data = ( ( data << 24 ) | ( data >> 8 ) );
280 if ( ( rc = guestrpc_command_data ( channel, data ) ) < 0 )
284 /* Receive reply length */
285 if ( ( len = guestrpc_reply_len ( channel, &reply_id ) ) < 0 ) {
291 for ( remaining = len ; remaining > 0 ; remaining -= sizeof ( data ) ) {
292 if ( ( rc = guestrpc_reply_data ( channel, reply_id,
296 for ( i = sizeof ( data ) ; i ; i-- ) {
298 *(status_bytes++) = ( data & 0xff );
301 } else if ( reply_len ) {
302 *(reply_bytes++) = ( data & 0xff );
305 data = ( ( data << 24 ) | ( data >> 8 ) );
309 /* Finish receiving RPC reply */
310 if ( ( rc = guestrpc_reply_finish ( channel, reply_id ) ) < 0 )
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 ) );
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 ));