blob: 9312095786841274e9f62311393f97fea617a191 [file] [log] [blame]
Stanimir Varbanovbe041992013-04-26 14:29:21 +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
Deepa Dinamani41fa8d62013-05-23 13:25:36 -070058extern uint32_t get_page_size();
Shashank Mittal162244e2011-08-08 19:01:25 -070059extern void reset_device_info();
60extern void set_device_root();
Shashank Mittal024c0332010-02-03 11:44:00 -080061
62int get_recovery_message(struct recovery_message *out)
63{
64 struct ptentry *ptn;
65 struct ptable *ptable;
66 unsigned offset = 0;
67 unsigned pagesize = flash_page_size();
68
69 ptable = flash_get_ptable();
70
71 if (ptable == NULL) {
72 dprintf(CRITICAL, "ERROR: Partition table not found\n");
73 return -1;
74 }
75 ptn = ptable_find(ptable, "misc");
76
77 if (ptn == NULL) {
78 dprintf(CRITICAL, "ERROR: No misc partition found\n");
79 return -1;
80 }
81
82 offset += (pagesize * MISC_COMMAND_PAGE);
Greg Griscod6250552011-06-29 14:40:23 -070083 if (flash_read(ptn, offset, (void *) buf, pagesize)) {
Shashank Mittal024c0332010-02-03 11:44:00 -080084 dprintf(CRITICAL, "ERROR: Cannot read recovery_header\n");
85 return -1;
86 }
87 memcpy(out, buf, sizeof(*out));
88 return 0;
89}
90
91int set_recovery_message(const struct recovery_message *in)
92{
93 struct ptentry *ptn;
94 struct ptable *ptable;
95 unsigned offset = 0;
96 unsigned pagesize = flash_page_size();
97 unsigned n = 0;
Pavel Nedev5d4a7052013-05-13 15:14:45 +030098 void *scratch_addr = target_get_scratch_address();
Shashank Mittal024c0332010-02-03 11:44:00 -080099
100 ptable = flash_get_ptable();
101
102 if (ptable == NULL) {
103 dprintf(CRITICAL, "ERROR: Partition table not found\n");
104 return -1;
105 }
106 ptn = ptable_find(ptable, "misc");
107
108 if (ptn == NULL) {
109 dprintf(CRITICAL, "ERROR: No misc partition found\n");
110 return -1;
111 }
112
113 n = pagesize * (MISC_COMMAND_PAGE + 1);
114
Pavel Nedev5d4a7052013-05-13 15:14:45 +0300115 if (flash_read(ptn, offset, scratch_addr, n)) {
Shashank Mittal024c0332010-02-03 11:44:00 -0800116 dprintf(CRITICAL, "ERROR: Cannot read recovery_header\n");
117 return -1;
118 }
119
120 offset += (pagesize * MISC_COMMAND_PAGE);
Pavel Nedev5d4a7052013-05-13 15:14:45 +0300121 offset += (unsigned) scratch_addr;
Greg Griscod6250552011-06-29 14:40:23 -0700122 memcpy((void *) offset, in, sizeof(*in));
Pavel Nedev5d4a7052013-05-13 15:14:45 +0300123 if (flash_write(ptn, 0, scratch_addr, n)) {
Shashank Mittal024c0332010-02-03 11:44:00 -0800124 dprintf(CRITICAL, "ERROR: flash write fail!\n");
125 return -1;
126 }
Greg Griscod6250552011-06-29 14:40:23 -0700127 return 0;
Shashank Mittal024c0332010-02-03 11:44:00 -0800128}
129
130int read_update_header_for_bootloader(struct update_header *header)
131{
132 struct ptentry *ptn;
133 struct ptable *ptable;
134 unsigned offset = 0;
135 unsigned pagesize = flash_page_size();
136
137 ptable = flash_get_ptable();
138 if (ptable == NULL) {
139 dprintf(CRITICAL, "ERROR: Partition table not found\n");
140 return -1;
141 }
142 ptn = ptable_find(ptable, "cache");
143
144 if (ptn == NULL) {
145 dprintf(CRITICAL, "ERROR: No cache partition found\n");
146 return -1;
147 }
148 if (flash_read(ptn, offset, buf, pagesize)) {
149 dprintf(CRITICAL, "ERROR: Cannot read recovery_header\n");
150 return -1;
151 }
152 memcpy(header, buf, sizeof(*header));
153
Greg Griscod6250552011-06-29 14:40:23 -0700154 if (strncmp((char *) header->MAGIC, UPDATE_MAGIC, UPDATE_MAGIC_SIZE))
Shashank Mittal024c0332010-02-03 11:44:00 -0800155 {
156 return -1;
157 }
158 return 0;
159}
160
161int update_firmware_image (struct update_header *header, char *name)
162{
163 struct ptentry *ptn;
164 struct ptable *ptable;
165 unsigned offset = 0;
166 unsigned pagesize = flash_page_size();
167 unsigned pagemask = pagesize -1;
168 unsigned n = 0;
Pavel Nedev5d4a7052013-05-13 15:14:45 +0300169 void *scratch_addr = target_get_scratch_address();
Shashank Mittal024c0332010-02-03 11:44:00 -0800170
171 ptable = flash_get_ptable();
172 if (ptable == NULL) {
173 dprintf(CRITICAL, "ERROR: Partition table not found\n");
174 return -1;
175 }
176
177 ptn = ptable_find(ptable, "cache");
178 if (ptn == NULL) {
179 dprintf(CRITICAL, "ERROR: No cache partition found\n");
180 return -1;
181 }
182
183 offset += header->image_offset;
184 n = (header->image_length + pagemask) & (~pagemask);
185
Pavel Nedev5d4a7052013-05-13 15:14:45 +0300186 if (flash_read(ptn, offset, scratch_addr, n)) {
Shashank Mittal024c0332010-02-03 11:44:00 -0800187 dprintf(CRITICAL, "ERROR: Cannot read radio image\n");
188 return -1;
189 }
190
191 ptn = ptable_find(ptable, name);
192 if (ptn == NULL) {
193 dprintf(CRITICAL, "ERROR: No %s partition found\n", name);
194 return -1;
195 }
196
Pavel Nedev5d4a7052013-05-13 15:14:45 +0300197 if (flash_write(ptn, 0, scratch_addr, n)) {
Shashank Mittal024c0332010-02-03 11:44:00 -0800198 dprintf(CRITICAL, "ERROR: flash write fail!\n");
199 return -1;
200 }
201
202 dprintf(INFO, "Partition writen successfully!");
203 return 0;
204}
205
Subbaraman Narayanamurthy0e445b02011-06-19 21:34:46 -0700206static int set_ssd_radio_update (char *name)
207{
208 struct ptentry *ptn;
209 struct ptable *ptable;
210 unsigned int ssd_cookie[2] = {0x53534443, 0x4F4F4B49};
211 unsigned pagesize = flash_page_size();
212 unsigned pagemask = pagesize -1;
213 unsigned n = 0;
214
215 ptable = flash_get_ptable();
216 if (ptable == NULL) {
217 dprintf(CRITICAL, "ERROR: Partition table not found\n");
218 return -1;
219 }
220
221 n = (sizeof(ssd_cookie) + pagemask) & (~pagemask);
222
223 ptn = ptable_find(ptable, name);
224 if (ptn == NULL) {
225 dprintf(CRITICAL, "ERROR: No %s partition found\n", name);
226 return -1;
227 }
228
229 if (flash_write(ptn, 0, ssd_cookie, n)) {
230 dprintf(CRITICAL, "ERROR: flash write fail!\n");
231 return -1;
232 }
233
234 dprintf(INFO, "FOTA partition written successfully!");
235 return 0;
236}
237
238int get_boot_info_apps (char type, unsigned int *status)
239{
240 boot_info_for_apps apps_boot_info;
241 int ret = 0;
242
243 ret = smem_read_alloc_entry(SMEM_BOOT_INFO_FOR_APPS,
244 &apps_boot_info, sizeof(apps_boot_info));
245 if (ret)
246 {
247 dprintf(CRITICAL, "ERROR: unable to read shared memory for apps boot info %d\n",ret);
248 return ret;
249 }
250
251 dprintf(INFO,"boot flag %x update status %x\n",apps_boot_info.boot_flags,
252 apps_boot_info.status.update_status);
253
254 if(type == BOOT_FLAGS)
255 *status = apps_boot_info.boot_flags;
256 else if(type == UPDATE_STATUS)
257 *status = apps_boot_info.status.update_status;
258
259 return ret;
260}
261
Shashank Mittal024c0332010-02-03 11:44:00 -0800262/* Bootloader / Recovery Flow
263 *
264 * On every boot, the bootloader will read the recovery_message
265 * from flash and check the command field. The bootloader should
266 * deal with the command field not having a 0 terminator correctly
267 * (so as to not crash if the block is invalid or corrupt).
268 *
269 * The bootloader will have to publish the partition that contains
270 * the recovery_message to the linux kernel so it can update it.
271 *
272 * if command == "boot-recovery" -> boot recovery.img
273 * else if command == "update-radio" -> update radio image (below)
274 * else -> boot boot.img (normal boot)
275 *
276 * Radio Update Flow
277 * 1. the bootloader will attempt to load and validate the header
278 * 2. if the header is invalid, status="invalid-update", goto #8
279 * 3. display the busy image on-screen
280 * 4. if the update image is invalid, status="invalid-radio-image", goto #8
281 * 5. attempt to update the firmware (depending on the command)
282 * 6. if successful, status="okay", goto #8
283 * 7. if failed, and the old image can still boot, status="failed-update"
284 * 8. write the recovery_message, leaving the recovery field
285 * unchanged, updating status, and setting command to
286 * "boot-recovery"
287 * 9. reboot
288 *
289 * The bootloader will not modify or erase the cache partition.
290 * It is recovery's responsibility to clean up the mess afterwards.
291 */
292
293int recovery_init (void)
294{
295 struct recovery_message msg;
Shashank Mittal024c0332010-02-03 11:44:00 -0800296 char partition_name[32];
297 unsigned valid_command = 0;
Subbaraman Narayanamurthy0e445b02011-06-19 21:34:46 -0700298 int update_status = 0;
Shashank Mittal024c0332010-02-03 11:44:00 -0800299
300 // get recovery message
Greg Griscod6250552011-06-29 14:40:23 -0700301 if (get_recovery_message(&msg))
Shashank Mittal024c0332010-02-03 11:44:00 -0800302 return -1;
Shashank Mittal024c0332010-02-03 11:44:00 -0800303 msg.command[sizeof(msg.command)-1] = '\0'; //Ensure termination
Pavel Nedev96a9aea2013-02-26 15:16:26 -0800304 if (msg.command[0] != 0 && msg.command[0] != 255) {
305 dprintf(INFO,"Recovery command: %d %s\n",
306 sizeof(msg.command), msg.command);
307 }
Shashank Mittal024c0332010-02-03 11:44:00 -0800308
Subbaraman Narayanamurthy0e445b02011-06-19 21:34:46 -0700309 if (!strcmp("boot-recovery",msg.command))
310 {
311 if(!strcmp("RADIO",msg.status))
312 {
313 /* We're now here due to radio update, so check for update status */
Greg Griscod2471ef2011-07-14 13:00:42 -0700314 int ret = get_boot_info_apps(UPDATE_STATUS, (unsigned int *) &update_status);
Subbaraman Narayanamurthy0e445b02011-06-19 21:34:46 -0700315
316 if(!ret && (update_status & 0x01))
317 {
318 dprintf(INFO,"radio update success\n");
Ajay Dudanif63d02f2011-10-01 08:29:53 -0700319 strlcpy(msg.status, "OKAY", sizeof(msg.status));
Subbaraman Narayanamurthy0e445b02011-06-19 21:34:46 -0700320 }
321 else
322 {
323 dprintf(INFO,"radio update failed\n");
Ajay Dudanif63d02f2011-10-01 08:29:53 -0700324 strlcpy(msg.status, "failed-update", sizeof(msg.status));
Subbaraman Narayanamurthy0e445b02011-06-19 21:34:46 -0700325 }
Ajay Dudanif63d02f2011-10-01 08:29:53 -0700326 strlcpy(msg.command, "", sizeof(msg.command)); // clearing recovery command
Subbaraman Narayanamurthy0e445b02011-06-19 21:34:46 -0700327 set_recovery_message(&msg); // send recovery message
328 boot_into_recovery = 1; // Boot in recovery mode
329 return 0;
330 }
331
Shashank Mittal024c0332010-02-03 11:44:00 -0800332 valid_command = 1;
Ajay Dudanif63d02f2011-10-01 08:29:53 -0700333 strlcpy(msg.command, "", sizeof(msg.command)); // to safe against multiple reboot into recovery
334 strlcpy(msg.status, "OKAY", sizeof(msg.status));
Shashank Mittal024c0332010-02-03 11:44:00 -0800335 set_recovery_message(&msg); // send recovery message
336 boot_into_recovery = 1; // Boot in recovery mode
337 return 0;
338 }
339
340 if (!strcmp("update-radio",msg.command)) {
Subbaraman Narayanamurthy0e445b02011-06-19 21:34:46 -0700341 dprintf(INFO,"start radio update\n");
Shashank Mittal024c0332010-02-03 11:44:00 -0800342 valid_command = 1;
Ajay Dudanif63d02f2011-10-01 08:29:53 -0700343 strlcpy(partition_name, "FOTA", sizeof(partition_name));
Shashank Mittal024c0332010-02-03 11:44:00 -0800344 }
345
346 //Todo: Add support for bootloader update too.
347
348 if(!valid_command) {
349 //We need not to do anything
350 return 0; // Boot in normal mode
351 }
352
Subbaraman Narayanamurthy0e445b02011-06-19 21:34:46 -0700353#ifdef OLD_FOTA_UPGRADE
Shashank Mittal024c0332010-02-03 11:44:00 -0800354 if (read_update_header_for_bootloader(&header)) {
Ajay Dudanif63d02f2011-10-01 08:29:53 -0700355 strlcpy(msg.status, "invalid-update", sizeof(msg.status));
Shashank Mittal024c0332010-02-03 11:44:00 -0800356 goto SEND_RECOVERY_MSG;
357 }
358
359 if (update_firmware_image (&header, partition_name)) {
Ajay Dudanif63d02f2011-10-01 08:29:53 -0700360 strlcpy(msg.status, "failed-update", sizeof(msg.status));
Shashank Mittal024c0332010-02-03 11:44:00 -0800361 goto SEND_RECOVERY_MSG;
362 }
Subbaraman Narayanamurthy0e445b02011-06-19 21:34:46 -0700363#else
364 if (set_ssd_radio_update(partition_name)) {
365 /* If writing to FOTA partition fails */
Ajay Dudanif63d02f2011-10-01 08:29:53 -0700366 strlcpy(msg.command, "", sizeof(msg.command));
367 strlcpy(msg.status, "failed-update", sizeof(msg.status));
Subbaraman Narayanamurthy0e445b02011-06-19 21:34:46 -0700368 goto SEND_RECOVERY_MSG;
369 }
370 else {
371 /* Setting this to check the radio update status */
Ajay Dudanif63d02f2011-10-01 08:29:53 -0700372 strlcpy(msg.command, "boot-recovery", sizeof(msg.command));
Ajay Dudanif4caa942011-10-02 08:57:15 -0700373 strlcpy(msg.status, "RADIO", sizeof(msg.status));
Subbaraman Narayanamurthy0e445b02011-06-19 21:34:46 -0700374 goto SEND_RECOVERY_MSG;
375 }
376#endif
Ajay Dudanif63d02f2011-10-01 08:29:53 -0700377 strlcpy(msg.status, "OKAY", sizeof(msg.status));
Shashank Mittal024c0332010-02-03 11:44:00 -0800378
379SEND_RECOVERY_MSG:
Shashank Mittal024c0332010-02-03 11:44:00 -0800380 set_recovery_message(&msg); // send recovery message
381 boot_into_recovery = 1; // Boot in recovery mode
382 reboot_device(0);
383 return 0;
384}
Subbaraman Narayanamurthy0e445b02011-06-19 21:34:46 -0700385
386static int emmc_set_recovery_msg(struct recovery_message *out)
387{
388 char *ptn_name = "misc";
389 unsigned long long ptn = 0;
390 unsigned int size = ROUND_TO_PAGE(sizeof(*out),511);
391 unsigned char data[size];
Kinson Chikf1a43512011-07-14 11:28:39 -0700392 int index = INVALID_PTN;
Subbaraman Narayanamurthy0e445b02011-06-19 21:34:46 -0700393
Kinson Chikf1a43512011-07-14 11:28:39 -0700394 index = partition_get_index((unsigned char *) ptn_name);
395 ptn = partition_get_offset(index);
Subbaraman Narayanamurthy0e445b02011-06-19 21:34:46 -0700396 if(ptn == 0) {
397 dprintf(CRITICAL,"partition %s doesn't exist\n",ptn_name);
398 return -1;
399 }
400 memcpy(data, out, sizeof(*out));
401 if (mmc_write(ptn , size, (unsigned int*)data)) {
402 dprintf(CRITICAL,"mmc write failure %s %d\n",ptn_name, sizeof(*out));
403 return -1;
404 }
405 return 0;
406}
407
408static int emmc_get_recovery_msg(struct recovery_message *in)
409{
410 char *ptn_name = "misc";
411 unsigned long long ptn = 0;
412 unsigned int size = ROUND_TO_PAGE(sizeof(*in),511);
413 unsigned char data[size];
Kinson Chikf1a43512011-07-14 11:28:39 -0700414 int index = INVALID_PTN;
Subbaraman Narayanamurthy0e445b02011-06-19 21:34:46 -0700415
Kinson Chikf1a43512011-07-14 11:28:39 -0700416 index = partition_get_index((unsigned char *) ptn_name);
417 ptn = partition_get_offset(index);
Subbaraman Narayanamurthy0e445b02011-06-19 21:34:46 -0700418 if(ptn == 0) {
419 dprintf(CRITICAL,"partition %s doesn't exist\n",ptn_name);
420 return -1;
421 }
422 if (mmc_read(ptn , (unsigned int*)data, size)) {
423 dprintf(CRITICAL,"mmc read failure %s %d\n",ptn_name, size);
424 return -1;
425 }
426 memcpy(in, data, sizeof(*in));
427 return 0;
428}
429
430int _emmc_recovery_init(void)
431{
432 int update_status = 0;
433 struct recovery_message msg;
434
435 // get recovery message
436 if(emmc_get_recovery_msg(&msg))
437 return -1;
Subbaraman Narayanamurthy0e445b02011-06-19 21:34:46 -0700438 msg.command[sizeof(msg.command)-1] = '\0'; //Ensure termination
Pavel Nedev96a9aea2013-02-26 15:16:26 -0800439 if (msg.command[0] != 0 && msg.command[0] != 255) {
440 dprintf(INFO,"Recovery command: %d %s\n",
441 sizeof(msg.command), msg.command);
442 }
Subbaraman Narayanamurthy0e445b02011-06-19 21:34:46 -0700443
Stanimir Varbanovbe041992013-04-26 14:29:21 +0300444 if (!strncmp(msg.command, "boot-recovery", strlen("boot-recovery"))) {
445 boot_into_recovery = 1;
446 }
447
Subbaraman Narayanamurthy0e445b02011-06-19 21:34:46 -0700448 if (!strcmp("update-radio",msg.command))
449 {
450 /* We're now here due to radio update, so check for update status */
Greg Griscod2471ef2011-07-14 13:00:42 -0700451 int ret = get_boot_info_apps(UPDATE_STATUS, (unsigned int *) &update_status);
Subbaraman Narayanamurthy0e445b02011-06-19 21:34:46 -0700452
453 if(!ret && (update_status & 0x01))
454 {
455 dprintf(INFO,"radio update success\n");
Ajay Dudanif63d02f2011-10-01 08:29:53 -0700456 strlcpy(msg.status, "OKAY", sizeof(msg.status));
Subbaraman Narayanamurthy0e445b02011-06-19 21:34:46 -0700457 }
458 else
459 {
460 dprintf(INFO,"radio update failed\n");
Ajay Dudanif63d02f2011-10-01 08:29:53 -0700461 strlcpy(msg.status, "failed-update", sizeof(msg.status));
Subbaraman Narayanamurthy0e445b02011-06-19 21:34:46 -0700462 }
Shashank Mittal162244e2011-08-08 19:01:25 -0700463 boot_into_recovery = 1; // Boot in recovery mode
464 }
465 if (!strcmp("reset-device-info",msg.command))
466 {
467 reset_device_info();
468 }
469 if (!strcmp("root-detect",msg.command))
470 {
471 set_device_root();
Subbaraman Narayanamurthy0e445b02011-06-19 21:34:46 -0700472 }
473 else
474 return 0; // do nothing
475
Ajay Dudanif63d02f2011-10-01 08:29:53 -0700476 strlcpy(msg.command, "", sizeof(msg.command)); // clearing recovery command
Subbaraman Narayanamurthy0e445b02011-06-19 21:34:46 -0700477 emmc_set_recovery_msg(&msg); // send recovery message
Subbaraman Narayanamurthy0e445b02011-06-19 21:34:46 -0700478 return 0;
479}
Pavel Nedeva1e62322013-04-05 15:21:36 +0300480
481static int read_misc(unsigned page_offset, void *buf, unsigned size)
482{
483 const char *ptn_name = "misc";
Deepa Dinamani41fa8d62013-05-23 13:25:36 -0700484 uint32_t pagesize = get_page_size();
Pavel Nedeva1e62322013-04-05 15:21:36 +0300485 unsigned offset;
Pavel Nedeva1e62322013-04-05 15:21:36 +0300486
Deepa Dinamani41fa8d62013-05-23 13:25:36 -0700487 if (size == 0 || buf == NULL)
Pavel Nedeva1e62322013-04-05 15:21:36 +0300488 return -1;
489
Deepa Dinamani41fa8d62013-05-23 13:25:36 -0700490 offset = page_offset * pagesize;
491
Pavel Nedeva1e62322013-04-05 15:21:36 +0300492 if (target_is_emmc_boot())
493 {
494 int index;
495 unsigned long long ptn;
496 unsigned long long ptn_size;
497
498 index = partition_get_index(ptn_name);
499 if (index == INVALID_PTN)
500 {
501 dprintf(CRITICAL, "No '%s' partition found\n", ptn_name);
502 return -1;
503 }
504
505 ptn = partition_get_offset(index);
506 ptn_size = partition_get_size(index);
507
Deepa Dinamani41fa8d62013-05-23 13:25:36 -0700508 if (ptn_size < offset + size)
Pavel Nedeva1e62322013-04-05 15:21:36 +0300509 {
510 dprintf(CRITICAL, "Read request out of '%s' boundaries\n",
511 ptn_name);
512 return -1;
513 }
514
Deepa Dinamani41fa8d62013-05-23 13:25:36 -0700515 if (mmc_read(ptn + offset, (unsigned int *)buf, size))
Pavel Nedeva1e62322013-04-05 15:21:36 +0300516 {
517 dprintf(CRITICAL, "Reading MMC failed\n");
518 return -1;
519 }
520 }
521 else
522 {
Deepa Dinamani41fa8d62013-05-23 13:25:36 -0700523 dprintf(CRITICAL, "Misc partition not supported for NAND targets.\n");
524 return -1;
Pavel Nedeva1e62322013-04-05 15:21:36 +0300525 }
526
Pavel Nedeva1e62322013-04-05 15:21:36 +0300527 return 0;
528}
529
Pavel Nedevc728bb32013-04-05 16:58:05 +0300530int write_misc(unsigned page_offset, void *buf, unsigned size)
531{
532 const char *ptn_name = "misc";
533 void *scratch_addr = target_get_scratch_address();
534 unsigned offset;
535 unsigned aligned_size;
536
537 if (size == 0 || buf == NULL || scratch_addr == NULL)
538 return -1;
539
540 if (target_is_emmc_boot())
541 {
542 int index;
543 unsigned long long ptn;
544 unsigned long long ptn_size;
545
546 index = partition_get_index(ptn_name);
547 if (index == INVALID_PTN)
548 {
549 dprintf(CRITICAL, "No '%s' partition found\n", ptn_name);
550 return -1;
551 }
552
553 ptn = partition_get_offset(index);
554 ptn_size = partition_get_size(index);
555
556 offset = page_offset * BLOCK_SIZE;
557 aligned_size = ROUND_TO_PAGE(size, (unsigned)BLOCK_SIZE - 1);
558 if (ptn_size < offset + aligned_size)
559 {
560 dprintf(CRITICAL, "Write request out of '%s' boundaries\n",
561 ptn_name);
562 return -1;
563 }
564
Mayank Grover5eaafbd2017-10-24 12:27:53 +0530565 /* This will ensure, we zeored out any extra bytes
566 we will push to emmc, to prevent information leak */
567 if (aligned_size > size)
568 memset((scratch_addr + size), 0, (aligned_size-size));
569
Pavel Nedevc728bb32013-04-05 16:58:05 +0300570 if (scratch_addr != buf)
571 memcpy(scratch_addr, buf, size);
572 if (mmc_write(ptn + offset, aligned_size, (unsigned int *)scratch_addr))
573 {
574 dprintf(CRITICAL, "Writing MMC failed\n");
575 return -1;
576 }
577 }
578 else
579 {
580 struct ptentry *ptn;
581 struct ptable *ptable;
582 unsigned pagesize = flash_page_size();
583
584 ptable = flash_get_ptable();
585 if (ptable == NULL)
586 {
587 dprintf(CRITICAL, "Partition table not found\n");
588 return -1;
589 }
590
591 ptn = ptable_find(ptable, ptn_name);
592 if (ptn == NULL)
593 {
594 dprintf(CRITICAL, "No '%s' partition found\n", ptn_name);
595 return -1;
596 }
597
598 offset = page_offset * pagesize;
599 aligned_size = ROUND_TO_PAGE(size, pagesize - 1);
600 if (ptn->length < offset + aligned_size)
601 {
602 dprintf(CRITICAL, "Write request out of '%s' boundaries\n",
603 ptn_name);
604 return -1;
605 }
606
Mayank Grover5eaafbd2017-10-24 12:27:53 +0530607 /* This will ensure, we zeored out any extra bytes
608 we will push, to prevent information leak */
609 if (aligned_size > size)
610 memset((scratch_addr + size), 0, (aligned_size-size));
611
Pavel Nedevc728bb32013-04-05 16:58:05 +0300612 if (scratch_addr != buf)
613 memcpy(scratch_addr, buf, size);
Mayank Grover5eaafbd2017-10-24 12:27:53 +0530614
Pavel Nedevc728bb32013-04-05 16:58:05 +0300615 if (flash_write(ptn, offset, scratch_addr, aligned_size)) {
616 dprintf(CRITICAL, "Writing flash failed\n");
617 return -1;
618 }
619 }
620
621 return 0;
622}
623
Deepa Dinamani41fa8d62013-05-23 13:25:36 -0700624int get_ffbm(char *ffbm, unsigned size)
Pavel Nedeva1e62322013-04-05 15:21:36 +0300625{
626 const char *ffbm_cmd = "ffbm-";
Deepa Dinamani41fa8d62013-05-23 13:25:36 -0700627 uint32_t page_size = get_page_size();
628 char *ffbm_page_buffer = NULL;
629 int retval = 0;
630 if (size < FFBM_MODE_BUF_SIZE || size >= page_size)
Pavel Nedeva1e62322013-04-05 15:21:36 +0300631 {
Deepa Dinamani41fa8d62013-05-23 13:25:36 -0700632 dprintf(CRITICAL, "Invalid size argument passed to get_ffbm\n");
633 retval = -1;
634 goto cleanup;
Pavel Nedeva1e62322013-04-05 15:21:36 +0300635 }
Deepa Dinamani41fa8d62013-05-23 13:25:36 -0700636 ffbm_page_buffer = (char*)malloc(page_size);
637 if (!ffbm_page_buffer)
638 {
639 dprintf(CRITICAL, "Failed to alloc buffer for ffbm cookie\n");
640 retval = -1;
641 goto cleanup;
642 }
643 if (read_misc(0, ffbm_page_buffer, page_size))
Pavel Nedeva1e62322013-04-05 15:21:36 +0300644 {
645 dprintf(CRITICAL, "Error reading MISC partition\n");
Deepa Dinamani41fa8d62013-05-23 13:25:36 -0700646 retval = -1;
647 goto cleanup;
Pavel Nedeva1e62322013-04-05 15:21:36 +0300648 }
Deepa Dinamani41fa8d62013-05-23 13:25:36 -0700649 ffbm_page_buffer[size] = '\0';
650 if (strncmp(ffbm_cmd, ffbm_page_buffer, strlen(ffbm_cmd)))
651 {
652 retval = 0;
653 goto cleanup;
654 }
655 else
656 {
657 if (strlcpy(ffbm, ffbm_page_buffer, size) <
658 FFBM_MODE_BUF_SIZE -1)
659 {
660 dprintf(CRITICAL, "Invalid string in misc partition\n");
661 retval = -1;
662 }
663 else
664 retval = 1;
665 }
666cleanup:
667 if(ffbm_page_buffer)
668 free(ffbm_page_buffer);
669 return retval;
Pavel Nedeva1e62322013-04-05 15:21:36 +0300670}
Deepa Dinamani41fa8d62013-05-23 13:25:36 -0700671
672