First version
[3rdparty/ote_partner/tlk.git] / app / aboot / aboot.c
1 /*
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
40 #include <dev/flash.h>
41 #include <lib/ptable.h>
42 #include <dev/keys.h>
43
44 #include "bootimg.h"
45 #include "fastboot.h"
46
47 #define TAGS_ADDR       0x10000100
48 #define KERNEL_ADDR     0x10800000
49 #define RAMDISK_ADDR    0x11000000
50 #define DEFAULT_CMDLINE "mem=50M console=null";
51
52 static struct udc_device surf_udc_device = {
53         .vendor_id      = 0x18d1,
54         .product_id     = 0x0001,
55         .version_id     = 0x0100,
56         .manufacturer   = "Google",
57         .product        = "Android",
58 };
59
60 struct atag_ptbl_entry
61 {
62         char name[16];
63         unsigned offset;
64         unsigned size;
65         unsigned flags;
66 };
67
68 void platform_uninit_timer(void);
69
70 static void ptentry_to_tag(unsigned **ptr, struct ptentry *ptn)
71 {
72         struct atag_ptbl_entry atag_ptn;
73
74         memcpy(atag_ptn.name, ptn->name, 16);
75         atag_ptn.name[15] = '\0';
76         atag_ptn.offset = ptn->start;
77         atag_ptn.size = ptn->length;
78         atag_ptn.flags = ptn->flags;
79         memcpy(*ptr, &atag_ptn, sizeof(struct atag_ptbl_entry));
80         *ptr += sizeof(struct atag_ptbl_entry) / sizeof(unsigned);
81 }
82
83 void boot_linux(void *kernel, unsigned *tags, 
84                 const char *cmdline, unsigned machtype,
85                 void *ramdisk, unsigned ramdisk_size)
86 {
87         unsigned *ptr = tags;
88         void (*entry)(unsigned,unsigned,unsigned*) = kernel;
89         struct ptable *ptable;
90
91         /* CORE */
92         *ptr++ = 2;
93         *ptr++ = 0x54410001;
94
95         if (ramdisk_size) {
96                 *ptr++ = 4;
97                 *ptr++ = 0x54420005;
98                 *ptr++ = (unsigned)ramdisk;
99                 *ptr++ = ramdisk_size;
100         }
101
102         if ((ptable = flash_get_ptable()) && (ptable->count != 0)) {
103                 int i;
104                 *ptr++ = 2 + (ptable->count * (sizeof(struct atag_ptbl_entry) /
105                                                sizeof(unsigned)));
106                 *ptr++ = 0x4d534d70;
107                 for (i = 0; i < ptable->count; ++i)
108                         ptentry_to_tag(&ptr, ptable_get(ptable, i));
109         }
110
111         if (cmdline && cmdline[0]) {
112                 unsigned n;
113                 /* include terminating 0 and round up to a word multiple */
114                 n = (strlen(cmdline) + 4) & (~3);
115                 *ptr++ = (n / 4) + 2;
116                 *ptr++ = 0x54410009;
117                 memcpy(ptr, cmdline, n);
118                 ptr += (n / 4);
119         }
120
121         /* END */
122         *ptr++ = 0;
123         *ptr++ = 0;
124
125         dprintf(INFO, "booting linux @ %p, ramdisk @ %p (%d)\n",
126                 kernel, ramdisk, ramdisk_size);
127         if (cmdline)
128                 dprintf(INFO, "cmdline: %s\n", cmdline);
129
130         enter_critical_section();
131         platform_uninit_timer();
132         arch_disable_cache(UCACHE);
133         arch_disable_mmu();
134
135         entry(0, machtype, tags);
136
137 }
138
139 #define PAGE_MASK 2047
140
141 #define ROUND_TO_PAGE(x) (((x) + PAGE_MASK) & (~PAGE_MASK))
142
143 static unsigned char buf[2048];
144
145 int boot_linux_from_flash(void)
146 {
147         struct boot_img_hdr *hdr = (void*) buf;
148         unsigned n;
149         struct ptentry *ptn;
150         struct ptable *ptable;
151         unsigned offset = 0;
152         const char *cmdline;
153
154         ptable = flash_get_ptable();
155         if (ptable == NULL) {
156                 dprintf(CRITICAL, "ERROR: Partition table not found\n");
157                 return -1;
158         }
159
160         ptn = ptable_find(ptable, "boot");
161         if (ptn == NULL) {
162                 dprintf(CRITICAL, "ERROR: No boot partition found\n");
163                 return -1;
164         }
165
166         if (flash_read(ptn, offset, buf, 2048)) {
167                 dprintf(CRITICAL, "ERROR: Cannot read boot image header\n");
168                 return -1;
169         }
170         offset += 2048;
171
172         if (memcmp(hdr->magic, BOOT_MAGIC, BOOT_MAGIC_SIZE)) {
173                 dprintf(CRITICAL, "ERROR: Invaled boot image heador\n");
174                 return -1;
175         }
176
177         n = ROUND_TO_PAGE(hdr->kernel_size);
178         if (flash_read(ptn, offset, (void *)hdr->kernel_addr, n)) {
179                 dprintf(CRITICAL, "ERROR: Cannot read kernel image\n");
180                 return -1;
181         }
182         offset += n;
183
184         n = ROUND_TO_PAGE(hdr->ramdisk_size);
185         if (flash_read(ptn, offset, (void *)hdr->ramdisk_addr, n)) {
186                 dprintf(CRITICAL, "ERROR: Cannot read ramdisk image\n");
187                 return -1;
188         }
189         offset += n;
190
191         dprintf(INFO, "\nkernel  @ %x (%d bytes)\n", hdr->kernel_addr,
192                 hdr->kernel_size);
193         dprintf(INFO, "ramdisk @ %x (%d bytes)\n", hdr->ramdisk_addr,
194                 hdr->ramdisk_size);
195
196         if(hdr->cmdline[0]) {
197                 cmdline = (char*) hdr->cmdline;
198         } else {
199                 cmdline = DEFAULT_CMDLINE;
200         }
201         dprintf(INFO, "cmdline = '%s'\n", cmdline);
202
203         /* TODO: create/pass atags to kernel */
204
205         dprintf(INFO, "\nBooting Linux\n");
206         boot_linux((void *)hdr->kernel_addr, (void *)TAGS_ADDR,
207                    (const char *)cmdline, LINUX_MACHTYPE,
208                    (void *)hdr->ramdisk_addr, hdr->ramdisk_size);
209
210         return 0;
211 }
212
213 void cmd_boot(const char *arg, void *data, unsigned sz)
214 {
215         unsigned kernel_actual;
216         unsigned ramdisk_actual;
217         static struct boot_img_hdr hdr;
218         char *ptr = ((char*) data);
219
220         if (sz < sizeof(hdr)) {
221                 fastboot_fail("invalid bootimage header");
222                 return;
223         }
224
225         memcpy(&hdr, data, sizeof(hdr));
226
227         /* ensure commandline is terminated */
228         hdr.cmdline[BOOT_ARGS_SIZE-1] = 0;
229
230         kernel_actual = ROUND_TO_PAGE(hdr.kernel_size);
231         ramdisk_actual = ROUND_TO_PAGE(hdr.ramdisk_size);
232
233         if (2048 + kernel_actual + ramdisk_actual < sz) {
234                 fastboot_fail("incomplete bootimage");
235                 return;
236         }
237
238         memmove((void*) KERNEL_ADDR, ptr + 2048, hdr.kernel_size);
239         memmove((void*) RAMDISK_ADDR, ptr + 2048 + kernel_actual, hdr.ramdisk_size);
240
241         fastboot_okay("");
242         udc_stop();
243
244
245         boot_linux((void*) KERNEL_ADDR, (void*) TAGS_ADDR,
246                    (const char*) hdr.cmdline, LINUX_MACHTYPE,
247                    (void*) RAMDISK_ADDR, hdr.ramdisk_size);
248 }
249
250 void cmd_erase(const char *arg, void *data, unsigned sz)
251 {
252         struct ptentry *ptn;
253         struct ptable *ptable;
254
255         ptable = flash_get_ptable();
256         if (ptable == NULL) {
257                 fastboot_fail("partition table doesn't exist");
258                 return;
259         }
260
261         ptn = ptable_find(ptable, arg);
262         if (ptn == NULL) {
263                 fastboot_fail("unknown partition name");
264                 return;
265         }
266
267         if (flash_erase(ptn)) {
268                 fastboot_fail("failed to erase partition");
269                 return;
270         }
271         fastboot_okay("");
272 }
273
274 void cmd_flash(const char *arg, void *data, unsigned sz)
275 {
276         struct ptentry *ptn;
277         struct ptable *ptable;
278         unsigned extra = 0;
279
280         ptable = flash_get_ptable();
281         if (ptable == NULL) {
282                 fastboot_fail("partition table doesn't exist");
283                 return;
284         }
285
286         ptn = ptable_find(ptable, arg);
287         if (ptn == NULL) {
288                 fastboot_fail("unknown partition name");
289                 return;
290         }
291
292         if (!strcmp(ptn->name, "boot") || !strcmp(ptn->name, "recovery")) {
293                 if (memcmp((void *)data, BOOT_MAGIC, BOOT_MAGIC_SIZE)) {
294                         fastboot_fail("image is not a boot image");
295                         return;
296                 }
297         }
298
299         if (!strcmp(ptn->name, "system") || !strcmp(ptn->name, "userdata"))
300                 extra = 64;
301         else
302                 sz = ROUND_TO_PAGE(sz);
303
304         dprintf(INFO, "writing %d bytes to '%s'\n", sz, ptn->name);
305         if (flash_write(ptn, extra, data, sz)) {
306                 fastboot_fail("flash write failure");
307                 return;
308         }
309         dprintf(INFO, "partition '%s' updated\n", ptn->name);
310         fastboot_okay("");
311 }
312
313 void cmd_continue(const char *arg, void *data, unsigned sz)
314 {
315         fastboot_okay("");
316         udc_stop();
317
318         boot_linux_from_flash();
319 }
320
321 void aboot_init(const struct app_descriptor *app)
322 {
323         if (keys_get_state(KEY_BACK) != 0)
324                 goto fastboot;
325
326         boot_linux_from_flash();
327         dprintf(CRITICAL, "ERROR: Could not do normal boot. Reverting "
328                 "to fastboot mode.\n");
329
330 fastboot:
331         udc_init(&surf_udc_device);
332
333         fastboot_register("boot", cmd_boot);
334         fastboot_register("erase:", cmd_erase);
335         fastboot_register("flash:", cmd_flash);
336         fastboot_register("continue", cmd_continue);
337         fastboot_publish("product", "swordfish");
338         fastboot_publish("kernel", "lk");
339
340         fastboot_init((void*) 0x10100000, 100 * 1024 * 1024);
341         udc_start();
342 }
343
344 APP_START(aboot)
345         .init = aboot_init,
346 APP_END
347