diff options
| -rw-r--r-- | drivers/lguest/interrupts_and_traps.c | 99 |
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 | */ |
| 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,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 | ||
