diff options
Diffstat (limited to 'arch/i386/kernel/paravirt.c')
-rw-r--r-- | arch/i386/kernel/paravirt.c | 17 |
1 files changed, 13 insertions, 4 deletions
diff --git a/arch/i386/kernel/paravirt.c b/arch/i386/kernel/paravirt.c index 53f07a8275e3..79c167fcaee9 100644 --- a/arch/i386/kernel/paravirt.c +++ b/arch/i386/kernel/paravirt.c | |||
@@ -124,20 +124,28 @@ unsigned paravirt_patch_ignore(unsigned len) | |||
124 | return len; | 124 | return len; |
125 | } | 125 | } |
126 | 126 | ||
127 | struct branch { | ||
128 | unsigned char opcode; | ||
129 | u32 delta; | ||
130 | } __attribute__((packed)); | ||
131 | |||
127 | unsigned paravirt_patch_call(void *target, u16 tgt_clobbers, | 132 | unsigned paravirt_patch_call(void *target, u16 tgt_clobbers, |
128 | void *site, u16 site_clobbers, | 133 | void *site, u16 site_clobbers, |
129 | unsigned len) | 134 | unsigned len) |
130 | { | 135 | { |
131 | unsigned char *call = site; | 136 | unsigned char *call = site; |
132 | unsigned long delta = (unsigned long)target - (unsigned long)(call+5); | 137 | unsigned long delta = (unsigned long)target - (unsigned long)(call+5); |
138 | struct branch b; | ||
133 | 139 | ||
134 | if (tgt_clobbers & ~site_clobbers) | 140 | if (tgt_clobbers & ~site_clobbers) |
135 | return len; /* target would clobber too much for this site */ | 141 | return len; /* target would clobber too much for this site */ |
136 | if (len < 5) | 142 | if (len < 5) |
137 | return len; /* call too long for patch site */ | 143 | return len; /* call too long for patch site */ |
138 | 144 | ||
139 | *call++ = 0xe8; /* call */ | 145 | b.opcode = 0xe8; /* call */ |
140 | *(unsigned long *)call = delta; | 146 | b.delta = delta; |
147 | BUILD_BUG_ON(sizeof(b) != 5); | ||
148 | text_poke(call, (unsigned char *)&b, 5); | ||
141 | 149 | ||
142 | return 5; | 150 | return 5; |
143 | } | 151 | } |
@@ -150,8 +158,9 @@ unsigned paravirt_patch_jmp(void *target, void *site, unsigned len) | |||
150 | if (len < 5) | 158 | if (len < 5) |
151 | return len; /* call too long for patch site */ | 159 | return len; /* call too long for patch site */ |
152 | 160 | ||
153 | *jmp++ = 0xe9; /* jmp */ | 161 | b.opcode = 0xe9; /* jmp */ |
154 | *(unsigned long *)jmp = delta; | 162 | b.delta = delta; |
163 | text_poke(call, (unsigned char *)&b, 5); | ||
155 | 164 | ||
156 | return 5; | 165 | return 5; |
157 | } | 166 | } |