sconfig: Split up sconfig-generated static.h

Currently sconfig generates a `static.h` to accompany
`static.c`. However, some payloads may decide they would like to consume
the FW_CONFIG macros as well. The current state of `static.h` makes this
impossible (relying on `device/device.h`).

This patch splits up `static.h` into 3 files: `static.h,
`static_devices.h`, and `static_fw_config.h`. `static.h` simply includes
the other two `.h` files to ensure no changes are needed to other
code. `static_devices.h` contains the extern'd definitions of the device
names recently introduced to sconfig.  `static_fw_config.h` contains the
FW_CONFIG_FIELD_* macros only, which makes it easily consumable by a
payload which wishes to use FW_CONFIG.

Also refactor the generation of all these output files, as the code was
getting messy.

Change-Id: Ie0f4520ee055528c7be84d1d1e2dcea113ea8b5f
Signed-off-by: Tim Wawrzynczak <twawrzynczak@chromium.org>
Reviewed-on: https://review.coreboot.org/c/coreboot/+/45667
Tested-by: build bot (Jenkins) <no-reply@coreboot.org>
Reviewed-by: Furquan Shaikh <furquan@google.com>
Reviewed-by: Nick Vaccaro <nvaccaro@google.com>
diff --git a/Makefile.inc b/Makefile.inc
index 297f7b1..a6418b1 100644
--- a/Makefile.inc
+++ b/Makefile.inc
@@ -611,6 +611,12 @@
 DEVICETREE_STATIC_H := $(obj)/static.h
 SCONFIG_OPTIONS += --output_h=$(DEVICETREE_STATIC_H)
 
+DEVICETREE_DEVICENAMES_H := $(obj)/static_devices.h
+SCONFIG_OPTIONS += --output_d=$(DEVICETREE_DEVICENAMES_H)
+
+DEVICETREE_FWCONFIG_H := $(obj)/static_fw_config.h
+SCONFIG_OPTIONS += --output_f=$(DEVICETREE_FWCONFIG_H)
+
 $(DEVICETREE_STATIC_C): $(DEVICETREE_FILE) $(OVERRIDE_DEVICETREE_FILE) $(CHIPSET_DEVICETREE_FILE) $(objutil)/sconfig/sconfig
 	@printf "    SCONFIG    $(subst $(src)/,,$(<))\n"
 	mkdir -p $(dir $(DEVICETREE_STATIC_C))
diff --git a/util/sconfig/main.c b/util/sconfig/main.c
index bff7215..4f13293 100644
--- a/util/sconfig/main.c
+++ b/util/sconfig/main.c
@@ -1,9 +1,11 @@
 /* sconfig, coreboot device tree compiler */
 /* SPDX-License-Identifier: GPL-2.0-only */
 
+#include <assert.h>
 #include <ctype.h>
 #include <getopt.h>
 /* stat.h needs to be included before commonlib/helpers.h to avoid errors.*/
+#include <libgen.h>
 #include <sys/stat.h>
 #include <commonlib/helpers.h>
 #include <stdint.h>
@@ -528,9 +530,6 @@
 	if (!field)
 		return;
 
-	fprintf(fil, "\n/* firmware configuration */\n");
-	fprintf(fil, "#include <fw_config.h>\n");
-
 	while (field) {
 		struct fw_config_option *option = field->options;
 		uint32_t mask;
@@ -1094,7 +1093,8 @@
 
 	/* Emit probe structures. */
 	if (ptr->probe && (emit_fw_config_probe(fil, ptr) < 0)) {
-		fclose(head);
+		if (head)
+			fclose(head);
 		fclose(fil);
 		exit(1);
 	}
@@ -1355,9 +1355,12 @@
 	printf("usage: sconfig <options>\n");
 	printf("  -c | --output_c          : Path to output static.c file (required)\n");
 	printf("  -r | --output_h          : Path to header static.h file (required)\n");
+	printf("  -d | --output_d          : Path to header static_devices.h file (required)\n");
+	printf("  -f | --output_f          : Path to header static_fw_config.h file (required)\n");
 	printf("  -m | --mainboard_devtree : Path to mainboard devicetree file (required)\n");
 	printf("  -o | --override_devtree  : Path to override devicetree file (optional)\n");
 	printf("  -p | --chipset_devtree   : Path to chipset/SOC devicetree file (optional)\n");
+
 	exit(1);
 }
 
@@ -1721,6 +1724,54 @@
 	override_devicetree(&base_root_bus, dev->bus);
 }
 
+static void generate_outputh(FILE *f, const char *fw_conf_header, const char *device_header)
+{
+	fprintf(f, "#ifndef __STATIC_DEVICE_TREE_H\n");
+	fprintf(f, "#define __STATIC_DEVICE_TREE_H\n\n");
+
+	fprintf(f, "#include <%s>\n", fw_conf_header);
+	fprintf(f, "#include <%s>\n\n", device_header);
+
+	fprintf(f, "\n#endif /* __STATIC_DEVICE_TREE_H */\n");
+}
+
+static void generate_outputc(FILE *f, const char *static_header)
+{
+	fprintf(f, "#include <device/device.h>\n");
+	fprintf(f, "#include <device/pci.h>\n");
+	fprintf(f, "#include <fw_config.h>\n");
+	fprintf(f, "#include <%s>\n", static_header);
+	emit_chip_headers(f, chip_header.next);
+	fprintf(f, "\n#define STORAGE static __unused DEVTREE_CONST\n\n");
+
+	walk_device_tree(NULL, NULL, &base_root_dev, inherit_subsystem_ids);
+	fprintf(f, "\n/* pass 0 */\n");
+	walk_device_tree(f, NULL, &base_root_dev, pass0);
+	walk_device_tree(NULL, NULL, &base_root_dev, update_references);
+	fprintf(f, "\n/* chip configs */\n");
+	emit_chip_configs(f);
+	fprintf(f, "\n/* pass 1 */\n");
+	walk_device_tree(f, NULL, &base_root_dev, pass1);
+}
+
+static void generate_outputd(FILE *gen, FILE *dev)
+{
+	fprintf(dev, "#ifndef __STATIC_DEVICES_H\n");
+	fprintf(dev, "#define __STATIC_DEVICES_H\n\n");
+	fprintf(dev, "#include <device/device.h>\n\n");
+	fprintf(dev, "/* expose_device_names */\n");
+	walk_device_tree(gen, dev, &base_root_dev, expose_device_names);
+	fprintf(dev, "\n#endif /* __STATIC_DEVICE_NAMES_H */\n");
+}
+
+static void generate_outputf(FILE *f)
+{
+	fprintf(f, "#ifndef __STATIC_FW_CONFIG_H\n");
+	fprintf(f, "#define __STATIC_FW_CONFIG_H\n\n");
+	emit_fw_config(f);
+	fprintf(f, "\n#endif /* __STATIC_FW_CONFIG_H */\n");
+}
+
 int main(int argc, char **argv)
 {
 	static const struct option long_options[] = {
@@ -1729,6 +1780,8 @@
 		{ "chipset_devtree", 1, NULL, 'p' },
 		{ "output_c", 1, NULL, 'c' },
 		{ "output_h", 1, NULL, 'r' },
+		{ "output_d", 1, NULL, 'd' },
+		{ "output_f", 1, NULL, 'f' },
 		{ "help", 1, NULL, 'h' },
 		{ }
 	};
@@ -1737,9 +1790,11 @@
 	const char *chipset_devtree = NULL;
 	const char *outputc = NULL;
 	const char *outputh = NULL;
+	const char *outputd = NULL;
+	const char *outputf = NULL;
 	int opt, option_index;
 
-	while ((opt = getopt_long(argc, argv, "m:o:p:c:r:h", long_options,
+	while ((opt = getopt_long(argc, argv, "m:o:p:c:r:d:f:h", long_options,
 				  &option_index)) != EOF) {
 		switch (opt) {
 		case 'm':
@@ -1757,13 +1812,19 @@
 		case 'r':
 			outputh = strdup(optarg);
 			break;
+		case 'd':
+			outputd = strdup(optarg);
+			break;
+		case 'f':
+			outputf = strdup(optarg);
+			break;
 		case 'h':
 		default:
 			usage();
 		}
 	}
 
-	if (!base_devtree || !outputc || !outputh)
+	if (!base_devtree || !outputc || !outputh || !outputd || !outputf)
 		usage();
 
 	if (chipset_devtree) {
@@ -1793,33 +1854,49 @@
 		fclose(autogen);
 		exit(1);
 	}
-	fprintf(autohead, "#ifndef __STATIC_DEVICE_TREE_H\n");
-	fprintf(autohead, "#define __STATIC_DEVICE_TREE_H\n\n");
-	fprintf(autohead, "#include <device/device.h>\n\n");
-	emit_fw_config(autohead);
 
-	fprintf(autogen, "#include <device/device.h>\n");
-	fprintf(autogen, "#include <device/pci.h>\n\n");
-	fprintf(autogen, "#include <static.h>\n");
-	emit_chip_headers(autogen, chip_header.next);
-	fprintf(autogen, "\n#define STORAGE static __unused DEVTREE_CONST\n\n");
+	FILE *autodev = fopen(outputd, "w");
+	if (!autodev) {
+		fprintf(stderr, "Could not open file '%s' for writing: ", outputd);
+		perror(NULL);
+		fclose(autogen);
+		fclose(autohead);
+		exit(1);
+	}
 
-	walk_device_tree(autogen, autohead, &base_root_dev, inherit_subsystem_ids);
-	fprintf(autogen, "\n/* pass 0 */\n");
-	walk_device_tree(autogen, autohead, &base_root_dev, pass0);
-	walk_device_tree(autogen, autohead, &base_root_dev, update_references);
-	fprintf(autogen, "\n/* chip configs */\n");
-	emit_chip_configs(autogen);
-	fprintf(autogen, "\n/* pass 1 */\n");
-	walk_device_tree(autogen, autohead, &base_root_dev, pass1);
+	FILE *autofwconf = fopen(outputf, "w");
+	if (!autofwconf) {
+		fprintf(stderr, "Could not open file '%s' for writing: ", outputf);
+		perror(NULL);
+		fclose(autogen);
+		fclose(autohead);
+		fclose(autodev);
+		exit(1);
+	}
 
-	/* Expose static devicenames to global namespace. */
-	fprintf(autogen, "\n/* expose_device_names */\n");
-	walk_device_tree(autogen, autohead, &base_root_dev, expose_device_names);
+	char *f = strdup(outputf);
+	assert(f);
+	char *d = strdup(outputd);
+	assert(d);
+	char *h = strdup(outputh);
+	assert(h);
 
-	fprintf(autohead, "\n#endif /* __STATIC_DEVICE_TREE_H */\n");
+	const char *fw_conf_header = basename(f);
+	const char *device_header = basename(d);
+	const char *static_header = basename(h);
+
+	generate_outputh(autohead, fw_conf_header, device_header);
+	generate_outputc(autogen, static_header);
+	generate_outputd(autogen, autodev);
+	generate_outputf(autofwconf);
+
 	fclose(autohead);
 	fclose(autogen);
+	fclose(autodev);
+	fclose(autofwconf);
+	free(f);
+	free(d);
+	free(h);
 
 	return 0;
 }