blob: ec03792755aa67d5101a0520b58eb65cc45d6178 [file] [log] [blame]
Brian Swetland9c4c0752009-01-25 16:23:50 -08001/*
2 * Copyright (c) 2009, Google Inc.
3 * All rights reserved.
4 *
Ajay Dudanid04110c2011-01-17 23:55:07 -08005 * Copyright (c) 2009-2011, Code Aurora Forum. All rights reserved.
Brian Swetland9c4c0752009-01-25 16:23:50 -08006 *
Chandan Uddaraju5fa471a2009-12-02 17:31:34 -08007 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions are met:
9 * * Redistributions of source code must retain the above copyright
10 * notice, this list of conditions and the following disclaimer.
11 * * Redistributions in binary form must reproduce the above copyright
12 * notice, this list of conditions and the following disclaimer in the
13 * documentation and/or other materials provided with the distribution.
14 * * Neither the name of Code Aurora nor
15 * the names of its contributors may be used to endorse or promote
16 * products derived from this software without specific prior written
17 * permission.
18 *
19 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
20 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
21 * IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
22 * NON-INFRINGEMENT ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
23 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
24 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
25 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
26 * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
27 * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
28 * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
29 * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
30 *
Brian Swetland9c4c0752009-01-25 16:23:50 -080031 */
32
33#include <app.h>
34#include <debug.h>
35#include <arch/arm.h>
36#include <dev/udc.h>
37#include <string.h>
38#include <kernel/thread.h>
39#include <arch/ops.h>
40
Dima Zavin214cc642009-01-26 11:16:21 -080041#include <dev/flash.h>
42#include <lib/ptable.h>
Dima Zavinb4283602009-01-26 16:36:57 -080043#include <dev/keys.h>
Shashank Mittal4f99a882010-02-01 13:58:50 -080044#include <dev/fbcon.h>
Ajay Dudanid04110c2011-01-17 23:55:07 -080045#include <baseband.h>
Greg Griscod6250552011-06-29 14:40:23 -070046#include <target.h>
47#include <mmc.h>
48#include <platform.h>
Dima Zavin214cc642009-01-26 11:16:21 -080049
Shashank Mittal024c0332010-02-03 11:44:00 -080050#include "recovery.h"
Brian Swetland9c4c0752009-01-25 16:23:50 -080051#include "bootimg.h"
52#include "fastboot.h"
Ajay Dudani5c761132011-04-07 20:19:04 -070053#include "sparse_format.h"
Brian Swetland9c4c0752009-01-25 16:23:50 -080054
kchik@codeaurora.orgbce18ea2011-04-18 20:22:28 -070055#include "scm_decrypt.h"
56
Subbaraman Narayanamurthyeb92bcc2010-07-20 14:32:46 -070057#define EXPAND(NAME) #NAME
58#define TARGET(NAME) EXPAND(NAME)
Chandan Uddarajuda919832009-11-17 01:06:11 -080059#define DEFAULT_CMDLINE "mem=100M console=null";
Brian Swetland2defe162009-08-18 14:35:59 -070060
Ajay Dudanicd01f9b2010-02-23 21:13:04 -080061#ifdef MEMBASE
62#define EMMC_BOOT_IMG_HEADER_ADDR (0xFF000+(MEMBASE))
63#else
David Ng183a7422009-12-07 14:55:21 -080064#define EMMC_BOOT_IMG_HEADER_ADDR 0xFF000
Ajay Dudanicd01f9b2010-02-23 21:13:04 -080065#endif
66
Chandan Uddarajude85d3f2010-01-05 16:32:33 -080067#define RECOVERY_MODE 0x77665502
68#define FASTBOOT_MODE 0x77665500
69
David Ng183a7422009-12-07 14:55:21 -080070static const char *emmc_cmdline = " androidboot.emmc=true";
Subbaraman Narayanamurthyf17b4ae2011-02-16 20:19:56 -080071static const char *usb_sn_cmdline = " androidboot.serialno=";
David Ngf773dde2010-07-26 19:55:08 -070072static const char *battchg_pause = " androidboot.battchg_pause=true";
David Ng183a7422009-12-07 14:55:21 -080073
Ajay Dudani6cff85e2011-02-04 16:02:16 -080074static const char *baseband_apq = " androidboot.baseband=apq";
75static const char *baseband_msm = " androidboot.baseband=msm";
76static const char *baseband_csfb = " androidboot.baseband=csfb";
77static const char *baseband_svlte2a = " androidboot.baseband=svlte2a";
Ajay Dudanid04110c2011-01-17 23:55:07 -080078
Brian Swetland9c4c0752009-01-25 16:23:50 -080079static struct udc_device surf_udc_device = {
80 .vendor_id = 0x18d1,
Chandan Uddarajuc53a1a12009-11-18 14:53:40 -080081 .product_id = 0xD00D,
Brian Swetland9c4c0752009-01-25 16:23:50 -080082 .version_id = 0x0100,
83 .manufacturer = "Google",
84 .product = "Android",
85};
86
Dima Zavin42168f22009-01-30 11:52:22 -080087struct atag_ptbl_entry
88{
89 char name[16];
90 unsigned offset;
91 unsigned size;
92 unsigned flags;
93};
94
Subbaraman Narayanamurthyf17b4ae2011-02-16 20:19:56 -080095char sn_buf[13];
Greg Griscod6250552011-06-29 14:40:23 -070096
97
Chandan Uddarajude85d3f2010-01-05 16:32:33 -080098
Dima Zavin42168f22009-01-30 11:52:22 -080099static void ptentry_to_tag(unsigned **ptr, struct ptentry *ptn)
100{
101 struct atag_ptbl_entry atag_ptn;
102
Greg Griscod6250552011-06-29 14:40:23 -0700103 if (ptn->type == TYPE_MODEM_PARTITION) {
Shashank Mittal8e49dec2010-03-01 15:19:04 -0800104 return;
Greg Griscod6250552011-06-29 14:40:23 -0700105 }
Dima Zavin42168f22009-01-30 11:52:22 -0800106 memcpy(atag_ptn.name, ptn->name, 16);
107 atag_ptn.name[15] = '\0';
108 atag_ptn.offset = ptn->start;
109 atag_ptn.size = ptn->length;
110 atag_ptn.flags = ptn->flags;
111 memcpy(*ptr, &atag_ptn, sizeof(struct atag_ptbl_entry));
112 *ptr += sizeof(struct atag_ptbl_entry) / sizeof(unsigned);
113}
Brian Swetland9c4c0752009-01-25 16:23:50 -0800114
kchik@codeaurora.orgbce18ea2011-04-18 20:22:28 -0700115void boot_linux(void *kernel, unsigned *tags,
Brian Swetland9c4c0752009-01-25 16:23:50 -0800116 const char *cmdline, unsigned machtype,
117 void *ramdisk, unsigned ramdisk_size)
118{
119 unsigned *ptr = tags;
Shashank Mittal8e49dec2010-03-01 15:19:04 -0800120 unsigned pcount = 0;
Brian Swetland9c4c0752009-01-25 16:23:50 -0800121 void (*entry)(unsigned,unsigned,unsigned*) = kernel;
Dima Zavin42168f22009-01-30 11:52:22 -0800122 struct ptable *ptable;
David Ng183a7422009-12-07 14:55:21 -0800123 int cmdline_len = 0;
124 int have_cmdline = 0;
David Ngf773dde2010-07-26 19:55:08 -0700125 int pause_at_bootup = 0;
Brian Swetland9c4c0752009-01-25 16:23:50 -0800126
127 /* CORE */
128 *ptr++ = 2;
129 *ptr++ = 0x54410001;
130
131 if (ramdisk_size) {
132 *ptr++ = 4;
133 *ptr++ = 0x54420005;
Dima Zavin214cc642009-01-26 11:16:21 -0800134 *ptr++ = (unsigned)ramdisk;
Brian Swetland9c4c0752009-01-25 16:23:50 -0800135 *ptr++ = ramdisk_size;
136 }
137
Chandan Uddarajuc6860e12009-11-19 11:22:15 -0800138 ptr = target_atag_mem(ptr);
139
David Ng183a7422009-12-07 14:55:21 -0800140 if (!target_is_emmc_boot()) {
141 /* Skip NAND partition ATAGS for eMMC boot */
142 if ((ptable = flash_get_ptable()) && (ptable->count != 0)) {
143 int i;
Shashank Mittal8e49dec2010-03-01 15:19:04 -0800144 for(i=0; i < ptable->count; i++) {
145 struct ptentry *ptn;
146 ptn = ptable_get(ptable, i);
147 if (ptn->type == TYPE_APPS_PARTITION)
148 pcount++;
149 }
150 *ptr++ = 2 + (pcount * (sizeof(struct atag_ptbl_entry) /
David Ng183a7422009-12-07 14:55:21 -0800151 sizeof(unsigned)));
152 *ptr++ = 0x4d534d70;
153 for (i = 0; i < ptable->count; ++i)
154 ptentry_to_tag(&ptr, ptable_get(ptable, i));
155 }
Dima Zavin42168f22009-01-30 11:52:22 -0800156 }
157
Brian Swetland9c4c0752009-01-25 16:23:50 -0800158 if (cmdline && cmdline[0]) {
David Ng183a7422009-12-07 14:55:21 -0800159 cmdline_len = strlen(cmdline);
160 have_cmdline = 1;
161 }
162 if (target_is_emmc_boot()) {
163 cmdline_len += strlen(emmc_cmdline);
164 }
Subbaraman Narayanamurthyf17b4ae2011-02-16 20:19:56 -0800165
166 cmdline_len += strlen(usb_sn_cmdline);
167 cmdline_len += strlen(sn_buf);
168
David Ngf773dde2010-07-26 19:55:08 -0700169 if (target_pause_for_battery_charge()) {
170 pause_at_bootup = 1;
171 cmdline_len += strlen(battchg_pause);
172 }
Ajay Dudanid04110c2011-01-17 23:55:07 -0800173
174 /* Determine correct androidboot.baseband to use */
175 switch(target_baseband())
176 {
177 case BASEBAND_APQ:
178 cmdline_len += strlen(baseband_apq);
179 break;
180
181 case BASEBAND_MSM:
182 cmdline_len += strlen(baseband_msm);
183 break;
184
185 case BASEBAND_CSFB:
186 cmdline_len += strlen(baseband_csfb);
187 break;
188
Ajay Dudani6cff85e2011-02-04 16:02:16 -0800189 case BASEBAND_SVLTE2A:
190 cmdline_len += strlen(baseband_svlte2a);
Ajay Dudanid04110c2011-01-17 23:55:07 -0800191 break;
192 }
193
David Ng183a7422009-12-07 14:55:21 -0800194 if (cmdline_len > 0) {
195 const char *src;
196 char *dst;
Brian Swetland9c4c0752009-01-25 16:23:50 -0800197 unsigned n;
198 /* include terminating 0 and round up to a word multiple */
David Ng183a7422009-12-07 14:55:21 -0800199 n = (cmdline_len + 4) & (~3);
Brian Swetland9c4c0752009-01-25 16:23:50 -0800200 *ptr++ = (n / 4) + 2;
201 *ptr++ = 0x54410009;
David Ng183a7422009-12-07 14:55:21 -0800202 dst = (char *)ptr;
203 if (have_cmdline) {
204 src = cmdline;
205 while ((*dst++ = *src++));
206 }
207 if (target_is_emmc_boot()) {
208 src = emmc_cmdline;
209 if (have_cmdline) --dst;
David Ngf773dde2010-07-26 19:55:08 -0700210 have_cmdline = 1;
211 while ((*dst++ = *src++));
212 }
Subbaraman Narayanamurthyf17b4ae2011-02-16 20:19:56 -0800213
214 src = usb_sn_cmdline;
215 if (have_cmdline) --dst;
216 have_cmdline = 1;
217 while ((*dst++ = *src++));
218 src = sn_buf;
219 if (have_cmdline) --dst;
220 have_cmdline = 1;
221 while ((*dst++ = *src++));
222
David Ngf773dde2010-07-26 19:55:08 -0700223 if (pause_at_bootup) {
224 src = battchg_pause;
225 if (have_cmdline) --dst;
David Ng183a7422009-12-07 14:55:21 -0800226 while ((*dst++ = *src++));
227 }
Ajay Dudanid04110c2011-01-17 23:55:07 -0800228
229 switch(target_baseband())
230 {
231 case BASEBAND_APQ:
232 src = baseband_apq;
233 if (have_cmdline) --dst;
234 while ((*dst++ = *src++));
235 break;
236
237 case BASEBAND_MSM:
238 src = baseband_msm;
239 if (have_cmdline) --dst;
240 while ((*dst++ = *src++));
241 break;
242
243 case BASEBAND_CSFB:
244 src = baseband_csfb;
245 if (have_cmdline) --dst;
246 while ((*dst++ = *src++));
247 break;
248
Ajay Dudani6cff85e2011-02-04 16:02:16 -0800249 case BASEBAND_SVLTE2A:
250 src = baseband_svlte2a;
Ajay Dudanid04110c2011-01-17 23:55:07 -0800251 if (have_cmdline) --dst;
252 while ((*dst++ = *src++));
253 break;
254 }
Brian Swetland9c4c0752009-01-25 16:23:50 -0800255 ptr += (n / 4);
256 }
257
258 /* END */
259 *ptr++ = 0;
260 *ptr++ = 0;
261
262 dprintf(INFO, "booting linux @ %p, ramdisk @ %p (%d)\n",
263 kernel, ramdisk, ramdisk_size);
264 if (cmdline)
265 dprintf(INFO, "cmdline: %s\n", cmdline);
266
267 enter_critical_section();
Amol Jadi4421e652011-06-16 15:00:48 -0700268 /* do any platform specific cleanup before kernel entry */
269 platform_uninit();
Brian Swetland9c4c0752009-01-25 16:23:50 -0800270 arch_disable_cache(UCACHE);
Brian Swetland9c4c0752009-01-25 16:23:50 -0800271 arch_disable_mmu();
Brian Swetland9c4c0752009-01-25 16:23:50 -0800272 entry(0, machtype, tags);
Brian Swetland9c4c0752009-01-25 16:23:50 -0800273}
274
Shashank Mittaldcc2e352009-11-19 19:11:16 -0800275unsigned page_size = 0;
276unsigned page_mask = 0;
Brian Swetland9c4c0752009-01-25 16:23:50 -0800277
Shashank Mittaldcc2e352009-11-19 19:11:16 -0800278#define ROUND_TO_PAGE(x,y) (((x) + (y)) & (~(y)))
Brian Swetland9c4c0752009-01-25 16:23:50 -0800279
Shashank Mittaldcc2e352009-11-19 19:11:16 -0800280static unsigned char buf[4096]; //Equal to max-supported pagesize
Dima Zavin214cc642009-01-26 11:16:21 -0800281
Shashank Mittal23b8f422010-04-16 19:27:21 -0700282int boot_linux_from_mmc(void)
283{
284 struct boot_img_hdr *hdr = (void*) buf;
285 struct boot_img_hdr *uhdr;
286 unsigned offset = 0;
287 unsigned long long ptn = 0;
288 unsigned n = 0;
289 const char *cmdline;
290
291 uhdr = (struct boot_img_hdr *)EMMC_BOOT_IMG_HEADER_ADDR;
292 if (!memcmp(uhdr->magic, BOOT_MAGIC, BOOT_MAGIC_SIZE)) {
293 dprintf(INFO, "Unified boot method!\n");
294 hdr = uhdr;
295 goto unified_boot;
296 }
Greg Griscod6250552011-06-29 14:40:23 -0700297 if (!boot_into_recovery) {
298 ptn = mmc_ptn_offset((unsigned char *) "boot");
299 if (ptn == 0) {
Shashank Mittal85b91f62010-10-30 10:12:38 -0700300 dprintf(CRITICAL, "ERROR: No boot partition found\n");
301 return -1;
302 }
Greg Griscod6250552011-06-29 14:40:23 -0700303 } else {
304 ptn = mmc_ptn_offset((unsigned char *) "recovery");
305 if (ptn == 0) {
Shashank Mittal85b91f62010-10-30 10:12:38 -0700306 dprintf(CRITICAL, "ERROR: No recovery partition found\n");
307 return -1;
308 }
Shashank Mittal23b8f422010-04-16 19:27:21 -0700309 }
310
Greg Griscod6250552011-06-29 14:40:23 -0700311 if (mmc_read(ptn + offset, (unsigned int *) buf, page_size)) {
Shashank Mittal23b8f422010-04-16 19:27:21 -0700312 dprintf(CRITICAL, "ERROR: Cannot read boot image header\n");
313 return -1;
314 }
Shashank Mittal23b8f422010-04-16 19:27:21 -0700315
316 if (memcmp(hdr->magic, BOOT_MAGIC, BOOT_MAGIC_SIZE)) {
Kinson Chik kchik@codeaurora.org82e4ae62011-04-12 17:42:07 -0700317 dprintf(CRITICAL, "ERROR: Invalid boot image header\n");
Shashank Mittal23b8f422010-04-16 19:27:21 -0700318 return -1;
319 }
320
Subbaraman Narayanamurthyfbe13a02010-09-10 11:51:12 -0700321 if (hdr->page_size && (hdr->page_size != page_size)) {
322 page_size = hdr->page_size;
323 page_mask = page_size - 1;
Shashank Mittal23b8f422010-04-16 19:27:21 -0700324 }
Subbaraman Narayanamurthyfbe13a02010-09-10 11:51:12 -0700325 offset += page_size;
Shashank Mittal23b8f422010-04-16 19:27:21 -0700326
327 n = ROUND_TO_PAGE(hdr->kernel_size, page_mask);
328 if (mmc_read(ptn + offset, (void *)hdr->kernel_addr, n)) {
329 dprintf(CRITICAL, "ERROR: Cannot read kernel image\n");
330 return -1;
331 }
332 offset += n;
333
334 n = ROUND_TO_PAGE(hdr->ramdisk_size, page_mask);
Subbaraman Narayanamurthy958fa242011-01-27 17:42:38 -0800335 if(n != 0)
336 {
337 if (mmc_read(ptn + offset, (void *)hdr->ramdisk_addr, n)) {
338 dprintf(CRITICAL, "ERROR: Cannot read ramdisk image\n");
339 return -1;
340 }
Shashank Mittal23b8f422010-04-16 19:27:21 -0700341 }
342 offset += n;
343
344unified_boot:
345 dprintf(INFO, "\nkernel @ %x (%d bytes)\n", hdr->kernel_addr,
346 hdr->kernel_size);
347 dprintf(INFO, "ramdisk @ %x (%d bytes)\n", hdr->ramdisk_addr,
348 hdr->ramdisk_size);
349
350 if(hdr->cmdline[0]) {
351 cmdline = (char*) hdr->cmdline;
352 } else {
353 cmdline = DEFAULT_CMDLINE;
354 }
355 dprintf(INFO, "cmdline = '%s'\n", cmdline);
356
357 dprintf(INFO, "\nBooting Linux\n");
Ajay Dudanie28a6072011-07-01 13:59:46 -0700358 boot_linux((void *)hdr->kernel_addr, hdr->tags_addr,
Shashank Mittal23b8f422010-04-16 19:27:21 -0700359 (const char *)cmdline, board_machtype(),
360 (void *)hdr->ramdisk_addr, hdr->ramdisk_size);
361
362 return 0;
363}
364
Dima Zavin214cc642009-01-26 11:16:21 -0800365int boot_linux_from_flash(void)
366{
367 struct boot_img_hdr *hdr = (void*) buf;
368 unsigned n;
369 struct ptentry *ptn;
370 struct ptable *ptable;
371 unsigned offset = 0;
372 const char *cmdline;
Chandan Uddarajude85d3f2010-01-05 16:32:33 -0800373
David Ng183a7422009-12-07 14:55:21 -0800374 if (target_is_emmc_boot()) {
375 hdr = (struct boot_img_hdr *)EMMC_BOOT_IMG_HEADER_ADDR;
376 if (memcmp(hdr->magic, BOOT_MAGIC, BOOT_MAGIC_SIZE)) {
377 dprintf(CRITICAL, "ERROR: Invalid boot image header\n");
378 return -1;
379 }
380 goto continue_boot;
381 }
382
Dima Zavin214cc642009-01-26 11:16:21 -0800383 ptable = flash_get_ptable();
384 if (ptable == NULL) {
385 dprintf(CRITICAL, "ERROR: Partition table not found\n");
386 return -1;
387 }
388
Chandan Uddarajude85d3f2010-01-05 16:32:33 -0800389 if(!boot_into_recovery)
390 {
391 ptn = ptable_find(ptable, "boot");
392 if (ptn == NULL) {
393 dprintf(CRITICAL, "ERROR: No boot partition found\n");
394 return -1;
395 }
396 }
397 else
398 {
399 ptn = ptable_find(ptable, "recovery");
400 if (ptn == NULL) {
401 dprintf(CRITICAL, "ERROR: No recovery partition found\n");
402 return -1;
403 }
Dima Zavin214cc642009-01-26 11:16:21 -0800404 }
405
Shashank Mittaldcc2e352009-11-19 19:11:16 -0800406 if (flash_read(ptn, offset, buf, page_size)) {
Dima Zavin214cc642009-01-26 11:16:21 -0800407 dprintf(CRITICAL, "ERROR: Cannot read boot image header\n");
408 return -1;
409 }
Shashank Mittaldcc2e352009-11-19 19:11:16 -0800410 offset += page_size;
Dima Zavin214cc642009-01-26 11:16:21 -0800411
412 if (memcmp(hdr->magic, BOOT_MAGIC, BOOT_MAGIC_SIZE)) {
Kinson Chik kchik@codeaurora.org82e4ae62011-04-12 17:42:07 -0700413 dprintf(CRITICAL, "ERROR: Invalid boot image header\n");
Dima Zavin214cc642009-01-26 11:16:21 -0800414 return -1;
415 }
416
Shashank Mittaldcc2e352009-11-19 19:11:16 -0800417 if (hdr->page_size != page_size) {
Kinson Chik kchik@codeaurora.org82e4ae62011-04-12 17:42:07 -0700418 dprintf(CRITICAL, "ERROR: Invalid boot image pagesize. Device pagesize: %d, Image pagesize: %d\n",page_size,hdr->page_size);
Shashank Mittaldcc2e352009-11-19 19:11:16 -0800419 return -1;
420 }
421
422 n = ROUND_TO_PAGE(hdr->kernel_size, page_mask);
Dima Zavin214cc642009-01-26 11:16:21 -0800423 if (flash_read(ptn, offset, (void *)hdr->kernel_addr, n)) {
424 dprintf(CRITICAL, "ERROR: Cannot read kernel image\n");
425 return -1;
426 }
427 offset += n;
428
Shashank Mittaldcc2e352009-11-19 19:11:16 -0800429 n = ROUND_TO_PAGE(hdr->ramdisk_size, page_mask);
Dima Zavin214cc642009-01-26 11:16:21 -0800430 if (flash_read(ptn, offset, (void *)hdr->ramdisk_addr, n)) {
431 dprintf(CRITICAL, "ERROR: Cannot read ramdisk image\n");
432 return -1;
433 }
434 offset += n;
435
David Ng183a7422009-12-07 14:55:21 -0800436continue_boot:
Dima Zavin214cc642009-01-26 11:16:21 -0800437 dprintf(INFO, "\nkernel @ %x (%d bytes)\n", hdr->kernel_addr,
438 hdr->kernel_size);
439 dprintf(INFO, "ramdisk @ %x (%d bytes)\n", hdr->ramdisk_addr,
440 hdr->ramdisk_size);
441
442 if(hdr->cmdline[0]) {
443 cmdline = (char*) hdr->cmdline;
444 } else {
445 cmdline = DEFAULT_CMDLINE;
446 }
447 dprintf(INFO, "cmdline = '%s'\n", cmdline);
448
449 /* TODO: create/pass atags to kernel */
450
451 dprintf(INFO, "\nBooting Linux\n");
Ajay Dudanie28a6072011-07-01 13:59:46 -0700452 boot_linux((void *)hdr->kernel_addr, (void *)hdr->tags_addr,
Chandan Uddaraju885e4db2009-12-03 22:45:26 -0800453 (const char *)cmdline, board_machtype(),
Dima Zavin214cc642009-01-26 11:16:21 -0800454 (void *)hdr->ramdisk_addr, hdr->ramdisk_size);
455
456 return 0;
457}
Brian Swetland9c4c0752009-01-25 16:23:50 -0800458
459void cmd_boot(const char *arg, void *data, unsigned sz)
460{
461 unsigned kernel_actual;
462 unsigned ramdisk_actual;
463 static struct boot_img_hdr hdr;
464 char *ptr = ((char*) data);
465
466 if (sz < sizeof(hdr)) {
467 fastboot_fail("invalid bootimage header");
468 return;
469 }
470
471 memcpy(&hdr, data, sizeof(hdr));
472
473 /* ensure commandline is terminated */
474 hdr.cmdline[BOOT_ARGS_SIZE-1] = 0;
475
Subbaraman Narayanamurthyfbe13a02010-09-10 11:51:12 -0700476 if(target_is_emmc_boot() && hdr.page_size) {
477 page_size = hdr.page_size;
478 page_mask = page_size - 1;
479 }
480
Shashank Mittaldcc2e352009-11-19 19:11:16 -0800481 kernel_actual = ROUND_TO_PAGE(hdr.kernel_size, page_mask);
482 ramdisk_actual = ROUND_TO_PAGE(hdr.ramdisk_size, page_mask);
Brian Swetland9c4c0752009-01-25 16:23:50 -0800483
Chandan Uddaraju1f6030f2010-03-19 13:26:38 -0700484 if (page_size + kernel_actual + ramdisk_actual < sz) {
Brian Swetland9c4c0752009-01-25 16:23:50 -0800485 fastboot_fail("incomplete bootimage");
486 return;
487 }
488
Ajay Dudanie28a6072011-07-01 13:59:46 -0700489 memmove((void*) hdr.kernel_addr, ptr + page_size, hdr.kernel_size);
490 memmove((void*) hdr.ramdisk_addr, ptr + page_size + kernel_actual, hdr.ramdisk_size);
Brian Swetland9c4c0752009-01-25 16:23:50 -0800491
492 fastboot_okay("");
Chandan Uddaraju7f5b9012010-02-06 16:37:48 -0800493 target_battery_charging_enable(0, 1);
Brian Swetland9c4c0752009-01-25 16:23:50 -0800494 udc_stop();
495
Ajay Dudanie28a6072011-07-01 13:59:46 -0700496 boot_linux((void*) hdr.kernel_addr, (void*) TAGS_ADDR,
Chandan Uddaraju885e4db2009-12-03 22:45:26 -0800497 (const char*) hdr.cmdline, board_machtype(),
Ajay Dudanie28a6072011-07-01 13:59:46 -0700498 (void*) hdr.ramdisk_addr, hdr.ramdisk_size);
Brian Swetland9c4c0752009-01-25 16:23:50 -0800499}
500
Dima Zavin214cc642009-01-26 11:16:21 -0800501void cmd_erase(const char *arg, void *data, unsigned sz)
502{
503 struct ptentry *ptn;
504 struct ptable *ptable;
505
506 ptable = flash_get_ptable();
507 if (ptable == NULL) {
508 fastboot_fail("partition table doesn't exist");
509 return;
510 }
511
512 ptn = ptable_find(ptable, arg);
513 if (ptn == NULL) {
514 fastboot_fail("unknown partition name");
515 return;
516 }
517
518 if (flash_erase(ptn)) {
519 fastboot_fail("failed to erase partition");
520 return;
521 }
522 fastboot_okay("");
523}
524
Bikas Gurungd48bd242010-09-04 19:54:32 -0700525
526void cmd_erase_mmc(const char *arg, void *data, unsigned sz)
527{
528 unsigned long long ptn = 0;
529 unsigned int out[512] = {0};
530
Greg Griscod6250552011-06-29 14:40:23 -0700531 ptn = mmc_ptn_offset((unsigned char *) arg);
532 if (ptn == 0) {
Bikas Gurungd48bd242010-09-04 19:54:32 -0700533 fastboot_fail("partition table doesn't exist");
534 return;
535 }
536
537
538 /* Simple inefficient version of erase. Just writing
539 0 in first block */
540 if (mmc_write(ptn , 512, (unsigned int *)out)) {
541 fastboot_fail("failed to erase partition");
542 return;
543 }
544 fastboot_okay("");
545}
546
547
Ajay Dudani5c761132011-04-07 20:19:04 -0700548void cmd_flash_mmc_img(const char *arg, void *data, unsigned sz)
Shashank Mittal23b8f422010-04-16 19:27:21 -0700549{
550 unsigned long long ptn = 0;
Subbaraman Narayanamurthyc95b5b12010-08-31 13:19:48 -0700551 unsigned long long size = 0;
552
Greg Griscod6250552011-06-29 14:40:23 -0700553 ptn = mmc_ptn_offset((unsigned char *) arg);
554 if (ptn == 0) {
Shashank Mittal23b8f422010-04-16 19:27:21 -0700555 fastboot_fail("partition table doesn't exist");
556 return;
557 }
558
559 if (!strcmp(arg, "boot") || !strcmp(arg, "recovery")) {
560 if (memcmp((void *)data, BOOT_MAGIC, BOOT_MAGIC_SIZE)) {
561 fastboot_fail("image is not a boot image");
562 return;
563 }
564 }
565
Greg Griscod6250552011-06-29 14:40:23 -0700566 size = mmc_ptn_size((unsigned char *) arg);
567 if (ROUND_TO_PAGE(sz, 511) > size) {
Subbaraman Narayanamurthyc95b5b12010-08-31 13:19:48 -0700568 fastboot_fail("size too large");
569 return;
570 }
571
Greg Griscod6250552011-06-29 14:40:23 -0700572 if (mmc_write(ptn , sz, (unsigned int *) data)) {
Shashank Mittal23b8f422010-04-16 19:27:21 -0700573 fastboot_fail("flash write failure");
574 return;
575 }
576 fastboot_okay("");
577 return;
578}
579
Greg Griscod6250552011-06-29 14:40:23 -0700580
581
Ajay Dudani5c761132011-04-07 20:19:04 -0700582void cmd_flash_mmc_sparse_img(const char *arg, void *data, unsigned sz)
583{
584 unsigned int chunk;
585 unsigned int chunk_data_sz;
586 sparse_header_t *sparse_header;
587 chunk_header_t *chunk_header;
Ajay Dudaniab18f022011-05-12 14:39:22 -0700588 uint32_t total_blocks = 0;
Ajay Dudani5c761132011-04-07 20:19:04 -0700589 unsigned long long ptn = 0;
Ajay Dudani5c761132011-04-07 20:19:04 -0700590
Greg Griscod6250552011-06-29 14:40:23 -0700591 ptn = mmc_ptn_offset((unsigned char *) arg);
592 if (ptn == 0) {
Ajay Dudani5c761132011-04-07 20:19:04 -0700593 fastboot_fail("partition table doesn't exist");
594 return;
595 }
596
597 /* Read and skip over sparse image header */
598 sparse_header = (sparse_header_t *) data;
599 data += sparse_header->file_hdr_sz;
600 if(sparse_header->file_hdr_sz > sizeof(sparse_header_t))
601 {
602 /* Skip the remaining bytes in a header that is longer than
603 * we expected.
604 */
605 data += (sparse_header->file_hdr_sz - sizeof(sparse_header_t));
606 }
607
Ajay Dudanib06c05f2011-05-12 14:46:10 -0700608 dprintf (SPEW, "=== Sparse Image Header ===\n");
609 dprintf (SPEW, "magic: 0x%x\n", sparse_header->magic);
610 dprintf (SPEW, "major_version: 0x%x\n", sparse_header->major_version);
611 dprintf (SPEW, "minor_version: 0x%x\n", sparse_header->minor_version);
612 dprintf (SPEW, "file_hdr_sz: %d\n", sparse_header->file_hdr_sz);
613 dprintf (SPEW, "chunk_hdr_sz: %d\n", sparse_header->chunk_hdr_sz);
614 dprintf (SPEW, "blk_sz: %d\n", sparse_header->blk_sz);
615 dprintf (SPEW, "total_blks: %d\n", sparse_header->total_blks);
616 dprintf (SPEW, "total_chunks: %d\n", sparse_header->total_chunks);
Ajay Dudani5c761132011-04-07 20:19:04 -0700617
618 /* Start processing chunks */
619 for (chunk=0; chunk<sparse_header->total_chunks; chunk++)
620 {
621 /* Read and skip over chunk header */
622 chunk_header = (chunk_header_t *) data;
623 data += sizeof(chunk_header_t);
624
625 dprintf (SPEW, "=== Chunk Header ===\n");
626 dprintf (SPEW, "chunk_type: 0x%x\n", chunk_header->chunk_type);
627 dprintf (SPEW, "chunk_data_sz: 0x%x\n", chunk_header->chunk_sz);
628 dprintf (SPEW, "total_size: 0x%x\n", chunk_header->total_sz);
629
630 if(sparse_header->chunk_hdr_sz > sizeof(chunk_header_t))
631 {
632 /* Skip the remaining bytes in a header that is longer than
633 * we expected.
634 */
635 data += (sparse_header->chunk_hdr_sz - sizeof(chunk_header_t));
636 }
637
638 chunk_data_sz = sparse_header->blk_sz * chunk_header->chunk_sz;
639 switch (chunk_header->chunk_type)
640 {
641 case CHUNK_TYPE_RAW:
642 if(chunk_header->total_sz != (sparse_header->chunk_hdr_sz +
643 chunk_data_sz))
644 {
645 fastboot_fail("Bogus chunk size for chunk type Raw");
646 return;
647 }
648
Ajay Dudaniab18f022011-05-12 14:39:22 -0700649 if(mmc_write(ptn + ((uint64_t)total_blocks*sparse_header->blk_sz),
650 chunk_data_sz,
651 (unsigned int*)data))
Ajay Dudani5c761132011-04-07 20:19:04 -0700652 {
653 fastboot_fail("flash write failure");
654 return;
655 }
656 total_blocks += chunk_header->chunk_sz;
657 data += chunk_data_sz;
658 break;
659
660 case CHUNK_TYPE_DONT_CARE:
Kinson Chik kchik@codeaurora.orgda29b1e2011-05-06 17:36:39 -0700661 total_blocks += chunk_header->chunk_sz;
662 break;
663
Ajay Dudani5c761132011-04-07 20:19:04 -0700664 case CHUNK_TYPE_CRC:
665 if(chunk_header->total_sz != sparse_header->chunk_hdr_sz)
666 {
667 fastboot_fail("Bogus chunk size for chunk type Dont Care");
668 return;
669 }
670 total_blocks += chunk_header->chunk_sz;
671 data += chunk_data_sz;
672 break;
673
Kinson Chik kchik@codeaurora.orgda29b1e2011-05-06 17:36:39 -0700674 default:
Ajay Dudani5c761132011-04-07 20:19:04 -0700675 fastboot_fail("Unknown chunk type");
676 return;
677 }
678 }
679
Ajay Dudani0c6927b2011-05-18 11:12:16 -0700680 dprintf(INFO, "Wrote %d blocks, expected to write %d blocks\n",
681 total_blocks, sparse_header->total_blks);
682
683 if(total_blocks != sparse_header->total_blks)
684 {
685 fastboot_fail("sparse image write failure");
686 }
Ajay Dudani5c761132011-04-07 20:19:04 -0700687
688 fastboot_okay("");
689 return;
690}
691
692void cmd_flash_mmc(const char *arg, void *data, unsigned sz)
693{
694 sparse_header_t *sparse_header;
kchik@codeaurora.orgbce18ea2011-04-18 20:22:28 -0700695 /* 8 Byte Magic + 2048 Byte xml + Encrypted Data */
696 unsigned int *magic_number = (unsigned int *) data;
697 int ret=0;
Ajay Dudani5c761132011-04-07 20:19:04 -0700698
kchik@codeaurora.orgbce18ea2011-04-18 20:22:28 -0700699 if (magic_number[0] == SSD_HEADER_MAGIC_0 &&
700 magic_number[1] == SSD_HEADER_MAGIC_1)
701 {
702#ifdef SSD_ENABLE
Greg Griscod6250552011-06-29 14:40:23 -0700703 ret = decrypt_img_scm((uint32 **) &data, &sz);
kchik@codeaurora.orgbce18ea2011-04-18 20:22:28 -0700704#endif
Greg Griscod6250552011-06-29 14:40:23 -0700705 if (ret != 0) {
kchik@codeaurora.orgbce18ea2011-04-18 20:22:28 -0700706 dprintf(CRITICAL, "ERROR: Invalid secure image\n");
707 return;
708 }
709 }
710 sparse_header = (sparse_header_t *) data;
Ajay Dudani5c761132011-04-07 20:19:04 -0700711 if (sparse_header->magic != SPARSE_HEADER_MAGIC)
712 cmd_flash_mmc_img(arg, data, sz);
713 else
714 cmd_flash_mmc_sparse_img(arg, data, sz);
Ajay Dudani5c761132011-04-07 20:19:04 -0700715 return;
716}
717
Dima Zavin214cc642009-01-26 11:16:21 -0800718void cmd_flash(const char *arg, void *data, unsigned sz)
719{
720 struct ptentry *ptn;
721 struct ptable *ptable;
722 unsigned extra = 0;
723
724 ptable = flash_get_ptable();
725 if (ptable == NULL) {
726 fastboot_fail("partition table doesn't exist");
727 return;
728 }
729
730 ptn = ptable_find(ptable, arg);
731 if (ptn == NULL) {
732 fastboot_fail("unknown partition name");
733 return;
734 }
735
736 if (!strcmp(ptn->name, "boot") || !strcmp(ptn->name, "recovery")) {
737 if (memcmp((void *)data, BOOT_MAGIC, BOOT_MAGIC_SIZE)) {
738 fastboot_fail("image is not a boot image");
739 return;
740 }
741 }
742
Chandan Uddarajud6d45042010-02-24 21:12:45 -0800743 if (!strcmp(ptn->name, "system") || !strcmp(ptn->name, "userdata")
Channagoud Kadabi404a7062011-03-21 19:27:50 +0530744 || !strcmp(ptn->name, "persist")) {
745 if (flash_ecc_bch_enabled())
746 /* Spare data bytes for 8 bit ECC increased by 4 */
747 extra = ((page_size >> 9) * 20);
748 else
749 extra = ((page_size >> 9) * 16);
750 } else
Shashank Mittaldcc2e352009-11-19 19:11:16 -0800751 sz = ROUND_TO_PAGE(sz, page_mask);
Dima Zavin214cc642009-01-26 11:16:21 -0800752
753 dprintf(INFO, "writing %d bytes to '%s'\n", sz, ptn->name);
754 if (flash_write(ptn, extra, data, sz)) {
755 fastboot_fail("flash write failure");
756 return;
757 }
758 dprintf(INFO, "partition '%s' updated\n", ptn->name);
759 fastboot_okay("");
760}
761
762void cmd_continue(const char *arg, void *data, unsigned sz)
763{
764 fastboot_okay("");
Chandan Uddaraju7f5b9012010-02-06 16:37:48 -0800765 target_battery_charging_enable(0, 1);
Dima Zavin214cc642009-01-26 11:16:21 -0800766 udc_stop();
Shashank Mittald8c42bf2010-06-09 15:44:28 -0700767 if (target_is_emmc_boot())
768 {
769 boot_linux_from_mmc();
770 }
771 else
772 {
773 boot_linux_from_flash();
774 }
Dima Zavin214cc642009-01-26 11:16:21 -0800775}
776
Chandan Uddaraju94183c02010-01-15 15:13:59 -0800777void cmd_reboot(const char *arg, void *data, unsigned sz)
778{
Shashank Mittald8c42bf2010-06-09 15:44:28 -0700779 dprintf(INFO, "rebooting the device\n");
Chandan Uddaraju94183c02010-01-15 15:13:59 -0800780 fastboot_okay("");
781 reboot_device(0);
782}
783
784void cmd_reboot_bootloader(const char *arg, void *data, unsigned sz)
785{
Shashank Mittald8c42bf2010-06-09 15:44:28 -0700786 dprintf(INFO, "rebooting the device\n");
Chandan Uddaraju94183c02010-01-15 15:13:59 -0800787 fastboot_okay("");
788 reboot_device(FASTBOOT_MODE);
789}
790
Chandan Uddaraju2943fd62010-06-21 10:56:39 -0700791void splash_screen ()
792{
793 struct ptentry *ptn;
794 struct ptable *ptable;
795 struct fbcon_config *fb_display = NULL;
796
797 if (!target_is_emmc_boot())
798 {
799 ptable = flash_get_ptable();
800 if (ptable == NULL) {
801 dprintf(CRITICAL, "ERROR: Partition table not found\n");
Greg Griscod6250552011-06-29 14:40:23 -0700802 return;
Chandan Uddaraju2943fd62010-06-21 10:56:39 -0700803 }
804
805 ptn = ptable_find(ptable, "splash");
806 if (ptn == NULL) {
807 dprintf(CRITICAL, "ERROR: No splash partition found\n");
808 } else {
809 fb_display = fbcon_display();
810 if (fb_display) {
811 if (flash_read(ptn, 0, fb_display->base,
812 (fb_display->width * fb_display->height * fb_display->bpp/8))) {
813 fbcon_clear();
814 dprintf(CRITICAL, "ERROR: Cannot read splash image\n");
815 }
816 }
817 }
818 }
819}
820
Brian Swetland9c4c0752009-01-25 16:23:50 -0800821void aboot_init(const struct app_descriptor *app)
822{
Shashank Mittal4f99a882010-02-01 13:58:50 -0800823 unsigned reboot_mode = 0;
Shashank Mittald8c42bf2010-06-09 15:44:28 -0700824 unsigned usb_init = 0;
Vivek Mehta5f1c9d42011-04-01 20:11:59 -0700825 unsigned sz = 0;
Chandan Uddarajubedca152010-06-02 23:05:15 -0700826
Chandan Uddaraju2943fd62010-06-21 10:56:39 -0700827 /* Setup page size information for nand/emmc reads */
Shashank Mittald8c42bf2010-06-09 15:44:28 -0700828 if (target_is_emmc_boot())
829 {
830 page_size = 2048;
831 page_mask = page_size - 1;
832 }
833 else
834 {
835 page_size = flash_page_size();
836 page_mask = page_size - 1;
837 }
838
Chandan Uddaraju2943fd62010-06-21 10:56:39 -0700839 /* Display splash screen if enabled */
840 #if DISPLAY_SPLASH_SCREEN
841 display_init();
Ajay Dudanib06c05f2011-05-12 14:46:10 -0700842 dprintf(SPEW, "Diplay initialized\n");
Greg Griscod6250552011-06-29 14:40:23 -0700843 display_image_on_screen();
Chandan Uddaraju2943fd62010-06-21 10:56:39 -0700844 #endif
845
Greg Griscod6250552011-06-29 14:40:23 -0700846 target_serialno((unsigned char *) sn_buf);
Ajay Dudanib06c05f2011-05-12 14:46:10 -0700847 dprintf(SPEW,"serial number: %s\n",sn_buf);
Subbaraman Narayanamurthyf17b4ae2011-02-16 20:19:56 -0800848 surf_udc_device.serialno = sn_buf;
849
Chandan Uddaraju2943fd62010-06-21 10:56:39 -0700850 /* Check if we should do something other than booting up */
Shashank Mittald8c42bf2010-06-09 15:44:28 -0700851 if (keys_get_state(KEY_HOME) != 0)
852 boot_into_recovery = 1;
Wentao Xu153902c2010-12-20 16:20:52 -0500853 if (keys_get_state(KEY_VOLUMEUP) != 0)
854 boot_into_recovery = 1;
Subbaraman Narayanamurthy0e445b02011-06-19 21:34:46 -0700855 if(!boot_into_recovery)
856 {
857 if (keys_get_state(KEY_BACK) != 0)
858 goto fastboot;
859 if (keys_get_state(KEY_VOLUMEDOWN) != 0)
860 goto fastboot;
861 }
Shashank Mittald8c42bf2010-06-09 15:44:28 -0700862
863 #if NO_KEYPAD_DRIVER
864 /* With no keypad implementation, check the status of USB connection. */
865 /* If USB is connected then go into fastboot mode. */
866 usb_init = 1;
867 udc_init(&surf_udc_device);
868 if (usb_cable_status())
869 goto fastboot;
870 #endif
Chandan Uddarajubedca152010-06-02 23:05:15 -0700871
Ajay Dudani77421292010-10-27 19:34:06 -0700872 reboot_mode = check_reboot_mode();
873 if (reboot_mode == RECOVERY_MODE) {
874 boot_into_recovery = 1;
875 } else if(reboot_mode == FASTBOOT_MODE) {
876 goto fastboot;
877 }
878
Shashank Mittal23b8f422010-04-16 19:27:21 -0700879 if (target_is_emmc_boot())
Shashank Mittald8c42bf2010-06-09 15:44:28 -0700880 {
Subbaraman Narayanamurthy0e445b02011-06-19 21:34:46 -0700881 if(emmc_recovery_init())
882 dprintf(ALWAYS,"error in emmc_recovery_init\n");
Shashank Mittald8c42bf2010-06-09 15:44:28 -0700883 boot_linux_from_mmc();
884 }
885 else
886 {
Shashank Mittald8c42bf2010-06-09 15:44:28 -0700887 recovery_init();
888 boot_linux_from_flash();
889 }
Dima Zavinb4283602009-01-26 16:36:57 -0800890 dprintf(CRITICAL, "ERROR: Could not do normal boot. Reverting "
891 "to fastboot mode.\n");
892
893fastboot:
Chandan Uddaraju2943fd62010-06-21 10:56:39 -0700894
Amol Jadi57abe4c2011-05-24 15:47:27 -0700895 target_fastboot_init();
896
Shashank Mittald8c42bf2010-06-09 15:44:28 -0700897 if(!usb_init)
898 udc_init(&surf_udc_device);
Brian Swetland9c4c0752009-01-25 16:23:50 -0800899
900 fastboot_register("boot", cmd_boot);
Bikas Gurungd48bd242010-09-04 19:54:32 -0700901
Shashank Mittal23b8f422010-04-16 19:27:21 -0700902 if (target_is_emmc_boot())
Shashank Mittald8c42bf2010-06-09 15:44:28 -0700903 {
904 fastboot_register("flash:", cmd_flash_mmc);
Bikas Gurungd48bd242010-09-04 19:54:32 -0700905 fastboot_register("erase:", cmd_erase_mmc);
Shashank Mittald8c42bf2010-06-09 15:44:28 -0700906 }
907 else
908 {
909 fastboot_register("flash:", cmd_flash);
Bikas Gurungd48bd242010-09-04 19:54:32 -0700910 fastboot_register("erase:", cmd_erase);
Shashank Mittald8c42bf2010-06-09 15:44:28 -0700911 }
912
913 fastboot_register("continue", cmd_continue);
Chandan Uddaraju94183c02010-01-15 15:13:59 -0800914 fastboot_register("reboot", cmd_reboot);
915 fastboot_register("reboot-bootloader", cmd_reboot_bootloader);
Subbaraman Narayanamurthyeb92bcc2010-07-20 14:32:46 -0700916 fastboot_publish("product", TARGET(BOARD));
Brian Swetland9c4c0752009-01-25 16:23:50 -0800917 fastboot_publish("kernel", "lk");
Vivek Mehta5f1c9d42011-04-01 20:11:59 -0700918 sz = target_get_max_flash_size();
919 fastboot_init(target_get_scratch_address(), sz);
Brian Swetland9c4c0752009-01-25 16:23:50 -0800920 udc_start();
Shashank Mittald8c42bf2010-06-09 15:44:28 -0700921 target_battery_charging_enable(1, 0);
Brian Swetland9c4c0752009-01-25 16:23:50 -0800922}
923
924APP_START(aboot)
925 .init = aboot_init,
926APP_END
927