Annotation of qemu/roms/seabios/src/virtio-blk.c, revision 1.1

1.1     ! root        1: // Virtio block boot support.
        !             2: //
        !             3: // Copyright (C) 2010 Red Hat Inc.
        !             4: //
        !             5: // Authors:
        !             6: //  Gleb Natapov <[email protected]>
        !             7: //
        !             8: // This file may be distributed under the terms of the GNU LGPLv3 license.
        !             9: 
        !            10: #include "util.h" // dprintf
        !            11: #include "pci.h" // foreachpci
        !            12: #include "config.h" // CONFIG_*
        !            13: #include "biosvar.h" // GET_GLOBAL
        !            14: #include "pci_ids.h" // PCI_DEVICE_ID_VIRTIO_BLK
        !            15: #include "pci_regs.h" // PCI_VENDOR_ID
        !            16: #include "boot.h" // add_bcv_internal
        !            17: #include "virtio-pci.h"
        !            18: #include "virtio-ring.h"
        !            19: #include "virtio-blk.h"
        !            20: #include "disk.h"
        !            21: 
        !            22: struct virtiodrive_s {
        !            23:     struct drive_s drive;
        !            24:     struct vring_virtqueue *vq;
        !            25:     u16 ioaddr;
        !            26: };
        !            27: 
        !            28: static int
        !            29: virtio_blk_read(struct disk_op_s *op)
        !            30: {
        !            31:     struct virtiodrive_s *vdrive_g =
        !            32:         container_of(op->drive_g, struct virtiodrive_s, drive);
        !            33:     struct vring_virtqueue *vq = GET_GLOBAL(vdrive_g->vq);
        !            34:     struct virtio_blk_outhdr hdr = {
        !            35:         .type = VIRTIO_BLK_T_IN,
        !            36:         .ioprio = 0,
        !            37:         .sector = op->lba,
        !            38:     };
        !            39:     u8 status = VIRTIO_BLK_S_UNSUPP;
        !            40:     struct vring_list sg[] = {
        !            41:         {
        !            42:             .addr      = MAKE_FLATPTR(GET_SEG(SS), &hdr),
        !            43:             .length    = sizeof(hdr),
        !            44:         },
        !            45:         {
        !            46:             .addr      = op->buf_fl,
        !            47:             .length    = GET_GLOBAL(vdrive_g->drive.blksize) * op->count,
        !            48:         },
        !            49:         {
        !            50:             .addr      = MAKE_FLATPTR(GET_SEG(SS), &status),
        !            51:             .length    = sizeof(status),
        !            52:         },
        !            53:     };
        !            54: 
        !            55:     /* Add to virtqueue and kick host */
        !            56:     vring_add_buf(vq, sg, 1, 2, 0, 0);
        !            57:     vring_kick(GET_GLOBAL(vdrive_g->ioaddr), vq, 1);
        !            58: 
        !            59:     /* Wait for reply */
        !            60:     while (!vring_more_used(vq))
        !            61:         usleep(5);
        !            62: 
        !            63:     /* Reclaim virtqueue element */
        !            64:     vring_get_buf(vq, NULL);
        !            65: 
        !            66:     /* Clear interrupt status register.  Avoid leaving interrupts stuck if
        !            67:      * VRING_AVAIL_F_NO_INTERRUPT was ignored and interrupts were raised.
        !            68:      */
        !            69:     vp_get_isr(GET_GLOBAL(vdrive_g->ioaddr));
        !            70: 
        !            71:     return status == VIRTIO_BLK_S_OK ? DISK_RET_SUCCESS : DISK_RET_EBADTRACK;
        !            72: }
        !            73: 
        !            74: int
        !            75: process_virtio_op(struct disk_op_s *op)
        !            76: {
        !            77:     if (! CONFIG_VIRTIO_BLK || CONFIG_COREBOOT)
        !            78:         return 0;
        !            79:     switch (op->command) {
        !            80:     case CMD_READ:
        !            81:         return virtio_blk_read(op);
        !            82:     case CMD_FORMAT:
        !            83:     case CMD_WRITE:
        !            84:         return DISK_RET_EWRITEPROTECT;
        !            85:     case CMD_RESET:
        !            86:     case CMD_ISREADY:
        !            87:     case CMD_VERIFY:
        !            88:     case CMD_SEEK:
        !            89:         return DISK_RET_SUCCESS;
        !            90:     default:
        !            91:         op->count = 0;
        !            92:         return DISK_RET_EPARAM;
        !            93:     }
        !            94: }
        !            95: 
        !            96: static void
        !            97: init_virtio_blk(u16 bdf)
        !            98: {
        !            99:     dprintf(1, "found virtio-blk at %x:%x\n", pci_bdf_to_bus(bdf),
        !           100:             pci_bdf_to_dev(bdf));
        !           101:     char *desc = malloc_tmphigh(MAXDESCSIZE);
        !           102:     struct virtiodrive_s *vdrive_g = malloc_fseg(sizeof(*vdrive_g));
        !           103:     struct vring_virtqueue *vq = memalign_low(PAGE_SIZE, sizeof(*vq));
        !           104:     if (!vdrive_g || !desc || !vq) {
        !           105:         warn_noalloc();
        !           106:         goto fail;
        !           107:     }
        !           108:     memset(vdrive_g, 0, sizeof(*vdrive_g));
        !           109:     vdrive_g->drive.type = DTYPE_VIRTIO;
        !           110:     vdrive_g->drive.cntl_id = bdf;
        !           111:     vdrive_g->vq = vq;
        !           112: 
        !           113:     u16 ioaddr = pci_config_readl(bdf, PCI_BASE_ADDRESS_0) &
        !           114:         PCI_BASE_ADDRESS_IO_MASK;
        !           115: 
        !           116:     vdrive_g->ioaddr = ioaddr;
        !           117: 
        !           118:     vp_reset(ioaddr);
        !           119:     vp_set_status(ioaddr, VIRTIO_CONFIG_S_ACKNOWLEDGE |
        !           120:                   VIRTIO_CONFIG_S_DRIVER );
        !           121: 
        !           122:     if (vp_find_vq(ioaddr, 0, vdrive_g->vq) < 0 ) {
        !           123:         dprintf(1, "fail to find vq for virtio-blk %x:%x\n",
        !           124:                 pci_bdf_to_bus(bdf), pci_bdf_to_dev(bdf));
        !           125:         goto fail;
        !           126:     }
        !           127: 
        !           128:     struct virtio_blk_config cfg;
        !           129:     vp_get(ioaddr, 0, &cfg, sizeof(cfg));
        !           130: 
        !           131:     u32 f = vp_get_features(ioaddr);
        !           132:     vdrive_g->drive.blksize = (f & (1 << VIRTIO_BLK_F_BLK_SIZE)) ?
        !           133:         cfg.blk_size : DISK_SECTOR_SIZE;
        !           134: 
        !           135:     vdrive_g->drive.sectors = cfg.capacity;
        !           136:     dprintf(3, "virtio-blk %x:%x blksize=%d sectors=%u\n",
        !           137:             pci_bdf_to_bus(bdf), pci_bdf_to_dev(bdf),
        !           138:             vdrive_g->drive.blksize, (u32)vdrive_g->drive.sectors);
        !           139: 
        !           140:     if (vdrive_g->drive.blksize != DISK_SECTOR_SIZE) {
        !           141:         dprintf(1, "virtio-blk %x:%x block size %d is unsupported\n",
        !           142:                 pci_bdf_to_bus(bdf), pci_bdf_to_dev(bdf),
        !           143:                 vdrive_g->drive.blksize);
        !           144:         goto fail;
        !           145:     }
        !           146: 
        !           147:     vdrive_g->drive.pchs.cylinders = cfg.cylinders;
        !           148:     vdrive_g->drive.pchs.heads = cfg.heads;
        !           149:     vdrive_g->drive.pchs.spt = cfg.sectors;
        !           150: 
        !           151:     setup_translation(&vdrive_g->drive);
        !           152:     add_bcv_internal(&vdrive_g->drive);
        !           153: 
        !           154:     snprintf(desc, MAXDESCSIZE, "Virtio disk PCI:%x:%x",
        !           155:              pci_bdf_to_bus(bdf), pci_bdf_to_dev(bdf));
        !           156: 
        !           157:     vdrive_g->drive.desc = desc;
        !           158: 
        !           159:     vp_set_status(ioaddr, VIRTIO_CONFIG_S_ACKNOWLEDGE |
        !           160:                   VIRTIO_CONFIG_S_DRIVER | VIRTIO_CONFIG_S_DRIVER_OK);
        !           161:     return;
        !           162: 
        !           163: fail:
        !           164:     free(vdrive_g);
        !           165:     free(desc);
        !           166:     free(vq);
        !           167: }
        !           168: 
        !           169: void
        !           170: virtio_blk_setup(void)
        !           171: {
        !           172:     ASSERT32FLAT();
        !           173:     if (! CONFIG_VIRTIO_BLK || CONFIG_COREBOOT)
        !           174:         return;
        !           175: 
        !           176:     dprintf(3, "init virtio-blk\n");
        !           177: 
        !           178:     int bdf, max;
        !           179:     u32 id = PCI_VENDOR_ID_REDHAT_QUMRANET | (PCI_DEVICE_ID_VIRTIO_BLK << 16);
        !           180:     foreachpci(bdf, max) {
        !           181:         u32 v = pci_config_readl(bdf, PCI_VENDOR_ID);
        !           182:         if (v != id)
        !           183:             continue;
        !           184:         init_virtio_blk(bdf);
        !           185:     }
        !           186: }

unix.superglobalmegacorp.com

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