blob: 9c525c80d13be7fa20163b0e863cf7a9b3a638ee [file] [log] [blame]
Brian Swetland9c4c0752009-01-25 16:23:50 -08001/*
2 * Copyright (c) 2009, Google Inc.
3 * All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
8 * * Redistributions of source code must retain the above copyright
9 * notice, this list of conditions and the following disclaimer.
10 * * Redistributions in binary form must reproduce the above copyright
11 * notice, this list of conditions and the following disclaimer in
12 * the documentation and/or other materials provided with the
13 * distribution.
14 * * Neither the name of Google, Inc. nor the names of its contributors
15 * may be used to endorse or promote products derived from this
16 * software without specific prior written permission.
17 *
18 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
19 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
20 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
21 * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
22 * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
23 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
24 * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
25 * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
26 * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
27 * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
28 * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
29 * SUCH DAMAGE.
30 */
31
32#include <app.h>
33#include <debug.h>
34#include <arch/arm.h>
35#include <dev/udc.h>
36#include <string.h>
37#include <kernel/thread.h>
38#include <arch/ops.h>
39
Dima Zavin214cc642009-01-26 11:16:21 -080040#include <dev/flash.h>
41#include <lib/ptable.h>
Dima Zavinb4283602009-01-26 16:36:57 -080042#include <dev/keys.h>
Dima Zavin214cc642009-01-26 11:16:21 -080043
Brian Swetland9c4c0752009-01-25 16:23:50 -080044#include "bootimg.h"
45#include "fastboot.h"
46
Chandan Uddarajuda919832009-11-17 01:06:11 -080047#define DEFAULT_CMDLINE "mem=100M console=null";
Brian Swetland2defe162009-08-18 14:35:59 -070048
Brian Swetland9c4c0752009-01-25 16:23:50 -080049static struct udc_device surf_udc_device = {
50 .vendor_id = 0x18d1,
Chandan Uddarajuc53a1a12009-11-18 14:53:40 -080051 .product_id = 0xD00D,
Brian Swetland9c4c0752009-01-25 16:23:50 -080052 .version_id = 0x0100,
53 .manufacturer = "Google",
54 .product = "Android",
55};
56
Dima Zavin42168f22009-01-30 11:52:22 -080057struct atag_ptbl_entry
58{
59 char name[16];
60 unsigned offset;
61 unsigned size;
62 unsigned flags;
63};
64
Brian Swetland9c4c0752009-01-25 16:23:50 -080065void platform_uninit_timer(void);
66
Dima Zavin42168f22009-01-30 11:52:22 -080067static void ptentry_to_tag(unsigned **ptr, struct ptentry *ptn)
68{
69 struct atag_ptbl_entry atag_ptn;
70
71 memcpy(atag_ptn.name, ptn->name, 16);
72 atag_ptn.name[15] = '\0';
73 atag_ptn.offset = ptn->start;
74 atag_ptn.size = ptn->length;
75 atag_ptn.flags = ptn->flags;
76 memcpy(*ptr, &atag_ptn, sizeof(struct atag_ptbl_entry));
77 *ptr += sizeof(struct atag_ptbl_entry) / sizeof(unsigned);
78}
Brian Swetland9c4c0752009-01-25 16:23:50 -080079
80void boot_linux(void *kernel, unsigned *tags,
81 const char *cmdline, unsigned machtype,
82 void *ramdisk, unsigned ramdisk_size)
83{
84 unsigned *ptr = tags;
85 void (*entry)(unsigned,unsigned,unsigned*) = kernel;
Dima Zavin42168f22009-01-30 11:52:22 -080086 struct ptable *ptable;
Brian Swetland9c4c0752009-01-25 16:23:50 -080087
88 /* CORE */
89 *ptr++ = 2;
90 *ptr++ = 0x54410001;
91
92 if (ramdisk_size) {
93 *ptr++ = 4;
94 *ptr++ = 0x54420005;
Dima Zavin214cc642009-01-26 11:16:21 -080095 *ptr++ = (unsigned)ramdisk;
Brian Swetland9c4c0752009-01-25 16:23:50 -080096 *ptr++ = ramdisk_size;
97 }
98
Dima Zavin42168f22009-01-30 11:52:22 -080099 if ((ptable = flash_get_ptable()) && (ptable->count != 0)) {
100 int i;
101 *ptr++ = 2 + (ptable->count * (sizeof(struct atag_ptbl_entry) /
102 sizeof(unsigned)));
103 *ptr++ = 0x4d534d70;
104 for (i = 0; i < ptable->count; ++i)
105 ptentry_to_tag(&ptr, ptable_get(ptable, i));
106 }
107
Brian Swetland9c4c0752009-01-25 16:23:50 -0800108 if (cmdline && cmdline[0]) {
109 unsigned n;
110 /* include terminating 0 and round up to a word multiple */
111 n = (strlen(cmdline) + 4) & (~3);
112 *ptr++ = (n / 4) + 2;
113 *ptr++ = 0x54410009;
114 memcpy(ptr, cmdline, n);
115 ptr += (n / 4);
116 }
117
118 /* END */
119 *ptr++ = 0;
120 *ptr++ = 0;
121
122 dprintf(INFO, "booting linux @ %p, ramdisk @ %p (%d)\n",
123 kernel, ramdisk, ramdisk_size);
124 if (cmdline)
125 dprintf(INFO, "cmdline: %s\n", cmdline);
126
127 enter_critical_section();
128 platform_uninit_timer();
129 arch_disable_cache(UCACHE);
Brian Swetland9c4c0752009-01-25 16:23:50 -0800130 arch_disable_mmu();
131
132 entry(0, machtype, tags);
133
134}
135
Shashank Mittaldcc2e352009-11-19 19:11:16 -0800136unsigned page_size = 0;
137unsigned page_mask = 0;
Brian Swetland9c4c0752009-01-25 16:23:50 -0800138
Shashank Mittaldcc2e352009-11-19 19:11:16 -0800139#define ROUND_TO_PAGE(x,y) (((x) + (y)) & (~(y)))
Brian Swetland9c4c0752009-01-25 16:23:50 -0800140
Shashank Mittaldcc2e352009-11-19 19:11:16 -0800141static unsigned char buf[4096]; //Equal to max-supported pagesize
Dima Zavin214cc642009-01-26 11:16:21 -0800142
143int boot_linux_from_flash(void)
144{
145 struct boot_img_hdr *hdr = (void*) buf;
146 unsigned n;
147 struct ptentry *ptn;
148 struct ptable *ptable;
149 unsigned offset = 0;
150 const char *cmdline;
151
152 ptable = flash_get_ptable();
153 if (ptable == NULL) {
154 dprintf(CRITICAL, "ERROR: Partition table not found\n");
155 return -1;
156 }
157
158 ptn = ptable_find(ptable, "boot");
159 if (ptn == NULL) {
160 dprintf(CRITICAL, "ERROR: No boot partition found\n");
161 return -1;
162 }
163
Shashank Mittaldcc2e352009-11-19 19:11:16 -0800164 if (flash_read(ptn, offset, buf, page_size)) {
Dima Zavin214cc642009-01-26 11:16:21 -0800165 dprintf(CRITICAL, "ERROR: Cannot read boot image header\n");
166 return -1;
167 }
Shashank Mittaldcc2e352009-11-19 19:11:16 -0800168 offset += page_size;
Dima Zavin214cc642009-01-26 11:16:21 -0800169
170 if (memcmp(hdr->magic, BOOT_MAGIC, BOOT_MAGIC_SIZE)) {
171 dprintf(CRITICAL, "ERROR: Invaled boot image heador\n");
172 return -1;
173 }
174
Shashank Mittaldcc2e352009-11-19 19:11:16 -0800175 if (hdr->page_size != page_size) {
176 dprintf(CRITICAL, "ERROR: Invaled boot image pagesize. Device pagesize: %d, Image pagesize: %d\n",page_size,hdr->page_size);
177 return -1;
178 }
179
180 n = ROUND_TO_PAGE(hdr->kernel_size, page_mask);
Dima Zavin214cc642009-01-26 11:16:21 -0800181 if (flash_read(ptn, offset, (void *)hdr->kernel_addr, n)) {
182 dprintf(CRITICAL, "ERROR: Cannot read kernel image\n");
183 return -1;
184 }
185 offset += n;
186
Shashank Mittaldcc2e352009-11-19 19:11:16 -0800187 n = ROUND_TO_PAGE(hdr->ramdisk_size, page_mask);
Dima Zavin214cc642009-01-26 11:16:21 -0800188 if (flash_read(ptn, offset, (void *)hdr->ramdisk_addr, n)) {
189 dprintf(CRITICAL, "ERROR: Cannot read ramdisk image\n");
190 return -1;
191 }
192 offset += n;
193
194 dprintf(INFO, "\nkernel @ %x (%d bytes)\n", hdr->kernel_addr,
195 hdr->kernel_size);
196 dprintf(INFO, "ramdisk @ %x (%d bytes)\n", hdr->ramdisk_addr,
197 hdr->ramdisk_size);
198
199 if(hdr->cmdline[0]) {
200 cmdline = (char*) hdr->cmdline;
201 } else {
202 cmdline = DEFAULT_CMDLINE;
203 }
204 dprintf(INFO, "cmdline = '%s'\n", cmdline);
205
206 /* TODO: create/pass atags to kernel */
207
208 dprintf(INFO, "\nBooting Linux\n");
209 boot_linux((void *)hdr->kernel_addr, (void *)TAGS_ADDR,
Dima Zavinf9faf3a2009-01-29 11:43:30 -0800210 (const char *)cmdline, LINUX_MACHTYPE,
Dima Zavin214cc642009-01-26 11:16:21 -0800211 (void *)hdr->ramdisk_addr, hdr->ramdisk_size);
212
213 return 0;
214}
Brian Swetland9c4c0752009-01-25 16:23:50 -0800215
216void cmd_boot(const char *arg, void *data, unsigned sz)
217{
218 unsigned kernel_actual;
219 unsigned ramdisk_actual;
220 static struct boot_img_hdr hdr;
221 char *ptr = ((char*) data);
222
223 if (sz < sizeof(hdr)) {
224 fastboot_fail("invalid bootimage header");
225 return;
226 }
227
228 memcpy(&hdr, data, sizeof(hdr));
229
230 /* ensure commandline is terminated */
231 hdr.cmdline[BOOT_ARGS_SIZE-1] = 0;
232
Shashank Mittaldcc2e352009-11-19 19:11:16 -0800233 kernel_actual = ROUND_TO_PAGE(hdr.kernel_size, page_mask);
234 ramdisk_actual = ROUND_TO_PAGE(hdr.ramdisk_size, page_mask);
Brian Swetland9c4c0752009-01-25 16:23:50 -0800235
236 if (2048 + kernel_actual + ramdisk_actual < sz) {
237 fastboot_fail("incomplete bootimage");
238 return;
239 }
240
241 memmove((void*) KERNEL_ADDR, ptr + 2048, hdr.kernel_size);
242 memmove((void*) RAMDISK_ADDR, ptr + 2048 + kernel_actual, hdr.ramdisk_size);
243
244 fastboot_okay("");
245 udc_stop();
246
247
248 boot_linux((void*) KERNEL_ADDR, (void*) TAGS_ADDR,
Dima Zavinf9faf3a2009-01-29 11:43:30 -0800249 (const char*) hdr.cmdline, LINUX_MACHTYPE,
Brian Swetland9c4c0752009-01-25 16:23:50 -0800250 (void*) RAMDISK_ADDR, hdr.ramdisk_size);
251}
252
Dima Zavin214cc642009-01-26 11:16:21 -0800253void cmd_erase(const char *arg, void *data, unsigned sz)
254{
255 struct ptentry *ptn;
256 struct ptable *ptable;
257
258 ptable = flash_get_ptable();
259 if (ptable == NULL) {
260 fastboot_fail("partition table doesn't exist");
261 return;
262 }
263
264 ptn = ptable_find(ptable, arg);
265 if (ptn == NULL) {
266 fastboot_fail("unknown partition name");
267 return;
268 }
269
270 if (flash_erase(ptn)) {
271 fastboot_fail("failed to erase partition");
272 return;
273 }
274 fastboot_okay("");
275}
276
277void cmd_flash(const char *arg, void *data, unsigned sz)
278{
279 struct ptentry *ptn;
280 struct ptable *ptable;
281 unsigned extra = 0;
282
283 ptable = flash_get_ptable();
284 if (ptable == NULL) {
285 fastboot_fail("partition table doesn't exist");
286 return;
287 }
288
289 ptn = ptable_find(ptable, arg);
290 if (ptn == NULL) {
291 fastboot_fail("unknown partition name");
292 return;
293 }
294
295 if (!strcmp(ptn->name, "boot") || !strcmp(ptn->name, "recovery")) {
296 if (memcmp((void *)data, BOOT_MAGIC, BOOT_MAGIC_SIZE)) {
297 fastboot_fail("image is not a boot image");
298 return;
299 }
300 }
301
302 if (!strcmp(ptn->name, "system") || !strcmp(ptn->name, "userdata"))
Shashank Mittaldcc2e352009-11-19 19:11:16 -0800303 extra = ((page_size >> 9) * 16);
Dima Zavin214cc642009-01-26 11:16:21 -0800304 else
Shashank Mittaldcc2e352009-11-19 19:11:16 -0800305 sz = ROUND_TO_PAGE(sz, page_mask);
Dima Zavin214cc642009-01-26 11:16:21 -0800306
307 dprintf(INFO, "writing %d bytes to '%s'\n", sz, ptn->name);
308 if (flash_write(ptn, extra, data, sz)) {
309 fastboot_fail("flash write failure");
310 return;
311 }
312 dprintf(INFO, "partition '%s' updated\n", ptn->name);
313 fastboot_okay("");
314}
315
316void cmd_continue(const char *arg, void *data, unsigned sz)
317{
318 fastboot_okay("");
319 udc_stop();
320
321 boot_linux_from_flash();
322}
323
Brian Swetland9c4c0752009-01-25 16:23:50 -0800324void aboot_init(const struct app_descriptor *app)
325{
Shashank Mittaldcc2e352009-11-19 19:11:16 -0800326 page_size = flash_page_size();
327 page_mask = page_size - 1;
Dima Zavinb4283602009-01-26 16:36:57 -0800328 if (keys_get_state(KEY_BACK) != 0)
329 goto fastboot;
330
331 boot_linux_from_flash();
332 dprintf(CRITICAL, "ERROR: Could not do normal boot. Reverting "
333 "to fastboot mode.\n");
334
335fastboot:
Brian Swetland9c4c0752009-01-25 16:23:50 -0800336 udc_init(&surf_udc_device);
337
338 fastboot_register("boot", cmd_boot);
Dima Zavin214cc642009-01-26 11:16:21 -0800339 fastboot_register("erase:", cmd_erase);
340 fastboot_register("flash:", cmd_flash);
341 fastboot_register("continue", cmd_continue);
Brian Swetland9c4c0752009-01-25 16:23:50 -0800342 fastboot_publish("product", "swordfish");
343 fastboot_publish("kernel", "lk");
344
Brian Swetland2defe162009-08-18 14:35:59 -0700345 fastboot_init((void*) SCRATCH_ADDR, 100 * 1024 * 1024);
Brian Swetland9c4c0752009-01-25 16:23:50 -0800346 udc_start();
347}
348
349APP_START(aboot)
350 .init = aboot_init,
351APP_END
352