iPXE
guestrpc.c
Go to the documentation of this file.
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 ) {
69  uint32_t discard_b;
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;
96 
97  /* Issue GuestRPC command */
98  status = vmware_cmd_guestrpc ( channel, GUESTRPC_COMMAND_LEN, len,
99  &discard_d, &discard_b );
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  */
118  uint16_t discard_d;
119  uint32_t discard_b;
121 
122  /* Issue GuestRPC command */
123  status = vmware_cmd_guestrpc ( channel, GUESTRPC_COMMAND_DATA, data,
124  &discard_d, &discard_b );
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;
145 
146  /* Issue GuestRPC command */
147  status = vmware_cmd_guestrpc ( channel, GUESTRPC_REPLY_LEN, 0,
148  reply_id, &len );
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;
170 
171  /* Issue GuestRPC command */
172  status = vmware_cmd_guestrpc ( channel, GUESTRPC_REPLY_DATA, reply_id,
173  &discard_d, data );
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;
195 
196  /* Issue GuestRPC command */
197  status = vmware_cmd_guestrpc ( channel, GUESTRPC_REPLY_FINISH, reply_id,
198  &discard_d, &discard_b );
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;
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;
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 );
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 );
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 }
struct arbelprm_rc_send_wqe rc
Definition: arbel.h:14
#define GUESTRPC_OPEN_SUCCESS
Open RPC channel success status.
Definition: guestrpc.h:22
unsigned short uint16_t
Definition: stdint.h:11
device command_len
Definition: threewire.h:59
static int guestrpc_reply_data(int channel, uint16_t reply_id, uint32_t *data)
Receive GuestRPC reply data.
Definition: guestrpc.c:166
#define GUESTRPC_COMMAND_LEN_SUCCESS
Send RPC command length success status.
Definition: guestrpc.h:28
int guestrpc_open(void)
Open GuestRPC channel.
Definition: guestrpc.c:67
#define GUESTRPC_CLOSE
Close RPC channel.
Definition: guestrpc.h:55
Error codes.
A command-line command.
Definition: command.h:9
static int guestrpc_command_data(int channel, uint32_t data)
Send GuestRPC command data.
Definition: guestrpc.c:117
#define EPROTO_REPLY_FINISH
Definition: guestrpc.c:55
#define GUESTRPC_COMMAND_DATA_SUCCESS
Send RPC command data success status.
Definition: guestrpc.h:34
#define DBGC(...)
Definition: compiler.h:505
FILE_LICENCE(GPL2_OR_LATER_OR_UBDL)
#define EPROTO_OPEN
Definition: guestrpc.c:40
uint8_t status
Status.
Definition: ena.h:16
#define GUESTRPC_CLOSE_SUCCESS
Close RPC channel success status.
Definition: guestrpc.h:58
#define GUESTRPC_REPLY_DATA
Receive RPC reply data.
Definition: guestrpc.h:43
#define GUESTRPC_REPLY_DATA_SUCCESS
Receive RPC reply data success status.
Definition: guestrpc.h:46
Assertions.
#define EPROTO_REPLY_DATA
Definition: guestrpc.c:52
assert((readw(&hdr->flags) &(GTF_reading|GTF_writing))==0)
VMware backdoor mechanism.
#define DBGC_HDA(...)
Definition: compiler.h:506
#define GUESTRPC_COMMAND_DATA
Send RPC command data.
Definition: guestrpc.h:31
static int guestrpc_command_len(int channel, size_t len)
Send GuestRPC command length.
Definition: guestrpc.c:92
VMware GuestRPC mechanism.
uint32_t channel
RNDIS channel.
Definition: netvsc.h:14
int guestrpc_command(int channel, const char *command, char *reply, size_t reply_len)
Issue GuestRPC command.
Definition: guestrpc.c:242
static int guestrpc_reply_len(int channel, uint16_t *reply_id)
Receive GuestRPC reply length.
Definition: guestrpc.c:142
#define GUESTRPC_COMMAND_LEN
Send RPC command length.
Definition: guestrpc.h:25
#define DBGC2_HDA(...)
Definition: compiler.h:523
#define EPROTO_COMMAND_LEN
Definition: guestrpc.c:43
#define EPROTO_REPLY_LEN
Definition: guestrpc.c:49
void guestrpc_close(int channel)
Close GuestRPC channel.
Definition: guestrpc.c:213
size_t strlen(const char *src)
Get length of string.
Definition: string.c:243
unsigned char uint8_t
Definition: stdint.h:10
unsigned int uint32_t
Definition: stdint.h:12
#define GUESTRPC_REPLY_LEN_SUCCESS
Receive RPC reply length success status.
Definition: guestrpc.h:40
#define GUESTRPC_OPEN
Open RPC channel.
Definition: guestrpc.h:19
#define EPROTO_COMMAND_DATA
Definition: guestrpc.c:46
static int guestrpc_reply_finish(int channel, uint16_t reply_id)
Finish receiving GuestRPC reply.
Definition: guestrpc.c:191
uint32_t len
Length.
Definition: ena.h:14
#define DBGC2(...)
Definition: compiler.h:522
#define GUESTRPC_SUCCESS
RPC command success status.
Definition: guestrpc.h:61
#define EIO
Input/output error.
Definition: errno.h:433
uint8_t data[48]
Additional event data.
Definition: ena.h:22
#define GUESTRPC_REPLY_FINISH_SUCCESS
Finish receiving RPC reply success status.
Definition: guestrpc.h:52
#define GUESTRPC_REPLY_FINISH
Finish receiving RPC reply.
Definition: guestrpc.h:49
#define GUESTRPC_REPLY_LEN
Receive RPC reply length.
Definition: guestrpc.h:37
#define GUESTRPC_MAGIC
GuestRPC magic number.
Definition: guestrpc.h:16
#define NULL
NULL pointer (VOID *)
Definition: Base.h:321
String functions.