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

sun4u_iommu.c (10741B)


      1/*
      2 * QEMU sun4u IOMMU emulation
      3 *
      4 * Copyright (c) 2006 Fabrice Bellard
      5 * Copyright (c) 2012,2013 Artyom Tarasenko
      6 * Copyright (c) 2017 Mark Cave-Ayland
      7 *
      8 * Permission is hereby granted, free of charge, to any person obtaining a copy
      9 * of this software and associated documentation files (the "Software"), to deal
     10 * in the Software without restriction, including without limitation the rights
     11 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
     12 * copies of the Software, and to permit persons to whom the Software is
     13 * furnished to do so, subject to the following conditions:
     14 *
     15 * The above copyright notice and this permission notice shall be included in
     16 * all copies or substantial portions of the Software.
     17 *
     18 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
     19 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
     20 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
     21 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
     22 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
     23 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
     24 * THE SOFTWARE.
     25 */
     26
     27#include "qemu/osdep.h"
     28#include "hw/sysbus.h"
     29#include "hw/sparc/sun4u_iommu.h"
     30#include "exec/address-spaces.h"
     31#include "qemu/log.h"
     32#include "qemu/module.h"
     33#include "trace.h"
     34
     35
     36#define IOMMU_PAGE_SIZE_8K      (1ULL << 13)
     37#define IOMMU_PAGE_MASK_8K      (~(IOMMU_PAGE_SIZE_8K - 1))
     38#define IOMMU_PAGE_SIZE_64K     (1ULL << 16)
     39#define IOMMU_PAGE_MASK_64K     (~(IOMMU_PAGE_SIZE_64K - 1))
     40
     41#define IOMMU_CTRL              0x0
     42#define IOMMU_CTRL_TBW_SIZE     (1ULL << 2)
     43#define IOMMU_CTRL_MMU_EN       (1ULL)
     44
     45#define IOMMU_CTRL_TSB_SHIFT    16
     46
     47#define IOMMU_BASE              0x8
     48#define IOMMU_FLUSH             0x10
     49
     50#define IOMMU_TTE_DATA_V        (1ULL << 63)
     51#define IOMMU_TTE_DATA_SIZE     (1ULL << 61)
     52#define IOMMU_TTE_DATA_W        (1ULL << 1)
     53
     54#define IOMMU_TTE_PHYS_MASK_8K  0x1ffffffe000ULL
     55#define IOMMU_TTE_PHYS_MASK_64K 0x1ffffff8000ULL
     56
     57#define IOMMU_TSB_8K_OFFSET_MASK_8M    0x00000000007fe000ULL
     58#define IOMMU_TSB_8K_OFFSET_MASK_16M   0x0000000000ffe000ULL
     59#define IOMMU_TSB_8K_OFFSET_MASK_32M   0x0000000001ffe000ULL
     60#define IOMMU_TSB_8K_OFFSET_MASK_64M   0x0000000003ffe000ULL
     61#define IOMMU_TSB_8K_OFFSET_MASK_128M  0x0000000007ffe000ULL
     62#define IOMMU_TSB_8K_OFFSET_MASK_256M  0x000000000fffe000ULL
     63#define IOMMU_TSB_8K_OFFSET_MASK_512M  0x000000001fffe000ULL
     64#define IOMMU_TSB_8K_OFFSET_MASK_1G    0x000000003fffe000ULL
     65
     66#define IOMMU_TSB_64K_OFFSET_MASK_64M  0x0000000003ff0000ULL
     67#define IOMMU_TSB_64K_OFFSET_MASK_128M 0x0000000007ff0000ULL
     68#define IOMMU_TSB_64K_OFFSET_MASK_256M 0x000000000fff0000ULL
     69#define IOMMU_TSB_64K_OFFSET_MASK_512M 0x000000001fff0000ULL
     70#define IOMMU_TSB_64K_OFFSET_MASK_1G   0x000000003fff0000ULL
     71#define IOMMU_TSB_64K_OFFSET_MASK_2G   0x000000007fff0000ULL
     72
     73
     74/* Called from RCU critical section */
     75static IOMMUTLBEntry sun4u_translate_iommu(IOMMUMemoryRegion *iommu,
     76                                           hwaddr addr,
     77                                           IOMMUAccessFlags flag, int iommu_idx)
     78{
     79    IOMMUState *is = container_of(iommu, IOMMUState, iommu);
     80    hwaddr baseaddr, offset;
     81    uint64_t tte;
     82    uint32_t tsbsize;
     83    IOMMUTLBEntry ret = {
     84        .target_as = &address_space_memory,
     85        .iova = 0,
     86        .translated_addr = 0,
     87        .addr_mask = ~(hwaddr)0,
     88        .perm = IOMMU_NONE,
     89    };
     90
     91    if (!(is->regs[IOMMU_CTRL >> 3] & IOMMU_CTRL_MMU_EN)) {
     92        /* IOMMU disabled, passthrough using standard 8K page */
     93        ret.iova = addr & IOMMU_PAGE_MASK_8K;
     94        ret.translated_addr = addr;
     95        ret.addr_mask = IOMMU_PAGE_MASK_8K;
     96        ret.perm = IOMMU_RW;
     97
     98        return ret;
     99    }
    100
    101    baseaddr = is->regs[IOMMU_BASE >> 3];
    102    tsbsize = (is->regs[IOMMU_CTRL >> 3] >> IOMMU_CTRL_TSB_SHIFT) & 0x7;
    103
    104    if (is->regs[IOMMU_CTRL >> 3] & IOMMU_CTRL_TBW_SIZE) {
    105        /* 64K */
    106        switch (tsbsize) {
    107        case 0:
    108            offset = (addr & IOMMU_TSB_64K_OFFSET_MASK_64M) >> 13;
    109            break;
    110        case 1:
    111            offset = (addr & IOMMU_TSB_64K_OFFSET_MASK_128M) >> 13;
    112            break;
    113        case 2:
    114            offset = (addr & IOMMU_TSB_64K_OFFSET_MASK_256M) >> 13;
    115            break;
    116        case 3:
    117            offset = (addr & IOMMU_TSB_64K_OFFSET_MASK_512M) >> 13;
    118            break;
    119        case 4:
    120            offset = (addr & IOMMU_TSB_64K_OFFSET_MASK_1G) >> 13;
    121            break;
    122        case 5:
    123            offset = (addr & IOMMU_TSB_64K_OFFSET_MASK_2G) >> 13;
    124            break;
    125        default:
    126            /* Not implemented, error */
    127            return ret;
    128        }
    129    } else {
    130        /* 8K */
    131        switch (tsbsize) {
    132        case 0:
    133            offset = (addr & IOMMU_TSB_8K_OFFSET_MASK_8M) >> 10;
    134            break;
    135        case 1:
    136            offset = (addr & IOMMU_TSB_8K_OFFSET_MASK_16M) >> 10;
    137            break;
    138        case 2:
    139            offset = (addr & IOMMU_TSB_8K_OFFSET_MASK_32M) >> 10;
    140            break;
    141        case 3:
    142            offset = (addr & IOMMU_TSB_8K_OFFSET_MASK_64M) >> 10;
    143            break;
    144        case 4:
    145            offset = (addr & IOMMU_TSB_8K_OFFSET_MASK_128M) >> 10;
    146            break;
    147        case 5:
    148            offset = (addr & IOMMU_TSB_8K_OFFSET_MASK_256M) >> 10;
    149            break;
    150        case 6:
    151            offset = (addr & IOMMU_TSB_8K_OFFSET_MASK_512M) >> 10;
    152            break;
    153        case 7:
    154            offset = (addr & IOMMU_TSB_8K_OFFSET_MASK_1G) >> 10;
    155            break;
    156        }
    157    }
    158
    159    tte = address_space_ldq_be(&address_space_memory, baseaddr + offset,
    160                               MEMTXATTRS_UNSPECIFIED, NULL);
    161
    162    if (!(tte & IOMMU_TTE_DATA_V)) {
    163        /* Invalid mapping */
    164        return ret;
    165    }
    166
    167    if (tte & IOMMU_TTE_DATA_W) {
    168        /* Writeable */
    169        ret.perm = IOMMU_RW;
    170    } else {
    171        ret.perm = IOMMU_RO;
    172    }
    173
    174    /* Extract phys */
    175    if (tte & IOMMU_TTE_DATA_SIZE) {
    176        /* 64K */
    177        ret.iova = addr & IOMMU_PAGE_MASK_64K;
    178        ret.translated_addr = tte & IOMMU_TTE_PHYS_MASK_64K;
    179        ret.addr_mask = (IOMMU_PAGE_SIZE_64K - 1);
    180    } else {
    181        /* 8K */
    182        ret.iova = addr & IOMMU_PAGE_MASK_8K;
    183        ret.translated_addr = tte & IOMMU_TTE_PHYS_MASK_8K;
    184        ret.addr_mask = (IOMMU_PAGE_SIZE_8K - 1);
    185    }
    186
    187    trace_sun4u_iommu_translate(ret.iova, ret.translated_addr, tte);
    188
    189    return ret;
    190}
    191
    192static void iommu_mem_write(void *opaque, hwaddr addr,
    193                            uint64_t val, unsigned size)
    194{
    195    IOMMUState *is = opaque;
    196
    197    trace_sun4u_iommu_mem_write(addr, val, size);
    198
    199    switch (addr) {
    200    case IOMMU_CTRL:
    201        if (size == 4) {
    202            is->regs[IOMMU_CTRL >> 3] &= 0xffffffffULL;
    203            is->regs[IOMMU_CTRL >> 3] |= val << 32;
    204        } else {
    205            is->regs[IOMMU_CTRL >> 3] = val;
    206        }
    207        break;
    208    case IOMMU_CTRL + 0x4:
    209        is->regs[IOMMU_CTRL >> 3] &= 0xffffffff00000000ULL;
    210        is->regs[IOMMU_CTRL >> 3] |= val & 0xffffffffULL;
    211        break;
    212    case IOMMU_BASE:
    213        if (size == 4) {
    214            is->regs[IOMMU_BASE >> 3] &= 0xffffffffULL;
    215            is->regs[IOMMU_BASE >> 3] |= val << 32;
    216        } else {
    217            is->regs[IOMMU_BASE >> 3] = val;
    218        }
    219        break;
    220    case IOMMU_BASE + 0x4:
    221        is->regs[IOMMU_BASE >> 3] &= 0xffffffff00000000ULL;
    222        is->regs[IOMMU_BASE >> 3] |= val & 0xffffffffULL;
    223        break;
    224    case IOMMU_FLUSH:
    225    case IOMMU_FLUSH + 0x4:
    226        break;
    227    default:
    228        qemu_log_mask(LOG_UNIMP,
    229                  "sun4u-iommu: Unimplemented register write "
    230                  "reg 0x%" HWADDR_PRIx " size 0x%x value 0x%" PRIx64 "\n",
    231                  addr, size, val);
    232        break;
    233    }
    234}
    235
    236static uint64_t iommu_mem_read(void *opaque, hwaddr addr, unsigned size)
    237{
    238    IOMMUState *is = opaque;
    239    uint64_t val;
    240
    241    switch (addr) {
    242    case IOMMU_CTRL:
    243        if (size == 4) {
    244            val = is->regs[IOMMU_CTRL >> 3] >> 32;
    245        } else {
    246            val = is->regs[IOMMU_CTRL >> 3];
    247        }
    248        break;
    249    case IOMMU_CTRL + 0x4:
    250        val = is->regs[IOMMU_CTRL >> 3] & 0xffffffffULL;
    251        break;
    252    case IOMMU_BASE:
    253        if (size == 4) {
    254            val = is->regs[IOMMU_BASE >> 3] >> 32;
    255        } else {
    256            val = is->regs[IOMMU_BASE >> 3];
    257        }
    258        break;
    259    case IOMMU_BASE + 0x4:
    260        val = is->regs[IOMMU_BASE >> 3] & 0xffffffffULL;
    261        break;
    262    case IOMMU_FLUSH:
    263    case IOMMU_FLUSH + 0x4:
    264        val = 0;
    265        break;
    266    default:
    267        qemu_log_mask(LOG_UNIMP,
    268                      "sun4u-iommu: Unimplemented register read "
    269                      "reg 0x%" HWADDR_PRIx " size 0x%x\n",
    270                      addr, size);
    271        val = 0;
    272        break;
    273    }
    274
    275    trace_sun4u_iommu_mem_read(addr, val, size);
    276
    277    return val;
    278}
    279
    280static const MemoryRegionOps iommu_mem_ops = {
    281    .read = iommu_mem_read,
    282    .write = iommu_mem_write,
    283    .endianness = DEVICE_BIG_ENDIAN,
    284};
    285
    286static void iommu_reset(DeviceState *d)
    287{
    288    IOMMUState *s = SUN4U_IOMMU(d);
    289
    290    memset(s->regs, 0, IOMMU_NREGS * sizeof(uint64_t));
    291}
    292
    293static void iommu_init(Object *obj)
    294{
    295    IOMMUState *s = SUN4U_IOMMU(obj);
    296    SysBusDevice *sbd = SYS_BUS_DEVICE(obj);
    297
    298    memory_region_init_iommu(&s->iommu, sizeof(s->iommu),
    299                             TYPE_SUN4U_IOMMU_MEMORY_REGION, OBJECT(s),
    300                             "iommu-sun4u", UINT64_MAX);
    301    address_space_init(&s->iommu_as, MEMORY_REGION(&s->iommu), "iommu-as");
    302
    303    memory_region_init_io(&s->iomem, obj, &iommu_mem_ops, s, "iommu",
    304                          IOMMU_NREGS * sizeof(uint64_t));
    305    sysbus_init_mmio(sbd, &s->iomem);
    306}
    307
    308static void iommu_class_init(ObjectClass *klass, void *data)
    309{
    310    DeviceClass *dc = DEVICE_CLASS(klass);
    311
    312    dc->reset = iommu_reset;
    313}
    314
    315static const TypeInfo iommu_info = {
    316    .name          = TYPE_SUN4U_IOMMU,
    317    .parent        = TYPE_SYS_BUS_DEVICE,
    318    .instance_size = sizeof(IOMMUState),
    319    .instance_init = iommu_init,
    320    .class_init    = iommu_class_init,
    321};
    322
    323static void sun4u_iommu_memory_region_class_init(ObjectClass *klass, void *data)
    324{
    325    IOMMUMemoryRegionClass *imrc = IOMMU_MEMORY_REGION_CLASS(klass);
    326
    327    imrc->translate = sun4u_translate_iommu;
    328}
    329
    330static const TypeInfo sun4u_iommu_memory_region_info = {
    331    .parent = TYPE_IOMMU_MEMORY_REGION,
    332    .name = TYPE_SUN4U_IOMMU_MEMORY_REGION,
    333    .class_init = sun4u_iommu_memory_region_class_init,
    334};
    335
    336static void iommu_register_types(void)
    337{
    338    type_register_static(&iommu_info);
    339    type_register_static(&sun4u_iommu_memory_region_info);
    340}
    341
    342type_init(iommu_register_types)