1 // SPDX-License-Identifier: GPL-2.0
2 /*
3 * debug_kinfo.c - backup kernel information for bootloader usage
4 *
5 * Copyright 2002 Rusty Russell <rusty@rustcorp.com.au> IBM Corporation
6 * Copyright 2021 Google LLC
7 */
8
9 #include <linux/platform_device.h>
10 #include <linux/kallsyms.h>
11 #include <linux/vmalloc.h>
12 #include <linux/module.h>
13 #include <linux/of_address.h>
14 #include <linux/of_reserved_mem.h>
15 #include <linux/pgtable.h>
16 #include <asm/module.h>
17 #include "debug_kinfo.h"
18
19 /*
20 * These will be re-linked against their real values
21 * during the second link stage.
22 */
23 extern const unsigned long kallsyms_addresses[] __weak;
24 extern const int kallsyms_offsets[] __weak;
25 extern const u8 kallsyms_names[] __weak;
26
27 /*
28 * Tell the compiler that the count isn't in the small data section if the arch
29 * has one (eg: FRV).
30 */
31 extern const unsigned int kallsyms_num_syms __weak
32 __section(".rodata");
33
34 extern const unsigned long kallsyms_relative_base __weak
35 __section(".rodata");
36
37 extern const u8 kallsyms_token_table[] __weak;
38 extern const u16 kallsyms_token_index[] __weak;
39
40 extern const unsigned int kallsyms_markers[] __weak;
41
42 static void *all_info_addr;
43 static u32 all_info_size;
44
update_kernel_all_info(struct kernel_all_info * all_info)45 static void update_kernel_all_info(struct kernel_all_info *all_info)
46 {
47 int index;
48 struct kernel_info *info;
49 u32 *checksum_info;
50
51 all_info->magic_number = DEBUG_KINFO_MAGIC;
52 all_info->combined_checksum = 0;
53
54 info = &(all_info->info);
55 checksum_info = (u32 *)info;
56 for (index = 0; index < sizeof(*info) / sizeof(u32); index++)
57 all_info->combined_checksum ^= checksum_info[index];
58 }
59
build_info_set(const char * str,const struct kernel_param * kp)60 static int build_info_set(const char *str, const struct kernel_param *kp)
61 {
62 struct kernel_all_info *all_info;
63 size_t build_info_size;
64 int ret = 0;
65
66 if (all_info_addr == 0 || all_info_size == 0) {
67 ret = -EPERM;
68 goto Exit;
69 }
70
71 all_info = (struct kernel_all_info *)all_info_addr;
72 build_info_size = sizeof(all_info->info.build_info);
73
74 memcpy(&all_info->info.build_info, str, min(build_info_size - 1, strlen(str)));
75 update_kernel_all_info(all_info);
76
77 if (strlen(str) > build_info_size) {
78 pr_warn("%s: Build info buffer (len: %zd) can't hold entire string '%s'\n",
79 __func__, build_info_size, str);
80 ret = -ENOMEM;
81 }
82
83 Exit:
84 return ret;
85 }
86
87 static const struct kernel_param_ops build_info_op = {
88 .set = build_info_set,
89 };
90
91 module_param_cb(build_info, &build_info_op, NULL, 0200);
92 MODULE_PARM_DESC(build_info, "Write build info to field 'build_info' of debug kinfo.");
93
debug_kinfo_probe(struct platform_device * pdev)94 static int debug_kinfo_probe(struct platform_device *pdev)
95 {
96 struct device_node *mem_region;
97 struct reserved_mem *rmem;
98 struct kernel_all_info *all_info;
99 struct kernel_info *info;
100
101 mem_region = of_parse_phandle(pdev->dev.of_node, "memory-region", 0);
102 if (!mem_region) {
103 dev_warn(&pdev->dev, "no such memory-region\n");
104 return -ENODEV;
105 }
106
107 rmem = of_reserved_mem_lookup(mem_region);
108 if (!rmem) {
109 dev_warn(&pdev->dev, "no such reserved mem of node name %s\n",
110 pdev->dev.of_node->name);
111 return -ENODEV;
112 }
113
114 /* Need to wait for reserved memory to be mapped */
115 if (!rmem->priv) {
116 return -EPROBE_DEFER;
117 }
118
119 if (!rmem->base || !rmem->size) {
120 dev_warn(&pdev->dev, "unexpected reserved memory\n");
121 return -EINVAL;
122 }
123
124 if (rmem->size < sizeof(struct kernel_all_info)) {
125 dev_warn(&pdev->dev, "unexpected reserved memory size\n");
126 return -EINVAL;
127 }
128
129 all_info_addr = rmem->priv;
130 all_info_size = rmem->size;
131
132 memset(all_info_addr, 0, sizeof(struct kernel_all_info));
133 all_info = (struct kernel_all_info *)all_info_addr;
134 info = &(all_info->info);
135 info->enabled_all = IS_ENABLED(CONFIG_KALLSYMS_ALL);
136 info->enabled_base_relative = IS_ENABLED(CONFIG_KALLSYMS_BASE_RELATIVE);
137 info->enabled_absolute_percpu = IS_ENABLED(CONFIG_KALLSYMS_ABSOLUTE_PERCPU);
138 info->enabled_cfi_clang = IS_ENABLED(CONFIG_CFI_CLANG);
139 info->num_syms = kallsyms_num_syms;
140 info->name_len = KSYM_NAME_LEN;
141 info->bit_per_long = BITS_PER_LONG;
142 info->module_name_len = MODULE_NAME_LEN;
143 info->symbol_len = KSYM_SYMBOL_LEN;
144 if (!info->enabled_base_relative)
145 info->_addresses_pa = (u64)__pa_symbol((volatile void *)kallsyms_addresses);
146 else {
147 info->_relative_pa = (u64)__pa_symbol((volatile void *)kallsyms_relative_base);
148 info->_offsets_pa = (u64)__pa_symbol((volatile void *)kallsyms_offsets);
149 }
150 info->_stext_pa = (u64)__pa_symbol(_stext);
151 info->_etext_pa = (u64)__pa_symbol(_etext);
152 info->_sinittext_pa = (u64)__pa_symbol(_sinittext);
153 info->_einittext_pa = (u64)__pa_symbol(_einittext);
154 info->_end_pa = (u64)__pa_symbol(_end);
155 info->_names_pa = (u64)__pa_symbol((volatile void *)kallsyms_names);
156 info->_token_table_pa = (u64)__pa_symbol((volatile void *)kallsyms_token_table);
157 info->_token_index_pa = (u64)__pa_symbol((volatile void *)kallsyms_token_index);
158 info->_markers_pa = (u64)__pa_symbol((volatile void *)kallsyms_markers);
159 info->thread_size = THREAD_SIZE;
160 info->swapper_pg_dir_pa = (u64)__pa_symbol(swapper_pg_dir);
161 strlcpy(info->last_uts_release, init_utsname()->release, sizeof(info->last_uts_release));
162 info->enabled_modules_tree_lookup = IS_ENABLED(CONFIG_MODULES_TREE_LOOKUP);
163 info->mod_core_layout_offset = offsetof(struct module, core_layout);
164 info->mod_init_layout_offset = offsetof(struct module, init_layout);
165 info->mod_kallsyms_offset = offsetof(struct module, kallsyms);
166 #if defined(CONFIG_RANDOMIZE_BASE) && defined(MODULES_VSIZE)
167 info->module_start_va = module_alloc_base;
168 info->module_end_va = info->module_start_va + MODULES_VSIZE;
169 #elif defined(CONFIG_MODULES) && defined(MODULES_VADDR)
170 info->module_start_va = MODULES_VADDR;
171 info->module_end_va = MODULES_END;
172 #else
173 info->module_start_va = VMALLOC_START;
174 info->module_end_va = VMALLOC_END;
175 #endif
176 info->enabled_module_scmversion = IS_ENABLED(CONFIG_MODULE_SCMVERSION);
177 info->mod_scmversion_offset = offsetof(struct module, scmversion);
178 update_kernel_all_info(all_info);
179
180 return 0;
181 }
182
183 static const struct of_device_id debug_kinfo_of_match[] = {
184 { .compatible = "google,debug-kinfo" },
185 {},
186 };
187 MODULE_DEVICE_TABLE(of, debug_kinfo_of_match);
188
189 static struct platform_driver debug_kinfo_driver = {
190 .probe = debug_kinfo_probe,
191 .driver = {
192 .name = "debug-kinfo",
193 .of_match_table = of_match_ptr(debug_kinfo_of_match),
194 },
195 };
196 module_platform_driver(debug_kinfo_driver);
197
198 MODULE_AUTHOR("Jone Chou <jonechou@google.com>");
199 MODULE_DESCRIPTION("Debug Kinfo Driver");
200 MODULE_LICENSE("GPL v2");
201