tz-msc.c (8444B)
1/* 2 * ARM TrustZone master security controller emulation 3 * 4 * Copyright (c) 2018 Linaro Limited 5 * Written by Peter Maydell 6 * 7 * This program is free software; you can redistribute it and/or modify 8 * it under the terms of the GNU General Public License version 2 or 9 * (at your option) any later version. 10 */ 11 12#include "qemu/osdep.h" 13#include "qemu/log.h" 14#include "qemu/module.h" 15#include "qapi/error.h" 16#include "trace.h" 17#include "hw/sysbus.h" 18#include "migration/vmstate.h" 19#include "hw/registerfields.h" 20#include "hw/irq.h" 21#include "hw/misc/tz-msc.h" 22#include "hw/qdev-properties.h" 23 24static void tz_msc_update_irq(TZMSC *s) 25{ 26 bool level = s->irq_status; 27 28 trace_tz_msc_update_irq(level); 29 qemu_set_irq(s->irq, level); 30} 31 32static void tz_msc_cfg_nonsec(void *opaque, int n, int level) 33{ 34 TZMSC *s = TZ_MSC(opaque); 35 36 trace_tz_msc_cfg_nonsec(level); 37 s->cfg_nonsec = level; 38} 39 40static void tz_msc_cfg_sec_resp(void *opaque, int n, int level) 41{ 42 TZMSC *s = TZ_MSC(opaque); 43 44 trace_tz_msc_cfg_sec_resp(level); 45 s->cfg_sec_resp = level; 46} 47 48static void tz_msc_irq_clear(void *opaque, int n, int level) 49{ 50 TZMSC *s = TZ_MSC(opaque); 51 52 trace_tz_msc_irq_clear(level); 53 54 s->irq_clear = level; 55 if (level) { 56 s->irq_status = false; 57 tz_msc_update_irq(s); 58 } 59} 60 61/* The MSC may either block a transaction by aborting it, block a 62 * transaction by making it RAZ/WI, allow it through with 63 * MemTxAttrs indicating a secure transaction, or allow it with 64 * MemTxAttrs indicating a non-secure transaction. 65 */ 66typedef enum MSCAction { 67 MSCBlockAbort, 68 MSCBlockRAZWI, 69 MSCAllowSecure, 70 MSCAllowNonSecure, 71} MSCAction; 72 73static MSCAction tz_msc_check(TZMSC *s, hwaddr addr) 74{ 75 /* 76 * Check whether to allow an access from the bus master, returning 77 * an MSCAction indicating the required behaviour. If the transaction 78 * is blocked, the caller must check cfg_sec_resp to determine 79 * whether to abort or RAZ/WI the transaction. 80 */ 81 IDAUInterfaceClass *iic = IDAU_INTERFACE_GET_CLASS(s->idau); 82 IDAUInterface *ii = IDAU_INTERFACE(s->idau); 83 bool idau_exempt = false, idau_ns = true, idau_nsc = true; 84 int idau_region = IREGION_NOTVALID; 85 86 iic->check(ii, addr, &idau_region, &idau_exempt, &idau_ns, &idau_nsc); 87 88 if (idau_exempt) { 89 /* 90 * Uncheck region -- OK, transaction type depends on 91 * whether bus master is configured as Secure or NonSecure 92 */ 93 return s->cfg_nonsec ? MSCAllowNonSecure : MSCAllowSecure; 94 } 95 96 if (idau_ns) { 97 /* NonSecure region -- always forward as NS transaction */ 98 return MSCAllowNonSecure; 99 } 100 101 if (!s->cfg_nonsec) { 102 /* Access to Secure region by Secure bus master: OK */ 103 return MSCAllowSecure; 104 } 105 106 /* Attempted access to Secure region by NS bus master: block */ 107 trace_tz_msc_access_blocked(addr); 108 if (!s->cfg_sec_resp) { 109 return MSCBlockRAZWI; 110 } 111 112 /* 113 * The TRM isn't clear on behaviour if irq_clear is high when a 114 * transaction is blocked. We assume that the MSC behaves like the 115 * PPC, where holding irq_clear high suppresses the interrupt. 116 */ 117 if (!s->irq_clear) { 118 s->irq_status = true; 119 tz_msc_update_irq(s); 120 } 121 return MSCBlockAbort; 122} 123 124static MemTxResult tz_msc_read(void *opaque, hwaddr addr, uint64_t *pdata, 125 unsigned size, MemTxAttrs attrs) 126{ 127 TZMSC *s = opaque; 128 AddressSpace *as = &s->downstream_as; 129 uint64_t data; 130 MemTxResult res; 131 132 switch (tz_msc_check(s, addr)) { 133 case MSCBlockAbort: 134 return MEMTX_ERROR; 135 case MSCBlockRAZWI: 136 *pdata = 0; 137 return MEMTX_OK; 138 case MSCAllowSecure: 139 attrs.secure = 1; 140 attrs.unspecified = 0; 141 break; 142 case MSCAllowNonSecure: 143 attrs.secure = 0; 144 attrs.unspecified = 0; 145 break; 146 } 147 148 switch (size) { 149 case 1: 150 data = address_space_ldub(as, addr, attrs, &res); 151 break; 152 case 2: 153 data = address_space_lduw_le(as, addr, attrs, &res); 154 break; 155 case 4: 156 data = address_space_ldl_le(as, addr, attrs, &res); 157 break; 158 case 8: 159 data = address_space_ldq_le(as, addr, attrs, &res); 160 break; 161 default: 162 g_assert_not_reached(); 163 } 164 *pdata = data; 165 return res; 166} 167 168static MemTxResult tz_msc_write(void *opaque, hwaddr addr, uint64_t val, 169 unsigned size, MemTxAttrs attrs) 170{ 171 TZMSC *s = opaque; 172 AddressSpace *as = &s->downstream_as; 173 MemTxResult res; 174 175 switch (tz_msc_check(s, addr)) { 176 case MSCBlockAbort: 177 return MEMTX_ERROR; 178 case MSCBlockRAZWI: 179 return MEMTX_OK; 180 case MSCAllowSecure: 181 attrs.secure = 1; 182 attrs.unspecified = 0; 183 break; 184 case MSCAllowNonSecure: 185 attrs.secure = 0; 186 attrs.unspecified = 0; 187 break; 188 } 189 190 switch (size) { 191 case 1: 192 address_space_stb(as, addr, val, attrs, &res); 193 break; 194 case 2: 195 address_space_stw_le(as, addr, val, attrs, &res); 196 break; 197 case 4: 198 address_space_stl_le(as, addr, val, attrs, &res); 199 break; 200 case 8: 201 address_space_stq_le(as, addr, val, attrs, &res); 202 break; 203 default: 204 g_assert_not_reached(); 205 } 206 return res; 207} 208 209static const MemoryRegionOps tz_msc_ops = { 210 .read_with_attrs = tz_msc_read, 211 .write_with_attrs = tz_msc_write, 212 .endianness = DEVICE_LITTLE_ENDIAN, 213}; 214 215static void tz_msc_reset(DeviceState *dev) 216{ 217 TZMSC *s = TZ_MSC(dev); 218 219 trace_tz_msc_reset(); 220 s->cfg_sec_resp = false; 221 s->cfg_nonsec = false; 222 s->irq_clear = 0; 223 s->irq_status = 0; 224} 225 226static void tz_msc_init(Object *obj) 227{ 228 DeviceState *dev = DEVICE(obj); 229 TZMSC *s = TZ_MSC(obj); 230 231 qdev_init_gpio_in_named(dev, tz_msc_cfg_nonsec, "cfg_nonsec", 1); 232 qdev_init_gpio_in_named(dev, tz_msc_cfg_sec_resp, "cfg_sec_resp", 1); 233 qdev_init_gpio_in_named(dev, tz_msc_irq_clear, "irq_clear", 1); 234 qdev_init_gpio_out_named(dev, &s->irq, "irq", 1); 235} 236 237static void tz_msc_realize(DeviceState *dev, Error **errp) 238{ 239 Object *obj = OBJECT(dev); 240 SysBusDevice *sbd = SYS_BUS_DEVICE(dev); 241 TZMSC *s = TZ_MSC(dev); 242 const char *name = "tz-msc-downstream"; 243 uint64_t size; 244 245 /* 246 * We can't create the upstream end of the port until realize, 247 * as we don't know the size of the MR used as the downstream until then. 248 * We insist on having a downstream, to avoid complicating the 249 * code with handling the "don't know how big this is" case. It's easy 250 * enough for the user to create an unimplemented_device as downstream 251 * if they have nothing else to plug into this. 252 */ 253 if (!s->downstream) { 254 error_setg(errp, "MSC 'downstream' link not set"); 255 return; 256 } 257 if (!s->idau) { 258 error_setg(errp, "MSC 'idau' link not set"); 259 return; 260 } 261 262 size = memory_region_size(s->downstream); 263 address_space_init(&s->downstream_as, s->downstream, name); 264 memory_region_init_io(&s->upstream, obj, &tz_msc_ops, s, name, size); 265 sysbus_init_mmio(sbd, &s->upstream); 266} 267 268static const VMStateDescription tz_msc_vmstate = { 269 .name = "tz-msc", 270 .version_id = 1, 271 .minimum_version_id = 1, 272 .fields = (VMStateField[]) { 273 VMSTATE_BOOL(cfg_nonsec, TZMSC), 274 VMSTATE_BOOL(cfg_sec_resp, TZMSC), 275 VMSTATE_BOOL(irq_clear, TZMSC), 276 VMSTATE_BOOL(irq_status, TZMSC), 277 VMSTATE_END_OF_LIST() 278 } 279}; 280 281static Property tz_msc_properties[] = { 282 DEFINE_PROP_LINK("downstream", TZMSC, downstream, 283 TYPE_MEMORY_REGION, MemoryRegion *), 284 DEFINE_PROP_LINK("idau", TZMSC, idau, 285 TYPE_IDAU_INTERFACE, IDAUInterface *), 286 DEFINE_PROP_END_OF_LIST(), 287}; 288 289static void tz_msc_class_init(ObjectClass *klass, void *data) 290{ 291 DeviceClass *dc = DEVICE_CLASS(klass); 292 293 dc->realize = tz_msc_realize; 294 dc->vmsd = &tz_msc_vmstate; 295 dc->reset = tz_msc_reset; 296 device_class_set_props(dc, tz_msc_properties); 297} 298 299static const TypeInfo tz_msc_info = { 300 .name = TYPE_TZ_MSC, 301 .parent = TYPE_SYS_BUS_DEVICE, 302 .instance_size = sizeof(TZMSC), 303 .instance_init = tz_msc_init, 304 .class_init = tz_msc_class_init, 305}; 306 307static void tz_msc_register_types(void) 308{ 309 type_register_static(&tz_msc_info); 310} 311 312type_init(tz_msc_register_types);