diff --git a/drivers/staging/android/Kconfig b/drivers/staging/android/Kconfig index 8d8fd5c29349..549120c5da21 100644 --- a/drivers/staging/android/Kconfig +++ b/drivers/staging/android/Kconfig @@ -14,6 +14,17 @@ config ASHMEM It is, in theory, a good memory allocator for low-memory devices, because it can discard shared memory units when under memory pressure. +config DEBUG_KINFO + bool "Debug Kernel Information Support" + depends on KALLSYMS + help + This supports kernel information backup for bootloader usage. + Specifics: + - The kallsyms symbols for unwind_backtrace + - Page directory pointer + - UTS_RELEASE + - BUILD_INFO(ro.build.fingerprint) + source "drivers/staging/android/ion/Kconfig" endif # if ANDROID diff --git a/drivers/staging/android/Makefile b/drivers/staging/android/Makefile index 3b66cd0b0ec5..ca5df9abd5bd 100644 --- a/drivers/staging/android/Makefile +++ b/drivers/staging/android/Makefile @@ -4,3 +4,4 @@ ccflags-y += -I$(src) # needed for trace events obj-y += ion/ obj-$(CONFIG_ASHMEM) += ashmem.o +obj-$(CONFIG_DEBUG_KINFO) += debug_kinfo.o diff --git a/drivers/staging/android/debug_kinfo.c b/drivers/staging/android/debug_kinfo.c new file mode 100644 index 000000000000..03b2ea4a28fe --- /dev/null +++ b/drivers/staging/android/debug_kinfo.c @@ -0,0 +1,181 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * debug_kinfo.c - backup kernel information for bootloader usage + * + * Copyright 2002 Rusty Russell IBM Corporation + * Copyright 2021 Google LLC + */ + +#include +#include +#include +#include +#include +#include +#include "debug_kinfo.h" + +/* + * These will be re-linked against their real values + * during the second link stage. + */ +extern const unsigned long kallsyms_addresses[] __weak; +extern const int kallsyms_offsets[] __weak; +extern const u8 kallsyms_names[] __weak; + +/* + * Tell the compiler that the count isn't in the small data section if the arch + * has one (eg: FRV). + */ +extern const unsigned int kallsyms_num_syms __weak +__section(".rodata"); + +extern const unsigned long kallsyms_relative_base __weak +__section(".rodata"); + +extern const u8 kallsyms_token_table[] __weak; +extern const u16 kallsyms_token_index[] __weak; + +extern const unsigned int kallsyms_markers[] __weak; + +static void *all_info_addr; +static u32 all_info_size; + +static void update_kernel_all_info(struct kernel_all_info *all_info) +{ + int index; + struct kernel_info *info; + u32 *checksum_info; + + all_info->magic_number = DEBUG_KINFO_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]; +} + +static int build_info_set(const char *str, const struct kernel_param *kp) +{ + struct kernel_all_info *all_info; + size_t build_info_size; + int ret = 0; + + if (all_info_addr == 0 || all_info_size == 0) { + ret = -EPERM; + goto Exit; + } + + all_info = (struct kernel_all_info *)all_info_addr; + build_info_size = sizeof(all_info->info.build_info); + + memcpy(&all_info->info.build_info, str, min(build_info_size - 1, strlen(str))); + update_kernel_all_info(all_info); + + if (strlen(str) > build_info_size) { + pr_warn("%s: Build info buffer (len: %zd) can't hold entire string '%s'\n", + __func__, build_info_size, str); + ret = -ENOMEM; + } + +Exit: + vunmap(all_info_addr); + return ret; +} + +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 debug kinfo."); + +static int debug_kinfo_probe(struct platform_device *pdev) +{ + struct device_node *mem_region; + struct reserved_mem *rmem; + struct kernel_all_info *all_info; + struct kernel_info *info; + + mem_region = of_parse_phandle(pdev->dev.of_node, "memory-region", 0); + if (!mem_region) { + dev_warn(&pdev->dev, "no such memory-region\n"); + return -ENODEV; + } + + rmem = of_reserved_mem_lookup(mem_region); + if (!rmem) { + dev_warn(&pdev->dev, "no such reserved mem of node name %s\n", + pdev->dev.of_node->name); + return -ENODEV; + } + + /* Deferred until dss.ko(dpm.o) and debug-snapshot-debug-kinfo.ko are ready */ + if (!rmem->priv) { + return -EPROBE_DEFER; + } + + if (!rmem->base || !rmem->size) { + dev_warn(&pdev->dev, "unexpected reserved memory\n"); + return -EINVAL; + } + + if (rmem->size < sizeof(struct kernel_all_info)) { + dev_warn(&pdev->dev, "unexpected reserved memory size\n"); + return -EINVAL; + } + + all_info_addr = rmem->priv; + all_info_size = rmem->size; + + memset(all_info_addr, 0, all_info_size); + all_info = (struct kernel_all_info *)all_info_addr; + info = &(all_info->info); + info->enabled_all = IS_ENABLED(CONFIG_KALLSYMS_ALL); + info->enabled_base_relative = IS_ENABLED(CONFIG_KALLSYMS_BASE_RELATIVE); + info->enabled_absolute_percpu = IS_ENABLED(CONFIG_KALLSYMS_ABSOLUTE_PERCPU); + info->enabled_cfi_clang = IS_ENABLED(CONFIG_CFI_CLANG); + info->num_syms = kallsyms_num_syms; + info->name_len = KSYM_NAME_LEN; + info->bit_per_long = BITS_PER_LONG; + info->module_name_len = MODULE_NAME_LEN; + info->symbol_len = KSYM_SYMBOL_LEN; + info->_addresses_pa = (u64)virt_to_phys((volatile void *)kallsyms_addresses); + info->_relative_pa = (u64)virt_to_phys((volatile void *)kallsyms_relative_base); + info->_stext_pa = (u64)virt_to_phys(_stext); + info->_etext_pa = (u64)virt_to_phys(_etext); + info->_sinittext_pa = (u64)virt_to_phys(_sinittext); + info->_einittext_pa = (u64)virt_to_phys(_einittext); + info->_end_pa = (u64)virt_to_phys(_end); + info->_offsets_pa = (u64)virt_to_phys((volatile void *)kallsyms_offsets); + info->_names_pa = (u64)virt_to_phys((volatile void *)kallsyms_names); + info->_token_table_pa = (u64)virt_to_phys((volatile void *)kallsyms_token_table); + info->_token_index_pa = (u64)virt_to_phys((volatile void *)kallsyms_token_index); + info->_markers_pa = (u64)virt_to_phys((volatile void *)kallsyms_markers); + info->thread_size = THREAD_SIZE; + info->swapper_pg_dir_pa = (u64)virt_to_phys(swapper_pg_dir); + strlcpy(info->last_uts_release, init_utsname()->release, sizeof(info->last_uts_release)); + + update_kernel_all_info(all_info); + + return 0; +} + +static const struct of_device_id debug_kinfo_of_match[] = { + { .compatible = "google,debug-kinfo" }, + {}, +}; +MODULE_DEVICE_TABLE(of, debug_kinfo_of_match); + +static struct platform_driver debug_kinfo_driver = { + .probe = debug_kinfo_probe, + .driver = { + .name = "debug-kinfo", + .of_match_table = of_match_ptr(debug_kinfo_of_match), + }, +}; +module_platform_driver(debug_kinfo_driver); + +MODULE_AUTHOR("Jone Chou "); +MODULE_DESCRIPTION("Debug Kinfo Driver"); +MODULE_LICENSE("GPL v2"); diff --git a/drivers/staging/android/debug_kinfo.h b/drivers/staging/android/debug_kinfo.h new file mode 100644 index 000000000000..d7dbba1d3b59 --- /dev/null +++ b/drivers/staging/android/debug_kinfo.h @@ -0,0 +1,63 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * debug_kinfo.h - backup kernel information for bootloader usage + * + * Copyright 2021 Google LLC + */ + +#ifndef DEBUG_KINFO_H +#define DEBUG_KINFO_H + +#include + +#define BUILD_INFO_LEN 256 +#define DEBUG_KINFO_MAGIC 0xCCEEDDFF + +/* + * Header structure must be byte-packed, since the table is provided to + * bootloader. + */ +struct kernel_info { + /* For kallsyms */ + __u8 enabled_all; + __u8 enabled_base_relative; + __u8 enabled_absolute_percpu; + __u8 enabled_cfi_clang; + __u32 num_syms; + __u16 name_len; + __u16 bit_per_long; + __u16 module_name_len; + __u16 symbol_len; + __u64 _addresses_pa; + __u64 _relative_pa; + __u64 _stext_pa; + __u64 _etext_pa; + __u64 _sinittext_pa; + __u64 _einittext_pa; + __u64 _end_pa; + __u64 _offsets_pa; + __u64 _names_pa; + __u64 _token_table_pa; + __u64 _token_index_pa; + __u64 _markers_pa; + + /* For frame pointer */ + __u32 thread_size; + + /* For virt_to_phys */ + __u64 swapper_pg_dir_pa; + + /* For linux banner */ + __u8 last_uts_release[__NEW_UTS_LEN]; + + /* Info of running build */ + __u8 build_info[BUILD_INFO_LEN]; +} __packed; + +struct kernel_all_info { + __u32 magic_number; + __u32 combined_checksum; + struct kernel_info info; +} __packed; + +#endif // DEBUG_KINFO_H