add: pic_end_of_interrupt(frame.vector);
context: i386_handle_trap(struct iframe frame){	struct thread *thread = thread_get_current_thread();	int ret = B_HANDLED_INTERRUPT;	if (thread)		x86_push_iframe(&thread->arch_info.iframes, &frame);	else		x86_push_iframe(&gBootFrameStack, &frame);	if (frame.cs == USER_CODE_SEG) {		i386_exit_user_debug_at_kernel_entry();		thread_at_kernel_entry();	}//	if(frame.vector != 0x20)//		dprintf("i386_handle_trap: vector 0x%x, ip 0x%x, cpu %d\n", frame.vector, frame.eip, smp_get_current_cpu());	switch (frame.vector) {		case 1:			ret = i386_handle_debug_exception(&frame);			break;		case 3:			ret = i386_handle_breakpoint_exception(&frame);			break;		case 8:		// double fault			ret = i386_double_fault(&frame);			break;		case 13:	// general protection fault			ret = i386_general_protection_fault(frame.error_code);			break;		case 14:	// page fault		{			unsigned int cr2;			addr_t newip;			asm("movl %%cr2, %0" : "=r" (cr2));			if ((frame.flags & 0x200) == 0 && !kernel_startup) {				// if the interrupts were disabled, and we are not running the kernel startup				// the page fault was not allowed to happen and we must panic				panic("page fault, but interrupts were disabled. Touching address %p from eip %p\n", (void *)cr2, (void *)frame.eip);			} else if (thread != NULL && thread->page_faults_allowed < 1)				panic("page fault not allowed at this place. Touching address %p from eip %p\n", (void *)cr2, (void *)frame.eip);			enable_interrupts();			ret = vm_page_fault(cr2, frame.eip,				(frame.error_code & 0x2) != 0,	// write access				(frame.error_code & 0x4) != 0,	// userland				&newip);			if (newip != 0) {				// the page fault handler wants us to modify the iframe to set the				// IP the cpu will return to to be this ip				frame.eip = newip;			}			break;		}		case 99:	// syscall		{			uint64 retcode;			unsigned int args[MAX_ARGS];#if 0{			int i;			dprintf("i386_handle_trap: syscall %d, count %d, ptr 0x%x\n", frame.eax, frame.ecx, frame.edx);			dprintf(" call stack:\n");			for(i=0; i<frame.ecx; i++)				dprintf("\t0x%x\n", ((unsigned int *)frame.edx)[i]);}#endif			/* syscall interface works as such:			 *  %eax has syscall #			 *  %ecx has number of args (0-16)			 *  %edx has pointer to buffer containing args from first to last			 * each is verified to make sure someone doesn't try to clobber it			 */			if (frame.ecx <= MAX_ARGS) {				if (IS_KERNEL_ADDRESS(frame.edx)					|| user_memcpy(args, (void *)frame.edx, frame.ecx * sizeof(unsigned int)) < B_OK) {					retcode =  B_BAD_ADDRESS;				} else					ret = syscall_dispatcher(frame.eax, (void *)args, &retcode);			} else {				// want to pass too many args into the system				retcode = EINVAL;			}			frame.eax = retcode & 0xffffffff;			frame.edx = retcode >> 32;			break;		}		default:			if (frame.vector >= ARCH_INTERRUPT_BASE) {				pic_end_of_interrupt(frame.vector);				// This is a workaround for spurious assertions of interrupts 7/15				// which seems to be an often seen problem on the PC platform				if (pic_is_spurious_interrupt(frame.vector - ARCH_INTERRUPT_BASE))					break;				ret = int_io_interrupt_handler(frame.vector - ARCH_INTERRUPT_BASE);			} else {				panic("i386_handle_trap: unhandled trap 0x%x (%s) at ip 0x%x, thread 0x%x!\n",					frame.vector, kInterruptNames[frame.vector], frame.eip, thread ? thread->id : -1);				ret = B_HANDLED_INTERRUPT;			}			break;	}	if (ret == B_INVOKE_SCHEDULER) {		cpu_status state = disable_interrupts();		GRAB_THREAD_LOCK();		scheduler_reschedule();		RELEASE_THREAD_LOCK();		restore_interrupts(state);	}	if (frame.cs == USER_CODE_SEG) {		thread_at_kernel_exit();		i386_init_user_debug_at_kernel_exit(&frame);	}//	dprintf("0x%x cpu %d!\n", thread_get_current_thread_id(), smp_get_current_cpu());	if (thread)		x86_pop_iframe(&thread->arch_info.iframes);	else		x86_pop_iframe(&gBootFrameStack);}