fedora core 6 1.2949 + vserver 2.2.0
[linux-2.6.git] / arch / ia64 / kernel / patch.c
index 6a4ac7d..6f22168 100644 (file)
@@ -115,7 +115,7 @@ ia64_patch_vtop (unsigned long start, unsigned long end)
        ia64_srlz_i();
 }
 
-void
+void __init
 ia64_patch_mckinley_e9 (unsigned long start, unsigned long end)
 {
        static int first_time = 1;
@@ -149,7 +149,7 @@ ia64_patch_mckinley_e9 (unsigned long start, unsigned long end)
        ia64_srlz_i();
 }
 
-static void
+static void __init
 patch_fsyscall_table (unsigned long start, unsigned long end)
 {
        extern unsigned long fsyscall_table[NR_syscalls];
@@ -166,7 +166,7 @@ patch_fsyscall_table (unsigned long start, unsigned long end)
        ia64_srlz_i();
 }
 
-static void
+static void __init
 patch_brl_fsys_bubble_down (unsigned long start, unsigned long end)
 {
        extern char fsys_bubble_down[];
@@ -184,7 +184,74 @@ patch_brl_fsys_bubble_down (unsigned long start, unsigned long end)
        ia64_srlz_i();
 }
 
-void
+#ifdef CONFIG_XEN_IA64_VDSO_PARAVIRT
+extern char __start_gate_running_on_xen_patchlist[];
+extern char __end_gate_running_on_xen_patchlist[];
+
+void __init
+patch_running_on_xen(unsigned long start, unsigned long end)
+{
+       extern int running_on_xen;
+       s32 *offp = (s32 *)start;
+       u64 ip;
+
+       while (offp < (s32 *)end) {
+               ip = (u64)ia64_imva((char *)offp + *offp);
+               ia64_patch_imm64(ip, (u64)&running_on_xen);
+               ia64_fc((void *)ip);
+               ++offp;
+       }
+       ia64_sync_i();
+       ia64_srlz_i();
+}
+
+static void __init
+patch_brl_symaddr(unsigned long start, unsigned long end,
+                  unsigned long symaddr)
+{
+       s32 *offp = (s32 *)start;
+       u64 ip;
+
+       while (offp < (s32 *)end) {
+               ip = (u64)offp + *offp;
+               ia64_patch_imm60((u64)ia64_imva((void *)ip),
+                                (u64)(symaddr - (ip & -16)) / 16);
+               ia64_fc((void *)ip);
+               ++offp;
+       }
+       ia64_sync_i();
+       ia64_srlz_i();
+}
+
+#define EXTERN_PATCHLIST(name)                                 \
+       extern char __start_gate_brl_##name##_patchlist[];      \
+       extern char __end_gate_brl_##name##_patchlist[];        \
+       extern char name[]
+
+#define PATCH_BRL_SYMADDR(name)                                                \
+       patch_brl_symaddr((unsigned long)__start_gate_brl_##name##_patchlist, \
+                         (unsigned long)__end_gate_brl_##name##_patchlist,   \
+                         (unsigned long)name)
+
+static void __init
+patch_brl_in_vdso(void)
+{
+       EXTERN_PATCHLIST(xen_rsm_be_i);
+       EXTERN_PATCHLIST(xen_get_psr);
+       EXTERN_PATCHLIST(xen_ssm_i_0);
+       EXTERN_PATCHLIST(xen_ssm_i_1);
+
+       PATCH_BRL_SYMADDR(xen_rsm_be_i);
+       PATCH_BRL_SYMADDR(xen_get_psr);
+       PATCH_BRL_SYMADDR(xen_ssm_i_0);
+       PATCH_BRL_SYMADDR(xen_ssm_i_1);
+}
+#else
+#define patch_running_on_xen(start, end)       do { } while (0)
+#define patch_brl_in_vdso()                    do { } while (0)
+#endif
+
+void __init
 ia64_patch_gate (void)
 {
 #      define START(name)      ((unsigned long) __start_gate_##name##_patchlist)
@@ -192,6 +259,10 @@ ia64_patch_gate (void)
 
        patch_fsyscall_table(START(fsyscall), END(fsyscall));
        patch_brl_fsys_bubble_down(START(brl_fsys_bubble_down), END(brl_fsys_bubble_down));
+#ifdef CONFIG_XEN
+       patch_running_on_xen(START(running_on_xen), END(running_on_xen));
+       patch_brl_in_vdso();
+#endif
        ia64_patch_vtop(START(vtop), END(vtop));
        ia64_patch_mckinley_e9(START(mckinley_e9), END(mckinley_e9));
 }