OMAP3 SRAM: add more comments on the SRAM code
[linux-ginger.git] / arch / ia64 / kernel / paravirt_patch.c
blobbfdfef1b1ffd2c57e8920cebc924cd13a4880d32
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 {
30 struct {
31 unsigned long long qp : 6;
32 unsigned long long : 31;
33 unsigned long long opcode : 4;
34 unsigned long long reserved : 23;
35 } generic;
36 unsigned long long l;
37 } ia64_inst_t;
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.
44 void __init_or_module
45 paravirt_flush_i_cache_range(const void *instr, unsigned long size)
47 extern void paravirt_fc_i(const void *addr);
48 unsigned long i;
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)
63 return tag & 3UL;
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);
82 switch (slot) {
83 case 0:
84 case 1:
85 return tag + 1;
86 case 2: {
87 bundle_t *bundle = paravirt_get_bundle(tag);
88 return (unsigned long)(bundle + 1);
90 default:
91 BUG();
93 /* NOTREACHED */
96 ia64_inst_t __init_or_module
97 paravirt_read_slot0(const bundle_t *bundle)
99 ia64_inst_t inst;
100 inst.l = bundle->quad0.slot0;
101 return inst;
104 ia64_inst_t __init_or_module
105 paravirt_read_slot1(const bundle_t *bundle)
107 ia64_inst_t inst;
108 inst.l = bundle->quad0.slot1_p0 |
109 ((unsigned long long)bundle->quad1.slot1_p1 << 18UL);
110 return inst;
113 ia64_inst_t __init_or_module
114 paravirt_read_slot2(const bundle_t *bundle)
116 ia64_inst_t inst;
117 inst.l = bundle->quad1.slot2;
118 return inst;
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);
127 switch (slot) {
128 case 0:
129 return paravirt_read_slot0(bundle);
130 case 1:
131 return paravirt_read_slot1(bundle);
132 case 2:
133 return paravirt_read_slot2(bundle);
134 default:
135 BUG();
137 /* NOTREACHED */
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);
165 switch (slot) {
166 case 0:
167 paravirt_write_slot0(bundle, inst);
168 break;
169 case 1:
170 paravirt_write_slot1(bundle, inst);
171 break;
172 case 2:
173 paravirt_write_slot2(bundle, inst);
174 break;
175 default:
176 BUG();
177 break;
179 paravirt_flush_i_cache_range(bundle, sizeof(*bundle));
182 /* for debug */
183 void
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);
191 printk(KERN_DEBUG
192 "bundle 0x%p 0x%016lx 0x%016lx\n", bundle, quad[0], quad[1]);
193 printk(KERN_DEBUG
194 "bundle template 0x%x\n",
195 bundle->quad0.template);
196 printk(KERN_DEBUG
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);
202 printk(KERN_DEBUG
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;
212 return 1;
214 __setup("noreplace-paravirt", setup_noreplace_paravirt);
216 #ifdef ASM_SUPPORTED
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;
243 unsigned long i;
245 BUG_ON((((unsigned long)sbundle) % sizeof(bundle_t)) != 0);
246 BUG_ON((((unsigned long)ebundle) % sizeof(bundle_t)) != 0);
248 found = NULL;
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;
255 if (found != NULL)
256 *found = p;
258 if (room < need) {
259 /* no room to replace. skip it */
260 printk(KERN_DEBUG
261 "the space is too small to put "
262 "bundles. type %ld need %ld room %ld\n",
263 type, need, room);
264 break;
267 used = need;
268 memcpy(sbundle, p->sbundle, used);
269 break;
273 return 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)
283 return;
284 if (pv_init_ops.patch_bundle == NULL)
285 return;
287 for (p = start; p < end; p++) {
288 unsigned long used;
290 used = (*pv_init_ops.patch_bundle)(p->sbundle, p->ebundle,
291 p->type);
292 if (used == 0)
293 continue;
295 fill_nop_bundle(p->sbundle + used, p->ebundle);
296 paravirt_flush_i_cache_range(p->sbundle,
297 p->ebundle - p->sbundle);
299 ia64_sync_i();
300 ia64_srlz_i();
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[];
312 unsigned long tag;
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)
327 return;
328 if (pv_init_ops.patch_inst == NULL)
329 return;
331 for (p = start; p < end; p++) {
332 unsigned long tag;
333 bundle_t *sbundle;
334 bundle_t *ebundle;
336 tag = (*pv_init_ops.patch_inst)(p->stag, p->etag, p->type);
337 if (tag == p->stag)
338 continue;
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) *
344 sizeof(bundle_t));
346 ia64_sync_i();
347 ia64_srlz_i();
349 #endif /* ASM_SUPPOTED */
351 /* brl.cond.sptk.many <target64> X3 */
352 typedef union inst_x3_op {
353 ia64_inst_t inst;
354 struct {
355 unsigned long qp: 6;
356 unsigned long btyp: 3;
357 unsigned long unused: 3;
358 unsigned long p: 1;
359 unsigned long imm20b: 20;
360 unsigned long wh: 2;
361 unsigned long d: 1;
362 unsigned long i: 1;
363 unsigned long opcode: 4;
365 unsigned long l;
366 } inst_x3_op_t;
368 typedef union inst_x3_imm {
369 ia64_inst_t inst;
370 struct {
371 unsigned long unused: 2;
372 unsigned long imm39: 39;
374 unsigned long l;
375 } inst_x3_imm_t;
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);
396 /* imm60[59] 1bit */
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 {
412 ia64_inst_t inst;
413 struct {
414 unsigned long qp: 6;
415 unsigned long btype: 3;
416 unsigned long unused: 3;
417 unsigned long p: 1;
418 unsigned long imm20b: 20;
419 unsigned long wh: 2;
420 unsigned long d: 1;
421 unsigned long s: 1;
422 unsigned long opcode: 4;
424 unsigned long l;
425 } inst_b1_t;
427 void __init
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;
433 inst_b1_t inst_b1;
435 BUG_ON(((unsigned long)target & (sizeof(bundle_t) - 1)) != 0);
437 inst_b1.l = inst.l;
438 if (target25 & (1UL << 63))
439 inst_b1.s = 1;
440 else
441 inst_b1.s = 0;
443 inst_b1.imm20b = target25 >> 4;
444 inst.l = inst_b1.l;
446 paravirt_write_inst(tag, inst);
449 void __init
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)
455 unsigned int i;
456 for (i = 0; i < nr_entries; i++) {
457 if (entries[i].type == type) {
458 paravirt_patch_reloc_br(tag, entries[i].entry);
459 break;
464 static void __init
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)
471 return;
472 if (pv_init_ops.patch_branch == NULL)
473 return;
475 for (p = start; p < end; p++)
476 (*pv_init_ops.patch_branch)(p->tag, p->type);
478 ia64_sync_i();
479 ia64_srlz_i();
482 void __init
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);
507 * Local variables:
508 * mode: C
509 * c-set-style: "linux"
510 * c-basic-offset: 8
511 * tab-width: 8
512 * indent-tabs-mode: t
513 * End: