qemu

FORK: QEMU emulator
git clone https://git.neptards.moe/neptards/qemu.git
Log | Files | Refs | Submodules | LICENSE

sun4u_iommu.c (10740B)


      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 */
     75 static 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         /* Writable */
    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 
    192 static 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 
    236 static 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 
    280 static const MemoryRegionOps iommu_mem_ops = {
    281     .read = iommu_mem_read,
    282     .write = iommu_mem_write,
    283     .endianness = DEVICE_BIG_ENDIAN,
    284 };
    285 
    286 static 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 
    293 static 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 
    308 static void iommu_class_init(ObjectClass *klass, void *data)
    309 {
    310     DeviceClass *dc = DEVICE_CLASS(klass);
    311 
    312     dc->reset = iommu_reset;
    313 }
    314 
    315 static 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 
    323 static 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 
    330 static 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 
    336 static void iommu_register_types(void)
    337 {
    338     type_register_static(&iommu_info);
    339     type_register_static(&sun4u_iommu_memory_region_info);
    340 }
    341 
    342 type_init(iommu_register_types)