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 /* These pointers should always be NULL when no helper module is loaded */
50 release_list((struct starts_with_next
*) reloc_namevals
);
51 release_list((struct starts_with_next
*) reloc_addrmaps
);
52 release_list((struct starts_with_next
*) safety_records
);
56 ksplice_do_helper(void)
58 struct ksplice_size
*s
;
59 int i
, record_count
= 0, ret
;
61 int numfinished
, oldfinished
= 0;
62 int restart_count
= 0, stage
= 1;
64 if (process_ksplice_relocs(1) != 0)
67 for (s
= &ksplice_sizes
; s
->name
!= NULL
; s
++) {
71 /* old kernels do not have kcalloc */
72 finished
= ksplice_kcalloc(record_count
);
75 for (s
= &ksplice_sizes
, i
= 0; s
->name
!= NULL
; s
++, i
++) {
81 ret
= search_for_match(s
, &stage
);
85 } else if (ret
== 0) {
91 for (i
= 0; i
< record_count
; i
++) {
95 if (numfinished
== record_count
) {
100 if (oldfinished
== numfinished
) {
105 print_abort("run-pre: could not match some sections");
109 oldfinished
= numfinished
;
111 if (restart_count
< 20) {
115 print_abort("run-pre: restart limit exceeded");
120 /* old kernels do not have kcalloc */
122 ksplice_kcalloc(int size
)
124 char *mem
= kmalloc(size
, GFP_KERNEL
);
126 for (i
= 0; i
< size
; i
++) {
133 search_for_match(struct ksplice_size
*s
, int *stage
)
137 struct ansglob
*glob
= NULL
, *g
;
139 for (i
= 0; i
< s
->num_sym_addrs
; i
++) {
140 add2glob(&glob
, s
->sym_addrs
[i
]);
143 compute_address(s
->name
, &glob
);
144 if (*stage
<= 1 && !singular(glob
)) {
150 printk("ksplice_h: run-pre: starting sect search for %s\n",
154 for (g
= glob
; g
!= NULL
; g
= g
->next
) {
158 if (try_addr(s
, run_addr
, s
->thismod_addr
, !singular(glob
))) {
170 brute_search_all_mods(s
);
176 try_addr(struct ksplice_size
*s
, long run_addr
, long pre_addr
,
179 struct safety_record
*tmp
;
181 if (run_pre_cmp(run_addr
, pre_addr
, s
->size
, 0) != 0) {
182 set_temp_myst_relocs(NOVAL
);
184 printk("ksplice_h: run-pre: sect %s does not match ",
186 printk("(r_a=%08lx p_a=%08lx s=%ld)\n",
187 run_addr
, pre_addr
, s
->size
);
188 printk("ksplice_h: run-pre: ");
189 run_pre_cmp(run_addr
, pre_addr
, s
->size
, 1);
193 set_temp_myst_relocs(VAL
);
196 printk("ksplice_h: run-pre: found sect %s=%08lx\n",
200 tmp
= kmalloc(sizeof (*tmp
), GFP_KERNEL
);
201 tmp
->addr
= run_addr
;
203 tmp
->next
= safety_records
;
205 safety_records
= tmp
;
207 if (create_nameval
) {
208 struct reloc_nameval
*nv
= find_nameval(s
->name
, 1);
219 run_pre_cmp(long run_addr
, long pre_addr
, int size
, int rerun
)
221 int run_o
, pre_o
, lenient
= 0, prev_c3
= 0, recent_5b
= 0;
222 unsigned char run
, pre
;
223 struct reloc_addrmap
*map
;
228 for (run_o
= 0, pre_o
= 0; run_o
< size
&& pre_o
< size
;
237 if (!virtual_address_mapped(run_addr
+ run_o
))
239 run
= *(unsigned char *) (run_addr
+ run_o
);
240 pre
= *(unsigned char *) (pre_addr
+ pre_o
);
243 printk("%02x/%02x ", run
, pre
);
246 if ((map
= find_addrmap(pre_addr
+ pre_o
)) != NULL
) {
247 if (handle_myst_reloc
248 (pre_addr
, &pre_o
, run_addr
, &run_o
,
258 lenient
= max(jumplen
[pre
] + 1, lenient
);
259 if (match_nop(run_addr
, &run_o
, &pre_o
) ||
260 match_nop(pre_addr
, &pre_o
, &run_o
))
265 if ((map
= find_addrmap(pre_addr
+ pre_o
)) != NULL
) {
266 if (handle_myst_reloc
267 (pre_addr
, &pre_o
, run_addr
, &run_o
, map
,
272 if (prev_c3
&& recent_5b
)
274 if (match_nop(run_addr
, &run_o
, &pre_o
) ||
275 match_nop(pre_addr
, &pre_o
, &run_o
))
277 if (jumplen
[run
] && jumplen
[pre
]) {
278 run_o
+= jumplen
[run
];
279 pre_o
+= jumplen
[pre
];
285 printk("[p_o=%08x] ! %02x/%02x %02x/%02x",
287 *(unsigned char *) (run_addr
+ run_o
+ 1),
288 *(unsigned char *) (pre_addr
+ pre_o
+ 1),
289 *(unsigned char *) (run_addr
+ run_o
+ 2),
290 *(unsigned char *) (pre_addr
+ pre_o
+ 2));
298 handle_myst_reloc(long pre_addr
, int *pre_o
, long run_addr
,
299 int *run_o
, struct reloc_addrmap
*map
, int rerun
)
302 int offset
= (int) (pre_addr
+ *pre_o
- map
->addr
);
303 int run_reloc
= *(int *) (run_addr
+ *run_o
- offset
);
305 if (debug
>= 3 && !rerun
) {
306 printk("ksplice_h: run-pre: reloc at r_a=%08lx p_o=%08x: ",
308 printk("%s=%08lx (A=%08lx *r=%08x)\n",
309 map
->nameval
->name
, map
->nameval
->val
,
310 map
->addend
, run_reloc
);
313 if (!starts_with(map
->nameval
->name
, ".rodata.str")) {
314 expected
= run_reloc
- map
->addend
;
315 if (run_reloc
== 0x77777777)
317 if (map
->flags
& PCREL
)
318 expected
+= run_addr
+ *run_o
- offset
;
319 if (map
->nameval
->status
== NOVAL
) {
320 map
->nameval
->val
= expected
;
321 map
->nameval
->status
= TEMP
;
322 } else if (map
->nameval
->val
!= expected
) {
325 printk("ksplice_h: pre-run reloc: Expected %s=%08x!\n",
326 map
->nameval
->name
, expected
);
331 *pre_o
+= 4 - offset
- 1;
332 *run_o
+= 4 - offset
- 1;
336 /* TODO: The recommended way to pad 64bit code is to use NOPs preceded by
337 maximally four 0x66 prefixes. */
339 match_nop(long addr
, int *o
, int *other_o
)
342 for (i
= NUM_NOPS
- 1; i
>= 0; i
--) {
343 for (j
= 0; j
< i
+ 1; j
++) {
344 if (!virtual_address_mapped(addr
+ *o
+ j
))
346 if (*(unsigned char *) (addr
+ *o
+ j
) != nops
[i
][j
])
360 brute_search_all_mods(struct ksplice_size
*s
)
363 list_for_each_entry(m
, &(THIS_MODULE
->list
), list
) {
364 if (!starts_with(m
->name
, ksplice_name
)
365 && !ends_with(m
->name
, "_helper")) {
366 if (brute_search(s
, m
->module_core
, m
->core_size
) == 0)
368 if (brute_search(s
, m
->module_init
, m
->init_size
) == 0)