cmd: pxe: add support for FIT config selection

Add a way in configuration files (exlinux.conf for sysboot command)
to select a specific FIT configuration. The configuration is selected
with a string added after the FIT filename in the label "KERNEL" or
"LINUX", using the same format than bootm command:

KERNEL [Filename]#<conf>[#<extra-conf[#...]]

This configuration string, beginning by '#', is directly appended
to bootm argument 1 after <kernel_addr_r>.

bootm [<kernel_addr_r>]#<conf>[#<extra-conf[#...]]

see doc/uImage.FIT/command_syntax_extensions.txt for details

Example :
 KERNEL /fit.itb#cfg1
 KERNEL /fit.itb#cfg2

Configuration can be use also for overlay management :
 KERNEL /fit.itb#cfg1#dtbo1#dtbo3

see doc/uImage.FIT/overlay-fdt-boot.txt for details

Signed-off-by: Patrick Delaunay <patrick.delaunay@st.com>
diff --git a/cmd/pxe.c b/cmd/pxe.c
index 5609545..2745553 100644
--- a/cmd/pxe.c
+++ b/cmd/pxe.c
@@ -471,6 +471,7 @@
 	char *name;
 	char *menu;
 	char *kernel;
+	char *config;
 	char *append;
 	char *initrd;
 	char *fdt;
@@ -538,6 +539,9 @@
 	if (label->kernel)
 		free(label->kernel);
 
+	if (label->config)
+		free(label->config);
+
 	if (label->append)
 		free(label->append);
 
@@ -618,6 +622,7 @@
 	char initrd_str[28];
 	char mac_str[29] = "";
 	char ip_str[68] = "";
+	char *fit_addr = NULL;
 	int bootm_argc = 2;
 	int len = 0;
 	ulong kernel_addr;
@@ -699,6 +704,18 @@
 	}
 
 	bootm_argv[1] = env_get("kernel_addr_r");
+	/* for FIT, append the configuration identifier */
+	if (label->config) {
+		int len = strlen(bootm_argv[1]) + strlen(label->config) + 1;
+
+		fit_addr = malloc(len);
+		if (!fit_addr) {
+			printf("malloc fail (FIT address)\n");
+			return 1;
+		}
+		snprintf(fit_addr, len, "%s%s", bootm_argv[1], label->config);
+		bootm_argv[1] = fit_addr;
+	}
 
 	/*
 	 * fdt usage is optional:
@@ -758,7 +775,7 @@
 			fdtfilefree = malloc(len);
 			if (!fdtfilefree) {
 				printf("malloc fail (FDT filename)\n");
-				return 1;
+				goto cleanup;
 			}
 
 			snprintf(fdtfilefree, len, "%s%s%s%s%s%s",
@@ -772,7 +789,7 @@
 			if (err < 0) {
 				printf("Skipping %s for failure retrieving fdt\n",
 						label->name);
-				return 1;
+				goto cleanup;
 			}
 		} else {
 			bootm_argv[3] = NULL;
@@ -803,6 +820,10 @@
 		do_bootz(cmdtp, 0, bootm_argc, bootm_argv);
 #endif
 	unmap_sysmem(buf);
+
+cleanup:
+	if (fit_addr)
+		free(fit_addr);
 	return 1;
 }
 
@@ -1188,6 +1209,33 @@
 }
 
 /*
+ * Handles parsing a 'kernel' label.
+ * expecting "filename" or "<fit_filename>#cfg"
+ */
+static int parse_label_kernel(char **c, struct pxe_label *label)
+{
+	char *s;
+	int err;
+
+	err = parse_sliteral(c, &label->kernel);
+	if (err < 0)
+		return err;
+
+	s = strstr(label->kernel, "#");
+	if (!s)
+		return 1;
+
+	label->config = malloc(strlen(s) + 1);
+	if (!label->config)
+		return -ENOMEM;
+
+	strcpy(label->config, s);
+	*s = 0;
+
+	return 1;
+}
+
+/*
  * Parses a label and adds it to the list of labels for a menu.
  *
  * A label ends when we either get to the end of a file, or
@@ -1228,7 +1276,7 @@
 
 		case T_KERNEL:
 		case T_LINUX:
-			err = parse_sliteral(c, &label->kernel);
+			err = parse_label_kernel(c, label);
 			break;
 
 		case T_APPEND: