Beispiel #1
0
int do_page_fault(unsigned long addr, int error_code, struct pt_regs *regs)
{
	struct task_struct *tsk;
	struct mm_struct *mm;
	int fault;

#if defined(CONFIG_KGDB)
	if (kgdb_fault_expected)
		kgdb_handle_bus_error();
#endif

	tsk = current;
	mm  = tsk->mm;

	/*
	 * If we're in an interrupt or have no user
	 * context, we must not take the fault..
	 */
	if (in_interrupt() || !mm)
		goto no_context;

	TRACE_TRAP_ENTRY(14, instruction_pointer(regs));

	down_read(&mm->mmap_sem);
	fault = __do_page_fault(mm, addr, error_code, tsk);
	up_read(&mm->mmap_sem);

        TRACE_EVENT(TRACE_EV_TRAP_EXIT, NULL);

	/*
	 * Handle the "normal" case first
	 */
	if (fault > 0)
		return 0;

	/*
	 * We had some memory, but were unable to
	 * successfully fix up this page fault.
	 */
	if (fault == 0)
		goto do_sigbus;

	/*
	 * If we are in kernel mode at this point, we
	 * have no context to handle this fault with.
	 */
	if (!user_mode(regs))
		goto no_context;

	if (fault == -3) {
		/*
		 * We ran out of memory, or some other thing happened to
		 * us that made us unable to handle the page fault gracefully.
		 */
		printk("VM: killing process %s\n", tsk->comm);
		do_exit(SIGKILL);
	} else
		__do_user_fault(tsk, addr, error_code, fault == -1 ?
				SEGV_ACCERR : SEGV_MAPERR, regs);
	return 0;


/*
 * We ran out of memory, or some other thing happened to us that made
 * us unable to handle the page fault gracefully.
 */
do_sigbus:
	/*
	 * Send a sigbus, regardless of whether we were in kernel
	 * or user mode.
	 */
	tsk->thread.address = addr;
	tsk->thread.error_code = error_code;
	tsk->thread.trap_no = 14;
	force_sig(SIGBUS, tsk);
#ifdef CONFIG_DEBUG_USER
	printk(KERN_DEBUG "%s: sigbus at 0x%08lx, pc=0x%08lx\n",
		current->comm, addr, instruction_pointer(regs));
#endif

	/* Kernel mode? Handle exceptions or die */
	if (user_mode(regs))
		return 0;

no_context:
	__do_kernel_fault(mm, addr, error_code, regs);
	return 0;
}
Beispiel #2
0
/*
 * s390_do_machine_check
 *
 * mchine check pre-processor, collecting the machine check info,
 *  queueing it and posting the machine check handler for processing.
 */
void s390_do_machine_check( void )
{
	int      crw_count;
	mcic_t   mcic;
        trapid_t ltt_interruption_code;
        uint32_t ltt_old_psw;

#ifdef S390_MACHCHK_DEBUG
	printk( KERN_INFO "s390_do_machine_check : starting ...\n");
#endif

	memcpy( &mcic,
	        &S390_lowcore.mcck_interruption_code,
	        sizeof(__u64));
	memcpy( &ltt_interruption_code,
	        &S390_lowcore.mcck_interruption_code,
	        sizeof(__u64));
	memcpy( &ltt_old_psw,
	        &S390_lowcore.mcck_old_psw,
	        sizeof(uint32_t));
        ltt_old_psw &=  PSW_ADDR_MASK;
        TRACE_TRAP_ENTRY(ltt_interruption_code,ltt_old_psw);
 		
	if (mcic.mcc.mcd.sd) /* system damage */
		s390_handle_damage("received system damage machine check\n");

	if (mcic.mcc.mcd.pd) /* instruction processing damage */
		s390_handle_damage("received instruction processing damage machine check\n");

	if (mcic.mcc.mcd.se) /* storage error uncorrected */
		s390_handle_damage("received storage error uncorrected machine check\n");

	if (mcic.mcc.mcd.sc) /* storage error corrected */
		printk(KERN_WARNING "received storage error corrected machine check\n");

	if (mcic.mcc.mcd.ke) /* storage key-error uncorrected */
		s390_handle_damage("received storage key-error uncorrected machine check\n");

	if (mcic.mcc.mcd.ds && mcic.mcc.mcd.fa) /* storage degradation */
		s390_handle_damage("received storage degradation machine check\n");

	if ( mcic.mcc.mcd.cp )	// CRW pending ?
	{
		crw_count = s390_collect_crw_info();

		if ( crw_count )
		{
			up( &s_sem );

		} /* endif */

	} /* endif */
#ifdef CONFIG_MACHCHK_WARNING
/*
 * The warning may remain for a prolonged period on the bare iron.
 * (actually till the machine is powered off, or until the problem is gone)
 * So we just stop listening for the WARNING MCH and prevent continuously
 * being interrupted.  One caveat is however, that we must do this per 
 * processor and cannot use the smp version of ctl_clear_bit().
 * On VM we only get one interrupt per virtally presented machinecheck.
 * Though one suffices, we may get one interrupt per (virtual) processor. 
 */
	if ( mcic.mcc.mcd.w )	// WARNING pending ?
	{
		// Use single machine clear, as we cannot handle smp right now
		__ctl_clear_bit( 14, 24 );	// Disable WARNING MCH

		if ( ! mchchk_wng_posted )
		{ 
			mchchk_wng_posted = s390_post_warning();

			if ( mchchk_wng_posted )
			{
				up( &s_sem );

			} /* endif */

		} /* endif */

	} /* endif */
#endif

#ifdef S390_MACHCHK_DEBUG
	printk( KERN_INFO "s390_do_machine_check : done \n");
#endif

	return;
}