diff options
Diffstat (limited to 'arch/i386/kernel/paravirt.c')
-rw-r--r-- | arch/i386/kernel/paravirt.c | 44 |
1 files changed, 44 insertions, 0 deletions
diff --git a/arch/i386/kernel/paravirt.c b/arch/i386/kernel/paravirt.c index 478192cd4b90..d46460426446 100644 --- a/arch/i386/kernel/paravirt.c +++ b/arch/i386/kernel/paravirt.c | |||
@@ -45,6 +45,49 @@ char *memory_setup(void) | |||
45 | return paravirt_ops.memory_setup(); | 45 | return paravirt_ops.memory_setup(); |
46 | } | 46 | } |
47 | 47 | ||
48 | /* Simple instruction patching code. */ | ||
49 | #define DEF_NATIVE(name, code) \ | ||
50 | extern const char start_##name[], end_##name[]; \ | ||
51 | asm("start_" #name ": " code "; end_" #name ":") | ||
52 | DEF_NATIVE(cli, "cli"); | ||
53 | DEF_NATIVE(sti, "sti"); | ||
54 | DEF_NATIVE(popf, "push %eax; popf"); | ||
55 | DEF_NATIVE(pushf, "pushf; pop %eax"); | ||
56 | DEF_NATIVE(pushf_cli, "pushf; pop %eax; cli"); | ||
57 | DEF_NATIVE(iret, "iret"); | ||
58 | DEF_NATIVE(sti_sysexit, "sti; sysexit"); | ||
59 | |||
60 | static const struct native_insns | ||
61 | { | ||
62 | const char *start, *end; | ||
63 | } native_insns[] = { | ||
64 | [PARAVIRT_IRQ_DISABLE] = { start_cli, end_cli }, | ||
65 | [PARAVIRT_IRQ_ENABLE] = { start_sti, end_sti }, | ||
66 | [PARAVIRT_RESTORE_FLAGS] = { start_popf, end_popf }, | ||
67 | [PARAVIRT_SAVE_FLAGS] = { start_pushf, end_pushf }, | ||
68 | [PARAVIRT_SAVE_FLAGS_IRQ_DISABLE] = { start_pushf_cli, end_pushf_cli }, | ||
69 | [PARAVIRT_INTERRUPT_RETURN] = { start_iret, end_iret }, | ||
70 | [PARAVIRT_STI_SYSEXIT] = { start_sti_sysexit, end_sti_sysexit }, | ||
71 | }; | ||
72 | |||
73 | static unsigned native_patch(u8 type, u16 clobbers, void *insns, unsigned len) | ||
74 | { | ||
75 | unsigned int insn_len; | ||
76 | |||
77 | /* Don't touch it if we don't have a replacement */ | ||
78 | if (type >= ARRAY_SIZE(native_insns) || !native_insns[type].start) | ||
79 | return len; | ||
80 | |||
81 | insn_len = native_insns[type].end - native_insns[type].start; | ||
82 | |||
83 | /* Similarly if we can't fit replacement. */ | ||
84 | if (len < insn_len) | ||
85 | return len; | ||
86 | |||
87 | memcpy(insns, native_insns[type].start, insn_len); | ||
88 | return insn_len; | ||
89 | } | ||
90 | |||
48 | static fastcall unsigned long native_get_debugreg(int regno) | 91 | static fastcall unsigned long native_get_debugreg(int regno) |
49 | { | 92 | { |
50 | unsigned long val = 0; /* Damn you, gcc! */ | 93 | unsigned long val = 0; /* Damn you, gcc! */ |
@@ -349,6 +392,7 @@ struct paravirt_ops paravirt_ops = { | |||
349 | .paravirt_enabled = 0, | 392 | .paravirt_enabled = 0, |
350 | .kernel_rpl = 0, | 393 | .kernel_rpl = 0, |
351 | 394 | ||
395 | .patch = native_patch, | ||
352 | .banner = default_banner, | 396 | .banner = default_banner, |
353 | .arch_setup = native_nop, | 397 | .arch_setup = native_nop, |
354 | .memory_setup = machine_specific_memory_setup, | 398 | .memory_setup = machine_specific_memory_setup, |