1 /******************************************************************************
2 * Copyright (c) 2011 IBM Corporation
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
10 * IBM Corporation - initial implementation
11 *****************************************************************************/
16 #include <byteorder.h>
19 #include "virtio-9p.h"
25 * Notes for 9P Server config:
27 * make distclean; cm make qemu
28 * sudo cp boot_rom.bin /opt/qemu/share/qemu/slof.bin
29 * /opt/qemu/bin/qemu-system-ppc64 -M pseries -m 512 -boot d -nographic -fsdev
30 * local,id=trule,path=/home/trule/virtfs,security_model=none -device
31 * virtio-9p-spapr,fsdev=trule,mount_tag=trule
32 * load virtfs:\some\file
35 /* We support only one instance due to the (ab)use of globals. We
36 * use the buffer size as an open marker as well.
38 static int __buf_size;
44 #define MIN(a,b) ((a)>(b)?(b):(a))
50 #define dprintf(_x ...) do { printf(_x); } while(0)
52 #define dprintf(_x ...)
56 static void dprint_buffer(const char *name, uint8_t *buffer, int length)
60 printf("*** %s ***", name);
62 for (i = 0; i < length; i++) {
64 printf("\n %04x:", i);
67 printf(" %02x", buffer[i]);
73 #define dprint_buffer(n, b, l)
79 * Perform a 9P transaction over the VIRTIO queue interface. This function is
80 * registered with the p9.c library via p9_reg_transport() to provide
81 * connectivity to the 9P server.
83 * @param tx[in] Data to send, mapped to first queue item.
84 * @param tx_size[in] Size of data to send.
85 * @param rx[out] Data to receive, mappend to second queue item.
86 * @param rx_size[out] Size of data received.
87 * @return 0 = success, -ve = error.
89 static int virtio_9p_transact(void *opaque, uint8_t *tx, int tx_size, uint8_t *rx,
92 struct virtio_device *dev = opaque;
93 struct vring_desc *desc;
96 struct vring_desc *vq_desc;
97 struct vring_avail *vq_avail;
98 struct vring_used *vq_used;
99 volatile uint16_t *current_used_idx;
100 uint16_t last_used_idx;
103 /* Virt IO queues. */
104 vq_size = virtio_get_qsize(dev, 0);
105 vq_desc = virtio_get_vring_desc(dev, 0);
106 vq_avail = virtio_get_vring_avail(dev, 0);
107 vq_used = virtio_get_vring_used(dev, 0);
109 last_used_idx = vq_used->idx;
110 current_used_idx = &vq_used->idx;
112 /* Determine descriptor index */
113 id = (vq_avail->idx * 3) % vq_size;
115 /* TX in first queue item. */
116 dprint_buffer("TX", tx, tx_size);
119 desc->addr = (uint64_t)tx;
121 desc->flags = VRING_DESC_F_NEXT;
122 desc->next = (id + 1) % vq_size;
124 /* RX in the second queue item. */
125 desc = &vq_desc[(id + 1) % vq_size];
126 desc->addr = (uint64_t)rx;
127 desc->len = *rx_size;
128 desc->flags = VRING_DESC_F_WRITE;
131 /* Tell HV that the queue is ready */
132 vq_avail->ring[vq_avail->idx % vq_size] = id;
135 virtio_queue_notify(dev, 0);
137 /* Receive the response. */
139 while (*current_used_idx == last_used_idx && i-- > 0) {
140 // do something better
147 *rx_size = MIN(*rx_size, le32_to_cpu(*(uint32_t*)(&rx[0])));
148 dprint_buffer("RX", rx, *rx_size);
156 * Establish the VIRTIO connection for use with the 9P server. Setup queues
157 * and negotiate capabilities. Setup the 9P (Client) library.
159 * @param reg[in] Pointer to device tree node for VIRTIO/9P interface.
160 * @param tx_buf[in] TX buffer for use by 9P Client lib - 8K in size.
161 * @param rx_buf[in] TX buffer for use by 9P Client lib - 8K in size.
162 * @param buf_size Somewhat redundant, buffer size expected to be 8k.
163 * @return 0 = success, -ve = error.
165 int virtio_9p_init(struct virtio_device *dev, void *tx_buf, void *rx_buf,
168 struct vring_avail *vq_avail;
169 int status = VIRTIO_STAT_ACKNOWLEDGE;
171 /* Check for double open */
174 __buf_size = buf_size;
176 dprintf("%s : device at %p\n", __func__, dev->base);
177 dprintf("%s : type is %04x\n", __func__, dev->type);
179 /* Keep it disabled until the driver is 1.0 capable */
180 dev->is_modern = false;
182 virtio_reset_device(dev);
184 /* Acknowledge device. */
185 virtio_set_status(dev, status);
187 /* Tell HV that we know how to drive the device. */
188 status |= VIRTIO_STAT_DRIVER;
189 virtio_set_status(dev, status);
191 /* Device specific setup - we do not support special features */
192 virtio_set_guest_features(dev, 0);
194 if (virtio_queue_init_vq(dev, &vq, 0))
197 vq_avail = virtio_get_vring_avail(dev, 0);
198 vq_avail->flags = VRING_AVAIL_F_NO_INTERRUPT;
201 /* Tell HV that setup succeeded */
202 status |= VIRTIO_STAT_DRIVER_OK;
203 virtio_set_status(dev, status);
205 /* Setup 9P library. */
206 p9_reg_transport(virtio_9p_transact, dev,(uint8_t *)tx_buf,
209 dprintf("%s : complete\n", __func__);
213 printf("%s: failed\n", __func__);
214 status |= VIRTIO_STAT_FAILED;
215 virtio_set_status(dev, status);
222 void virtio_9p_shutdown(struct virtio_device *dev)
225 virtio_set_status(dev, VIRTIO_STAT_FAILED);
228 virtio_reset_device(dev);
236 * Read a file from the 9P Server on the VIRTIO interface.
238 * @param file_name[in] File to read, use Linux style paths.
239 * @param buffer[out] Where to read the file to.
240 * @return +ve = amount of data read, -ve = error.
242 long virtio_9p_load(struct virtio_device *dev, const char *file_name, uint8_t *buffer)
246 char tag_name[TAG_SIZE];
248 uint8_t *pos = (uint8_t *)file_name;
249 int start_fid = ROOT_FID;
250 p9_connection_t connection = {
251 .message_size = __buf_size,
256 .connection = &connection,
261 /* Get the share name from 9P config space. */
262 tag_len = virtio_get_config(dev, 0, sizeof(tag_len));
263 if (tag_len >= TAG_SIZE)
264 tag_len = TAG_SIZE - 1;
265 __virtio_read_config(dev, tag_name, 2, tag_len);
266 connection.aname = tag_name;
268 /* Connect to the 9P server. */
269 dprintf("%s : connecting, tag = %s, user = %s, msgsize = %d\n",
270 __func__, connection.aname, connection.uname,
271 connection.message_size);
272 rc = p9_version(&connection);
274 printf("Version check failed, rc = %d\n", rc);
275 goto cleanup_connection;
277 rc = p9_attach(&connection);
279 printf("Attach failed, rc = %d\n", rc);
280 goto cleanup_connection;
282 dprintf("%s : connected, msgsize = %d\n", __func__,
283 connection.message_size);
285 /* Walk to the file. */
287 dprintf("%s : walk path %s\n", __func__, pos);
288 rc = p9_walk(&connection, start_fid, FILE_FID, &pos);
290 if (rc < 0) { /* Some error. */
291 printf("Walk failed, rc = %d\n", rc);
292 goto cleanup_connection;
296 * If partial walk (*pos != 0) then continue the walk from
297 * mid point with start_fid updated to current position
298 * FILE_FID. FILE_FID will then be reused for the result of
299 * the next call to walk.
301 start_fid = FILE_FID;
305 dprintf("%s : stat and open\n", __func__);
308 printf("Stat failed, rc = %d\n", rc);
311 rc = p9_open(&file, 0x00); /* TODO find include for "read mode" */
313 printf("Open failed, rc = %d\n", rc);
316 dprintf("%s : file opened, size %lld\n", __func__, file.length);
318 /* Read the file contents to buffer. */
319 while (offset < file.length) {
320 dprintf("%s : read from offset %llu\n", __func__, offset);
321 rc = p9_read(&file, buffer + offset,
322 file.length - offset, offset);
323 dprintf("%s : read done, length was %d\n", __func__, rc);
325 printf("Read failed, rc = %d\n", rc);
335 /* Cleanup and disconnect. */
337 dprintf("%s : clunking file\n", __func__);
338 p9_clunk(&connection, file.fid);
341 dprintf("%s : clunking connection\n", __func__);
342 p9_clunk(&connection, connection.fid);
345 dprintf("%s : complete, read %llu bytes\n", __func__, offset);
346 return rc == 0 ? (long)offset : rc;