qemu

Форк
0
/
tz-msc.c 
312 строк · 8.3 Кб
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

24
static 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

32
static 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

40
static 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

48
static 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
 */
66
typedef enum MSCAction {
67
    MSCBlockAbort,
68
    MSCBlockRAZWI,
69
    MSCAllowSecure,
70
    MSCAllowNonSecure,
71
} MSCAction;
72

73
static 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

124
static 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

168
static 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

209
static 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

215
static 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

226
static 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

237
static 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

268
static const VMStateDescription tz_msc_vmstate = {
269
    .name = "tz-msc",
270
    .version_id = 1,
271
    .minimum_version_id = 1,
272
    .fields = (const 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

281
static 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

289
static 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

299
static 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

307
static void tz_msc_register_types(void)
308
{
309
    type_register_static(&tz_msc_info);
310
}
311

312
type_init(tz_msc_register_types);
313

Использование cookies

Мы используем файлы cookie в соответствии с Политикой конфиденциальности и Политикой использования cookies.

Нажимая кнопку «Принимаю», Вы даете АО «СберТех» согласие на обработку Ваших персональных данных в целях совершенствования нашего веб-сайта и Сервиса GitVerse, а также повышения удобства их использования.

Запретить использование cookies Вы можете самостоятельно в настройках Вашего браузера.