aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/lguest
diff options
context:
space:
mode:
authorRusty Russell <rusty@rustcorp.com.au>2016-03-31 21:45:46 -0400
committerIngo Molnar <mingo@kernel.org>2016-04-01 02:58:13 -0400
commitf87e0434a3bedeb5e4d75d96d9f3ad424dae6b33 (patch)
treeaa18b1303e0082c527e5fad3b4d43631cd0d4fb1 /drivers/lguest
parent6d92bc9d483aa1751755a66fee8fb39dffb088c0 (diff)
lguest, x86/entry/32: Fix handling of guest syscalls using interrupt gates
In a798f091113e ("x86/entry/32: Change INT80 to be an interrupt gate") Andy broke lguest. This is because lguest had special code to allow the 0x80 trap gate go straight into the guest itself; interrupts gates (without more work, as mentioned in the file's comments) bounce via the hypervisor. His change made them go via the hypervisor, but as it's in the range of normal hardware interrupts, they were not directed through to the guest at all. Turns out the guest userspace isn't very effective if syscalls are all noops. I haven't ripped out all the now-useless trap-direct-to-guest-kernel code yet, since it will still be needed if someone decides to update this optimization. Signed-off-by: Rusty Russell <rusty@rustcorp.com.au> Cc: Andy Lutomirski <luto@amacapital.net> Cc: Andy Lutomirski <luto@kernel.org> Cc: Borislav Petkov <bp@alien8.de> Cc: Brian Gerst <brgerst@gmail.com> Cc: Denys Vlasenko <dvlasenk@redhat.com> Cc: H. Peter Anvin <hpa@zytor.com> Cc: Linus Torvalds <torvalds@linux-foundation.org> Cc: Peter Zijlstra <peterz@infradead.org> Cc: Thomas Gleixner <tglx@linutronix.de> Cc: Weisbecker <fweisbec@gmail.com> Cc: x86\@kernel.org Link: http://lkml.kernel.org/r/87fuv685kl.fsf@rustcorp.com.au Signed-off-by: Ingo Molnar <mingo@kernel.org>
Diffstat (limited to 'drivers/lguest')
-rw-r--r--drivers/lguest/interrupts_and_traps.c6
-rw-r--r--drivers/lguest/lg.h1
-rw-r--r--drivers/lguest/x86/core.c6
3 files changed, 11 insertions, 2 deletions
diff --git a/drivers/lguest/interrupts_and_traps.c b/drivers/lguest/interrupts_and_traps.c
index eb934b0242e0..67392b6ab845 100644
--- a/drivers/lguest/interrupts_and_traps.c
+++ b/drivers/lguest/interrupts_and_traps.c
@@ -331,7 +331,7 @@ void set_interrupt(struct lg_cpu *cpu, unsigned int irq)
331 * Actually now I think of it, it's possible that Ron *is* half the Plan 9 331 * Actually now I think of it, it's possible that Ron *is* half the Plan 9
332 * userbase. Oh well. 332 * userbase. Oh well.
333 */ 333 */
334static bool could_be_syscall(unsigned int num) 334bool could_be_syscall(unsigned int num)
335{ 335{
336 /* Normal Linux IA32_SYSCALL_VECTOR or reserved vector? */ 336 /* Normal Linux IA32_SYSCALL_VECTOR or reserved vector? */
337 return num == IA32_SYSCALL_VECTOR || num == syscall_vector; 337 return num == IA32_SYSCALL_VECTOR || num == syscall_vector;
@@ -416,6 +416,10 @@ bool deliver_trap(struct lg_cpu *cpu, unsigned int num)
416 * 416 *
417 * This routine indicates if a particular trap number could be delivered 417 * This routine indicates if a particular trap number could be delivered
418 * directly. 418 * directly.
419 *
420 * Unfortunately, Linux 4.6 started using an interrupt gate instead of a
421 * trap gate for syscalls, so this trick is ineffective. See Mastery for
422 * how we could do this anyway...
419 */ 423 */
420static bool direct_trap(unsigned int num) 424static bool direct_trap(unsigned int num)
421{ 425{
diff --git a/drivers/lguest/lg.h b/drivers/lguest/lg.h
index ac8ad0461e80..69b3814afd2f 100644
--- a/drivers/lguest/lg.h
+++ b/drivers/lguest/lg.h
@@ -167,6 +167,7 @@ void guest_set_clockevent(struct lg_cpu *cpu, unsigned long delta);
167bool send_notify_to_eventfd(struct lg_cpu *cpu); 167bool send_notify_to_eventfd(struct lg_cpu *cpu);
168void init_clockdev(struct lg_cpu *cpu); 168void init_clockdev(struct lg_cpu *cpu);
169bool check_syscall_vector(struct lguest *lg); 169bool check_syscall_vector(struct lguest *lg);
170bool could_be_syscall(unsigned int num);
170int init_interrupts(void); 171int init_interrupts(void);
171void free_interrupts(void); 172void free_interrupts(void);
172 173
diff --git a/drivers/lguest/x86/core.c b/drivers/lguest/x86/core.c
index 6a4cd771a2be..adc162c7040d 100644
--- a/drivers/lguest/x86/core.c
+++ b/drivers/lguest/x86/core.c
@@ -429,8 +429,12 @@ void lguest_arch_handle_trap(struct lg_cpu *cpu)
429 return; 429 return;
430 break; 430 break;
431 case 32 ... 255: 431 case 32 ... 255:
432 /* This might be a syscall. */
433 if (could_be_syscall(cpu->regs->trapnum))
434 break;
435
432 /* 436 /*
433 * These values mean a real interrupt occurred, in which case 437 * Other values mean a real interrupt occurred, in which case
434 * the Host handler has already been run. We just do a 438 * the Host handler has already been run. We just do a
435 * friendly check if another process should now be run, then 439 * friendly check if another process should now be run, then
436 * return to run the Guest again. 440 * return to run the Guest again.