1 /* Copyright (C) 2008 Jeffrey Brian Arnold <jbarnold@mit.edu>
3 * This program is free software; you can redistribute it and/or modify
4 * it under the terms of the GNU General Public License, version 2.
6 * This program is distributed in the hope that it will be useful,
7 * but WITHOUT ANY WARRANTY; without even the implied warranty of
8 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
9 * GNU General Public License for more details.
11 * You should have received a copy of the GNU General Public License
12 * along with this program; if not, write to the Free Software
13 * Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston, MA
17 #include "modcommon.h"
21 #include <linux/kthread.h>
23 /* defined by modcommon.c */
26 /* defined by ksplice-create */
27 extern struct ksplice_size ksplice_sizes
;
30 #define max(a, b) ((a) > (b) ? (a) : (b))
34 printk("ksplice_h: Preparing and checking %s\n", ksplice_name
);
36 if (ksplice_do_helper() != 0)
39 if (ksplice_do_primary() != 0)
45 void cleanup_module(void)
47 clear_list(&reloc_namevals
, struct reloc_nameval
, list
);
48 clear_list(&reloc_addrmaps
, struct reloc_addrmap
, list
);
49 if (ksplice_state
== KSPLICE_PREPARING
)
50 clear_list(&safety_records
, struct safety_record
, list
);
53 int ksplice_do_helper(void)
55 struct ksplice_size
*s
;
56 int i
, record_count
= 0, ret
;
58 int numfinished
, oldfinished
= 0;
59 int restart_count
= 0, stage
= 1;
61 if (process_ksplice_relocs(1) != 0)
64 for (s
= &ksplice_sizes
; s
->name
!= NULL
; s
++) {
68 /* old kernels do not have kcalloc */
69 finished
= ksplice_kcalloc(record_count
);
72 for (s
= &ksplice_sizes
, i
= 0; s
->name
!= NULL
; s
++, i
++) {
78 ret
= search_for_match(s
, &stage
);
82 } else if (ret
== 0) {
88 for (i
= 0; i
< record_count
; i
++) {
92 if (numfinished
== record_count
) {
97 if (oldfinished
== numfinished
) {
102 print_abort("run-pre: could not match some sections");
106 oldfinished
= numfinished
;
108 if (restart_count
< 20) {
112 print_abort("run-pre: restart limit exceeded");
117 /* old kernels do not have kcalloc */
118 void *ksplice_kcalloc(int size
)
120 char *mem
= kmalloc(size
, GFP_KERNEL
);
122 for (i
= 0; i
< size
; i
++) {
128 int search_for_match(struct ksplice_size
*s
, int *stage
)
133 struct candidate_val
*v
;
135 for (i
= 0; i
< s
->num_sym_addrs
; i
++) {
136 add_candidate_val(&vals
, s
->sym_addrs
[i
]);
139 compute_address(s
->name
, &vals
);
140 if (*stage
<= 1 && !singular(&vals
)) {
146 printk("ksplice_h: run-pre: starting sect search for %s\n",
150 list_for_each_entry(v
, &vals
, list
) {
154 if (try_addr(s
, run_addr
, s
->thismod_addr
, !singular(&vals
))) {
166 brute_search_all_mods(s
);
172 try_addr(struct ksplice_size
*s
, long run_addr
, long pre_addr
,
175 struct safety_record
*tmp
;
177 if (run_pre_cmp(run_addr
, pre_addr
, s
->size
, 0) != 0) {
178 set_temp_myst_relocs(NOVAL
);
180 printk("ksplice_h: run-pre: sect %s does not match ",
182 printk("(r_a=%08lx p_a=%08lx s=%ld)\n",
183 run_addr
, pre_addr
, s
->size
);
184 printk("ksplice_h: run-pre: ");
185 run_pre_cmp(run_addr
, pre_addr
, s
->size
, 1);
189 set_temp_myst_relocs(VAL
);
192 printk("ksplice_h: run-pre: found sect %s=%08lx\n",
196 tmp
= kmalloc(sizeof(*tmp
), GFP_KERNEL
);
197 tmp
->addr
= run_addr
;
200 list_add(&tmp
->list
, &safety_records
);
202 if (create_nameval
) {
203 struct reloc_nameval
*nv
= find_nameval(s
->name
, 1);
213 int run_pre_cmp(long run_addr
, long pre_addr
, int size
, int rerun
)
215 int run_o
= 0, pre_o
= 0, lenient
= 0, prev_c3
= 0, recent_5b
= 0;
216 unsigned char run
, pre
;
217 struct reloc_addrmap
*map
;
222 while (run_o
< size
&& pre_o
< size
) {
230 if (!virtual_address_mapped(run_addr
+ run_o
))
233 if ((map
= find_addrmap(pre_addr
+ pre_o
)) != NULL
) {
234 if (handle_myst_reloc
235 (pre_addr
, &pre_o
, run_addr
, &run_o
, map
,
241 if (match_nop(run_addr
, &run_o
) || match_nop(pre_addr
, &pre_o
))
244 run
= *(unsigned char *)(run_addr
+ run_o
);
245 pre
= *(unsigned char *)(pre_addr
+ pre_o
);
248 printk("%02x/%02x ", run
, pre
);
256 lenient
= max(jumplen
[pre
] + 1, lenient
);
261 if (prev_c3
&& recent_5b
)
263 if (jumplen
[run
] && jumplen
[pre
]) {
264 run_o
+= 1 + jumplen
[run
];
265 pre_o
+= 1 + jumplen
[pre
];
273 printk("[p_o=%08x] ! %02x/%02x %02x/%02x",
275 *(unsigned char *)(run_addr
+ run_o
+ 1),
276 *(unsigned char *)(pre_addr
+ pre_o
+ 1),
277 *(unsigned char *)(run_addr
+ run_o
+ 2),
278 *(unsigned char *)(pre_addr
+ pre_o
+ 2));
286 handle_myst_reloc(long pre_addr
, int *pre_o
, long run_addr
,
287 int *run_o
, struct reloc_addrmap
*map
, int rerun
)
290 int offset
= (int)(pre_addr
+ *pre_o
- map
->addr
);
293 run_reloc_addr
= run_addr
+ *run_o
- offset
;
294 if (map
->size
== 4) {
295 run_reloc
= *(int *)run_reloc_addr
;
296 } else if (map
->size
== 8) {
297 run_reloc
= *(long long *)run_reloc_addr
;
302 if (debug
>= 3 && !rerun
) {
303 printk("ksplice_h: run-pre: reloc at r_a=%08lx p_o=%08x: ",
305 printk("%s=%08lx (A=%08lx *r=%08lx)\n",
306 map
->nameval
->name
, map
->nameval
->val
,
307 map
->addend
, run_reloc
);
310 if (!starts_with(map
->nameval
->name
, ".rodata.str")) {
311 expected
= run_reloc
- map
->addend
;
312 if ((int)run_reloc
== 0x77777777)
314 if (map
->flags
& PCREL
)
315 expected
+= run_reloc_addr
;
316 if (map
->nameval
->status
== NOVAL
) {
317 map
->nameval
->val
= expected
;
318 map
->nameval
->status
= TEMP
;
319 } else if (map
->nameval
->val
!= expected
) {
322 printk("ksplice_h: pre-run reloc: Expected %s=%08x!\n",
323 map
->nameval
->name
, expected
);
328 *pre_o
+= map
->size
- offset
;
329 *run_o
+= map
->size
- offset
;
333 /* TODO: The recommended way to pad 64bit code is to use NOPs preceded by
334 maximally four 0x66 prefixes. */
335 int match_nop(long addr
, int *o
)
338 for (i
= NUM_NOPS
- 1; i
>= 0; i
--) {
339 for (j
= 0; j
< i
+ 1; j
++) {
340 if (!virtual_address_mapped(addr
+ *o
+ j
))
342 if (*(unsigned char *)(addr
+ *o
+ j
) != nops
[i
][j
])
354 void brute_search_all_mods(struct ksplice_size
*s
)
357 list_for_each_entry(m
, &(THIS_MODULE
->list
), list
) {
358 if (!starts_with(m
->name
, ksplice_name
)
359 && !ends_with(m
->name
, "_helper")) {
360 if (brute_search(s
, m
->module_core
, m
->core_size
) == 0)
362 if (brute_search(s
, m
->module_init
, m
->init_size
) == 0)