static int xmon_core()

in xmon/xmon.c [492:738]


static int xmon_core(struct pt_regs *regs, volatile int fromipi)
{
	volatile int cmd = 0;
	struct bpt *volatile bp;
	long recurse_jmp[JMP_BUF_LEN];
	bool locked_down;
	unsigned long offset;
	unsigned long flags;
#ifdef CONFIG_SMP
	int cpu;
	int secondary;
#endif

	local_irq_save(flags);
	hard_irq_disable();

	locked_down = xmon_is_locked_down();

	if (!fromipi) {
		tracing_enabled = tracing_is_on();
		tracing_off();
	}

	bp = in_breakpoint_table(regs->nip, &offset);
	if (bp != NULL) {
		regs_set_return_ip(regs, bp->address + offset);
		atomic_dec(&bp->ref_count);
	}

	remove_cpu_bpts();

#ifdef CONFIG_SMP
	cpu = smp_processor_id();
	if (cpumask_test_cpu(cpu, &cpus_in_xmon)) {
		/*
		 * We catch SPR read/write faults here because the 0x700, 0xf60
		 * etc. handlers don't call debugger_fault_handler().
		 */
		if (catch_spr_faults)
			longjmp(bus_error_jmp, 1);
		get_output_lock();
		excprint(regs);
		printf("cpu 0x%x: Exception %lx %s in xmon, "
		       "returning to main loop\n",
		       cpu, regs->trap, getvecname(TRAP(regs)));
		release_output_lock();
		longjmp(xmon_fault_jmp[cpu], 1);
	}

	if (setjmp(recurse_jmp) != 0) {
		if (!in_xmon || !xmon_gate) {
			get_output_lock();
			printf("xmon: WARNING: bad recursive fault "
			       "on cpu 0x%x\n", cpu);
			release_output_lock();
			goto waiting;
		}
		secondary = !(xmon_taken && cpu == xmon_owner);
		goto cmdloop;
	}

	xmon_fault_jmp[cpu] = recurse_jmp;

	bp = NULL;
	if ((regs->msr & (MSR_IR|MSR_PR|MSR_64BIT)) == (MSR_IR|MSR_64BIT))
		bp = at_breakpoint(regs->nip);
	if (bp || regs_is_unrecoverable(regs))
		fromipi = 0;

	if (!fromipi) {
		get_output_lock();
		if (!locked_down)
			excprint(regs);
		if (bp) {
			printf("cpu 0x%x stopped at breakpoint 0x%tx (",
			       cpu, BP_NUM(bp));
			xmon_print_symbol(regs->nip, " ", ")\n");
		}
		if (regs_is_unrecoverable(regs))
			printf("WARNING: exception is not recoverable, "
			       "can't continue\n");
		release_output_lock();
	}

	cpumask_set_cpu(cpu, &cpus_in_xmon);

 waiting:
	secondary = 1;
	spin_begin();
	while (secondary && !xmon_gate) {
		if (in_xmon == 0) {
			if (fromipi) {
				spin_end();
				goto leave;
			}
			secondary = test_and_set_bit(0, &in_xmon);
		}
		spin_cpu_relax();
		touch_nmi_watchdog();
	}
	spin_end();

	if (!secondary && !xmon_gate) {
		/* we are the first cpu to come in */
		/* interrupt other cpu(s) */
		int ncpus = num_online_cpus();

		xmon_owner = cpu;
		mb();
		if (ncpus > 1) {
			/*
			 * A system reset (trap == 0x100) can be triggered on
			 * all CPUs, so when we come in via 0x100 try waiting
			 * for the other CPUs to come in before we send the
			 * debugger break (IPI). This is similar to
			 * crash_kexec_secondary().
			 */
			if (TRAP(regs) !=  INTERRUPT_SYSTEM_RESET || !wait_for_other_cpus(ncpus))
				smp_send_debugger_break();

			wait_for_other_cpus(ncpus);
		}
		remove_bpts();
		disable_surveillance();

		if (!locked_down) {
			/* for breakpoint or single step, print curr insn */
			if (bp || TRAP(regs) == INTERRUPT_TRACE)
				ppc_inst_dump(regs->nip, 1, 0);
			printf("enter ? for help\n");
		}

		mb();
		xmon_gate = 1;
		barrier();
		touch_nmi_watchdog();
	}

 cmdloop:
	while (in_xmon) {
		if (secondary) {
			spin_begin();
			if (cpu == xmon_owner) {
				if (!test_and_set_bit(0, &xmon_taken)) {
					secondary = 0;
					spin_end();
					continue;
				}
				/* missed it */
				while (cpu == xmon_owner)
					spin_cpu_relax();
			}
			spin_cpu_relax();
			touch_nmi_watchdog();
		} else {
			cmd = 1;
#ifdef CONFIG_SMP
			if (xmon_batch)
				cmd = batch_cmds(regs);
#endif
			if (!locked_down && cmd)
				cmd = cmds(regs);
			if (locked_down || cmd != 0) {
				/* exiting xmon */
				insert_bpts();
				xmon_gate = 0;
				wmb();
				in_xmon = 0;
				break;
			}
			/* have switched to some other cpu */
			secondary = 1;
		}
	}
 leave:
	cpumask_clear_cpu(cpu, &cpus_in_xmon);
	xmon_fault_jmp[cpu] = NULL;
#else
	/* UP is simple... */
	if (in_xmon) {
		printf("Exception %lx %s in xmon, returning to main loop\n",
		       regs->trap, getvecname(TRAP(regs)));
		longjmp(xmon_fault_jmp[0], 1);
	}
	if (setjmp(recurse_jmp) == 0) {
		xmon_fault_jmp[0] = recurse_jmp;
		in_xmon = 1;

		excprint(regs);
		bp = at_breakpoint(regs->nip);
		if (bp) {
			printf("Stopped at breakpoint %tx (", BP_NUM(bp));
			xmon_print_symbol(regs->nip, " ", ")\n");
		}
		if (regs_is_unrecoverable(regs))
			printf("WARNING: exception is not recoverable, "
			       "can't continue\n");
		remove_bpts();
		disable_surveillance();
		if (!locked_down) {
			/* for breakpoint or single step, print current insn */
			if (bp || TRAP(regs) == INTERRUPT_TRACE)
				ppc_inst_dump(regs->nip, 1, 0);
			printf("enter ? for help\n");
		}
	}

	if (!locked_down)
		cmd = cmds(regs);

	insert_bpts();
	in_xmon = 0;
#endif

#ifdef CONFIG_BOOKE
	if (regs->msr & MSR_DE) {
		bp = at_breakpoint(regs->nip);
		if (bp != NULL) {
			regs_set_return_ip(regs, (unsigned long) &bp->instr[0]);
			atomic_inc(&bp->ref_count);
		}
	}
#else
	if ((regs->msr & (MSR_IR|MSR_PR|MSR_64BIT)) == (MSR_IR|MSR_64BIT)) {
		bp = at_breakpoint(regs->nip);
		if (bp != NULL) {
			int stepped = emulate_step(regs, ppc_inst_read(bp->instr));
			if (stepped == 0) {
				regs_set_return_ip(regs, (unsigned long) &bp->instr[0]);
				atomic_inc(&bp->ref_count);
			} else if (stepped < 0) {
				printf("Couldn't single-step %s instruction\n",
				    IS_RFID(ppc_inst_read(bp->instr))? "rfid": "mtmsrd");
			}
		}
	}
#endif
	if (locked_down)
		clear_all_bpt();
	else
		insert_cpu_bpts();

	xmon_touch_watchdogs();
	local_irq_restore(flags);

	return cmd != 'X' && cmd != EOF;
}