hc
2024-08-16 a24a44ff9ca902811b99aa9663d697cf452e08ef
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
// 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 <linux/pgtable.h>
#include <asm/module.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:
   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;
   }
 
   /* Need to wait for reserved memory to be mapped */
   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, sizeof(struct kernel_all_info));
   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;
   if (!info->enabled_base_relative)
       info->_addresses_pa = (u64)__pa_symbol((volatile void *)kallsyms_addresses);
   else {
       info->_relative_pa = (u64)__pa_symbol((volatile void *)kallsyms_relative_base);
       info->_offsets_pa = (u64)__pa_symbol((volatile void *)kallsyms_offsets);
   }
   info->_stext_pa = (u64)__pa_symbol(_stext);
   info->_etext_pa = (u64)__pa_symbol(_etext);
   info->_sinittext_pa = (u64)__pa_symbol(_sinittext);
   info->_einittext_pa = (u64)__pa_symbol(_einittext);
   info->_end_pa = (u64)__pa_symbol(_end);
   info->_names_pa = (u64)__pa_symbol((volatile void *)kallsyms_names);
   info->_token_table_pa = (u64)__pa_symbol((volatile void *)kallsyms_token_table);
   info->_token_index_pa = (u64)__pa_symbol((volatile void *)kallsyms_token_index);
   info->_markers_pa = (u64)__pa_symbol((volatile void *)kallsyms_markers);
   info->thread_size = THREAD_SIZE;
   info->swapper_pg_dir_pa = (u64)__pa_symbol(swapper_pg_dir);
   strlcpy(info->last_uts_release, init_utsname()->release, sizeof(info->last_uts_release));
   info->enabled_modules_tree_lookup = IS_ENABLED(CONFIG_MODULES_TREE_LOOKUP);
   info->mod_core_layout_offset = offsetof(struct module, core_layout);
   info->mod_init_layout_offset = offsetof(struct module, init_layout);
   info->mod_kallsyms_offset = offsetof(struct module, kallsyms);
#if defined(CONFIG_RANDOMIZE_BASE) && defined(MODULES_VSIZE)
   info->module_start_va = module_alloc_base;
   info->module_end_va = info->module_start_va + MODULES_VSIZE;
#elif defined(CONFIG_MODULES) && defined(MODULES_VADDR)
   info->module_start_va = MODULES_VADDR;
   info->module_end_va = MODULES_END;
#else
   info->module_start_va = VMALLOC_START;
   info->module_end_va = VMALLOC_END;
#endif
   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");