blob: ac71cd4207d073d333b7f97bcd43b56eb1141ad5 [file] [log] [blame]
Pavel Nedeva1e62322013-04-05 15:21:36 +03001/* Copyright (c) 2010-2013, The Linux Foundation. All rights reserved.
Shashank Mittal024c0332010-02-03 11:44:00 -08002
3 * Redistribution and use in source and binary forms, with or without
4 * modification, are permitted provided that the following conditions are
5 * met:
6 * * Redistributions of source code must retain the above copyright
7 * notice, this list of conditions and the following disclaimer.
8 * * Redistributions in binary form must reproduce the above
9 * copyright notice, this list of conditions and the following
10 * disclaimer in the documentation and/or other materials provided
11 * with the distribution.
Duy Truongf3ac7b32013-02-13 01:07:28 -080012 * * Neither the name of The Linux Foundation nor the names of its
Shashank Mittal024c0332010-02-03 11:44:00 -080013 * contributors may be used to endorse or promote products derived
14 * from this software without specific prior written permission.
15 *
16 * THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED
17 * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
18 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT
19 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS
20 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
21 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
22 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
23 * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
24 * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
25 * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
26 * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27 */
28
29#include <debug.h>
30#include <arch/arm.h>
31#include <dev/udc.h>
32#include <string.h>
33#include <kernel/thread.h>
34#include <arch/ops.h>
35
36#include <dev/flash.h>
37#include <lib/ptable.h>
38#include <dev/keys.h>
Greg Griscod6250552011-06-29 14:40:23 -070039#include <platform.h>
Pavel Nedeva1e62322013-04-05 15:21:36 +030040#include <target.h>
Kinson Chikf1a43512011-07-14 11:28:39 -070041#include <partition_parser.h>
Greg Griscod2471ef2011-07-14 13:00:42 -070042#include <mmc.h>
Shashank Mittal024c0332010-02-03 11:44:00 -080043
44#include "recovery.h"
45#include "bootimg.h"
Subbaraman Narayanamurthy0e445b02011-06-19 21:34:46 -070046#include "smem.h"
47
48#define BOOT_FLAGS 1
49#define UPDATE_STATUS 2
50#define ROUND_TO_PAGE(x,y) (((x) + (y)) & (~(y)))
Shashank Mittal024c0332010-02-03 11:44:00 -080051
52static const int MISC_PAGES = 3; // number of pages to save
53static const int MISC_COMMAND_PAGE = 1; // bootloader command is this page
54static char buf[4096];
Pavel Nedeva1e62322013-04-05 15:21:36 +030055
Shashank Mittal024c0332010-02-03 11:44:00 -080056unsigned boot_into_recovery = 0;
57
Shashank Mittal162244e2011-08-08 19:01:25 -070058extern void reset_device_info();
59extern void set_device_root();
Shashank Mittal024c0332010-02-03 11:44:00 -080060
61int get_recovery_message(struct recovery_message *out)
62{
63 struct ptentry *ptn;
64 struct ptable *ptable;
65 unsigned offset = 0;
66 unsigned pagesize = flash_page_size();
67
68 ptable = flash_get_ptable();
69
70 if (ptable == NULL) {
71 dprintf(CRITICAL, "ERROR: Partition table not found\n");
72 return -1;
73 }
74 ptn = ptable_find(ptable, "misc");
75
76 if (ptn == NULL) {
77 dprintf(CRITICAL, "ERROR: No misc partition found\n");
78 return -1;
79 }
80
81 offset += (pagesize * MISC_COMMAND_PAGE);
Greg Griscod6250552011-06-29 14:40:23 -070082 if (flash_read(ptn, offset, (void *) buf, pagesize)) {
Shashank Mittal024c0332010-02-03 11:44:00 -080083 dprintf(CRITICAL, "ERROR: Cannot read recovery_header\n");
84 return -1;
85 }
86 memcpy(out, buf, sizeof(*out));
87 return 0;
88}
89
90int set_recovery_message(const struct recovery_message *in)
91{
92 struct ptentry *ptn;
93 struct ptable *ptable;
94 unsigned offset = 0;
95 unsigned pagesize = flash_page_size();
96 unsigned n = 0;
97
98 ptable = flash_get_ptable();
99
100 if (ptable == NULL) {
101 dprintf(CRITICAL, "ERROR: Partition table not found\n");
102 return -1;
103 }
104 ptn = ptable_find(ptable, "misc");
105
106 if (ptn == NULL) {
107 dprintf(CRITICAL, "ERROR: No misc partition found\n");
108 return -1;
109 }
110
111 n = pagesize * (MISC_COMMAND_PAGE + 1);
112
Greg Griscod6250552011-06-29 14:40:23 -0700113 if (flash_read(ptn, offset, (void *) SCRATCH_ADDR, n)) {
Shashank Mittal024c0332010-02-03 11:44:00 -0800114 dprintf(CRITICAL, "ERROR: Cannot read recovery_header\n");
115 return -1;
116 }
117
118 offset += (pagesize * MISC_COMMAND_PAGE);
119 offset += SCRATCH_ADDR;
Greg Griscod6250552011-06-29 14:40:23 -0700120 memcpy((void *) offset, in, sizeof(*in));
Shashank Mittal024c0332010-02-03 11:44:00 -0800121 if (flash_write(ptn, 0, (void *)SCRATCH_ADDR, n)) {
122 dprintf(CRITICAL, "ERROR: flash write fail!\n");
123 return -1;
124 }
Greg Griscod6250552011-06-29 14:40:23 -0700125 return 0;
Shashank Mittal024c0332010-02-03 11:44:00 -0800126}
127
128int read_update_header_for_bootloader(struct update_header *header)
129{
130 struct ptentry *ptn;
131 struct ptable *ptable;
132 unsigned offset = 0;
133 unsigned pagesize = flash_page_size();
134
135 ptable = flash_get_ptable();
136 if (ptable == NULL) {
137 dprintf(CRITICAL, "ERROR: Partition table not found\n");
138 return -1;
139 }
140 ptn = ptable_find(ptable, "cache");
141
142 if (ptn == NULL) {
143 dprintf(CRITICAL, "ERROR: No cache partition found\n");
144 return -1;
145 }
146 if (flash_read(ptn, offset, buf, pagesize)) {
147 dprintf(CRITICAL, "ERROR: Cannot read recovery_header\n");
148 return -1;
149 }
150 memcpy(header, buf, sizeof(*header));
151
Greg Griscod6250552011-06-29 14:40:23 -0700152 if (strncmp((char *) header->MAGIC, UPDATE_MAGIC, UPDATE_MAGIC_SIZE))
Shashank Mittal024c0332010-02-03 11:44:00 -0800153 {
154 return -1;
155 }
156 return 0;
157}
158
159int update_firmware_image (struct update_header *header, char *name)
160{
161 struct ptentry *ptn;
162 struct ptable *ptable;
163 unsigned offset = 0;
164 unsigned pagesize = flash_page_size();
165 unsigned pagemask = pagesize -1;
166 unsigned n = 0;
167
168 ptable = flash_get_ptable();
169 if (ptable == NULL) {
170 dprintf(CRITICAL, "ERROR: Partition table not found\n");
171 return -1;
172 }
173
174 ptn = ptable_find(ptable, "cache");
175 if (ptn == NULL) {
176 dprintf(CRITICAL, "ERROR: No cache partition found\n");
177 return -1;
178 }
179
180 offset += header->image_offset;
181 n = (header->image_length + pagemask) & (~pagemask);
182
Greg Griscod6250552011-06-29 14:40:23 -0700183 if (flash_read(ptn, offset, (void *) SCRATCH_ADDR, n)) {
Shashank Mittal024c0332010-02-03 11:44:00 -0800184 dprintf(CRITICAL, "ERROR: Cannot read radio image\n");
185 return -1;
186 }
187
188 ptn = ptable_find(ptable, name);
189 if (ptn == NULL) {
190 dprintf(CRITICAL, "ERROR: No %s partition found\n", name);
191 return -1;
192 }
193
Greg Griscod6250552011-06-29 14:40:23 -0700194 if (flash_write(ptn, 0, (void *) SCRATCH_ADDR, n)) {
Shashank Mittal024c0332010-02-03 11:44:00 -0800195 dprintf(CRITICAL, "ERROR: flash write fail!\n");
196 return -1;
197 }
198
199 dprintf(INFO, "Partition writen successfully!");
200 return 0;
201}
202
Subbaraman Narayanamurthy0e445b02011-06-19 21:34:46 -0700203static int set_ssd_radio_update (char *name)
204{
205 struct ptentry *ptn;
206 struct ptable *ptable;
207 unsigned int ssd_cookie[2] = {0x53534443, 0x4F4F4B49};
208 unsigned pagesize = flash_page_size();
209 unsigned pagemask = pagesize -1;
210 unsigned n = 0;
211
212 ptable = flash_get_ptable();
213 if (ptable == NULL) {
214 dprintf(CRITICAL, "ERROR: Partition table not found\n");
215 return -1;
216 }
217
218 n = (sizeof(ssd_cookie) + pagemask) & (~pagemask);
219
220 ptn = ptable_find(ptable, name);
221 if (ptn == NULL) {
222 dprintf(CRITICAL, "ERROR: No %s partition found\n", name);
223 return -1;
224 }
225
226 if (flash_write(ptn, 0, ssd_cookie, n)) {
227 dprintf(CRITICAL, "ERROR: flash write fail!\n");
228 return -1;
229 }
230
231 dprintf(INFO, "FOTA partition written successfully!");
232 return 0;
233}
234
235int get_boot_info_apps (char type, unsigned int *status)
236{
237 boot_info_for_apps apps_boot_info;
238 int ret = 0;
239
240 ret = smem_read_alloc_entry(SMEM_BOOT_INFO_FOR_APPS,
241 &apps_boot_info, sizeof(apps_boot_info));
242 if (ret)
243 {
244 dprintf(CRITICAL, "ERROR: unable to read shared memory for apps boot info %d\n",ret);
245 return ret;
246 }
247
248 dprintf(INFO,"boot flag %x update status %x\n",apps_boot_info.boot_flags,
249 apps_boot_info.status.update_status);
250
251 if(type == BOOT_FLAGS)
252 *status = apps_boot_info.boot_flags;
253 else if(type == UPDATE_STATUS)
254 *status = apps_boot_info.status.update_status;
255
256 return ret;
257}
258
Shashank Mittal024c0332010-02-03 11:44:00 -0800259/* Bootloader / Recovery Flow
260 *
261 * On every boot, the bootloader will read the recovery_message
262 * from flash and check the command field. The bootloader should
263 * deal with the command field not having a 0 terminator correctly
264 * (so as to not crash if the block is invalid or corrupt).
265 *
266 * The bootloader will have to publish the partition that contains
267 * the recovery_message to the linux kernel so it can update it.
268 *
269 * if command == "boot-recovery" -> boot recovery.img
270 * else if command == "update-radio" -> update radio image (below)
271 * else -> boot boot.img (normal boot)
272 *
273 * Radio Update Flow
274 * 1. the bootloader will attempt to load and validate the header
275 * 2. if the header is invalid, status="invalid-update", goto #8
276 * 3. display the busy image on-screen
277 * 4. if the update image is invalid, status="invalid-radio-image", goto #8
278 * 5. attempt to update the firmware (depending on the command)
279 * 6. if successful, status="okay", goto #8
280 * 7. if failed, and the old image can still boot, status="failed-update"
281 * 8. write the recovery_message, leaving the recovery field
282 * unchanged, updating status, and setting command to
283 * "boot-recovery"
284 * 9. reboot
285 *
286 * The bootloader will not modify or erase the cache partition.
287 * It is recovery's responsibility to clean up the mess afterwards.
288 */
289
290int recovery_init (void)
291{
292 struct recovery_message msg;
Shashank Mittal024c0332010-02-03 11:44:00 -0800293 char partition_name[32];
294 unsigned valid_command = 0;
Subbaraman Narayanamurthy0e445b02011-06-19 21:34:46 -0700295 int update_status = 0;
Shashank Mittal024c0332010-02-03 11:44:00 -0800296
297 // get recovery message
Greg Griscod6250552011-06-29 14:40:23 -0700298 if (get_recovery_message(&msg))
Shashank Mittal024c0332010-02-03 11:44:00 -0800299 return -1;
300 if (msg.command[0] != 0 && msg.command[0] != 255) {
Greg Griscod6250552011-06-29 14:40:23 -0700301 dprintf(INFO, "Recovery command: %.*s\n", sizeof(msg.command), msg.command);
Shashank Mittal024c0332010-02-03 11:44:00 -0800302 }
303 msg.command[sizeof(msg.command)-1] = '\0'; //Ensure termination
304
Subbaraman Narayanamurthy0e445b02011-06-19 21:34:46 -0700305 if (!strcmp("boot-recovery",msg.command))
306 {
307 if(!strcmp("RADIO",msg.status))
308 {
309 /* We're now here due to radio update, so check for update status */
Greg Griscod2471ef2011-07-14 13:00:42 -0700310 int ret = get_boot_info_apps(UPDATE_STATUS, (unsigned int *) &update_status);
Subbaraman Narayanamurthy0e445b02011-06-19 21:34:46 -0700311
312 if(!ret && (update_status & 0x01))
313 {
314 dprintf(INFO,"radio update success\n");
Ajay Dudanif63d02f2011-10-01 08:29:53 -0700315 strlcpy(msg.status, "OKAY", sizeof(msg.status));
Subbaraman Narayanamurthy0e445b02011-06-19 21:34:46 -0700316 }
317 else
318 {
319 dprintf(INFO,"radio update failed\n");
Ajay Dudanif63d02f2011-10-01 08:29:53 -0700320 strlcpy(msg.status, "failed-update", sizeof(msg.status));
Subbaraman Narayanamurthy0e445b02011-06-19 21:34:46 -0700321 }
Ajay Dudanif63d02f2011-10-01 08:29:53 -0700322 strlcpy(msg.command, "", sizeof(msg.command)); // clearing recovery command
Subbaraman Narayanamurthy0e445b02011-06-19 21:34:46 -0700323 set_recovery_message(&msg); // send recovery message
324 boot_into_recovery = 1; // Boot in recovery mode
325 return 0;
326 }
327
Shashank Mittal024c0332010-02-03 11:44:00 -0800328 valid_command = 1;
Ajay Dudanif63d02f2011-10-01 08:29:53 -0700329 strlcpy(msg.command, "", sizeof(msg.command)); // to safe against multiple reboot into recovery
330 strlcpy(msg.status, "OKAY", sizeof(msg.status));
Shashank Mittal024c0332010-02-03 11:44:00 -0800331 set_recovery_message(&msg); // send recovery message
332 boot_into_recovery = 1; // Boot in recovery mode
333 return 0;
334 }
335
336 if (!strcmp("update-radio",msg.command)) {
Subbaraman Narayanamurthy0e445b02011-06-19 21:34:46 -0700337 dprintf(INFO,"start radio update\n");
Shashank Mittal024c0332010-02-03 11:44:00 -0800338 valid_command = 1;
Ajay Dudanif63d02f2011-10-01 08:29:53 -0700339 strlcpy(partition_name, "FOTA", sizeof(partition_name));
Shashank Mittal024c0332010-02-03 11:44:00 -0800340 }
341
342 //Todo: Add support for bootloader update too.
343
344 if(!valid_command) {
345 //We need not to do anything
346 return 0; // Boot in normal mode
347 }
348
Subbaraman Narayanamurthy0e445b02011-06-19 21:34:46 -0700349#ifdef OLD_FOTA_UPGRADE
Shashank Mittal024c0332010-02-03 11:44:00 -0800350 if (read_update_header_for_bootloader(&header)) {
Ajay Dudanif63d02f2011-10-01 08:29:53 -0700351 strlcpy(msg.status, "invalid-update", sizeof(msg.status));
Shashank Mittal024c0332010-02-03 11:44:00 -0800352 goto SEND_RECOVERY_MSG;
353 }
354
355 if (update_firmware_image (&header, partition_name)) {
Ajay Dudanif63d02f2011-10-01 08:29:53 -0700356 strlcpy(msg.status, "failed-update", sizeof(msg.status));
Shashank Mittal024c0332010-02-03 11:44:00 -0800357 goto SEND_RECOVERY_MSG;
358 }
Subbaraman Narayanamurthy0e445b02011-06-19 21:34:46 -0700359#else
360 if (set_ssd_radio_update(partition_name)) {
361 /* If writing to FOTA partition fails */
Ajay Dudanif63d02f2011-10-01 08:29:53 -0700362 strlcpy(msg.command, "", sizeof(msg.command));
363 strlcpy(msg.status, "failed-update", sizeof(msg.status));
Subbaraman Narayanamurthy0e445b02011-06-19 21:34:46 -0700364 goto SEND_RECOVERY_MSG;
365 }
366 else {
367 /* Setting this to check the radio update status */
Ajay Dudanif63d02f2011-10-01 08:29:53 -0700368 strlcpy(msg.command, "boot-recovery", sizeof(msg.command));
Ajay Dudanif4caa942011-10-02 08:57:15 -0700369 strlcpy(msg.status, "RADIO", sizeof(msg.status));
Subbaraman Narayanamurthy0e445b02011-06-19 21:34:46 -0700370 goto SEND_RECOVERY_MSG;
371 }
372#endif
Ajay Dudanif63d02f2011-10-01 08:29:53 -0700373 strlcpy(msg.status, "OKAY", sizeof(msg.status));
Shashank Mittal024c0332010-02-03 11:44:00 -0800374
375SEND_RECOVERY_MSG:
Shashank Mittal024c0332010-02-03 11:44:00 -0800376 set_recovery_message(&msg); // send recovery message
377 boot_into_recovery = 1; // Boot in recovery mode
378 reboot_device(0);
379 return 0;
380}
Subbaraman Narayanamurthy0e445b02011-06-19 21:34:46 -0700381
382static int emmc_set_recovery_msg(struct recovery_message *out)
383{
384 char *ptn_name = "misc";
385 unsigned long long ptn = 0;
386 unsigned int size = ROUND_TO_PAGE(sizeof(*out),511);
387 unsigned char data[size];
Kinson Chikf1a43512011-07-14 11:28:39 -0700388 int index = INVALID_PTN;
Subbaraman Narayanamurthy0e445b02011-06-19 21:34:46 -0700389
Kinson Chikf1a43512011-07-14 11:28:39 -0700390 index = partition_get_index((unsigned char *) ptn_name);
391 ptn = partition_get_offset(index);
Subbaraman Narayanamurthy0e445b02011-06-19 21:34:46 -0700392 if(ptn == 0) {
393 dprintf(CRITICAL,"partition %s doesn't exist\n",ptn_name);
394 return -1;
395 }
396 memcpy(data, out, sizeof(*out));
397 if (mmc_write(ptn , size, (unsigned int*)data)) {
398 dprintf(CRITICAL,"mmc write failure %s %d\n",ptn_name, sizeof(*out));
399 return -1;
400 }
401 return 0;
402}
403
404static int emmc_get_recovery_msg(struct recovery_message *in)
405{
406 char *ptn_name = "misc";
407 unsigned long long ptn = 0;
408 unsigned int size = ROUND_TO_PAGE(sizeof(*in),511);
409 unsigned char data[size];
Kinson Chikf1a43512011-07-14 11:28:39 -0700410 int index = INVALID_PTN;
Subbaraman Narayanamurthy0e445b02011-06-19 21:34:46 -0700411
Kinson Chikf1a43512011-07-14 11:28:39 -0700412 index = partition_get_index((unsigned char *) ptn_name);
413 ptn = partition_get_offset(index);
Subbaraman Narayanamurthy0e445b02011-06-19 21:34:46 -0700414 if(ptn == 0) {
415 dprintf(CRITICAL,"partition %s doesn't exist\n",ptn_name);
416 return -1;
417 }
418 if (mmc_read(ptn , (unsigned int*)data, size)) {
419 dprintf(CRITICAL,"mmc read failure %s %d\n",ptn_name, size);
420 return -1;
421 }
422 memcpy(in, data, sizeof(*in));
423 return 0;
424}
425
426int _emmc_recovery_init(void)
427{
428 int update_status = 0;
429 struct recovery_message msg;
430
431 // get recovery message
432 if(emmc_get_recovery_msg(&msg))
433 return -1;
434 if (msg.command[0] != 0 && msg.command[0] != 255) {
435 dprintf(INFO,"Recovery command: %d %s\n", sizeof(msg.command), msg.command);
436 }
437 msg.command[sizeof(msg.command)-1] = '\0'; //Ensure termination
438
439 if (!strcmp("update-radio",msg.command))
440 {
441 /* We're now here due to radio update, so check for update status */
Greg Griscod2471ef2011-07-14 13:00:42 -0700442 int ret = get_boot_info_apps(UPDATE_STATUS, (unsigned int *) &update_status);
Subbaraman Narayanamurthy0e445b02011-06-19 21:34:46 -0700443
444 if(!ret && (update_status & 0x01))
445 {
446 dprintf(INFO,"radio update success\n");
Ajay Dudanif63d02f2011-10-01 08:29:53 -0700447 strlcpy(msg.status, "OKAY", sizeof(msg.status));
Subbaraman Narayanamurthy0e445b02011-06-19 21:34:46 -0700448 }
449 else
450 {
451 dprintf(INFO,"radio update failed\n");
Ajay Dudanif63d02f2011-10-01 08:29:53 -0700452 strlcpy(msg.status, "failed-update", sizeof(msg.status));
Subbaraman Narayanamurthy0e445b02011-06-19 21:34:46 -0700453 }
Shashank Mittal162244e2011-08-08 19:01:25 -0700454 boot_into_recovery = 1; // Boot in recovery mode
455 }
456 if (!strcmp("reset-device-info",msg.command))
457 {
458 reset_device_info();
459 }
460 if (!strcmp("root-detect",msg.command))
461 {
462 set_device_root();
Subbaraman Narayanamurthy0e445b02011-06-19 21:34:46 -0700463 }
464 else
465 return 0; // do nothing
466
Ajay Dudanif63d02f2011-10-01 08:29:53 -0700467 strlcpy(msg.command, "", sizeof(msg.command)); // clearing recovery command
Subbaraman Narayanamurthy0e445b02011-06-19 21:34:46 -0700468 emmc_set_recovery_msg(&msg); // send recovery message
Subbaraman Narayanamurthy0e445b02011-06-19 21:34:46 -0700469 return 0;
470}
Pavel Nedeva1e62322013-04-05 15:21:36 +0300471
472static int read_misc(unsigned page_offset, void *buf, unsigned size)
473{
474 const char *ptn_name = "misc";
475 void *scratch_addr = target_get_scratch_address();
476 unsigned offset;
477 unsigned aligned_size;
478
479 if (size == 0 || buf == NULL || scratch_addr == NULL)
480 return -1;
481
482 if (target_is_emmc_boot())
483 {
484 int index;
485 unsigned long long ptn;
486 unsigned long long ptn_size;
487
488 index = partition_get_index(ptn_name);
489 if (index == INVALID_PTN)
490 {
491 dprintf(CRITICAL, "No '%s' partition found\n", ptn_name);
492 return -1;
493 }
494
495 ptn = partition_get_offset(index);
496 ptn_size = partition_get_size(index);
497
498 offset = page_offset * BLOCK_SIZE;
499 aligned_size = ROUND_TO_PAGE(size, (unsigned)BLOCK_SIZE - 1);
500 if (ptn_size < offset + aligned_size)
501 {
502 dprintf(CRITICAL, "Read request out of '%s' boundaries\n",
503 ptn_name);
504 return -1;
505 }
506
507 if (mmc_read(ptn + offset, (unsigned int *)scratch_addr, aligned_size))
508 {
509 dprintf(CRITICAL, "Reading MMC failed\n");
510 return -1;
511 }
512 }
513 else
514 {
515 struct ptentry *ptn;
516 struct ptable *ptable;
517 unsigned pagesize = flash_page_size();
518
519 ptable = flash_get_ptable();
520 if (ptable == NULL)
521 {
522 dprintf(CRITICAL, "Partition table not found\n");
523 return -1;
524 }
525
526 ptn = ptable_find(ptable, ptn_name);
527 if (ptn == NULL)
528 {
529 dprintf(CRITICAL, "No '%s' partition found\n", ptn_name);
530 return -1;
531 }
532
533 offset = page_offset * pagesize;
534 aligned_size = ROUND_TO_PAGE(size, pagesize - 1);
535 if (ptn->length < offset + aligned_size)
536 {
537 dprintf(CRITICAL, "Read request out of '%s' boundaries\n",
538 ptn_name);
539 return -1;
540 }
541
542 if (flash_read(ptn, offset, scratch_addr, aligned_size)) {
543 dprintf(CRITICAL, "Reading flash failed\n");
544 return -1;
545 }
546 }
547
548 if (scratch_addr != buf)
549 memcpy(buf, scratch_addr, size);
550
551 return 0;
552}
553
Pavel Nedevc728bb32013-04-05 16:58:05 +0300554int write_misc(unsigned page_offset, void *buf, unsigned size)
555{
556 const char *ptn_name = "misc";
557 void *scratch_addr = target_get_scratch_address();
558 unsigned offset;
559 unsigned aligned_size;
560
561 if (size == 0 || buf == NULL || scratch_addr == NULL)
562 return -1;
563
564 if (target_is_emmc_boot())
565 {
566 int index;
567 unsigned long long ptn;
568 unsigned long long ptn_size;
569
570 index = partition_get_index(ptn_name);
571 if (index == INVALID_PTN)
572 {
573 dprintf(CRITICAL, "No '%s' partition found\n", ptn_name);
574 return -1;
575 }
576
577 ptn = partition_get_offset(index);
578 ptn_size = partition_get_size(index);
579
580 offset = page_offset * BLOCK_SIZE;
581 aligned_size = ROUND_TO_PAGE(size, (unsigned)BLOCK_SIZE - 1);
582 if (ptn_size < offset + aligned_size)
583 {
584 dprintf(CRITICAL, "Write request out of '%s' boundaries\n",
585 ptn_name);
586 return -1;
587 }
588
589 if (scratch_addr != buf)
590 memcpy(scratch_addr, buf, size);
591 if (mmc_write(ptn + offset, aligned_size, (unsigned int *)scratch_addr))
592 {
593 dprintf(CRITICAL, "Writing MMC failed\n");
594 return -1;
595 }
596 }
597 else
598 {
599 struct ptentry *ptn;
600 struct ptable *ptable;
601 unsigned pagesize = flash_page_size();
602
603 ptable = flash_get_ptable();
604 if (ptable == NULL)
605 {
606 dprintf(CRITICAL, "Partition table not found\n");
607 return -1;
608 }
609
610 ptn = ptable_find(ptable, ptn_name);
611 if (ptn == NULL)
612 {
613 dprintf(CRITICAL, "No '%s' partition found\n", ptn_name);
614 return -1;
615 }
616
617 offset = page_offset * pagesize;
618 aligned_size = ROUND_TO_PAGE(size, pagesize - 1);
619 if (ptn->length < offset + aligned_size)
620 {
621 dprintf(CRITICAL, "Write request out of '%s' boundaries\n",
622 ptn_name);
623 return -1;
624 }
625
626 if (scratch_addr != buf)
627 memcpy(scratch_addr, buf, size);
628 if (flash_write(ptn, offset, scratch_addr, aligned_size)) {
629 dprintf(CRITICAL, "Writing flash failed\n");
630 return -1;
631 }
632 }
633
634 return 0;
635}
636
Pavel Nedeva1e62322013-04-05 15:21:36 +0300637bool get_ffbm(char *ffbm, unsigned size)
638{
639 const char *ffbm_cmd = "ffbm-";
640 const unsigned ffbm_submode_size = 2;
641 unsigned ffbm_mode_size = strlen(ffbm_cmd) + ffbm_submode_size;
642
643 if (size < ffbm_mode_size + 1)
644 {
645 dprintf(CRITICAL, "Buffer too short to get FFBM string\n");
646 return false;
647 }
648
649 if (read_misc(0, ffbm, ffbm_mode_size))
650 {
651 dprintf(CRITICAL, "Error reading MISC partition\n");
652 return false;
653 }
654 ffbm[ffbm_mode_size] = 0;
655
656 if (!strncmp(ffbm, ffbm_cmd, strlen(ffbm_cmd)))
657 return true;
658
659 return false;
660}