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))
35 printk("ksplice_h: Preparing and checking %s\n", ksplice_name
);
37 if (ksplice_do_helper() != 0)
40 if (ksplice_do_primary() != 0)
49 clear_list(&reloc_namevals
, struct reloc_nameval
, list
);
50 clear_list(&reloc_addrmaps
, struct reloc_addrmap
, list
);
52 /* These pointers should always be NULL when no helper module is loaded */
53 release_list((struct starts_with_next
*) safety_records
);
57 ksplice_do_helper(void)
59 struct ksplice_size
*s
;
60 int i
, record_count
= 0, ret
;
62 int numfinished
, oldfinished
= 0;
63 int restart_count
= 0, stage
= 1;
65 if (process_ksplice_relocs(1) != 0)
68 for (s
= &ksplice_sizes
; s
->name
!= NULL
; s
++) {
72 /* old kernels do not have kcalloc */
73 finished
= ksplice_kcalloc(record_count
);
76 for (s
= &ksplice_sizes
, i
= 0; s
->name
!= NULL
; s
++, i
++) {
82 ret
= search_for_match(s
, &stage
);
86 } else if (ret
== 0) {
92 for (i
= 0; i
< record_count
; i
++) {
96 if (numfinished
== record_count
) {
101 if (oldfinished
== numfinished
) {
106 print_abort("run-pre: could not match some sections");
110 oldfinished
= numfinished
;
112 if (restart_count
< 20) {
116 print_abort("run-pre: restart limit exceeded");
121 /* old kernels do not have kcalloc */
123 ksplice_kcalloc(int size
)
125 char *mem
= kmalloc(size
, GFP_KERNEL
);
127 for (i
= 0; i
< size
; i
++) {
134 search_for_match(struct ksplice_size
*s
, int *stage
)
141 for (i
= 0; i
< s
->num_sym_addrs
; i
++) {
142 add2glob(&glob
, s
->sym_addrs
[i
]);
145 compute_address(s
->name
, &glob
);
146 if (*stage
<= 1 && !singular(&glob
)) {
152 printk("ksplice_h: run-pre: starting sect search for %s\n",
156 list_for_each_entry(g
, &glob
, list
) {
160 if (try_addr(s
, run_addr
, s
->thismod_addr
, !singular(&glob
))) {
172 brute_search_all_mods(s
);
178 try_addr(struct ksplice_size
*s
, long run_addr
, long pre_addr
,
181 struct safety_record
*tmp
;
183 if (run_pre_cmp(run_addr
, pre_addr
, s
->size
, 0) != 0) {
184 set_temp_myst_relocs(NOVAL
);
186 printk("ksplice_h: run-pre: sect %s does not match ",
188 printk("(r_a=%08lx p_a=%08lx s=%ld)\n",
189 run_addr
, pre_addr
, s
->size
);
190 printk("ksplice_h: run-pre: ");
191 run_pre_cmp(run_addr
, pre_addr
, s
->size
, 1);
195 set_temp_myst_relocs(VAL
);
198 printk("ksplice_h: run-pre: found sect %s=%08lx\n",
202 tmp
= kmalloc(sizeof (*tmp
), GFP_KERNEL
);
203 tmp
->addr
= run_addr
;
205 tmp
->next
= safety_records
;
207 safety_records
= tmp
;
209 if (create_nameval
) {
210 struct reloc_nameval
*nv
= find_nameval(s
->name
, 1);
221 run_pre_cmp(long run_addr
, long pre_addr
, int size
, int rerun
)
223 int run_o
, pre_o
, lenient
= 0, prev_c3
= 0, recent_5b
= 0;
224 unsigned char run
, pre
;
225 struct reloc_addrmap
*map
;
230 for (run_o
= 0, pre_o
= 0; run_o
< size
&& pre_o
< size
;
239 if (!virtual_address_mapped(run_addr
+ run_o
))
241 run
= *(unsigned char *) (run_addr
+ run_o
);
242 pre
= *(unsigned char *) (pre_addr
+ pre_o
);
245 printk("%02x/%02x ", run
, pre
);
248 if ((map
= find_addrmap(pre_addr
+ pre_o
)) != NULL
) {
249 if (handle_myst_reloc
250 (pre_addr
, &pre_o
, run_addr
, &run_o
,
260 lenient
= max(jumplen
[pre
] + 1, lenient
);
261 if (match_nop(run_addr
, &run_o
, &pre_o
) ||
262 match_nop(pre_addr
, &pre_o
, &run_o
))
267 if ((map
= find_addrmap(pre_addr
+ pre_o
)) != NULL
) {
268 if (handle_myst_reloc
269 (pre_addr
, &pre_o
, run_addr
, &run_o
, map
,
274 if (prev_c3
&& recent_5b
)
276 if (match_nop(run_addr
, &run_o
, &pre_o
) ||
277 match_nop(pre_addr
, &pre_o
, &run_o
))
279 if (jumplen
[run
] && jumplen
[pre
]) {
280 run_o
+= jumplen
[run
];
281 pre_o
+= jumplen
[pre
];
287 printk("[p_o=%08x] ! %02x/%02x %02x/%02x",
289 *(unsigned char *) (run_addr
+ run_o
+ 1),
290 *(unsigned char *) (pre_addr
+ pre_o
+ 1),
291 *(unsigned char *) (run_addr
+ run_o
+ 2),
292 *(unsigned char *) (pre_addr
+ pre_o
+ 2));
300 handle_myst_reloc(long pre_addr
, int *pre_o
, long run_addr
,
301 int *run_o
, struct reloc_addrmap
*map
, int rerun
)
304 int offset
= (int) (pre_addr
+ *pre_o
- map
->addr
);
305 int run_reloc
= *(int *) (run_addr
+ *run_o
- offset
);
307 if (debug
>= 3 && !rerun
) {
308 printk("ksplice_h: run-pre: reloc at r_a=%08lx p_o=%08x: ",
310 printk("%s=%08lx (A=%08lx *r=%08x)\n",
311 map
->nameval
->name
, map
->nameval
->val
,
312 map
->addend
, run_reloc
);
315 if (!starts_with(map
->nameval
->name
, ".rodata.str")) {
316 expected
= run_reloc
- map
->addend
;
317 if (run_reloc
== 0x77777777)
319 if (map
->flags
& PCREL
)
320 expected
+= run_addr
+ *run_o
- offset
;
321 if (map
->nameval
->status
== NOVAL
) {
322 map
->nameval
->val
= expected
;
323 map
->nameval
->status
= TEMP
;
324 } else if (map
->nameval
->val
!= expected
) {
327 printk("ksplice_h: pre-run reloc: Expected %s=%08x!\n",
328 map
->nameval
->name
, expected
);
333 *pre_o
+= 4 - offset
- 1;
334 *run_o
+= 4 - offset
- 1;
338 /* TODO: The recommended way to pad 64bit code is to use NOPs preceded by
339 maximally four 0x66 prefixes. */
341 match_nop(long addr
, int *o
, int *other_o
)
344 for (i
= NUM_NOPS
- 1; i
>= 0; i
--) {
345 for (j
= 0; j
< i
+ 1; j
++) {
346 if (!virtual_address_mapped(addr
+ *o
+ j
))
348 if (*(unsigned char *) (addr
+ *o
+ j
) != nops
[i
][j
])
362 brute_search_all_mods(struct ksplice_size
*s
)
365 list_for_each_entry(m
, &(THIS_MODULE
->list
), list
) {
366 if (!starts_with(m
->name
, ksplice_name
)
367 && !ends_with(m
->name
, "_helper")) {
368 if (brute_search(s
, m
->module_core
, m
->core_size
) == 0)
370 if (brute_search(s
, m
->module_init
, m
->init_size
) == 0)