diff options
Diffstat (limited to 'drivers/lguest/interrupts_and_traps.c')
-rw-r--r-- | drivers/lguest/interrupts_and_traps.c | 13 |
1 files changed, 9 insertions, 4 deletions
diff --git a/drivers/lguest/interrupts_and_traps.c b/drivers/lguest/interrupts_and_traps.c index a57d757eab6e..3271c0031a1b 100644 --- a/drivers/lguest/interrupts_and_traps.c +++ b/drivers/lguest/interrupts_and_traps.c | |||
@@ -62,8 +62,9 @@ static void push_guest_stack(struct lguest *lg, unsigned long *gstack, u32 val) | |||
62 | * it). */ | 62 | * it). */ |
63 | static void set_guest_interrupt(struct lguest *lg, u32 lo, u32 hi, int has_err) | 63 | static void set_guest_interrupt(struct lguest *lg, u32 lo, u32 hi, int has_err) |
64 | { | 64 | { |
65 | unsigned long gstack; | 65 | unsigned long gstack, origstack; |
66 | u32 eflags, ss, irq_enable; | 66 | u32 eflags, ss, irq_enable; |
67 | unsigned long virtstack; | ||
67 | 68 | ||
68 | /* There are two cases for interrupts: one where the Guest is already | 69 | /* There are two cases for interrupts: one where the Guest is already |
69 | * in the kernel, and a more complex one where the Guest is in | 70 | * in the kernel, and a more complex one where the Guest is in |
@@ -71,8 +72,10 @@ static void set_guest_interrupt(struct lguest *lg, u32 lo, u32 hi, int has_err) | |||
71 | if ((lg->regs->ss&0x3) != GUEST_PL) { | 72 | if ((lg->regs->ss&0x3) != GUEST_PL) { |
72 | /* The Guest told us their kernel stack with the SET_STACK | 73 | /* The Guest told us their kernel stack with the SET_STACK |
73 | * hypercall: both the virtual address and the segment */ | 74 | * hypercall: both the virtual address and the segment */ |
74 | gstack = guest_pa(lg, lg->esp1); | 75 | virtstack = lg->esp1; |
75 | ss = lg->ss1; | 76 | ss = lg->ss1; |
77 | |||
78 | origstack = gstack = guest_pa(lg, virtstack); | ||
76 | /* We push the old stack segment and pointer onto the new | 79 | /* We push the old stack segment and pointer onto the new |
77 | * stack: when the Guest does an "iret" back from the interrupt | 80 | * stack: when the Guest does an "iret" back from the interrupt |
78 | * handler the CPU will notice they're dropping privilege | 81 | * handler the CPU will notice they're dropping privilege |
@@ -81,8 +84,10 @@ static void set_guest_interrupt(struct lguest *lg, u32 lo, u32 hi, int has_err) | |||
81 | push_guest_stack(lg, &gstack, lg->regs->esp); | 84 | push_guest_stack(lg, &gstack, lg->regs->esp); |
82 | } else { | 85 | } else { |
83 | /* We're staying on the same Guest (kernel) stack. */ | 86 | /* We're staying on the same Guest (kernel) stack. */ |
84 | gstack = guest_pa(lg, lg->regs->esp); | 87 | virtstack = lg->regs->esp; |
85 | ss = lg->regs->ss; | 88 | ss = lg->regs->ss; |
89 | |||
90 | origstack = gstack = guest_pa(lg, virtstack); | ||
86 | } | 91 | } |
87 | 92 | ||
88 | /* Remember that we never let the Guest actually disable interrupts, so | 93 | /* Remember that we never let the Guest actually disable interrupts, so |
@@ -108,7 +113,7 @@ static void set_guest_interrupt(struct lguest *lg, u32 lo, u32 hi, int has_err) | |||
108 | /* Now we've pushed all the old state, we change the stack, the code | 113 | /* Now we've pushed all the old state, we change the stack, the code |
109 | * segment and the address to execute. */ | 114 | * segment and the address to execute. */ |
110 | lg->regs->ss = ss; | 115 | lg->regs->ss = ss; |
111 | lg->regs->esp = gstack + lg->page_offset; | 116 | lg->regs->esp = virtstack + (gstack - origstack); |
112 | lg->regs->cs = (__KERNEL_CS|GUEST_PL); | 117 | lg->regs->cs = (__KERNEL_CS|GUEST_PL); |
113 | lg->regs->eip = idt_address(lo, hi); | 118 | lg->regs->eip = idt_address(lo, hi); |
114 | 119 | ||