1 /******************************************************************************
2 * linux/arch/ia64/xen/paravirt_patch.c
4 * Copyright (c) 2008 Isaku Yamahata <yamahata at valinux co jp>
5 * VA Linux Systems Japan K.K.
7 * This program is free software; you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License as published by
9 * the Free Software Foundation; either version 2 of the License, or
10 * (at your option) any later version.
12 * This program is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 * GNU General Public License for more details.
17 * You should have received a copy of the GNU General Public License
18 * along with this program; if not, write to the Free Software
19 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
23 #include <linux/init.h>
24 #include <asm/intrinsics.h>
25 #include <asm/kprobes.h>
26 #include <asm/paravirt.h>
27 #include <asm/paravirt_patch.h>
29 typedef union ia64_inst
{
31 unsigned long long qp
: 6;
32 unsigned long long : 31;
33 unsigned long long opcode
: 4;
34 unsigned long long reserved
: 23;
40 * flush_icache_range() can't be used here.
41 * we are here before cpu_init() which initializes
42 * ia64_i_cache_stride_shift. flush_icache_range() uses it.
45 paravirt_flush_i_cache_range(const void *instr
, unsigned long size
)
47 extern void paravirt_fc_i(const void *addr
);
50 for (i
= 0; i
< size
; i
+= sizeof(bundle_t
))
51 paravirt_fc_i(instr
+ i
);
54 bundle_t
* __init_or_module
55 paravirt_get_bundle(unsigned long tag
)
57 return (bundle_t
*)(tag
& ~3UL);
60 unsigned long __init_or_module
61 paravirt_get_slot(unsigned long tag
)
66 unsigned long __init_or_module
67 paravirt_get_num_inst(unsigned long stag
, unsigned long etag
)
69 bundle_t
*sbundle
= paravirt_get_bundle(stag
);
70 unsigned long sslot
= paravirt_get_slot(stag
);
71 bundle_t
*ebundle
= paravirt_get_bundle(etag
);
72 unsigned long eslot
= paravirt_get_slot(etag
);
74 return (ebundle
- sbundle
) * 3 + eslot
- sslot
+ 1;
77 unsigned long __init_or_module
78 paravirt_get_next_tag(unsigned long tag
)
80 unsigned long slot
= paravirt_get_slot(tag
);
87 bundle_t
*bundle
= paravirt_get_bundle(tag
);
88 return (unsigned long)(bundle
+ 1);
96 ia64_inst_t __init_or_module
97 paravirt_read_slot0(const bundle_t
*bundle
)
100 inst
.l
= bundle
->quad0
.slot0
;
104 ia64_inst_t __init_or_module
105 paravirt_read_slot1(const bundle_t
*bundle
)
108 inst
.l
= bundle
->quad0
.slot1_p0
|
109 ((unsigned long long)bundle
->quad1
.slot1_p1
<< 18UL);
113 ia64_inst_t __init_or_module
114 paravirt_read_slot2(const bundle_t
*bundle
)
117 inst
.l
= bundle
->quad1
.slot2
;
121 ia64_inst_t __init_or_module
122 paravirt_read_inst(unsigned long tag
)
124 bundle_t
*bundle
= paravirt_get_bundle(tag
);
125 unsigned long slot
= paravirt_get_slot(tag
);
129 return paravirt_read_slot0(bundle
);
131 return paravirt_read_slot1(bundle
);
133 return paravirt_read_slot2(bundle
);
140 void __init_or_module
141 paravirt_write_slot0(bundle_t
*bundle
, ia64_inst_t inst
)
143 bundle
->quad0
.slot0
= inst
.l
;
146 void __init_or_module
147 paravirt_write_slot1(bundle_t
*bundle
, ia64_inst_t inst
)
149 bundle
->quad0
.slot1_p0
= inst
.l
;
150 bundle
->quad1
.slot1_p1
= inst
.l
>> 18UL;
153 void __init_or_module
154 paravirt_write_slot2(bundle_t
*bundle
, ia64_inst_t inst
)
156 bundle
->quad1
.slot2
= inst
.l
;
159 void __init_or_module
160 paravirt_write_inst(unsigned long tag
, ia64_inst_t inst
)
162 bundle_t
*bundle
= paravirt_get_bundle(tag
);
163 unsigned long slot
= paravirt_get_slot(tag
);
167 paravirt_write_slot0(bundle
, inst
);
170 paravirt_write_slot1(bundle
, inst
);
173 paravirt_write_slot2(bundle
, inst
);
179 paravirt_flush_i_cache_range(bundle
, sizeof(*bundle
));
184 paravirt_print_bundle(const bundle_t
*bundle
)
186 const unsigned long *quad
= (const unsigned long *)bundle
;
187 ia64_inst_t slot0
= paravirt_read_slot0(bundle
);
188 ia64_inst_t slot1
= paravirt_read_slot1(bundle
);
189 ia64_inst_t slot2
= paravirt_read_slot2(bundle
);
192 "bundle 0x%p 0x%016lx 0x%016lx\n", bundle
, quad
[0], quad
[1]);
194 "bundle template 0x%x\n",
195 bundle
->quad0
.template);
197 "slot0 0x%lx slot1_p0 0x%lx slot1_p1 0x%lx slot2 0x%lx\n",
198 (unsigned long)bundle
->quad0
.slot0
,
199 (unsigned long)bundle
->quad0
.slot1_p0
,
200 (unsigned long)bundle
->quad1
.slot1_p1
,
201 (unsigned long)bundle
->quad1
.slot2
);
203 "slot0 0x%016llx slot1 0x%016llx slot2 0x%016llx\n",
204 slot0
.l
, slot1
.l
, slot2
.l
);
207 static int noreplace_paravirt __init_or_module
= 0;
209 static int __init
setup_noreplace_paravirt(char *str
)
211 noreplace_paravirt
= 1;
214 __setup("noreplace-paravirt", setup_noreplace_paravirt
);
217 static void __init_or_module
218 fill_nop_bundle(void *sbundle
, void *ebundle
)
220 extern const char paravirt_nop_bundle
[];
221 extern const unsigned long paravirt_nop_bundle_size
;
223 void *bundle
= sbundle
;
225 BUG_ON((((unsigned long)sbundle
) % sizeof(bundle_t
)) != 0);
226 BUG_ON((((unsigned long)ebundle
) % sizeof(bundle_t
)) != 0);
228 while (bundle
< ebundle
) {
229 memcpy(bundle
, paravirt_nop_bundle
, paravirt_nop_bundle_size
);
231 bundle
+= paravirt_nop_bundle_size
;
235 /* helper function */
236 unsigned long __init_or_module
237 __paravirt_patch_apply_bundle(void *sbundle
, void *ebundle
, unsigned long type
,
238 const struct paravirt_patch_bundle_elem
*elems
,
239 unsigned long nelems
,
240 const struct paravirt_patch_bundle_elem
**found
)
242 unsigned long used
= 0;
245 BUG_ON((((unsigned long)sbundle
) % sizeof(bundle_t
)) != 0);
246 BUG_ON((((unsigned long)ebundle
) % sizeof(bundle_t
)) != 0);
249 for (i
= 0; i
< nelems
; i
++) {
250 const struct paravirt_patch_bundle_elem
*p
= &elems
[i
];
251 if (p
->type
== type
) {
252 unsigned long need
= p
->ebundle
- p
->sbundle
;
253 unsigned long room
= ebundle
- sbundle
;
259 /* no room to replace. skip it */
261 "the space is too small to put "
262 "bundles. type %ld need %ld room %ld\n",
268 memcpy(sbundle
, p
->sbundle
, used
);
276 void __init_or_module
277 paravirt_patch_apply_bundle(const struct paravirt_patch_site_bundle
*start
,
278 const struct paravirt_patch_site_bundle
*end
)
280 const struct paravirt_patch_site_bundle
*p
;
282 if (noreplace_paravirt
)
284 if (pv_init_ops
.patch_bundle
== NULL
)
287 for (p
= start
; p
< end
; p
++) {
290 used
= (*pv_init_ops
.patch_bundle
)(p
->sbundle
, p
->ebundle
,
295 fill_nop_bundle(p
->sbundle
+ used
, p
->ebundle
);
296 paravirt_flush_i_cache_range(p
->sbundle
,
297 p
->ebundle
- p
->sbundle
);
304 * nop.i, nop.m, nop.f instruction are same format.
305 * but nop.b has differennt format.
306 * This doesn't support nop.b for now.
308 static void __init_or_module
309 fill_nop_inst(unsigned long stag
, unsigned long etag
)
311 extern const bundle_t paravirt_nop_mfi_inst_bundle
[];
313 const ia64_inst_t nop_inst
=
314 paravirt_read_slot0(paravirt_nop_mfi_inst_bundle
);
316 for (tag
= stag
; tag
< etag
; tag
= paravirt_get_next_tag(tag
))
317 paravirt_write_inst(tag
, nop_inst
);
320 void __init_or_module
321 paravirt_patch_apply_inst(const struct paravirt_patch_site_inst
*start
,
322 const struct paravirt_patch_site_inst
*end
)
324 const struct paravirt_patch_site_inst
*p
;
326 if (noreplace_paravirt
)
328 if (pv_init_ops
.patch_inst
== NULL
)
331 for (p
= start
; p
< end
; p
++) {
336 tag
= (*pv_init_ops
.patch_inst
)(p
->stag
, p
->etag
, p
->type
);
340 fill_nop_inst(tag
, p
->etag
);
341 sbundle
= paravirt_get_bundle(p
->stag
);
342 ebundle
= paravirt_get_bundle(p
->etag
) + 1;
343 paravirt_flush_i_cache_range(sbundle
, (ebundle
- sbundle
) *
349 #endif /* ASM_SUPPOTED */
351 /* brl.cond.sptk.many <target64> X3 */
352 typedef union inst_x3_op
{
356 unsigned long btyp
: 3;
357 unsigned long unused
: 3;
359 unsigned long imm20b
: 20;
363 unsigned long opcode
: 4;
368 typedef union inst_x3_imm
{
371 unsigned long unused
: 2;
372 unsigned long imm39
: 39;
377 void __init_or_module
378 paravirt_patch_reloc_brl(unsigned long tag
, const void *target
)
380 unsigned long tag_op
= paravirt_get_next_tag(tag
);
381 unsigned long tag_imm
= tag
;
382 bundle_t
*bundle
= paravirt_get_bundle(tag
);
384 ia64_inst_t inst_op
= paravirt_read_inst(tag_op
);
385 ia64_inst_t inst_imm
= paravirt_read_inst(tag_imm
);
387 inst_x3_op_t inst_x3_op
= { .l
= inst_op
.l
};
388 inst_x3_imm_t inst_x3_imm
= { .l
= inst_imm
.l
};
390 unsigned long imm60
=
391 ((unsigned long)target
- (unsigned long)bundle
) >> 4;
393 BUG_ON(paravirt_get_slot(tag
) != 1); /* MLX */
394 BUG_ON(((unsigned long)target
& (sizeof(bundle_t
) - 1)) != 0);
397 inst_x3_op
.i
= (imm60
>> 59) & 1;
398 /* imm60[19:0] 20bit */
399 inst_x3_op
.imm20b
= imm60
& ((1UL << 20) - 1);
400 /* imm60[58:20] 39bit */
401 inst_x3_imm
.imm39
= (imm60
>> 20) & ((1UL << 39) - 1);
403 inst_op
.l
= inst_x3_op
.l
;
404 inst_imm
.l
= inst_x3_imm
.l
;
406 paravirt_write_inst(tag_op
, inst_op
);
407 paravirt_write_inst(tag_imm
, inst_imm
);
410 /* br.cond.sptk.many <target25> B1 */
411 typedef union inst_b1
{
415 unsigned long btype
: 3;
416 unsigned long unused
: 3;
418 unsigned long imm20b
: 20;
422 unsigned long opcode
: 4;
428 paravirt_patch_reloc_br(unsigned long tag
, const void *target
)
430 bundle_t
*bundle
= paravirt_get_bundle(tag
);
431 ia64_inst_t inst
= paravirt_read_inst(tag
);
432 unsigned long target25
= (unsigned long)target
- (unsigned long)bundle
;
435 BUG_ON(((unsigned long)target
& (sizeof(bundle_t
) - 1)) != 0);
438 if (target25
& (1UL << 63))
443 inst_b1
.imm20b
= target25
>> 4;
446 paravirt_write_inst(tag
, inst
);
450 __paravirt_patch_apply_branch(
451 unsigned long tag
, unsigned long type
,
452 const struct paravirt_patch_branch_target
*entries
,
453 unsigned int nr_entries
)
456 for (i
= 0; i
< nr_entries
; i
++) {
457 if (entries
[i
].type
== type
) {
458 paravirt_patch_reloc_br(tag
, entries
[i
].entry
);
465 paravirt_patch_apply_branch(const struct paravirt_patch_site_branch
*start
,
466 const struct paravirt_patch_site_branch
*end
)
468 const struct paravirt_patch_site_branch
*p
;
470 if (noreplace_paravirt
)
472 if (pv_init_ops
.patch_branch
== NULL
)
475 for (p
= start
; p
< end
; p
++)
476 (*pv_init_ops
.patch_branch
)(p
->tag
, p
->type
);
483 paravirt_patch_apply(void)
485 extern const char __start_paravirt_bundles
[];
486 extern const char __stop_paravirt_bundles
[];
487 extern const char __start_paravirt_insts
[];
488 extern const char __stop_paravirt_insts
[];
489 extern const char __start_paravirt_branches
[];
490 extern const char __stop_paravirt_branches
[];
492 paravirt_patch_apply_bundle((const struct paravirt_patch_site_bundle
*)
493 __start_paravirt_bundles
,
494 (const struct paravirt_patch_site_bundle
*)
495 __stop_paravirt_bundles
);
496 paravirt_patch_apply_inst((const struct paravirt_patch_site_inst
*)
497 __start_paravirt_insts
,
498 (const struct paravirt_patch_site_inst
*)
499 __stop_paravirt_insts
);
500 paravirt_patch_apply_branch((const struct paravirt_patch_site_branch
*)
501 __start_paravirt_branches
,
502 (const struct paravirt_patch_site_branch
*)
503 __stop_paravirt_branches
);
509 * c-set-style: "linux"
512 * indent-tabs-mode: t