diff options
Diffstat (limited to 'tools/pblimage.c')
| -rw-r--r-- | tools/pblimage.c | 331 | 
1 files changed, 331 insertions, 0 deletions
| diff --git a/tools/pblimage.c b/tools/pblimage.c new file mode 100644 index 000000000..508a747a3 --- /dev/null +++ b/tools/pblimage.c @@ -0,0 +1,331 @@ +/* + * Copyright 2012 Freescale Semiconductor, Inc. + * + * See file CREDITS for list of people who contributed to this + * project. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of + * the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, + * MA 02111-1307 USA + */ +#define _GNU_SOURCE + +#include "mkimage.h" +#include <image.h> +#include "pblimage.h" + +/* + * The PBL can load up to 64 bytes at a time, so we split the U-Boot + * image into 64 byte chunks. PBL needs a command for each piece, of + * the form "81xxxxxx", where "xxxxxx" is the offset. SYS_TEXT_BASE + * is 0xFFF80000 for PBL boot, and PBL only cares about low 24-bit, + * so it starts from 0x81F80000. + */ +static uint32_t next_pbl_cmd = 0x81F80000; +/* + * need to store all bytes in memory for calculating crc32, then write the + * bytes to image file for PBL boot. + */ +static unsigned char mem_buf[600000]; +static unsigned char *pmem_buf = mem_buf; +static int pbl_size; +static char *fname = "Unknown"; +static int lineno = -1; +static struct pbl_header pblimage_header; + +static union +{ +	char c[4]; +	unsigned char l; +} endian_test = { {'l', '?', '?', 'b'} }; + +#define ENDIANNESS ((char)endian_test.l) + +static void generate_pbl_cmd(void) +{ +	uint32_t val = next_pbl_cmd; +	next_pbl_cmd += 0x40; +	int i; + +	for (i = 3; i >= 0; i--) { +		*pmem_buf++ = (val >> (i * 8)) & 0xff; +		pbl_size++; +	} +} + +static void pbl_fget(size_t size, FILE *stream) +{ +	unsigned char c; +	int c_temp; + +	while (size && (c_temp = fgetc(stream)) != EOF) { +		c = (unsigned char)c_temp; +		*pmem_buf++ = c; +		pbl_size++; +		size--; +	} +} + +/* load split u-boot with PBI command 81xxxxxx. */ +static void load_uboot(FILE *fp_uboot) +{ +	while (next_pbl_cmd < 0x82000000) { +		generate_pbl_cmd(); +		pbl_fget(64, fp_uboot); +	} +} + +static void check_get_hexval(char *token) +{ +	uint32_t hexval; +	int i; + +	if (!sscanf(token, "%x", &hexval)) { +		printf("Error:%s[%d] - Invalid hex data(%s)\n", fname, +			lineno, token); +		exit(EXIT_FAILURE); +	} +	for (i = 3; i >= 0; i--) { +		*pmem_buf++ = (hexval >> (i * 8)) & 0xff; +		pbl_size++; +	} +} + +static void pbl_parser(char *name) +{ +	FILE *fd = NULL; +	char *line = NULL; +	char *token, *saveptr1, *saveptr2; +	size_t len = 0; + +	fname = name; +	fd = fopen(name, "r"); +	if (fd == NULL) { +		printf("Error:%s - Can't open\n", fname); +		exit(EXIT_FAILURE); +	} + +	while ((getline(&line, &len, fd)) > 0) { +		lineno++; +		token = strtok_r(line, "\r\n", &saveptr1); +		/* drop all lines with zero tokens (= empty lines) */ +		if (token == NULL) +			continue; +		for (line = token;; line = NULL) { +			token = strtok_r(line, " \t", &saveptr2); +			if (token == NULL) +				break; +			/* Drop all text starting with '#' as comments */ +			if (token[0] == '#') +				break; +			check_get_hexval(token); +		} +	} +	if (line) +		free(line); +	fclose(fd); +} + +static uint32_t crc_table[256]; + +static void make_crc_table(void) +{ +	uint32_t mask; +	int i, j; +	uint32_t poly; /* polynomial exclusive-or pattern */ + +	/* +	 * the polynomial used by PBL is 1 + x1 + x2 + x4 + x5 + x7 + x8 + x10 +	 * + x11 + x12 + x16 + x22 + x23 + x26 + x32. +	 */ +	poly = 0x04c11db7; + +	for (i = 0; i < 256; i++) { +		mask = i << 24; +		for (j = 0; j < 8; j++) { +			if (mask & 0x80000000) +				mask = (mask << 1) ^ poly; +			else +				mask <<= 1; +		} +		crc_table[i] = mask; +	} +} + +unsigned long pbl_crc32(unsigned long crc, const char *buf, uint32_t len) +{ +	uint32_t crc32_val = 0xffffffff; +	uint32_t xor = 0x0; +	int i; + +	make_crc_table(); + +	for (i = 0; i < len; i++) +		crc32_val = (crc32_val << 8) ^ +			crc_table[(crc32_val >> 24) ^ (*buf++ & 0xff)]; + +	crc32_val = crc32_val ^ xor; +	if (crc32_val < 0) { +		crc32_val += 0xffffffff; +		crc32_val += 1; +	} +	return crc32_val; +} + +static uint32_t reverse_byte(uint32_t val) +{ +	uint32_t temp; +	unsigned char *p1; +	int j; + +	temp = val; +	p1 = (unsigned char *)&temp; +	for (j = 3; j >= 0; j--) +		*p1++ = (val >> (j * 8)) & 0xff; +	return temp; +} + +/* write end command and crc command to memory. */ +static void add_end_cmd(void) +{ +	uint32_t pbl_end_cmd[4] = {0x09138000, 0x00000000, +		0x091380c0, 0x00000000}; +	uint32_t crc32_pbl; +	int i; +	unsigned char *p = (unsigned char *)&pbl_end_cmd; + +	if (ENDIANNESS == 'l') { +		for (i = 0; i < 4; i++) +			pbl_end_cmd[i] = reverse_byte(pbl_end_cmd[i]); +	} + +	for (i = 0; i < 16; i++) { +		*pmem_buf++ = *p++; +		pbl_size++; +	} + +	/* Add PBI CRC command. */ +	*pmem_buf++ = 0x08; +	*pmem_buf++ = 0x13; +	*pmem_buf++ = 0x80; +	*pmem_buf++ = 0x40; +	pbl_size += 4; + +	/* calculated CRC32 and write it to memory. */ +	crc32_pbl = pbl_crc32(0, (const char *)mem_buf, pbl_size); +	*pmem_buf++ = (crc32_pbl >> 24) & 0xff; +	*pmem_buf++ = (crc32_pbl >> 16) & 0xff; +	*pmem_buf++ = (crc32_pbl >> 8) & 0xff; +	*pmem_buf++ = (crc32_pbl) & 0xff; +	pbl_size += 4; + +	if ((pbl_size % 16) != 0) { +		for (i = 0; i < 8; i++) { +			*pmem_buf++ = 0x0; +			pbl_size++; +		} +	} +	if ((pbl_size % 16 != 0)) { +		printf("Error: Bad size of image file\n"); +		exit(EXIT_FAILURE); +	} +} + +void pbl_load_uboot(int ifd, struct mkimage_params *params) +{ +	FILE *fp_uboot; +	int size; + +	/* parse the rcw.cfg file. */ +	pbl_parser(params->imagename); + +	/* parse the pbi.cfg file. */ +	pbl_parser(params->imagename2); + +	fp_uboot = fopen(params->datafile, "r"); +	if (fp_uboot == NULL) { +		printf("Error: %s open failed\n", params->datafile); +		exit(EXIT_FAILURE); +	} + +	load_uboot(fp_uboot); +	add_end_cmd(); +	fclose(fp_uboot); +	lseek(ifd, 0, SEEK_SET); + +	size = pbl_size; +	if (write(ifd, (const void *)&mem_buf, size) != size) { +		fprintf(stderr, "Write error on %s: %s\n", +			params->imagefile, strerror(errno)); +		exit(EXIT_FAILURE); +	} +} + +static int pblimage_check_image_types(uint8_t type) +{ +	if (type == IH_TYPE_PBLIMAGE) +		return EXIT_SUCCESS; +	else +		return EXIT_FAILURE; +} + +static int pblimage_verify_header(unsigned char *ptr, int image_size, +			struct mkimage_params *params) +{ +	struct pbl_header *pbl_hdr = (struct pbl_header *) ptr; + +	/* Only a few checks can be done: search for magic numbers */ +	if (ENDIANNESS == 'l') { +		if (pbl_hdr->preamble != reverse_byte(RCW_PREAMBLE)) +			return -FDT_ERR_BADSTRUCTURE; + +		if (pbl_hdr->rcwheader != reverse_byte(RCW_HEADER)) +			return -FDT_ERR_BADSTRUCTURE; +	} else { +		if (pbl_hdr->preamble != RCW_PREAMBLE) +			return -FDT_ERR_BADSTRUCTURE; + +		if (pbl_hdr->rcwheader != RCW_HEADER) +			return -FDT_ERR_BADSTRUCTURE; +	} +	return 0; +} + +static void pblimage_print_header(const void *ptr) +{ +	printf("Image Type:   Freescale PBL Boot Image\n"); +} + +static void pblimage_set_header(void *ptr, struct stat *sbuf, int ifd, +				struct mkimage_params *params) +{ +	/*nothing need to do, pbl_load_uboot takes care of whole file. */ +} + +/* pblimage parameters */ +static struct image_type_params pblimage_params = { +	.name		= "Freescale PBL Boot Image support", +	.header_size	= sizeof(struct pbl_header), +	.hdr		= (void *)&pblimage_header, +	.check_image_type = pblimage_check_image_types, +	.verify_header	= pblimage_verify_header, +	.print_header	= pblimage_print_header, +	.set_header	= pblimage_set_header, +}; + +void init_pbl_image_type(void) +{ +	pbl_size = 0; +	mkimage_register(&pblimage_params); +} |