Cleanup vm86 fault handling
PATCH 1/1 Cleanup vm86 fault handling
This patch makes handle_vm86_trap() accept or reject traps, instead of handling it in do_trap(). This enables some extra cleanups with the general protection fault and cache flush fault.
--
Brian Gerst
arch/i386/kernel/traps.c +14 -69
@@ -258,12 +258,6 @@do_exit (SIGSEGV ); } -static inline void die_if_kernel (const char * str,struct pt_regs * regs,long err) -{ -if (!(regs->eflags &VM_MASK ) && !(3 & regs->xcs)) -die (str, regs, err); -} -static inline unsigned long get_cr2 (void ) {unsigned long address;
@@ -273,14 +267,11 @@return address; } -static inline void do_trap (int trapnr,int signr,char *str,int vm86, +static inline void do_trap (int trapnr,int signr,char *str,struct pt_regs * regs,long error_code,siginfo_t *info) { -if (regs->eflags &VM_MASK ) { -if (vm86) - goto vm86_trap; - goto trap_signal; - } +if (regs->eflags &VM_MASK ) + goto vm86_trap;if (!(regs->xcs &3 )) goto kernel_trap;
@@ -303,8 +294,8 @@ } vm86_trap: { -int ret =handle_vm86_trap ((struct kernel_vm86_regs *) regs, error_code, trapnr); -if (ret) goto trap_signal; +if (handle_vm86_trap ((struct kernel_vm86_regs *) regs, error_code, trapnr)) + goto trap_signal;return ; } }
@@ -312,7 +303,7 @@#define DO_ERROR (trapnr, signr, str, name) \ asmlinkage void do_##name(struct pt_regs * regs, long error_code) \ { \ - do_trap(trapnr, signr, str, 0, regs, error_code, NULL); \ + do_trap(trapnr, signr, str, regs, error_code, NULL); \ }#define DO_ERROR_INFO (trapnr, signr, str, name, sicode, siaddr) \
@@ -323,61 +314,23 @@ info.si_errno =0 ; \ info.si_code = sicode; \ info.si_addr = (void *)siaddr; \ -do_trap (trapnr, signr, str,0 , regs, error_code, &info); \ -} - -#define DO_VM86_ERROR (trapnr, signr, str, name) \ -asmlinkage void do_##name(struct pt_regs * regs, long error_code) \ -{ \ - do_trap(trapnr, signr, str, 1, regs, error_code, NULL); \ +do_trap (trapnr, signr, str, regs, error_code, &info); \ } -#define DO_VM86_ERROR_INFO (trapnr, signr, str, name, sicode, siaddr) \ -asmlinkage void do_##name(struct pt_regs * regs, long error_code) \ -{ \ - siginfo_t info; \ - info.si_signo = signr; \ - info.si_errno = 0; \ - info.si_code = sicode; \ - info.si_addr = (void *)siaddr; \ - do_trap(trapnr, signr, str, 1, regs, error_code, &info); \ -} - -DO_VM86_ERROR_INFO( 0, SIGFPE, "divide error", divide_error, FPE_INTDIV, regs->eip) -DO_VM86_ERROR( 3, SIGTRAP, "int3", int3) -DO_VM86_ERROR( 4, SIGSEGV, "overflow", overflow) -DO_VM86_ERROR( 5, SIGSEGV, "bounds", bounds) +DO_ERROR_INFO( 0, SIGFPE, "divide error", divide_error, FPE_INTDIV, regs->eip) +DO_ERROR( 3, SIGTRAP, "int3", int3) +DO_ERROR( 4, SIGSEGV, "overflow", overflow) +DO_ERROR( 5, SIGSEGV, "bounds", bounds) DO_ERROR_INFO( 6, SIGILL, "invalid operand", invalid_op, ILL_ILLOPN, regs->eip) -DO_VM86_ERROR( 7, SIGSEGV, "device not available", device_not_available) +DO_ERROR( 7, SIGSEGV, "device not available", device_not_available) DO_ERROR( 8, SIGSEGV, "double fault", double_fault) DO_ERROR( 9, SIGFPE, "coprocessor segment overrun", coprocessor_segment_overrun) DO_ERROR(10, SIGSEGV, "invalid TSS", invalid_TSS) DO_ERROR(11, SIGBUS, "segment not present", segment_not_present) DO_ERROR(12, SIGBUS, "stack segment", stack_segment) +DO_ERROR(13, SIGSEGV, "general protection fault", general_protection) DO_ERROR_INFO(17, SIGBUS, "alignment check", alignment_check, BUS_ADRALN, get_cr2()) -asmlinkage void do_general_protection(struct pt_regs * regs, long error_code) -{ -if (regs->eflags &VM_MASK ) - goto gp_in_vm86; - -if (!(regs->xcs &3 )) - goto gp_in_kernel; - - current->thread.error_code = error_code; - current->thread.trap_no =13 ; -force_sig (SIGSEGV , current); -return ; - -gp_in_vm86: -handle_vm86_fault ((struct kernel_vm86_regs *) regs, error_code); -return ; - -gp_in_kernel: -if (!fixup_exception (regs)) -die ("general protection fault" , regs, error_code); -} -static void mem_parity_error (unsigned char reason,struct pt_regs * regs) {printk ("Uhhuh. NMI received. Dazed and confused, but trying to continue\n" );
@@ -703,15 +656,7 @@* Handle strange cache flush from user space exception * in all other cases. This is undocumented behaviour. */ -if (regs->eflags &VM_MASK ) { -handle_vm86_fault ((struct kernel_vm86_regs *)regs, - error_code); -return ; - } -die_if_kernel ("cache flush denied" , regs, error_code); - current->thread.trap_no =19 ; - current->thread.error_code = error_code; -force_sig (SIGSEGV , current); +do_trap (19 ,SIGSEGV ,"cache flush denied" , regs, error_code,NULL ); } }
arch/i386/kernel/vm86.c +15 -0
@@ -502,6 +502,21 @@int handle_vm86_trap (struct kernel_vm86_regs * regs,long error_code,int trapno) { +switch (trapno) { +case 13 : +case 19 : +handle_vm86_fault (regs, error_code); +return 0 ; +case 0 : +case 1 : +case 3 : +case 4 : +case 7 : +break ; +default : +return 1 ; + }; +if (VMPI .is_vm86pus) {if ( (trapno==3 ) || (trapno==1 ) )return_to_32bit (regs,VM86_TRAP + (trapno <<8 ));