mirror of
https://github.com/hardkernel/linux.git
synced 2026-06-06 19:08:57 +09:00
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,
|
||||
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
|
||||
|
||||
endmenu
|
||||
|
||||
@@ -2,3 +2,4 @@
|
||||
ccflags-y += -I$(src) # needed for trace events
|
||||
|
||||
obj-$(CONFIG_ASHMEM) += ashmem.o
|
||||
obj-$(CONFIG_DEBUG_KINFO) += debug_kinfo.o
|
||||
|
||||
181
drivers/staging/android/debug_kinfo.c
Normal file
181
drivers/staging/android/debug_kinfo.c
Normal file
@@ -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");
|
||||
63
drivers/staging/android/debug_kinfo.h
Normal file
63
drivers/staging/android/debug_kinfo.h
Normal file
@@ -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