• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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