Annotation of qemu/roms/SLOF/lib/libvirtio/virtio-9p.c, revision 1.1

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: }

unix.superglobalmegacorp.com

This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.