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