xref: /openbmc/qemu/hw/misc/tz-mpc.c (revision 5e7b204d)
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"
140b8fa32fSMarkus Armbruster #include "qemu/module.h"
15344f4b15SPeter Maydell #include "qapi/error.h"
16344f4b15SPeter Maydell #include "trace.h"
17344f4b15SPeter Maydell #include "hw/sysbus.h"
18d6454270SMarkus Armbruster #include "migration/vmstate.h"
19344f4b15SPeter Maydell #include "hw/registerfields.h"
2064552b6bSMarkus Armbruster #include "hw/irq.h"
21344f4b15SPeter Maydell #include "hw/misc/tz-mpc.h"
22a27bd6c7SMarkus Armbruster #include "hw/qdev-properties.h"
23344f4b15SPeter Maydell 
24344f4b15SPeter Maydell /* Our IOMMU has two IOMMU indexes, one for secure transactions and one for
25344f4b15SPeter Maydell  * non-secure transactions.
26344f4b15SPeter Maydell  */
27344f4b15SPeter Maydell enum {
28344f4b15SPeter Maydell     IOMMU_IDX_S,
29344f4b15SPeter Maydell     IOMMU_IDX_NS,
30344f4b15SPeter Maydell     IOMMU_NUM_INDEXES,
31344f4b15SPeter Maydell };
32344f4b15SPeter Maydell 
33344f4b15SPeter Maydell /* Config registers */
34344f4b15SPeter Maydell REG32(CTRL, 0x00)
35cdb60998SPeter Maydell     FIELD(CTRL, SEC_RESP, 4, 1)
36cdb60998SPeter Maydell     FIELD(CTRL, AUTOINC, 8, 1)
37cdb60998SPeter Maydell     FIELD(CTRL, LOCKDOWN, 31, 1)
38344f4b15SPeter Maydell REG32(BLK_MAX, 0x10)
39344f4b15SPeter Maydell REG32(BLK_CFG, 0x14)
40344f4b15SPeter Maydell REG32(BLK_IDX, 0x18)
41344f4b15SPeter Maydell REG32(BLK_LUT, 0x1c)
42344f4b15SPeter Maydell REG32(INT_STAT, 0x20)
43cdb60998SPeter Maydell     FIELD(INT_STAT, IRQ, 0, 1)
44344f4b15SPeter Maydell REG32(INT_CLEAR, 0x24)
45cdb60998SPeter Maydell     FIELD(INT_CLEAR, IRQ, 0, 1)
46344f4b15SPeter Maydell REG32(INT_EN, 0x28)
47cdb60998SPeter Maydell     FIELD(INT_EN, IRQ, 0, 1)
48344f4b15SPeter Maydell REG32(INT_INFO1, 0x2c)
49344f4b15SPeter Maydell REG32(INT_INFO2, 0x30)
5057c49a6eSPeter Maydell     FIELD(INT_INFO2, HMASTER, 0, 16)
5157c49a6eSPeter Maydell     FIELD(INT_INFO2, HNONSEC, 16, 1)
5257c49a6eSPeter Maydell     FIELD(INT_INFO2, CFG_NS, 17, 1)
53344f4b15SPeter Maydell REG32(INT_SET, 0x34)
54cdb60998SPeter Maydell     FIELD(INT_SET, IRQ, 0, 1)
55344f4b15SPeter Maydell REG32(PIDR4, 0xfd0)
56344f4b15SPeter Maydell REG32(PIDR5, 0xfd4)
57344f4b15SPeter Maydell REG32(PIDR6, 0xfd8)
58344f4b15SPeter Maydell REG32(PIDR7, 0xfdc)
59344f4b15SPeter Maydell REG32(PIDR0, 0xfe0)
60344f4b15SPeter Maydell REG32(PIDR1, 0xfe4)
61344f4b15SPeter Maydell REG32(PIDR2, 0xfe8)
62344f4b15SPeter Maydell REG32(PIDR3, 0xfec)
63344f4b15SPeter Maydell REG32(CIDR0, 0xff0)
64344f4b15SPeter Maydell REG32(CIDR1, 0xff4)
65344f4b15SPeter Maydell REG32(CIDR2, 0xff8)
66344f4b15SPeter Maydell REG32(CIDR3, 0xffc)
67344f4b15SPeter Maydell 
68344f4b15SPeter Maydell static const uint8_t tz_mpc_idregs[] = {
69344f4b15SPeter Maydell     0x04, 0x00, 0x00, 0x00,
70344f4b15SPeter Maydell     0x60, 0xb8, 0x1b, 0x00,
71344f4b15SPeter Maydell     0x0d, 0xf0, 0x05, 0xb1,
72344f4b15SPeter Maydell };
73344f4b15SPeter Maydell 
tz_mpc_irq_update(TZMPC * s)74cdb60998SPeter Maydell static void tz_mpc_irq_update(TZMPC *s)
75cdb60998SPeter Maydell {
76cdb60998SPeter Maydell     qemu_set_irq(s->irq, s->int_stat && s->int_en);
77cdb60998SPeter Maydell }
78cdb60998SPeter Maydell 
tz_mpc_iommu_notify(TZMPC * s,uint32_t lutidx,uint32_t oldlut,uint32_t newlut)79dd29d068SPeter Maydell static void tz_mpc_iommu_notify(TZMPC *s, uint32_t lutidx,
80dd29d068SPeter Maydell                                 uint32_t oldlut, uint32_t newlut)
81dd29d068SPeter Maydell {
82dd29d068SPeter Maydell     /* Called when the LUT word at lutidx has changed from oldlut to newlut;
83dd29d068SPeter Maydell      * must call the IOMMU notifiers for the changed blocks.
84dd29d068SPeter Maydell      */
85*5039caf3SEugenio Pérez     IOMMUTLBEvent event = {
86*5039caf3SEugenio Pérez         .entry = {
87dd29d068SPeter Maydell             .addr_mask = s->blocksize - 1,
88*5039caf3SEugenio Pérez         }
89dd29d068SPeter Maydell     };
90dd29d068SPeter Maydell     hwaddr addr = lutidx * s->blocksize * 32;
91dd29d068SPeter Maydell     int i;
92dd29d068SPeter Maydell 
93dd29d068SPeter Maydell     for (i = 0; i < 32; i++, addr += s->blocksize) {
94dd29d068SPeter Maydell         bool block_is_ns;
95dd29d068SPeter Maydell 
96dd29d068SPeter Maydell         if (!((oldlut ^ newlut) & (1 << i))) {
97dd29d068SPeter Maydell             continue;
98dd29d068SPeter Maydell         }
99dd29d068SPeter Maydell         /* This changes the mappings for both the S and the NS space,
100dd29d068SPeter Maydell          * so we need to do four notifies: an UNMAP then a MAP for each.
101dd29d068SPeter Maydell          */
102dd29d068SPeter Maydell         block_is_ns = newlut & (1 << i);
103dd29d068SPeter Maydell 
104dd29d068SPeter Maydell         trace_tz_mpc_iommu_notify(addr);
105*5039caf3SEugenio Pérez         event.entry.iova = addr;
106*5039caf3SEugenio Pérez         event.entry.translated_addr = addr;
107dd29d068SPeter Maydell 
108*5039caf3SEugenio Pérez         event.type = IOMMU_NOTIFIER_UNMAP;
109*5039caf3SEugenio Pérez         event.entry.perm = IOMMU_NONE;
110*5039caf3SEugenio Pérez         memory_region_notify_iommu(&s->upstream, IOMMU_IDX_S, event);
111*5039caf3SEugenio Pérez         memory_region_notify_iommu(&s->upstream, IOMMU_IDX_NS, event);
112dd29d068SPeter Maydell 
113*5039caf3SEugenio Pérez         event.type = IOMMU_NOTIFIER_MAP;
114*5039caf3SEugenio Pérez         event.entry.perm = IOMMU_RW;
115dd29d068SPeter Maydell         if (block_is_ns) {
116*5039caf3SEugenio Pérez             event.entry.target_as = &s->blocked_io_as;
117dd29d068SPeter Maydell         } else {
118*5039caf3SEugenio Pérez             event.entry.target_as = &s->downstream_as;
119dd29d068SPeter Maydell         }
120*5039caf3SEugenio Pérez         memory_region_notify_iommu(&s->upstream, IOMMU_IDX_S, event);
121dd29d068SPeter Maydell         if (block_is_ns) {
122*5039caf3SEugenio Pérez             event.entry.target_as = &s->downstream_as;
123dd29d068SPeter Maydell         } else {
124*5039caf3SEugenio Pérez             event.entry.target_as = &s->blocked_io_as;
125dd29d068SPeter Maydell         }
126*5039caf3SEugenio Pérez         memory_region_notify_iommu(&s->upstream, IOMMU_IDX_NS, event);
127dd29d068SPeter Maydell     }
128dd29d068SPeter Maydell }
129dd29d068SPeter Maydell 
tz_mpc_autoinc_idx(TZMPC * s,unsigned access_size)130cdb60998SPeter Maydell static void tz_mpc_autoinc_idx(TZMPC *s, unsigned access_size)
131cdb60998SPeter Maydell {
132cdb60998SPeter Maydell     /* Auto-increment BLK_IDX if necessary */
133cdb60998SPeter Maydell     if (access_size == 4 && (s->ctrl & R_CTRL_AUTOINC_MASK)) {
134cdb60998SPeter Maydell         s->blk_idx++;
135cdb60998SPeter Maydell         s->blk_idx %= s->blk_max;
136cdb60998SPeter Maydell     }
137cdb60998SPeter Maydell }
138cdb60998SPeter Maydell 
tz_mpc_reg_read(void * opaque,hwaddr addr,uint64_t * pdata,unsigned size,MemTxAttrs attrs)139344f4b15SPeter Maydell static MemTxResult tz_mpc_reg_read(void *opaque, hwaddr addr,
140344f4b15SPeter Maydell                                    uint64_t *pdata,
141344f4b15SPeter Maydell                                    unsigned size, MemTxAttrs attrs)
142344f4b15SPeter Maydell {
143cdb60998SPeter Maydell     TZMPC *s = TZ_MPC(opaque);
144344f4b15SPeter Maydell     uint64_t r;
145344f4b15SPeter Maydell     uint32_t offset = addr & ~0x3;
146344f4b15SPeter Maydell 
147344f4b15SPeter Maydell     if (!attrs.secure && offset < A_PIDR4) {
148344f4b15SPeter Maydell         /* NS accesses can only see the ID registers */
149344f4b15SPeter Maydell         qemu_log_mask(LOG_GUEST_ERROR,
150344f4b15SPeter Maydell                       "TZ MPC register read: NS access to offset 0x%x\n",
151344f4b15SPeter Maydell                       offset);
152344f4b15SPeter Maydell         r = 0;
153344f4b15SPeter Maydell         goto read_out;
154344f4b15SPeter Maydell     }
155344f4b15SPeter Maydell 
156344f4b15SPeter Maydell     switch (offset) {
157cdb60998SPeter Maydell     case A_CTRL:
158cdb60998SPeter Maydell         r = s->ctrl;
159cdb60998SPeter Maydell         break;
160cdb60998SPeter Maydell     case A_BLK_MAX:
161619d54a8SPeter Maydell         r = s->blk_max - 1;
162cdb60998SPeter Maydell         break;
163cdb60998SPeter Maydell     case A_BLK_CFG:
164cdb60998SPeter Maydell         /* We are never in "init in progress state", so this just indicates
165cdb60998SPeter Maydell          * the block size. s->blocksize == (1 << BLK_CFG + 5), so
166cdb60998SPeter Maydell          * BLK_CFG == ctz32(s->blocksize) - 5
167cdb60998SPeter Maydell          */
168cdb60998SPeter Maydell         r = ctz32(s->blocksize) - 5;
169cdb60998SPeter Maydell         break;
170cdb60998SPeter Maydell     case A_BLK_IDX:
171cdb60998SPeter Maydell         r = s->blk_idx;
172cdb60998SPeter Maydell         break;
173cdb60998SPeter Maydell     case A_BLK_LUT:
174cdb60998SPeter Maydell         r = s->blk_lut[s->blk_idx];
175cdb60998SPeter Maydell         tz_mpc_autoinc_idx(s, size);
176cdb60998SPeter Maydell         break;
177cdb60998SPeter Maydell     case A_INT_STAT:
178cdb60998SPeter Maydell         r = s->int_stat;
179cdb60998SPeter Maydell         break;
180cdb60998SPeter Maydell     case A_INT_EN:
181cdb60998SPeter Maydell         r = s->int_en;
182cdb60998SPeter Maydell         break;
183cdb60998SPeter Maydell     case A_INT_INFO1:
184cdb60998SPeter Maydell         r = s->int_info1;
185cdb60998SPeter Maydell         break;
186cdb60998SPeter Maydell     case A_INT_INFO2:
187cdb60998SPeter Maydell         r = s->int_info2;
188cdb60998SPeter Maydell         break;
189344f4b15SPeter Maydell     case A_PIDR4:
190344f4b15SPeter Maydell     case A_PIDR5:
191344f4b15SPeter Maydell     case A_PIDR6:
192344f4b15SPeter Maydell     case A_PIDR7:
193344f4b15SPeter Maydell     case A_PIDR0:
194344f4b15SPeter Maydell     case A_PIDR1:
195344f4b15SPeter Maydell     case A_PIDR2:
196344f4b15SPeter Maydell     case A_PIDR3:
197344f4b15SPeter Maydell     case A_CIDR0:
198344f4b15SPeter Maydell     case A_CIDR1:
199344f4b15SPeter Maydell     case A_CIDR2:
200344f4b15SPeter Maydell     case A_CIDR3:
201344f4b15SPeter Maydell         r = tz_mpc_idregs[(offset - A_PIDR4) / 4];
202344f4b15SPeter Maydell         break;
203344f4b15SPeter Maydell     case A_INT_CLEAR:
204344f4b15SPeter Maydell     case A_INT_SET:
205344f4b15SPeter Maydell         qemu_log_mask(LOG_GUEST_ERROR,
206344f4b15SPeter Maydell                       "TZ MPC register read: write-only offset 0x%x\n",
207344f4b15SPeter Maydell                       offset);
208344f4b15SPeter Maydell         r = 0;
209344f4b15SPeter Maydell         break;
210344f4b15SPeter Maydell     default:
211344f4b15SPeter Maydell         qemu_log_mask(LOG_GUEST_ERROR,
212344f4b15SPeter Maydell                       "TZ MPC register read: bad offset 0x%x\n", offset);
213344f4b15SPeter Maydell         r = 0;
214344f4b15SPeter Maydell         break;
215344f4b15SPeter Maydell     }
216344f4b15SPeter Maydell 
217344f4b15SPeter Maydell     if (size != 4) {
218344f4b15SPeter Maydell         /* None of our registers are read-sensitive (except BLK_LUT,
219344f4b15SPeter Maydell          * which can special case the "size not 4" case), so just
220344f4b15SPeter Maydell          * pull the right bytes out of the word read result.
221344f4b15SPeter Maydell          */
222344f4b15SPeter Maydell         r = extract32(r, (addr & 3) * 8, size * 8);
223344f4b15SPeter Maydell     }
224344f4b15SPeter Maydell 
225344f4b15SPeter Maydell read_out:
226344f4b15SPeter Maydell     trace_tz_mpc_reg_read(addr, r, size);
227344f4b15SPeter Maydell     *pdata = r;
228344f4b15SPeter Maydell     return MEMTX_OK;
229344f4b15SPeter Maydell }
230344f4b15SPeter Maydell 
tz_mpc_reg_write(void * opaque,hwaddr addr,uint64_t value,unsigned size,MemTxAttrs attrs)231344f4b15SPeter Maydell static MemTxResult tz_mpc_reg_write(void *opaque, hwaddr addr,
232344f4b15SPeter Maydell                                     uint64_t value,
233344f4b15SPeter Maydell                                     unsigned size, MemTxAttrs attrs)
234344f4b15SPeter Maydell {
235cdb60998SPeter Maydell     TZMPC *s = TZ_MPC(opaque);
236344f4b15SPeter Maydell     uint32_t offset = addr & ~0x3;
237344f4b15SPeter Maydell 
238344f4b15SPeter Maydell     trace_tz_mpc_reg_write(addr, value, size);
239344f4b15SPeter Maydell 
240344f4b15SPeter Maydell     if (!attrs.secure && offset < A_PIDR4) {
241344f4b15SPeter Maydell         /* NS accesses can only see the ID registers */
242344f4b15SPeter Maydell         qemu_log_mask(LOG_GUEST_ERROR,
243344f4b15SPeter Maydell                       "TZ MPC register write: NS access to offset 0x%x\n",
244344f4b15SPeter Maydell                       offset);
245344f4b15SPeter Maydell         return MEMTX_OK;
246344f4b15SPeter Maydell     }
247344f4b15SPeter Maydell 
248344f4b15SPeter Maydell     if (size != 4) {
249344f4b15SPeter Maydell         /* Expand the byte or halfword write to a full word size.
250344f4b15SPeter Maydell          * In most cases we can do this with zeroes; the exceptions
251344f4b15SPeter Maydell          * are CTRL, BLK_IDX and BLK_LUT.
252344f4b15SPeter Maydell          */
253344f4b15SPeter Maydell         uint32_t oldval;
254344f4b15SPeter Maydell 
255344f4b15SPeter Maydell         switch (offset) {
256cdb60998SPeter Maydell         case A_CTRL:
257cdb60998SPeter Maydell             oldval = s->ctrl;
258cdb60998SPeter Maydell             break;
259cdb60998SPeter Maydell         case A_BLK_IDX:
260cdb60998SPeter Maydell             oldval = s->blk_idx;
261cdb60998SPeter Maydell             break;
262cdb60998SPeter Maydell         case A_BLK_LUT:
263cdb60998SPeter Maydell             oldval = s->blk_lut[s->blk_idx];
264cdb60998SPeter Maydell             break;
265344f4b15SPeter Maydell         default:
266344f4b15SPeter Maydell             oldval = 0;
267344f4b15SPeter Maydell             break;
268344f4b15SPeter Maydell         }
269344f4b15SPeter Maydell         value = deposit32(oldval, (addr & 3) * 8, size * 8, value);
270344f4b15SPeter Maydell     }
271344f4b15SPeter Maydell 
272cdb60998SPeter Maydell     if ((s->ctrl & R_CTRL_LOCKDOWN_MASK) &&
273cdb60998SPeter Maydell         (offset == A_CTRL || offset == A_BLK_LUT || offset == A_INT_EN)) {
274cdb60998SPeter Maydell         /* Lockdown mode makes these three registers read-only, and
275cdb60998SPeter Maydell          * the only way out of it is to reset the device.
276cdb60998SPeter Maydell          */
277cdb60998SPeter Maydell         qemu_log_mask(LOG_GUEST_ERROR, "TZ MPC register write to offset 0x%x "
278cdb60998SPeter Maydell                       "while MPC is in lockdown mode\n", offset);
279cdb60998SPeter Maydell         return MEMTX_OK;
280cdb60998SPeter Maydell     }
281cdb60998SPeter Maydell 
282344f4b15SPeter Maydell     switch (offset) {
283cdb60998SPeter Maydell     case A_CTRL:
284cdb60998SPeter Maydell         /* We don't implement the 'data gating' feature so all other bits
285cdb60998SPeter Maydell          * are reserved and we make them RAZ/WI.
286cdb60998SPeter Maydell          */
287cdb60998SPeter Maydell         s->ctrl = value & (R_CTRL_SEC_RESP_MASK |
288cdb60998SPeter Maydell                            R_CTRL_AUTOINC_MASK |
289cdb60998SPeter Maydell                            R_CTRL_LOCKDOWN_MASK);
290cdb60998SPeter Maydell         break;
291cdb60998SPeter Maydell     case A_BLK_IDX:
292cdb60998SPeter Maydell         s->blk_idx = value % s->blk_max;
293cdb60998SPeter Maydell         break;
294cdb60998SPeter Maydell     case A_BLK_LUT:
295dd29d068SPeter Maydell         tz_mpc_iommu_notify(s, s->blk_idx, s->blk_lut[s->blk_idx], value);
296cdb60998SPeter Maydell         s->blk_lut[s->blk_idx] = value;
297cdb60998SPeter Maydell         tz_mpc_autoinc_idx(s, size);
298cdb60998SPeter Maydell         break;
299cdb60998SPeter Maydell     case A_INT_CLEAR:
300cdb60998SPeter Maydell         if (value & R_INT_CLEAR_IRQ_MASK) {
301cdb60998SPeter Maydell             s->int_stat = 0;
302cdb60998SPeter Maydell             tz_mpc_irq_update(s);
303cdb60998SPeter Maydell         }
304cdb60998SPeter Maydell         break;
305cdb60998SPeter Maydell     case A_INT_EN:
306cdb60998SPeter Maydell         s->int_en = value & R_INT_EN_IRQ_MASK;
307cdb60998SPeter Maydell         tz_mpc_irq_update(s);
308cdb60998SPeter Maydell         break;
309cdb60998SPeter Maydell     case A_INT_SET:
310cdb60998SPeter Maydell         if (value & R_INT_SET_IRQ_MASK) {
311cdb60998SPeter Maydell             s->int_stat = R_INT_STAT_IRQ_MASK;
312cdb60998SPeter Maydell             tz_mpc_irq_update(s);
313cdb60998SPeter Maydell         }
314cdb60998SPeter Maydell         break;
315344f4b15SPeter Maydell     case A_PIDR4:
316344f4b15SPeter Maydell     case A_PIDR5:
317344f4b15SPeter Maydell     case A_PIDR6:
318344f4b15SPeter Maydell     case A_PIDR7:
319344f4b15SPeter Maydell     case A_PIDR0:
320344f4b15SPeter Maydell     case A_PIDR1:
321344f4b15SPeter Maydell     case A_PIDR2:
322344f4b15SPeter Maydell     case A_PIDR3:
323344f4b15SPeter Maydell     case A_CIDR0:
324344f4b15SPeter Maydell     case A_CIDR1:
325344f4b15SPeter Maydell     case A_CIDR2:
326344f4b15SPeter Maydell     case A_CIDR3:
327344f4b15SPeter Maydell         qemu_log_mask(LOG_GUEST_ERROR,
328344f4b15SPeter Maydell                       "TZ MPC register write: read-only offset 0x%x\n", offset);
329344f4b15SPeter Maydell         break;
330344f4b15SPeter Maydell     default:
331344f4b15SPeter Maydell         qemu_log_mask(LOG_GUEST_ERROR,
332344f4b15SPeter Maydell                       "TZ MPC register write: bad offset 0x%x\n", offset);
333344f4b15SPeter Maydell         break;
334344f4b15SPeter Maydell     }
335344f4b15SPeter Maydell 
336344f4b15SPeter Maydell     return MEMTX_OK;
337344f4b15SPeter Maydell }
338344f4b15SPeter Maydell 
339344f4b15SPeter Maydell static const MemoryRegionOps tz_mpc_reg_ops = {
340344f4b15SPeter Maydell     .read_with_attrs = tz_mpc_reg_read,
341344f4b15SPeter Maydell     .write_with_attrs = tz_mpc_reg_write,
342344f4b15SPeter Maydell     .endianness = DEVICE_LITTLE_ENDIAN,
343344f4b15SPeter Maydell     .valid.min_access_size = 1,
344344f4b15SPeter Maydell     .valid.max_access_size = 4,
345344f4b15SPeter Maydell     .impl.min_access_size = 1,
346344f4b15SPeter Maydell     .impl.max_access_size = 4,
347344f4b15SPeter Maydell };
348344f4b15SPeter Maydell 
tz_mpc_cfg_ns(TZMPC * s,hwaddr addr)34957c49a6eSPeter Maydell static inline bool tz_mpc_cfg_ns(TZMPC *s, hwaddr addr)
35057c49a6eSPeter Maydell {
35157c49a6eSPeter Maydell     /* Return the cfg_ns bit from the LUT for the specified address */
35257c49a6eSPeter Maydell     hwaddr blknum = addr / s->blocksize;
35357c49a6eSPeter Maydell     hwaddr blkword = blknum / 32;
35457c49a6eSPeter Maydell     uint32_t blkbit = 1U << (blknum % 32);
35557c49a6eSPeter Maydell 
35657c49a6eSPeter Maydell     /* This would imply the address was larger than the size we
35757c49a6eSPeter Maydell      * defined this memory region to be, so it can't happen.
35857c49a6eSPeter Maydell      */
35957c49a6eSPeter Maydell     assert(blkword < s->blk_max);
36057c49a6eSPeter Maydell     return s->blk_lut[blkword] & blkbit;
36157c49a6eSPeter Maydell }
36257c49a6eSPeter Maydell 
tz_mpc_handle_block(TZMPC * s,hwaddr addr,MemTxAttrs attrs)36357c49a6eSPeter Maydell static MemTxResult tz_mpc_handle_block(TZMPC *s, hwaddr addr, MemTxAttrs attrs)
36457c49a6eSPeter Maydell {
36557c49a6eSPeter Maydell     /* Handle a blocked transaction: raise IRQ, capture info, etc */
36657c49a6eSPeter Maydell     if (!s->int_stat) {
36757c49a6eSPeter Maydell         /* First blocked transfer: capture information into INT_INFO1 and
36857c49a6eSPeter Maydell          * INT_INFO2. Subsequent transfers are still blocked but don't
36957c49a6eSPeter Maydell          * capture information until the guest clears the interrupt.
37057c49a6eSPeter Maydell          */
37157c49a6eSPeter Maydell 
37257c49a6eSPeter Maydell         s->int_info1 = addr;
37357c49a6eSPeter Maydell         s->int_info2 = 0;
37457c49a6eSPeter Maydell         s->int_info2 = FIELD_DP32(s->int_info2, INT_INFO2, HMASTER,
37557c49a6eSPeter Maydell                                   attrs.requester_id & 0xffff);
37657c49a6eSPeter Maydell         s->int_info2 = FIELD_DP32(s->int_info2, INT_INFO2, HNONSEC,
37757c49a6eSPeter Maydell                                   ~attrs.secure);
37857c49a6eSPeter Maydell         s->int_info2 = FIELD_DP32(s->int_info2, INT_INFO2, CFG_NS,
37957c49a6eSPeter Maydell                                   tz_mpc_cfg_ns(s, addr));
38057c49a6eSPeter Maydell         s->int_stat |= R_INT_STAT_IRQ_MASK;
38157c49a6eSPeter Maydell         tz_mpc_irq_update(s);
38257c49a6eSPeter Maydell     }
38357c49a6eSPeter Maydell 
38457c49a6eSPeter Maydell     /* Generate bus error if desired; otherwise RAZ/WI */
38557c49a6eSPeter Maydell     return (s->ctrl & R_CTRL_SEC_RESP_MASK) ? MEMTX_ERROR : MEMTX_OK;
38657c49a6eSPeter Maydell }
38757c49a6eSPeter Maydell 
388344f4b15SPeter Maydell /* Accesses only reach these read and write functions if the MPC is
389344f4b15SPeter Maydell  * blocking them; non-blocked accesses go directly to the downstream
390344f4b15SPeter Maydell  * memory region without passing through this code.
391344f4b15SPeter Maydell  */
tz_mpc_mem_blocked_read(void * opaque,hwaddr addr,uint64_t * pdata,unsigned size,MemTxAttrs attrs)392344f4b15SPeter Maydell static MemTxResult tz_mpc_mem_blocked_read(void *opaque, hwaddr addr,
393344f4b15SPeter Maydell                                            uint64_t *pdata,
394344f4b15SPeter Maydell                                            unsigned size, MemTxAttrs attrs)
395344f4b15SPeter Maydell {
39657c49a6eSPeter Maydell     TZMPC *s = TZ_MPC(opaque);
39757c49a6eSPeter Maydell 
398344f4b15SPeter Maydell     trace_tz_mpc_mem_blocked_read(addr, size, attrs.secure);
399344f4b15SPeter Maydell 
400344f4b15SPeter Maydell     *pdata = 0;
40157c49a6eSPeter Maydell     return tz_mpc_handle_block(s, addr, attrs);
402344f4b15SPeter Maydell }
403344f4b15SPeter Maydell 
tz_mpc_mem_blocked_write(void * opaque,hwaddr addr,uint64_t value,unsigned size,MemTxAttrs attrs)404344f4b15SPeter Maydell static MemTxResult tz_mpc_mem_blocked_write(void *opaque, hwaddr addr,
405344f4b15SPeter Maydell                                             uint64_t value,
406344f4b15SPeter Maydell                                             unsigned size, MemTxAttrs attrs)
407344f4b15SPeter Maydell {
40857c49a6eSPeter Maydell     TZMPC *s = TZ_MPC(opaque);
40957c49a6eSPeter Maydell 
410344f4b15SPeter Maydell     trace_tz_mpc_mem_blocked_write(addr, value, size, attrs.secure);
411344f4b15SPeter Maydell 
41257c49a6eSPeter Maydell     return tz_mpc_handle_block(s, addr, attrs);
413344f4b15SPeter Maydell }
414344f4b15SPeter Maydell 
415344f4b15SPeter Maydell static const MemoryRegionOps tz_mpc_mem_blocked_ops = {
416344f4b15SPeter Maydell     .read_with_attrs = tz_mpc_mem_blocked_read,
417344f4b15SPeter Maydell     .write_with_attrs = tz_mpc_mem_blocked_write,
418344f4b15SPeter Maydell     .endianness = DEVICE_LITTLE_ENDIAN,
419344f4b15SPeter Maydell     .valid.min_access_size = 1,
420344f4b15SPeter Maydell     .valid.max_access_size = 8,
421344f4b15SPeter Maydell     .impl.min_access_size = 1,
422344f4b15SPeter Maydell     .impl.max_access_size = 8,
423344f4b15SPeter Maydell };
424344f4b15SPeter Maydell 
tz_mpc_translate(IOMMUMemoryRegion * iommu,hwaddr addr,IOMMUAccessFlags flags,int iommu_idx)425344f4b15SPeter Maydell static IOMMUTLBEntry tz_mpc_translate(IOMMUMemoryRegion *iommu,
426344f4b15SPeter Maydell                                       hwaddr addr, IOMMUAccessFlags flags,
427344f4b15SPeter Maydell                                       int iommu_idx)
428344f4b15SPeter Maydell {
429344f4b15SPeter Maydell     TZMPC *s = TZ_MPC(container_of(iommu, TZMPC, upstream));
430344f4b15SPeter Maydell     bool ok;
431344f4b15SPeter Maydell 
432344f4b15SPeter Maydell     IOMMUTLBEntry ret = {
433344f4b15SPeter Maydell         .iova = addr & ~(s->blocksize - 1),
434344f4b15SPeter Maydell         .translated_addr = addr & ~(s->blocksize - 1),
435344f4b15SPeter Maydell         .addr_mask = s->blocksize - 1,
436344f4b15SPeter Maydell         .perm = IOMMU_RW,
437344f4b15SPeter Maydell     };
438344f4b15SPeter Maydell 
439344f4b15SPeter Maydell     /* Look at the per-block configuration for this address, and
440344f4b15SPeter Maydell      * return a TLB entry directing the transaction at either
441344f4b15SPeter Maydell      * downstream_as or blocked_io_as, as appropriate.
442dd29d068SPeter Maydell      * If the LUT cfg_ns bit is 1, only non-secure transactions
443dd29d068SPeter Maydell      * may pass. If the bit is 0, only secure transactions may pass.
444344f4b15SPeter Maydell      */
445dd29d068SPeter Maydell     ok = tz_mpc_cfg_ns(s, addr) == (iommu_idx == IOMMU_IDX_NS);
446344f4b15SPeter Maydell 
447344f4b15SPeter Maydell     trace_tz_mpc_translate(addr, flags,
448344f4b15SPeter Maydell                            iommu_idx == IOMMU_IDX_S ? "S" : "NS",
449344f4b15SPeter Maydell                            ok ? "pass" : "block");
450344f4b15SPeter Maydell 
451344f4b15SPeter Maydell     ret.target_as = ok ? &s->downstream_as : &s->blocked_io_as;
452344f4b15SPeter Maydell     return ret;
453344f4b15SPeter Maydell }
454344f4b15SPeter Maydell 
tz_mpc_attrs_to_index(IOMMUMemoryRegion * iommu,MemTxAttrs attrs)455344f4b15SPeter Maydell static int tz_mpc_attrs_to_index(IOMMUMemoryRegion *iommu, MemTxAttrs attrs)
456344f4b15SPeter Maydell {
457344f4b15SPeter Maydell     /* We treat unspecified attributes like secure. Transactions with
458344f4b15SPeter Maydell      * unspecified attributes come from places like
4593c8133f9SPeter Maydell      * rom_reset() for initial image load, and we want
460344f4b15SPeter Maydell      * those to pass through the from-reset "everything is secure" config.
461344f4b15SPeter Maydell      * All the real during-emulation transactions from the CPU will
462344f4b15SPeter Maydell      * specify attributes.
463344f4b15SPeter Maydell      */
464344f4b15SPeter Maydell     return (attrs.unspecified || attrs.secure) ? IOMMU_IDX_S : IOMMU_IDX_NS;
465344f4b15SPeter Maydell }
466344f4b15SPeter Maydell 
tz_mpc_num_indexes(IOMMUMemoryRegion * iommu)467344f4b15SPeter Maydell static int tz_mpc_num_indexes(IOMMUMemoryRegion *iommu)
468344f4b15SPeter Maydell {
469344f4b15SPeter Maydell     return IOMMU_NUM_INDEXES;
470344f4b15SPeter Maydell }
471344f4b15SPeter Maydell 
tz_mpc_reset(DeviceState * dev)472344f4b15SPeter Maydell static void tz_mpc_reset(DeviceState *dev)
473344f4b15SPeter Maydell {
474cdb60998SPeter Maydell     TZMPC *s = TZ_MPC(dev);
475cdb60998SPeter Maydell 
476cdb60998SPeter Maydell     s->ctrl = 0x00000100;
477cdb60998SPeter Maydell     s->blk_idx = 0;
478cdb60998SPeter Maydell     s->int_stat = 0;
479cdb60998SPeter Maydell     s->int_en = 1;
480cdb60998SPeter Maydell     s->int_info1 = 0;
481cdb60998SPeter Maydell     s->int_info2 = 0;
482cdb60998SPeter Maydell 
483cdb60998SPeter Maydell     memset(s->blk_lut, 0, s->blk_max * sizeof(uint32_t));
484344f4b15SPeter Maydell }
485344f4b15SPeter Maydell 
tz_mpc_init(Object * obj)486344f4b15SPeter Maydell static void tz_mpc_init(Object *obj)
487344f4b15SPeter Maydell {
488344f4b15SPeter Maydell     DeviceState *dev = DEVICE(obj);
489344f4b15SPeter Maydell     TZMPC *s = TZ_MPC(obj);
490344f4b15SPeter Maydell 
491344f4b15SPeter Maydell     qdev_init_gpio_out_named(dev, &s->irq, "irq", 1);
492344f4b15SPeter Maydell }
493344f4b15SPeter Maydell 
tz_mpc_realize(DeviceState * dev,Error ** errp)494344f4b15SPeter Maydell static void tz_mpc_realize(DeviceState *dev, Error **errp)
495344f4b15SPeter Maydell {
496344f4b15SPeter Maydell     Object *obj = OBJECT(dev);
497344f4b15SPeter Maydell     SysBusDevice *sbd = SYS_BUS_DEVICE(dev);
498344f4b15SPeter Maydell     TZMPC *s = TZ_MPC(dev);
499344f4b15SPeter Maydell     uint64_t size;
500344f4b15SPeter Maydell 
501344f4b15SPeter Maydell     /* We can't create the upstream end of the port until realize,
502344f4b15SPeter Maydell      * as we don't know the size of the MR used as the downstream until then.
503344f4b15SPeter Maydell      * We insist on having a downstream, to avoid complicating the code
504344f4b15SPeter Maydell      * with handling the "don't know how big this is" case. It's easy
505344f4b15SPeter Maydell      * enough for the user to create an unimplemented_device as downstream
506344f4b15SPeter Maydell      * if they have nothing else to plug into this.
507344f4b15SPeter Maydell      */
508344f4b15SPeter Maydell     if (!s->downstream) {
509344f4b15SPeter Maydell         error_setg(errp, "MPC 'downstream' link not set");
510344f4b15SPeter Maydell         return;
511344f4b15SPeter Maydell     }
512344f4b15SPeter Maydell 
513344f4b15SPeter Maydell     size = memory_region_size(s->downstream);
514344f4b15SPeter Maydell 
515344f4b15SPeter Maydell     memory_region_init_iommu(&s->upstream, sizeof(s->upstream),
516344f4b15SPeter Maydell                              TYPE_TZ_MPC_IOMMU_MEMORY_REGION,
517344f4b15SPeter Maydell                              obj, "tz-mpc-upstream", size);
518344f4b15SPeter Maydell 
519344f4b15SPeter Maydell     /* In real hardware the block size is configurable. In QEMU we could
520344f4b15SPeter Maydell      * make it configurable but will need it to be at least as big as the
521344f4b15SPeter Maydell      * target page size so we can execute out of the resulting MRs. Guest
522344f4b15SPeter Maydell      * software is supposed to check the block size using the BLK_CFG
523344f4b15SPeter Maydell      * register, so make it fixed at the page size.
524344f4b15SPeter Maydell      */
525344f4b15SPeter Maydell     s->blocksize = memory_region_iommu_get_min_page_size(&s->upstream);
526344f4b15SPeter Maydell     if (size % s->blocksize != 0) {
527344f4b15SPeter Maydell         error_setg(errp,
528344f4b15SPeter Maydell                    "MPC 'downstream' size %" PRId64
529344f4b15SPeter Maydell                    " is not a multiple of %" HWADDR_PRIx " bytes",
530344f4b15SPeter Maydell                    size, s->blocksize);
531344f4b15SPeter Maydell         object_unref(OBJECT(&s->upstream));
532344f4b15SPeter Maydell         return;
533344f4b15SPeter Maydell     }
534344f4b15SPeter Maydell 
535344f4b15SPeter Maydell     /* BLK_MAX is the max value of BLK_IDX, which indexes an array of 32-bit
536344f4b15SPeter Maydell      * words, each bit of which indicates one block.
537344f4b15SPeter Maydell      */
538344f4b15SPeter Maydell     s->blk_max = DIV_ROUND_UP(size / s->blocksize, 32);
539344f4b15SPeter Maydell 
540344f4b15SPeter Maydell     memory_region_init_io(&s->regmr, obj, &tz_mpc_reg_ops,
541344f4b15SPeter Maydell                           s, "tz-mpc-regs", 0x1000);
542344f4b15SPeter Maydell     sysbus_init_mmio(sbd, &s->regmr);
543344f4b15SPeter Maydell 
544344f4b15SPeter Maydell     sysbus_init_mmio(sbd, MEMORY_REGION(&s->upstream));
545344f4b15SPeter Maydell 
546344f4b15SPeter Maydell     /* This memory region is not exposed to users of this device as a
547344f4b15SPeter Maydell      * sysbus MMIO region, but is instead used internally as something
548344f4b15SPeter Maydell      * that our IOMMU translate function might direct accesses to.
549344f4b15SPeter Maydell      */
550344f4b15SPeter Maydell     memory_region_init_io(&s->blocked_io, obj, &tz_mpc_mem_blocked_ops,
551344f4b15SPeter Maydell                           s, "tz-mpc-blocked-io", size);
552344f4b15SPeter Maydell 
553344f4b15SPeter Maydell     address_space_init(&s->downstream_as, s->downstream,
554344f4b15SPeter Maydell                        "tz-mpc-downstream");
555344f4b15SPeter Maydell     address_space_init(&s->blocked_io_as, &s->blocked_io,
556344f4b15SPeter Maydell                        "tz-mpc-blocked-io");
557cdb60998SPeter Maydell 
558218fe5ceSPeter Maydell     s->blk_lut = g_new0(uint32_t, s->blk_max);
559cdb60998SPeter Maydell }
560cdb60998SPeter Maydell 
tz_mpc_post_load(void * opaque,int version_id)561cdb60998SPeter Maydell static int tz_mpc_post_load(void *opaque, int version_id)
562cdb60998SPeter Maydell {
563cdb60998SPeter Maydell     TZMPC *s = TZ_MPC(opaque);
564cdb60998SPeter Maydell 
565cdb60998SPeter Maydell     /* Check the incoming data doesn't point blk_idx off the end of blk_lut. */
566cdb60998SPeter Maydell     if (s->blk_idx >= s->blk_max) {
567cdb60998SPeter Maydell         return -1;
568cdb60998SPeter Maydell     }
569cdb60998SPeter Maydell     return 0;
570344f4b15SPeter Maydell }
571344f4b15SPeter Maydell 
572344f4b15SPeter Maydell static const VMStateDescription tz_mpc_vmstate = {
573344f4b15SPeter Maydell     .name = "tz-mpc",
574344f4b15SPeter Maydell     .version_id = 1,
575344f4b15SPeter Maydell     .minimum_version_id = 1,
576cdb60998SPeter Maydell     .post_load = tz_mpc_post_load,
577344f4b15SPeter Maydell     .fields = (VMStateField[]) {
578cdb60998SPeter Maydell         VMSTATE_UINT32(ctrl, TZMPC),
579cdb60998SPeter Maydell         VMSTATE_UINT32(blk_idx, TZMPC),
580cdb60998SPeter Maydell         VMSTATE_UINT32(int_stat, TZMPC),
581cdb60998SPeter Maydell         VMSTATE_UINT32(int_en, TZMPC),
582cdb60998SPeter Maydell         VMSTATE_UINT32(int_info1, TZMPC),
583cdb60998SPeter Maydell         VMSTATE_UINT32(int_info2, TZMPC),
584cdb60998SPeter Maydell         VMSTATE_VARRAY_UINT32(blk_lut, TZMPC, blk_max,
585cdb60998SPeter Maydell                               0, vmstate_info_uint32, uint32_t),
586344f4b15SPeter Maydell         VMSTATE_END_OF_LIST()
587344f4b15SPeter Maydell     }
588344f4b15SPeter Maydell };
589344f4b15SPeter Maydell 
590344f4b15SPeter Maydell static Property tz_mpc_properties[] = {
591344f4b15SPeter Maydell     DEFINE_PROP_LINK("downstream", TZMPC, downstream,
592344f4b15SPeter Maydell                      TYPE_MEMORY_REGION, MemoryRegion *),
593344f4b15SPeter Maydell     DEFINE_PROP_END_OF_LIST(),
594344f4b15SPeter Maydell };
595344f4b15SPeter Maydell 
tz_mpc_class_init(ObjectClass * klass,void * data)596344f4b15SPeter Maydell static void tz_mpc_class_init(ObjectClass *klass, void *data)
597344f4b15SPeter Maydell {
598344f4b15SPeter Maydell     DeviceClass *dc = DEVICE_CLASS(klass);
599344f4b15SPeter Maydell 
600344f4b15SPeter Maydell     dc->realize = tz_mpc_realize;
601344f4b15SPeter Maydell     dc->vmsd = &tz_mpc_vmstate;
602344f4b15SPeter Maydell     dc->reset = tz_mpc_reset;
6034f67d30bSMarc-André Lureau     device_class_set_props(dc, tz_mpc_properties);
604344f4b15SPeter Maydell }
605344f4b15SPeter Maydell 
606344f4b15SPeter Maydell static const TypeInfo tz_mpc_info = {
607344f4b15SPeter Maydell     .name = TYPE_TZ_MPC,
608344f4b15SPeter Maydell     .parent = TYPE_SYS_BUS_DEVICE,
609344f4b15SPeter Maydell     .instance_size = sizeof(TZMPC),
610344f4b15SPeter Maydell     .instance_init = tz_mpc_init,
611344f4b15SPeter Maydell     .class_init = tz_mpc_class_init,
612344f4b15SPeter Maydell };
613344f4b15SPeter Maydell 
tz_mpc_iommu_memory_region_class_init(ObjectClass * klass,void * data)614344f4b15SPeter Maydell static void tz_mpc_iommu_memory_region_class_init(ObjectClass *klass,
615344f4b15SPeter Maydell                                                   void *data)
616344f4b15SPeter Maydell {
617344f4b15SPeter Maydell     IOMMUMemoryRegionClass *imrc = IOMMU_MEMORY_REGION_CLASS(klass);
618344f4b15SPeter Maydell 
619344f4b15SPeter Maydell     imrc->translate = tz_mpc_translate;
620344f4b15SPeter Maydell     imrc->attrs_to_index = tz_mpc_attrs_to_index;
621344f4b15SPeter Maydell     imrc->num_indexes = tz_mpc_num_indexes;
622344f4b15SPeter Maydell }
623344f4b15SPeter Maydell 
624344f4b15SPeter Maydell static const TypeInfo tz_mpc_iommu_memory_region_info = {
625344f4b15SPeter Maydell     .name = TYPE_TZ_MPC_IOMMU_MEMORY_REGION,
626344f4b15SPeter Maydell     .parent = TYPE_IOMMU_MEMORY_REGION,
627344f4b15SPeter Maydell     .class_init = tz_mpc_iommu_memory_region_class_init,
628344f4b15SPeter Maydell };
629344f4b15SPeter Maydell 
tz_mpc_register_types(void)630344f4b15SPeter Maydell static void tz_mpc_register_types(void)
631344f4b15SPeter Maydell {
632344f4b15SPeter Maydell     type_register_static(&tz_mpc_info);
633344f4b15SPeter Maydell     type_register_static(&tz_mpc_iommu_memory_region_info);
634344f4b15SPeter Maydell }
635344f4b15SPeter Maydell 
636344f4b15SPeter Maydell type_init(tz_mpc_register_types);
637