1 /*
2  * Copyright (c) 2014-2015, Linaro Ltd and Contributors. All rights reserved.
3  * Copyright (c) 2014-2015, Hisilicon Ltd and Contributors. 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 are met:
7  *
8  * Redistributions of source code must retain the above copyright notice, this
9  * list of conditions and the following disclaimer.
10  *
11  * Redistributions in binary form must reproduce the above copyright notice,
12  * this list of conditions and the following disclaimer in the documentation
13  * and/or other materials provided with the distribution.
14  *
15  * Neither the name of ARM nor the names of its contributors may be used
16  * to endorse or promote products derived from this software without specific
17  * prior written 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 AND FITNESS FOR A PARTICULAR PURPOSE
22  * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
23  * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
24  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
25  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
26  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
27  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
28  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
29  * POSSIBILITY OF SUCH DAMAGE.
30  */
31 
32 #include <arch_helpers.h>
33 #include <assert.h>
34 #include <debug.h>
35 #include <dw_mmc.h>
36 #include <fastboot.h>
37 #include <io_block.h>
38 #include <io_driver.h>
39 #include <io_fip.h>
40 #include <io_memmap.h>
41 #include <io_storage.h>
42 #include <mmio.h>
43 #include <partitions.h>
44 #include <platform_def.h>
45 #include <semihosting.h>	/* For FOPEN_MODE_... */
46 #include <string.h>
47 #include "hikey_private.h"
48 
49 #define LOADER_MAX_ENTRIES		2
50 #define PTABLE_MAX_ENTRIES		3
51 #define USER_MAX_ENTRIES		2
52 
53 #define FLUSH_BASE			(DDR_BASE + 0x100000)
54 
55 struct entry_head {
56 	unsigned char	magic[8];
57 	unsigned char	name[8];
58 	unsigned int	start;	/* lba */
59 	unsigned int	count;	/* lba */
60 	unsigned int	flag;
61 };
62 
63 static const io_dev_connector_t *bl1_mem_dev_con;
64 static uintptr_t bl1_mem_dev_spec;
65 static uintptr_t loader_mem_dev_handle;
66 static uintptr_t bl1_mem_init_params;
67 static const io_dev_connector_t *fip_dev_con;
68 static uintptr_t fip_dev_spec;
69 static uintptr_t fip_dev_handle;
70 static const io_dev_connector_t *dw_mmc_dev_con;
71 static struct block_ops dw_mmc_ops;
72 static uintptr_t emmc_dev_handle;
73 
74 #define SPARSE_FILL_BUFFER_ADDRESS	0x18000000
75 #define SPARSE_FILL_BUFFER_SIZE		0x08000000
76 
77 /* Page 1024, since only a few pages before 2048 are used as partition table */
78 #define SERIALNO_OFFSET			(1024 * 512)
79 
80 static const io_block_spec_t loader_mem_spec = {
81 	/* l-loader.bin that contains bl1.bin */
82 	.offset = LOADER_RAM_BASE,
83 	.length = BL1_RO_LIMIT - LOADER_RAM_BASE,
84 };
85 
86 static const io_block_spec_t boot_emmc_spec = {
87 	.offset = MMC_LOADER_BASE,
88 	.length = BL1_RO_LIMIT - LOADER_RAM_BASE,
89 };
90 
91 static const io_block_spec_t normal_emmc_spec = {
92 	.offset = MMC_BASE,
93 	.length = MMC_SIZE,
94 };
95 
96 static io_block_spec_t fip_block_spec = {
97 	.offset = 0,
98 	.length = 0,
99 };
100 
101 static const io_file_spec_t bl2_file_spec = {
102 	.path = BL2_IMAGE_NAME,
103 	.mode = FOPEN_MODE_RB
104 };
105 
106 static const io_file_spec_t bl30_file_spec = {
107 	.path = BL30_IMAGE_NAME,
108 	.mode = FOPEN_MODE_RB
109 };
110 
111 static const io_file_spec_t bl31_file_spec = {
112 	.path = BL31_IMAGE_NAME,
113 	.mode = FOPEN_MODE_RB
114 };
115 
116 static const io_file_spec_t bl32_file_spec = {
117 	.path = BL32_IMAGE_NAME,
118 	.mode = FOPEN_MODE_RB
119 };
120 
121 static const io_file_spec_t bl33_file_spec = {
122 	.path = BL33_IMAGE_NAME,
123 	.mode = FOPEN_MODE_RB
124 };
125 
126 static int open_loader_mem(const uintptr_t spec);
127 static int open_fip(const uintptr_t spec);
128 static int open_dw_mmc(const uintptr_t spec);
129 static int open_dw_mmc_boot(const uintptr_t spec);
130 
131 struct plat_io_policy {
132 	const char	*image_name;
133 	uintptr_t	*dev_handle;
134 	uintptr_t	image_spec;
135 	int		(*check)(const uintptr_t spec);
136 };
137 
138 static const struct plat_io_policy policies[] = {
139 	{
140 		LOADER_MEM_NAME,
141 		&loader_mem_dev_handle,
142 		(uintptr_t)&loader_mem_spec,
143 		open_loader_mem
144 	}, {
145 		BOOT_EMMC_NAME,
146 		&emmc_dev_handle,
147 		(uintptr_t)&boot_emmc_spec,
148 		open_dw_mmc_boot
149 	}, {
150 		NORMAL_EMMC_NAME,
151 		&emmc_dev_handle,
152 		(uintptr_t)&normal_emmc_spec,
153 		open_dw_mmc
154 	}, {
155 		FIP_IMAGE_NAME,
156 		&emmc_dev_handle,
157 		(uintptr_t)&fip_block_spec,
158 		open_dw_mmc
159 	}, {
160 		BL2_IMAGE_NAME,
161 		&fip_dev_handle,
162 		(uintptr_t)&bl2_file_spec,
163 		open_fip
164 	}, {
165 		BL30_IMAGE_NAME,
166 		&fip_dev_handle,
167 		(uintptr_t)&bl30_file_spec,
168 		open_fip
169 	}, {
170 		BL31_IMAGE_NAME,
171 		&fip_dev_handle,
172 		(uintptr_t)&bl31_file_spec,
173 		open_fip
174 	}, {
175 		BL32_IMAGE_NAME,
176 		&fip_dev_handle,
177 		(uintptr_t)&bl32_file_spec,
178 		open_fip
179 	}, {
180 		BL33_IMAGE_NAME,
181 		&fip_dev_handle,
182 		(uintptr_t)&bl33_file_spec,
183 		open_fip
184 	}, {
185 		0, 0, 0, 0
186 	}
187 };
188 
open_loader_mem(const uintptr_t spec)189 static int open_loader_mem(const uintptr_t spec)
190 {
191 	int result = IO_FAIL;
192 	uintptr_t image_handle;
193 
194 	result = io_dev_init(loader_mem_dev_handle, bl1_mem_init_params);
195 	if (result == IO_SUCCESS) {
196 		result = io_open(loader_mem_dev_handle, spec, &image_handle);
197 		if (result == IO_SUCCESS) {
198 			io_close(image_handle);
199 		}
200 	}
201 	return result;
202 }
203 
open_fip(const uintptr_t spec)204 static int open_fip(const uintptr_t spec)
205 {
206 	int result = IO_FAIL;
207 
208 	/* See if a Firmware Image Package is available */
209 	result = io_dev_init(fip_dev_handle, (uintptr_t)FIP_IMAGE_NAME);
210 	if (result == IO_SUCCESS) {
211 		INFO("Using FIP\n");
212 		/*TODO: Check image defined in spec is present in FIP. */
213 	}
214 	return result;
215 }
216 
217 
open_dw_mmc(const uintptr_t spec)218 static int open_dw_mmc(const uintptr_t spec)
219 {
220 	int result = IO_FAIL;
221 	uintptr_t image_handle;
222 
223 	/* indicate to select normal partition in eMMC */
224 	result = io_dev_init(emmc_dev_handle, 0);
225 	if (result == IO_SUCCESS) {
226 		result = io_open(emmc_dev_handle, spec, &image_handle);
227 		if (result == IO_SUCCESS) {
228 			/* INFO("Using DW MMC IO\n"); */
229 			io_close(image_handle);
230 		}
231 	}
232 	return result;
233 }
234 
open_dw_mmc_boot(const uintptr_t spec)235 static int open_dw_mmc_boot(const uintptr_t spec)
236 {
237 	int result = IO_FAIL;
238 	uintptr_t image_handle;
239 
240 	/* indicate to select boot partition in eMMC */
241 	result = io_dev_init(emmc_dev_handle, 1);
242 	if (result == IO_SUCCESS) {
243 		result = io_open(emmc_dev_handle, spec, &image_handle);
244 		if (result == IO_SUCCESS) {
245 			/* INFO("Using DW MMC IO\n"); */
246 			io_close(image_handle);
247 		}
248 	}
249 	return result;
250 }
251 
io_setup(void)252 void io_setup(void)
253 {
254 	int io_result = IO_FAIL;
255 
256 	/* Register the IO devices on this platform */
257 	io_result = register_io_dev_fip(&fip_dev_con);
258 	assert(io_result == IO_SUCCESS);
259 
260 	io_result = register_io_dev_block(&dw_mmc_dev_con);
261 	assert(io_result == IO_SUCCESS);
262 
263 	io_result = register_io_dev_memmap(&bl1_mem_dev_con);
264 	assert(io_result == IO_SUCCESS);
265 
266 	/* Open connections to devices and cache the handles */
267 	io_result = io_dev_open(fip_dev_con, fip_dev_spec, &fip_dev_handle);
268 	assert(io_result == IO_SUCCESS);
269 
270 	dw_mmc_ops.init = init_mmc;
271 	dw_mmc_ops.read = mmc0_read;
272 	dw_mmc_ops.write = mmc0_write;
273 	io_result = io_dev_open(dw_mmc_dev_con, (uintptr_t)&dw_mmc_ops,
274 				&emmc_dev_handle);
275 	assert(io_result == IO_SUCCESS);
276 
277 	io_result = io_dev_open(bl1_mem_dev_con, bl1_mem_dev_spec,
278 				&loader_mem_dev_handle);
279 	assert(io_result == IO_SUCCESS);
280 
281 	/* Ignore improbable errors in release builds */
282 	(void)io_result;
283 }
284 
285 /* Return an IO device handle and specification which can be used to access
286  * an image. Use this to enforce platform load policy */
plat_get_image_source(const char * image_name,uintptr_t * dev_handle,uintptr_t * image_spec)287 int plat_get_image_source(const char *image_name, uintptr_t *dev_handle,
288 			  uintptr_t *image_spec)
289 {
290 	int result = IO_FAIL;
291 	const struct plat_io_policy *policy;
292 
293 	if ((image_name != NULL) && (dev_handle != NULL) &&
294 	    (image_spec != NULL)) {
295 		policy = policies;
296 		while (policy->image_name != NULL) {
297 			if (strcmp(policy->image_name, image_name) == 0) {
298 				result = policy->check(policy->image_spec);
299 				if (result == IO_SUCCESS) {
300 					*image_spec = policy->image_spec;
301 					*dev_handle = *(policy->dev_handle);
302 					break;
303 				}
304 			}
305 			policy++;
306 		}
307 	} else {
308 		result = IO_FAIL;
309 	}
310 	return result;
311 }
312 
update_fip_spec(void)313 int update_fip_spec(void)
314 {
315 	struct ptentry *ptn;
316 
317 	ptn = find_ptn("fastboot");
318 	if (!ptn) {
319 		WARN("failed to find partition fastboot\n");
320 		ptn = find_ptn("bios");
321 		if (!ptn) {
322 			WARN("failed to find partition bios\n");
323 			return IO_FAIL;
324 		}
325 	}
326 	VERBOSE("%s: name:%s, start:%llx, length:%llx\n",
327 		__func__, ptn->name, ptn->start, ptn->length);
328 	fip_block_spec.offset = ptn->start;
329 	fip_block_spec.length = ptn->length;
330 	return IO_SUCCESS;
331 }
332 
fetch_entry_head(void * buf,int num,struct entry_head * hd)333 static int fetch_entry_head(void *buf, int num, struct entry_head *hd)
334 {
335 	unsigned char magic[8] = "ENTRYHDR";
336 	if (hd == NULL)
337 		return IO_FAIL;
338 	memcpy((void *)hd, buf, sizeof(struct entry_head) * num);
339 	if (!strncmp((void *)hd->magic, (void *)magic, 8))
340 		return IO_SUCCESS;
341 	return IO_NOT_SUPPORTED;
342 }
343 
flush_loader(void)344 static int flush_loader(void)
345 {
346 	struct entry_head entries[5];
347 	uintptr_t img_handle, spec;
348 	int result = IO_FAIL;
349 	size_t bytes_read, length;
350 	ssize_t offset;
351 	int i, fp;
352 
353 	result = fetch_entry_head((void *)(FLUSH_BASE + 28),
354 				  LOADER_MAX_ENTRIES, entries);
355 	if (result) {
356 		WARN("failed to parse entries in loader image\n");
357 		return result;
358 	}
359 
360 	spec = 0;
361 	for (i = 0, fp = 0; i < LOADER_MAX_ENTRIES; i++) {
362 		if (entries[i].flag != 1) {
363 			WARN("Invalid flag in entry:0x%x\n", entries[i].flag);
364 			return IO_NOT_SUPPORTED;
365 		}
366 		result = plat_get_image_source(BOOT_EMMC_NAME, &emmc_dev_handle,
367 					       &spec);
368 		if (result) {
369 			WARN("failed to open emmc boot area\n");
370 			return result;
371 		}
372 		/* offset in Boot Area1 */
373 		offset = MMC_LOADER_BASE + entries[i].start * 512;
374 
375 		result = io_open(emmc_dev_handle, spec, &img_handle);
376 		if (result != IO_SUCCESS) {
377 			WARN("Failed to open memmap device\n");
378 			return result;
379 		}
380 		length = entries[i].count * 512;
381 
382 		result = io_seek(img_handle, IO_SEEK_SET, offset);
383 		if (result)
384 			goto exit;
385 
386 		if (i == 1)
387 			fp = (entries[1].start - entries[0].start) * 512;
388 		result = io_write(img_handle, FLUSH_BASE + fp, length,
389 				  &bytes_read);
390 		if ((result != IO_SUCCESS) || (bytes_read < length)) {
391 			WARN("Failed to write '%s' file (%i)\n",
392 			     LOADER_MEM_NAME, result);
393 			goto exit;
394 		}
395 		io_close(img_handle);
396 	}
397 	return result;
398 exit:
399 	io_close(img_handle);
400 	return result;
401 }
402 
403 /*
404  * Flush l-loader.bin (loader & bl1.bin) into Boot Area1 of eMMC.
405  */
flush_loader_image(void)406 int flush_loader_image(void)
407 {
408 	uintptr_t bl1_image_spec;
409 	int result = IO_FAIL;
410 	size_t bytes_read, length;
411 	uintptr_t img_handle;
412 
413 	result = plat_get_image_source(LOADER_MEM_NAME, &loader_mem_dev_handle,
414 				       &bl1_image_spec);
415 
416 	result = io_open(loader_mem_dev_handle, bl1_image_spec, &img_handle);
417 	if (result != IO_SUCCESS) {
418 		WARN("Failed to open memmap device\n");
419 		goto exit;
420 	}
421 	length = loader_mem_spec.length;
422 	result = io_read(img_handle, FLUSH_BASE, length, &bytes_read);
423 	if ((result != IO_SUCCESS) || (bytes_read < length)) {
424 		WARN("Failed to load '%s' file (%i)\n", LOADER_MEM_NAME, result);
425 		goto exit;
426 	}
427 	io_close(img_handle);
428 
429 	result = flush_loader();
430 	if (result != IO_SUCCESS) {
431 		io_dev_close(loader_mem_dev_handle);
432 		return result;
433 	}
434 exit:
435 	io_close(img_handle);
436 	io_dev_close(loader_mem_dev_handle);
437 	return result;
438 }
439 
flush_single_image(const char * mmc_name,unsigned long img_addr,ssize_t offset,size_t length)440 static int flush_single_image(const char *mmc_name, unsigned long img_addr,
441 				ssize_t offset, size_t length)
442 {
443 	uintptr_t img_handle, spec = 0;
444 	size_t bytes_read;
445 	int result = IO_FAIL;
446 
447 	result = plat_get_image_source(mmc_name, &emmc_dev_handle,
448 				       &spec);
449 	if (result) {
450 		NOTICE("failed to open emmc user data area\n");
451 		return result;
452 	}
453 
454 	result = io_open(emmc_dev_handle, spec, &img_handle);
455 	if (result != IO_SUCCESS) {
456 		NOTICE("Failed to open memmap device\n");
457 		return result;
458 	}
459 
460 	result = io_seek(img_handle, IO_SEEK_SET, offset);
461 	if (result) {
462 		NOTICE("Failed to seek at offset:0x%x\n", offset);
463 		goto exit;
464 	}
465 
466 	result = io_write(img_handle, img_addr, length,
467 			  &bytes_read);
468 	if ((result != IO_SUCCESS) || (bytes_read < length)) {
469 		NOTICE("Failed to write file (%i)\n", result);
470 		goto exit;
471 	}
472 exit:
473 	io_close(img_handle);
474 	return result;
475 }
476 
is_sparse_image(unsigned long img_addr)477 static int is_sparse_image(unsigned long img_addr)
478 {
479 	if (*(uint32_t *)img_addr == SPARSE_HEADER_MAGIC)
480 		return 1;
481 	return 0;
482 }
483 
do_unsparse(char * cmdbuf,unsigned long img_addr,unsigned long img_length)484 static int do_unsparse(char *cmdbuf, unsigned long img_addr, unsigned long img_length)
485 {
486 	sparse_header_t *header = (sparse_header_t *)img_addr;
487 	chunk_header_t *chunk = NULL;
488 	struct ptentry *ptn;
489 	void *data = (void *)img_addr;
490 	uint64_t out_blks = 0, out_length = 0;
491 	uint64_t length;
492 	uint32_t fill_value;
493 	uint64_t left, count;
494 	int i, result;
495 
496 	ptn = find_ptn(cmdbuf);
497 	if (!ptn) {
498 		NOTICE("failed to find partition %s\n", cmdbuf);
499 		return IO_FAIL;
500 	}
501 	length = (uint64_t)(header->total_blks) * (uint64_t)(header->blk_sz);
502 	if (length > ptn->length) {
503 		NOTICE("Unsparsed image length is %lld, pentry length is %lld.\n",
504 			length, ptn->length);
505 		return IO_FAIL;
506 	}
507 
508 	data = (void *)((unsigned long)data + header->file_hdr_sz);
509 	for (i = 0; i < header->total_chunks; i++) {
510 		chunk = (chunk_header_t *)data;
511 		data = (void *)((unsigned long)data + sizeof(chunk_header_t));
512 		length = (uint64_t)chunk->chunk_sz * (uint64_t)header->blk_sz;
513 
514 		switch (chunk->chunk_type) {
515 		case CHUNK_TYPE_RAW:
516 			result = flush_single_image(NORMAL_EMMC_NAME,
517 						    (unsigned long)data,
518 						    ptn->start + out_length, length);
519 			if (result < 0) {
520 				NOTICE("sparse: failed to flush raw chunk\n");
521 				return result;
522 			}
523 			out_blks += length / 512;
524 			out_length += length;
525 			/* next chunk is just after the raw data */
526 			data = (void *)((unsigned long)data + length);
527 			break;
528 		case CHUNK_TYPE_FILL:
529 			if (chunk->total_sz != (sizeof(unsigned int) + sizeof(chunk_header_t))) {
530 				NOTICE("sparse: bad chunk size\n");
531 				return IO_FAIL;
532 			}
533 			fill_value = *(unsigned int *)data;
534 			if (fill_value != 0) {
535 				NOTICE("sparse: filled value shouldn't be zero.\n");
536 			}
537 			memset((void *)SPARSE_FILL_BUFFER_ADDRESS,
538 				0, SPARSE_FILL_BUFFER_SIZE);
539 			left = length;
540 			while (left > 0) {
541 				if (left < SPARSE_FILL_BUFFER_SIZE)
542 					count = left;
543 				else
544 					count = SPARSE_FILL_BUFFER_SIZE;
545 				result = flush_single_image(NORMAL_EMMC_NAME,
546 							    SPARSE_FILL_BUFFER_ADDRESS,
547 							    ptn->start + out_length, count);
548 				if (result < 0) {
549 					WARN("sparse: failed to flush fill chunk\n");
550 					return result;
551 				}
552 				out_blks += count / 512;
553 				out_length += count;
554 				left = left - count;
555 			}
556 			/* next chunk is just after the filled data */
557 			data = (void *)((unsigned long)data + sizeof(unsigned int));
558 			break;
559 		case CHUNK_TYPE_DONT_CARE:
560 			if (chunk->total_sz != sizeof(chunk_header_t)) {
561 				NOTICE("sparse: unmatched chunk size\n");
562 				return IO_FAIL;
563 			}
564 			out_blks += length / 512;
565 			out_length += length;
566 			break;
567 		default:
568 			NOTICE("sparse: unrecognized type 0x%x\n", chunk->chunk_type);
569 			break;
570 		}
571 	}
572 	return 0;
573 }
574 
575 /* Page 1024 is used to store serial number */
flush_random_serialno(unsigned long addr,unsigned long length)576 int flush_random_serialno(unsigned long addr, unsigned long length)
577 {
578 	int result;
579 
580 	memset((void *)SPARSE_FILL_BUFFER_ADDRESS, 0, 512);
581 	memcpy((void *)SPARSE_FILL_BUFFER_ADDRESS, (void *)addr, length);
582 	result = flush_single_image(NORMAL_EMMC_NAME, SPARSE_FILL_BUFFER_ADDRESS,
583 				    SERIALNO_OFFSET, 512);
584 	return result;
585 }
586 
load_serialno(void)587 char *load_serialno(void)
588 {
589 	uintptr_t img_handle, spec = 0;
590 	size_t bytes_read;
591 	struct random_serial_num *random = NULL;
592 	int result;
593 
594 	result = plat_get_image_source(NORMAL_EMMC_NAME, &emmc_dev_handle,
595 				       &spec);
596 	if (result) {
597 		NOTICE("failed to open emmc user data area\n");
598 		return NULL;
599 	}
600 
601 	result = io_open(emmc_dev_handle, spec, &img_handle);
602 	if (result != IO_SUCCESS) {
603 		NOTICE("Failed to open memmap device\n");
604 		return NULL;
605 	}
606 
607 	result = io_seek(img_handle, IO_SEEK_SET, SERIALNO_OFFSET);
608 	if (result) {
609 		NOTICE("Failed to seek at offset 0\n");
610 		goto exit;
611 	}
612 	result = io_read(img_handle, SPARSE_FILL_BUFFER_ADDRESS, 512, &bytes_read);
613 	if ((result != IO_SUCCESS) || (bytes_read < 512)) {
614 		NOTICE("Failed to load '%s' file (%i)\n", LOADER_MEM_NAME, result);
615 		goto exit;
616 	}
617 	io_close(img_handle);
618 
619 	random = (struct random_serial_num *)SPARSE_FILL_BUFFER_ADDRESS;
620 	if (random->magic != RANDOM_MAGIC)
621 		return NULL;
622 
623 	return random->serialno;
624 exit:
625 	io_close(img_handle);
626 	return NULL;
627 }
628 
629 /*
630  * Flush bios.bin into User Data Area in eMMC
631  */
flush_user_images(char * cmdbuf,unsigned long img_addr,unsigned long img_length)632 int flush_user_images(char *cmdbuf, unsigned long img_addr,
633 		      unsigned long img_length)
634 {
635 	struct entry_head entries[5];
636 	struct ptentry *ptn;
637 	size_t length;
638 	ssize_t offset;
639 	int result = IO_FAIL;
640 	int i, fp;
641 
642 	result = fetch_entry_head((void *)img_addr, USER_MAX_ENTRIES, entries);
643 	switch (result) {
644 	case IO_NOT_SUPPORTED:
645 		if (!strncmp(cmdbuf, "fastboot", 8) ||
646 		    !strncmp(cmdbuf, "bios", 4)) {
647 			update_fip_spec();
648 		}
649 		if (is_sparse_image(img_addr)) {
650 			result = do_unsparse(cmdbuf, img_addr, img_length);
651 		} else {
652 			ptn = find_ptn(cmdbuf);
653 			if (!ptn) {
654 				WARN("failed to find partition %s\n", cmdbuf);
655 				return IO_FAIL;
656 			}
657 			img_length = (img_length + 512 - 1) / 512 * 512;
658 			result = flush_single_image(NORMAL_EMMC_NAME, img_addr,
659 						    ptn->start, img_length);
660 		}
661 		break;
662 	case IO_SUCCESS:
663 		if (strncmp(cmdbuf, "ptable", 6)) {
664 			WARN("it's not for ptable\n");
665 			return IO_FAIL;
666 		}
667 		/* currently it's for partition table */
668 		/* the first block is for entry headers */
669 		fp = 512;
670 
671 		for (i = 0; i < USER_MAX_ENTRIES; i++) {
672 			if (entries[i].flag != 0) {
673 				WARN("Invalid flag in entry:0x%x\n",
674 					entries[i].flag);
675 				return IO_NOT_SUPPORTED;
676 			}
677 			if (entries[i].count == 0)
678 				continue;
679 			length = entries[i].count * 512;
680 			offset = MMC_BASE + entries[i].start * 512;
681 			VERBOSE("i:%d, start:%x, count:%x\n",
682 				i, entries[i].start, entries[i].count);
683 			result = flush_single_image(NORMAL_EMMC_NAME,
684 						img_addr + fp, offset, length);
685 			fp += entries[i].count * 512;
686 		}
687 		get_partition();
688 		break;
689 	case IO_FAIL:
690 		WARN("failed to parse entries in user image.\n");
691 		return result;
692 	}
693 	return result;
694 }
695