1b9944a77SDirk Eibach /*
2b9944a77SDirk Eibach * (C) Copyright 2013
3b9944a77SDirk Eibach * Reinhard Pfau, Guntermann & Drunck GmbH, reinhard.pfau@gdsys.cc
4b9944a77SDirk Eibach *
55b8031ccSTom Rini * SPDX-License-Identifier: GPL-2.0+
6b9944a77SDirk Eibach */
7b9944a77SDirk Eibach
8b9944a77SDirk Eibach /* TODO: some more #ifdef's to avoid unneeded code for stage 1 / stage 2 */
9b9944a77SDirk Eibach
10b9944a77SDirk Eibach #ifdef CCDM_ID_DEBUG
11b9944a77SDirk Eibach #define DEBUG
12b9944a77SDirk Eibach #endif
13b9944a77SDirk Eibach
14b9944a77SDirk Eibach #include <common.h>
15b9944a77SDirk Eibach #include <malloc.h>
16b9944a77SDirk Eibach #include <fs.h>
17b9944a77SDirk Eibach #include <i2c.h>
18b9944a77SDirk Eibach #include <mmc.h>
19b9944a77SDirk Eibach #include <tpm.h>
202b9912e6SJeroen Hofstee #include <u-boot/sha1.h>
21b9944a77SDirk Eibach #include <asm/byteorder.h>
22b9944a77SDirk Eibach #include <asm/unaligned.h>
23b9944a77SDirk Eibach #include <pca9698.h>
24b9944a77SDirk Eibach
25b9944a77SDirk Eibach #undef CCDM_FIRST_STAGE
26b9944a77SDirk Eibach #undef CCDM_SECOND_STAGE
27b9944a77SDirk Eibach #undef CCDM_AUTO_FIRST_STAGE
28b9944a77SDirk Eibach
29b9944a77SDirk Eibach #ifdef CONFIG_DEVELOP
30b9944a77SDirk Eibach #define CCDM_DEVELOP
31b9944a77SDirk Eibach #endif
32b9944a77SDirk Eibach
33b9944a77SDirk Eibach #ifdef CONFIG_TRAILBLAZER
34b9944a77SDirk Eibach #define CCDM_FIRST_STAGE
35b9944a77SDirk Eibach #undef CCDM_SECOND_STAGE
36b9944a77SDirk Eibach #else
37b9944a77SDirk Eibach #undef CCDM_FIRST_STAGE
38b9944a77SDirk Eibach #define CCDM_SECOND_STAGE
39b9944a77SDirk Eibach #endif
40b9944a77SDirk Eibach
41b9944a77SDirk Eibach #if defined(CCDM_DEVELOP) && defined(CCDM_SECOND_STAGE) && \
42b9944a77SDirk Eibach !defined(CCCM_FIRST_STAGE)
43b9944a77SDirk Eibach #define CCDM_AUTO_FIRST_STAGE
44b9944a77SDirk Eibach #endif
45b9944a77SDirk Eibach
46b9944a77SDirk Eibach /* CCDM specific contants */
47b9944a77SDirk Eibach enum {
48b9944a77SDirk Eibach /* NV indices */
49b9944a77SDirk Eibach NV_COMMON_DATA_INDEX = 0x40000001,
50b9944a77SDirk Eibach /* magics for key blob chains */
51b9944a77SDirk Eibach MAGIC_KEY_PROGRAM = 0x68726500,
52b9944a77SDirk Eibach MAGIC_HMAC = 0x68616300,
53b9944a77SDirk Eibach MAGIC_END_OF_CHAIN = 0x00000000,
54b9944a77SDirk Eibach /* sizes */
55b9944a77SDirk Eibach NV_COMMON_DATA_MIN_SIZE = 3 * sizeof(uint64_t) + 2 * sizeof(uint16_t),
56b9944a77SDirk Eibach };
57b9944a77SDirk Eibach
58b9944a77SDirk Eibach /* other constants */
59b9944a77SDirk Eibach enum {
60b9944a77SDirk Eibach ESDHC_BOOT_IMAGE_SIG_OFS = 0x40,
61b9944a77SDirk Eibach ESDHC_BOOT_IMAGE_SIZE_OFS = 0x48,
62b9944a77SDirk Eibach ESDHC_BOOT_IMAGE_ADDR_OFS = 0x50,
63b9944a77SDirk Eibach ESDHC_BOOT_IMAGE_TARGET_OFS = 0x58,
64b9944a77SDirk Eibach ESDHC_BOOT_IMAGE_ENTRY_OFS = 0x60,
65b9944a77SDirk Eibach };
66b9944a77SDirk Eibach
6735ecf752SDirk Eibach enum {
6835ecf752SDirk Eibach I2C_SOC_0 = 0,
6935ecf752SDirk Eibach I2C_SOC_1 = 1,
7035ecf752SDirk Eibach };
7135ecf752SDirk Eibach
72b9944a77SDirk Eibach struct key_program {
73b9944a77SDirk Eibach uint32_t magic;
74b9944a77SDirk Eibach uint32_t code_crc;
75b9944a77SDirk Eibach uint32_t code_size;
76b9944a77SDirk Eibach uint8_t code[];
77b9944a77SDirk Eibach };
78b9944a77SDirk Eibach
79b9944a77SDirk Eibach struct h_reg {
80b9944a77SDirk Eibach bool valid;
81b9944a77SDirk Eibach uint8_t digest[20];
82b9944a77SDirk Eibach };
83b9944a77SDirk Eibach
84b9944a77SDirk Eibach
85b9944a77SDirk Eibach enum access_mode {
86b9944a77SDirk Eibach HREG_NONE = 0,
87b9944a77SDirk Eibach HREG_RD = 1,
88b9944a77SDirk Eibach HREG_WR = 2,
89b9944a77SDirk Eibach HREG_RDWR = 3,
90b9944a77SDirk Eibach };
91b9944a77SDirk Eibach
92b9944a77SDirk Eibach /* register constants */
93b9944a77SDirk Eibach enum {
94b9944a77SDirk Eibach FIX_HREG_DEVICE_ID_HASH = 0,
95b9944a77SDirk Eibach FIX_HREG_SELF_HASH = 1,
96b9944a77SDirk Eibach FIX_HREG_STAGE2_HASH = 2,
97b9944a77SDirk Eibach FIX_HREG_VENDOR = 3,
98b9944a77SDirk Eibach COUNT_FIX_HREGS
99b9944a77SDirk Eibach };
100b9944a77SDirk Eibach
101b9944a77SDirk Eibach
102b9944a77SDirk Eibach /* hre opcodes */
103b9944a77SDirk Eibach enum {
104b9944a77SDirk Eibach /* opcodes w/o data */
105b9944a77SDirk Eibach HRE_NOP = 0x00,
106b9944a77SDirk Eibach HRE_SYNC = HRE_NOP,
107b9944a77SDirk Eibach HRE_CHECK0 = 0x01,
108b9944a77SDirk Eibach /* opcodes w/o data, w/ sync dst */
109b9944a77SDirk Eibach /* opcodes w/ data */
110b9944a77SDirk Eibach HRE_LOAD = 0x81,
111b9944a77SDirk Eibach /* opcodes w/data, w/sync dst */
112b9944a77SDirk Eibach HRE_XOR = 0xC1,
113b9944a77SDirk Eibach HRE_AND = 0xC2,
114b9944a77SDirk Eibach HRE_OR = 0xC3,
115b9944a77SDirk Eibach HRE_EXTEND = 0xC4,
116b9944a77SDirk Eibach HRE_LOADKEY = 0xC5,
117b9944a77SDirk Eibach };
118b9944a77SDirk Eibach
119b9944a77SDirk Eibach /* hre errors */
120b9944a77SDirk Eibach enum {
121b9944a77SDirk Eibach HRE_E_OK = 0,
122b9944a77SDirk Eibach HRE_E_TPM_FAILURE,
123b9944a77SDirk Eibach HRE_E_INVALID_HREG,
124b9944a77SDirk Eibach };
125b9944a77SDirk Eibach
126b9944a77SDirk Eibach static uint64_t device_id;
127b9944a77SDirk Eibach static uint64_t device_cl;
128b9944a77SDirk Eibach static uint64_t device_type;
129b9944a77SDirk Eibach
130b9944a77SDirk Eibach static uint32_t platform_key_handle;
131b9944a77SDirk Eibach
132b9944a77SDirk Eibach static void(*bl2_entry)(void);
133b9944a77SDirk Eibach
134b9944a77SDirk Eibach static struct h_reg pcr_hregs[24];
135b9944a77SDirk Eibach static struct h_reg fix_hregs[COUNT_FIX_HREGS];
136b9944a77SDirk Eibach static struct h_reg var_hregs[8];
137b9944a77SDirk Eibach static uint32_t hre_tpm_err;
138b9944a77SDirk Eibach static int hre_err = HRE_E_OK;
139b9944a77SDirk Eibach
140b9944a77SDirk Eibach #define IS_PCR_HREG(spec) ((spec) & 0x20)
141b9944a77SDirk Eibach #define IS_FIX_HREG(spec) (((spec) & 0x38) == 0x08)
142b9944a77SDirk Eibach #define IS_VAR_HREG(spec) (((spec) & 0x38) == 0x10)
143b9944a77SDirk Eibach #define HREG_IDX(spec) ((spec) & (IS_PCR_HREG(spec) ? 0x1f : 0x7))
144b9944a77SDirk Eibach
145b9944a77SDirk Eibach static const uint8_t vendor[] = "Guntermann & Drunck";
146b9944a77SDirk Eibach
147b9944a77SDirk Eibach /**
148b9944a77SDirk Eibach * @brief read a bunch of data from MMC into memory.
149b9944a77SDirk Eibach *
150b9944a77SDirk Eibach * @param mmc pointer to the mmc structure to use.
151b9944a77SDirk Eibach * @param src offset where the data starts on MMC/SD device (in bytes).
152b9944a77SDirk Eibach * @param dst pointer to the location where the read data should be stored.
153b9944a77SDirk Eibach * @param size number of bytes to read from the MMC/SD device.
154b9944a77SDirk Eibach * @return number of bytes read or -1 on error.
155b9944a77SDirk Eibach */
ccdm_mmc_read(struct mmc * mmc,u64 src,u8 * dst,int size)156b9944a77SDirk Eibach static int ccdm_mmc_read(struct mmc *mmc, u64 src, u8 *dst, int size)
157b9944a77SDirk Eibach {
158b9944a77SDirk Eibach int result = 0;
159b9944a77SDirk Eibach u32 blk_len, ofs;
160b9944a77SDirk Eibach ulong block_no, n, cnt;
161b9944a77SDirk Eibach u8 *tmp_buf = NULL;
162b9944a77SDirk Eibach
163b9944a77SDirk Eibach if (size <= 0)
164b9944a77SDirk Eibach goto end;
165b9944a77SDirk Eibach
166b9944a77SDirk Eibach blk_len = mmc->read_bl_len;
167b9944a77SDirk Eibach tmp_buf = malloc(blk_len);
168b9944a77SDirk Eibach if (!tmp_buf)
169b9944a77SDirk Eibach goto failure;
170b9944a77SDirk Eibach block_no = src / blk_len;
171b9944a77SDirk Eibach ofs = src % blk_len;
172b9944a77SDirk Eibach
173b9944a77SDirk Eibach if (ofs) {
1747c4213f6SStephen Warren n = mmc->block_dev.block_read(&mmc->block_dev, block_no++, 1,
175b9944a77SDirk Eibach tmp_buf);
176b9944a77SDirk Eibach if (!n)
177b9944a77SDirk Eibach goto failure;
178b4141195SMasahiro Yamada result = min(size, (int)(blk_len - ofs));
179b9944a77SDirk Eibach memcpy(dst, tmp_buf + ofs, result);
180b9944a77SDirk Eibach dst += result;
181b9944a77SDirk Eibach size -= result;
182b9944a77SDirk Eibach }
183b9944a77SDirk Eibach cnt = size / blk_len;
184b9944a77SDirk Eibach if (cnt) {
1857c4213f6SStephen Warren n = mmc->block_dev.block_read(&mmc->block_dev, block_no, cnt,
186b9944a77SDirk Eibach dst);
187b9944a77SDirk Eibach if (n != cnt)
188b9944a77SDirk Eibach goto failure;
189b9944a77SDirk Eibach size -= cnt * blk_len;
190b9944a77SDirk Eibach result += cnt * blk_len;
191b9944a77SDirk Eibach dst += cnt * blk_len;
192b9944a77SDirk Eibach block_no += cnt;
193b9944a77SDirk Eibach }
194b9944a77SDirk Eibach if (size) {
1957c4213f6SStephen Warren n = mmc->block_dev.block_read(&mmc->block_dev, block_no++, 1,
196b9944a77SDirk Eibach tmp_buf);
197b9944a77SDirk Eibach if (!n)
198b9944a77SDirk Eibach goto failure;
199b9944a77SDirk Eibach memcpy(dst, tmp_buf, size);
200b9944a77SDirk Eibach result += size;
201b9944a77SDirk Eibach }
202b9944a77SDirk Eibach goto end;
203b9944a77SDirk Eibach failure:
204b9944a77SDirk Eibach result = -1;
205b9944a77SDirk Eibach end:
206b9944a77SDirk Eibach if (tmp_buf)
207b9944a77SDirk Eibach free(tmp_buf);
208b9944a77SDirk Eibach return result;
209b9944a77SDirk Eibach }
210b9944a77SDirk Eibach
211b9944a77SDirk Eibach /**
212b9944a77SDirk Eibach * @brief returns a location where the 2nd stage bootloader can be(/ is) placed.
213b9944a77SDirk Eibach *
214b9944a77SDirk Eibach * @return pointer to the location for/of the 2nd stage bootloader
215b9944a77SDirk Eibach */
get_2nd_stage_bl_location(ulong target_addr)216b9944a77SDirk Eibach static u8 *get_2nd_stage_bl_location(ulong target_addr)
217b9944a77SDirk Eibach {
218b9944a77SDirk Eibach ulong addr;
219b9944a77SDirk Eibach #ifdef CCDM_SECOND_STAGE
220*bfebc8c9SSimon Glass addr = env_get_ulong("loadaddr", 16, CONFIG_LOADADDR);
221b9944a77SDirk Eibach #else
222b9944a77SDirk Eibach addr = target_addr;
223b9944a77SDirk Eibach #endif
224b9944a77SDirk Eibach return (u8 *)(addr);
225b9944a77SDirk Eibach }
226b9944a77SDirk Eibach
227b9944a77SDirk Eibach
228b9944a77SDirk Eibach #ifdef CCDM_SECOND_STAGE
229b9944a77SDirk Eibach /**
230b9944a77SDirk Eibach * @brief returns a location where the image can be(/ is) placed.
231b9944a77SDirk Eibach *
232b9944a77SDirk Eibach * @return pointer to the location for/of the image
233b9944a77SDirk Eibach */
get_image_location(void)234b9944a77SDirk Eibach static u8 *get_image_location(void)
235b9944a77SDirk Eibach {
236b9944a77SDirk Eibach ulong addr;
237b9944a77SDirk Eibach /* TODO use other area? */
238*bfebc8c9SSimon Glass addr = env_get_ulong("loadaddr", 16, CONFIG_LOADADDR);
239b9944a77SDirk Eibach return (u8 *)(addr);
240b9944a77SDirk Eibach }
241b9944a77SDirk Eibach #endif
242b9944a77SDirk Eibach
243b9944a77SDirk Eibach /**
244b9944a77SDirk Eibach * @brief get the size of a given (TPM) NV area
245b9944a77SDirk Eibach * @param index NV index of the area to get size for
246b9944a77SDirk Eibach * @param size pointer to the size
247b9944a77SDirk Eibach * @return 0 on success, != 0 on error
248b9944a77SDirk Eibach */
get_tpm_nv_size(uint32_t index,uint32_t * size)249b9944a77SDirk Eibach static int get_tpm_nv_size(uint32_t index, uint32_t *size)
250b9944a77SDirk Eibach {
251b9944a77SDirk Eibach uint32_t err;
252b9944a77SDirk Eibach uint8_t info[72];
253b9944a77SDirk Eibach uint8_t *ptr;
254b9944a77SDirk Eibach uint16_t v16;
255b9944a77SDirk Eibach
256b9944a77SDirk Eibach err = tpm_get_capability(TPM_CAP_NV_INDEX, index,
257b9944a77SDirk Eibach info, sizeof(info));
258b9944a77SDirk Eibach if (err) {
259b9944a77SDirk Eibach printf("tpm_get_capability(CAP_NV_INDEX, %08x) failed: %u\n",
260b9944a77SDirk Eibach index, err);
261b9944a77SDirk Eibach return 1;
262b9944a77SDirk Eibach }
263b9944a77SDirk Eibach
264b9944a77SDirk Eibach /* skip tag and nvIndex */
265b9944a77SDirk Eibach ptr = info + 6;
266b9944a77SDirk Eibach /* skip 2 pcr info fields */
267b9944a77SDirk Eibach v16 = get_unaligned_be16(ptr);
268b9944a77SDirk Eibach ptr += 2 + v16 + 1 + 20;
269b9944a77SDirk Eibach v16 = get_unaligned_be16(ptr);
270b9944a77SDirk Eibach ptr += 2 + v16 + 1 + 20;
271b9944a77SDirk Eibach /* skip permission and flags */
272b9944a77SDirk Eibach ptr += 6 + 3;
273b9944a77SDirk Eibach
274b9944a77SDirk Eibach *size = get_unaligned_be32(ptr);
275b9944a77SDirk Eibach return 0;
276b9944a77SDirk Eibach }
277b9944a77SDirk Eibach
278b9944a77SDirk Eibach /**
279b9944a77SDirk Eibach * @brief search for a key by usage auth and pub key hash.
280b9944a77SDirk Eibach * @param auth usage auth of the key to search for
281b9944a77SDirk Eibach * @param pubkey_digest (SHA1) hash of the pub key structure of the key
282b9944a77SDirk Eibach * @param[out] handle the handle of the key iff found
283b9944a77SDirk Eibach * @return 0 if key was found in TPM; != 0 if not.
284b9944a77SDirk Eibach */
find_key(const uint8_t auth[20],const uint8_t pubkey_digest[20],uint32_t * handle)285b9944a77SDirk Eibach static int find_key(const uint8_t auth[20], const uint8_t pubkey_digest[20],
286b9944a77SDirk Eibach uint32_t *handle)
287b9944a77SDirk Eibach {
288b9944a77SDirk Eibach uint16_t key_count;
289b9944a77SDirk Eibach uint32_t key_handles[10];
290b9944a77SDirk Eibach uint8_t buf[288];
291b9944a77SDirk Eibach uint8_t *ptr;
292b9944a77SDirk Eibach uint32_t err;
293b9944a77SDirk Eibach uint8_t digest[20];
294b9944a77SDirk Eibach size_t buf_len;
295b9944a77SDirk Eibach unsigned int i;
296b9944a77SDirk Eibach
297b9944a77SDirk Eibach /* fetch list of already loaded keys in the TPM */
298b9944a77SDirk Eibach err = tpm_get_capability(TPM_CAP_HANDLE, TPM_RT_KEY, buf, sizeof(buf));
299b9944a77SDirk Eibach if (err)
300b9944a77SDirk Eibach return -1;
301b9944a77SDirk Eibach key_count = get_unaligned_be16(buf);
302b9944a77SDirk Eibach ptr = buf + 2;
303b9944a77SDirk Eibach for (i = 0; i < key_count; ++i, ptr += 4)
304b9944a77SDirk Eibach key_handles[i] = get_unaligned_be32(ptr);
305b9944a77SDirk Eibach
306b9944a77SDirk Eibach /* now search a(/ the) key which we can access with the given auth */
307b9944a77SDirk Eibach for (i = 0; i < key_count; ++i) {
308b9944a77SDirk Eibach buf_len = sizeof(buf);
309b9944a77SDirk Eibach err = tpm_get_pub_key_oiap(key_handles[i], auth, buf, &buf_len);
310b9944a77SDirk Eibach if (err && err != TPM_AUTHFAIL)
311b9944a77SDirk Eibach return -1;
312b9944a77SDirk Eibach if (err)
313b9944a77SDirk Eibach continue;
314b9944a77SDirk Eibach sha1_csum(buf, buf_len, digest);
315b9944a77SDirk Eibach if (!memcmp(digest, pubkey_digest, 20)) {
316b9944a77SDirk Eibach *handle = key_handles[i];
317b9944a77SDirk Eibach return 0;
318b9944a77SDirk Eibach }
319b9944a77SDirk Eibach }
320b9944a77SDirk Eibach return 1;
321b9944a77SDirk Eibach }
322b9944a77SDirk Eibach
323b9944a77SDirk Eibach /**
324b9944a77SDirk Eibach * @brief read CCDM common data from TPM NV
325b9944a77SDirk Eibach * @return 0 if CCDM common data was found and read, !=0 if something failed.
326b9944a77SDirk Eibach */
read_common_data(void)327b9944a77SDirk Eibach static int read_common_data(void)
328b9944a77SDirk Eibach {
329b9944a77SDirk Eibach uint32_t size;
330b9944a77SDirk Eibach uint32_t err;
331b9944a77SDirk Eibach uint8_t buf[256];
332b9944a77SDirk Eibach sha1_context ctx;
333b9944a77SDirk Eibach
334b9944a77SDirk Eibach if (get_tpm_nv_size(NV_COMMON_DATA_INDEX, &size) ||
335b9944a77SDirk Eibach size < NV_COMMON_DATA_MIN_SIZE)
336b9944a77SDirk Eibach return 1;
337b9944a77SDirk Eibach err = tpm_nv_read_value(NV_COMMON_DATA_INDEX,
338b9944a77SDirk Eibach buf, min(sizeof(buf), size));
339b9944a77SDirk Eibach if (err) {
340b9944a77SDirk Eibach printf("tpm_nv_read_value() failed: %u\n", err);
341b9944a77SDirk Eibach return 1;
342b9944a77SDirk Eibach }
343b9944a77SDirk Eibach
344b9944a77SDirk Eibach device_id = get_unaligned_be64(buf);
345b9944a77SDirk Eibach device_cl = get_unaligned_be64(buf + 8);
346b9944a77SDirk Eibach device_type = get_unaligned_be64(buf + 16);
347b9944a77SDirk Eibach
348b9944a77SDirk Eibach sha1_starts(&ctx);
349b9944a77SDirk Eibach sha1_update(&ctx, buf, 24);
350b9944a77SDirk Eibach sha1_finish(&ctx, fix_hregs[FIX_HREG_DEVICE_ID_HASH].digest);
351b9944a77SDirk Eibach fix_hregs[FIX_HREG_DEVICE_ID_HASH].valid = true;
352b9944a77SDirk Eibach
353b9944a77SDirk Eibach platform_key_handle = get_unaligned_be32(buf + 24);
354b9944a77SDirk Eibach
355b9944a77SDirk Eibach return 0;
356b9944a77SDirk Eibach }
357b9944a77SDirk Eibach
358b9944a77SDirk Eibach /**
359b9944a77SDirk Eibach * @brief compute hash of bootloader itself.
360b9944a77SDirk Eibach * @param[out] dst hash register where the hash should be stored
361b9944a77SDirk Eibach * @return 0 on success, != 0 on failure.
362b9944a77SDirk Eibach *
363b9944a77SDirk Eibach * @note MUST be called at a time where the boot loader is accessible at the
364b9944a77SDirk Eibach * configured location (; so take care when code is reallocated).
365b9944a77SDirk Eibach */
compute_self_hash(struct h_reg * dst)366b9944a77SDirk Eibach static int compute_self_hash(struct h_reg *dst)
367b9944a77SDirk Eibach {
368b9944a77SDirk Eibach sha1_csum((const uint8_t *)CONFIG_SYS_MONITOR_BASE,
369b9944a77SDirk Eibach CONFIG_SYS_MONITOR_LEN, dst->digest);
370b9944a77SDirk Eibach dst->valid = true;
371b9944a77SDirk Eibach return 0;
372b9944a77SDirk Eibach }
373b9944a77SDirk Eibach
ccdm_compute_self_hash(void)374b9944a77SDirk Eibach int ccdm_compute_self_hash(void)
375b9944a77SDirk Eibach {
376b9944a77SDirk Eibach if (!fix_hregs[FIX_HREG_SELF_HASH].valid)
377b9944a77SDirk Eibach compute_self_hash(&fix_hregs[FIX_HREG_SELF_HASH]);
378b9944a77SDirk Eibach return 0;
379b9944a77SDirk Eibach }
380b9944a77SDirk Eibach
381b9944a77SDirk Eibach /**
382b9944a77SDirk Eibach * @brief compute the hash of the 2nd stage boot loader (on SD card)
383b9944a77SDirk Eibach * @param[out] dst hash register to store the computed hash
384b9944a77SDirk Eibach * @return 0 on success, != 0 on failure
385b9944a77SDirk Eibach *
386b9944a77SDirk Eibach * Determines the size and location of the 2nd stage boot loader on SD card,
387b9944a77SDirk Eibach * loads the 2nd stage boot loader and computes the (SHA1) hash value.
388b9944a77SDirk Eibach * Within the 1st stage boot loader, the 2nd stage boot loader is loaded at
389b9944a77SDirk Eibach * the desired memory location and the variable @a bl2_entry is set.
390b9944a77SDirk Eibach *
391b9944a77SDirk Eibach * @note This sets the variable @a bl2_entry to the entry point when the
392b9944a77SDirk Eibach * 2nd stage boot loader is loaded at its configured memory location.
393b9944a77SDirk Eibach */
compute_second_stage_hash(struct h_reg * dst)394b9944a77SDirk Eibach static int compute_second_stage_hash(struct h_reg *dst)
395b9944a77SDirk Eibach {
396b9944a77SDirk Eibach int result = 0;
397b9944a77SDirk Eibach u32 code_len, code_offset, target_addr, exec_entry;
398b9944a77SDirk Eibach struct mmc *mmc;
399b9944a77SDirk Eibach u8 *load_addr = NULL;
400b9944a77SDirk Eibach u8 buf[128];
401b9944a77SDirk Eibach
402b9944a77SDirk Eibach mmc = find_mmc_device(0);
403b9944a77SDirk Eibach if (!mmc)
404b9944a77SDirk Eibach goto failure;
405b9944a77SDirk Eibach mmc_init(mmc);
406b9944a77SDirk Eibach
407b9944a77SDirk Eibach if (ccdm_mmc_read(mmc, 0, buf, sizeof(buf)) < 0)
408b9944a77SDirk Eibach goto failure;
409b9944a77SDirk Eibach
410b9944a77SDirk Eibach code_offset = *(u32 *)(buf + ESDHC_BOOT_IMAGE_ADDR_OFS);
411b9944a77SDirk Eibach code_len = *(u32 *)(buf + ESDHC_BOOT_IMAGE_SIZE_OFS);
412b9944a77SDirk Eibach target_addr = *(u32 *)(buf + ESDHC_BOOT_IMAGE_TARGET_OFS);
413b9944a77SDirk Eibach exec_entry = *(u32 *)(buf + ESDHC_BOOT_IMAGE_ENTRY_OFS);
414b9944a77SDirk Eibach
415b9944a77SDirk Eibach load_addr = get_2nd_stage_bl_location(target_addr);
416b9944a77SDirk Eibach if (load_addr == (u8 *)target_addr)
417b9944a77SDirk Eibach bl2_entry = (void(*)(void))exec_entry;
418b9944a77SDirk Eibach
419b9944a77SDirk Eibach if (ccdm_mmc_read(mmc, code_offset, load_addr, code_len) < 0)
420b9944a77SDirk Eibach goto failure;
421b9944a77SDirk Eibach
422b9944a77SDirk Eibach sha1_csum(load_addr, code_len, dst->digest);
423b9944a77SDirk Eibach dst->valid = true;
424b9944a77SDirk Eibach
425b9944a77SDirk Eibach goto end;
426b9944a77SDirk Eibach failure:
427b9944a77SDirk Eibach result = 1;
428b9944a77SDirk Eibach bl2_entry = NULL;
429b9944a77SDirk Eibach end:
430b9944a77SDirk Eibach return result;
431b9944a77SDirk Eibach }
432b9944a77SDirk Eibach
433b9944a77SDirk Eibach /**
434b9944a77SDirk Eibach * @brief get pointer to hash register by specification
435b9944a77SDirk Eibach * @param spec specification of a hash register
436b9944a77SDirk Eibach * @return pointer to hash register or NULL if @a spec does not qualify a
437b9944a77SDirk Eibach * valid hash register; NULL else.
438b9944a77SDirk Eibach */
get_hreg(uint8_t spec)439b9944a77SDirk Eibach static struct h_reg *get_hreg(uint8_t spec)
440b9944a77SDirk Eibach {
441b9944a77SDirk Eibach uint8_t idx;
442b9944a77SDirk Eibach
443b9944a77SDirk Eibach idx = HREG_IDX(spec);
444b9944a77SDirk Eibach if (IS_FIX_HREG(spec)) {
445b9944a77SDirk Eibach if (idx < ARRAY_SIZE(fix_hregs))
446b9944a77SDirk Eibach return fix_hregs + idx;
447b9944a77SDirk Eibach hre_err = HRE_E_INVALID_HREG;
448b9944a77SDirk Eibach } else if (IS_PCR_HREG(spec)) {
449b9944a77SDirk Eibach if (idx < ARRAY_SIZE(pcr_hregs))
450b9944a77SDirk Eibach return pcr_hregs + idx;
451b9944a77SDirk Eibach hre_err = HRE_E_INVALID_HREG;
452b9944a77SDirk Eibach } else if (IS_VAR_HREG(spec)) {
453b9944a77SDirk Eibach if (idx < ARRAY_SIZE(var_hregs))
454b9944a77SDirk Eibach return var_hregs + idx;
455b9944a77SDirk Eibach hre_err = HRE_E_INVALID_HREG;
456b9944a77SDirk Eibach }
457b9944a77SDirk Eibach return NULL;
458b9944a77SDirk Eibach }
459b9944a77SDirk Eibach
460b9944a77SDirk Eibach /**
461b9944a77SDirk Eibach * @brief get pointer of a hash register by specification and usage.
462b9944a77SDirk Eibach * @param spec specification of a hash register
463b9944a77SDirk Eibach * @param mode access mode (read or write or read/write)
464b9944a77SDirk Eibach * @return pointer to hash register if found and valid; NULL else.
465b9944a77SDirk Eibach *
466b9944a77SDirk Eibach * This func uses @a get_reg() to determine the hash register for a given spec.
467b9944a77SDirk Eibach * If a register is found it is validated according to the desired access mode.
468b9944a77SDirk Eibach * The value of automatic registers (PCR register and fixed registers) is
469b9944a77SDirk Eibach * loaded or computed on read access.
470b9944a77SDirk Eibach */
access_hreg(uint8_t spec,enum access_mode mode)471b9944a77SDirk Eibach static struct h_reg *access_hreg(uint8_t spec, enum access_mode mode)
472b9944a77SDirk Eibach {
473b9944a77SDirk Eibach struct h_reg *result;
474b9944a77SDirk Eibach
475b9944a77SDirk Eibach result = get_hreg(spec);
476b9944a77SDirk Eibach if (!result)
477b9944a77SDirk Eibach return NULL;
478b9944a77SDirk Eibach
479b9944a77SDirk Eibach if (mode & HREG_WR) {
480b9944a77SDirk Eibach if (IS_FIX_HREG(spec)) {
481b9944a77SDirk Eibach hre_err = HRE_E_INVALID_HREG;
482b9944a77SDirk Eibach return NULL;
483b9944a77SDirk Eibach }
484b9944a77SDirk Eibach }
485b9944a77SDirk Eibach if (mode & HREG_RD) {
486b9944a77SDirk Eibach if (!result->valid) {
487b9944a77SDirk Eibach if (IS_PCR_HREG(spec)) {
488b9944a77SDirk Eibach hre_tpm_err = tpm_pcr_read(HREG_IDX(spec),
489b9944a77SDirk Eibach result->digest, 20);
490b9944a77SDirk Eibach result->valid = (hre_tpm_err == TPM_SUCCESS);
491b9944a77SDirk Eibach } else if (IS_FIX_HREG(spec)) {
492b9944a77SDirk Eibach switch (HREG_IDX(spec)) {
493b9944a77SDirk Eibach case FIX_HREG_DEVICE_ID_HASH:
494b9944a77SDirk Eibach read_common_data();
495b9944a77SDirk Eibach break;
496b9944a77SDirk Eibach case FIX_HREG_SELF_HASH:
497b9944a77SDirk Eibach ccdm_compute_self_hash();
498b9944a77SDirk Eibach break;
499b9944a77SDirk Eibach case FIX_HREG_STAGE2_HASH:
500b9944a77SDirk Eibach compute_second_stage_hash(result);
501b9944a77SDirk Eibach break;
502b9944a77SDirk Eibach case FIX_HREG_VENDOR:
503b9944a77SDirk Eibach memcpy(result->digest, vendor, 20);
504b9944a77SDirk Eibach result->valid = true;
505b9944a77SDirk Eibach break;
506b9944a77SDirk Eibach }
507b9944a77SDirk Eibach } else {
508b9944a77SDirk Eibach result->valid = true;
509b9944a77SDirk Eibach }
510b9944a77SDirk Eibach }
511b9944a77SDirk Eibach if (!result->valid) {
512b9944a77SDirk Eibach hre_err = HRE_E_INVALID_HREG;
513b9944a77SDirk Eibach return NULL;
514b9944a77SDirk Eibach }
515b9944a77SDirk Eibach }
516b9944a77SDirk Eibach
517b9944a77SDirk Eibach return result;
518b9944a77SDirk Eibach }
519b9944a77SDirk Eibach
compute_and(void * _dst,const void * _src,size_t n)520b9944a77SDirk Eibach static void *compute_and(void *_dst, const void *_src, size_t n)
521b9944a77SDirk Eibach {
522b9944a77SDirk Eibach uint8_t *dst = _dst;
523b9944a77SDirk Eibach const uint8_t *src = _src;
524b9944a77SDirk Eibach size_t i;
525b9944a77SDirk Eibach
526b9944a77SDirk Eibach for (i = n; i-- > 0; )
527b9944a77SDirk Eibach *dst++ &= *src++;
528b9944a77SDirk Eibach
529b9944a77SDirk Eibach return _dst;
530b9944a77SDirk Eibach }
531b9944a77SDirk Eibach
compute_or(void * _dst,const void * _src,size_t n)532b9944a77SDirk Eibach static void *compute_or(void *_dst, const void *_src, size_t n)
533b9944a77SDirk Eibach {
534b9944a77SDirk Eibach uint8_t *dst = _dst;
535b9944a77SDirk Eibach const uint8_t *src = _src;
536b9944a77SDirk Eibach size_t i;
537b9944a77SDirk Eibach
538b9944a77SDirk Eibach for (i = n; i-- > 0; )
539b9944a77SDirk Eibach *dst++ |= *src++;
540b9944a77SDirk Eibach
541b9944a77SDirk Eibach return _dst;
542b9944a77SDirk Eibach }
543b9944a77SDirk Eibach
compute_xor(void * _dst,const void * _src,size_t n)544b9944a77SDirk Eibach static void *compute_xor(void *_dst, const void *_src, size_t n)
545b9944a77SDirk Eibach {
546b9944a77SDirk Eibach uint8_t *dst = _dst;
547b9944a77SDirk Eibach const uint8_t *src = _src;
548b9944a77SDirk Eibach size_t i;
549b9944a77SDirk Eibach
550b9944a77SDirk Eibach for (i = n; i-- > 0; )
551b9944a77SDirk Eibach *dst++ ^= *src++;
552b9944a77SDirk Eibach
553b9944a77SDirk Eibach return _dst;
554b9944a77SDirk Eibach }
555b9944a77SDirk Eibach
compute_extend(void * _dst,const void * _src,size_t n)556b9944a77SDirk Eibach static void *compute_extend(void *_dst, const void *_src, size_t n)
557b9944a77SDirk Eibach {
558b9944a77SDirk Eibach uint8_t digest[20];
559b9944a77SDirk Eibach sha1_context ctx;
560b9944a77SDirk Eibach
561b9944a77SDirk Eibach sha1_starts(&ctx);
562b9944a77SDirk Eibach sha1_update(&ctx, _dst, n);
563b9944a77SDirk Eibach sha1_update(&ctx, _src, n);
564b9944a77SDirk Eibach sha1_finish(&ctx, digest);
565b9944a77SDirk Eibach memcpy(_dst, digest, min(n, sizeof(digest)));
566b9944a77SDirk Eibach
567b9944a77SDirk Eibach return _dst;
568b9944a77SDirk Eibach }
569b9944a77SDirk Eibach
hre_op_loadkey(struct h_reg * src_reg,struct h_reg * dst_reg,const void * key,size_t key_size)570b9944a77SDirk Eibach static int hre_op_loadkey(struct h_reg *src_reg, struct h_reg *dst_reg,
571b9944a77SDirk Eibach const void *key, size_t key_size)
572b9944a77SDirk Eibach {
573b9944a77SDirk Eibach uint32_t parent_handle;
574b9944a77SDirk Eibach uint32_t key_handle;
575b9944a77SDirk Eibach
576b9944a77SDirk Eibach if (!src_reg || !dst_reg || !src_reg->valid || !dst_reg->valid)
577b9944a77SDirk Eibach return -1;
578b9944a77SDirk Eibach if (find_key(src_reg->digest, dst_reg->digest, &parent_handle))
579b9944a77SDirk Eibach return -1;
580b9944a77SDirk Eibach hre_tpm_err = tpm_load_key2_oiap(parent_handle, key, key_size,
581b9944a77SDirk Eibach src_reg->digest, &key_handle);
582b9944a77SDirk Eibach if (hre_tpm_err) {
583b9944a77SDirk Eibach hre_err = HRE_E_TPM_FAILURE;
584b9944a77SDirk Eibach return -1;
585b9944a77SDirk Eibach }
586b9944a77SDirk Eibach /* TODO remember key handle somehow? */
587b9944a77SDirk Eibach
588b9944a77SDirk Eibach return 0;
589b9944a77SDirk Eibach }
590b9944a77SDirk Eibach
591b9944a77SDirk Eibach /**
592b9944a77SDirk Eibach * @brief executes the next opcode on the hash register engine.
593b9944a77SDirk Eibach * @param[in,out] ip pointer to the opcode (instruction pointer)
594b9944a77SDirk Eibach * @param[in,out] code_size (remaining) size of the code
595b9944a77SDirk Eibach * @return new instruction pointer on success, NULL on error.
596b9944a77SDirk Eibach */
hre_execute_op(const uint8_t ** ip,size_t * code_size)597b9944a77SDirk Eibach static const uint8_t *hre_execute_op(const uint8_t **ip, size_t *code_size)
598b9944a77SDirk Eibach {
599b9944a77SDirk Eibach bool dst_modified = false;
600b9944a77SDirk Eibach uint32_t ins;
601b9944a77SDirk Eibach uint8_t opcode;
602b9944a77SDirk Eibach uint8_t src_spec;
603b9944a77SDirk Eibach uint8_t dst_spec;
604b9944a77SDirk Eibach uint16_t data_size;
605b9944a77SDirk Eibach struct h_reg *src_reg, *dst_reg;
606b9944a77SDirk Eibach uint8_t buf[20];
607b9944a77SDirk Eibach const uint8_t *src_buf, *data;
608b9944a77SDirk Eibach uint8_t *ptr;
609b9944a77SDirk Eibach int i;
610b9944a77SDirk Eibach void * (*bin_func)(void *, const void *, size_t);
611b9944a77SDirk Eibach
612b9944a77SDirk Eibach if (*code_size < 4)
613b9944a77SDirk Eibach return NULL;
614b9944a77SDirk Eibach
615b9944a77SDirk Eibach ins = get_unaligned_be32(*ip);
616b9944a77SDirk Eibach opcode = **ip;
617b9944a77SDirk Eibach data = *ip + 4;
618b9944a77SDirk Eibach src_spec = (ins >> 18) & 0x3f;
619b9944a77SDirk Eibach dst_spec = (ins >> 12) & 0x3f;
620b9944a77SDirk Eibach data_size = (ins & 0x7ff);
621b9944a77SDirk Eibach
622b9944a77SDirk Eibach debug("HRE: ins=%08x (op=%02x, s=%02x, d=%02x, L=%d)\n", ins,
623b9944a77SDirk Eibach opcode, src_spec, dst_spec, data_size);
624b9944a77SDirk Eibach
625b9944a77SDirk Eibach if ((opcode & 0x80) && (data_size + 4) > *code_size)
626b9944a77SDirk Eibach return NULL;
627b9944a77SDirk Eibach
628b9944a77SDirk Eibach src_reg = access_hreg(src_spec, HREG_RD);
629b9944a77SDirk Eibach if (hre_err || hre_tpm_err)
630b9944a77SDirk Eibach return NULL;
631b9944a77SDirk Eibach dst_reg = access_hreg(dst_spec, (opcode & 0x40) ? HREG_RDWR : HREG_WR);
632b9944a77SDirk Eibach if (hre_err || hre_tpm_err)
633b9944a77SDirk Eibach return NULL;
634b9944a77SDirk Eibach
635b9944a77SDirk Eibach switch (opcode) {
636b9944a77SDirk Eibach case HRE_NOP:
637b9944a77SDirk Eibach goto end;
638b9944a77SDirk Eibach case HRE_CHECK0:
639b9944a77SDirk Eibach if (src_reg) {
640b9944a77SDirk Eibach for (i = 0; i < 20; ++i) {
641b9944a77SDirk Eibach if (src_reg->digest[i])
642b9944a77SDirk Eibach return NULL;
643b9944a77SDirk Eibach }
644b9944a77SDirk Eibach }
645b9944a77SDirk Eibach break;
646b9944a77SDirk Eibach case HRE_LOAD:
647b9944a77SDirk Eibach bin_func = memcpy;
648b9944a77SDirk Eibach goto do_bin_func;
649b9944a77SDirk Eibach case HRE_XOR:
650b9944a77SDirk Eibach bin_func = compute_xor;
651b9944a77SDirk Eibach goto do_bin_func;
652b9944a77SDirk Eibach case HRE_AND:
653b9944a77SDirk Eibach bin_func = compute_and;
654b9944a77SDirk Eibach goto do_bin_func;
655b9944a77SDirk Eibach case HRE_OR:
656b9944a77SDirk Eibach bin_func = compute_or;
657b9944a77SDirk Eibach goto do_bin_func;
658b9944a77SDirk Eibach case HRE_EXTEND:
659b9944a77SDirk Eibach bin_func = compute_extend;
660b9944a77SDirk Eibach do_bin_func:
661b9944a77SDirk Eibach if (!dst_reg)
662b9944a77SDirk Eibach return NULL;
663b9944a77SDirk Eibach if (src_reg) {
664b9944a77SDirk Eibach src_buf = src_reg->digest;
665b9944a77SDirk Eibach } else {
666b9944a77SDirk Eibach if (!data_size) {
667b9944a77SDirk Eibach memset(buf, 0, 20);
668b9944a77SDirk Eibach src_buf = buf;
669b9944a77SDirk Eibach } else if (data_size == 1) {
670b9944a77SDirk Eibach memset(buf, *data, 20);
671b9944a77SDirk Eibach src_buf = buf;
672b9944a77SDirk Eibach } else if (data_size >= 20) {
673b9944a77SDirk Eibach src_buf = data;
674b9944a77SDirk Eibach } else {
675b9944a77SDirk Eibach src_buf = buf;
676b9944a77SDirk Eibach for (ptr = (uint8_t *)src_buf, i = 20; i > 0;
677b9944a77SDirk Eibach i -= data_size, ptr += data_size)
678b4141195SMasahiro Yamada memcpy(ptr, data,
679b4141195SMasahiro Yamada min_t(size_t, i, data_size));
680b9944a77SDirk Eibach }
681b9944a77SDirk Eibach }
682b9944a77SDirk Eibach bin_func(dst_reg->digest, src_buf, 20);
683b9944a77SDirk Eibach dst_reg->valid = true;
684b9944a77SDirk Eibach dst_modified = true;
685b9944a77SDirk Eibach break;
686b9944a77SDirk Eibach case HRE_LOADKEY:
687b9944a77SDirk Eibach if (hre_op_loadkey(src_reg, dst_reg, data, data_size))
688b9944a77SDirk Eibach return NULL;
689b9944a77SDirk Eibach break;
690b9944a77SDirk Eibach default:
691b9944a77SDirk Eibach return NULL;
692b9944a77SDirk Eibach }
693b9944a77SDirk Eibach
694b9944a77SDirk Eibach if (dst_reg && dst_modified && IS_PCR_HREG(dst_spec)) {
695b9944a77SDirk Eibach hre_tpm_err = tpm_extend(HREG_IDX(dst_spec), dst_reg->digest,
696b9944a77SDirk Eibach dst_reg->digest);
697b9944a77SDirk Eibach if (hre_tpm_err) {
698b9944a77SDirk Eibach hre_err = HRE_E_TPM_FAILURE;
699b9944a77SDirk Eibach return NULL;
700b9944a77SDirk Eibach }
701b9944a77SDirk Eibach }
702b9944a77SDirk Eibach end:
703b9944a77SDirk Eibach *ip += 4;
704b9944a77SDirk Eibach *code_size -= 4;
705b9944a77SDirk Eibach if (opcode & 0x80) {
706b9944a77SDirk Eibach *ip += data_size;
707b9944a77SDirk Eibach *code_size -= data_size;
708b9944a77SDirk Eibach }
709b9944a77SDirk Eibach
710b9944a77SDirk Eibach return *ip;
711b9944a77SDirk Eibach }
712b9944a77SDirk Eibach
713b9944a77SDirk Eibach /**
714b9944a77SDirk Eibach * @brief runs a program on the hash register engine.
715b9944a77SDirk Eibach * @param code pointer to the (HRE) code.
716b9944a77SDirk Eibach * @param code_size size of the code (in bytes).
717b9944a77SDirk Eibach * @return 0 on success, != 0 on failure.
718b9944a77SDirk Eibach */
hre_run_program(const uint8_t * code,size_t code_size)719b9944a77SDirk Eibach static int hre_run_program(const uint8_t *code, size_t code_size)
720b9944a77SDirk Eibach {
721b9944a77SDirk Eibach size_t code_left;
722b9944a77SDirk Eibach const uint8_t *ip = code;
723b9944a77SDirk Eibach
724b9944a77SDirk Eibach code_left = code_size;
725b9944a77SDirk Eibach hre_tpm_err = 0;
726b9944a77SDirk Eibach hre_err = HRE_E_OK;
727b9944a77SDirk Eibach while (code_left > 0)
728b9944a77SDirk Eibach if (!hre_execute_op(&ip, &code_left))
729b9944a77SDirk Eibach return -1;
730b9944a77SDirk Eibach
731b9944a77SDirk Eibach return hre_err;
732b9944a77SDirk Eibach }
733b9944a77SDirk Eibach
check_hmac(struct key_program * hmac,const uint8_t * data,size_t data_size)734b9944a77SDirk Eibach static int check_hmac(struct key_program *hmac,
735b9944a77SDirk Eibach const uint8_t *data, size_t data_size)
736b9944a77SDirk Eibach {
737b9944a77SDirk Eibach uint8_t key[20], computed_hmac[20];
738b9944a77SDirk Eibach uint32_t type;
739b9944a77SDirk Eibach
740b9944a77SDirk Eibach type = get_unaligned_be32(hmac->code);
741b9944a77SDirk Eibach if (type != 0)
742b9944a77SDirk Eibach return 1;
743b9944a77SDirk Eibach memset(key, 0, sizeof(key));
744b9944a77SDirk Eibach compute_extend(key, pcr_hregs[1].digest, 20);
745b9944a77SDirk Eibach compute_extend(key, pcr_hregs[2].digest, 20);
746b9944a77SDirk Eibach compute_extend(key, pcr_hregs[3].digest, 20);
747b9944a77SDirk Eibach compute_extend(key, pcr_hregs[4].digest, 20);
748b9944a77SDirk Eibach
749b9944a77SDirk Eibach sha1_hmac(key, sizeof(key), data, data_size, computed_hmac);
750b9944a77SDirk Eibach
751b9944a77SDirk Eibach return memcmp(computed_hmac, hmac->code + 4, 20);
752b9944a77SDirk Eibach }
753b9944a77SDirk Eibach
verify_program(struct key_program * prg)754b9944a77SDirk Eibach static int verify_program(struct key_program *prg)
755b9944a77SDirk Eibach {
756b9944a77SDirk Eibach uint32_t crc;
757b9944a77SDirk Eibach crc = crc32(0, prg->code, prg->code_size);
758b9944a77SDirk Eibach
759b9944a77SDirk Eibach if (crc != prg->code_crc) {
760b9944a77SDirk Eibach printf("HRC crc mismatch: %08x != %08x\n",
761b9944a77SDirk Eibach crc, prg->code_crc);
762b9944a77SDirk Eibach return 1;
763b9944a77SDirk Eibach }
764b9944a77SDirk Eibach return 0;
765b9944a77SDirk Eibach }
766b9944a77SDirk Eibach
767b9944a77SDirk Eibach #if defined(CCDM_FIRST_STAGE) || (defined CCDM_AUTO_FIRST_STAGE)
load_sd_key_program(void)768b9944a77SDirk Eibach static struct key_program *load_sd_key_program(void)
769b9944a77SDirk Eibach {
770b9944a77SDirk Eibach u32 code_len, code_offset;
771b9944a77SDirk Eibach struct mmc *mmc;
772b9944a77SDirk Eibach u8 buf[128];
773b9944a77SDirk Eibach struct key_program *result = NULL, *hmac = NULL;
774b9944a77SDirk Eibach struct key_program header;
775b9944a77SDirk Eibach
776b9944a77SDirk Eibach mmc = find_mmc_device(0);
777b9944a77SDirk Eibach if (!mmc)
778b9944a77SDirk Eibach return NULL;
779b9944a77SDirk Eibach mmc_init(mmc);
780b9944a77SDirk Eibach
781b9944a77SDirk Eibach if (ccdm_mmc_read(mmc, 0, buf, sizeof(buf)) <= 0)
782b9944a77SDirk Eibach goto failure;
783b9944a77SDirk Eibach
784b9944a77SDirk Eibach code_offset = *(u32 *)(buf + ESDHC_BOOT_IMAGE_ADDR_OFS);
785b9944a77SDirk Eibach code_len = *(u32 *)(buf + ESDHC_BOOT_IMAGE_SIZE_OFS);
786b9944a77SDirk Eibach
787b9944a77SDirk Eibach code_offset += code_len;
788b9944a77SDirk Eibach /* TODO: the following needs to be the size of the 2nd stage env */
789b9944a77SDirk Eibach code_offset += CONFIG_ENV_SIZE;
790b9944a77SDirk Eibach
791b9944a77SDirk Eibach if (ccdm_mmc_read(mmc, code_offset, buf, 4*3) < 0)
792b9944a77SDirk Eibach goto failure;
793b9944a77SDirk Eibach
794b9944a77SDirk Eibach header.magic = get_unaligned_be32(buf);
795b9944a77SDirk Eibach header.code_crc = get_unaligned_be32(buf + 4);
796b9944a77SDirk Eibach header.code_size = get_unaligned_be32(buf + 8);
797b9944a77SDirk Eibach
798b9944a77SDirk Eibach if (header.magic != MAGIC_KEY_PROGRAM)
799b9944a77SDirk Eibach goto failure;
800b9944a77SDirk Eibach
801b9944a77SDirk Eibach result = malloc(sizeof(struct key_program) + header.code_size);
802b9944a77SDirk Eibach if (!result)
803b9944a77SDirk Eibach goto failure;
804b9944a77SDirk Eibach *result = header;
805b9944a77SDirk Eibach
806b9944a77SDirk Eibach printf("load key program chunk from SD card (%u bytes) ",
807b9944a77SDirk Eibach header.code_size);
808b9944a77SDirk Eibach code_offset += 12;
809b9944a77SDirk Eibach if (ccdm_mmc_read(mmc, code_offset, result->code, header.code_size)
810b9944a77SDirk Eibach < 0)
811b9944a77SDirk Eibach goto failure;
812b9944a77SDirk Eibach code_offset += header.code_size;
813b9944a77SDirk Eibach puts("\n");
814b9944a77SDirk Eibach
815b9944a77SDirk Eibach if (verify_program(result))
816b9944a77SDirk Eibach goto failure;
817b9944a77SDirk Eibach
818b9944a77SDirk Eibach if (ccdm_mmc_read(mmc, code_offset, buf, 4*3) < 0)
819b9944a77SDirk Eibach goto failure;
820b9944a77SDirk Eibach
821b9944a77SDirk Eibach header.magic = get_unaligned_be32(buf);
822b9944a77SDirk Eibach header.code_crc = get_unaligned_be32(buf + 4);
823b9944a77SDirk Eibach header.code_size = get_unaligned_be32(buf + 8);
824b9944a77SDirk Eibach
825b9944a77SDirk Eibach if (header.magic == MAGIC_HMAC) {
826b9944a77SDirk Eibach puts("check integrity\n");
827b9944a77SDirk Eibach hmac = malloc(sizeof(struct key_program) + header.code_size);
828b9944a77SDirk Eibach if (!hmac)
829b9944a77SDirk Eibach goto failure;
830b9944a77SDirk Eibach *hmac = header;
831b9944a77SDirk Eibach code_offset += 12;
832b9944a77SDirk Eibach if (ccdm_mmc_read(mmc, code_offset, hmac->code,
833b9944a77SDirk Eibach hmac->code_size) < 0)
834b9944a77SDirk Eibach goto failure;
835b9944a77SDirk Eibach if (verify_program(hmac))
836b9944a77SDirk Eibach goto failure;
837b9944a77SDirk Eibach if (check_hmac(hmac, result->code, result->code_size)) {
838b9944a77SDirk Eibach puts("key program integrity could not be verified\n");
839b9944a77SDirk Eibach goto failure;
840b9944a77SDirk Eibach }
841b9944a77SDirk Eibach puts("key program verified\n");
842b9944a77SDirk Eibach }
843b9944a77SDirk Eibach
844b9944a77SDirk Eibach goto end;
845b9944a77SDirk Eibach failure:
846b9944a77SDirk Eibach if (result)
847b9944a77SDirk Eibach free(result);
848b9944a77SDirk Eibach result = NULL;
849b9944a77SDirk Eibach end:
850b9944a77SDirk Eibach if (hmac)
851b9944a77SDirk Eibach free(hmac);
852b9944a77SDirk Eibach
853b9944a77SDirk Eibach return result;
854b9944a77SDirk Eibach }
855b9944a77SDirk Eibach #endif
856b9944a77SDirk Eibach
857b9944a77SDirk Eibach #ifdef CCDM_SECOND_STAGE
858b9944a77SDirk Eibach /**
859b9944a77SDirk Eibach * @brief load a key program from file system.
860b9944a77SDirk Eibach * @param ifname interface of the file system
861b9944a77SDirk Eibach * @param dev_part_str device part of the file system
862b9944a77SDirk Eibach * @param fs_type tyep of the file system
863b9944a77SDirk Eibach * @param path path of the file to load.
864b9944a77SDirk Eibach * @return the loaded structure or NULL on failure.
865b9944a77SDirk Eibach */
load_key_chunk(const char * ifname,const char * dev_part_str,int fs_type,const char * path)866b9944a77SDirk Eibach static struct key_program *load_key_chunk(const char *ifname,
867b9944a77SDirk Eibach const char *dev_part_str, int fs_type,
868b9944a77SDirk Eibach const char *path)
869b9944a77SDirk Eibach {
870b9944a77SDirk Eibach struct key_program *result = NULL;
871b9944a77SDirk Eibach struct key_program header;
872b9944a77SDirk Eibach uint32_t crc;
873b9944a77SDirk Eibach uint8_t buf[12];
874d455d878SSuriyan Ramasami loff_t i;
875b9944a77SDirk Eibach
876b9944a77SDirk Eibach if (fs_set_blk_dev(ifname, dev_part_str, fs_type))
877b9944a77SDirk Eibach goto failure;
878d455d878SSuriyan Ramasami if (fs_read(path, (ulong)buf, 0, 12, &i) < 0)
879d455d878SSuriyan Ramasami goto failure;
880b9944a77SDirk Eibach if (i < 12)
881b9944a77SDirk Eibach goto failure;
882b9944a77SDirk Eibach header.magic = get_unaligned_be32(buf);
883b9944a77SDirk Eibach header.code_crc = get_unaligned_be32(buf + 4);
884b9944a77SDirk Eibach header.code_size = get_unaligned_be32(buf + 8);
885b9944a77SDirk Eibach
886b9944a77SDirk Eibach if (header.magic != MAGIC_HMAC && header.magic != MAGIC_KEY_PROGRAM)
887b9944a77SDirk Eibach goto failure;
888b9944a77SDirk Eibach
889b9944a77SDirk Eibach result = malloc(sizeof(struct key_program) + header.code_size);
890b9944a77SDirk Eibach if (!result)
891b9944a77SDirk Eibach goto failure;
892b9944a77SDirk Eibach if (fs_set_blk_dev(ifname, dev_part_str, fs_type))
893b9944a77SDirk Eibach goto failure;
894d455d878SSuriyan Ramasami if (fs_read(path, (ulong)result, 0,
895d455d878SSuriyan Ramasami sizeof(struct key_program) + header.code_size, &i) < 0)
896d455d878SSuriyan Ramasami goto failure;
897b9944a77SDirk Eibach if (i <= 0)
898b9944a77SDirk Eibach goto failure;
899b9944a77SDirk Eibach *result = header;
900b9944a77SDirk Eibach
901b9944a77SDirk Eibach crc = crc32(0, result->code, result->code_size);
902b9944a77SDirk Eibach
903b9944a77SDirk Eibach if (crc != result->code_crc) {
904b9944a77SDirk Eibach printf("%s: HRC crc mismatch: %08x != %08x\n",
905b9944a77SDirk Eibach path, crc, result->code_crc);
906b9944a77SDirk Eibach goto failure;
907b9944a77SDirk Eibach }
908b9944a77SDirk Eibach goto end;
909b9944a77SDirk Eibach failure:
910b9944a77SDirk Eibach if (result) {
911b9944a77SDirk Eibach free(result);
912b9944a77SDirk Eibach result = NULL;
913b9944a77SDirk Eibach }
914b9944a77SDirk Eibach end:
915b9944a77SDirk Eibach return result;
916b9944a77SDirk Eibach }
917b9944a77SDirk Eibach #endif
918b9944a77SDirk Eibach
919b9944a77SDirk Eibach #if defined(CCDM_FIRST_STAGE) || (defined CCDM_AUTO_FIRST_STAGE)
9203a97763aSTom Rini static const uint8_t prg_stage1_prepare[] = {
9213a97763aSTom Rini 0x00, 0x20, 0x00, 0x00, /* opcode: SYNC f0 */
9223a97763aSTom Rini 0x00, 0x24, 0x00, 0x00, /* opcode: SYNC f1 */
9233a97763aSTom Rini 0x01, 0x80, 0x00, 0x00, /* opcode: CHECK0 PCR0 */
9243a97763aSTom Rini 0x81, 0x22, 0x00, 0x00, /* opcode: LOAD PCR0, f0 */
9253a97763aSTom Rini 0x01, 0x84, 0x00, 0x00, /* opcode: CHECK0 PCR1 */
9263a97763aSTom Rini 0x81, 0x26, 0x10, 0x00, /* opcode: LOAD PCR1, f1 */
9273a97763aSTom Rini 0x01, 0x88, 0x00, 0x00, /* opcode: CHECK0 PCR2 */
9283a97763aSTom Rini 0x81, 0x2a, 0x20, 0x00, /* opcode: LOAD PCR2, f2 */
9293a97763aSTom Rini 0x01, 0x8c, 0x00, 0x00, /* opcode: CHECK0 PCR3 */
9303a97763aSTom Rini 0x81, 0x2e, 0x30, 0x00, /* opcode: LOAD PCR3, f3 */
9313a97763aSTom Rini };
9323a97763aSTom Rini
first_stage_actions(void)933b9944a77SDirk Eibach static int first_stage_actions(void)
934b9944a77SDirk Eibach {
935b9944a77SDirk Eibach int result = 0;
936b9944a77SDirk Eibach struct key_program *sd_prg = NULL;
937b9944a77SDirk Eibach
938b9944a77SDirk Eibach puts("CCDM S1: start actions\n");
939b9944a77SDirk Eibach #ifndef CCDM_SECOND_STAGE
940b9944a77SDirk Eibach if (tpm_continue_self_test())
941b9944a77SDirk Eibach goto failure;
942b9944a77SDirk Eibach #else
943b9944a77SDirk Eibach tpm_continue_self_test();
944b9944a77SDirk Eibach #endif
945b9944a77SDirk Eibach mdelay(37);
946b9944a77SDirk Eibach
947b9944a77SDirk Eibach if (hre_run_program(prg_stage1_prepare, sizeof(prg_stage1_prepare)))
948b9944a77SDirk Eibach goto failure;
949b9944a77SDirk Eibach
950b9944a77SDirk Eibach sd_prg = load_sd_key_program();
951b9944a77SDirk Eibach if (sd_prg) {
952b9944a77SDirk Eibach if (hre_run_program(sd_prg->code, sd_prg->code_size))
953b9944a77SDirk Eibach goto failure;
954b9944a77SDirk Eibach puts("SD code run successfully\n");
955b9944a77SDirk Eibach } else {
956b9944a77SDirk Eibach puts("no key program found on SD\n");
957b9944a77SDirk Eibach goto failure;
958b9944a77SDirk Eibach }
959b9944a77SDirk Eibach goto end;
960b9944a77SDirk Eibach failure:
961b9944a77SDirk Eibach result = 1;
962b9944a77SDirk Eibach end:
963b9944a77SDirk Eibach if (sd_prg)
964b9944a77SDirk Eibach free(sd_prg);
965b9944a77SDirk Eibach printf("CCDM S1: actions done (%d)\n", result);
966b9944a77SDirk Eibach return result;
967b9944a77SDirk Eibach }
968b9944a77SDirk Eibach #endif
969b9944a77SDirk Eibach
970b9944a77SDirk Eibach #ifdef CCDM_FIRST_STAGE
first_stage_init(void)971b9944a77SDirk Eibach static int first_stage_init(void)
972b9944a77SDirk Eibach {
973b9944a77SDirk Eibach int res = 0;
974b9944a77SDirk Eibach puts("CCDM S1\n");
975b9944a77SDirk Eibach if (tpm_init() || tpm_startup(TPM_ST_CLEAR))
976b9944a77SDirk Eibach return 1;
977b9944a77SDirk Eibach res = first_stage_actions();
978b9944a77SDirk Eibach #ifndef CCDM_SECOND_STAGE
979b9944a77SDirk Eibach if (!res) {
980b9944a77SDirk Eibach if (bl2_entry)
981b9944a77SDirk Eibach (*bl2_entry)();
982b9944a77SDirk Eibach res = 1;
983b9944a77SDirk Eibach }
984b9944a77SDirk Eibach #endif
985b9944a77SDirk Eibach return res;
986b9944a77SDirk Eibach }
987b9944a77SDirk Eibach #endif
988b9944a77SDirk Eibach
989b9944a77SDirk Eibach #ifdef CCDM_SECOND_STAGE
9900f160f66STom Rini static const uint8_t prg_stage2_prepare[] = {
9910f160f66STom Rini 0x00, 0x80, 0x00, 0x00, /* opcode: SYNC PCR0 */
9920f160f66STom Rini 0x00, 0x84, 0x00, 0x00, /* opcode: SYNC PCR1 */
9930f160f66STom Rini 0x00, 0x88, 0x00, 0x00, /* opcode: SYNC PCR2 */
9940f160f66STom Rini 0x00, 0x8c, 0x00, 0x00, /* opcode: SYNC PCR3 */
9950f160f66STom Rini 0x00, 0x90, 0x00, 0x00, /* opcode: SYNC PCR4 */
9960f160f66STom Rini };
9970f160f66STom Rini
9980f160f66STom Rini static const uint8_t prg_stage2_success[] = {
9990f160f66STom Rini 0x81, 0x02, 0x40, 0x14, /* opcode: LOAD PCR4, #<20B data> */
10000f160f66STom Rini 0x48, 0xfd, 0x95, 0x17, 0xe7, 0x54, 0x6b, 0x68, /* data */
10010f160f66STom Rini 0x92, 0x31, 0x18, 0x05, 0xf8, 0x58, 0x58, 0x3c, /* data */
10020f160f66STom Rini 0xe4, 0xd2, 0x81, 0xe0, /* data */
10030f160f66STom Rini };
10040f160f66STom Rini
10050f160f66STom Rini static const uint8_t prg_stage_fail[] = {
10060f160f66STom Rini 0x81, 0x01, 0x00, 0x14, /* opcode: LOAD v0, #<20B data> */
10070f160f66STom Rini 0xc0, 0x32, 0xad, 0xc1, 0xff, 0x62, 0x9c, 0x9b, /* data */
10080f160f66STom Rini 0x66, 0xf2, 0x27, 0x49, 0xad, 0x66, 0x7e, 0x6b, /* data */
10090f160f66STom Rini 0xea, 0xdf, 0x14, 0x4b, /* data */
10100f160f66STom Rini 0x81, 0x42, 0x30, 0x00, /* opcode: LOAD PCR3, v0 */
10110f160f66STom Rini 0x81, 0x42, 0x40, 0x00, /* opcode: LOAD PCR4, v0 */
10120f160f66STom Rini };
10130f160f66STom Rini
second_stage_init(void)1014b9944a77SDirk Eibach static int second_stage_init(void)
1015b9944a77SDirk Eibach {
1016b9944a77SDirk Eibach static const char mac_suffix[] = ".mac";
1017b9944a77SDirk Eibach bool did_first_stage_run = true;
1018b9944a77SDirk Eibach int result = 0;
1019b9944a77SDirk Eibach char *cptr, *mmcdev = NULL;
1020b9944a77SDirk Eibach struct key_program *hmac_blob = NULL;
1021b9944a77SDirk Eibach const char *image_path = "/ccdm.itb";
1022b9944a77SDirk Eibach char *mac_path = NULL;
1023b9944a77SDirk Eibach ulong image_addr;
1024d455d878SSuriyan Ramasami loff_t image_size;
1025b9944a77SDirk Eibach uint32_t err;
1026b9944a77SDirk Eibach
1027b9944a77SDirk Eibach printf("CCDM S2\n");
1028b9944a77SDirk Eibach if (tpm_init())
1029b9944a77SDirk Eibach return 1;
1030b9944a77SDirk Eibach err = tpm_startup(TPM_ST_CLEAR);
1031b9944a77SDirk Eibach if (err != TPM_INVALID_POSTINIT)
1032b9944a77SDirk Eibach did_first_stage_run = false;
1033b9944a77SDirk Eibach
1034b9944a77SDirk Eibach #ifdef CCDM_AUTO_FIRST_STAGE
1035b9944a77SDirk Eibach if (!did_first_stage_run && first_stage_actions())
1036b9944a77SDirk Eibach goto failure;
1037b9944a77SDirk Eibach #else
1038b9944a77SDirk Eibach if (!did_first_stage_run)
1039b9944a77SDirk Eibach goto failure;
1040b9944a77SDirk Eibach #endif
1041b9944a77SDirk Eibach
1042b9944a77SDirk Eibach if (hre_run_program(prg_stage2_prepare, sizeof(prg_stage2_prepare)))
1043b9944a77SDirk Eibach goto failure;
1044b9944a77SDirk Eibach
1045b9944a77SDirk Eibach /* run "prepboot" from env to get "mmcdev" set */
104600caae6dSSimon Glass cptr = env_get("prepboot");
1047b9944a77SDirk Eibach if (cptr && !run_command(cptr, 0))
104800caae6dSSimon Glass mmcdev = env_get("mmcdev");
1049b9944a77SDirk Eibach if (!mmcdev)
1050b9944a77SDirk Eibach goto failure;
1051b9944a77SDirk Eibach
105200caae6dSSimon Glass cptr = env_get("ramdiskimage");
1053b9944a77SDirk Eibach if (cptr)
1054b9944a77SDirk Eibach image_path = cptr;
1055b9944a77SDirk Eibach
1056b9944a77SDirk Eibach mac_path = malloc(strlen(image_path) + strlen(mac_suffix) + 1);
1057b9944a77SDirk Eibach if (mac_path == NULL)
1058b9944a77SDirk Eibach goto failure;
1059b9944a77SDirk Eibach strcpy(mac_path, image_path);
1060b9944a77SDirk Eibach strcat(mac_path, mac_suffix);
1061b9944a77SDirk Eibach
1062b9944a77SDirk Eibach /* read image from mmcdev (ccdm.itb) */
1063b9944a77SDirk Eibach image_addr = (ulong)get_image_location();
1064b9944a77SDirk Eibach if (fs_set_blk_dev("mmc", mmcdev, FS_TYPE_EXT))
1065b9944a77SDirk Eibach goto failure;
1066d455d878SSuriyan Ramasami if (fs_read(image_path, image_addr, 0, 0, &image_size) < 0)
1067d455d878SSuriyan Ramasami goto failure;
1068b9944a77SDirk Eibach if (image_size <= 0)
1069b9944a77SDirk Eibach goto failure;
1070d455d878SSuriyan Ramasami printf("CCDM image found on %s, %lld bytes\n", mmcdev, image_size);
1071b9944a77SDirk Eibach
1072b9944a77SDirk Eibach hmac_blob = load_key_chunk("mmc", mmcdev, FS_TYPE_EXT, mac_path);
1073b9944a77SDirk Eibach if (!hmac_blob) {
1074b9944a77SDirk Eibach puts("failed to load mac file\n");
1075b9944a77SDirk Eibach goto failure;
1076b9944a77SDirk Eibach }
1077b9944a77SDirk Eibach if (verify_program(hmac_blob)) {
1078b9944a77SDirk Eibach puts("corrupted mac file\n");
1079b9944a77SDirk Eibach goto failure;
1080b9944a77SDirk Eibach }
1081b9944a77SDirk Eibach if (check_hmac(hmac_blob, (u8 *)image_addr, image_size)) {
1082b9944a77SDirk Eibach puts("image integrity could not be verified\n");
1083b9944a77SDirk Eibach goto failure;
1084b9944a77SDirk Eibach }
1085b9944a77SDirk Eibach puts("CCDM image OK\n");
1086b9944a77SDirk Eibach
1087b9944a77SDirk Eibach hre_run_program(prg_stage2_success, sizeof(prg_stage2_success));
1088b9944a77SDirk Eibach
1089b9944a77SDirk Eibach goto end;
1090b9944a77SDirk Eibach failure:
1091b9944a77SDirk Eibach result = 1;
1092b9944a77SDirk Eibach hre_run_program(prg_stage_fail, sizeof(prg_stage_fail));
1093b9944a77SDirk Eibach end:
1094b9944a77SDirk Eibach if (hmac_blob)
1095b9944a77SDirk Eibach free(hmac_blob);
1096b9944a77SDirk Eibach if (mac_path)
1097b9944a77SDirk Eibach free(mac_path);
1098b9944a77SDirk Eibach
1099b9944a77SDirk Eibach return result;
1100b9944a77SDirk Eibach }
1101b9944a77SDirk Eibach #endif
1102b9944a77SDirk Eibach
show_self_hash(void)1103b9944a77SDirk Eibach int show_self_hash(void)
1104b9944a77SDirk Eibach {
1105b9944a77SDirk Eibach struct h_reg *hash_ptr;
1106b9944a77SDirk Eibach #ifdef CCDM_SECOND_STAGE
1107b9944a77SDirk Eibach struct h_reg hash;
1108b9944a77SDirk Eibach
1109b9944a77SDirk Eibach hash_ptr = &hash;
1110b9944a77SDirk Eibach if (compute_self_hash(hash_ptr))
1111b9944a77SDirk Eibach return 1;
1112b9944a77SDirk Eibach #else
1113b9944a77SDirk Eibach hash_ptr = &fix_hregs[FIX_HREG_SELF_HASH];
1114b9944a77SDirk Eibach #endif
1115b9944a77SDirk Eibach puts("self hash: ");
1116b9944a77SDirk Eibach if (hash_ptr && hash_ptr->valid)
1117b9944a77SDirk Eibach print_buffer(0, hash_ptr->digest, 1, 20, 20);
1118b9944a77SDirk Eibach else
1119b9944a77SDirk Eibach puts("INVALID\n");
1120b9944a77SDirk Eibach
1121b9944a77SDirk Eibach return 0;
1122b9944a77SDirk Eibach }
1123b9944a77SDirk Eibach
1124b9944a77SDirk Eibach /**
1125b9944a77SDirk Eibach * @brief let the system hang.
1126b9944a77SDirk Eibach *
1127b9944a77SDirk Eibach * Called on error.
1128b9944a77SDirk Eibach * Will stop the boot process; display a message and signal the error condition
1129b9944a77SDirk Eibach * by blinking the "status" and the "finder" LED of the controller board.
1130b9944a77SDirk Eibach *
1131b9944a77SDirk Eibach * @note the develop version runs the blink cycle 2 times and then returns.
1132b9944a77SDirk Eibach * The release version never returns.
1133b9944a77SDirk Eibach */
ccdm_hang(void)1134b9944a77SDirk Eibach static void ccdm_hang(void)
1135b9944a77SDirk Eibach {
1136b9944a77SDirk Eibach static const u64 f0 = 0x0ba3bb8ba2e880; /* blink code "finder" LED */
1137b9944a77SDirk Eibach static const u64 s0 = 0x00f0f0f0f0f0f0; /* blink code "status" LED */
1138b9944a77SDirk Eibach u64 f, s;
1139b9944a77SDirk Eibach int i;
1140b9944a77SDirk Eibach #ifdef CCDM_DEVELOP
1141b9944a77SDirk Eibach int j;
1142b9944a77SDirk Eibach #endif
1143b9944a77SDirk Eibach
114435ecf752SDirk Eibach I2C_SET_BUS(I2C_SOC_0);
1145b9944a77SDirk Eibach pca9698_direction_output(0x22, 0, 0); /* Finder */
1146b9944a77SDirk Eibach pca9698_direction_output(0x22, 4, 0); /* Status */
1147b9944a77SDirk Eibach
1148b9944a77SDirk Eibach puts("### ERROR ### Please RESET the board ###\n");
1149b9944a77SDirk Eibach bootstage_error(BOOTSTAGE_ID_NEED_RESET);
1150b9944a77SDirk Eibach #ifdef CCDM_DEVELOP
1151b9944a77SDirk Eibach puts("*** ERROR ******** THIS WOULD HANG ******** ERROR ***\n");
1152b9944a77SDirk Eibach puts("** but we continue since this is a DEVELOP version **\n");
1153b9944a77SDirk Eibach puts("*** ERROR ******** THIS WOULD HANG ******** ERROR ***\n");
1154b9944a77SDirk Eibach for (j = 2; j-- > 0;) {
1155b9944a77SDirk Eibach putc('#');
1156b9944a77SDirk Eibach #else
1157b9944a77SDirk Eibach for (;;) {
1158b9944a77SDirk Eibach #endif
1159b9944a77SDirk Eibach f = f0;
1160b9944a77SDirk Eibach s = s0;
1161b9944a77SDirk Eibach for (i = 54; i-- > 0;) {
1162b9944a77SDirk Eibach pca9698_set_value(0x22, 0, !(f & 1));
1163b9944a77SDirk Eibach pca9698_set_value(0x22, 4, (s & 1));
1164b9944a77SDirk Eibach f >>= 1;
1165b9944a77SDirk Eibach s >>= 1;
1166b9944a77SDirk Eibach mdelay(120);
1167b9944a77SDirk Eibach }
1168b9944a77SDirk Eibach }
1169b9944a77SDirk Eibach puts("\ncontinue...\n");
1170b9944a77SDirk Eibach }
1171b9944a77SDirk Eibach
1172b9944a77SDirk Eibach int startup_ccdm_id_module(void)
1173b9944a77SDirk Eibach {
1174b9944a77SDirk Eibach int result = 0;
1175b9944a77SDirk Eibach unsigned int orig_i2c_bus;
1176b9944a77SDirk Eibach
117735ecf752SDirk Eibach orig_i2c_bus = i2c_get_bus_num();
117835ecf752SDirk Eibach i2c_set_bus_num(I2C_SOC_1);
1179b9944a77SDirk Eibach
1180b9944a77SDirk Eibach /* goto end; */
1181b9944a77SDirk Eibach
1182b9944a77SDirk Eibach #ifdef CCDM_DEVELOP
1183b9944a77SDirk Eibach show_self_hash();
1184b9944a77SDirk Eibach #endif
1185b9944a77SDirk Eibach #ifdef CCDM_FIRST_STAGE
1186b9944a77SDirk Eibach result = first_stage_init();
1187b9944a77SDirk Eibach if (result) {
1188b9944a77SDirk Eibach puts("1st stage init failed\n");
1189b9944a77SDirk Eibach goto failure;
1190b9944a77SDirk Eibach }
1191b9944a77SDirk Eibach #endif
1192b9944a77SDirk Eibach #ifdef CCDM_SECOND_STAGE
1193b9944a77SDirk Eibach result = second_stage_init();
1194b9944a77SDirk Eibach if (result) {
1195b9944a77SDirk Eibach puts("2nd stage init failed\n");
1196b9944a77SDirk Eibach goto failure;
1197b9944a77SDirk Eibach }
1198b9944a77SDirk Eibach #endif
1199b9944a77SDirk Eibach
1200b9944a77SDirk Eibach goto end;
1201b9944a77SDirk Eibach failure:
1202b9944a77SDirk Eibach result = 1;
1203b9944a77SDirk Eibach end:
120435ecf752SDirk Eibach i2c_set_bus_num(orig_i2c_bus);
1205b9944a77SDirk Eibach if (result)
1206b9944a77SDirk Eibach ccdm_hang();
1207b9944a77SDirk Eibach
1208b9944a77SDirk Eibach return result;
1209b9944a77SDirk Eibach }
1210