Add qemu 2.4.0
[kvmfornfv.git] / qemu / roms / SLOF / lib / libvirtio / p9.c
1 /******************************************************************************
2  * Copyright (c) 2011 IBM Corporation
3  * All rights reserved.
4  * This program and the accompanying materials
5  * are made available under the terms of the BSD License
6  * which accompanies this distribution, and is available at
7  * http://www.opensource.org/licenses/bsd-license.php
8  *
9  * Contributors:
10  *     IBM Corporation - initial implementation
11  *****************************************************************************/
12
13 #include <stdio.h>
14 #include <stdint.h>
15 #include <string.h>
16 #include <byteorder.h>
17 #include "p9.h"
18
19
20 /* Protocol stack marshaling. */
21 uint8_t *sp;
22
23 #define GET_08(s,i)     (s)[(i)]
24 #define GET_16(s,i)     le16_to_cpu(*(uint16_t*)(&(s)[(i)]))
25 #define GET_32(s,i)     le32_to_cpu(*(uint32_t*)(&(s)[(i)]))
26 #define GET_64(s,i)     le64_to_cpu(*(uint64_t*)(&(s)[(i)]))
27
28 #define SET_08(s,i,v)   (s)[(i)] = (v)
29 #define SET_16(s,i,v)   *(uint16_t*)(&(s)[(i)]) = cpu_to_le16(v)
30 #define SET_32(s,i,v)   *(uint32_t*)(&(s)[(i)]) = cpu_to_le32(v)
31 #define SET_64(s,i,v)   *(uint64_t*)(&(s)[(i)]) = cpu_to_le64(v)
32
33 #define PUT_08(v)       sp[0] = (v);sp+=1
34 #define PUT_16(v)       *(uint16_t*)(&sp[0]) = cpu_to_le16(v);sp+=2
35 #define PUT_32(v)       *(uint32_t*)(&sp[0]) = cpu_to_le32(v);sp+=4
36 #define PUT_64(v)       *(uint64_t*)(&sp[0]) = cpu_to_le64(v);sp+=8
37
38 #define PUT_HD(m,t)     PUT_32(0);PUT_08(m);PUT_16(t)
39 #define PUT_SN(v,n)     PUT_16(n);memcpy(sp,(v),(n));sp+=n
40 #define PUT_ST(v)       PUT_16(strlen(v));memcpy(sp,(v),strlen(v));\
41                                 sp+=strlen(v)
42
43 #define GET_SIZE        (sp - tx)
44
45
46 /* General defines. */
47 #define MIN(a,b)        ((a)>(b)?(b):(a))
48
49 #define NOTAG           ((uint16_t)~0)
50 #define NOFID           ((uint32_t)~0)
51 #define TAG             1
52 #define BUF_SIZE        (8*1024)
53
54 #define VERSION                 "9P2000.u"
55 #define UNKNOWN_VER             "unknown"
56
57 #define MSG_SIZE                0
58 #define MSG_ID                  4
59 #define MSG_ERR                 0x6b
60 #define MSG_ERR_STR             9
61 #define MSG_ERR_STR_LEN         7
62 #define MSG_TAG                 5
63 #define MSG_VER_MSIZE           7
64 #define MSG_VER_STR_LEN         11
65 #define MSG_VER_STR             13
66 #define MSG_WALK_TX_ELMT        15
67 #define MSG_WALK_RX_ELMT        7
68 #define MSG_SIZE                0
69 #define MSG_WALK_MAX_ELMT       16
70 #define MSG_QID_SIZE            13
71 #define MSG_WALK_RX_HDR_SIZE    9
72 #define MSG_OPEN_IOUNIT         20
73 #define MSG_OPEN_MODE_MASK      0x5f
74 #define MSG_READ_COUNT          7
75 #define MSG_READ_DATA           11
76 #define MSG_STAT_LEN            42
77 #define MSG_STAT_TYPE           17
78
79 #define T_VERSION       100
80 #define R_VERSION       (T_VERSION + 1)
81 #define T_ATTACH        104
82 #define R_ATTACH        (T_ATTACH + 1)
83 #define T_ERROR         106
84 #define R_ERROR         (T_ERROR + 1)
85 #define T_WALK          110
86 #define R_WALK          (T_WALK + 1)
87 #define T_OPEN          112
88 #define R_OPEN          (T_OPEN + 1)
89 #define T_READ          116
90 #define R_READ          (T_READ + 1)
91 #define T_CLUNK         120
92 #define R_CLUNK         (T_CLUNK + 1)
93 #define T_STAT          124
94 #define R_STAT          (T_STAT + 1)
95
96 static p9_transact_t transact;
97 static void *transact_opaque;
98 static uint8_t *tx;
99 static uint8_t *rx;
100
101
102 /**
103  * p9_reg_transport
104  *
105  * Registers a transport function for use by the P9 protocol. The transport
106  * connects the P9 Client (this library) to a server instance.
107  *
108  * @param transact_func[in]     Function pointer to type p9_transact_t.
109  * @param tx_buffer[in]         TX buffer, must be 8k in size.
110  * @param rx_buffer[in]         RX buffer, must be 8k in size.
111  */
112 void p9_reg_transport(p9_transact_t transact_func, void *opaque,
113                       uint8_t *tx_buffer, uint8_t *rx_buffer)
114 {
115         transact = transact_func;
116         transact_opaque = opaque;
117         tx = tx_buffer;
118         rx = rx_buffer;
119 }
120
121 /**
122  * reset_buffers
123  *
124  * Reset the RX and TX buffers to BUF_SIZE (8k) and reset the Stack Pointer
125  * for the TX buffer, which is referenced by the PUT_* macro's.
126  */
127 void reset_buffers(void)
128 {
129         memset(tx, 0, BUF_SIZE);
130         memset(rx, 0, BUF_SIZE);
131         sp = tx;
132 }
133
134 /**
135  * p9_transaction
136  *
137  * Perform a transaction (send/recv) over the registered transport.
138  *
139  * @param connection[in|out]    Connection object.
140  * @return      0 = success, -ve = error.
141  */
142 int p9_transaction(p9_connection_t *connection)
143 {
144         int rc;
145         int tx_size = GET_SIZE;
146         int rx_size = connection->message_size;
147
148         if (transact == NULL) {
149                 return P9_NO_TRANSPORT;
150         }
151         if (tx == NULL || rx == NULL) {
152                 return P9_NO_BUFFER;
153         }
154         if (connection->message_size > BUF_SIZE) {
155                 return P9_MSG_SIZE_TOO_BIG;
156         }
157         if (tx_size > connection->message_size) {
158                 return P9_MSG_TOO_LONG;
159         }
160
161         SET_32(tx, MSG_SIZE, tx_size);
162         rc = transact(transact_opaque, tx, tx_size, rx, &rx_size);
163
164         if (rc != 0) {
165                 return P9_TRANSPORT_ERROR;
166         }
167         if (GET_16(tx, MSG_TAG) != GET_16(rx, MSG_TAG)) {
168                 return P9_UNEXPECTED_TAG;
169         }
170         if (GET_08(rx, MSG_ID) == MSG_ERR) {
171                 char error_string[200];
172
173                 memset(error_string, 0, 200);
174                 strncpy(error_string, (char *)&rx[MSG_ERR_STR],
175                                 MIN(200 - 1, GET_16(rx, MSG_ERR_STR_LEN)));
176 #ifndef TEST
177                 printf("\nError: %s\n", error_string);
178 #endif
179                 return P9_R_ERROR;
180         }
181         if ((GET_08(tx, MSG_ID) + 1) != GET_08(rx, MSG_ID)) {
182                 return P9_UNEXPECTED_MSG;
183         }
184
185         return 0;
186 }
187
188 /**
189  * p9_version
190  *
191  * Called to start a session. Negotiates the maximum message size for the
192  * P9 protocol.
193  *
194  * @param connection[in|out]    Connection object, contains message_size.
195  * @return      0 = success, -ve = error.
196  *
197  * @remark
198  * size[4] Tversion tag[2] msize[4] version[s]
199  * size[4] Rversion tag[2] msize[4] version[s]
200  */
201 int p9_version(p9_connection_t *connection)
202 {
203         int rc;
204         char *ver_str;
205         int ver_len;
206
207         reset_buffers();
208
209         /* Build message. */
210         PUT_HD(T_VERSION, NOTAG);
211         PUT_32(connection->message_size);
212         PUT_ST(VERSION);
213
214         /* Send message. */
215         rc = p9_transaction(connection);
216         if (rc != 0) {
217                 return rc;
218         }
219
220         /* Handle response. */
221         connection->message_size = MIN(connection->message_size,
222                         GET_32(rx, MSG_VER_MSIZE));
223
224         ver_str = (char *)&rx[MSG_VER_STR];
225         ver_len = GET_16(rx, MSG_VER_STR_LEN);
226         if (strncmp(UNKNOWN_VER, ver_str, ver_len) == 0) {
227                 return P9_UNKNOWN_VERSION;
228         }
229
230
231         return 0;
232 }
233
234 /**
235  * p9_attach
236  *
237  * Called to open a connection for a user to a file tree on the server. There
238  * is no authorisation undertaken (NOFID).
239  *
240  * @param connection[in|out]    Connection object, contains uname and aname as
241  *      well as the connection fid and returned qid.
242  * @return      0 = success, -ve = error.
243  *
244  * @remark
245  * size[4] Tattach tag[2] fid[4] afid[4] uname[s] aname[s] n_uname[4]
246  * size[4] Rattach tag[2] qid[13]
247  */
248 int p9_attach(p9_connection_t *connection)
249 {
250         int rc;
251         int length = 19 + strlen(connection->uname) + strlen(connection->aname);
252
253         if (length > connection->message_size) {
254                 return P9_MSG_TOO_LONG;
255         }
256
257         reset_buffers();
258
259         /* Build message. */
260         PUT_HD(T_ATTACH, TAG);
261         PUT_32(connection->fid);        
262         PUT_32(NOFID);
263         PUT_ST(connection->uname);
264         PUT_ST(connection->aname);
265         PUT_32(~0); /* ??? */
266
267         /* Send message. */
268         rc = p9_transaction(connection);
269         if (rc != 0) {
270                 return rc;
271         }
272
273
274         return 0;
275 }
276
277 /**
278  * p9_clunk
279  *
280  * Called when closing a file or connection (or after failed opens). Tells the
281  * server that the supplied fid is no longer needed by this client.
282  *
283  * @param connection[in|out]    Connection object.
284  * @param fid[in]       Fid to be clunked (released) on the server.
285  * @return      0 = success, -ve = error.
286  *
287  * @remark
288  * size[4] Tclunk tag[2] fid[4]
289  * size[4] Rclunk tag[2]
290  */
291 int p9_clunk(p9_connection_t *connection, uint32_t fid)
292 {
293         int rc;
294
295         reset_buffers();
296
297         /* Build message. */
298         PUT_HD(T_CLUNK, TAG);
299         PUT_32(fid);
300
301         /* Send message. */
302         rc = p9_transaction(connection);
303         if (rc != 0) {
304                 return rc;
305         }
306
307
308         return 0;
309 }
310
311 /**
312  * p9_walk
313  *
314  * Walk the provided path to a file (or directory) starting at the directory
315  * indicated by fid and assigning new_fid to the last successfully walked
316  * element. If not all elements of the path can be walked then the pos
317  * pointer is set to the part of the path following the last successful
318  * walked element. The function can be called again to walk the remainder
319  * of the path (or produce an error).
320  *
321  * @param connection[in]        Connection object.
322  * @param fid[in]       Fid to start walk from, must be directory or root (from
323  *      call to p9_attach).
324  * @param new_fid[in]   Fid to be used for the last walked element.
325  * @param pos[in|out]   Position in path that remains to be walked. If the
326  *      path was completely walked without error this will point to the NULL
327  *      at the end of path.
328  * @return      1 = partial walk, 0 = success, -ve = error.
329  *
330  * @remark
331  * size[4] Twalk tag[2] fid[4] newfid[4] nwname[2] nwname*(wname[s])
332  * size[4] Rwalk tag[2] nwqid[2] nwqid*(qid[13])
333  */
334 int p9_walk(p9_connection_t *connection, uint32_t fid, uint32_t new_fid,
335                 uint8_t **pos)
336 {
337         int rc;
338         const char *path = (const char *)*pos;
339         uint8_t *s_tok;
340         uint8_t *e_tok;
341         int element_count = 0;
342
343         if (path == NULL) {
344                 *pos = NULL;
345                 return P9_NULL_PATH;
346         }
347
348         reset_buffers();
349
350         /* Build message. */
351         PUT_HD(T_WALK, TAG);    /* Length to 0, set later. */
352         PUT_32(fid);
353         PUT_32(new_fid);
354         PUT_16(0);              /* Element count to 0, set later. */
355
356         /* Get elements from path, and append to message. */
357         s_tok = (uint8_t *)path;
358         e_tok = s_tok;
359
360         while (*s_tok != 0) {
361                 while (*s_tok == '/') {
362                         s_tok++;
363                 }
364                 e_tok = s_tok;
365                 while ((*e_tok != '/') && (*e_tok != 0)) {
366                         e_tok++;
367                 }
368
369                 /* Check the element is OK. */
370                 if (strncmp(".", (const char *)s_tok, (e_tok - s_tok)) == 0) {
371                         /* Don't send ".", continue to next. */
372                         s_tok = e_tok;
373                         continue;
374                 }
375                 int tx_size = (e_tok - s_tok + 2 + GET_SIZE);
376                 int rx_size = ((element_count + 1) * MSG_QID_SIZE
377                                 + MSG_WALK_RX_HDR_SIZE);
378                 if ((tx_size > connection->message_size)
379                         || (rx_size > connection->message_size)) {
380                         /*
381                          * Element makes TX msg too long OR expected RX msg
382                          * too long. Move pos to previous element and do
383                          * partial walk.
384                          */
385                         e_tok = s_tok;
386                         if (*(e_tok - 1) == '/') {
387                                 e_tok--;
388                         }
389                         break;
390                 }
391
392                 /* Add the element to the message. */
393                 PUT_SN(s_tok, e_tok - s_tok);
394                 element_count++;
395
396                 /* Server supports no more than 16 elements, partial walk. */
397                 if (element_count == MSG_WALK_MAX_ELMT) {
398                         break;
399                 }
400
401                 /* Ready to find the next element. */
402                 s_tok = e_tok;
403         }
404
405         if ((element_count == 0) && (strlen(path) > 0)) {
406                 return P9_PATH_ELEMENT_TOO_LONG;
407         }
408
409         *pos = e_tok;
410
411         /* Update counts and then send message. */
412         SET_16(tx, MSG_WALK_TX_ELMT, element_count);
413         rc = p9_transaction(connection);
414         if (rc != 0) {
415                 return rc;
416         }
417
418         /* Check for special return conditions. */
419         if (element_count != GET_16(rx, MSG_WALK_RX_ELMT)) {
420                 /* Find the last element successfully walked */
421                 s_tok = (uint8_t *)path;
422                 e_tok = s_tok;
423                 element_count = GET_16(rx, MSG_WALK_RX_ELMT);
424
425                 while (element_count--) {
426                         while (*s_tok == '/') {
427                                 s_tok++;
428                         }
429
430                         e_tok = s_tok;
431
432                         while ((*e_tok != '/') && (*e_tok != 0)) {
433                                 e_tok++;
434                         }
435
436                         s_tok = e_tok;
437                 }
438
439                 *pos = e_tok;
440         }
441         if (**pos != 0) {
442                 rc = P9_PARTIAL_WALK;
443         }
444
445
446         return rc;
447 }
448
449 /**
450  * p9_open
451  *
452  * Opens the file represented by fid with associated mode bit mask. The iounit
453  * size returned from the server is written to the connection object.
454  *
455  * @param file[in|out]  File object, contains fid for file.
456  * @param mode[in]      Mode to open with. Bit's 0=R, 1=W, 2=RW, 3=EX, 4=Trunc
457  *      and 6=Delete on Close.
458  * @return      0 = success, -ve = error.
459  *
460  * @remark
461  * size[4] Topen tag[2] fid[4] mode[1]
462  * size[4] Ropen tag[2] qid[13] iounit[4]
463  */
464 int p9_open(p9_file_t *file, uint8_t mode)
465 {
466         int rc;
467         p9_connection_t *connection = file->connection;
468
469         reset_buffers();
470         file->iounit = 0;
471
472         /* Build message. */
473         PUT_HD(T_OPEN, TAG);
474         PUT_32(file->fid);
475         PUT_08(mode & MSG_OPEN_MODE_MASK);
476
477         /* Send message. */
478         rc = p9_transaction(connection);
479         if (rc != 0) {
480                 return rc;
481         }
482
483         /* Handle response. */
484         file->iounit = GET_32(rx, MSG_OPEN_IOUNIT);
485
486
487         return 0;
488 }
489
490 /**
491  * p9_read
492  *
493  * Reads the file in to buffer.
494  *
495  * @param file[in]      File object, contains fid for file.
496  * @param buffer[out]   Buffer for data.
497  * @param count[in]     Number of bytes to read (less bytes than requested
498  *       may be read).
499  * @param offset[in]    Offset in file to read from.
500  * @return      Bytes read, -ve = error.
501  *
502  * @remark
503  * size[4] Tread tag[2] fid[4] offset[8] count[4]
504  * size[4] Rread tag[2] count[4] data[count]
505  */
506 int p9_read(p9_file_t *file, uint8_t *buffer,
507                 uint32_t count, uint64_t offset)
508 {
509         int rc;
510         p9_connection_t *connection = file->connection;
511         uint32_t got;
512
513         reset_buffers();
514         count = MIN((connection->message_size - MSG_READ_DATA), count);
515
516         /* Build message. */
517         PUT_HD(T_READ, TAG);
518         PUT_32(file->fid);
519         PUT_64(offset);
520         PUT_32(count);
521
522         /* Send message. */
523         rc = p9_transaction(connection);
524         if (rc != 0) {
525                 return rc;
526         }
527         got = GET_32(rx, MSG_READ_COUNT);
528         if (got > count) {
529                 return P9_READ_UNEXPECTED_DATA;
530         }
531
532         /* Handle response. */
533         memcpy(buffer, &rx[MSG_READ_DATA], got);
534
535         return got;
536 }
537
538 /**
539  * p9_stat
540  *
541  * Stat's the fid and writes the type and length to the file object.
542  *
543  * @param file[in|out]  File object, contains fid for file.
544  * @return      0 = success, -ve = error.
545  *
546  * @remark
547  * size[4] Tstat tag[2] fid[4]
548  * size[4] Rstat tag[2] size[2] stat[n]
549  */
550 int p9_stat(p9_file_t *file)
551 {
552         int rc;
553         p9_connection_t *connection = file->connection;
554
555         reset_buffers();
556         file->length = 0;
557         file->type = 0;
558
559         /* Build message. */
560         PUT_HD(T_STAT, TAG);
561         PUT_32(file->fid);
562
563         /* Send message. */
564         rc = p9_transaction(connection);
565         if (rc != 0) {
566                 return rc;
567         }
568
569         /* Handle response. */
570         file->length = GET_64(rx, MSG_STAT_LEN);
571         file->type = GET_08(rx, MSG_STAT_TYPE);
572
573
574         return 0;
575 }