|
|
1.1 ! root 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 <string.h> ! 15: #include <stdint.h> ! 16: #include <byteorder.h> ! 17: ! 18: #include "virtio-9p.h" ! 19: #include "p9.h" ! 20: ! 21: ! 22: /** ! 23: * Notes for 9P Server config: ! 24: * ! 25: * make distclean; cm make qemu ! 26: * sudo cp boot_rom.bin /opt/qemu/share/qemu/slof.bin ! 27: * /opt/qemu/bin/qemu-system-ppc64 -M pseries -m 512 -boot d -nographic -fsdev ! 28: * local,id=trule,path=/home/trule/virtfs,security_model=none -device ! 29: * virtio-9p-spapr,fsdev=trule,mount_tag=trule ! 30: * load virtfs:\some\file ! 31: */ ! 32: ! 33: /* We support only one instance due to the (ab)use of globals. We ! 34: * use the buffer size as an open marker as well. ! 35: */ ! 36: static int __buf_size; ! 37: ! 38: ! 39: #define ROOT_FID 1 ! 40: #define FILE_FID 2 ! 41: #define TAG_SIZE 128 ! 42: #define sync() asm volatile (" sync \n" ::: "memory") ! 43: #define MIN(a,b) ((a)>(b)?(b):(a)) ! 44: ! 45: ! 46: #undef DEBUG ! 47: //#define DEBUG ! 48: #ifdef DEBUG ! 49: #define dprintf(_x ...) printf(_x) ! 50: #else ! 51: #define dprintf(_x ...) ! 52: #endif ! 53: ! 54: #ifdef DEBUG ! 55: static void dprint_buffer(const char *name, uint8_t *buffer, int length) ! 56: { ! 57: int i; ! 58: ! 59: printf("*** %s ***", name); ! 60: ! 61: for (i = 0; i < length; i++) { ! 62: if (i % 16 == 0) { ! 63: printf("\n %04x:", i); ! 64: } ! 65: ! 66: printf(" %02x", buffer[i]); ! 67: } ! 68: ! 69: printf("\n"); ! 70: } ! 71: #else ! 72: #define dprint_buffer(n, b, l) ! 73: #endif ! 74: ! 75: /** ! 76: * virtio_9p_transact ! 77: * ! 78: * Perform a 9P transaction over the VIRTIO queue interface. This function is ! 79: * registered with the p9.c library via p9_reg_transport() to provide ! 80: * connectivity to the 9P server. ! 81: * ! 82: * @param tx[in] Data to send, mapped to first queue item. ! 83: * @param tx_size[in] Size of data to send. ! 84: * @param rx[out] Data to receive, mappend to second queue item. ! 85: * @param rx_size[out] Size of data received. ! 86: * @return 0 = success, -ve = error. ! 87: */ ! 88: static int virtio_9p_transact(void *opaque, uint8_t *tx, int tx_size, uint8_t *rx, ! 89: int *rx_size) ! 90: { ! 91: struct virtio_device *dev = opaque; ! 92: struct vring_desc *desc; ! 93: int id, i; ! 94: uint32_t vq_size; ! 95: struct vring_desc *vq_desc; ! 96: struct vring_avail *vq_avail; ! 97: struct vring_used *vq_used; ! 98: volatile uint16_t *current_used_idx; ! 99: uint16_t last_used_idx; ! 100: ! 101: ! 102: /* Virt IO queues. */ ! 103: vq_size = virtio_get_qsize(dev, 0); ! 104: vq_desc = virtio_get_vring_desc(dev, 0); ! 105: vq_avail = virtio_get_vring_avail(dev, 0); ! 106: vq_used = virtio_get_vring_used(dev, 0); ! 107: ! 108: last_used_idx = vq_used->idx; ! 109: current_used_idx = &vq_used->idx; ! 110: ! 111: /* Determine descriptor index */ ! 112: id = (vq_avail->idx * 3) % vq_size; ! 113: ! 114: /* TX in first queue item. */ ! 115: dprint_buffer("TX", tx, tx_size); ! 116: ! 117: desc = &vq_desc[id]; ! 118: desc->addr = (uint64_t)tx; ! 119: desc->len = tx_size; ! 120: desc->flags = VRING_DESC_F_NEXT; ! 121: desc->next = (id + 1) % vq_size; ! 122: ! 123: /* RX in the second queue item. */ ! 124: desc = &vq_desc[(id + 1) % vq_size]; ! 125: desc->addr = (uint64_t)rx; ! 126: desc->len = *rx_size; ! 127: desc->flags = VRING_DESC_F_WRITE; ! 128: desc->next = 0; ! 129: ! 130: /* Tell HV that the queue is ready */ ! 131: vq_avail->ring[vq_avail->idx % vq_size] = id; ! 132: sync(); ! 133: vq_avail->idx += 1; ! 134: virtio_queue_notify(dev, 0); ! 135: ! 136: /* Receive the response. */ ! 137: i = 10000000; ! 138: while (*current_used_idx == last_used_idx && i-- > 0) { ! 139: // do something better ! 140: sync(); ! 141: } ! 142: if (i == 0) { ! 143: return -1; ! 144: } ! 145: ! 146: *rx_size = MIN(*rx_size, le32_to_cpu(*(uint32_t*)(&rx[0]))); ! 147: dprint_buffer("RX", rx, *rx_size); ! 148: ! 149: return 0; ! 150: } ! 151: ! 152: /** ! 153: * virtio_9p_init ! 154: * ! 155: * Establish the VIRTIO connection for use with the 9P server. Setup queues ! 156: * and negotiate capabilities. Setup the 9P (Client) library. ! 157: * ! 158: * @param reg[in] Pointer to device tree node for VIRTIO/9P interface. ! 159: * @param tx_buf[in] TX buffer for use by 9P Client lib - 8K in size. ! 160: * @param rx_buf[in] TX buffer for use by 9P Client lib - 8K in size. ! 161: * @param buf_size Somewhat redundant, buffer size expected to be 8k. ! 162: * @return 0 = success, -ve = error. ! 163: */ ! 164: int virtio_9p_init(struct virtio_device *dev, void *tx_buf, void *rx_buf, ! 165: int buf_size) ! 166: { ! 167: struct vring_avail *vq_avail; ! 168: ! 169: /* Check for double open */ ! 170: if (__buf_size) ! 171: return -1; ! 172: __buf_size = buf_size; ! 173: ! 174: dprintf("%s : device at %p\n", __func__, dev->base); ! 175: dprintf("%s : type is %04x\n", __func__, dev->type); ! 176: ! 177: /* Reset device */ ! 178: // XXX That will clear the virtq base. We need to move ! 179: // initializing it to here anyway ! 180: // ! 181: // virtio_reset_device(dev); ! 182: ! 183: /* Acknowledge device. */ ! 184: virtio_set_status(dev, VIRTIO_STAT_ACKNOWLEDGE); ! 185: ! 186: /* Tell HV that we know how to drive the device. */ ! 187: virtio_set_status(dev, VIRTIO_STAT_ACKNOWLEDGE | VIRTIO_STAT_DRIVER); ! 188: ! 189: /* Device specific setup - we do not support special features */ ! 190: virtio_set_guest_features(dev, 0); ! 191: ! 192: vq_avail = virtio_get_vring_avail(dev, 0); ! 193: vq_avail->flags = VRING_AVAIL_F_NO_INTERRUPT; ! 194: vq_avail->idx = 0; ! 195: ! 196: /* Tell HV that setup succeeded */ ! 197: virtio_set_status(dev, VIRTIO_STAT_ACKNOWLEDGE | VIRTIO_STAT_DRIVER ! 198: |VIRTIO_STAT_DRIVER_OK); ! 199: ! 200: /* Setup 9P library. */ ! 201: p9_reg_transport(virtio_9p_transact, dev,(uint8_t *)tx_buf, ! 202: (uint8_t *)rx_buf); ! 203: ! 204: dprintf("%s : complete\n", __func__); ! 205: return 0; ! 206: } ! 207: ! 208: /** ! 209: * virtio_9p_shutdown ! 210: */ ! 211: void virtio_9p_shutdown(struct virtio_device *dev) ! 212: { ! 213: /* Quiesce device */ ! 214: virtio_set_status(dev, VIRTIO_STAT_FAILED); ! 215: ! 216: /* Reset device */ ! 217: virtio_reset_device(dev); ! 218: ! 219: __buf_size = 0; ! 220: } ! 221: ! 222: /** ! 223: * virtio_9p_load ! 224: * ! 225: * Read a file from the 9P Server on the VIRTIO interface. ! 226: * ! 227: * @param file_name[in] File to read, use Linux style paths. ! 228: * @param buffer[out] Where to read the file to. ! 229: * @return +ve = amount of data read, -ve = error. ! 230: */ ! 231: int virtio_9p_load(struct virtio_device *dev, const char *file_name, uint8_t *buffer) ! 232: { ! 233: int rc; ! 234: uint16_t tag_len; ! 235: char tag_name[TAG_SIZE]; ! 236: uint64_t offset = 0; ! 237: uint8_t *pos = (uint8_t *)file_name; ! 238: int start_fid = ROOT_FID; ! 239: p9_connection_t connection = { ! 240: .message_size = __buf_size, ! 241: .fid = ROOT_FID, ! 242: .uname = "slof" ! 243: }; ! 244: p9_file_t file = { ! 245: .connection = &connection, ! 246: .fid = FILE_FID, ! 247: }; ! 248: ! 249: ! 250: /* Get the share name from 9P config space. */ ! 251: tag_len = virtio_get_config(dev, 0, sizeof(tag_len)); ! 252: if (tag_len >= TAG_SIZE) ! 253: tag_len = TAG_SIZE - 1; ! 254: __virtio_read_config(dev, tag_name, 2, tag_len); ! 255: connection.aname = tag_name; ! 256: ! 257: /* Connect to the 9P server. */ ! 258: dprintf("%s : connecting, tag = %s, user = %s, msgsize = %d\n", ! 259: __func__, connection.aname, connection.uname, ! 260: connection.message_size); ! 261: rc = p9_version(&connection); ! 262: if (rc != 0) { ! 263: printf("Version check failed, rc = %d\n", rc); ! 264: goto cleanup_connection; ! 265: } ! 266: rc = p9_attach(&connection); ! 267: if (rc != 0) { ! 268: printf("Attach failed, rc = %d\n", rc); ! 269: goto cleanup_connection; ! 270: } ! 271: dprintf("%s : connected, msgsize = %d\n", __func__, ! 272: connection.message_size); ! 273: ! 274: /* Walk to the file. */ ! 275: do { ! 276: dprintf("%s : walk path %s\n", __func__, pos); ! 277: rc = p9_walk(&connection, start_fid, FILE_FID, &pos); ! 278: ! 279: if (rc < 0) { /* Some error. */ ! 280: printf("Walk failed, rc = %d\n", rc); ! 281: goto cleanup_connection; ! 282: } ! 283: ! 284: /* ! 285: * If partial walk (*pos != 0) then continue the walk from ! 286: * mid point with start_fid updated to current position ! 287: * FILE_FID. FILE_FID will then be reused for the result of ! 288: * the next call to walk. ! 289: */ ! 290: start_fid = FILE_FID; ! 291: } while (*pos != 0); ! 292: ! 293: /* Open the file. */ ! 294: dprintf("%s : stat and open\n", __func__); ! 295: rc = p9_stat(&file); ! 296: if (rc != 0) { ! 297: printf("Stat failed, rc = %d\n", rc); ! 298: goto cleanup_file; ! 299: } ! 300: rc = p9_open(&file, 0x00); /* TODO find include for "read mode" */ ! 301: if (rc != 0) { ! 302: printf("Open failed, rc = %d\n", rc); ! 303: goto cleanup_file; ! 304: } ! 305: dprintf("%s : file opened, size %lld\n", __func__, file.length); ! 306: ! 307: /* Read the file contents to buffer. */ ! 308: while (offset < file.length) { ! 309: dprintf("%s : read from offset %llu\n", __func__, offset); ! 310: rc = p9_read(&file, buffer + offset, ! 311: file.length - offset, offset); ! 312: dprintf("%s : read done, length was %d\n", __func__, rc); ! 313: if (rc < 0) { ! 314: printf("Read failed, rc = %d\n", rc); ! 315: goto cleanup_file; ! 316: } ! 317: if (rc == 0) { ! 318: break; ! 319: } ! 320: offset += rc; ! 321: rc = 0; ! 322: } ! 323: ! 324: /* Cleanup and disconnect. */ ! 325: cleanup_file: ! 326: dprintf("%s : clunking file\n", __func__); ! 327: p9_clunk(&connection, file.fid); ! 328: ! 329: cleanup_connection: ! 330: dprintf("%s : clunking connection\n", __func__); ! 331: p9_clunk(&connection, connection.fid); ! 332: ! 333: ! 334: dprintf("%s : complete, read %llu bytes\n", __func__, offset); ! 335: return rc == 0 ? offset : rc; ! 336: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.