tzc400.c 8.34 KB
Newer Older
Harry Liebel's avatar
Harry Liebel committed
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
/*
 * Copyright (c) 2014, ARM Limited and Contributors. All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions are met:
 *
 * Redistributions of source code must retain the above copyright notice, this
 * list of conditions and the following disclaimer.
 *
 * Redistributions in binary form must reproduce the above copyright notice,
 * this list of conditions and the following disclaimer in the documentation
 * and/or other materials provided with the distribution.
 *
 * Neither the name of ARM nor the names of its contributors may be used
 * to endorse or promote products derived from this software without specific
 * prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
 * POSSIBILITY OF SUCH DAMAGE.
 */

#include <assert.h>
32
#include <debug.h>
33
34
35
#include <mmio.h>
#include <stddef.h>
#include <tzc400.h>
Harry Liebel's avatar
Harry Liebel committed
36

37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
/*
 * Implementation defined values used to validate inputs later.
 * Filters : max of 4 ; 0 to 3
 * Regions : max of 9 ; 0 to 8
 * Address width : Values between 32 to 64
 */
typedef struct tzc_instance {
	uint64_t base;
	uint8_t addr_width;
	uint8_t num_filters;
	uint8_t num_regions;
} tzc_instance_t;

tzc_instance_t tzc;


static inline uint32_t tzc_read_build_config(uint64_t base)
Harry Liebel's avatar
Harry Liebel committed
54
55
56
57
{
	return mmio_read_32(base + BUILD_CONFIG_OFF);
}

58
static inline uint32_t tzc_read_gate_keeper(uint64_t base)
Harry Liebel's avatar
Harry Liebel committed
59
60
61
62
{
	return mmio_read_32(base + GATE_KEEPER_OFF);
}

63
static inline void tzc_write_gate_keeper(uint64_t base, uint32_t val)
Harry Liebel's avatar
Harry Liebel committed
64
65
66
67
{
	mmio_write_32(base + GATE_KEEPER_OFF, val);
}

68
static inline void tzc_write_action(uint64_t base, tzc_action_t action)
Harry Liebel's avatar
Harry Liebel committed
69
70
71
72
{
	mmio_write_32(base + ACTION_OFF, action);
}

73
74
75
static inline void tzc_write_region_base_low(uint64_t base,
					uint32_t region,
					uint32_t val)
Harry Liebel's avatar
Harry Liebel committed
76
{
77
78
	mmio_write_32(base + REGION_BASE_LOW_OFF +
		REGION_NUM_OFF(region), val);
Harry Liebel's avatar
Harry Liebel committed
79
80
}

81
82
83
static inline void tzc_write_region_base_high(uint64_t base,
					uint32_t region,
					uint32_t val)
Harry Liebel's avatar
Harry Liebel committed
84
{
85
86
	mmio_write_32(base + REGION_BASE_HIGH_OFF +
		REGION_NUM_OFF(region), val);
Harry Liebel's avatar
Harry Liebel committed
87
88
}

89
90
91
static inline void tzc_write_region_top_low(uint64_t base,
					uint32_t region,
					uint32_t val)
Harry Liebel's avatar
Harry Liebel committed
92
{
93
94
	mmio_write_32(base + REGION_TOP_LOW_OFF +
		REGION_NUM_OFF(region), val);
Harry Liebel's avatar
Harry Liebel committed
95
96
}

97
98
99
static inline void tzc_write_region_top_high(uint64_t base,
					uint32_t region,
					uint32_t val)
Harry Liebel's avatar
Harry Liebel committed
100
{
101
102
	mmio_write_32(base + REGION_TOP_HIGH_OFF +
		REGION_NUM_OFF(region), val);
Harry Liebel's avatar
Harry Liebel committed
103
104
}

105
106
107
static inline void tzc_write_region_attributes(uint64_t base,
					uint32_t region,
					uint32_t val)
Harry Liebel's avatar
Harry Liebel committed
108
{
109
110
	mmio_write_32(base + REGION_ATTRIBUTES_OFF +
		REGION_NUM_OFF(region), val);
Harry Liebel's avatar
Harry Liebel committed
111
112
}

113
114
115
static inline void tzc_write_region_id_access(uint64_t base,
					uint32_t region,
					uint32_t val)
Harry Liebel's avatar
Harry Liebel committed
116
{
117
118
	mmio_write_32(base + REGION_ID_ACCESS_OFF +
		REGION_NUM_OFF(region), val);
Harry Liebel's avatar
Harry Liebel committed
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
}

static uint32_t tzc_read_component_id(uint64_t base)
{
	uint32_t id;

	id = mmio_read_8(base + CID0_OFF);
	id |= (mmio_read_8(base + CID1_OFF) << 8);
	id |= (mmio_read_8(base + CID2_OFF) << 16);
	id |= (mmio_read_8(base + CID3_OFF) << 24);

	return id;
}

static uint32_t tzc_get_gate_keeper(uint64_t base, uint8_t filter)
{
	uint32_t tmp;

	tmp = (tzc_read_gate_keeper(base) >> GATE_KEEPER_OS_SHIFT) &
		GATE_KEEPER_OS_MASK;

140
	return (tmp >> filter) & GATE_KEEPER_FILTER_MASK;
Harry Liebel's avatar
Harry Liebel committed
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
}

/* This function is not MP safe. */
static void tzc_set_gate_keeper(uint64_t base, uint8_t filter, uint32_t val)
{
	uint32_t tmp;

	/* Upper half is current state. Lower half is requested state. */
	tmp = (tzc_read_gate_keeper(base) >> GATE_KEEPER_OS_SHIFT) &
		GATE_KEEPER_OS_MASK;

	if (val)
		tmp |=  (1 << filter);
	else
		tmp &= ~(1 << filter);

	tzc_write_gate_keeper(base, (tmp & GATE_KEEPER_OR_MASK) <<
			      GATE_KEEPER_OR_SHIFT);

	/* Wait here until we see the change reflected in the TZC status. */
	while (((tzc_read_gate_keeper(base) >> GATE_KEEPER_OS_SHIFT) &
		GATE_KEEPER_OS_MASK) != tmp)
	  ;
}


167
void tzc_init(uint64_t base)
Harry Liebel's avatar
Harry Liebel committed
168
169
170
{
	uint32_t tzc_id, tzc_build;

171
172
	assert(base);
	tzc.base = base;
Harry Liebel's avatar
Harry Liebel committed
173
174
175
176
177

	/*
	 * We expect to see a tzc400. Check component ID. The TZC-400 TRM shows
	 * component ID is expected to be "0xB105F00D".
	 */
178
	tzc_id = tzc_read_component_id(tzc.base);
Harry Liebel's avatar
Harry Liebel committed
179
180
181
182
183
184
	if (tzc_id != TZC400_COMPONENT_ID) {
		ERROR("TZC : Wrong device ID (0x%x).\n", tzc_id);
		panic();
	}

	/* Save values we will use later. */
185
186
	tzc_build = tzc_read_build_config(tzc.base);
	tzc.num_filters = ((tzc_build >> BUILD_CONFIG_NF_SHIFT) &
Harry Liebel's avatar
Harry Liebel committed
187
			   BUILD_CONFIG_NF_MASK) + 1;
188
	tzc.addr_width  = ((tzc_build >> BUILD_CONFIG_AW_SHIFT) &
Harry Liebel's avatar
Harry Liebel committed
189
			   BUILD_CONFIG_AW_MASK) + 1;
190
	tzc.num_regions = ((tzc_build >> BUILD_CONFIG_NR_SHIFT) &
Harry Liebel's avatar
Harry Liebel committed
191
192
193
194
195
196
197
198
199
200
201
202
203
			   BUILD_CONFIG_NR_MASK) + 1;
}


/*
 * `tzc_configure_region` is used to program regions into the TrustZone
 * controller. A region can be associated with more than one filter. The
 * associated filters are passed in as a bitmap (bit0 = filter0).
 * NOTE:
 * The region 0 covers the whole address space and is enabled on all filters,
 * this cannot be changed. It is, however, possible to change some region 0
 * permissions.
 */
204
void tzc_configure_region(uint32_t filters,
Harry Liebel's avatar
Harry Liebel committed
205
206
207
			  uint8_t  region,
			  uint64_t region_base,
			  uint64_t region_top,
208
			  tzc_region_attributes_t sec_attr,
Harry Liebel's avatar
Harry Liebel committed
209
210
			  uint32_t ns_device_access)
{
211
	assert(tzc.base);
Harry Liebel's avatar
Harry Liebel committed
212
213

	/* Do range checks on filters and regions. */
214
215
	assert(((filters >> tzc.num_filters) == 0) &&
	       (region < tzc.num_regions));
Harry Liebel's avatar
Harry Liebel committed
216
217
218
219
220

	/*
	 * Do address range check based on TZC configuration. A 64bit address is
	 * the max and expected case.
	 */
221
222
	assert(((region_top <= (UINT64_MAX >> (64 - tzc.addr_width))) &&
		(region_base < region_top)));
Harry Liebel's avatar
Harry Liebel committed
223
224
225
226
227
228
229
230
231
232
233

	/* region_base and (region_top + 1) must be 4KB aligned */
	assert(((region_base | (region_top + 1)) & (4096 - 1)) == 0);

	assert(sec_attr <= TZC_REGION_S_RDWR);

	/*
	 * Inputs look ok, start programming registers.
	 * All the address registers are 32 bits wide and have a LOW and HIGH
	 * component used to construct a up to a 64bit address.
	 */
234
235
236
237
	tzc_write_region_base_low(tzc.base, region,
				(uint32_t)(region_base));
	tzc_write_region_base_high(tzc.base, region,
				(uint32_t)(region_base >> 32));
Harry Liebel's avatar
Harry Liebel committed
238

239
240
241
242
	tzc_write_region_top_low(tzc.base, region,
				(uint32_t)(region_top));
	tzc_write_region_top_high(tzc.base, region,
				(uint32_t)(region_top >> 32));
Harry Liebel's avatar
Harry Liebel committed
243
244

	/* Assign the region to a filter and set secure attributes */
245
	tzc_write_region_attributes(tzc.base, region,
Harry Liebel's avatar
Harry Liebel committed
246
247
248
249
250
251
		(sec_attr << REGION_ATTRIBUTES_SEC_SHIFT) | filters);

	/*
	 * Specify which non-secure devices have permission to access this
	 * region.
	 */
252
	tzc_write_region_id_access(tzc.base, region, ns_device_access);
Harry Liebel's avatar
Harry Liebel committed
253
254
255
}


256
void tzc_set_action(tzc_action_t action)
Harry Liebel's avatar
Harry Liebel committed
257
{
258
	assert(tzc.base);
Harry Liebel's avatar
Harry Liebel committed
259
260
261
262
263
264

	/*
	 * - Currently no handler is provided to trap an error via interrupt
	 *   or exception.
	 * - The interrupt action has not been tested.
	 */
265
	tzc_write_action(tzc.base, action);
Harry Liebel's avatar
Harry Liebel committed
266
267
268
}


269
void tzc_enable_filters(void)
Harry Liebel's avatar
Harry Liebel committed
270
271
272
273
{
	uint32_t state;
	uint32_t filter;

274
	assert(tzc.base);
Harry Liebel's avatar
Harry Liebel committed
275

276
277
	for (filter = 0; filter < tzc.num_filters; filter++) {
		state = tzc_get_gate_keeper(tzc.base, filter);
Harry Liebel's avatar
Harry Liebel committed
278
		if (state) {
279
280
281
282
283
284
285
			/* The TZC filter is already configured. Changing the
			 * programmer's view in an active system can cause
			 * unpredictable behavior therefore panic for now rather
			 * than try to determine whether this is safe in this
			 * instance. See:
			 * http://infocenter.arm.com/help/index.jsp?\
			 * topic=/com.arm.doc.ddi0504c/CJHHECBF.html */
Harry Liebel's avatar
Harry Liebel committed
286
287
288
289
			ERROR("TZC : Filter %d Gatekeeper already enabled.\n",
				filter);
			panic();
		}
290
		tzc_set_gate_keeper(tzc.base, filter, 1);
Harry Liebel's avatar
Harry Liebel committed
291
292
293
294
	}
}


295
void tzc_disable_filters(void)
Harry Liebel's avatar
Harry Liebel committed
296
297
298
{
	uint32_t filter;

299
	assert(tzc.base);
Harry Liebel's avatar
Harry Liebel committed
300
301
302
303
304

	/*
	 * We don't do the same state check as above as the Gatekeepers are
	 * disabled after reset.
	 */
305
306
	for (filter = 0; filter < tzc.num_filters; filter++)
		tzc_set_gate_keeper(tzc.base, filter, 0);
Harry Liebel's avatar
Harry Liebel committed
307
}