Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(65)

Side by Side Diff: arch/arm/cpu/arm_cortexa9/tegra2/warmboot.c

Issue 4841001: Tegra2: implement Warmboot code and lp0_vec (Closed) Base URL: http://git.chromium.org/git/u-boot-next.git@chromeos-v2010.09
Patch Set: Created 10 years, 1 month ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
OLDNEW
(Empty)
1 /*
2 * (C) Copyright 2010
3 * NVIDIA Corporation <www.nvidia.com>
4 *
5 * See file CREDITS for list of people who contributed to this
6 * project.
7 *
8 * This program is free software; you can redistribute it and/or
9 * modify it under the terms of the GNU General Public License as
10 * published by the Free Software Foundation; either version 2 of
11 * the License, or (at your option) any later version.
12 *
13 * This program is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 * GNU General Public License for more details.
17 *
18 * You should have received a copy of the GNU General Public License
19 * along with this program; if not, write to the Free Software
20 * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
21 * MA 02111-1307 USA
22 */
23
24 #include <common.h>
25 #include <asm/arch/nv_drf.h>
26 #include <asm/arch/nvboot_error.h>
27 #include <asm/arch/nvcommon.h>
28 #include <asm/arch/nverror.h>
29 #include <asm/arch/tegra2.h>
30 #include <asm/arch/nv_hardware_access.h>
31 #include "warmboot.h"
32
33 NvBootError sign_data_block(NvU8 *source,
34 NvU32 length,
35 NvU8 *hash);
36
37 /* -------------------------------------
38 * Configuration parameters
39 * -------------------------------------
40 */
41
42 /* -------------------------------------
43 * Definitions
44 * -------------------------------------
45 */
46
47 /* NOTE: If more than one of the following is enabled, only one of them will
48 * actually be used. RANDOM takes precedence over PATTERN and ZERO, and
49 * PATTERN takes precedence overy ZERO.
50 */
51 #define RANDOM_AES_BLOCK_IS_RANDOM 1 /* Set nonzero to random ize the header */
52 #define RANDOM_AES_BLOCK_IS_PATTERN 1 /* Set nonzero to patter nize the header */
53 #define RANDOM_AES_BLOCK_IS_ZERO 1 /* Set nonzero to clear the header */
54
55 /* Address at which AP20 WB0 code runs */
56 /* The address must not overlap the bootrom's IRAM usage */
57 #define AP20_WB0_RUN_ADDRESS 0x40020000
58 #define AP20_IRAM_BASE 0x40000000
59
60 /* -------------------------------------
61 * Global External Labels
62 * -------------------------------------
63 */
64
65 void wb_start(void); /* Start of WB assembly code */
66 void wb_end(void); /* End of WB assembly code */
67
68 #define NV_ADDRESS_MAP_FUSE_BASE 0x7000F800UL
69 #define FUSE_PRODUCTION_MODE_0 _MK_ADDR_CONST(0x100)
70 #define FUSE_FA_0 _MK_ADDR_CONST(0x148)
71 #define FUSE_SECURITY_MODE_0 _MK_ADDR_CONST(0x1a0)
72
73 /* -------------------------------------
74 * Local Functions
75 * -------------------------------------
76 */
77 static NvU32 get_major_version(void)
78 {
79 NvU32 reg = 0;
80 NvU32 major_id = 0;
81
82 reg = NV_READ32( NV_ADDRESS_MAP_APB_MISC_BASE + APB_MISC_GP_HIDREV_0) ;
83 major_id = NV_DRF_VAL(APB_MISC, GP_HIDREV, MAJORREV, reg);
84 return major_id;
85 }
86
87 static NvBool is_production_mode_fuse_set(void)
88 {
89 NvU32 reg;
90
91 reg = NV_READ32(NV_ADDRESS_MAP_FUSE_BASE + FUSE_PRODUCTION_MODE_0);
92 if (reg)
93 return NV_TRUE;
94 else
95 return NV_FALSE;
96 }
97
98 static NvBool is_odm_production_mode_fuse_set(void)
99 {
100 NvU32 reg;
101
102 reg = NV_READ32(NV_ADDRESS_MAP_FUSE_BASE + FUSE_SECURITY_MODE_0);
103 if (reg)
104 return NV_TRUE;
105 else
106 return NV_FALSE;
107 }
108
109 static NvBool ap20_is_failure_analysis_mode(void)
110 {
111 volatile NvU32 reg;
112
113 reg = NV_READ32(NV_ADDRESS_MAP_FUSE_BASE + FUSE_FA_0);
114 if (reg)
115 return NV_TRUE;
116 else
117 return NV_FALSE;
118 }
119
120 static NvBool ap20_is_odm_production_mode(void)
121 {
122 if (!ap20_is_failure_analysis_mode() &&
123 is_odm_production_mode_fuse_set())
124 return NV_TRUE;
125 else
126 return NV_FALSE;
127 }
128
129 static NvBool ap20_is_production_mode(void)
130 {
131 if (get_major_version() == 0)
132 return NV_TRUE;
133
134 if (!ap20_is_failure_analysis_mode() &&
135 is_production_mode_fuse_set() &&
136 !is_odm_production_mode_fuse_set())
137 return NV_TRUE;
138 else
139 return NV_FALSE;
140 }
141
142 static NvBool fuse_get_ap20_hal(nv_fuse_hal *hal)
143 {
144 NvU32 reg;
145
146 reg = NV_READ32(NV_ADDRESS_MAP_APB_MISC_BASE + APB_MISC_GP_HIDREV_0);
147 if (NV_DRF_VAL(APB_MISC_GP, HIDREV, CHIPID, reg) == 0x20) {
148 hal->is_odm_production_mode = ap20_is_odm_production_mode;
149 hal->is_nv_production_mode = ap20_is_production_mode;
150 return NV_TRUE;
151 }
152 return NV_FALSE;
153 }
154
155 static nvbl_operating_mode nv_fuse_get_operation_mode(void)
156 {
157 nv_fuse_hal hal;
158 if (fuse_get_ap20_hal(&hal)) {
159 if (hal.is_odm_production_mode()) {
160 printf("!!! OdmProductionMode is not supported !!!\n");
161 return nvbl_mode_undefined;
162 } else {
163 if (hal.is_nv_production_mode())
164 return nvbl_mode_production;
165 else
166 return nvbl_mode_undefined;
167 }
168 }
169 return nvbl_mode_undefined;
170 }
171
172 static NvU64 query_random_seed(void)
173 {
174 return 0;
175 }
176
177 static void determine_crypto_options(NvBool* is_encrypted, NvBool* is_signed, Nv Bool* use_zero_key)
178 {
179 switch (nv_fuse_get_operation_mode()) {
180 case nvbl_mode_production:
181 *is_encrypted = NV_FALSE;
182 *is_signed = NV_TRUE;
183 *use_zero_key = NV_TRUE;
184 break;
185
186 case nvbl_mode_undefined:
187 default:
188 *is_encrypted = NV_FALSE;
189 *is_signed = NV_FALSE;
190 *use_zero_key = NV_FALSE;
191 break;
192 }
193 }
194
195 static NvBootError sign_wb_code(NvU32 start, NvU32 length, NvBool use_zero_key)
196 {
197 NvBootError e;
198 NvU8 *source; /* Pointer to source */
199 NvU8 *hash;
200
201 /* Calculate AES block parameters. */
202 source = (NvU8 *)(start + offsetof(nvboot_wb_header, random_aes_block));
203 length -= offsetof(nvboot_wb_header, random_aes_block);
204 hash = (NvU8 *)(start + offsetof(nvboot_wb_header, hash));
205 e = sign_data_block(source, length, hash);
206 return e;
207 }
208
209 /* -------------------------------------
210 * Global Functions
211 * -------------------------------------
212 */
213
214 NvBootError prepare_wb_code(NvU32 seg_address, NvU32 seg_length)
215 {
216 NvBootError e = NvBootError_NotInitialized; /* Error code */
217
218 NvU32 start; /* start of the actual code */
219 NvU32 end; /* end of the actual code */
220 NvU32 actual_length; /* length of the actual code */
221 NvU32 length; /* length of the signed/encrypte d code */
222 nvboot_wb_header *src_header; /* Pointer to source WB0 header */
223 nvboot_wb_header *dst_header; /* Pointer to destination WB0 he ader */
224 NvBool is_encrypted; /* Segment is encrypted */
225 NvBool is_signed; /* Segment is signed */
226 NvBool use_zero_key; /* Use key of all zeros */
227
228 /* Determine crypto options. */
229 determine_crypto_options(&is_encrypted, &is_signed, &use_zero_key);
230
231 /* Get the actual code limits. */
232 start = (NvU32)wb_start;
233 end = (NvU32)wb_end;
234 actual_length = end - start;
235 length = ((actual_length + 15) >> 4) << 4;
236
237 /* The region specified by seg_address must be in SDRAM and must be
238 * nonzero in length.
239 */
240 if ((seg_length == 0) ||(seg_address == 0) ||
241 (seg_address >= AP20_IRAM_BASE)) {
242 goto fail;
243 }
244
245 /* Things must be 16-byte aligned. */
246 if ((seg_length & 0xF) || (seg_address & 0xF)) {
247 goto fail;
248 }
249
250 /* Will the code fit? */
251 if (seg_length < length) {
252 goto fail;
253 }
254
255 /* Get a pointers to the source and destination region header. */
256 src_header = (nvboot_wb_header*)start;
257 dst_header = (nvboot_wb_header*)seg_address;
258
259 /* Populate the random_aes_block as requested. */
260 #if RANDOM_AES_BLOCK_IS_RANDOM
261 {
262 NvU64 *pRandomAesBlock = (NvU64*)&(src_header->random_aes_bloc k);
263 NvU64 *pEnd = (NvU64*)(((NvU32)pRandomAesBlock) +
264 sizeof(src_header->random_aes_block));
265 do {
266 *pRandomAesBlock++ = query_random_seed();
267 } while (pRandomAesBlock < pEnd);
268 }
269 #elif RANDOM_AES_BLOCK_IS_PATTERN
270 {
271 NvU32 *pRandomAesBlock = (NvU32*)&(src_header->random_aes_bloc k);
272 NvU32 *pEnd = (NvU32*)(((NvU32)pRandomAesBlock) +
273 sizeof(src_header->random_aes_block));
274
275 do {
276 *pRandomAesBlock++ = RANDOM_AES_BLOCK_IS_PATTERN;
277 } while (pRandomAesBlock < pEnd);
278 }
279 #elif RANDOM_AES_BLOCK_IS_ZERO
280 {
281 NvU32 *pRandomAesBlock = (NvU32*)&(src_header->random_aes_bloc k);
282 NvU32 *pEnd = (NvU32*)(((NvU32)pRandomAesBlock) +
283 sizeof(src_header->random_aes_block));
284
285 do {
286 *pRandomAesBlock++ = 0;
287 } while (pRandomAesBlock < pEnd);
288 }
289 #endif
290
291 /* Populate the header. */
292 src_header->length_in_secure = length;
293 src_header->length_secure = length;
294 src_header->destination = AP20_WB0_RUN_ADDRESS;
295 src_header->entry_point = AP20_WB0_RUN_ADDRESS;
296 src_header->code_length = length - sizeof(nvboot_wb_header);
297
298 if (is_encrypted) {
299 /* Encryption is not supported */
300 printf("!!!! No Encrypion implemented!!!!\n");
301 dst_header->length_in_secure = 0;
302 e = NvBootError_Unimplemented;
303 goto fail;
304 } else {
305 /* No, just copy the code directly. */
306 memcpy(dst_header, src_header, length);
307 }
308
309 /* Clear the signature in the destination code segment. */
310 memset(&(dst_header->hash), 0, sizeof(dst_header->hash));
311
312 if (is_signed) {
313 NV_CHECK_ERROR_CLEANUP(sign_wb_code(seg_address, length, use_zer o_key));
314 }
315
316 fail:
317 if (e != NvBootError_Success)
318 printf("WB0 code is not copied to LP0 location !!! (error=0x%x)\ n", e);
319
320 return e;
321 }
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698