8dee595eaf85359bcf6a128fba2b088cc77cbbee
[karo-tx-uboot.git] / arch / arm / cpu / armv7 / mx6 / hab.c
1 /*
2  * Copyright (C) 2010-2014 Freescale Semiconductor, Inc.
3  *
4  * SPDX-License-Identifier:    GPL-2.0+
5  */
6
7 #include <common.h>
8 #include <asm/io.h>
9 #include <asm/system.h>
10 #include <asm/arch/hab.h>
11 #include <asm/arch/clock.h>
12 #include <asm/arch/sys_proto.h>
13
14 /* -------- start of HAB API updates ------------*/
15
16 #define hab_rvt_report_event_p                                  \
17 (                                                               \
18         ((is_cpu_type(MXC_CPU_MX6Q) ||                          \
19           is_cpu_type(MXC_CPU_MX6D)) &&                         \
20           (soc_rev() >= CHIP_REV_1_5)) ?                        \
21         ((hab_rvt_report_event_t *)HAB_RVT_REPORT_EVENT_NEW) :  \
22         (is_cpu_type(MXC_CPU_MX6DL) &&                          \
23          (soc_rev() >= CHIP_REV_1_2)) ?                         \
24         ((hab_rvt_report_event_t *)HAB_RVT_REPORT_EVENT_NEW) :  \
25         ((hab_rvt_report_event_t *)HAB_RVT_REPORT_EVENT)        \
26 )
27
28 #define hab_rvt_report_status_p                                 \
29 (                                                               \
30         ((is_cpu_type(MXC_CPU_MX6Q) ||                          \
31           is_cpu_type(MXC_CPU_MX6D)) &&                         \
32           (soc_rev() >= CHIP_REV_1_5)) ?                        \
33         ((hab_rvt_report_status_t *)HAB_RVT_REPORT_STATUS_NEW) :\
34         (is_cpu_type(MXC_CPU_MX6DL) &&                          \
35          (soc_rev() >= CHIP_REV_1_2)) ?                         \
36         ((hab_rvt_report_status_t *)HAB_RVT_REPORT_STATUS_NEW) :\
37         ((hab_rvt_report_status_t *)HAB_RVT_REPORT_STATUS)      \
38 )
39
40 #define hab_rvt_authenticate_image_p                            \
41 (                                                               \
42         ((is_cpu_type(MXC_CPU_MX6Q) ||                          \
43           is_cpu_type(MXC_CPU_MX6D)) &&                         \
44           (soc_rev() >= CHIP_REV_1_5)) ?                        \
45         ((hab_rvt_authenticate_image_t *)HAB_RVT_AUTHENTICATE_IMAGE_NEW) : \
46         (is_cpu_type(MXC_CPU_MX6DL) &&                          \
47          (soc_rev() >= CHIP_REV_1_2)) ?                         \
48         ((hab_rvt_authenticate_image_t *)HAB_RVT_AUTHENTICATE_IMAGE_NEW) : \
49         ((hab_rvt_authenticate_image_t *)HAB_RVT_AUTHENTICATE_IMAGE)    \
50 )
51
52 #define hab_rvt_entry_p                                         \
53 (                                                               \
54         ((is_cpu_type(MXC_CPU_MX6Q) ||                          \
55           is_cpu_type(MXC_CPU_MX6D)) &&                         \
56           (soc_rev() >= CHIP_REV_1_5)) ?                        \
57         ((hab_rvt_entry_t *)HAB_RVT_ENTRY_NEW) :                \
58         (is_cpu_type(MXC_CPU_MX6DL) &&                          \
59          (soc_rev() >= CHIP_REV_1_2)) ?                         \
60         ((hab_rvt_entry_t *)HAB_RVT_ENTRY_NEW) :                \
61         ((hab_rvt_entry_t *)HAB_RVT_ENTRY)                      \
62 )
63
64 #define hab_rvt_exit_p                                          \
65 (                                                               \
66         ((is_cpu_type(MXC_CPU_MX6Q) ||                          \
67           is_cpu_type(MXC_CPU_MX6D)) &&                         \
68           (soc_rev() >= CHIP_REV_1_5)) ?                        \
69         ((hab_rvt_exit_t *)HAB_RVT_EXIT_NEW) :                  \
70         (is_cpu_type(MXC_CPU_MX6DL) &&                          \
71          (soc_rev() >= CHIP_REV_1_2)) ?                         \
72         ((hab_rvt_exit_t *)HAB_RVT_EXIT_NEW) :                  \
73         ((hab_rvt_exit_t *)HAB_RVT_EXIT)                        \
74 )
75
76 #define IVT_SIZE                0x20
77 #define ALIGN_SIZE              0x1000
78 #define CSF_PAD_SIZE            0x2000
79 #define MX6DQ_PU_IROM_MMU_EN_VAR        0x009024a8
80 #define MX6DLS_PU_IROM_MMU_EN_VAR       0x00901dd0
81 #define MX6SL_PU_IROM_MMU_EN_VAR        0x00900a18
82
83 /*
84  * +------------+  0x0 (DDR_UIMAGE_START) -
85  * |   Header   |                          |
86  * +------------+  0x40                    |
87  * |            |                          |
88  * |            |                          |
89  * |            |                          |
90  * |            |                          |
91  * | Image Data |                          |
92  * .            |                          |
93  * .            |                           > Stuff to be authenticated ----+
94  * .            |                          |                                |
95  * |            |                          |                                |
96  * |            |                          |                                |
97  * +------------+                          |                                |
98  * |            |                          |                                |
99  * | Fill Data  |                          |                                |
100  * |            |                          |                                |
101  * +------------+ Align to ALIGN_SIZE      |                                |
102  * |    IVT     |                          |                                |
103  * +------------+ + IVT_SIZE              -                                 |
104  * |            |                                                           |
105  * |  CSF DATA  | <---------------------------------------------------------+
106  * |            |
107  * +------------+
108  * |            |
109  * | Fill Data  |
110  * |            |
111  * +------------+ + CSF_PAD_SIZE
112  */
113
114 bool is_hab_enabled(void)
115 {
116         struct ocotp_regs *ocotp = (struct ocotp_regs *)OCOTP_BASE_ADDR;
117         struct fuse_bank *bank = &ocotp->bank[0];
118         struct fuse_bank0_regs *fuse =
119                 (struct fuse_bank0_regs *)bank->fuse_regs;
120         uint32_t reg = readl(&fuse->cfg5);
121
122         return (reg & 0x2) == 0x2;
123 }
124
125 void display_event(uint8_t *event_data, size_t bytes)
126 {
127         uint32_t i;
128
129         if (!(event_data && bytes > 0))
130                 return;
131
132         for (i = 0; i < bytes; i++) {
133                 if (i == 0)
134                         printf("\t0x%02x", event_data[i]);
135                 else if ((i % 8) == 0)
136                         printf("\n\t0x%02x", event_data[i]);
137                 else
138                         printf(" 0x%02x", event_data[i]);
139         }
140 }
141
142 int get_hab_status(void)
143 {
144         uint32_t index = 0; /* Loop index */
145         uint8_t event_data[128]; /* Event data buffer */
146         size_t bytes = sizeof(event_data); /* Event size in bytes */
147         enum hab_config config = 0;
148         enum hab_state state = 0;
149         hab_rvt_report_event_t *hab_rvt_report_event;
150         hab_rvt_report_status_t *hab_rvt_report_status;
151
152         hab_rvt_report_event = hab_rvt_report_event_p;
153         hab_rvt_report_status = hab_rvt_report_status_p;
154
155         if (is_hab_enabled())
156                 puts("\nSecure boot enabled\n");
157         else
158                 puts("\nSecure boot disabled\n");
159
160         /* Check HAB status */
161         if (hab_rvt_report_status(&config, &state) != HAB_SUCCESS) {
162                 printf("\nHAB Configuration: 0x%02x, HAB State: 0x%02x\n",
163                        config, state);
164
165                 /* Display HAB Error events */
166                 while (hab_rvt_report_event(HAB_FAILURE, index, event_data,
167                                         &bytes) == HAB_SUCCESS) {
168                         puts("\n");
169                         printf("--------- HAB Event %d -----------------\n",
170                                index + 1);
171                         puts("event data:\n");
172                         display_event(event_data, bytes);
173                         puts("\n");
174                         bytes = sizeof(event_data);
175                         index++;
176                 }
177         }
178         /* Display message if no HAB events are found */
179         else {
180                 printf("\nHAB Configuration: 0x%02x, HAB State: 0x%02x\n",
181                        config, state);
182                 puts("No HAB Events Found!\n\n");
183         }
184         return 0;
185 }
186
187 uint32_t authenticate_image(uint32_t ddr_start, uint32_t image_size)
188 {
189         uint32_t load_addr = 0;
190         size_t bytes;
191         ptrdiff_t ivt_offset = 0;
192         int result = 0;
193         ulong start;
194         hab_rvt_authenticate_image_t *hab_rvt_authenticate_image;
195         hab_rvt_entry_t *hab_rvt_entry;
196         hab_rvt_exit_t *hab_rvt_exit;
197
198         hab_rvt_authenticate_image = hab_rvt_authenticate_image_p;
199         hab_rvt_entry = hab_rvt_entry_p;
200         hab_rvt_exit = hab_rvt_exit_p;
201
202         if (is_hab_enabled()) {
203                 printf("\nAuthenticate image from DDR location 0x%x...\n",
204                        ddr_start);
205
206                 hab_caam_clock_enable(1);
207
208                 if (hab_rvt_entry() == HAB_SUCCESS) {
209                         /* If not already aligned, Align to ALIGN_SIZE */
210                         ivt_offset = (image_size + ALIGN_SIZE - 1) &
211                                         ~(ALIGN_SIZE - 1);
212
213                         start = ddr_start;
214                         bytes = ivt_offset + IVT_SIZE + CSF_PAD_SIZE;
215 #ifdef DEBUG
216                         printf("\nivt_offset = 0x%x, ivt addr = 0x%x\n",
217                                ivt_offset, ddr_start + ivt_offset);
218                         puts("Dumping IVT\n");
219                         print_buffer(ddr_start + ivt_offset,
220                                      (void *)(ddr_start + ivt_offset),
221                                      4, 0x8, 0);
222
223                         puts("Dumping CSF Header\n");
224                         print_buffer(ddr_start + ivt_offset+IVT_SIZE,
225                                      (void *)(ddr_start + ivt_offset+IVT_SIZE),
226                                      4, 0x10, 0);
227
228                         get_hab_status();
229
230                         puts("\nCalling authenticate_image in ROM\n");
231                         printf("\tivt_offset = 0x%x\n", ivt_offset);
232                         printf("\tstart = 0x%08lx\n", start);
233                         printf("\tbytes = 0x%x\n", bytes);
234 #endif
235                         /*
236                          * If the MMU is enabled, we have to notify the ROM
237                          * code, or it won't flush the caches when needed.
238                          * This is done, by setting the "pu_irom_mmu_enabled"
239                          * word to 1. You can find its address by looking in
240                          * the ROM map. This is critical for
241                          * authenticate_image(). If MMU is enabled, without
242                          * setting this bit, authentication will fail and may
243                          * crash.
244                          */
245                         /* Check MMU enabled */
246                         if (get_cr() & CR_M) {
247                                 if (is_cpu_type(MXC_CPU_MX6Q) ||
248                                     is_cpu_type(MXC_CPU_MX6D)) {
249                                         /*
250                                          * This won't work on Rev 1.0.0 of
251                                          * i.MX6Q/D, since their ROM doesn't
252                                          * do cache flushes. don't think any
253                                          * exist, so we ignore them.
254                                          */
255                                         writel(1, MX6DQ_PU_IROM_MMU_EN_VAR);
256                                 } else if (is_cpu_type(MXC_CPU_MX6DL) ||
257                                            is_cpu_type(MXC_CPU_MX6SOLO)) {
258                                         writel(1, MX6DLS_PU_IROM_MMU_EN_VAR);
259                                 } else if (is_cpu_type(MXC_CPU_MX6SL)) {
260                                         writel(1, MX6SL_PU_IROM_MMU_EN_VAR);
261                                 }
262                         }
263
264                         load_addr = (uint32_t)hab_rvt_authenticate_image(
265                                         HAB_CID_UBOOT,
266                                         ivt_offset, (void **)&start,
267                                         (size_t *)&bytes, NULL);
268                         if (hab_rvt_exit() != HAB_SUCCESS) {
269                                 puts("hab exit function fail\n");
270                                 load_addr = 0;
271                         }
272                 } else {
273                         puts("hab entry function fail\n");
274                 }
275
276                 hab_caam_clock_enable(0);
277
278                 get_hab_status();
279         } else {
280                 puts("hab fuse not enabled\n");
281         }
282
283         if ((!is_hab_enabled()) || (load_addr != 0))
284                 result = 1;
285
286         return result;
287 }
288
289 int do_hab_status(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
290 {
291         if ((argc != 1)) {
292                 cmd_usage(cmdtp);
293                 return 1;
294         }
295
296         get_hab_status();
297
298         return 0;
299 }
300
301 static int do_authenticate_image(cmd_tbl_t *cmdtp, int flag, int argc,
302                                 char * const argv[])
303 {
304         ulong   addr, ivt_offset;
305         int     rcode = 0;
306
307         if (argc < 3)
308                 return CMD_RET_USAGE;
309
310         addr = simple_strtoul(argv[1], NULL, 16);
311         ivt_offset = simple_strtoul(argv[2], NULL, 16);
312
313         rcode = authenticate_image(addr, ivt_offset);
314
315         return rcode;
316 }
317
318 U_BOOT_CMD(
319                 hab_status, CONFIG_SYS_MAXARGS, 1, do_hab_status,
320                 "display HAB status",
321                 ""
322           );
323
324 U_BOOT_CMD(
325                 hab_auth_img, 3, 0, do_authenticate_image,
326                 "authenticate image via HAB",
327                 "addr ivt_offset\n"
328                 "addr - image hex address\n"
329                 "ivt_offset - hex offset of IVT in the image"
330           );