1344f4b15SPeter Maydell /* 2344f4b15SPeter Maydell * ARM AHB5 TrustZone Memory Protection Controller emulation 3344f4b15SPeter Maydell * 4344f4b15SPeter Maydell * Copyright (c) 2018 Linaro Limited 5344f4b15SPeter Maydell * Written by Peter Maydell 6344f4b15SPeter Maydell * 7344f4b15SPeter Maydell * This program is free software; you can redistribute it and/or modify 8344f4b15SPeter Maydell * it under the terms of the GNU General Public License version 2 or 9344f4b15SPeter Maydell * (at your option) any later version. 10344f4b15SPeter Maydell */ 11344f4b15SPeter Maydell 12344f4b15SPeter Maydell #include "qemu/osdep.h" 13344f4b15SPeter Maydell #include "qemu/log.h" 14344f4b15SPeter Maydell #include "qapi/error.h" 15344f4b15SPeter Maydell #include "trace.h" 16344f4b15SPeter Maydell #include "hw/sysbus.h" 17344f4b15SPeter Maydell #include "hw/registerfields.h" 18344f4b15SPeter Maydell #include "hw/misc/tz-mpc.h" 19344f4b15SPeter Maydell 20344f4b15SPeter Maydell /* Our IOMMU has two IOMMU indexes, one for secure transactions and one for 21344f4b15SPeter Maydell * non-secure transactions. 22344f4b15SPeter Maydell */ 23344f4b15SPeter Maydell enum { 24344f4b15SPeter Maydell IOMMU_IDX_S, 25344f4b15SPeter Maydell IOMMU_IDX_NS, 26344f4b15SPeter Maydell IOMMU_NUM_INDEXES, 27344f4b15SPeter Maydell }; 28344f4b15SPeter Maydell 29344f4b15SPeter Maydell /* Config registers */ 30344f4b15SPeter Maydell REG32(CTRL, 0x00) 31*cdb60998SPeter Maydell FIELD(CTRL, SEC_RESP, 4, 1) 32*cdb60998SPeter Maydell FIELD(CTRL, AUTOINC, 8, 1) 33*cdb60998SPeter Maydell FIELD(CTRL, LOCKDOWN, 31, 1) 34344f4b15SPeter Maydell REG32(BLK_MAX, 0x10) 35344f4b15SPeter Maydell REG32(BLK_CFG, 0x14) 36344f4b15SPeter Maydell REG32(BLK_IDX, 0x18) 37344f4b15SPeter Maydell REG32(BLK_LUT, 0x1c) 38344f4b15SPeter Maydell REG32(INT_STAT, 0x20) 39*cdb60998SPeter Maydell FIELD(INT_STAT, IRQ, 0, 1) 40344f4b15SPeter Maydell REG32(INT_CLEAR, 0x24) 41*cdb60998SPeter Maydell FIELD(INT_CLEAR, IRQ, 0, 1) 42344f4b15SPeter Maydell REG32(INT_EN, 0x28) 43*cdb60998SPeter Maydell FIELD(INT_EN, IRQ, 0, 1) 44344f4b15SPeter Maydell REG32(INT_INFO1, 0x2c) 45344f4b15SPeter Maydell REG32(INT_INFO2, 0x30) 46344f4b15SPeter Maydell REG32(INT_SET, 0x34) 47*cdb60998SPeter Maydell FIELD(INT_SET, IRQ, 0, 1) 48344f4b15SPeter Maydell REG32(PIDR4, 0xfd0) 49344f4b15SPeter Maydell REG32(PIDR5, 0xfd4) 50344f4b15SPeter Maydell REG32(PIDR6, 0xfd8) 51344f4b15SPeter Maydell REG32(PIDR7, 0xfdc) 52344f4b15SPeter Maydell REG32(PIDR0, 0xfe0) 53344f4b15SPeter Maydell REG32(PIDR1, 0xfe4) 54344f4b15SPeter Maydell REG32(PIDR2, 0xfe8) 55344f4b15SPeter Maydell REG32(PIDR3, 0xfec) 56344f4b15SPeter Maydell REG32(CIDR0, 0xff0) 57344f4b15SPeter Maydell REG32(CIDR1, 0xff4) 58344f4b15SPeter Maydell REG32(CIDR2, 0xff8) 59344f4b15SPeter Maydell REG32(CIDR3, 0xffc) 60344f4b15SPeter Maydell 61344f4b15SPeter Maydell static const uint8_t tz_mpc_idregs[] = { 62344f4b15SPeter Maydell 0x04, 0x00, 0x00, 0x00, 63344f4b15SPeter Maydell 0x60, 0xb8, 0x1b, 0x00, 64344f4b15SPeter Maydell 0x0d, 0xf0, 0x05, 0xb1, 65344f4b15SPeter Maydell }; 66344f4b15SPeter Maydell 67*cdb60998SPeter Maydell static void tz_mpc_irq_update(TZMPC *s) 68*cdb60998SPeter Maydell { 69*cdb60998SPeter Maydell qemu_set_irq(s->irq, s->int_stat && s->int_en); 70*cdb60998SPeter Maydell } 71*cdb60998SPeter Maydell 72*cdb60998SPeter Maydell static void tz_mpc_autoinc_idx(TZMPC *s, unsigned access_size) 73*cdb60998SPeter Maydell { 74*cdb60998SPeter Maydell /* Auto-increment BLK_IDX if necessary */ 75*cdb60998SPeter Maydell if (access_size == 4 && (s->ctrl & R_CTRL_AUTOINC_MASK)) { 76*cdb60998SPeter Maydell s->blk_idx++; 77*cdb60998SPeter Maydell s->blk_idx %= s->blk_max; 78*cdb60998SPeter Maydell } 79*cdb60998SPeter Maydell } 80*cdb60998SPeter Maydell 81344f4b15SPeter Maydell static MemTxResult tz_mpc_reg_read(void *opaque, hwaddr addr, 82344f4b15SPeter Maydell uint64_t *pdata, 83344f4b15SPeter Maydell unsigned size, MemTxAttrs attrs) 84344f4b15SPeter Maydell { 85*cdb60998SPeter Maydell TZMPC *s = TZ_MPC(opaque); 86344f4b15SPeter Maydell uint64_t r; 87344f4b15SPeter Maydell uint32_t offset = addr & ~0x3; 88344f4b15SPeter Maydell 89344f4b15SPeter Maydell if (!attrs.secure && offset < A_PIDR4) { 90344f4b15SPeter Maydell /* NS accesses can only see the ID registers */ 91344f4b15SPeter Maydell qemu_log_mask(LOG_GUEST_ERROR, 92344f4b15SPeter Maydell "TZ MPC register read: NS access to offset 0x%x\n", 93344f4b15SPeter Maydell offset); 94344f4b15SPeter Maydell r = 0; 95344f4b15SPeter Maydell goto read_out; 96344f4b15SPeter Maydell } 97344f4b15SPeter Maydell 98344f4b15SPeter Maydell switch (offset) { 99*cdb60998SPeter Maydell case A_CTRL: 100*cdb60998SPeter Maydell r = s->ctrl; 101*cdb60998SPeter Maydell break; 102*cdb60998SPeter Maydell case A_BLK_MAX: 103*cdb60998SPeter Maydell r = s->blk_max; 104*cdb60998SPeter Maydell break; 105*cdb60998SPeter Maydell case A_BLK_CFG: 106*cdb60998SPeter Maydell /* We are never in "init in progress state", so this just indicates 107*cdb60998SPeter Maydell * the block size. s->blocksize == (1 << BLK_CFG + 5), so 108*cdb60998SPeter Maydell * BLK_CFG == ctz32(s->blocksize) - 5 109*cdb60998SPeter Maydell */ 110*cdb60998SPeter Maydell r = ctz32(s->blocksize) - 5; 111*cdb60998SPeter Maydell break; 112*cdb60998SPeter Maydell case A_BLK_IDX: 113*cdb60998SPeter Maydell r = s->blk_idx; 114*cdb60998SPeter Maydell break; 115*cdb60998SPeter Maydell case A_BLK_LUT: 116*cdb60998SPeter Maydell r = s->blk_lut[s->blk_idx]; 117*cdb60998SPeter Maydell tz_mpc_autoinc_idx(s, size); 118*cdb60998SPeter Maydell break; 119*cdb60998SPeter Maydell case A_INT_STAT: 120*cdb60998SPeter Maydell r = s->int_stat; 121*cdb60998SPeter Maydell break; 122*cdb60998SPeter Maydell case A_INT_EN: 123*cdb60998SPeter Maydell r = s->int_en; 124*cdb60998SPeter Maydell break; 125*cdb60998SPeter Maydell case A_INT_INFO1: 126*cdb60998SPeter Maydell r = s->int_info1; 127*cdb60998SPeter Maydell break; 128*cdb60998SPeter Maydell case A_INT_INFO2: 129*cdb60998SPeter Maydell r = s->int_info2; 130*cdb60998SPeter Maydell break; 131344f4b15SPeter Maydell case A_PIDR4: 132344f4b15SPeter Maydell case A_PIDR5: 133344f4b15SPeter Maydell case A_PIDR6: 134344f4b15SPeter Maydell case A_PIDR7: 135344f4b15SPeter Maydell case A_PIDR0: 136344f4b15SPeter Maydell case A_PIDR1: 137344f4b15SPeter Maydell case A_PIDR2: 138344f4b15SPeter Maydell case A_PIDR3: 139344f4b15SPeter Maydell case A_CIDR0: 140344f4b15SPeter Maydell case A_CIDR1: 141344f4b15SPeter Maydell case A_CIDR2: 142344f4b15SPeter Maydell case A_CIDR3: 143344f4b15SPeter Maydell r = tz_mpc_idregs[(offset - A_PIDR4) / 4]; 144344f4b15SPeter Maydell break; 145344f4b15SPeter Maydell case A_INT_CLEAR: 146344f4b15SPeter Maydell case A_INT_SET: 147344f4b15SPeter Maydell qemu_log_mask(LOG_GUEST_ERROR, 148344f4b15SPeter Maydell "TZ MPC register read: write-only offset 0x%x\n", 149344f4b15SPeter Maydell offset); 150344f4b15SPeter Maydell r = 0; 151344f4b15SPeter Maydell break; 152344f4b15SPeter Maydell default: 153344f4b15SPeter Maydell qemu_log_mask(LOG_GUEST_ERROR, 154344f4b15SPeter Maydell "TZ MPC register read: bad offset 0x%x\n", offset); 155344f4b15SPeter Maydell r = 0; 156344f4b15SPeter Maydell break; 157344f4b15SPeter Maydell } 158344f4b15SPeter Maydell 159344f4b15SPeter Maydell if (size != 4) { 160344f4b15SPeter Maydell /* None of our registers are read-sensitive (except BLK_LUT, 161344f4b15SPeter Maydell * which can special case the "size not 4" case), so just 162344f4b15SPeter Maydell * pull the right bytes out of the word read result. 163344f4b15SPeter Maydell */ 164344f4b15SPeter Maydell r = extract32(r, (addr & 3) * 8, size * 8); 165344f4b15SPeter Maydell } 166344f4b15SPeter Maydell 167344f4b15SPeter Maydell read_out: 168344f4b15SPeter Maydell trace_tz_mpc_reg_read(addr, r, size); 169344f4b15SPeter Maydell *pdata = r; 170344f4b15SPeter Maydell return MEMTX_OK; 171344f4b15SPeter Maydell } 172344f4b15SPeter Maydell 173344f4b15SPeter Maydell static MemTxResult tz_mpc_reg_write(void *opaque, hwaddr addr, 174344f4b15SPeter Maydell uint64_t value, 175344f4b15SPeter Maydell unsigned size, MemTxAttrs attrs) 176344f4b15SPeter Maydell { 177*cdb60998SPeter Maydell TZMPC *s = TZ_MPC(opaque); 178344f4b15SPeter Maydell uint32_t offset = addr & ~0x3; 179344f4b15SPeter Maydell 180344f4b15SPeter Maydell trace_tz_mpc_reg_write(addr, value, size); 181344f4b15SPeter Maydell 182344f4b15SPeter Maydell if (!attrs.secure && offset < A_PIDR4) { 183344f4b15SPeter Maydell /* NS accesses can only see the ID registers */ 184344f4b15SPeter Maydell qemu_log_mask(LOG_GUEST_ERROR, 185344f4b15SPeter Maydell "TZ MPC register write: NS access to offset 0x%x\n", 186344f4b15SPeter Maydell offset); 187344f4b15SPeter Maydell return MEMTX_OK; 188344f4b15SPeter Maydell } 189344f4b15SPeter Maydell 190344f4b15SPeter Maydell if (size != 4) { 191344f4b15SPeter Maydell /* Expand the byte or halfword write to a full word size. 192344f4b15SPeter Maydell * In most cases we can do this with zeroes; the exceptions 193344f4b15SPeter Maydell * are CTRL, BLK_IDX and BLK_LUT. 194344f4b15SPeter Maydell */ 195344f4b15SPeter Maydell uint32_t oldval; 196344f4b15SPeter Maydell 197344f4b15SPeter Maydell switch (offset) { 198*cdb60998SPeter Maydell case A_CTRL: 199*cdb60998SPeter Maydell oldval = s->ctrl; 200*cdb60998SPeter Maydell break; 201*cdb60998SPeter Maydell case A_BLK_IDX: 202*cdb60998SPeter Maydell oldval = s->blk_idx; 203*cdb60998SPeter Maydell break; 204*cdb60998SPeter Maydell case A_BLK_LUT: 205*cdb60998SPeter Maydell oldval = s->blk_lut[s->blk_idx]; 206*cdb60998SPeter Maydell break; 207344f4b15SPeter Maydell default: 208344f4b15SPeter Maydell oldval = 0; 209344f4b15SPeter Maydell break; 210344f4b15SPeter Maydell } 211344f4b15SPeter Maydell value = deposit32(oldval, (addr & 3) * 8, size * 8, value); 212344f4b15SPeter Maydell } 213344f4b15SPeter Maydell 214*cdb60998SPeter Maydell if ((s->ctrl & R_CTRL_LOCKDOWN_MASK) && 215*cdb60998SPeter Maydell (offset == A_CTRL || offset == A_BLK_LUT || offset == A_INT_EN)) { 216*cdb60998SPeter Maydell /* Lockdown mode makes these three registers read-only, and 217*cdb60998SPeter Maydell * the only way out of it is to reset the device. 218*cdb60998SPeter Maydell */ 219*cdb60998SPeter Maydell qemu_log_mask(LOG_GUEST_ERROR, "TZ MPC register write to offset 0x%x " 220*cdb60998SPeter Maydell "while MPC is in lockdown mode\n", offset); 221*cdb60998SPeter Maydell return MEMTX_OK; 222*cdb60998SPeter Maydell } 223*cdb60998SPeter Maydell 224344f4b15SPeter Maydell switch (offset) { 225*cdb60998SPeter Maydell case A_CTRL: 226*cdb60998SPeter Maydell /* We don't implement the 'data gating' feature so all other bits 227*cdb60998SPeter Maydell * are reserved and we make them RAZ/WI. 228*cdb60998SPeter Maydell */ 229*cdb60998SPeter Maydell s->ctrl = value & (R_CTRL_SEC_RESP_MASK | 230*cdb60998SPeter Maydell R_CTRL_AUTOINC_MASK | 231*cdb60998SPeter Maydell R_CTRL_LOCKDOWN_MASK); 232*cdb60998SPeter Maydell break; 233*cdb60998SPeter Maydell case A_BLK_IDX: 234*cdb60998SPeter Maydell s->blk_idx = value % s->blk_max; 235*cdb60998SPeter Maydell break; 236*cdb60998SPeter Maydell case A_BLK_LUT: 237*cdb60998SPeter Maydell s->blk_lut[s->blk_idx] = value; 238*cdb60998SPeter Maydell tz_mpc_autoinc_idx(s, size); 239*cdb60998SPeter Maydell break; 240*cdb60998SPeter Maydell case A_INT_CLEAR: 241*cdb60998SPeter Maydell if (value & R_INT_CLEAR_IRQ_MASK) { 242*cdb60998SPeter Maydell s->int_stat = 0; 243*cdb60998SPeter Maydell tz_mpc_irq_update(s); 244*cdb60998SPeter Maydell } 245*cdb60998SPeter Maydell break; 246*cdb60998SPeter Maydell case A_INT_EN: 247*cdb60998SPeter Maydell s->int_en = value & R_INT_EN_IRQ_MASK; 248*cdb60998SPeter Maydell tz_mpc_irq_update(s); 249*cdb60998SPeter Maydell break; 250*cdb60998SPeter Maydell case A_INT_SET: 251*cdb60998SPeter Maydell if (value & R_INT_SET_IRQ_MASK) { 252*cdb60998SPeter Maydell s->int_stat = R_INT_STAT_IRQ_MASK; 253*cdb60998SPeter Maydell tz_mpc_irq_update(s); 254*cdb60998SPeter Maydell } 255*cdb60998SPeter Maydell break; 256344f4b15SPeter Maydell case A_PIDR4: 257344f4b15SPeter Maydell case A_PIDR5: 258344f4b15SPeter Maydell case A_PIDR6: 259344f4b15SPeter Maydell case A_PIDR7: 260344f4b15SPeter Maydell case A_PIDR0: 261344f4b15SPeter Maydell case A_PIDR1: 262344f4b15SPeter Maydell case A_PIDR2: 263344f4b15SPeter Maydell case A_PIDR3: 264344f4b15SPeter Maydell case A_CIDR0: 265344f4b15SPeter Maydell case A_CIDR1: 266344f4b15SPeter Maydell case A_CIDR2: 267344f4b15SPeter Maydell case A_CIDR3: 268344f4b15SPeter Maydell qemu_log_mask(LOG_GUEST_ERROR, 269344f4b15SPeter Maydell "TZ MPC register write: read-only offset 0x%x\n", offset); 270344f4b15SPeter Maydell break; 271344f4b15SPeter Maydell default: 272344f4b15SPeter Maydell qemu_log_mask(LOG_GUEST_ERROR, 273344f4b15SPeter Maydell "TZ MPC register write: bad offset 0x%x\n", offset); 274344f4b15SPeter Maydell break; 275344f4b15SPeter Maydell } 276344f4b15SPeter Maydell 277344f4b15SPeter Maydell return MEMTX_OK; 278344f4b15SPeter Maydell } 279344f4b15SPeter Maydell 280344f4b15SPeter Maydell static const MemoryRegionOps tz_mpc_reg_ops = { 281344f4b15SPeter Maydell .read_with_attrs = tz_mpc_reg_read, 282344f4b15SPeter Maydell .write_with_attrs = tz_mpc_reg_write, 283344f4b15SPeter Maydell .endianness = DEVICE_LITTLE_ENDIAN, 284344f4b15SPeter Maydell .valid.min_access_size = 1, 285344f4b15SPeter Maydell .valid.max_access_size = 4, 286344f4b15SPeter Maydell .impl.min_access_size = 1, 287344f4b15SPeter Maydell .impl.max_access_size = 4, 288344f4b15SPeter Maydell }; 289344f4b15SPeter Maydell 290344f4b15SPeter Maydell /* Accesses only reach these read and write functions if the MPC is 291344f4b15SPeter Maydell * blocking them; non-blocked accesses go directly to the downstream 292344f4b15SPeter Maydell * memory region without passing through this code. 293344f4b15SPeter Maydell */ 294344f4b15SPeter Maydell static MemTxResult tz_mpc_mem_blocked_read(void *opaque, hwaddr addr, 295344f4b15SPeter Maydell uint64_t *pdata, 296344f4b15SPeter Maydell unsigned size, MemTxAttrs attrs) 297344f4b15SPeter Maydell { 298344f4b15SPeter Maydell trace_tz_mpc_mem_blocked_read(addr, size, attrs.secure); 299344f4b15SPeter Maydell 300344f4b15SPeter Maydell *pdata = 0; 301344f4b15SPeter Maydell return MEMTX_OK; 302344f4b15SPeter Maydell } 303344f4b15SPeter Maydell 304344f4b15SPeter Maydell static MemTxResult tz_mpc_mem_blocked_write(void *opaque, hwaddr addr, 305344f4b15SPeter Maydell uint64_t value, 306344f4b15SPeter Maydell unsigned size, MemTxAttrs attrs) 307344f4b15SPeter Maydell { 308344f4b15SPeter Maydell trace_tz_mpc_mem_blocked_write(addr, value, size, attrs.secure); 309344f4b15SPeter Maydell 310344f4b15SPeter Maydell return MEMTX_OK; 311344f4b15SPeter Maydell } 312344f4b15SPeter Maydell 313344f4b15SPeter Maydell static const MemoryRegionOps tz_mpc_mem_blocked_ops = { 314344f4b15SPeter Maydell .read_with_attrs = tz_mpc_mem_blocked_read, 315344f4b15SPeter Maydell .write_with_attrs = tz_mpc_mem_blocked_write, 316344f4b15SPeter Maydell .endianness = DEVICE_LITTLE_ENDIAN, 317344f4b15SPeter Maydell .valid.min_access_size = 1, 318344f4b15SPeter Maydell .valid.max_access_size = 8, 319344f4b15SPeter Maydell .impl.min_access_size = 1, 320344f4b15SPeter Maydell .impl.max_access_size = 8, 321344f4b15SPeter Maydell }; 322344f4b15SPeter Maydell 323344f4b15SPeter Maydell static IOMMUTLBEntry tz_mpc_translate(IOMMUMemoryRegion *iommu, 324344f4b15SPeter Maydell hwaddr addr, IOMMUAccessFlags flags, 325344f4b15SPeter Maydell int iommu_idx) 326344f4b15SPeter Maydell { 327344f4b15SPeter Maydell TZMPC *s = TZ_MPC(container_of(iommu, TZMPC, upstream)); 328344f4b15SPeter Maydell bool ok; 329344f4b15SPeter Maydell 330344f4b15SPeter Maydell IOMMUTLBEntry ret = { 331344f4b15SPeter Maydell .iova = addr & ~(s->blocksize - 1), 332344f4b15SPeter Maydell .translated_addr = addr & ~(s->blocksize - 1), 333344f4b15SPeter Maydell .addr_mask = s->blocksize - 1, 334344f4b15SPeter Maydell .perm = IOMMU_RW, 335344f4b15SPeter Maydell }; 336344f4b15SPeter Maydell 337344f4b15SPeter Maydell /* Look at the per-block configuration for this address, and 338344f4b15SPeter Maydell * return a TLB entry directing the transaction at either 339344f4b15SPeter Maydell * downstream_as or blocked_io_as, as appropriate. 340344f4b15SPeter Maydell * For the moment, always permit accesses. 341344f4b15SPeter Maydell */ 342344f4b15SPeter Maydell ok = true; 343344f4b15SPeter Maydell 344344f4b15SPeter Maydell trace_tz_mpc_translate(addr, flags, 345344f4b15SPeter Maydell iommu_idx == IOMMU_IDX_S ? "S" : "NS", 346344f4b15SPeter Maydell ok ? "pass" : "block"); 347344f4b15SPeter Maydell 348344f4b15SPeter Maydell ret.target_as = ok ? &s->downstream_as : &s->blocked_io_as; 349344f4b15SPeter Maydell return ret; 350344f4b15SPeter Maydell } 351344f4b15SPeter Maydell 352344f4b15SPeter Maydell static int tz_mpc_attrs_to_index(IOMMUMemoryRegion *iommu, MemTxAttrs attrs) 353344f4b15SPeter Maydell { 354344f4b15SPeter Maydell /* We treat unspecified attributes like secure. Transactions with 355344f4b15SPeter Maydell * unspecified attributes come from places like 356344f4b15SPeter Maydell * cpu_physical_memory_write_rom() for initial image load, and we want 357344f4b15SPeter Maydell * those to pass through the from-reset "everything is secure" config. 358344f4b15SPeter Maydell * All the real during-emulation transactions from the CPU will 359344f4b15SPeter Maydell * specify attributes. 360344f4b15SPeter Maydell */ 361344f4b15SPeter Maydell return (attrs.unspecified || attrs.secure) ? IOMMU_IDX_S : IOMMU_IDX_NS; 362344f4b15SPeter Maydell } 363344f4b15SPeter Maydell 364344f4b15SPeter Maydell static int tz_mpc_num_indexes(IOMMUMemoryRegion *iommu) 365344f4b15SPeter Maydell { 366344f4b15SPeter Maydell return IOMMU_NUM_INDEXES; 367344f4b15SPeter Maydell } 368344f4b15SPeter Maydell 369344f4b15SPeter Maydell static void tz_mpc_reset(DeviceState *dev) 370344f4b15SPeter Maydell { 371*cdb60998SPeter Maydell TZMPC *s = TZ_MPC(dev); 372*cdb60998SPeter Maydell 373*cdb60998SPeter Maydell s->ctrl = 0x00000100; 374*cdb60998SPeter Maydell s->blk_idx = 0; 375*cdb60998SPeter Maydell s->int_stat = 0; 376*cdb60998SPeter Maydell s->int_en = 1; 377*cdb60998SPeter Maydell s->int_info1 = 0; 378*cdb60998SPeter Maydell s->int_info2 = 0; 379*cdb60998SPeter Maydell 380*cdb60998SPeter Maydell memset(s->blk_lut, 0, s->blk_max * sizeof(uint32_t)); 381344f4b15SPeter Maydell } 382344f4b15SPeter Maydell 383344f4b15SPeter Maydell static void tz_mpc_init(Object *obj) 384344f4b15SPeter Maydell { 385344f4b15SPeter Maydell DeviceState *dev = DEVICE(obj); 386344f4b15SPeter Maydell TZMPC *s = TZ_MPC(obj); 387344f4b15SPeter Maydell 388344f4b15SPeter Maydell qdev_init_gpio_out_named(dev, &s->irq, "irq", 1); 389344f4b15SPeter Maydell } 390344f4b15SPeter Maydell 391344f4b15SPeter Maydell static void tz_mpc_realize(DeviceState *dev, Error **errp) 392344f4b15SPeter Maydell { 393344f4b15SPeter Maydell Object *obj = OBJECT(dev); 394344f4b15SPeter Maydell SysBusDevice *sbd = SYS_BUS_DEVICE(dev); 395344f4b15SPeter Maydell TZMPC *s = TZ_MPC(dev); 396344f4b15SPeter Maydell uint64_t size; 397344f4b15SPeter Maydell 398344f4b15SPeter Maydell /* We can't create the upstream end of the port until realize, 399344f4b15SPeter Maydell * as we don't know the size of the MR used as the downstream until then. 400344f4b15SPeter Maydell * We insist on having a downstream, to avoid complicating the code 401344f4b15SPeter Maydell * with handling the "don't know how big this is" case. It's easy 402344f4b15SPeter Maydell * enough for the user to create an unimplemented_device as downstream 403344f4b15SPeter Maydell * if they have nothing else to plug into this. 404344f4b15SPeter Maydell */ 405344f4b15SPeter Maydell if (!s->downstream) { 406344f4b15SPeter Maydell error_setg(errp, "MPC 'downstream' link not set"); 407344f4b15SPeter Maydell return; 408344f4b15SPeter Maydell } 409344f4b15SPeter Maydell 410344f4b15SPeter Maydell size = memory_region_size(s->downstream); 411344f4b15SPeter Maydell 412344f4b15SPeter Maydell memory_region_init_iommu(&s->upstream, sizeof(s->upstream), 413344f4b15SPeter Maydell TYPE_TZ_MPC_IOMMU_MEMORY_REGION, 414344f4b15SPeter Maydell obj, "tz-mpc-upstream", size); 415344f4b15SPeter Maydell 416344f4b15SPeter Maydell /* In real hardware the block size is configurable. In QEMU we could 417344f4b15SPeter Maydell * make it configurable but will need it to be at least as big as the 418344f4b15SPeter Maydell * target page size so we can execute out of the resulting MRs. Guest 419344f4b15SPeter Maydell * software is supposed to check the block size using the BLK_CFG 420344f4b15SPeter Maydell * register, so make it fixed at the page size. 421344f4b15SPeter Maydell */ 422344f4b15SPeter Maydell s->blocksize = memory_region_iommu_get_min_page_size(&s->upstream); 423344f4b15SPeter Maydell if (size % s->blocksize != 0) { 424344f4b15SPeter Maydell error_setg(errp, 425344f4b15SPeter Maydell "MPC 'downstream' size %" PRId64 426344f4b15SPeter Maydell " is not a multiple of %" HWADDR_PRIx " bytes", 427344f4b15SPeter Maydell size, s->blocksize); 428344f4b15SPeter Maydell object_unref(OBJECT(&s->upstream)); 429344f4b15SPeter Maydell return; 430344f4b15SPeter Maydell } 431344f4b15SPeter Maydell 432344f4b15SPeter Maydell /* BLK_MAX is the max value of BLK_IDX, which indexes an array of 32-bit 433344f4b15SPeter Maydell * words, each bit of which indicates one block. 434344f4b15SPeter Maydell */ 435344f4b15SPeter Maydell s->blk_max = DIV_ROUND_UP(size / s->blocksize, 32); 436344f4b15SPeter Maydell 437344f4b15SPeter Maydell memory_region_init_io(&s->regmr, obj, &tz_mpc_reg_ops, 438344f4b15SPeter Maydell s, "tz-mpc-regs", 0x1000); 439344f4b15SPeter Maydell sysbus_init_mmio(sbd, &s->regmr); 440344f4b15SPeter Maydell 441344f4b15SPeter Maydell sysbus_init_mmio(sbd, MEMORY_REGION(&s->upstream)); 442344f4b15SPeter Maydell 443344f4b15SPeter Maydell /* This memory region is not exposed to users of this device as a 444344f4b15SPeter Maydell * sysbus MMIO region, but is instead used internally as something 445344f4b15SPeter Maydell * that our IOMMU translate function might direct accesses to. 446344f4b15SPeter Maydell */ 447344f4b15SPeter Maydell memory_region_init_io(&s->blocked_io, obj, &tz_mpc_mem_blocked_ops, 448344f4b15SPeter Maydell s, "tz-mpc-blocked-io", size); 449344f4b15SPeter Maydell 450344f4b15SPeter Maydell address_space_init(&s->downstream_as, s->downstream, 451344f4b15SPeter Maydell "tz-mpc-downstream"); 452344f4b15SPeter Maydell address_space_init(&s->blocked_io_as, &s->blocked_io, 453344f4b15SPeter Maydell "tz-mpc-blocked-io"); 454*cdb60998SPeter Maydell 455*cdb60998SPeter Maydell s->blk_lut = g_new(uint32_t, s->blk_max); 456*cdb60998SPeter Maydell } 457*cdb60998SPeter Maydell 458*cdb60998SPeter Maydell static int tz_mpc_post_load(void *opaque, int version_id) 459*cdb60998SPeter Maydell { 460*cdb60998SPeter Maydell TZMPC *s = TZ_MPC(opaque); 461*cdb60998SPeter Maydell 462*cdb60998SPeter Maydell /* Check the incoming data doesn't point blk_idx off the end of blk_lut. */ 463*cdb60998SPeter Maydell if (s->blk_idx >= s->blk_max) { 464*cdb60998SPeter Maydell return -1; 465*cdb60998SPeter Maydell } 466*cdb60998SPeter Maydell return 0; 467344f4b15SPeter Maydell } 468344f4b15SPeter Maydell 469344f4b15SPeter Maydell static const VMStateDescription tz_mpc_vmstate = { 470344f4b15SPeter Maydell .name = "tz-mpc", 471344f4b15SPeter Maydell .version_id = 1, 472344f4b15SPeter Maydell .minimum_version_id = 1, 473*cdb60998SPeter Maydell .post_load = tz_mpc_post_load, 474344f4b15SPeter Maydell .fields = (VMStateField[]) { 475*cdb60998SPeter Maydell VMSTATE_UINT32(ctrl, TZMPC), 476*cdb60998SPeter Maydell VMSTATE_UINT32(blk_idx, TZMPC), 477*cdb60998SPeter Maydell VMSTATE_UINT32(int_stat, TZMPC), 478*cdb60998SPeter Maydell VMSTATE_UINT32(int_en, TZMPC), 479*cdb60998SPeter Maydell VMSTATE_UINT32(int_info1, TZMPC), 480*cdb60998SPeter Maydell VMSTATE_UINT32(int_info2, TZMPC), 481*cdb60998SPeter Maydell VMSTATE_VARRAY_UINT32(blk_lut, TZMPC, blk_max, 482*cdb60998SPeter Maydell 0, vmstate_info_uint32, uint32_t), 483344f4b15SPeter Maydell VMSTATE_END_OF_LIST() 484344f4b15SPeter Maydell } 485344f4b15SPeter Maydell }; 486344f4b15SPeter Maydell 487344f4b15SPeter Maydell static Property tz_mpc_properties[] = { 488344f4b15SPeter Maydell DEFINE_PROP_LINK("downstream", TZMPC, downstream, 489344f4b15SPeter Maydell TYPE_MEMORY_REGION, MemoryRegion *), 490344f4b15SPeter Maydell DEFINE_PROP_END_OF_LIST(), 491344f4b15SPeter Maydell }; 492344f4b15SPeter Maydell 493344f4b15SPeter Maydell static void tz_mpc_class_init(ObjectClass *klass, void *data) 494344f4b15SPeter Maydell { 495344f4b15SPeter Maydell DeviceClass *dc = DEVICE_CLASS(klass); 496344f4b15SPeter Maydell 497344f4b15SPeter Maydell dc->realize = tz_mpc_realize; 498344f4b15SPeter Maydell dc->vmsd = &tz_mpc_vmstate; 499344f4b15SPeter Maydell dc->reset = tz_mpc_reset; 500344f4b15SPeter Maydell dc->props = tz_mpc_properties; 501344f4b15SPeter Maydell } 502344f4b15SPeter Maydell 503344f4b15SPeter Maydell static const TypeInfo tz_mpc_info = { 504344f4b15SPeter Maydell .name = TYPE_TZ_MPC, 505344f4b15SPeter Maydell .parent = TYPE_SYS_BUS_DEVICE, 506344f4b15SPeter Maydell .instance_size = sizeof(TZMPC), 507344f4b15SPeter Maydell .instance_init = tz_mpc_init, 508344f4b15SPeter Maydell .class_init = tz_mpc_class_init, 509344f4b15SPeter Maydell }; 510344f4b15SPeter Maydell 511344f4b15SPeter Maydell static void tz_mpc_iommu_memory_region_class_init(ObjectClass *klass, 512344f4b15SPeter Maydell void *data) 513344f4b15SPeter Maydell { 514344f4b15SPeter Maydell IOMMUMemoryRegionClass *imrc = IOMMU_MEMORY_REGION_CLASS(klass); 515344f4b15SPeter Maydell 516344f4b15SPeter Maydell imrc->translate = tz_mpc_translate; 517344f4b15SPeter Maydell imrc->attrs_to_index = tz_mpc_attrs_to_index; 518344f4b15SPeter Maydell imrc->num_indexes = tz_mpc_num_indexes; 519344f4b15SPeter Maydell } 520344f4b15SPeter Maydell 521344f4b15SPeter Maydell static const TypeInfo tz_mpc_iommu_memory_region_info = { 522344f4b15SPeter Maydell .name = TYPE_TZ_MPC_IOMMU_MEMORY_REGION, 523344f4b15SPeter Maydell .parent = TYPE_IOMMU_MEMORY_REGION, 524344f4b15SPeter Maydell .class_init = tz_mpc_iommu_memory_region_class_init, 525344f4b15SPeter Maydell }; 526344f4b15SPeter Maydell 527344f4b15SPeter Maydell static void tz_mpc_register_types(void) 528344f4b15SPeter Maydell { 529344f4b15SPeter Maydell type_register_static(&tz_mpc_info); 530344f4b15SPeter Maydell type_register_static(&tz_mpc_iommu_memory_region_info); 531344f4b15SPeter Maydell } 532344f4b15SPeter Maydell 533344f4b15SPeter Maydell type_init(tz_mpc_register_types); 534