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
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
|
// SPDX-License-Identifier: GPL-2.0
/* Copyright 2018 Google, Inc.
*
* This software is licensed under the terms of the GNU General Public
* License version 2, as published by the Free Software Foundation, and
* may be copied, distributed, and modified under those terms.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*/
#include <linux/slab.h>
#include <linux/kallsyms.h>
#include <linux/module.h>
#include <linux/io.h>
#include <linux/of_address.h>
#include <linux/bldr_debug_tools.h>
#include <linux/utsname.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 long kallsyms_num_syms
__attribute__((weak, section(".rodata")));
extern const unsigned long kallsyms_relative_base
__attribute__((weak, section(".rodata")));
extern const u8 kallsyms_token_table[] __weak;
extern const u16 kallsyms_token_index[] __weak;
extern const unsigned long kallsyms_markers[] __weak;
static phys_addr_t all_info_addr;
/*
* 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;
phys_addr_t _addresses_va;
phys_addr_t _relative_va;
phys_addr_t _stext_va;
phys_addr_t _etext_va;
phys_addr_t _sinittext_va;
phys_addr_t _einittext_va;
phys_addr_t _end_va;
phys_addr_t _offsets_va;
phys_addr_t _names_va;
phys_addr_t _token_table_va;
phys_addr_t _token_index_va;
phys_addr_t _markers_va;
/* For frame pointer */
u32 thread_size;
/* For virt_to_phys */
u32 va_bits;
u64 page_offset;
u64 phys_offset;
u64 swapper_pg_dir;
u64 kimage_voffset;
/* For linux banner */
u8 last_uts_release[__NEW_UTS_LEN];
/* Info of running build */
char build_info[32];
} __packed;
struct kernel_all_info {
u32 magic_number;
u32 combined_checksum;
struct kernel_info info;
} __packed;
static void update_all_info_toio(void __iomem *io_base,
struct kernel_all_info *all_info)
{
int index;
struct kernel_info *info;
u32 *checksum_info;
all_info->magic_number = BOOT_DEBUG_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];
memcpy_toio(io_base, all_info, sizeof(*all_info));
}
static void backup_kernel_info(void)
{
struct device_node *np;
struct resource res;
struct kernel_all_info all_info;
struct kernel_info *info;
void __iomem *imem_base;
int num_reg = 0;
int ret;
np = of_find_compatible_node(NULL, NULL, "msm-imem-kernel_info");
if (!np) {
pr_warn("%s: msm-imem-kernel_info node does not exist\n",
__func__);
return;
}
ret = of_address_to_resource(np, num_reg, &res);
if(ret) {
pr_warn("%s: invalid argument, ret %d\n", __func__, ret);
return;
}
if ((!res.start) ||
(resource_size(&res) < sizeof(struct kernel_all_info))) {
pr_warn("%s: unexpected resource start %llx and size %llx\n",
__func__, res.start, resource_size(&res));
return;
}
all_info_addr = res.start;
imem_base= ioremap(res.start, resource_size(&res));
if (!imem_base) {
pr_warn("%s: msm imem kernel info imem offset mapping failed\n",
__func__);
return;
}
memset(&all_info, 0, sizeof(all_info));
memset_io(imem_base, 0, resource_size(&res));
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_va = (phys_addr_t)kallsyms_addresses;
info->_relative_va = (phys_addr_t)kallsyms_relative_base;
info->_stext_va = (phys_addr_t)_stext;
info->_etext_va = (phys_addr_t)_etext;
info->_sinittext_va = (phys_addr_t)_sinittext;
info->_einittext_va = (phys_addr_t)_einittext;
info->_end_va = (phys_addr_t)_end;
info->_offsets_va = (phys_addr_t)kallsyms_offsets;
info->_names_va = (phys_addr_t)kallsyms_names;
info->_token_table_va = (phys_addr_t)kallsyms_token_table;
info->_token_index_va = (phys_addr_t)kallsyms_token_index;
info->_markers_va = (phys_addr_t)kallsyms_markers;
info->thread_size = THREAD_SIZE;
info->va_bits = VA_BITS;
info->page_offset = PAGE_OFFSET;
info->phys_offset = PHYS_OFFSET;
info->swapper_pg_dir = (u64)swapper_pg_dir;
info->kimage_voffset = kimage_voffset;
strlcpy(info->last_uts_release, init_utsname()->release,
sizeof(info->last_uts_release));
update_all_info_toio(imem_base, &all_info);
iounmap(imem_base);
}
static int build_info_set(const char *str, const struct kernel_param *kp)
{
void __iomem *imem_base;
struct kernel_all_info all_info;
const size_t build_info_size = sizeof(all_info.info.build_info);
if (all_info_addr == 0)
return -EPERM;
imem_base = ioremap(all_info_addr, sizeof(all_info));
if (!imem_base) {
pr_err("%s: Failed to map all_info\n", __func__);
return -EPERM;
}
memcpy_fromio(&all_info, imem_base, sizeof(all_info));
memcpy(&all_info.info.build_info, str,
min(build_info_size, strlen(str)));
update_all_info_toio(imem_base, &all_info);
iounmap(imem_base);
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);
return -ENOMEM;
}
return 0;
}
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 kdebuginfo.");
static int __init kdebuginfo_init(void)
{
/* Backup kernel information for bootloader */
backup_kernel_info();
return 0;
}
device_initcall(kdebuginfo_init);
MODULE_LICENSE("GPL v2");
MODULE_DESCRIPTION("Append bootloader log to ramoops");
|