xref: /openbmc/u-boot/tools/ublimage.c (revision 83d290c56fab2d38cd1ab4c4cc7099559c1d5046)
1*83d290c5STom Rini // SPDX-License-Identifier: GPL-2.0+
27816f2cfSHeiko Schocher /*
37816f2cfSHeiko Schocher  * (C) Copyright 2011
47816f2cfSHeiko Schocher  * Heiko Schocher, DENX Software Engineering, hs@denx.de.
57816f2cfSHeiko Schocher  *
67816f2cfSHeiko Schocher  * Based on:
77816f2cfSHeiko Schocher  * (C) Copyright 2009
87816f2cfSHeiko Schocher  * Stefano Babic, DENX Software Engineering, sbabic@denx.de.
97816f2cfSHeiko Schocher  *
107816f2cfSHeiko Schocher  * (C) Copyright 2008
117816f2cfSHeiko Schocher  * Marvell Semiconductor <www.marvell.com>
127816f2cfSHeiko Schocher  * Written-by: Prafulla Wadaskar <prafulla@marvell.com>
137816f2cfSHeiko Schocher  */
147816f2cfSHeiko Schocher 
15f86ed6a8SGuilherme Maciel Ferreira #include "imagetool.h"
167816f2cfSHeiko Schocher #include <image.h>
177816f2cfSHeiko Schocher #include "ublimage.h"
187816f2cfSHeiko Schocher 
197816f2cfSHeiko Schocher /*
207816f2cfSHeiko Schocher  * Supported commands for configuration file
217816f2cfSHeiko Schocher  */
227816f2cfSHeiko Schocher static table_entry_t ublimage_cmds[] = {
237816f2cfSHeiko Schocher 	{CMD_BOOT_MODE,	"MODE",		"UBL special modes", },
247816f2cfSHeiko Schocher 	{CMD_ENTRY,	"ENTRY",	"Entry point addr for bootloader", },
257816f2cfSHeiko Schocher 	{CMD_PAGE,	"PAGES",
267816f2cfSHeiko Schocher 		"number of pages (size of bootloader)", },
277816f2cfSHeiko Schocher 	{CMD_ST_BLOCK,	"START_BLOCK",
287816f2cfSHeiko Schocher 		"block number where bootloader is present", },
297816f2cfSHeiko Schocher 	{CMD_ST_PAGE,	"START_PAGE",
307816f2cfSHeiko Schocher 		"page number where bootloader is present", },
317816f2cfSHeiko Schocher 	{CMD_LD_ADDR,	"LD_ADDR",
327816f2cfSHeiko Schocher 		"load addr", },
337816f2cfSHeiko Schocher 	{-1,		"",		"", },
347816f2cfSHeiko Schocher };
357816f2cfSHeiko Schocher 
367816f2cfSHeiko Schocher /*
377816f2cfSHeiko Schocher  * Supported Boot options for configuration file
387816f2cfSHeiko Schocher  * this is needed to set the correct flash offset
397816f2cfSHeiko Schocher  */
407816f2cfSHeiko Schocher static table_entry_t ublimage_bootops[] = {
417816f2cfSHeiko Schocher 	{UBL_MAGIC_SAFE,	"safe",	"Safe boot mode",	},
427816f2cfSHeiko Schocher 	{-1,			"",	"Invalid",		},
437816f2cfSHeiko Schocher };
447816f2cfSHeiko Schocher 
457816f2cfSHeiko Schocher static struct ubl_header ublimage_header;
467816f2cfSHeiko Schocher 
get_cfg_value(char * token,char * name,int linenr)477816f2cfSHeiko Schocher static uint32_t get_cfg_value(char *token, char *name,  int linenr)
487816f2cfSHeiko Schocher {
497816f2cfSHeiko Schocher 	char *endptr;
507816f2cfSHeiko Schocher 	uint32_t value;
517816f2cfSHeiko Schocher 
527816f2cfSHeiko Schocher 	errno = 0;
537816f2cfSHeiko Schocher 	value = strtoul(token, &endptr, 16);
547816f2cfSHeiko Schocher 	if (errno || (token == endptr)) {
557816f2cfSHeiko Schocher 		fprintf(stderr, "Error: %s[%d] - Invalid hex data(%s)\n",
567816f2cfSHeiko Schocher 			name,  linenr, token);
577816f2cfSHeiko Schocher 		exit(EXIT_FAILURE);
587816f2cfSHeiko Schocher 	}
597816f2cfSHeiko Schocher 	return value;
607816f2cfSHeiko Schocher }
617816f2cfSHeiko Schocher 
print_hdr(struct ubl_header * ubl_hdr)627816f2cfSHeiko Schocher static void print_hdr(struct ubl_header *ubl_hdr)
637816f2cfSHeiko Schocher {
647816f2cfSHeiko Schocher 	printf("Image Type : Davinci UBL Boot Image\n");
657816f2cfSHeiko Schocher 	printf("UBL magic  : %08x\n", ubl_hdr->magic);
667816f2cfSHeiko Schocher 	printf("Entry Point: %08x\n", ubl_hdr->entry);
677816f2cfSHeiko Schocher 	printf("nr of pages: %08x\n", ubl_hdr->pages);
687816f2cfSHeiko Schocher 	printf("start block: %08x\n", ubl_hdr->block);
697816f2cfSHeiko Schocher 	printf("start page : %08x\n", ubl_hdr->page);
707816f2cfSHeiko Schocher }
717816f2cfSHeiko Schocher 
parse_cfg_cmd(struct ubl_header * ublhdr,int32_t cmd,char * token,char * name,int lineno,int fld,int dcd_len)727816f2cfSHeiko Schocher static void parse_cfg_cmd(struct ubl_header *ublhdr, int32_t cmd, char *token,
737816f2cfSHeiko Schocher 				char *name, int lineno, int fld, int dcd_len)
747816f2cfSHeiko Schocher {
757816f2cfSHeiko Schocher 	static int cmd_ver_first = ~0;
767816f2cfSHeiko Schocher 
777816f2cfSHeiko Schocher 	switch (cmd) {
787816f2cfSHeiko Schocher 	case CMD_BOOT_MODE:
797816f2cfSHeiko Schocher 		ublhdr->magic = get_table_entry_id(ublimage_bootops,
807816f2cfSHeiko Schocher 					"ublimage special boot mode", token);
817816f2cfSHeiko Schocher 		if (ublhdr->magic == -1) {
827816f2cfSHeiko Schocher 			fprintf(stderr, "Error: %s[%d] -Invalid boot mode"
837816f2cfSHeiko Schocher 				"(%s)\n", name, lineno, token);
847816f2cfSHeiko Schocher 			exit(EXIT_FAILURE);
857816f2cfSHeiko Schocher 		}
867816f2cfSHeiko Schocher 		ublhdr->magic += UBL_MAGIC_BASE;
877816f2cfSHeiko Schocher 		if (unlikely(cmd_ver_first != 1))
887816f2cfSHeiko Schocher 			cmd_ver_first = 0;
897816f2cfSHeiko Schocher 		break;
907816f2cfSHeiko Schocher 	case CMD_ENTRY:
917816f2cfSHeiko Schocher 		ublhdr->entry = get_cfg_value(token, name, lineno);
927816f2cfSHeiko Schocher 		break;
937816f2cfSHeiko Schocher 	case CMD_PAGE:
947816f2cfSHeiko Schocher 		ublhdr->pages = get_cfg_value(token, name, lineno);
957816f2cfSHeiko Schocher 		break;
967816f2cfSHeiko Schocher 	case CMD_ST_BLOCK:
977816f2cfSHeiko Schocher 		ublhdr->block = get_cfg_value(token, name, lineno);
987816f2cfSHeiko Schocher 		break;
997816f2cfSHeiko Schocher 	case CMD_ST_PAGE:
1007816f2cfSHeiko Schocher 		ublhdr->page = get_cfg_value(token, name, lineno);
1017816f2cfSHeiko Schocher 		break;
1027816f2cfSHeiko Schocher 	case CMD_LD_ADDR:
1037816f2cfSHeiko Schocher 		ublhdr->pll_m = get_cfg_value(token, name, lineno);
1047816f2cfSHeiko Schocher 		break;
1057816f2cfSHeiko Schocher 	}
1067816f2cfSHeiko Schocher }
1077816f2cfSHeiko Schocher 
parse_cfg_fld(struct ubl_header * ublhdr,int32_t * cmd,char * token,char * name,int lineno,int fld,int * dcd_len)1087816f2cfSHeiko Schocher static void parse_cfg_fld(struct ubl_header *ublhdr, int32_t *cmd,
1097816f2cfSHeiko Schocher 		char *token, char *name, int lineno, int fld, int *dcd_len)
1107816f2cfSHeiko Schocher {
1117816f2cfSHeiko Schocher 
1127816f2cfSHeiko Schocher 	switch (fld) {
1137816f2cfSHeiko Schocher 	case CFG_COMMAND:
1147816f2cfSHeiko Schocher 		*cmd = get_table_entry_id(ublimage_cmds,
1157816f2cfSHeiko Schocher 			"ublimage commands", token);
1167816f2cfSHeiko Schocher 		if (*cmd < 0) {
1177816f2cfSHeiko Schocher 			fprintf(stderr, "Error: %s[%d] - Invalid command"
1187816f2cfSHeiko Schocher 			"(%s)\n", name, lineno, token);
1197816f2cfSHeiko Schocher 			exit(EXIT_FAILURE);
1207816f2cfSHeiko Schocher 		}
1217816f2cfSHeiko Schocher 		break;
1227816f2cfSHeiko Schocher 	case CFG_REG_VALUE:
1237816f2cfSHeiko Schocher 		parse_cfg_cmd(ublhdr, *cmd, token, name, lineno, fld, *dcd_len);
1247816f2cfSHeiko Schocher 		break;
1257816f2cfSHeiko Schocher 	default:
1267816f2cfSHeiko Schocher 		break;
1277816f2cfSHeiko Schocher 	}
1287816f2cfSHeiko Schocher }
parse_cfg_file(struct ubl_header * ublhdr,char * name)1297816f2cfSHeiko Schocher static uint32_t parse_cfg_file(struct ubl_header *ublhdr, char *name)
1307816f2cfSHeiko Schocher {
1317816f2cfSHeiko Schocher 	FILE *fd = NULL;
1327816f2cfSHeiko Schocher 	char *line = NULL;
1337816f2cfSHeiko Schocher 	char *token, *saveptr1, *saveptr2;
1347816f2cfSHeiko Schocher 	int lineno = 0;
1357816f2cfSHeiko Schocher 	int	i;
1367816f2cfSHeiko Schocher 	char *ptr = (char *)ublhdr;
1377816f2cfSHeiko Schocher 	int fld;
1387816f2cfSHeiko Schocher 	size_t len;
1397816f2cfSHeiko Schocher 	int dcd_len = 0;
1407816f2cfSHeiko Schocher 	int32_t cmd;
1417816f2cfSHeiko Schocher 	int ublhdrlen = sizeof(struct ubl_header);
1427816f2cfSHeiko Schocher 
1437816f2cfSHeiko Schocher 	fd = fopen(name, "r");
1447816f2cfSHeiko Schocher 	if (fd == 0) {
1457816f2cfSHeiko Schocher 		fprintf(stderr, "Error: %s - Can't open DCD file\n", name);
1467816f2cfSHeiko Schocher 		exit(EXIT_FAILURE);
1477816f2cfSHeiko Schocher 	}
1487816f2cfSHeiko Schocher 
1497816f2cfSHeiko Schocher 	/* Fill header with 0xff */
1507816f2cfSHeiko Schocher 	for (i = 0; i < ublhdrlen; i++) {
1517816f2cfSHeiko Schocher 		*ptr = 0xff;
1527816f2cfSHeiko Schocher 		ptr++;
1537816f2cfSHeiko Schocher 	}
1547816f2cfSHeiko Schocher 
1557816f2cfSHeiko Schocher 	/*
1567816f2cfSHeiko Schocher 	 * Very simple parsing, line starting with # are comments
1577816f2cfSHeiko Schocher 	 * and are dropped
1587816f2cfSHeiko Schocher 	 */
1597816f2cfSHeiko Schocher 	while ((getline(&line, &len, fd)) > 0) {
1607816f2cfSHeiko Schocher 		lineno++;
1617816f2cfSHeiko Schocher 
1627816f2cfSHeiko Schocher 		token = strtok_r(line, "\r\n", &saveptr1);
1637816f2cfSHeiko Schocher 		if (token == NULL)
1647816f2cfSHeiko Schocher 			continue;
1657816f2cfSHeiko Schocher 
1667816f2cfSHeiko Schocher 		/* Check inside the single line */
1677816f2cfSHeiko Schocher 		for (fld = CFG_COMMAND, cmd = CMD_INVALID,
1687816f2cfSHeiko Schocher 				line = token; ; line = NULL, fld++) {
1697816f2cfSHeiko Schocher 			token = strtok_r(line, " \t", &saveptr2);
1707816f2cfSHeiko Schocher 			if (token == NULL)
1717816f2cfSHeiko Schocher 				break;
1727816f2cfSHeiko Schocher 
1737816f2cfSHeiko Schocher 			/* Drop all text starting with '#' as comments */
1747816f2cfSHeiko Schocher 			if (token[0] == '#')
1757816f2cfSHeiko Schocher 				break;
1767816f2cfSHeiko Schocher 
1777816f2cfSHeiko Schocher 			parse_cfg_fld(ublhdr, &cmd, token, name,
1787816f2cfSHeiko Schocher 					lineno, fld, &dcd_len);
1797816f2cfSHeiko Schocher 		}
1807816f2cfSHeiko Schocher 	}
1817816f2cfSHeiko Schocher 	fclose(fd);
1827816f2cfSHeiko Schocher 
1837816f2cfSHeiko Schocher 	return dcd_len;
1847816f2cfSHeiko Schocher }
1857816f2cfSHeiko Schocher 
ublimage_check_image_types(uint8_t type)1867816f2cfSHeiko Schocher static int ublimage_check_image_types(uint8_t type)
1877816f2cfSHeiko Schocher {
1887816f2cfSHeiko Schocher 	if (type == IH_TYPE_UBLIMAGE)
1897816f2cfSHeiko Schocher 		return EXIT_SUCCESS;
1907816f2cfSHeiko Schocher 	else
1917816f2cfSHeiko Schocher 		return EXIT_FAILURE;
1927816f2cfSHeiko Schocher }
1937816f2cfSHeiko Schocher 
ublimage_verify_header(unsigned char * ptr,int image_size,struct image_tool_params * params)1947816f2cfSHeiko Schocher static int ublimage_verify_header(unsigned char *ptr, int image_size,
195f86ed6a8SGuilherme Maciel Ferreira 			struct image_tool_params *params)
1967816f2cfSHeiko Schocher {
19716396790SStefano Babic 	struct ubl_header *ubl_hdr = (struct ubl_header *)ptr;
19816396790SStefano Babic 
19916396790SStefano Babic 	if ((ubl_hdr->magic & 0xFFFFFF00) != UBL_MAGIC_BASE)
20016396790SStefano Babic 		return -1;
20116396790SStefano Babic 
2027816f2cfSHeiko Schocher 	return 0;
2037816f2cfSHeiko Schocher }
2047816f2cfSHeiko Schocher 
ublimage_print_header(const void * ptr)2057816f2cfSHeiko Schocher static void ublimage_print_header(const void *ptr)
2067816f2cfSHeiko Schocher {
2077816f2cfSHeiko Schocher 	struct ubl_header *ubl_hdr = (struct ubl_header *) ptr;
2087816f2cfSHeiko Schocher 
2097816f2cfSHeiko Schocher 	print_hdr(ubl_hdr);
2107816f2cfSHeiko Schocher }
2117816f2cfSHeiko Schocher 
ublimage_set_header(void * ptr,struct stat * sbuf,int ifd,struct image_tool_params * params)2127816f2cfSHeiko Schocher static void ublimage_set_header(void *ptr, struct stat *sbuf, int ifd,
213f86ed6a8SGuilherme Maciel Ferreira 				struct image_tool_params *params)
2147816f2cfSHeiko Schocher {
2157816f2cfSHeiko Schocher 	struct ubl_header *ublhdr = (struct ubl_header *)ptr;
2167816f2cfSHeiko Schocher 
2177816f2cfSHeiko Schocher 	/* Parse configuration file */
2187816f2cfSHeiko Schocher 	parse_cfg_file(ublhdr, params->imagename);
2197816f2cfSHeiko Schocher }
2207816f2cfSHeiko Schocher 
ublimage_check_params(struct image_tool_params * params)221f86ed6a8SGuilherme Maciel Ferreira int ublimage_check_params(struct image_tool_params *params)
2227816f2cfSHeiko Schocher {
2237816f2cfSHeiko Schocher 	if (!params)
2247816f2cfSHeiko Schocher 		return CFG_INVALID;
2257816f2cfSHeiko Schocher 	if (!strlen(params->imagename)) {
2267816f2cfSHeiko Schocher 		fprintf(stderr, "Error: %s - Configuration file not"
2277816f2cfSHeiko Schocher 			"specified, it is needed for ublimage generation\n",
2287816f2cfSHeiko Schocher 			params->cmdname);
2297816f2cfSHeiko Schocher 		return CFG_INVALID;
2307816f2cfSHeiko Schocher 	}
2317816f2cfSHeiko Schocher 	/*
2327816f2cfSHeiko Schocher 	 * Check parameters:
2337816f2cfSHeiko Schocher 	 * XIP is not allowed and verify that incompatible
2347816f2cfSHeiko Schocher 	 * parameters are not sent at the same time
2357816f2cfSHeiko Schocher 	 * For example, if list is required a data image must not be provided
2367816f2cfSHeiko Schocher 	 */
2377816f2cfSHeiko Schocher 	return	(params->dflag && (params->fflag || params->lflag)) ||
2387816f2cfSHeiko Schocher 		(params->fflag && (params->dflag || params->lflag)) ||
2397816f2cfSHeiko Schocher 		(params->lflag && (params->dflag || params->fflag)) ||
2407816f2cfSHeiko Schocher 		(params->xflag) || !(strlen(params->imagename));
2417816f2cfSHeiko Schocher }
2427816f2cfSHeiko Schocher 
2437816f2cfSHeiko Schocher /*
2447816f2cfSHeiko Schocher  * ublimage parameters
2457816f2cfSHeiko Schocher  */
246a93648d1SGuilherme Maciel Ferreira U_BOOT_IMAGE_TYPE(
247a93648d1SGuilherme Maciel Ferreira 	ublimage,
248a93648d1SGuilherme Maciel Ferreira 	"Davinci UBL boot support",
249a93648d1SGuilherme Maciel Ferreira 	sizeof(struct ubl_header),
250a93648d1SGuilherme Maciel Ferreira 	(void *)&ublimage_header,
251a93648d1SGuilherme Maciel Ferreira 	ublimage_check_params,
252a93648d1SGuilherme Maciel Ferreira 	ublimage_verify_header,
253a93648d1SGuilherme Maciel Ferreira 	ublimage_print_header,
254a93648d1SGuilherme Maciel Ferreira 	ublimage_set_header,
255a93648d1SGuilherme Maciel Ferreira 	NULL,
256a93648d1SGuilherme Maciel Ferreira 	ublimage_check_image_types,
257a93648d1SGuilherme Maciel Ferreira 	NULL,
258a93648d1SGuilherme Maciel Ferreira 	NULL
259a93648d1SGuilherme Maciel Ferreira );
260