util/kconfig: Uprev to Linux 5.16's kconfig

Linux 5.16 saw a significant rewrite in the boolean handling which
reduces our change set. On the other hand, it's all new code.

Comparing the config.build and config.h files generated by
`util/abuild/abuild -C`, only a few lines of comment in the header
changed.

Change-Id: I52984e15a48236ddf228707aec85e90f71aa4382
Signed-off-by: Patrick Georgi <patrick@coreboot.org>
Reviewed-on: https://review.coreboot.org/c/coreboot/+/66045
Tested-by: build bot (Jenkins) <no-reply@coreboot.org>
Reviewed-by: Elyes Haouas <ehaouas@noos.fr>
diff --git a/util/kconfig/conf.c b/util/kconfig/conf.c
index bc7b2f6..5637559 100644
--- a/util/kconfig/conf.c
+++ b/util/kconfig/conf.c
@@ -648,19 +648,8 @@
 
 		switch (input_mode) {
 		case listnewconfig:
-			if (sym->name) {
-				const char *str;
-
-				if (sym->type == S_STRING) {
-					str = sym_get_string_value(sym);
-					str = sym_escape_string_value(str);
-					printf("%s%s=%s\n", CONFIG_, sym->name, str);
-					free((void *)str);
-				} else {
-					str = sym_get_string_value(sym);
-					printf("%s%s=%s\n", CONFIG_, sym->name, str);
-				}
-			}
+			if (sym->name)
+				print_symbol_for_listconfig(sym);
 			break;
 		case helpnewconfig:
 			printf("-----\n");
diff --git a/util/kconfig/confdata.c b/util/kconfig/confdata.c
index 24759dc..de421e0 100644
--- a/util/kconfig/confdata.c
+++ b/util/kconfig/confdata.c
@@ -11,6 +11,7 @@
 #include <fcntl.h>
 #include <limits.h>
 #include <stdarg.h>
+#include <stdbool.h>
 #include <stdio.h>
 #include <stdlib.h>
 #include <string.h>
@@ -129,45 +130,22 @@
 /* touch depfile for symbol 'name' */
 static int conf_touch_dep(const char *name)
 {
-	int fd, ret;
-	char *d;
+	int fd;
 
 	/* check overflow: prefix + name + '\0' must fit in buffer. */
 	if (depfile_prefix_len + strlen(name) + 1 > sizeof(depfile_path))
 		return -1;
 
-	d = depfile_path + depfile_prefix_len;
-	strcpy(d, name);
+	strcpy(depfile_path + depfile_prefix_len, name);
 
-	/* Assume directory path already exists. */
 	fd = open(depfile_path, O_WRONLY | O_CREAT | O_TRUNC, 0644);
-	if (fd == -1) {
-		if (errno != ENOENT)
-			return -1;
-
-		ret = make_parent_dir(depfile_path);
-		if (ret)
-			return ret;
-
-		/* Try it again. */
-		fd = open(depfile_path, O_WRONLY | O_CREAT | O_TRUNC, 0644);
-		if (fd == -1)
-			return -1;
-	}
+	if (fd == -1)
+		return -1;
 	close(fd);
 
 	return 0;
 }
 
-struct conf_printer {
-	void (*print_symbol)(FILE *, struct symbol *, const char *, void *);
-	void (*print_comment)(FILE *, const char *, void *);
-};
-
-#ifdef __MINGW32__
-#define mkdir(_n,_p) mkdir((_n))
-#endif
-
 static void conf_warning(const char *fmt, ...)
 	__attribute__ ((format (printf, 1, 2)));
 
@@ -177,6 +155,10 @@
 static const char *conf_filename;
 static int conf_lineno, conf_warnings;
 
+#ifdef __MINGW32__
+#define mkdir(_n,_p) mkdir((_n))
+#endif
+
 static void conf_warning(const char *fmt, ...)
 {
 	va_list ap;
@@ -241,6 +223,13 @@
 	return name ? name : "include/config/auto.conf";
 }
 
+static const char *conf_get_autoheader_name(void)
+{
+	char *name = getenv("KCONFIG_AUTOHEADER");
+
+	return name ? name : "include/generated/autoconf.h";
+}
+
 static const char *conf_get_autobase_name(void)
 {
 	char *name = getenv("KCONFIG_SPLITCONFIG");
@@ -621,186 +610,186 @@
 	return 0;
 }
 
+struct comment_style {
+	const char *decoration;
+	const char *prefix;
+	const char *postfix;
+};
+
+static const struct comment_style comment_style_pound = {
+	.decoration = "#",
+	.prefix = "#",
+	.postfix = "#",
+};
+
+static const struct comment_style comment_style_c = {
+	.decoration = " *",
+	.prefix = "/*",
+	.postfix = " */",
+};
+
+static void conf_write_heading(FILE *fp, const struct comment_style *cs)
+{
+	fprintf(fp, "%s\n", cs->prefix);
+
+	fprintf(fp, "%s Automatically generated file; DO NOT EDIT.\n",
+		cs->decoration);
+
+	fprintf(fp, "%s %s\n", cs->decoration, rootmenu.prompt->text);
+
+	fprintf(fp, "%s\n", cs->postfix);
+}
+
+/* The returned pointer must be freed on the caller side */
+static char *escape_string_value(const char *in)
+{
+	const char *p;
+	char *out;
+	size_t len;
+
+	len = strlen(in) + strlen("\"\"") + 1;
+
+	p = in;
+	while (1) {
+		p += strcspn(p, "\"\\");
+
+		if (p[0] == '\0')
+			break;
+
+		len++;
+		p++;
+	}
+
+	out = xmalloc(len);
+	out[0] = '\0';
+
+	strcat(out, "\"");
+
+	p = in;
+	while (1) {
+		len = strcspn(p, "\"\\");
+		strncat(out, p, len);
+		p += len;
+
+		if (p[0] == '\0')
+			break;
+
+		strcat(out, "\\");
+		strncat(out, p++, 1);
+	}
+
+	strcat(out, "\"");
+
+	return out;
+}
+
 /*
  * Kconfig configuration printer
  *
  * This printer is used when generating the resulting configuration after
  * kconfig invocation and `defconfig' files. Unset symbol might be omitted by
  * passing a non-NULL argument to the printer.
- *
  */
-static void
-kconfig_print_symbol(FILE *fp, struct symbol *sym, const char *value, void *arg)
+enum output_n { OUTPUT_N, OUTPUT_N_AS_UNSET, OUTPUT_N_NONE };
+
+static void __print_symbol(FILE *fp, struct symbol *sym, enum output_n output_n,
+			   bool escape_string)
 {
+	const char *val;
+	char *escaped = NULL;
+
+	if (sym->type == S_UNKNOWN)
+		return;
+
+	val = sym_get_string_value(sym);
+
+	if ((sym->type == S_BOOLEAN || sym->type == S_TRISTATE) &&
+	    output_n != OUTPUT_N && *val == 'n') {
+		if (output_n == OUTPUT_N_AS_UNSET)
+			fprintf(fp, "# %s%s is not set\n", CONFIG_, sym->name);
+		return;
+	}
+
+	if (sym->type == S_STRING && escape_string) {
+		escaped = escape_string_value(val);
+		val = escaped;
+	}
+
+	fprintf(fp, "%s%s=%s\n", CONFIG_, sym->name, val);
+
+	free(escaped);
+}
+
+static void print_symbol_for_dotconfig(FILE *fp, struct symbol *sym)
+{
+	__print_symbol(fp, sym, OUTPUT_N_AS_UNSET, true);
+}
+
+static void print_symbol_for_autoconf(FILE *fp, struct symbol *sym)
+{
+	int print_negatives = getenv("KCONFIG_NEGATIVES") != NULL;
+	enum output_n out = OUTPUT_N_NONE;
+	if (print_negatives) {
+		out = OUTPUT_N;
+	}
+	__print_symbol(fp, sym, out, true);
+}
+
+void print_symbol_for_listconfig(struct symbol *sym)
+{
+	__print_symbol(stdout, sym, OUTPUT_N, true);
+}
+
+static void print_symbol_for_c(FILE *fp, struct symbol *sym)
+{
+	const char *val;
+	const char *sym_suffix = "";
+	const char *val_prefix = "";
+	char *escaped = NULL;
+
+	if (sym->type == S_UNKNOWN)
+		return;
+
+	val = sym_get_string_value(sym);
 
 	switch (sym->type) {
 	case S_BOOLEAN:
 	case S_TRISTATE:
-		if (*value == 'n') {
-			bool skip_unset = (arg != NULL);
-
-			if (!skip_unset)
-				fprintf(fp, "# %s%s is not set\n",
-				    CONFIG_, sym->name);
-			return;
-		}
-		break;
-	default:
-		break;
-	}
-
-	fprintf(fp, "%s%s=%s\n", CONFIG_, sym->name, value);
-}
-
-static void
-kconfig_print_comment(FILE *fp, const char *value, void *arg)
-{
-	const char *p = value;
-	size_t l;
-
-	for (;;) {
-		l = strcspn(p, "\n");
-		fprintf(fp, "#");
-		if (l) {
-			fprintf(fp, " ");
-			xfwrite(p, l, 1, fp);
-			p += l;
-		}
-		fprintf(fp, "\n");
-		if (*p++ == '\0')
-			break;
-	}
-}
-
-static struct conf_printer kconfig_printer_cb =
-{
-	.print_symbol = kconfig_print_symbol,
-	.print_comment = kconfig_print_comment,
-};
-
-/*
- * Header printer
- *
- * This printer is used when generating the `include/generated/autoconf.h' file.
- */
-static void
-header_print_symbol(FILE *fp, struct symbol *sym, const char *value, void *arg)
-{
-
-	switch (sym->type) {
-	case S_BOOLEAN:
-	case S_TRISTATE: {
-		const char *suffix = "";
-
-		switch (*value) {
+		switch (*val) {
 		case 'n':
-			if (getenv("KCONFIG_NEGATIVES") != NULL)
-				fprintf(fp, "#define %s%s%s 0\n",
-				    CONFIG_, sym->name, suffix);
-			break;
+			if (getenv("KCONFIG_NEGATIVES") != NULL) {
+				val = "0";
+				break;
+			}
+			return;
 		case 'm':
-			suffix = "_MODULE";
+			sym_suffix = "_MODULE";
 			/* fall through */
 		default:
-			fprintf(fp, "#define %s%s%s 1\n",
-			    CONFIG_, sym->name, suffix);
+			val = "1";
 		}
 		break;
-	}
-	case S_HEX: {
-		const char *prefix = "";
-
-		if (value[0] != '0' || (value[1] != 'x' && value[1] != 'X'))
-			prefix = "0x";
-		if (value[0] == '\0') {
-			/*
-			 * prefix is reset to remain closer to the older
-			 * coreboot patch. No need to keep this once kconfig
-			 * is fully upreved
-			 */
-			prefix = "";
-			value = "0";
-		}
-		fprintf(fp, "#define %s%s %s%s\n",
-		    CONFIG_, sym->name, prefix, value);
-		break;
-	}
-	case S_STRING:
-		if (value[0] == '\0')
-			break;
-		if (!(sym->flags & SYMBOL_WRITE))
-			break;
+	case S_HEX:
+		if (val[0] != '0' || (val[1] != 'x' && val[1] != 'X'))
+			val_prefix = "0x";
 		/* fall through */
 	case S_INT:
-		fprintf(fp, "#define %s%s %s\n",
-		    CONFIG_, sym->name, value[0]?value:"0");
-		break;
-	default:
-		break;
-	}
-
-}
-
-static void
-header_print_comment(FILE *fp, const char *value, void *arg)
-{
-	const char *p = value;
-	size_t l;
-
-	fprintf(fp, "/*\n");
-	for (;;) {
-		l = strcspn(p, "\n");
-		fprintf(fp, " *");
-		if (l) {
-			fprintf(fp, " ");
-			xfwrite(p, l, 1, fp);
-			p += l;
+		if (val[0] == '\0') {
+			val = "0";
+			val_prefix = "";
 		}
-		fprintf(fp, "\n");
-		if (*p++ == '\0')
-			break;
-	}
-	fprintf(fp, " */\n");
-}
-
-static struct conf_printer header_printer_cb =
-{
-	.print_symbol = header_print_symbol,
-	.print_comment = header_print_comment,
-};
-
-static void conf_write_symbol(FILE *fp, struct symbol *sym,
-			      struct conf_printer *printer, void *printer_arg)
-{
-	const char *str;
-
-	switch (sym->type) {
-	case S_UNKNOWN:
 		break;
 	case S_STRING:
-		str = sym_get_string_value(sym);
-		str = sym_escape_string_value(str);
-		printer->print_symbol(fp, sym, str, printer_arg);
-		free((void *)str);
-		break;
+		escaped = escape_string_value(val);
+		val = escaped;
 	default:
-		str = sym_get_string_value(sym);
-		printer->print_symbol(fp, sym, str, printer_arg);
+		break;
 	}
-}
 
-static void
-conf_write_heading(FILE *fp, struct conf_printer *printer, void *printer_arg)
-{
-	char buf[256];
+	fprintf(fp, "#define %s%s%s %s%s\n", CONFIG_, sym->name, sym_suffix,
+		val_prefix, val);
 
-	snprintf(buf, sizeof(buf),
-	    "\n"
-	    "Automatically generated file; DO NOT EDIT.\n"
-	    "%s\n",
-	    rootmenu.prompt->text);
-
-	printer->print_comment(fp, buf, printer_arg);
+	free(escaped);
 }
 
 /*
@@ -859,7 +848,7 @@
 						goto next_menu;
 				}
 			}
-			conf_write_symbol(out, sym, &kconfig_printer_cb, NULL);
+			print_symbol_for_dotconfig(out, sym);
 		}
 next_menu:
 		if (menu->list != NULL) {
@@ -880,16 +869,6 @@
 	return 0;
 }
 
-
-static int conf_mktemp(const char *path, char *tmpfile)
-{
-	if (snprintf(tmpfile, PATH_MAX, "%s.tmp.XXXXXX", path) >= PATH_MAX) {
-		errno = EOVERFLOW;
-		return -1;
-	}
-	return mkstemp(tmpfile);
-}
-
 int conf_write(const char *name)
 {
 	FILE *out;
@@ -929,7 +908,7 @@
 	if (!out)
 		return 1;
 
-	conf_write_heading(out, &kconfig_printer_cb, NULL);
+	conf_write_heading(out, &comment_style_pound);
 
 	if (!conf_get_changed())
 		sym_clear_all_valid();
@@ -956,7 +935,7 @@
 				need_newline = false;
 			}
 			sym->flags |= SYMBOL_WRITTEN;
-			conf_write_symbol(out, sym, &kconfig_printer_cb, NULL);
+			print_symbol_for_dotconfig(out, sym);
 		}
 
 next:
@@ -1006,37 +985,50 @@
 }
 
 /* write a dependency file as used by kbuild to track dependencies */
-static int conf_write_dep(const char *name)
+static int conf_write_autoconf_cmd(const char *autoconf_name)
 {
+	char name[PATH_MAX], tmp[PATH_MAX];
 	struct file *file;
 	FILE *out;
+	int ret;
+
+	ret = snprintf(name, sizeof(name), "%s.cmd", autoconf_name);
+	if (ret >= sizeof(name)) /* check truncation */
+		return -1;
 
 	if (make_parent_dir(name))
-		return 1;
-	char filename[PATH_MAX];
-	int fd = conf_mktemp(name, filename);
-	if (fd == -1)
-		return 1;
+		return -1;
 
-	out = fdopen(fd, "w");
-	if (!out)
-		return 1;
-	fprintf(out, "deps_config := \\\n");
-	for (file = file_list; file; file = file->next) {
-		if (file->next)
-			fprintf(out, "\t%s \\\n", file->name);
-		else
-			fprintf(out, "\t%s\n", file->name);
+	ret = snprintf(tmp, sizeof(tmp), "%s.cmd.tmp", autoconf_name);
+	if (ret >= sizeof(tmp)) /* check truncation */
+		return -1;
+
+	out = fopen(tmp, "w");
+	if (!out) {
+		perror("fopen");
+		return -1;
 	}
-	fprintf(out, "\n%s: \\\n"
-		     "\t$(deps_config)\n\n", conf_get_autoconfig_name());
 
-	env_write_dep(out, conf_get_autoconfig_name());
+	fprintf(out, "deps_config := \\\n");
+	for (file = file_list; file; file = file->next)
+		fprintf(out, "\t%s \\\n", file->name);
+
+	fprintf(out, "\n%s: $(deps_config)\n\n", autoconf_name);
+
+	env_write_dep(out, autoconf_name);
 
 	fprintf(out, "\n$(deps_config): ;\n");
+
+	if (ferror(out)) /* error check for all fprintf() calls */
+		return -1;
+
 	fclose(out);
 
-	rename(filename, name);
+	if (rename(tmp, name)) {
+		perror("rename");
+		return -1;
+	}
+
 	return 0;
 }
 
@@ -1112,77 +1104,84 @@
 	return 0;
 }
 
+static int __conf_write_autoconf(const char *filename,
+				 void (*print_symbol)(FILE *, struct symbol *),
+				 const struct comment_style *comment_style)
+{
+	char tmp[PATH_MAX];
+	FILE *file;
+	struct symbol *sym;
+	int ret, i;
+
+	if (make_parent_dir(filename))
+		return -1;
+
+	ret = snprintf(tmp, sizeof(tmp), "%s.tmp", filename);
+	if (ret >= sizeof(tmp)) /* check truncation */
+		return -1;
+
+	file = fopen(tmp, "w");
+	if (!file) {
+		perror("fopen");
+		return -1;
+	}
+
+	conf_write_heading(file, comment_style);
+
+	int print_negatives = getenv("KCONFIG_NEGATIVES") != NULL;
+	for_all_symbols(i, sym)
+		if (((sym->flags & SYMBOL_WRITE) || (print_negatives && sym->type != S_STRING)) && sym->name)
+			print_symbol(file, sym);
+
+	/* check possible errors in conf_write_heading() and print_symbol() */
+	if (ferror(file))
+		return -1;
+
+	fclose(file);
+
+	if (rename(tmp, filename)) {
+		perror("rename");
+		return -1;
+	}
+
+	return 0;
+}
+
 int conf_write_autoconf(int overwrite)
 {
 	struct symbol *sym;
-	const char *name;
 	const char *autoconf_name = conf_get_autoconfig_name();
-	FILE *out, *out_h;
-	int i;
-	int print_negatives = getenv("KCONFIG_NEGATIVES") != NULL;
+	int ret, i;
 
 	if (!overwrite && is_present(autoconf_name))
 		return 0;
 
-	char autoconfcmd_path[PATH_MAX];
-	snprintf(autoconfcmd_path, sizeof(autoconfcmd_path), "%s%s",
-		conf_get_autobase_name(), "auto.conf.cmd");
-	conf_write_dep(autoconfcmd_path);
+	ret = conf_write_autoconf_cmd(autoconf_name);
+	if (ret)
+		return -1;
 
 	if (conf_touch_deps())
 		return 1;
 
-	if (make_parent_dir(autoconf_name))
-		return 1;
-	char filename[PATH_MAX];
-	int fd = conf_mktemp(autoconf_name, filename);
-	if (fd == -1)
-		return 1;
-	out = fdopen(fd, "w");
-	if (!out)
-		return 1;
-
-	name = getenv("KCONFIG_AUTOHEADER");
-	if (!name)
-		name = "include/generated/autoconf.h";
-	if (make_parent_dir(name))
-		return 1;
-	char filename_h[PATH_MAX];
-	int fd_h = conf_mktemp(name, filename_h);
-	if (fd_h == -1)
-		return 1;
-	out_h = fdopen(fd_h, "w");
-	if (!out_h) {
-		fclose(out);
-		return 1;
-	}
-
-	conf_write_heading(out, &kconfig_printer_cb, NULL);
-	conf_write_heading(out_h, &header_printer_cb, NULL);
-
-	for_all_symbols(i, sym) {
+	for_all_symbols(i, sym)
 		sym_calc_value(sym);
-		if (!(sym->flags & SYMBOL_WRITE) && !print_negatives)
-			continue;
-		if (!sym->name)
-			continue;
 
-		/* write symbols to auto.conf and autoconf.h */
-		conf_write_symbol(out, sym, &kconfig_printer_cb, print_negatives?NULL:(void *)1);
-		conf_write_symbol(out_h, sym, &header_printer_cb, NULL);
-	}
-	fclose(out);
-	fclose(out_h);
-
-	if (rename(filename_h, name))
-		return 1;
+	ret = __conf_write_autoconf(conf_get_autoheader_name(),
+				    print_symbol_for_c,
+				    &comment_style_c);
+	if (ret)
+		return ret;
 
 	/*
-	 * This must be the last step, kbuild has a dependency on auto.conf
-	 * and this marks the successful completion of the previous steps.
+	 * Create include/config/auto.conf. This must be the last step because
+	 * Kbuild has a dependency on auto.conf and this marks the successful
+	 * completion of the previous steps.
 	 */
-	if (rename(filename, autoconf_name))
-		return 1;
+	ret = __conf_write_autoconf(conf_get_autoconfig_name(),
+				    print_symbol_for_autoconf,
+				    &comment_style_pound);
+	if (ret)
+		return ret;
 
 	return 0;
 }
diff --git a/util/kconfig/lexer.l b/util/kconfig/lexer.l
index dcb5648..2a754a8 100644
--- a/util/kconfig/lexer.l
+++ b/util/kconfig/lexer.l
@@ -85,8 +85,7 @@
 n	[A-Za-z0-9_-]
 
 %%
-	int str = 0;
-	int ts, i;
+	char open_quote = 0;
 
 #.*			/* ignore comment */
 [ \t]*			/* whitespaces */
@@ -135,7 +134,7 @@
 ":="			return T_COLON_EQUAL;
 "+="			return T_PLUS_EQUAL;
 \"|\'			{
-				str = yytext[0];
+				open_quote = yytext[0];
 				new_string();
 				BEGIN(STRING);
 			}
@@ -172,7 +171,7 @@
 		append_string(yytext + 1, yyleng - 1);
 	}
 	\'|\"	{
-		if (str == yytext[0]) {
+		if (open_quote == yytext[0]) {
 			BEGIN(INITIAL);
 			yylval.string = text;
 			return T_WORD_QUOTE;
@@ -197,6 +196,8 @@
 
 <HELP>{
 	[ \t]+	{
+		int ts, i;
+
 		ts = 0;
 		for (i = 0; i < yyleng; i++) {
 			if (yytext[i] == '\t')
diff --git a/util/kconfig/lkc_proto.h b/util/kconfig/lkc_proto.h
index a11626b..edd1e61 100644
--- a/util/kconfig/lkc_proto.h
+++ b/util/kconfig/lkc_proto.h
@@ -18,7 +18,7 @@
 
 struct symbol * sym_lookup(const char *name, int flags);
 struct symbol * sym_find(const char *name);
-const char * sym_escape_string_value(const char *in);
+void print_symbol_for_listconfig(struct symbol *sym);
 struct symbol ** sym_re_search(const char *pattern);
 const char * sym_type_name(enum symbol_type type);
 void sym_calc_value(struct symbol *sym);
diff --git a/util/kconfig/menu.c b/util/kconfig/menu.c
index 606ba8a..3d6f7cb 100644
--- a/util/kconfig/menu.c
+++ b/util/kconfig/menu.c
@@ -728,7 +728,7 @@
 		get_dep_str(r, prop->visible.expr, "  Visible if: ");
 
 	menu = prop->menu->parent;
-	for (i = 0; menu != &rootmenu && i < 8; menu = menu->parent) {
+	for (i = 0; menu && i < 8; menu = menu->parent) {
 		bool accessible = menu_is_visible(menu);
 
 		submenu[i++] = menu;
@@ -758,21 +758,24 @@
 		list_add_tail(&jump->entries, head);
 	}
 
-	if (i > 0) {
-		str_printf(r, "  Location:\n");
-		for (j = 4; --i >= 0; j += 2) {
-			menu = submenu[i];
-			if (jump && menu == location)
-				jump->offset = strlen(r->s);
-			str_printf(r, "%*c-> %s", j, ' ',
-				   menu_get_prompt(menu));
-			if (menu->sym) {
-				str_printf(r, " (%s [=%s])", menu->sym->name ?
-					menu->sym->name : "<choice>",
-					sym_get_string_value(menu->sym));
-			}
-			str_append(r, "\n");
+	str_printf(r, "  Location:\n");
+	for (j = 4; --i >= 0; j += 2) {
+		menu = submenu[i];
+		if (jump && menu == location)
+			jump->offset = strlen(r->s);
+
+		if (menu == &rootmenu)
+			/* The real rootmenu prompt is ugly */
+			str_printf(r, "%*cMain menu", j, ' ');
+		else
+			str_printf(r, "%*c-> %s", j, ' ', menu_get_prompt(menu));
+
+		if (menu->sym) {
+			str_printf(r, " (%s [=%s])", menu->sym->name ?
+				menu->sym->name : "<choice>",
+				sym_get_string_value(menu->sym));
 		}
+		str_append(r, "\n");
 	}
 }
 
diff --git a/util/kconfig/patches/0001-Kconfig-Add-KCONFIG_STRICT-mode.patch b/util/kconfig/patches/0001-Kconfig-Add-KCONFIG_STRICT-mode.patch
index 6c43734..37f41b0 100644
--- a/util/kconfig/patches/0001-Kconfig-Add-KCONFIG_STRICT-mode.patch
+++ b/util/kconfig/patches/0001-Kconfig-Add-KCONFIG_STRICT-mode.patch
@@ -19,7 +19,7 @@
 ===================================================================
 --- kconfig.orig/confdata.c
 +++ kconfig/confdata.c
-@@ -439,6 +439,7 @@ load:
+@@ -428,6 +428,7 @@ load:
  			if (def == S_DEF_USER) {
  				sym = sym_find(line + 2 + strlen(CONFIG_));
  				if (!sym) {
@@ -27,7 +27,7 @@
  					conf_set_changed(true);
  					continue;
  				}
-@@ -521,6 +522,13 @@ load:
+@@ -510,6 +511,13 @@ load:
  	}
  	free(line);
  	fclose(in);
diff --git a/util/kconfig/patches/0002-Kconfig-Change-symbol-override-from-warning-to-notic.patch b/util/kconfig/patches/0002-Kconfig-Change-symbol-override-from-warning-to-notic.patch
index 4ce52da..e9b6462 100644
--- a/util/kconfig/patches/0002-Kconfig-Change-symbol-override-from-warning-to-notic.patch
+++ b/util/kconfig/patches/0002-Kconfig-Change-symbol-override-from-warning-to-notic.patch
@@ -23,7 +23,7 @@
 ===================================================================
 --- kconfig.orig/confdata.c
 +++ kconfig/confdata.c
-@@ -184,6 +184,16 @@ static void conf_warning(const char *fmt
+@@ -166,6 +166,16 @@ static void conf_warning(const char *fmt
  	conf_warnings++;
  }
  
@@ -40,7 +40,7 @@
  static void conf_default_message_callback(const char *s)
  {
  	printf("#\n# ");
-@@ -449,7 +459,7 @@ load:
+@@ -438,7 +448,7 @@ load:
  					sym->type = S_BOOLEAN;
  			}
  			if (sym->flags & def_flags) {
@@ -49,7 +49,7 @@
  			}
  			switch (sym->type) {
  			case S_BOOLEAN:
-@@ -488,7 +498,7 @@ load:
+@@ -477,7 +487,7 @@ load:
  			}
  
  			if (sym->flags & def_flags) {
@@ -58,7 +58,7 @@
  			}
  			if (conf_set_sym_val(sym, def, def_flags, p))
  				continue;
-@@ -513,7 +523,7 @@ load:
+@@ -502,7 +512,7 @@ load:
  				break;
  			case yes:
  				if (cs->def[def].tri != no)
diff --git a/util/kconfig/patches/0003-util-kconfig-conf.c-Fix-newline-in-error-printf.patch b/util/kconfig/patches/0003-util-kconfig-conf.c-Fix-newline-in-error-printf.patch
index ea27fbd..dabb0d9f 100644
--- a/util/kconfig/patches/0003-util-kconfig-conf.c-Fix-newline-in-error-printf.patch
+++ b/util/kconfig/patches/0003-util-kconfig-conf.c-Fix-newline-in-error-printf.patch
@@ -14,7 +14,7 @@
 ===================================================================
 --- kconfig.orig/conf.c
 +++ kconfig/conf.c
-@@ -900,7 +900,7 @@ int main(int ac, char **av)
+@@ -889,7 +889,7 @@ int main(int ac, char **av)
  
  	if (input_mode == savedefconfig) {
  		if (conf_write_defconfig(defconfig_file)) {
diff --git a/util/kconfig/patches/0005-util-kconfig-Ignore-extra-symbols-in-configs-instead.patch b/util/kconfig/patches/0005-util-kconfig-Ignore-extra-symbols-in-configs-instead.patch
index 8753522..142788d 100644
--- a/util/kconfig/patches/0005-util-kconfig-Ignore-extra-symbols-in-configs-instead.patch
+++ b/util/kconfig/patches/0005-util-kconfig-Ignore-extra-symbols-in-configs-instead.patch
@@ -24,7 +24,7 @@
 ===================================================================
 --- kconfig.orig/confdata.c
 +++ kconfig/confdata.c
-@@ -449,7 +449,9 @@ load:
+@@ -438,7 +438,9 @@ load:
  			if (def == S_DEF_USER) {
  				sym = sym_find(line + 2 + strlen(CONFIG_));
  				if (!sym) {
diff --git a/util/kconfig/patches/0006-util-kconfig-Set-parameter-of-mkdir-to-only-one-for-.patch b/util/kconfig/patches/0006-util-kconfig-Set-parameter-of-mkdir-to-only-one-for-.patch
index d6598ac..cd61f44 100644
--- a/util/kconfig/patches/0006-util-kconfig-Set-parameter-of-mkdir-to-only-one-for-.patch
+++ b/util/kconfig/patches/0006-util-kconfig-Set-parameter-of-mkdir-to-only-one-for-.patch
@@ -15,14 +15,14 @@
 ===================================================================
 --- kconfig.orig/confdata.c
 +++ kconfig/confdata.c
-@@ -164,6 +164,10 @@ struct conf_printer {
- 	void (*print_comment)(FILE *, const char *, void *);
- };
+@@ -155,6 +155,10 @@ static void conf_message(const char *fmt
+ static const char *conf_filename;
+ static int conf_lineno, conf_warnings;
  
 +#ifdef __MINGW32__
 +#define mkdir(_n,_p) mkdir((_n))
 +#endif
 +
  static void conf_warning(const char *fmt, ...)
- 	__attribute__ ((format (printf, 1, 2)));
- 
+ {
+ 	va_list ap;
diff --git a/util/kconfig/patches/0007-kconfig-Allow-KCONFIG_STRICT-outside-of-confdata.c.patch b/util/kconfig/patches/0007-kconfig-Allow-KCONFIG_STRICT-outside-of-confdata.c.patch
index 1af5e01..315d0e7 100644
--- a/util/kconfig/patches/0007-kconfig-Allow-KCONFIG_STRICT-outside-of-confdata.c.patch
+++ b/util/kconfig/patches/0007-kconfig-Allow-KCONFIG_STRICT-outside-of-confdata.c.patch
@@ -36,7 +36,7 @@
  static void conf(struct menu *menu);
  static void check_conf(struct menu *menu);
  
-@@ -732,6 +734,7 @@ int main(int ac, char **av)
+@@ -721,6 +723,7 @@ int main(int ac, char **av)
  	const char *progname = av[0];
  	int opt;
  	const char *name, *defconfig_file = NULL /* gcc uninit */;
@@ -44,7 +44,7 @@
  	int no_conf_write = 0;
  
  	tty_stdio = isatty(0) && isatty(1);
-@@ -838,6 +841,13 @@ int main(int ac, char **av)
+@@ -827,6 +830,13 @@ int main(int ac, char **av)
  		break;
  	}
  
@@ -62,7 +62,7 @@
 ===================================================================
 --- kconfig.orig/confdata.c
 +++ kconfig/confdata.c
-@@ -539,11 +539,7 @@ load:
+@@ -528,11 +528,7 @@ load:
  	free(line);
  	fclose(in);
  
diff --git a/util/kconfig/patches/0008-kconfig-Add-wildcard-support-for-source.patch b/util/kconfig/patches/0008-kconfig-Add-wildcard-support-for-source.patch
index abd6574..688b387 100644
--- a/util/kconfig/patches/0008-kconfig-Add-wildcard-support-for-source.patch
+++ b/util/kconfig/patches/0008-kconfig-Add-wildcard-support-for-source.patch
@@ -34,7 +34,7 @@
  #include <limits.h>
  #include <stdio.h>
  #include <stdlib.h>
-@@ -438,6 +439,32 @@ void zconf_nextfile(const char *name)
+@@ -439,6 +440,32 @@ void zconf_nextfile(const char *name)
  	current_file = file;
  }
  
diff --git a/util/kconfig/patches/0009-util-kconfig-Allow-emitting-false-booleans-into-kconfig-output.patch b/util/kconfig/patches/0009-util-kconfig-Allow-emitting-false-booleans-into-kconfig-output.patch
index 7e005e5..aae6c97 100644
--- a/util/kconfig/patches/0009-util-kconfig-Allow-emitting-false-booleans-into-kconfig-output.patch
+++ b/util/kconfig/patches/0009-util-kconfig-Allow-emitting-false-booleans-into-kconfig-output.patch
@@ -10,74 +10,6 @@
     Change-Id: I9e62b05e45709f1539e455e2eed37308609be15e
     Signed-off-by: Patrick Georgi <pgeorgi@google.com>
 
-Index: kconfig/confdata.c
-===================================================================
---- kconfig.orig/confdata.c
-+++ kconfig/confdata.c
-@@ -687,6 +687,9 @@ header_print_symbol(FILE *fp, struct sym
- 
- 		switch (*value) {
- 		case 'n':
-+			if (getenv("KCONFIG_NEGATIVES") != NULL)
-+				fprintf(fp, "#define %s%s%s 0\n",
-+				    CONFIG_, sym->name, suffix);
- 			break;
- 		case 'm':
- 			suffix = "_MODULE";
-@@ -702,14 +705,28 @@ header_print_symbol(FILE *fp, struct sym
- 
- 		if (value[0] != '0' || (value[1] != 'x' && value[1] != 'X'))
- 			prefix = "0x";
-+		if (value[0] == '\0') {
-+			/*
-+			 * prefix is reset to remain closer to the older
-+			 * coreboot patch. No need to keep this once kconfig
-+			 * is fully upreved
-+			 */
-+			prefix = "";
-+			value = "0";
-+		}
- 		fprintf(fp, "#define %s%s %s%s\n",
- 		    CONFIG_, sym->name, prefix, value);
- 		break;
- 	}
- 	case S_STRING:
-+		if (value[0] == '\0')
-+			break;
-+		if (!(sym->flags & SYMBOL_WRITE))
-+			break;
-+		/* fall through */
- 	case S_INT:
- 		fprintf(fp, "#define %s%s %s\n",
--		    CONFIG_, sym->name, value);
-+		    CONFIG_, sym->name, value[0]?value:"0");
- 		break;
- 	default:
- 		break;
-@@ -1080,6 +1097,7 @@ int conf_write_autoconf(int overwrite)
- 	const char *autoconf_name = conf_get_autoconfig_name();
- 	FILE *out, *out_h;
- 	int i;
-+	int print_negatives = getenv("KCONFIG_NEGATIVES") != NULL;
- 
- 	if (!overwrite && is_present(autoconf_name))
- 		return 0;
-@@ -1104,11 +1122,13 @@ int conf_write_autoconf(int overwrite)
- 
- 	for_all_symbols(i, sym) {
- 		sym_calc_value(sym);
--		if (!(sym->flags & SYMBOL_WRITE) || !sym->name)
-+		if (!(sym->flags & SYMBOL_WRITE) && !print_negatives)
-+			continue;
-+		if (!sym->name)
- 			continue;
- 
- 		/* write symbols to auto.conf and autoconf.h */
--		conf_write_symbol(out, sym, &kconfig_printer_cb, (void *)1);
-+		conf_write_symbol(out, sym, &kconfig_printer_cb, print_negatives?NULL:(void *)1);
- 		conf_write_symbol(out_h, sym, &header_printer_cb, NULL);
- 	}
- 	fclose(out);
 Index: kconfig/symbol.c
 ===================================================================
 --- kconfig.orig/symbol.c
@@ -91,3 +23,56 @@
  	case S_STRING:
  		return str;
  	case S_UNKNOWN:
+Index: kconfig/confdata.c
+===================================================================
+--- kconfig.orig/confdata.c
++++ kconfig/confdata.c
+@@ -720,7 +720,12 @@ static void print_symbol_for_dotconfig(F
+ 
+ static void print_symbol_for_autoconf(FILE *fp, struct symbol *sym)
+ {
+-	__print_symbol(fp, sym, OUTPUT_N_NONE, true);
++	int print_negatives = getenv("KCONFIG_NEGATIVES") != NULL;
++	enum output_n out = OUTPUT_N_NONE;
++	if (print_negatives) {
++		out = OUTPUT_N;
++	}
++	__print_symbol(fp, sym, out, true);
+ }
+ 
+ void print_symbol_for_listconfig(struct symbol *sym)
+@@ -745,6 +750,10 @@ static void print_symbol_for_c(FILE *fp,
+ 	case S_TRISTATE:
+ 		switch (*val) {
+ 		case 'n':
++			if (getenv("KCONFIG_NEGATIVES") != NULL) {
++				val = "0";
++				break;
++			}
+ 			return;
+ 		case 'm':
+ 			sym_suffix = "_MODULE";
+@@ -756,6 +765,12 @@ static void print_symbol_for_c(FILE *fp,
+ 	case S_HEX:
+ 		if (val[0] != '0' || (val[1] != 'x' && val[1] != 'X'))
+ 			val_prefix = "0x";
++		/* fall through */
++	case S_INT:
++		if (val[0] == '\0') {
++			val = "0";
++			val_prefix = "";
++		}
+ 		break;
+ 	case S_STRING:
+ 		escaped = escape_string_value(val);
+@@ -1106,8 +1121,9 @@ static int __conf_write_autoconf(const c
+ 
+ 	conf_write_heading(file, comment_style);
+ 
++	int print_negatives = getenv("KCONFIG_NEGATIVES") != NULL;
+ 	for_all_symbols(i, sym)
+-		if ((sym->flags & SYMBOL_WRITE) && sym->name)
++		if (((sym->flags & SYMBOL_WRITE) || (print_negatives && sym->type != S_STRING)) && sym->name)
+ 			print_symbol(file, sym);
+ 
+ 	/* check possible errors in conf_write_heading() and print_symbol() */
diff --git a/util/kconfig/patches/0011-remove-include-config-hardcodes.patch b/util/kconfig/patches/0011-remove-include-config-hardcodes.patch
index fa21dac..ca408d9 100644
--- a/util/kconfig/patches/0011-remove-include-config-hardcodes.patch
+++ b/util/kconfig/patches/0011-remove-include-config-hardcodes.patch
@@ -2,8 +2,8 @@
 ===================================================================
 --- kconfig.orig/confdata.c
 +++ kconfig/confdata.c
-@@ -241,6 +241,13 @@ static const char *conf_get_autoconfig_n
- 	return name ? name : "include/config/auto.conf";
+@@ -230,6 +230,13 @@ static const char *conf_get_autoheader_n
+ 	return name ? name : "include/generated/autoconf.h";
  }
  
 +static const char *conf_get_autobase_name(void)
@@ -16,7 +16,7 @@
  static int conf_set_sym_val(struct symbol *sym, int def, int def_flags, char *p)
  {
  	char *p2;
-@@ -1024,7 +1031,7 @@ static int conf_touch_deps(void)
+@@ -1031,7 +1038,7 @@ static int conf_touch_deps(void)
  	struct symbol *sym;
  	int res, i;
  
@@ -25,15 +25,3 @@
  	depfile_prefix_len = strlen(depfile_path);
  
  	name = conf_get_autoconfig_name();
-@@ -1102,7 +1109,10 @@ int conf_write_autoconf(int overwrite)
- 	if (!overwrite && is_present(autoconf_name))
- 		return 0;
- 
--	conf_write_dep("include/config/auto.conf.cmd");
-+	char autoconfcmd_path[PATH_MAX];
-+	snprintf(autoconfcmd_path, sizeof(autoconfcmd_path), "%s%s",
-+		conf_get_autobase_name(), "auto.conf.cmd");
-+	conf_write_dep(autoconfcmd_path);
- 
- 	if (conf_touch_deps())
- 		return 1;
diff --git a/util/kconfig/patches/0012-safer-tmpfiles.patch b/util/kconfig/patches/0012-safer-tmpfiles.patch
deleted file mode 100644
index d9b8361..0000000
--- a/util/kconfig/patches/0012-safer-tmpfiles.patch
+++ /dev/null
@@ -1,124 +0,0 @@
-commit 7b2deddbb0ef350e189fe42c025b07c943aedc4c
-Author: Raul E Rangel <rrangel@chromium.org>
-Date:   Thu Jul 25 15:49:52 2019 -0600
-
-    Kconfig: Write tmp files into same directory as target files
-
-    This removes the need for COREBOOT_BUILD_DIR in Kconfig. Since the
-    original files will be replaced with the tmp file, the parent directory
-    already needs to be writable.
-
-    Before this change, the tmp files would be created in the CWD (src) if
-    COREBOOT_BUILD_DIR was not specified.
-
-    BUG=b:112267918
-    TEST=emerge-grunt coreboot and verified no tmp files were created in the
-    src directory.
-
-    Change-Id: Icdaf2ff3dd1ec98813b75ef55b96e38e1ca19ec7
-    Signed-off-by: Raul E Rangel <rrangel@chromium.org>
-    Reviewed-on: https://review.coreboot.org/c/coreboot/+/34244
-    Reviewed-by: Martin Roth <martinroth@google.com>
-    Tested-by: build bot (Jenkins) <no-reply@coreboot.org>
-
-Index: kconfig/confdata.c
-===================================================================
---- kconfig.orig/confdata.c
-+++ kconfig/confdata.c
-@@ -880,6 +880,16 @@ next_menu:
- 	return 0;
- }
- 
-+
-+static int conf_mktemp(const char *path, char *tmpfile)
-+{
-+	if (snprintf(tmpfile, PATH_MAX, "%s.tmp.XXXXXX", path) >= PATH_MAX) {
-+		errno = EOVERFLOW;
-+		return -1;
-+	}
-+	return mkstemp(tmpfile);
-+}
-+
- int conf_write(const char *name)
- {
- 	FILE *out;
-@@ -1001,7 +1011,14 @@ static int conf_write_dep(const char *na
- 	struct file *file;
- 	FILE *out;
- 
--	out = fopen("..config.tmp", "w");
-+	if (make_parent_dir(name))
-+		return 1;
-+	char filename[PATH_MAX];
-+	int fd = conf_mktemp(name, filename);
-+	if (fd == -1)
-+		return 1;
-+
-+	out = fdopen(fd, "w");
- 	if (!out)
- 		return 1;
- 	fprintf(out, "deps_config := \\\n");
-@@ -1019,9 +1036,7 @@ static int conf_write_dep(const char *na
- 	fprintf(out, "\n$(deps_config): ;\n");
- 	fclose(out);
- 
--	if (make_parent_dir(name))
--		return 1;
--	rename("..config.tmp", name);
-+	rename(filename, name);
- 	return 0;
- }
- 
-@@ -1117,11 +1132,26 @@ int conf_write_autoconf(int overwrite)
- 	if (conf_touch_deps())
- 		return 1;
- 
--	out = fopen(".tmpconfig", "w");
-+	if (make_parent_dir(autoconf_name))
-+		return 1;
-+	char filename[PATH_MAX];
-+	int fd = conf_mktemp(autoconf_name, filename);
-+	if (fd == -1)
-+		return 1;
-+	out = fdopen(fd, "w");
- 	if (!out)
- 		return 1;
- 
--	out_h = fopen(".tmpconfig.h", "w");
-+	name = getenv("KCONFIG_AUTOHEADER");
-+	if (!name)
-+		name = "include/generated/autoconf.h";
-+	if (make_parent_dir(name))
-+		return 1;
-+	char filename_h[PATH_MAX];
-+	int fd_h = conf_mktemp(name, filename_h);
-+	if (fd_h == -1)
-+		return 1;
-+	out_h = fdopen(fd_h, "w");
- 	if (!out_h) {
- 		fclose(out);
- 		return 1;
-@@ -1144,21 +1174,14 @@ int conf_write_autoconf(int overwrite)
- 	fclose(out);
- 	fclose(out_h);
- 
--	name = getenv("KCONFIG_AUTOHEADER");
--	if (!name)
--		name = "include/generated/autoconf.h";
--	if (make_parent_dir(name))
--		return 1;
--	if (rename(".tmpconfig.h", name))
-+	if (rename(filename_h, name))
- 		return 1;
- 
--	if (make_parent_dir(autoconf_name))
--		return 1;
- 	/*
- 	 * This must be the last step, kbuild has a dependency on auto.conf
- 	 * and this marks the successful completion of the previous steps.
- 	 */
--	if (rename(".tmpconfig", autoconf_name))
-+	if (rename(filename, autoconf_name))
- 		return 1;
- 
- 	return 0;
diff --git a/util/kconfig/patches/series b/util/kconfig/patches/series
index dfc614e..bccab80 100644
--- a/util/kconfig/patches/series
+++ b/util/kconfig/patches/series
@@ -9,5 +9,4 @@
 0009-util-kconfig-Allow-emitting-false-booleans-into-kconfig-output.patch
 0010-reenable-source-in-choice.patch
 0011-remove-include-config-hardcodes.patch
-0012-safer-tmpfiles.patch
 0013-util-kconfig-detect-ncurses-on-FreeBSD.patch
diff --git a/util/kconfig/symbol.c b/util/kconfig/symbol.c
index 7a03aa2..7c687b0 100644
--- a/util/kconfig/symbol.c
+++ b/util/kconfig/symbol.c
@@ -872,49 +872,6 @@
 	return symbol;
 }
 
-const char *sym_escape_string_value(const char *in)
-{
-	const char *p;
-	size_t reslen;
-	char *res;
-	size_t l;
-
-	reslen = strlen(in) + strlen("\"\"") + 1;
-
-	p = in;
-	for (;;) {
-		l = strcspn(p, "\"\\");
-		p += l;
-
-		if (p[0] == '\0')
-			break;
-
-		reslen++;
-		p++;
-	}
-
-	res = xmalloc(reslen);
-	res[0] = '\0';
-
-	strcat(res, "\"");
-
-	p = in;
-	for (;;) {
-		l = strcspn(p, "\"\\");
-		strncat(res, p, l);
-		p += l;
-
-		if (p[0] == '\0')
-			break;
-
-		strcat(res, "\\");
-		strncat(res, p++, 1);
-	}
-
-	strcat(res, "\"");
-	return res;
-}
-
 struct sym_match {
 	struct symbol	*sym;
 	off_t		so, eo;