amdfwtool: Add universal cleanup function

Change-Id: Icc0cb79c06614aa2976d250dc73b8dc4040fd28c
Signed-off-by: Zheng Bao <fishbaozi@gmail.com>
Reviewed-on: https://review.coreboot.org/c/coreboot/+/73119
Tested-by: build bot (Jenkins) <no-reply@coreboot.org>
Reviewed-by: Fred Reitberger <reitbergerfred@gmail.com>
diff --git a/util/amdfwtool/amdfwtool.c b/util/amdfwtool/amdfwtool.c
index fae0bea..594cc53 100644
--- a/util/amdfwtool/amdfwtool.c
+++ b/util/amdfwtool/amdfwtool.c
@@ -491,12 +491,55 @@
 #define SET_ADDR_MODE_BY_TABLE(table) \
 		SET_ADDR_MODE((table), (table)->header.additional_info_fields.address_mode)
 
+
+static void free_psp_firmware_filenames(amd_fw_entry *fw_table)
+{
+	amd_fw_entry *index;
+
+	for (index = fw_table; index->type != AMD_FW_INVALID; index++) {
+		if (index->filename &&
+				index->type != AMD_FW_VERSTAGE_SIG &&
+				index->type != AMD_FW_PSP_VERSTAGE &&
+				index->type != AMD_FW_SPL &&
+				index->type != AMD_FW_PSP_WHITELIST) {
+			free(index->filename);
+			index->filename = NULL;
+		}
+	}
+}
+
+static void free_bdt_firmware_filenames(amd_bios_entry *fw_table)
+{
+	amd_bios_entry *index;
+
+	for (index = fw_table; index->type != AMD_BIOS_INVALID; index++) {
+		if (index->filename &&
+				index->type != AMD_BIOS_APCB &&
+				index->type != AMD_BIOS_BIN &&
+				index->type != AMD_BIOS_APCB_BK &&
+				index->type != AMD_BIOS_UCODE) {
+			free(index->filename);
+			index->filename = NULL;
+		}
+	}
+}
+
+static void amdfwtool_cleanup(context *ctx)
+{
+	free(ctx->rom);
+	ctx->rom = NULL;
+
+	/* Free the filename. */
+	free_psp_firmware_filenames(amd_psp_fw_table);
+	free_bdt_firmware_filenames(amd_bios_table);
+}
+
 void assert_fw_entry(uint32_t count, uint32_t max, context *ctx)
 {
 	if (count >= max) {
 		fprintf(stderr, "Error: BIOS entries (%d) exceeds max allowed items "
 			"(%d)\n", count, max);
-		free(ctx->rom);
+		amdfwtool_cleanup(ctx);
 		exit(1);
 	}
 }
@@ -506,7 +549,7 @@
 	if (ctx->current_pointer_saved != 0xFFFFFFFF &&
 			ctx->current_pointer_saved != ctx->current) {
 		fprintf(stderr, "Error: The pointer is changed elsewhere\n");
-		free(ctx->rom);
+		amdfwtool_cleanup(ctx);
 		exit(1);
 	}
 
@@ -514,7 +557,7 @@
 
 	if (ctx->current > ctx->rom_size) {
 		fprintf(stderr, "Error: Packing data causes overflow\n");
-		free(ctx->rom);
+		amdfwtool_cleanup(ctx);
 		exit(1);
 	}
 
@@ -609,6 +652,7 @@
 		table_size = ctx->current - ctx->current_table;
 		if ((table_size % TABLE_ALIGNMENT) != 0) {
 			fprintf(stderr, "The PSP table size should be 4K aligned\n");
+			amdfwtool_cleanup(ctx);
 			exit(1);
 		}
 		dir->header.cookie = cookie;
@@ -627,6 +671,7 @@
 		table_size = ctx->current - ctx->current_table;
 		if ((table_size % TABLE_ALIGNMENT) != 0) {
 			fprintf(stderr, "The BIOS table size should be 4K aligned\n");
+			amdfwtool_cleanup(ctx);
 			exit(1);
 		}
 		bdir->header.cookie = cookie;
@@ -897,7 +942,7 @@
 			bytes = copy_blob(BUFF_CURRENT(*ctx),
 					fw_table[i].filename, BUFF_ROOM(*ctx));
 			if (bytes < 0) {
-				free(ctx->rom);
+				amdfwtool_cleanup(ctx);
 				exit(1);
 			}
 
@@ -929,35 +974,6 @@
 	}
 }
 
-static void free_psp_firmware_filenames(amd_fw_entry *fw_table)
-{
-	amd_fw_entry *index;
-
-	for (index = fw_table; index->type != AMD_FW_INVALID; index++) {
-		if (index->filename &&
-				index->type != AMD_FW_VERSTAGE_SIG &&
-				index->type != AMD_FW_PSP_VERSTAGE &&
-				index->type != AMD_FW_SPL &&
-				index->type != AMD_FW_PSP_WHITELIST) {
-			free(index->filename);
-		}
-	}
-}
-
-static void free_bdt_firmware_filenames(amd_bios_entry *fw_table)
-{
-	amd_bios_entry *index;
-
-	for (index = fw_table; index->type != AMD_BIOS_INVALID; index++) {
-		if (index->filename &&
-				index->type != AMD_BIOS_APCB &&
-				index->type != AMD_BIOS_BIN &&
-				index->type != AMD_BIOS_APCB_BK &&
-				index->type != AMD_BIOS_UCODE)
-			free(index->filename);
-	}
-}
-
 static void write_or_fail(int fd, void *ptr, size_t size)
 {
 	ssize_t written;
@@ -1321,6 +1337,7 @@
 				if (addr != ALIGN_UP(addr, ERASE_ALIGNMENT)) {
 					fprintf(stderr,
 						"Error: PSP NVRAM section not aligned with erase block size.\n\n");
+					amdfwtool_cleanup(ctx);
 					exit(1);
 				}
 			} else {
@@ -1328,7 +1345,7 @@
 				bytes = copy_blob(BUFF_CURRENT(*ctx),
 						fw_table[i].filename, BUFF_ROOM(*ctx));
 				if (bytes <= 0) {
-					free(ctx->rom);
+					amdfwtool_cleanup(ctx);
 					exit(1);
 				}
 
@@ -1358,7 +1375,7 @@
 				bytes = copy_blob(BUFF_CURRENT(*ctx),
 						fw_table[i].filename, BUFF_ROOM(*ctx));
 				if (bytes < 0) {
-					free(ctx->rom);
+					amdfwtool_cleanup(ctx);
 					exit(1);
 				}
 				pspdir->entries[count].addr = RUN_CURRENT(*ctx);
@@ -1572,7 +1589,7 @@
 				continue; /* APOB_NV not used */
 			if (fw_table[i].src && !fw_table[i].size) {
 				fprintf(stderr, "Error: APOB NV address provided, but no size\n");
-				free(ctx->rom);
+				amdfwtool_cleanup(ctx);
 				exit(1);
 			}
 			/* If the APOB isn't used, APOB_NV isn't used either */
@@ -1584,7 +1601,7 @@
 		/* APOB_DATA needs destination */
 		if (fw_table[i].type == AMD_BIOS_APOB && !fw_table[i].dest) {
 			fprintf(stderr, "Error: APOB destination not provided\n");
-			free(ctx->rom);
+			amdfwtool_cleanup(ctx);
 			exit(1);
 		}
 
@@ -1594,12 +1611,12 @@
 		if (fw_table[i].type == AMD_BIOS_BIN) {
 			if (!fw_table[i].dest || !fw_table[i].size) {
 				fprintf(stderr, "Error: BIOS binary destination and uncompressed size are required\n");
-				free(ctx->rom);
+				amdfwtool_cleanup(ctx);
 				exit(1);
 			}
 			if (!fw_table[i].filename && !fw_table[i].src) {
 				fprintf(stderr, "Error: BIOS binary assumed outside amdfw.rom but no source address given\n");
-				free(ctx->rom);
+				amdfwtool_cleanup(ctx);
 				exit(1);
 			}
 		}
@@ -1680,7 +1697,7 @@
 			bytes = copy_blob(BUFF_CURRENT(*ctx),
 					fw_table[i].filename, BUFF_ROOM(*ctx));
 			if (bytes <= 0) {
-				free(ctx->rom);
+				amdfwtool_cleanup(ctx);
 				exit(1);
 			}
 
@@ -1703,7 +1720,7 @@
 			bytes = copy_blob(BUFF_CURRENT(*ctx),
 					fw_table[i].filename, BUFF_ROOM(*ctx));
 			if (bytes <= 0) {
-				free(ctx->rom);
+				amdfwtool_cleanup(ctx);
 				exit(1);
 			}
 
@@ -2028,7 +2045,7 @@
 	return 0;
 }
 
-static ssize_t write_efs(char *output, embedded_firmware *amd_romsig)
+static ssize_t write_efs(char *output, embedded_firmware *amd_romsig, context *ctx)
 {
 	char efs_name[PATH_MAX], efs_tmp_name[PATH_MAX];
 	int ret;
@@ -2042,21 +2059,25 @@
 	if (ret < 0) {
 		fprintf(stderr, "Error %s forming EFS tmp file name: %d\n",
 							strerror(errno), ret);
+		amdfwtool_cleanup(ctx);
 		exit(1);
 	} else if ((unsigned int)ret >= sizeof(efs_tmp_name)) {
 		fprintf(stderr, "EFS File name %d  > %zu\n", ret, sizeof(efs_tmp_name));
+		amdfwtool_cleanup(ctx);
 		exit(1);
 	}
 
 	fd = open(efs_tmp_name, O_RDWR | O_CREAT | O_TRUNC, 0666);
 	if (fd < 0) {
 		fprintf(stderr, "Error: Opening %s file: %s\n", efs_tmp_name, strerror(errno));
+		amdfwtool_cleanup(ctx);
 		exit(1);
 	}
 
 	bytes = write_from_buf_to_file(fd, amd_romsig, sizeof(*amd_romsig));
 	if (bytes != sizeof(*amd_romsig)) {
 		fprintf(stderr, "Error: Writing to file %s failed\n", efs_tmp_name);
+		amdfwtool_cleanup(ctx);
 		exit(1);
 	}
 	close(fd);
@@ -2065,11 +2086,13 @@
 	ret = snprintf(efs_name, sizeof(efs_name), "%s%s", output, EFS_FILE_SUFFIX);
 	if (ret < 0) {
 		fprintf(stderr, "Error %s forming EFS file name: %d\n", strerror(errno), ret);
+		amdfwtool_cleanup(ctx);
 		exit(1);
 	}
 
 	if (rename(efs_tmp_name, efs_name)) {
 		fprintf(stderr, "Error: renaming file %s to %s\n", efs_tmp_name, efs_name);
+		amdfwtool_cleanup(ctx);
 		exit(1);
 	}
 
@@ -2637,10 +2660,6 @@
 		}
 	}
 
-	/* Free the filename. */
-	free_psp_firmware_filenames(amd_psp_fw_table);
-	free_bdt_firmware_filenames(amd_bios_table);
-
 	targetfd = open(output, O_RDWR | O_CREAT | O_TRUNC, 0666);
 	if (targetfd >= 0) {
 		ssize_t bytes;
@@ -2660,13 +2679,13 @@
 	if (efs_location != body_location) {
 		ssize_t bytes;
 
-		bytes = write_efs(output, amd_romsig);
+		bytes = write_efs(output, amd_romsig, &ctx);
 		if (bytes != sizeof(*amd_romsig)) {
 			fprintf(stderr, "Error: Writing EFS\n");
 			retval = 1;
 		}
 	}
 
-	free(ctx.rom);
+	amdfwtool_cleanup(&ctx);
 	return retval;
 }