kdebuginfo: Interface to set buildinfo

Bug: 154441754
Bug: 182735318
Change-Id: I2d6efccab9c8b0ee8a8f6c0d069205403d890296
Signed-off-by: Woody Lin <woodylin@google.com>
(cherry picked from commit a79a9d5aba6790859b725aaa8a0a618da867d62f)
diff --git a/kernel/kdebuginfo.c b/kernel/kdebuginfo.c
index ce977da..5cdd6d2 100644
--- a/kernel/kdebuginfo.c
+++ b/kernel/kdebuginfo.c
@@ -39,6 +39,8 @@
 
 extern const unsigned long kallsyms_markers[] __weak;
 
+static phys_addr_t all_info_addr;
+
 /*
  * Header structure must be byte-packed, since the table is provided to
  * bootloader.
@@ -81,6 +83,9 @@
 
 	/* For mmu table */
 	u64 swapper_pg_dir;
+
+	/* Info of running build */
+	char build_info[32];
 } __packed;
 
 struct kernel_all_info {
@@ -89,6 +94,24 @@
 	struct kernel_info info;
 } __packed;
 
+static void update_all_info_toio(void __iomem *io_base,
+		struct kernel_all_info *all_info)
+{
+	int index;
+	struct kernel_info *info;
+	u32 *checksum_info;
+
+	all_info->magic_number = BOOT_DEBUG_MAGIC;
+	all_info->combined_checksum = 0;
+
+	info = &(all_info->info);
+	checksum_info = (u32 *)info;
+	for (index = 0; index < sizeof(*info)/sizeof(u32); index++)
+		all_info->combined_checksum ^= checksum_info[index];
+
+	memcpy_toio(io_base, all_info, sizeof(*all_info));
+}
+
 static void backup_kernel_info(void)
 {
 	struct device_node *np;
@@ -96,9 +119,8 @@
 	struct kernel_all_info all_info;
 	struct kernel_info *info;
 	void __iomem *info_base;
-	u32 *checksum_info;
 	int num_reg = 0;
-	int ret, index;
+	int ret;
 
 	np = of_find_compatible_node(NULL, NULL, "bootloader_kinfo");
 	if (!np) {
@@ -119,6 +141,8 @@
 		return;
 	}
 
+	all_info_addr = res.start;
+
 	info_base = ioremap(res.start, resource_size(&res));
 	if (!info_base) {
 		pr_warn("%s: bootloader kernel info offset mapping failed\n",
@@ -160,17 +184,48 @@
 			sizeof(info->last_uts_release));
 	info->swapper_pg_dir = (u64)swapper_pg_dir;
 
-	checksum_info = (u32 *)info;
-	for (index = 0; index < sizeof(struct kernel_info)/sizeof(u32);
-		index++) {
-		all_info.combined_checksum ^= checksum_info[index];
-	}
-
-	all_info.magic_number = BOOT_DEBUG_MAGIC;
-	memcpy_toio(info_base, &all_info, sizeof(struct kernel_all_info));
+	update_all_info_toio(info_base, &all_info);
 	iounmap(info_base);
 }
 
+static int build_info_set(const char *str, const struct kernel_param *kp)
+{
+	void __iomem *info_base;
+	struct kernel_all_info all_info;
+	const size_t build_info_size = sizeof(all_info.info.build_info);
+
+	if (all_info_addr == 0)
+		return -EPERM;
+
+	info_base = ioremap(all_info_addr, sizeof(all_info));
+	if (!info_base) {
+		pr_err("%s: Failed to map all_info\n", __func__);
+		return -EPERM;
+	}
+
+	memcpy_fromio(&all_info, info_base, sizeof(all_info));
+	memcpy(&all_info.info.build_info, str,
+			min(build_info_size, strlen(str)));
+	update_all_info_toio(info_base, &all_info);
+	iounmap(info_base);
+
+	if (strlen(str) > build_info_size) {
+		pr_warn("%s: buffer too small (%zd bytes) for string '%s'\n",
+				__func__, build_info_size, str);
+		return -ENOMEM;
+	}
+
+	return 0;
+}
+
+static const struct kernel_param_ops build_info_op = {
+	.set = build_info_set,
+};
+
+module_param_cb(build_info, &build_info_op, NULL, 0200);
+MODULE_PARM_DESC(build_info,
+		"Write build info to field 'build_info' of kdebuginfo.");
+
 static int __init kdebuginfo_init(void)
 {
 	/* Backup kernel information for bootloader */