ANDROID: staging: add debug-kinfo driver
Backup kernel information for bootloader usage. Specifics: - The kallsyms symbols for unwind_backtrace - Page directory pointer - UTS_RELEASE - BUILD_INFO(ro.build.fingerprint) Bug: 170851792 Bug: 169101608 Signed-off-by: Jone Chou <jonechou@google.com> Signed-off-by: Will McVicker <willmcvicker@google.com> Change-Id: Ida76bf90315652b8debc081a010bc5720a5a186e
This commit is contained in:
@@ -14,6 +14,17 @@ config ASHMEM
|
|||||||
It is, in theory, a good memory allocator for low-memory devices,
|
It is, in theory, a good memory allocator for low-memory devices,
|
||||||
because it can discard shared memory units when under memory pressure.
|
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)
|
||||||
|
|
||||||
endif # if ANDROID
|
endif # if ANDROID
|
||||||
|
|
||||||
endmenu
|
endmenu
|
||||||
|
|||||||
@@ -2,3 +2,4 @@
|
|||||||
ccflags-y += -I$(src) # needed for trace events
|
ccflags-y += -I$(src) # needed for trace events
|
||||||
|
|
||||||
obj-$(CONFIG_ASHMEM) += ashmem.o
|
obj-$(CONFIG_ASHMEM) += ashmem.o
|
||||||
|
obj-$(CONFIG_DEBUG_KINFO) += debug_kinfo.o
|
||||||
|
|||||||
@@ -0,0 +1,181 @@
|
|||||||
|
// SPDX-License-Identifier: GPL-2.0
|
||||||
|
/*
|
||||||
|
* debug_kinfo.c - backup kernel information for bootloader usage
|
||||||
|
*
|
||||||
|
* Copyright 2002 Rusty Russell <rusty@rustcorp.com.au> IBM Corporation
|
||||||
|
* Copyright 2021 Google LLC
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <linux/platform_device.h>
|
||||||
|
#include <linux/kallsyms.h>
|
||||||
|
#include <linux/vmalloc.h>
|
||||||
|
#include <linux/module.h>
|
||||||
|
#include <linux/of_address.h>
|
||||||
|
#include <linux/of_reserved_mem.h>
|
||||||
|
#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 <jonechou@google.com>");
|
||||||
|
MODULE_DESCRIPTION("Debug Kinfo Driver");
|
||||||
|
MODULE_LICENSE("GPL v2");
|
||||||
@@ -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 <linux/utsname.h>
|
||||||
|
|
||||||
|
#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
|
||||||
Reference in New Issue
Block a user