summaryrefslogtreecommitdiff
path: root/cpu/arm_cortexa9/db8500/sec_bridge.c
blob: 2998d9466c29bdfbb97ae71cceed6b638b37185d (plain)
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
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
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
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
/*
 * Copyright (C) ST-Ericsson SA 2010
 *
 * Author: Mikael Larsson <mikael.xt.larsson@stericsson.com> for ST-Ericsson.
 *
 * License terms: GNU General Public License (GPL), version 2.
 */
#include <common.h>
#include <asm/arch/sec_bridge.h>

typedef u32 (*boot_rom_bridge_func_t)(const u32 , const u32, const va_list);
static boot_rom_bridge_func_t hw_sec_rom_pub_bridge;

struct sec_rom_cut_desc {
	u32 cutid_addr;
	u32 cutid;
	u32 bridge_func;
};

static const struct sec_rom_cut_desc cuttable[] = {
	{ 0x9001DBF4, 0x008500B2, 0x90017300 },
	{ 0x9001DBF4, 0x008500B1, 0x90017300 },
	{ 0x9001DBF4, 0x008500B0, 0x90017300 },
	{ 0x9001FFF4, 0x008500A1, 0x90018300 },
	{ 0x9001FFF4, 0x005500A0, 0x90018300 },
	{ 0x9001FFF4, 0x008500A0, 0x90018300 },
};

int sec_bridge_init_bridge(void)
{
	u8 cutnb = 0;

	hw_sec_rom_pub_bridge = NULL;

	while ((cutnb < ARRAY_SIZE(cuttable)) &&
	       (cuttable[cutnb].cutid != *(u32 *)(cuttable[cutnb].cutid_addr)))
			cutnb++;

	if (cutnb < ARRAY_SIZE(cuttable)) {
		hw_sec_rom_pub_bridge =
			(boot_rom_bridge_func_t)cuttable[cutnb].bridge_func;

		return 0;
	}

	printf("sec_bridge: cutid not found\n");
	return 1;
}

u32 sec_bridge_call_secure_service(const u32 serviceid,
				   const u32 secureconfig,
				   ...)
{
	va_list ap;
	u32 returnvalue;

	va_start(ap, secureconfig);

	returnvalue = hw_sec_rom_pub_bridge(serviceid,
					    secureconfig,
					    ap);

	va_end(ap);
	return returnvalue;
}

int sec_bridge_flush_issw(void)
{
	u32 ret;

	if (hw_sec_rom_pub_bridge != NULL) {

		ret = sec_bridge_call_secure_service(ISSWAPI_FLUSH_BOOT_CODE,
						SEC_ROM_FORCE_CLEAN_MASK,
						0,
						0);

		if (ret != SEC_ROM_RET_OK) {
			printf("sec_bridge: ISSWAPI_FLUSH_BOOT_CODE: %d\n",
				ret);
			return 1;
		}
	}
	return 0;
}

/*
 * All this signed header verification code is put here to reuse the static
 * functions defined in this file to call secure world.
 *
 * We are planning to export generic code verifcation to u-boot via another
 * module so the generic code below can be removed at that stage.
 */

#if defined(CONFIG_SECURE_KERNEL_BOOT)

/* Stuff copied from isswapi_types.h */
enum issw_payload_type {
	ISSW_PL_TYPE_TAPP = 0,
	ISSW_PL_TYPE_PRCMU,
	ISSW_PL_TYPE_MEMINIT,
	ISSW_PL_TYPE_X_LOADER,
	ISSW_PL_TYPE_OS_LOADER,
	ISSW_PL_TYPE_APE_NW_CODE,
	ISSW_PL_TYPE_FC_LOADER,
	ISSW_PL_TYPE_MODEM_CODE,
	ISSW_PL_TYPE_FOTA,
	ISSW_PL_TYPE_DNTCERT,
	ISSW_PL_TYPE_AUTHCERT,
	ISSW_PL_TYPE_IPL,
	ISSW_PL_TYPE_FLASH_ARCHIVE,
	ISSW_PL_TYPE_ITP,
	ISSW_PL_TYPE_AUTH_CHALLENGE = -1 /* 0xffffffff */
};


typedef struct issw_signed_header {
	u32    magic;
	u16    size_of_signed_header;
	u16    size_of_signature;
	u32    sign_hash_type; /* see t_hash_type */
	u32    signature_type; /* see t_signature_type */
	u32    hash_type;      /* see t_hash_type */
	u32    payload_type;   /* see enum issw_payload_type */
	u32    flags;	  /* reserved */
	u32    size_of_payload;
	u32    sw_vers_nbr;
	u32    load_address;
	u32    startup_address;
	u32    spare;	  /* reserved */
#if 0
	/* Pseudo code visualize layout of signed header */
	u8     hash[get_hash_length(this.hash_type)];
	u8     signature[size_of_signature];
#endif
} issw_signed_header_t;

#define ISSW_SIGNED_HEADER_MAGIC  0x53484452

#define ISSW_SIGNED_HEADER_HASH(hdr) \
	((u8 *)((issw_signed_header_t *)(hdr) + 1))

#define ISSW_SIGNED_HEADER_HASH_SIZE(hdr) \
	(((issw_signed_header_t *)(hdr))->size_of_signed_header - \
	    ((issw_signed_header_t *)(hdr))->size_of_signature - \
		sizeof(issw_signed_header_t))

#define ISSW_SIGNED_HEADER_SIGNATURE(hdr) \
	(ISSW_SIGNED_HEADER_HASH(hdr) + ISSW_SIGNED_HEADER_HASH_SIZE(hdr))

#define ISSW_SIGNED_HEADER_PAYLOAD(hdr) \
	((u8 *)(hdr) + \
		((issw_signed_header_t *)(hdr))->size_of_signed_header)

static int sec_bridge_verify_signed_header(issw_signed_header_t *hdr,
					   enum issw_payload_type pt)
{
	u32 ret;

	ret = sec_bridge_call_secure_service(ISSWAPI_VERIFY_SIGNED_HEADER,
					     SEC_ROM_FORCE_CLEAN_MASK, hdr, (u32)pt);
	if (ret != SEC_ROM_RET_OK) {
		printf("sec_bridge: "
		       "ISSWAPI_VERIFY_SIGNED_HEADER: %d\n", ret);
		return 1;
	}
	return 0;
}

static int sec_bridge_verify_hash(u8 *hash, u32 hash_size, u8 *payload,
			u32 payload_size, u32 hash_type)
{
	u32 ret;

	ret = sec_bridge_call_secure_service(ISSWAPI_VERIFY_HASH,
				      SEC_ROM_FORCE_CLEAN_MASK,
				      hash, hash_size, payload, payload_size,
				      hash_type);
	if (ret != SEC_ROM_RET_OK) {
		printf("sec_bridge: "
		       "ISSWAPI_VERIFY_HASH: %d\n", ret);
		return 1;
	}
	return 0;
}

static int sec_bridge_verify_image(u32 *img_addr,
				   enum issw_payload_type payload_type)
{
	issw_signed_header_t *hdr = (issw_signed_header_t *) *img_addr;

	debug("sec_bridge_verify_image(img_addr->0x%08x, payload_type:%d)\n", *img_addr, payload_type);

	if (*img_addr  == 0)
		return 1;

	if (sec_bridge_verify_signed_header(hdr, payload_type)) 
		return 1;

	/*
	 * Using a secure service for this since sha256 in u-boot
	 * was incedible slow.
	 */
	if (sec_bridge_verify_hash(ISSW_SIGNED_HEADER_HASH(hdr),
				   ISSW_SIGNED_HEADER_HASH_SIZE(hdr),
				   ISSW_SIGNED_HEADER_PAYLOAD(hdr),
				   hdr->size_of_payload, hdr->hash_type))
		return 1;

	*img_addr = (ulong)ISSW_SIGNED_HEADER_PAYLOAD(hdr);
	debug("sec_bridge: Changed img_addr->0x%08x\n", *img_addr);
	return 0;
}

int sec_bridge_verify_kernel_image(u32 *img_addr) {
	return sec_bridge_verify_image(img_addr, ISSW_PL_TYPE_APE_NW_CODE);
}

int sec_bridge_verify_itp_image(u32 *img_addr) {
	return sec_bridge_verify_image(img_addr, ISSW_PL_TYPE_ITP);
}

#endif /* CONFIG_SECURE_KERNEL_BOOT */