diff options
Diffstat (limited to 'drivers/lguest/interrupts_and_traps.c')
-rw-r--r-- | drivers/lguest/interrupts_and_traps.c | 105 |
1 files changed, 75 insertions, 30 deletions
diff --git a/drivers/lguest/interrupts_and_traps.c b/drivers/lguest/interrupts_and_traps.c index 70dfcdc29f1f..5e7559be222a 100644 --- a/drivers/lguest/interrupts_and_traps.c +++ b/drivers/lguest/interrupts_and_traps.c | |||
@@ -56,21 +56,16 @@ static void push_guest_stack(struct lg_cpu *cpu, unsigned long *gstack, u32 val) | |||
56 | } | 56 | } |
57 | 57 | ||
58 | /*H:210 | 58 | /*H:210 |
59 | * The set_guest_interrupt() routine actually delivers the interrupt or | 59 | * The push_guest_interrupt_stack() routine saves Guest state on the stack for |
60 | * trap. The mechanics of delivering traps and interrupts to the Guest are the | 60 | * an interrupt or trap. The mechanics of delivering traps and interrupts to |
61 | * same, except some traps have an "error code" which gets pushed onto the | 61 | * the Guest are the same, except some traps have an "error code" which gets |
62 | * stack as well: the caller tells us if this is one. | 62 | * pushed onto the stack as well: the caller tells us if this is one. |
63 | * | ||
64 | * "lo" and "hi" are the two parts of the Interrupt Descriptor Table for this | ||
65 | * interrupt or trap. It's split into two parts for traditional reasons: gcc | ||
66 | * on i386 used to be frightened by 64 bit numbers. | ||
67 | * | 63 | * |
68 | * We set up the stack just like the CPU does for a real interrupt, so it's | 64 | * We set up the stack just like the CPU does for a real interrupt, so it's |
69 | * identical for the Guest (and the standard "iret" instruction will undo | 65 | * identical for the Guest (and the standard "iret" instruction will undo |
70 | * it). | 66 | * it). |
71 | */ | 67 | */ |
72 | static void set_guest_interrupt(struct lg_cpu *cpu, u32 lo, u32 hi, | 68 | static void push_guest_interrupt_stack(struct lg_cpu *cpu, bool has_err) |
73 | bool has_err) | ||
74 | { | 69 | { |
75 | unsigned long gstack, origstack; | 70 | unsigned long gstack, origstack; |
76 | u32 eflags, ss, irq_enable; | 71 | u32 eflags, ss, irq_enable; |
@@ -130,12 +125,28 @@ static void set_guest_interrupt(struct lg_cpu *cpu, u32 lo, u32 hi, | |||
130 | if (has_err) | 125 | if (has_err) |
131 | push_guest_stack(cpu, &gstack, cpu->regs->errcode); | 126 | push_guest_stack(cpu, &gstack, cpu->regs->errcode); |
132 | 127 | ||
133 | /* | 128 | /* Adjust the stack pointer and stack segment. */ |
134 | * Now we've pushed all the old state, we change the stack, the code | ||
135 | * segment and the address to execute. | ||
136 | */ | ||
137 | cpu->regs->ss = ss; | 129 | cpu->regs->ss = ss; |
138 | cpu->regs->esp = virtstack + (gstack - origstack); | 130 | cpu->regs->esp = virtstack + (gstack - origstack); |
131 | } | ||
132 | |||
133 | /* | ||
134 | * This actually makes the Guest start executing the given interrupt/trap | ||
135 | * handler. | ||
136 | * | ||
137 | * "lo" and "hi" are the two parts of the Interrupt Descriptor Table for this | ||
138 | * interrupt or trap. It's split into two parts for traditional reasons: gcc | ||
139 | * on i386 used to be frightened by 64 bit numbers. | ||
140 | */ | ||
141 | static void guest_run_interrupt(struct lg_cpu *cpu, u32 lo, u32 hi) | ||
142 | { | ||
143 | /* If we're already in the kernel, we don't change stacks. */ | ||
144 | if ((cpu->regs->ss&0x3) != GUEST_PL) | ||
145 | cpu->regs->ss = cpu->esp1; | ||
146 | |||
147 | /* | ||
148 | * Set the code segment and the address to execute. | ||
149 | */ | ||
139 | cpu->regs->cs = (__KERNEL_CS|GUEST_PL); | 150 | cpu->regs->cs = (__KERNEL_CS|GUEST_PL); |
140 | cpu->regs->eip = idt_address(lo, hi); | 151 | cpu->regs->eip = idt_address(lo, hi); |
141 | 152 | ||
@@ -158,6 +169,24 @@ static void set_guest_interrupt(struct lg_cpu *cpu, u32 lo, u32 hi, | |||
158 | kill_guest(cpu, "Disabling interrupts"); | 169 | kill_guest(cpu, "Disabling interrupts"); |
159 | } | 170 | } |
160 | 171 | ||
172 | /* This restores the eflags word which was pushed on the stack by a trap */ | ||
173 | static void restore_eflags(struct lg_cpu *cpu) | ||
174 | { | ||
175 | /* This is the physical address of the stack. */ | ||
176 | unsigned long stack_pa = guest_pa(cpu, cpu->regs->esp); | ||
177 | |||
178 | /* | ||
179 | * Stack looks like this: | ||
180 | * Address Contents | ||
181 | * esp EIP | ||
182 | * esp + 4 CS | ||
183 | * esp + 8 EFLAGS | ||
184 | */ | ||
185 | cpu->regs->eflags = lgread(cpu, stack_pa + 8, u32); | ||
186 | cpu->regs->eflags &= | ||
187 | ~(X86_EFLAGS_TF|X86_EFLAGS_VM|X86_EFLAGS_RF|X86_EFLAGS_NT); | ||
188 | } | ||
189 | |||
161 | /*H:205 | 190 | /*H:205 |
162 | * Virtual Interrupts. | 191 | * Virtual Interrupts. |
163 | * | 192 | * |
@@ -200,14 +229,6 @@ void try_deliver_interrupt(struct lg_cpu *cpu, unsigned int irq, bool more) | |||
200 | 229 | ||
201 | BUG_ON(irq >= LGUEST_IRQS); | 230 | BUG_ON(irq >= LGUEST_IRQS); |
202 | 231 | ||
203 | /* | ||
204 | * They may be in the middle of an iret, where they asked us never to | ||
205 | * deliver interrupts. | ||
206 | */ | ||
207 | if (cpu->regs->eip >= cpu->lg->noirq_start && | ||
208 | (cpu->regs->eip < cpu->lg->noirq_end)) | ||
209 | return; | ||
210 | |||
211 | /* If they're halted, interrupts restart them. */ | 232 | /* If they're halted, interrupts restart them. */ |
212 | if (cpu->halted) { | 233 | if (cpu->halted) { |
213 | /* Re-enable interrupts. */ | 234 | /* Re-enable interrupts. */ |
@@ -237,12 +258,34 @@ void try_deliver_interrupt(struct lg_cpu *cpu, unsigned int irq, bool more) | |||
237 | if (idt_present(idt->a, idt->b)) { | 258 | if (idt_present(idt->a, idt->b)) { |
238 | /* OK, mark it no longer pending and deliver it. */ | 259 | /* OK, mark it no longer pending and deliver it. */ |
239 | clear_bit(irq, cpu->irqs_pending); | 260 | clear_bit(irq, cpu->irqs_pending); |
261 | |||
240 | /* | 262 | /* |
241 | * set_guest_interrupt() takes the interrupt descriptor and a | 263 | * They may be about to iret, where they asked us never to |
242 | * flag to say whether this interrupt pushes an error code onto | 264 | * deliver interrupts. In this case, we can emulate that iret |
243 | * the stack as well: virtual interrupts never do. | 265 | * then immediately deliver the interrupt. This is basically |
266 | * a noop: the iret would pop the interrupt frame and restore | ||
267 | * eflags, and then we'd set it up again. So just restore the | ||
268 | * eflags word and jump straight to the handler in this case. | ||
269 | * | ||
270 | * Denys Vlasenko points out that this isn't quite right: if | ||
271 | * the iret was returning to userspace, then that interrupt | ||
272 | * would reset the stack pointer (which the Guest told us | ||
273 | * about via LHCALL_SET_STACK). But unless the Guest is being | ||
274 | * *really* weird, that will be the same as the current stack | ||
275 | * anyway. | ||
244 | */ | 276 | */ |
245 | set_guest_interrupt(cpu, idt->a, idt->b, false); | 277 | if (cpu->regs->eip == cpu->lg->noirq_iret) { |
278 | restore_eflags(cpu); | ||
279 | } else { | ||
280 | /* | ||
281 | * set_guest_interrupt() takes a flag to say whether | ||
282 | * this interrupt pushes an error code onto the stack | ||
283 | * as well: virtual interrupts never do. | ||
284 | */ | ||
285 | push_guest_interrupt_stack(cpu, false); | ||
286 | } | ||
287 | /* Actually make Guest cpu jump to handler. */ | ||
288 | guest_run_interrupt(cpu, idt->a, idt->b); | ||
246 | } | 289 | } |
247 | 290 | ||
248 | /* | 291 | /* |
@@ -353,8 +396,9 @@ bool deliver_trap(struct lg_cpu *cpu, unsigned int num) | |||
353 | */ | 396 | */ |
354 | if (!idt_present(cpu->arch.idt[num].a, cpu->arch.idt[num].b)) | 397 | if (!idt_present(cpu->arch.idt[num].a, cpu->arch.idt[num].b)) |
355 | return false; | 398 | return false; |
356 | set_guest_interrupt(cpu, cpu->arch.idt[num].a, | 399 | push_guest_interrupt_stack(cpu, has_err(num)); |
357 | cpu->arch.idt[num].b, has_err(num)); | 400 | guest_run_interrupt(cpu, cpu->arch.idt[num].a, |
401 | cpu->arch.idt[num].b); | ||
358 | return true; | 402 | return true; |
359 | } | 403 | } |
360 | 404 | ||
@@ -395,8 +439,9 @@ static bool direct_trap(unsigned int num) | |||
395 | * The Guest has the ability to turn its interrupt gates into trap gates, | 439 | * The Guest has the ability to turn its interrupt gates into trap gates, |
396 | * if it is careful. The Host will let trap gates can go directly to the | 440 | * if it is careful. The Host will let trap gates can go directly to the |
397 | * Guest, but the Guest needs the interrupts atomically disabled for an | 441 | * Guest, but the Guest needs the interrupts atomically disabled for an |
398 | * interrupt gate. It can do this by pointing the trap gate at instructions | 442 | * interrupt gate. The Host could provide a mechanism to register more |
399 | * within noirq_start and noirq_end, where it can safely disable interrupts. | 443 | * "no-interrupt" regions, and the Guest could point the trap gate at |
444 | * instructions within that region, where it can safely disable interrupts. | ||
400 | */ | 445 | */ |
401 | 446 | ||
402 | /*M:006 | 447 | /*M:006 |