From 3aefd4332700d1fb8b97f3a734cb8959c366c6f9 Mon Sep 17 00:00:00 2001
From: Safae Ouajih <souajih@baylibre.com>
Date: Thu, 11 Aug 2022 15:30:38 +0200
Subject: [PATCH] android boot image header v4 bootconfig support

This adds support for bootconfig feature.

Signed-off-by: Safae Ouajih <souajih@baylibre.com>
---
 boot/image-android.c    |  15 +++++-
 include/android_image.h |   3 +-
 include/xbc.h           |   1 +
 lib/Kconfig             |  12 +++++
 lib/Makefile            |   1 +
 lib/libxbc/Makefile     |   1 +
 lib/libxbc/libxbc.c     | 112 ++++++++++++++++++++++++++++++++++++++++
 lib/libxbc/libxbc.h     |  54 +++++++++++++++++++
 8 files changed, 197 insertions(+), 2 deletions(-)
 create mode 100644 include/xbc.h
 create mode 100644 lib/libxbc/Makefile
 create mode 100644 lib/libxbc/libxbc.c
 create mode 100644 lib/libxbc/libxbc.h

diff --git a/boot/image-android.c b/boot/image-android.c
index 39cdce11abe..67ee8d16582 100644
--- a/boot/image-android.c
+++ b/boot/image-android.c
@@ -13,6 +13,7 @@
 #include <asm/unaligned.h>
 #include <mapmem.h>
 #include <linux/libfdt.h>
+#include <xbc.h>
 
 #define ANDROID_IMAGE_DEFAULT_KERNEL_ADDR	0x10008000
 
@@ -115,6 +116,7 @@ void android_vendor_boot_image_v3_v4_get_end(const struct andr_vendor_boot_img_h
 	data->image_name = hdr->name;
 	data->kernel_load_addr = hdr->kernel_addr;
 	data->ramdisk_load_addr = hdr->ramdisk_addr;
+	data->bootconfig_size = hdr->bootconfig_size;
 	end = (ulong)hdr;
 	end += hdr->page_size;
 	if (hdr->vendor_ramdisk_size) {
@@ -129,7 +131,14 @@ void android_vendor_boot_image_v3_v4_get_end(const struct andr_vendor_boot_img_h
 
 	end += ALIGN(hdr->dtb_size, hdr->page_size);
 	end += ALIGN(hdr->vendor_ramdisk_table_size, hdr->page_size);
-	end += ALIGN(hdr->bootconfig_size, hdr->page_size);
+
+	data->bootconfig_addr = end;
+	if (hdr->bootconfig_size) {
+		data->bootconfig_size += addBootConfigTrailer(data->bootconfig_addr, data->bootconfig_size);
+		data->ramdisk_size += data->bootconfig_size;
+	}
+
+	end += ALIGN(data->bootconfig_size, hdr->page_size);
 	data->boot_img_total_size = end - (ulong)hdr;
 }
 
@@ -320,6 +329,10 @@ int android_image_get_ramdisk(const void *boot_img, const void *vendor_boot_img,
 		ulong ramdisk_ptr = img_data.ramdisk_ptr;
 		memcpy((void *)(ramdisk_ptr), (void *)img_data.vendor_ramdisk_ptr, img_data.vendor_ramdisk_size);
 		memcpy((void *)(ramdisk_ptr + img_data.vendor_ramdisk_size), (void*)img_data.ramdisk_ptr, img_data.boot_ramdisk_size);
+		if (img_data.bootconfig_size) {
+			memcpy((void *)(ramdisk_ptr + img_data.vendor_ramdisk_size + img_data.boot_ramdisk_size),
+				       	(void*)img_data.bootconfig_addr, img_data.bootconfig_size);
+		}
 	}
 
 	printf("RAM disk load addr 0x%08lx size %u KiB\n",
diff --git a/include/android_image.h b/include/android_image.h
index 529680076bd..96541bf32a4 100644
--- a/include/android_image.h
+++ b/include/android_image.h
@@ -332,7 +332,8 @@ struct andr_image_data {
 	uint32_t dtb_size;
 	ulong recovery_dtbo_ptr;
 	uint32_t recovery_dtbo_size;
-
+	ulong bootconfig_addr;
+	ulong bootconfig_size;
 	const char *kcmdline;
 	const char *kcmdline_extra;
 	const char *image_name;
diff --git a/include/xbc.h b/include/xbc.h
new file mode 100644
index 00000000000..725e65ff6ad
--- /dev/null
+++ b/include/xbc.h
@@ -0,0 +1 @@
+#include <../lib/libxbc/libxbc.h>
diff --git a/lib/Kconfig b/lib/Kconfig
index 3c6fa99b1a6..6406e713c27 100644
--- a/lib/Kconfig
+++ b/lib/Kconfig
@@ -386,6 +386,18 @@ config LIBAVB
 
 endmenu
 
+menu "Boot Configuration"
+config XBC
+	bool "Boot Configuration support"
+	depends on ANDROID_BOOT_IMAGE
+	default n
+	help
+	  This enables support of Boot Configuration which can be used
+	  to pass boot configuration parameters to user space. These
+	  parameters will show up in /proc/bootconfig similar to the kernel
+	  parameters that show up in /proc/cmdline
+endmenu
+
 menu "Hashing Support"
 
 config BLAKE2
diff --git a/lib/Makefile b/lib/Makefile
index 11b03d1cbec..15fb58f8bb6 100644
--- a/lib/Makefile
+++ b/lib/Makefile
@@ -85,6 +85,7 @@ obj-$(CONFIG_$(SPL_)LZ4) += lz4_wrapper.o
 obj-$(CONFIG_$(SPL_)LIB_RATIONAL) += rational.o
 
 obj-$(CONFIG_LIBAVB) += libavb/
+obj-$(CONFIG_XBC) += libxbc/
 
 obj-$(CONFIG_$(SPL_TPL_)OF_LIBFDT) += libfdt/
 obj-$(CONFIG_$(SPL_TPL_)OF_REAL) += fdtdec_common.o fdtdec.o
diff --git a/lib/libxbc/Makefile b/lib/libxbc/Makefile
new file mode 100644
index 00000000000..05da3f6d578
--- /dev/null
+++ b/lib/libxbc/Makefile
@@ -0,0 +1 @@
+obj-$(CONFIG_XBC) += libxbc.o
diff --git a/lib/libxbc/libxbc.c b/lib/libxbc/libxbc.c
new file mode 100644
index 00000000000..129bffc7c62
--- /dev/null
+++ b/lib/libxbc/libxbc.c
@@ -0,0 +1,112 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+#include "libxbc.h"
+#define BOOTCONFIG_MAGIC "#BOOTCONFIG\n"
+#define BOOTCONFIG_MAGIC_SIZE 12
+#define BOOTCONFIG_SIZE_SIZE 4
+#define BOOTCONFIG_CHECKSUM_SIZE 4
+#define BOOTCONFIG_TRAILER_SIZE BOOTCONFIG_MAGIC_SIZE + \
+                                BOOTCONFIG_SIZE_SIZE + \
+                                BOOTCONFIG_CHECKSUM_SIZE
+
+/*
+ * Simple checksum for a buffer.
+ *
+ * @param addr pointer to the start of the buffer.
+ * @param size size of the buffer in bytes.
+ * @return check sum result.
+ */
+static uint32_t checksum(const unsigned char* const buffer, uint32_t size) {
+    uint32_t sum = 0;
+    for (uint32_t i = 0; i < size; i++) {
+        sum += buffer[i];
+    }
+    return sum;
+}
+
+/*
+ * Check if the bootconfig trailer is present within the bootconfig section.
+ *
+ * @param bootconfig_end_addr address of the end of the bootconfig section. If
+ *        the trailer is present, it will be directly preceding this address.
+ * @return true if the trailer is present, false if not.
+ */
+static bool isTrailerPresent(uint64_t bootconfig_end_addr) {
+    return !strncmp((char*)(bootconfig_end_addr - BOOTCONFIG_MAGIC_SIZE),
+                    BOOTCONFIG_MAGIC, BOOTCONFIG_MAGIC_SIZE);
+}
+
+/*
+ * Add a string of boot config parameters to memory appended by the trailer.
+ */
+int32_t addBootConfigParameters(char* params, uint32_t params_size,
+    uint64_t bootconfig_start_addr, uint32_t bootconfig_size) {
+    if (!params || !bootconfig_start_addr) {
+        return -1;
+    }
+    if (params_size == 0) {
+        return 0;
+    }
+    int32_t applied_bytes = 0;
+    int32_t new_size = 0;
+    uint64_t end = bootconfig_start_addr + bootconfig_size;
+    if (isTrailerPresent(end)) {
+      end -= BOOTCONFIG_TRAILER_SIZE;
+      applied_bytes -= BOOTCONFIG_TRAILER_SIZE;
+      memcpy(&new_size, (void *)end, BOOTCONFIG_SIZE_SIZE);
+    } else {
+      new_size = bootconfig_size;
+    }
+    // params
+    memcpy((void*)end, params, params_size);
+    applied_bytes += params_size;
+    applied_bytes += addBootConfigTrailer(bootconfig_start_addr,
+        bootconfig_size + applied_bytes);
+    return applied_bytes;
+}
+
+/*
+ * Add boot config trailer.
+ */
+
+int32_t addBootConfigTrailer(uint64_t bootconfig_start_addr,
+                            uint32_t bootconfig_size) {
+    if (!bootconfig_start_addr) {
+        return -1;
+    }
+
+    if (bootconfig_size == 0) {
+        return 0;
+    }
+
+    uint64_t end = bootconfig_start_addr + bootconfig_size;
+    if (isTrailerPresent(end)) {
+        return 0;
+    }
+
+    // size
+    memcpy((void *)(end), &bootconfig_size, BOOTCONFIG_SIZE_SIZE);
+
+    // checksum
+    uint32_t sum = checksum((unsigned char*)bootconfig_start_addr, bootconfig_size);
+    memcpy((void *)(end + BOOTCONFIG_SIZE_SIZE), &sum, BOOTCONFIG_CHECKSUM_SIZE);
+
+    // magic
+    memcpy((void *)(end + BOOTCONFIG_SIZE_SIZE + BOOTCONFIG_CHECKSUM_SIZE),
+           BOOTCONFIG_MAGIC, BOOTCONFIG_MAGIC_SIZE);
+
+    return BOOTCONFIG_TRAILER_SIZE;
+}
diff --git a/lib/libxbc/libxbc.h b/lib/libxbc/libxbc.h
new file mode 100644
index 00000000000..0b6ba496090
--- /dev/null
+++ b/lib/libxbc/libxbc.h
@@ -0,0 +1,54 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+#ifndef LIBXBC_H_
+#define LIBXBC_H_
+
+#include <common.h>
+/*
+ * Add a string of boot config parameters to memory appended by the trailer.
+ * This memory needs to be immediately following the end of the ramdisks.
+ * The new boot config trailer will be written to the end of the entire
+ * parameter section(previous + new). The trailer contains a 4 byte size of the
+ * parameters, followed by a 4 byte checksum of the parameters, followed by a 12
+ * byte magic string.
+ *
+ * @param params pointer to string of boot config parameters
+ * @param params_size size of params string in bytes
+ * @param bootconfig_start_addr address that the boot config section is starting
+ *        at in memory.
+ * @param bootconfig_size size of the current bootconfig section in bytes.
+ * @return number of bytes added to the boot config section. -1 for error.
+ */
+int addBootConfigParameters(char *params, uint32_t params_size,
+                            uint64_t bootconfig_start_addr,
+                            uint32_t bootconfig_size);
+/*
+ * Add the boot config trailer to the end of the boot config parameter section.
+ * This can be used after the vendor bootconfig section has been placed into
+ * memory if there are no additional parameters that need to be added.
+ * The new boot config trailer will be written to the end of the entire
+ * parameter section at (bootconfig_start_addr + bootconfig_size).
+ * The trailer contains a 4 byte size of the parameters, followed by a 4 byte
+ * checksum of the parameters, followed by a 12 byte magic string.
+ *
+ * @param bootconfig_start_addr address that the boot config section is starting
+ *        at in memory.
+ * @param bootconfig_size size of the current bootconfig section in bytes.
+ * @return number of bytes added to the boot config section. -1 for error.
+ */
+int addBootConfigTrailer(uint64_t bootconfig_start_addr,
+                         uint32_t bootconfig_size);
+#endif /* LIBXBC_H_ */
-- 
GitLab