1 /*
2  * Copyright (c) 2019-2021, Arm Limited. All rights reserved.
3  *
4  * SPDX-License-Identifier: BSD-3-Clause
5  *
6  */
7 
8 #include <stdint.h>
9 #include "firewall.h"
10 
11 #define FIREWALL_COMPONENT_SIZE      (0x10000)
12 #define FIREWALL_MAX_COMPONENTS      (0x20)
13 
14 #define FIREWALL_COMMON_REG_OFFSET   (0xFA0)
15 struct _firewall_common_reg_map_t {
16     volatile uint32_t fc_cap0;
17          /*!< Offset: 0xFA0 (R/ ) Firewall Component Capability Register 0 */
18     volatile uint32_t fc_cap1;
19          /*!< Offset: 0xFA4 (R/ ) Firewall Component Capability Register 1 */
20     volatile uint32_t fc_cap2;
21          /*!< Offset: 0xFA8 (R/ ) Firewall Component Capability Register 2 */
22     volatile uint32_t fc_cap3;
23          /*!< Offset: 0xFAC (R/ ) Firewall Component Capability Register 3 */
24     volatile uint32_t fc_cfg0;
25          /*!< Offset: 0xFB0 (R/ ) Firewall Component Configuration Register 0 */
26     volatile uint32_t fc_cfg1;
27          /*!< Offset: 0xFB4 (R/ ) Firewall Component Configuration Register 1 */
28     volatile uint32_t fc_cfg2;
29          /*!< Offset: 0xFB8 (R/ ) Firewall Component Configuration Register 2 */
30     volatile uint32_t fc_cfg3;
31          /*!< Offset: 0xFBC (R/ ) Firewall Component Configuration Register 3 */
32 };
33 
34 #define FIREWALL_PE_CS_REG_OFFSET    (0x100)
35                       /*!< Protection Control and Status register type offset */
36 struct _firewall_pe_cs_reg_map_t {
37     volatile uint32_t pe_ctrl;
38                        /*!< Offset: 0x100 (R/W) Protection Extenstion Control */
39     volatile uint32_t pe_st;
40                        /*!< Offset: 0x104 (R/ ) Protection Extenstion Status */
41     volatile uint32_t pe_bps;
42                        /*!< Offset: 0x108 (R/W) Protection Extenstion Bypass */
43 };
44 #define PE_CTRL_EN_MASK              (0x1u  << PE_CTRL_EN_OFF)
45 #define PE_CTRL_EN_BYPASS_MASK       (0x1u  << PE_CTRL_EN_BYPASS_OFF)
46 #define PE_ST_EN_MASK                (0x1u  << PE_ST_EN_OFF)
47 #define PE_BPS_BYPASS_ST_MASK        (0x1u  << PE_BPS_BYPASS_ST_OFF)
48 
49 #define FIREWALL_PE_RWE_REG_OFFSET   (0x10C)
50                       /*!< Region Window Entry (RWE) register type offset */
51 struct _firewall_pe_rwe_reg_map_t {
52     volatile uint32_t rwe_ctrl;
53                      /*!< Offset: 0x10C (R/W) Region Window Entry Control */
54     volatile uint32_t rgn_ctrl0;
55                      /*!< Offset: 0x110 (R/W) Region Control 0 */
56     volatile uint32_t rgn_ctrl1;
57                      /*!< Offset: 0x114 (R/W) Region Control 1 */
58     volatile uint32_t rgn_lctrl;
59                      /*!< Offset: 0x118 (R/W) Region Lock Control */
60     volatile uint32_t rgn_st;
61                      /*!< Offset: 0x11C (R/ ) Region Status */
62     volatile uint32_t rgn_cfg0;
63                      /*!< Offset: 0x120 (R/W) Region Config 0 */
64     volatile uint32_t rgn_cfg1;
65                      /*!< Offset: 0x124 (R/W) Region Config 1 */
66     volatile uint32_t rgn_size;
67                      /*!< Offset: 0x128 (R/W) Region Size */
68     volatile uint32_t reserved_0;
69                      /*!< Offset: 0x12C       Reserved */
70     volatile uint32_t rgn_tcfg0;
71                      /*!< Offset: 0x130 (R/W) Region Translation Config 0 */
72     volatile uint32_t rgn_tcfg1;
73                      /*!< Offset: 0x134 (R/W) Region Translation Config 1 */
74     volatile uint32_t rgn_tcfg2;
75                      /*!< Offset: 0x138 (R/W) Region Translation Config 2 */
76     volatile uint32_t reserved_1;
77                      /*!< Offset: 0x13C       Reserved */
78     volatile uint32_t rgn_mid0;
79                      /*!< Offset: 0x140 (R/W) Region Master ID 0 */
80     volatile uint32_t rgn_mpl0;
81                      /*!< Offset: 0x144 (R/W) Region Master Permission List 0 */
82     volatile uint32_t rgn_mid1;
83                      /*!< Offset: 0x148 (R/W) Region Master ID 1 */
84     volatile uint32_t rgn_mpl1;
85                      /*!< Offset: 0x14C (R/W) Region Master Permission List 1 */
86     volatile uint32_t rgn_mid2;
87                      /*!< Offset: 0x150 (R/W) Region Master ID 2 */
88     volatile uint32_t rgn_mpl2;
89                      /*!< Offset: 0x154 (R/W) Region Master Permission List 2 */
90     volatile uint32_t rgn_mid3;
91                      /*!< Offset: 0x158 (R/W) Region Master ID 3 */
92     volatile uint32_t rgn_mpl3;
93                      /*!< Offset: 0x15C (R/W) Region Master Permission List 3 */
94 };
95 #define RWE_CTRL_RGN_INDX_MASK       (0xFFu   << RWE_CTRL_RGN_INDX_OFF)
96 #define RGN_CTRL0_EN_MASK            (0x1u    << RGN_EN_OFF)
97 #define RGN_LCTRL_LOCK_MASK          (0x1u    << RGN_LCTRL_LOCK_OFF)
98 #define RGN_CTRL1_MPE_EN_MASK        (0xFu    << RGN_MPE0_EN_OFF)
99 #define RGN_MPL_EN_MASK              (0x1FFFu)
100 #define RGN_ST_EN_MASK               (0x1u    << RGN_EN_OFF)
101 #define RGN_ST_MPE0_EN_MASK          (0x1u    << RGN_MPE0_EN_OFF)
102 #define RGN_ST_MPE1_EN_MASK          (0x1u    << RGN_MPE1_EN_OFF)
103 #define RGN_ST_MPE2_EN_MASK          (0x1u    << RGN_MPE2_EN_OFF)
104 #define RGN_ST_MPE3_EN_MASK          (0x1u    << RGN_MPE3_EN_OFF)
105 #define RGN_SIZE_SIZE_MASK           (0xFFu   << RGN_SIZE_SIZE_OFF)
106 #define RGN_SIZE_MULnPO2_MASK        (0x1u    << RGN_SIZE_MULnPO2_OFF)
107 #define RGN_TCFG2_ADDR_TRANS_EN_MASK (0x1u    << RGN_TCFG2_ADDR_TRANS_EN_OFF)
108 #define RGN_TCFG2_MA_TRANS_EN_MASK   (0x1u    << RGN_TCFG2_MA_TRANS_EN_OFF)
109 #define RGN_TCFG2_INST_MASK          (0x3u    << RGN_TCFG2_INST_OFF)
110 #define RGN_TCFG2_PRIV_MASK          (0x3u    << RGN_TCFG2_PRIV_OFF)
111 #define RGN_TCFG2_MA_MASK            (0xFFu   << RGN_TCFG2_MA_OFF)
112 #define RGN_TCFG2_SH_MASK            (0x3u    << RGN_TCFG2_SH_OFF)
113 #define RGN_TCFG2_NS_MASK            (0x3u    << RGN_TCFG2_NS_OFF)
114 
115 #define FIREWALL_PE_FWE_REG_OFFSET   (0x180)
116                       /*!< Fault Window Entry (FWE) register type offset */
117 struct _firewall_pe_fwe_reg_map_t {
118     volatile uint32_t fe_tal;
119                /*!< Offset: 0x180 (R/ ) Fault Entry Transaction Address Lower */
120     volatile uint32_t fe_tau;
121                /*!< Offset: 0x184 (R/ ) Fault Entry Transaction Address Upper */
122     volatile uint32_t fe_tp;
123                /*!< Offset: 0x188 (R/ ) Fault Entry Transaction Properties */
124     volatile uint32_t fe_mid;
125                /*!< Offset: 0x18C (R/ ) Fault Entry Master ID */
126     volatile uint32_t fe_ctrl;
127                /*!< Offset: 0x190 (R/W) Fault Entry Control */
128 };
129 
130 #define FIREWALL_LDE_REG_OFFSET      (0x10)
131                       /*!< Lockdown Extension (LDE) register type offset */
132 struct _firewall_lde_reg_map_t {
133     volatile uint32_t ld_ctrl;
134                /*!< Offset: 0x10 (R/W) Lockdown Control */
135 };
136 #define LD_CTRL_LOCK_MASK            (0x3u   << LD_CTRL_LOCK_OFF)
137 #define LD_CTRL_LDI_ST_MASK          (0x1u   << LD_CTRL_LDI_ST_OFF)
138 
139 #define CS_REG_ADDR(x, y)\
140                 (x + (y * FIREWALL_COMPONENT_SIZE) + FIREWALL_PE_CS_REG_OFFSET)
141 #define RWE_REG_ADDR(x, y)\
142                 (x + (y * FIREWALL_COMPONENT_SIZE) + FIREWALL_PE_RWE_REG_OFFSET)
143 #define FWE_REG_ADDR(x, y)\
144                 (x + (y * FIREWALL_COMPONENT_SIZE) + FIREWALL_PE_FWE_REG_OFFSET)
145 #define LDE_REG_ADDR(x)    (x + FIREWALL_LDE_REG_OFFSET)
146 
147 struct fw_dev_data_t fw_data;
148 
fc_select(void * base_addr,uint32_t comp_id)149 void fc_select(void *base_addr, uint32_t comp_id)
150 {
151     fw_data.base_addr = base_addr;
152     fw_data.comp_id = comp_id;
153     fw_data.cs_ptr  = CS_REG_ADDR(fw_data.base_addr, fw_data.comp_id);
154     fw_data.rwe_ptr = RWE_REG_ADDR(fw_data.base_addr, fw_data.comp_id);
155 }
156 
fc_enable_bypass(void)157 void fc_enable_bypass(void)
158 {
159     struct _firewall_pe_cs_reg_map_t *ptr =
160          (struct _firewall_pe_cs_reg_map_t *)fw_data.cs_ptr;
161     ptr->pe_ctrl &= ~PE_CTRL_EN_BYPASS_MASK;
162     while (!(ptr->pe_bps & PE_BPS_BYPASS_ST_MASK))
163         ;
164 }
165 
fc_disable_bypass(void)166 void fc_disable_bypass(void)
167 {
168     struct _firewall_pe_cs_reg_map_t *ptr =
169          (struct _firewall_pe_cs_reg_map_t *)fw_data.cs_ptr;
170     ptr->pe_ctrl |= PE_CTRL_EN_BYPASS_MASK;
171     while ((ptr->pe_bps & PE_BPS_BYPASS_ST_MASK))
172         ;
173 }
174 
fc_pe_enable(void)175 void fc_pe_enable(void)
176 {
177     struct _firewall_pe_cs_reg_map_t *ptr =
178          (struct _firewall_pe_cs_reg_map_t *)fw_data.cs_ptr;
179     ptr->pe_ctrl |= PE_CTRL_EN_MASK;
180     while (!(ptr->pe_st & PE_ST_EN_MASK))
181         ;
182 }
183 
fc_pe_disable(void)184 void fc_pe_disable(void)
185 {
186     struct _firewall_pe_cs_reg_map_t *ptr =
187          (struct _firewall_pe_cs_reg_map_t *)fw_data.cs_ptr;
188     ptr->pe_ctrl &= ~PE_CTRL_EN_MASK;
189     while ((ptr->pe_st & PE_ST_EN_MASK))
190         ;
191 }
192 
fc_disable_txn_term_error(void * base_addr)193 void fc_disable_txn_term_error(void *base_addr)
194 {
195     uint32_t *ptr = (uint32_t *)base_addr;
196     /* Write 0 to ERR bit field of FW_CTRL register */
197     *ptr = 0;
198 }
199 
fc_select_region(uint32_t region_id)200 void fc_select_region(uint32_t region_id)
201 {
202     struct _firewall_pe_rwe_reg_map_t *ptr =
203          (struct _firewall_pe_rwe_reg_map_t *)fw_data.rwe_ptr;
204     ptr->rwe_ctrl = (ptr->rwe_ctrl & ~RWE_CTRL_RGN_INDX_MASK) |
205                     (region_id & RWE_CTRL_RGN_INDX_MASK);
206 }
207 
fc_enable_regions(void)208 void fc_enable_regions(void)
209 {
210     struct _firewall_pe_rwe_reg_map_t *ptr =
211          (struct _firewall_pe_rwe_reg_map_t *)fw_data.rwe_ptr;
212     ptr->rgn_ctrl0 |= RGN_CTRL0_EN_MASK;
213 }
214 
fc_disable_regions(void)215 void fc_disable_regions(void)
216 {
217     struct _firewall_pe_rwe_reg_map_t *ptr =
218          (struct _firewall_pe_rwe_reg_map_t *)fw_data.rwe_ptr;
219     ptr->rgn_ctrl0 &= ~RGN_CTRL0_EN_MASK;
220 }
221 
fc_prog_rgn(enum rgn_size_t size,uint32_t base_addr)222 void fc_prog_rgn(enum rgn_size_t size, uint32_t base_addr)
223 {
224     struct _firewall_pe_rwe_reg_map_t *ptr =
225          (struct _firewall_pe_rwe_reg_map_t *)fw_data.rwe_ptr;
226     /*
227      * As the reset value is rgn_size register is UNKNOWN, Arm recommends to set
228      * register to a known value before performing read-modify-write operations
229      */
230     ptr->rgn_size = 0;
231     ptr->rgn_size = (ptr->rgn_size & ~RGN_SIZE_SIZE_MASK) |
232                     (size & RGN_SIZE_SIZE_MASK);
233     ptr->rgn_cfg0 = base_addr;
234 }
235 
fc_prog_rgn_upper_addr(uint32_t upper_addr)236 void fc_prog_rgn_upper_addr(uint32_t upper_addr)
237 {
238     struct _firewall_pe_rwe_reg_map_t *ptr =
239          (struct _firewall_pe_rwe_reg_map_t *)fw_data.rwe_ptr;
240     ptr->rgn_tcfg0 = upper_addr;
241 }
242 
fc_enable_addr_trans(void)243 void fc_enable_addr_trans(void)
244 {
245     struct _firewall_pe_rwe_reg_map_t *ptr =
246          (struct _firewall_pe_rwe_reg_map_t *)fw_data.rwe_ptr;
247     ptr->rgn_tcfg2 |= RGN_TCFG2_ADDR_TRANS_EN_MASK;
248 }
249 
fc_disable_addr_trans(void)250 void fc_disable_addr_trans(void)
251 {
252     struct _firewall_pe_rwe_reg_map_t *ptr =
253          (struct _firewall_pe_rwe_reg_map_t *)fw_data.rwe_ptr;
254     ptr->rgn_tcfg2 &= ~RGN_TCFG2_ADDR_TRANS_EN_MASK;
255 }
256 
fc_init_mpl(enum rgn_mpe_t mpe)257 void fc_init_mpl(enum rgn_mpe_t mpe)
258 {
259     struct _firewall_pe_rwe_reg_map_t *ptr =
260          (struct _firewall_pe_rwe_reg_map_t *)fw_data.rwe_ptr;
261     /* Before enabling an MPE, it must:
262      * 1) Set the RGN_MPL fields with an UNKNOWN reset value to a known value.
263      * 2) Set either:
264      *    RGN_MID{0-3} to a known value.
265      *    RGN_MPL.ANY_MST to 0b1.
266      */
267     if (mpe == RGN_MPE0) {
268         ptr->rgn_mpl0 = 0x1000;
269         ptr->rgn_mpl0 = 0x0;
270     } else if (mpe == RGN_MPE1) {
271         ptr->rgn_mpl1 = 0x1000;
272         ptr->rgn_mpl1 = 0x0;
273     } else if (mpe == RGN_MPE2) {
274         ptr->rgn_mpl2 = 0x1000;
275         ptr->rgn_mpl2 = 0x0;
276     } else if (mpe == RGN_MPE3) {
277         ptr->rgn_mpl3 = 0x1000;
278         ptr->rgn_mpl3 = 0x0;
279     }
280 }
281 
fc_enable_mpl(enum rgn_mpe_t mpe,enum rgn_mpl_t mpl)282 void fc_enable_mpl(enum rgn_mpe_t mpe, enum rgn_mpl_t mpl)
283 {
284     struct _firewall_pe_rwe_reg_map_t *ptr =
285          (struct _firewall_pe_rwe_reg_map_t *)fw_data.rwe_ptr;
286     if (mpe == RGN_MPE0)
287         ptr->rgn_mpl0 |= (mpl & RGN_MPL_EN_MASK);
288     else if (mpe == RGN_MPE1)
289         ptr->rgn_mpl1 |= (mpl & RGN_MPL_EN_MASK);
290     else if (mpe == RGN_MPE2)
291         ptr->rgn_mpl2 |= (mpl & RGN_MPL_EN_MASK);
292     else if (mpe == RGN_MPE3)
293         ptr->rgn_mpl3 |= (mpl & RGN_MPL_EN_MASK);
294 }
295 
fc_read_mpl(enum rgn_mpe_t mpe,enum rgn_mpl_t * mpl)296 void fc_read_mpl(enum rgn_mpe_t mpe, enum rgn_mpl_t* mpl)
297 {
298     struct _firewall_pe_rwe_reg_map_t *ptr =
299          (struct _firewall_pe_rwe_reg_map_t *)fw_data.rwe_ptr;
300     if (mpe == RGN_MPE0)
301         *mpl = (ptr->rgn_mpl0 & RGN_MPL_EN_MASK);
302     else if (mpe == RGN_MPE1)
303         *mpl = (ptr->rgn_mpl1 & RGN_MPL_EN_MASK);
304     else if (mpe == RGN_MPE2)
305         *mpl = (ptr->rgn_mpl2 & RGN_MPL_EN_MASK);
306     else if (mpe == RGN_MPE3)
307         *mpl = (ptr->rgn_mpl3 & RGN_MPL_EN_MASK);
308 }
309 
310 
fc_disable_mpl(enum rgn_mpe_t mpe,enum rgn_mpl_t mpl)311 void fc_disable_mpl(enum rgn_mpe_t mpe, enum rgn_mpl_t mpl)
312 {
313     struct _firewall_pe_rwe_reg_map_t *ptr =
314          (struct _firewall_pe_rwe_reg_map_t *)fw_data.rwe_ptr;
315     mpl &= RGN_MPL_EN_MASK;
316     if (mpe == RGN_MPE0)
317         ptr->rgn_mpl0 &= ~mpl;
318     else if (mpe == RGN_MPE1)
319         ptr->rgn_mpl1 &= ~mpl;
320     else if (mpe == RGN_MPE2)
321         ptr->rgn_mpl2 &= ~mpl;
322     else if (mpe == RGN_MPE3)
323         ptr->rgn_mpl3 &= ~mpl;
324 }
325 
fc_prog_mid(enum rgn_mpe_t mpe,uint32_t mid)326 void fc_prog_mid(enum rgn_mpe_t mpe, uint32_t mid)
327 {
328     struct _firewall_pe_rwe_reg_map_t *ptr =
329          (struct _firewall_pe_rwe_reg_map_t *)fw_data.rwe_ptr;
330     if (mpe == RGN_MPE0)
331         ptr->rgn_mid0 = mid;
332     else if (mpe == RGN_MPE1)
333         ptr->rgn_mid1 = mid;
334     else if (mpe == RGN_MPE2)
335         ptr->rgn_mid2 = mid;
336     else if (mpe == RGN_MPE3)
337         ptr->rgn_mid3 = mid;
338 }
339 
fc_enable_mpe(enum rgn_mpe_t mpe)340 void fc_enable_mpe(enum rgn_mpe_t mpe)
341 {
342     struct _firewall_pe_rwe_reg_map_t *ptr =
343          (struct _firewall_pe_rwe_reg_map_t *)fw_data.rwe_ptr;
344     ptr->rgn_ctrl1 |= (mpe & RGN_CTRL1_MPE_EN_MASK);
345     while (!(ptr->rgn_st & mpe))
346         ;
347 }
348 
fc_disable_mpe(enum rgn_mpe_t mpe)349 void fc_disable_mpe(enum rgn_mpe_t mpe)
350 {
351     struct _firewall_pe_rwe_reg_map_t *ptr =
352          (struct _firewall_pe_rwe_reg_map_t *)fw_data.rwe_ptr;
353     mpe &= RGN_CTRL1_MPE_EN_MASK;
354     ptr->rgn_ctrl1 &= ~mpe;
355     while ((ptr->rgn_st & mpe))
356         ;
357 }
358 
fc_rgn_lock(void)359 void fc_rgn_lock(void)
360 {
361     struct _firewall_pe_rwe_reg_map_t *ptr =
362          (struct _firewall_pe_rwe_reg_map_t *)fw_data.rwe_ptr;
363     ptr->rgn_lctrl |= RGN_LCTRL_LOCK_MASK;
364 }
365 
fc_rgn_unlock(void)366 void fc_rgn_unlock(void)
367 {
368     struct _firewall_pe_rwe_reg_map_t *ptr =
369          (struct _firewall_pe_rwe_reg_map_t *)fw_data.rwe_ptr;
370     ptr->rgn_lctrl &= ~RGN_LCTRL_LOCK_MASK;
371 }
372 
fw_get_lockdown_status(void)373 enum fw_lockdown_status_t fw_get_lockdown_status(void)
374 {
375     struct _firewall_lde_reg_map_t *ptr = (struct _firewall_lde_reg_map_t *)
376      LDE_REG_ADDR(fw_data.base_addr);
377     if (ptr->ld_ctrl & LD_CTRL_LDI_ST_MASK)
378         return FW_LOCKED;
379     else
380         return FW_UNLOCKED;
381 }
382 
fw_lockdown(enum fw_lockdown_state_t lockdown_state)383 void fw_lockdown(enum fw_lockdown_state_t lockdown_state)
384 {
385     struct _firewall_lde_reg_map_t *ptr = (struct _firewall_lde_reg_map_t *)
386      LDE_REG_ADDR(fw_data.base_addr);
387     ptr->ld_ctrl |= lockdown_state;
388 }
389