aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--drivers/lguest/interrupts_and_traps.c99
1 files changed, 72 insertions, 27 deletions
diff --git a/drivers/lguest/interrupts_and_traps.c b/drivers/lguest/interrupts_and_traps.c
index 6d4c072b61e1..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 */
72static void set_guest_interrupt(struct lg_cpu *cpu, u32 lo, u32 hi, 68static 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 */
141static 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 */
173static 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,13 +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_iret)
208 return;
209
210 /* If they're halted, interrupts restart them. */ 232 /* If they're halted, interrupts restart them. */
211 if (cpu->halted) { 233 if (cpu->halted) {
212 /* Re-enable interrupts. */ 234 /* Re-enable interrupts. */
@@ -236,12 +258,34 @@ void try_deliver_interrupt(struct lg_cpu *cpu, unsigned int irq, bool more)
236 if (idt_present(idt->a, idt->b)) { 258 if (idt_present(idt->a, idt->b)) {
237 /* OK, mark it no longer pending and deliver it. */ 259 /* OK, mark it no longer pending and deliver it. */
238 clear_bit(irq, cpu->irqs_pending); 260 clear_bit(irq, cpu->irqs_pending);
261
239 /* 262 /*
240 * set_guest_interrupt() takes the interrupt descriptor and a 263 * They may be about to iret, where they asked us never to
241 * flag to say whether this interrupt pushes an error code onto 264 * deliver interrupts. In this case, we can emulate that iret
242 * 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.
243 */ 276 */
244 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);
245 } 289 }
246 290
247 /* 291 /*
@@ -352,8 +396,9 @@ bool deliver_trap(struct lg_cpu *cpu, unsigned int num)
352 */ 396 */
353 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))
354 return false; 398 return false;
355 set_guest_interrupt(cpu, cpu->arch.idt[num].a, 399 push_guest_interrupt_stack(cpu, has_err(num));
356 cpu->arch.idt[num].b, has_err(num)); 400 guest_run_interrupt(cpu, cpu->arch.idt[num].a,
401 cpu->arch.idt[num].b);
357 return true; 402 return true;
358} 403}
359 404