|
|
|
@@ -56,21 +56,16 @@ static void push_guest_stack(struct lg_cpu *cpu, unsigned long *gstack, u32 val)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/*H:210
|
|
|
|
|
* The set_guest_interrupt() routine actually delivers the interrupt or
|
|
|
|
|
* trap. The mechanics of delivering traps and interrupts to the Guest are the
|
|
|
|
|
* same, except some traps have an "error code" which gets pushed onto the
|
|
|
|
|
* stack as well: the caller tells us if this is one.
|
|
|
|
|
*
|
|
|
|
|
* "lo" and "hi" are the two parts of the Interrupt Descriptor Table for this
|
|
|
|
|
* interrupt or trap. It's split into two parts for traditional reasons: gcc
|
|
|
|
|
* on i386 used to be frightened by 64 bit numbers.
|
|
|
|
|
* The push_guest_interrupt_stack() routine saves Guest state on the stack for
|
|
|
|
|
* an interrupt or trap. The mechanics of delivering traps and interrupts to
|
|
|
|
|
* the Guest are the same, except some traps have an "error code" which gets
|
|
|
|
|
* pushed onto the stack as well: the caller tells us if this is one.
|
|
|
|
|
*
|
|
|
|
|
* We set up the stack just like the CPU does for a real interrupt, so it's
|
|
|
|
|
* identical for the Guest (and the standard "iret" instruction will undo
|
|
|
|
|
* it).
|
|
|
|
|
*/
|
|
|
|
|
static void set_guest_interrupt(struct lg_cpu *cpu, u32 lo, u32 hi,
|
|
|
|
|
bool has_err)
|
|
|
|
|
static void push_guest_interrupt_stack(struct lg_cpu *cpu, bool has_err)
|
|
|
|
|
{
|
|
|
|
|
unsigned long gstack, origstack;
|
|
|
|
|
u32 eflags, ss, irq_enable;
|
|
|
|
@@ -130,12 +125,28 @@ static void set_guest_interrupt(struct lg_cpu *cpu, u32 lo, u32 hi,
|
|
|
|
|
if (has_err)
|
|
|
|
|
push_guest_stack(cpu, &gstack, cpu->regs->errcode);
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
* Now we've pushed all the old state, we change the stack, the code
|
|
|
|
|
* segment and the address to execute.
|
|
|
|
|
*/
|
|
|
|
|
/* Adjust the stack pointer and stack segment. */
|
|
|
|
|
cpu->regs->ss = ss;
|
|
|
|
|
cpu->regs->esp = virtstack + (gstack - origstack);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
* This actually makes the Guest start executing the given interrupt/trap
|
|
|
|
|
* handler.
|
|
|
|
|
*
|
|
|
|
|
* "lo" and "hi" are the two parts of the Interrupt Descriptor Table for this
|
|
|
|
|
* interrupt or trap. It's split into two parts for traditional reasons: gcc
|
|
|
|
|
* on i386 used to be frightened by 64 bit numbers.
|
|
|
|
|
*/
|
|
|
|
|
static void guest_run_interrupt(struct lg_cpu *cpu, u32 lo, u32 hi)
|
|
|
|
|
{
|
|
|
|
|
/* If we're already in the kernel, we don't change stacks. */
|
|
|
|
|
if ((cpu->regs->ss&0x3) != GUEST_PL)
|
|
|
|
|
cpu->regs->ss = cpu->esp1;
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
* Set the code segment and the address to execute.
|
|
|
|
|
*/
|
|
|
|
|
cpu->regs->cs = (__KERNEL_CS|GUEST_PL);
|
|
|
|
|
cpu->regs->eip = idt_address(lo, hi);
|
|
|
|
|
|
|
|
|
@@ -158,6 +169,24 @@ static void set_guest_interrupt(struct lg_cpu *cpu, u32 lo, u32 hi,
|
|
|
|
|
kill_guest(cpu, "Disabling interrupts");
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* This restores the eflags word which was pushed on the stack by a trap */
|
|
|
|
|
static void restore_eflags(struct lg_cpu *cpu)
|
|
|
|
|
{
|
|
|
|
|
/* This is the physical address of the stack. */
|
|
|
|
|
unsigned long stack_pa = guest_pa(cpu, cpu->regs->esp);
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
* Stack looks like this:
|
|
|
|
|
* Address Contents
|
|
|
|
|
* esp EIP
|
|
|
|
|
* esp + 4 CS
|
|
|
|
|
* esp + 8 EFLAGS
|
|
|
|
|
*/
|
|
|
|
|
cpu->regs->eflags = lgread(cpu, stack_pa + 8, u32);
|
|
|
|
|
cpu->regs->eflags &=
|
|
|
|
|
~(X86_EFLAGS_TF|X86_EFLAGS_VM|X86_EFLAGS_RF|X86_EFLAGS_NT);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/*H:205
|
|
|
|
|
* Virtual Interrupts.
|
|
|
|
|
*
|
|
|
|
@@ -200,14 +229,6 @@ void try_deliver_interrupt(struct lg_cpu *cpu, unsigned int irq, bool more)
|
|
|
|
|
|
|
|
|
|
BUG_ON(irq >= LGUEST_IRQS);
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
* They may be in the middle of an iret, where they asked us never to
|
|
|
|
|
* deliver interrupts.
|
|
|
|
|
*/
|
|
|
|
|
if (cpu->regs->eip >= cpu->lg->noirq_start &&
|
|
|
|
|
(cpu->regs->eip < cpu->lg->noirq_end))
|
|
|
|
|
return;
|
|
|
|
|
|
|
|
|
|
/* If they're halted, interrupts restart them. */
|
|
|
|
|
if (cpu->halted) {
|
|
|
|
|
/* Re-enable interrupts. */
|
|
|
|
@@ -237,12 +258,34 @@ void try_deliver_interrupt(struct lg_cpu *cpu, unsigned int irq, bool more)
|
|
|
|
|
if (idt_present(idt->a, idt->b)) {
|
|
|
|
|
/* OK, mark it no longer pending and deliver it. */
|
|
|
|
|
clear_bit(irq, cpu->irqs_pending);
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
* set_guest_interrupt() takes the interrupt descriptor and a
|
|
|
|
|
* flag to say whether this interrupt pushes an error code onto
|
|
|
|
|
* the stack as well: virtual interrupts never do.
|
|
|
|
|
* They may be about to iret, where they asked us never to
|
|
|
|
|
* deliver interrupts. In this case, we can emulate that iret
|
|
|
|
|
* then immediately deliver the interrupt. This is basically
|
|
|
|
|
* a noop: the iret would pop the interrupt frame and restore
|
|
|
|
|
* eflags, and then we'd set it up again. So just restore the
|
|
|
|
|
* eflags word and jump straight to the handler in this case.
|
|
|
|
|
*
|
|
|
|
|
* Denys Vlasenko points out that this isn't quite right: if
|
|
|
|
|
* the iret was returning to userspace, then that interrupt
|
|
|
|
|
* would reset the stack pointer (which the Guest told us
|
|
|
|
|
* about via LHCALL_SET_STACK). But unless the Guest is being
|
|
|
|
|
* *really* weird, that will be the same as the current stack
|
|
|
|
|
* anyway.
|
|
|
|
|
*/
|
|
|
|
|
set_guest_interrupt(cpu, idt->a, idt->b, false);
|
|
|
|
|
if (cpu->regs->eip == cpu->lg->noirq_iret) {
|
|
|
|
|
restore_eflags(cpu);
|
|
|
|
|
} else {
|
|
|
|
|
/*
|
|
|
|
|
* set_guest_interrupt() takes a flag to say whether
|
|
|
|
|
* this interrupt pushes an error code onto the stack
|
|
|
|
|
* as well: virtual interrupts never do.
|
|
|
|
|
*/
|
|
|
|
|
push_guest_interrupt_stack(cpu, false);
|
|
|
|
|
}
|
|
|
|
|
/* Actually make Guest cpu jump to handler. */
|
|
|
|
|
guest_run_interrupt(cpu, idt->a, idt->b);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
@@ -353,8 +396,9 @@ bool deliver_trap(struct lg_cpu *cpu, unsigned int num)
|
|
|
|
|
*/
|
|
|
|
|
if (!idt_present(cpu->arch.idt[num].a, cpu->arch.idt[num].b))
|
|
|
|
|
return false;
|
|
|
|
|
set_guest_interrupt(cpu, cpu->arch.idt[num].a,
|
|
|
|
|
cpu->arch.idt[num].b, has_err(num));
|
|
|
|
|
push_guest_interrupt_stack(cpu, has_err(num));
|
|
|
|
|
guest_run_interrupt(cpu, cpu->arch.idt[num].a,
|
|
|
|
|
cpu->arch.idt[num].b);
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
@@ -395,8 +439,9 @@ static bool direct_trap(unsigned int num)
|
|
|
|
|
* The Guest has the ability to turn its interrupt gates into trap gates,
|
|
|
|
|
* if it is careful. The Host will let trap gates can go directly to the
|
|
|
|
|
* Guest, but the Guest needs the interrupts atomically disabled for an
|
|
|
|
|
* interrupt gate. It can do this by pointing the trap gate at instructions
|
|
|
|
|
* within noirq_start and noirq_end, where it can safely disable interrupts.
|
|
|
|
|
* interrupt gate. The Host could provide a mechanism to register more
|
|
|
|
|
* "no-interrupt" regions, and the Guest could point the trap gate at
|
|
|
|
|
* instructions within that region, where it can safely disable interrupts.
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
/*M:006
|
|
|
|
|