cachepc-qemu

Fork of AMDESE/qemu with changes for cachepc side-channel attack
git clone https://git.sinitax.com/sinitax/cachepc-qemu
Log | Files | Refs | Submodules | LICENSE | sfeed.txt

virtio-blkdev.c (7832B)


      1/*
      2 * Virtio driver bits
      3 *
      4 * Copyright (c) 2013 Alexander Graf <agraf@suse.de>
      5 *
      6 * This work is licensed under the terms of the GNU GPL, version 2 or (at
      7 * your option) any later version. See the COPYING file in the top-level
      8 * directory.
      9 */
     10
     11#include "libc.h"
     12#include "s390-ccw.h"
     13#include "virtio.h"
     14#include "virtio-scsi.h"
     15
     16static int virtio_blk_read_many(VDev *vdev, ulong sector, void *load_addr,
     17                                int sec_num)
     18{
     19    VirtioBlkOuthdr out_hdr;
     20    u8 status;
     21    VRing *vr = &vdev->vrings[vdev->cmd_vr_idx];
     22
     23    /* Tell the host we want to read */
     24    out_hdr.type = VIRTIO_BLK_T_IN;
     25    out_hdr.ioprio = 99;
     26    out_hdr.sector = virtio_sector_adjust(sector);
     27
     28    vring_send_buf(vr, &out_hdr, sizeof(out_hdr), VRING_DESC_F_NEXT);
     29
     30    /* This is where we want to receive data */
     31    vring_send_buf(vr, load_addr, virtio_get_block_size() * sec_num,
     32                   VRING_DESC_F_WRITE | VRING_HIDDEN_IS_CHAIN |
     33                   VRING_DESC_F_NEXT);
     34
     35    /* status field */
     36    vring_send_buf(vr, &status, sizeof(u8),
     37                   VRING_DESC_F_WRITE | VRING_HIDDEN_IS_CHAIN);
     38
     39    /* Now we can tell the host to read */
     40    vring_wait_reply();
     41
     42    if (drain_irqs(vr->schid)) {
     43        /* Well, whatever status is supposed to contain... */
     44        status = 1;
     45    }
     46    return status;
     47}
     48
     49int virtio_read_many(ulong sector, void *load_addr, int sec_num)
     50{
     51    VDev *vdev = virtio_get_device();
     52
     53    switch (vdev->senseid.cu_model) {
     54    case VIRTIO_ID_BLOCK:
     55        return virtio_blk_read_many(vdev, sector, load_addr, sec_num);
     56    case VIRTIO_ID_SCSI:
     57        return virtio_scsi_read_many(vdev, sector, load_addr, sec_num);
     58    }
     59    panic("\n! No readable IPL device !\n");
     60    return -1;
     61}
     62
     63unsigned long virtio_load_direct(ulong rec_list1, ulong rec_list2,
     64                                 ulong subchan_id, void *load_addr)
     65{
     66    u8 status;
     67    int sec = rec_list1;
     68    int sec_num = ((rec_list2 >> 32) & 0xffff) + 1;
     69    int sec_len = rec_list2 >> 48;
     70    ulong addr = (ulong)load_addr;
     71
     72    if (sec_len != virtio_get_block_size()) {
     73        return -1;
     74    }
     75
     76    sclp_print(".");
     77    status = virtio_read_many(sec, (void *)addr, sec_num);
     78    if (status) {
     79        panic("I/O Error");
     80    }
     81    addr += sec_num * virtio_get_block_size();
     82
     83    return addr;
     84}
     85
     86int virtio_read(ulong sector, void *load_addr)
     87{
     88    return virtio_read_many(sector, load_addr, 1);
     89}
     90
     91/*
     92 * Other supported value pairs, if any, would need to be added here.
     93 * Note: head count is always 15.
     94 */
     95static inline u8 virtio_eckd_sectors_for_block_size(int size)
     96{
     97    switch (size) {
     98    case 512:
     99        return 49;
    100    case 1024:
    101        return 33;
    102    case 2048:
    103        return 21;
    104    case 4096:
    105        return 12;
    106    }
    107    return 0;
    108}
    109
    110VirtioGDN virtio_guessed_disk_nature(void)
    111{
    112    return virtio_get_device()->guessed_disk_nature;
    113}
    114
    115void virtio_assume_scsi(void)
    116{
    117    VDev *vdev = virtio_get_device();
    118
    119    switch (vdev->senseid.cu_model) {
    120    case VIRTIO_ID_BLOCK:
    121        vdev->guessed_disk_nature = VIRTIO_GDN_SCSI;
    122        vdev->config.blk.blk_size = VIRTIO_SCSI_BLOCK_SIZE;
    123        vdev->config.blk.physical_block_exp = 0;
    124        vdev->blk_factor = 1;
    125        break;
    126    case VIRTIO_ID_SCSI:
    127        vdev->scsi_block_size = VIRTIO_SCSI_BLOCK_SIZE;
    128        break;
    129    }
    130}
    131
    132void virtio_assume_iso9660(void)
    133{
    134    VDev *vdev = virtio_get_device();
    135
    136    switch (vdev->senseid.cu_model) {
    137    case VIRTIO_ID_BLOCK:
    138        vdev->guessed_disk_nature = VIRTIO_GDN_SCSI;
    139        vdev->config.blk.blk_size = VIRTIO_ISO_BLOCK_SIZE;
    140        vdev->config.blk.physical_block_exp = 0;
    141        vdev->blk_factor = VIRTIO_ISO_BLOCK_SIZE / VIRTIO_SECTOR_SIZE;
    142        break;
    143    case VIRTIO_ID_SCSI:
    144        vdev->scsi_block_size = VIRTIO_ISO_BLOCK_SIZE;
    145        break;
    146    }
    147}
    148
    149void virtio_assume_eckd(void)
    150{
    151    VDev *vdev = virtio_get_device();
    152
    153    vdev->guessed_disk_nature = VIRTIO_GDN_DASD;
    154    vdev->blk_factor = 1;
    155    vdev->config.blk.physical_block_exp = 0;
    156    switch (vdev->senseid.cu_model) {
    157    case VIRTIO_ID_BLOCK:
    158        vdev->config.blk.blk_size = 4096;
    159        break;
    160    case VIRTIO_ID_SCSI:
    161        vdev->config.blk.blk_size = vdev->scsi_block_size;
    162        break;
    163    }
    164    vdev->config.blk.geometry.heads = 15;
    165    vdev->config.blk.geometry.sectors =
    166        virtio_eckd_sectors_for_block_size(vdev->config.blk.blk_size);
    167}
    168
    169bool virtio_disk_is_scsi(void)
    170{
    171    VDev *vdev = virtio_get_device();
    172
    173    if (vdev->guessed_disk_nature == VIRTIO_GDN_SCSI) {
    174        return true;
    175    }
    176    switch (vdev->senseid.cu_model) {
    177    case VIRTIO_ID_BLOCK:
    178        return (vdev->config.blk.geometry.heads == 255)
    179            && (vdev->config.blk.geometry.sectors == 63)
    180            && (virtio_get_block_size()  == VIRTIO_SCSI_BLOCK_SIZE);
    181    case VIRTIO_ID_SCSI:
    182        return true;
    183    }
    184    return false;
    185}
    186
    187bool virtio_disk_is_eckd(void)
    188{
    189    VDev *vdev = virtio_get_device();
    190    const int block_size = virtio_get_block_size();
    191
    192    if (vdev->guessed_disk_nature == VIRTIO_GDN_DASD) {
    193        return true;
    194    }
    195    switch (vdev->senseid.cu_model) {
    196    case VIRTIO_ID_BLOCK:
    197        return (vdev->config.blk.geometry.heads == 15)
    198            && (vdev->config.blk.geometry.sectors ==
    199                virtio_eckd_sectors_for_block_size(block_size));
    200    case VIRTIO_ID_SCSI:
    201        return false;
    202    }
    203    return false;
    204}
    205
    206bool virtio_ipl_disk_is_valid(void)
    207{
    208    return virtio_disk_is_scsi() || virtio_disk_is_eckd();
    209}
    210
    211int virtio_get_block_size(void)
    212{
    213    VDev *vdev = virtio_get_device();
    214
    215    switch (vdev->senseid.cu_model) {
    216    case VIRTIO_ID_BLOCK:
    217        return vdev->config.blk.blk_size << vdev->config.blk.physical_block_exp;
    218    case VIRTIO_ID_SCSI:
    219        return vdev->scsi_block_size;
    220    }
    221    return 0;
    222}
    223
    224uint8_t virtio_get_heads(void)
    225{
    226    VDev *vdev = virtio_get_device();
    227
    228    switch (vdev->senseid.cu_model) {
    229    case VIRTIO_ID_BLOCK:
    230        return vdev->config.blk.geometry.heads;
    231    case VIRTIO_ID_SCSI:
    232        return vdev->guessed_disk_nature == VIRTIO_GDN_DASD
    233               ? vdev->config.blk.geometry.heads : 255;
    234    }
    235    return 0;
    236}
    237
    238uint8_t virtio_get_sectors(void)
    239{
    240    VDev *vdev = virtio_get_device();
    241
    242    switch (vdev->senseid.cu_model) {
    243    case VIRTIO_ID_BLOCK:
    244        return vdev->config.blk.geometry.sectors;
    245    case VIRTIO_ID_SCSI:
    246        return vdev->guessed_disk_nature == VIRTIO_GDN_DASD
    247               ? vdev->config.blk.geometry.sectors : 63;
    248    }
    249    return 0;
    250}
    251
    252uint64_t virtio_get_blocks(void)
    253{
    254    VDev *vdev = virtio_get_device();
    255    const uint64_t factor = virtio_get_block_size() / VIRTIO_SECTOR_SIZE;
    256
    257    switch (vdev->senseid.cu_model) {
    258    case VIRTIO_ID_BLOCK:
    259        return vdev->config.blk.capacity / factor;
    260    case VIRTIO_ID_SCSI:
    261        return vdev->scsi_last_block / factor;
    262    }
    263    return 0;
    264}
    265
    266int virtio_blk_setup_device(SubChannelId schid)
    267{
    268    VDev *vdev = virtio_get_device();
    269    int ret = 0;
    270
    271    vdev->schid = schid;
    272    virtio_setup_ccw(vdev);
    273
    274    switch (vdev->senseid.cu_model) {
    275    case VIRTIO_ID_BLOCK:
    276        sclp_print("Using virtio-blk.\n");
    277        if (!virtio_ipl_disk_is_valid()) {
    278            /* make sure all getters but blocksize return 0 for
    279             * invalid IPL disk
    280             */
    281            memset(&vdev->config.blk, 0, sizeof(vdev->config.blk));
    282            virtio_assume_scsi();
    283        }
    284        break;
    285    case VIRTIO_ID_SCSI:
    286        IPL_assert(vdev->config.scsi.sense_size == VIRTIO_SCSI_SENSE_SIZE,
    287            "Config: sense size mismatch");
    288        IPL_assert(vdev->config.scsi.cdb_size == VIRTIO_SCSI_CDB_SIZE,
    289            "Config: CDB size mismatch");
    290
    291        sclp_print("Using virtio-scsi.\n");
    292        ret = virtio_scsi_setup(vdev);
    293        break;
    294    default:
    295        panic("\n! No IPL device available !\n");
    296    }
    297
    298    return ret;
    299}