Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit ac3ee84c authored by Linus Torvalds's avatar Linus Torvalds
Browse files

Merge branch 'dbg-early-merge' of...

Merge branch 'dbg-early-merge' of git://git.kernel.org/pub/scm/linux/kernel/git/jwessel/linux-2.6-kgdb

* 'dbg-early-merge' of git://git.kernel.org/pub/scm/linux/kernel/git/jwessel/linux-2.6-kgdb:
  echi-dbgp: Add kernel debugger support for the usb debug port
  earlyprintk,vga,kdb: Fix \b and \r for earlyprintk=vga with kdb
  kgdboc: Add ekgdboc for early use of the kernel debugger
  x86,early dr regs,kgdb: Allow kernel debugger early dr register access
  x86,kgdb: Implement early hardware breakpoint debugging
  x86, kgdb, init: Add early and late debug states
  x86, kgdb: early trap init for early debug
parents 90b9a32d 4fe1da4e
Loading
Loading
Loading
Loading
+17 −0
Original line number Diff line number Diff line
@@ -713,6 +713,12 @@ and is between 256 and 4096 characters. It is defined in the file
			The VGA output is eventually overwritten by the real
			console.

	ekgdboc=	[X86,KGDB] Allow early kernel console debugging
			ekgdboc=kbd

			This is desgined to be used in conjunction with
			the boot argument: earlyprintk=vga

	eata=		[HW,SCSI]

	edd=		[EDD]
@@ -1121,6 +1127,17 @@ and is between 256 and 4096 characters. It is defined in the file
			use the HighMem zone if it exists, and the Normal
			zone if it does not.

	kgdbdbgp=	[KGDB,HW] kgdb over EHCI usb debug port.
			Format: <Controller#>[,poll interval]
			The controller # is the number of the ehci usb debug
			port as it is probed via PCI.  The poll interval is
			optional and is the number seconds in between
			each poll cycle to the debug port in case you need
			the functionality for interrupting the kernel with
			gdb or control-c on the dbgp connection.  When
			not using this parameter you use sysrq-g to break into
			the kernel debugger.

	kgdboc=		[KGDB,HW] kgdb over consoles.
			Requires a tty driver that supports console polling,
			or a supported polling keyboard driver (non-usb).
+2 −0
Original line number Diff line number Diff line
@@ -789,6 +789,8 @@ static inline void wbinvd_halt(void)
extern void enable_sep_cpu(void);
extern int sysenter_setup(void);

extern void early_trap_init(void);

/* Defined in head.S */
extern struct desc_ptr		early_gdt_descr;

+17 −12
Original line number Diff line number Diff line
@@ -1084,6 +1084,20 @@ static void clear_all_debug_regs(void)
	}
}

#ifdef CONFIG_KGDB
/*
 * Restore debug regs if using kgdbwait and you have a kernel debugger
 * connection established.
 */
static void dbg_restore_debug_regs(void)
{
	if (unlikely(kgdb_connected && arch_kgdb_ops.correct_hw_break))
		arch_kgdb_ops.correct_hw_break();
}
#else /* ! CONFIG_KGDB */
#define dbg_restore_debug_regs()
#endif /* ! CONFIG_KGDB */

/*
 * cpu_init() initializes state that is per-CPU. Some data is already
 * initialized (naturally) in the bootstrap process, such as the GDT
@@ -1174,18 +1188,8 @@ void __cpuinit cpu_init(void)
	load_TR_desc();
	load_LDT(&init_mm.context);

#ifdef CONFIG_KGDB
	/*
	 * If the kgdb is connected no debug regs should be altered.  This
	 * is only applicable when KGDB and a KGDB I/O module are built
	 * into the kernel and you are using early debugging with
	 * kgdbwait. KGDB will control the kernel HW breakpoint registers.
	 */
	if (kgdb_connected && arch_kgdb_ops.correct_hw_break)
		arch_kgdb_ops.correct_hw_break();
	else
#endif
	clear_all_debug_regs();
	dbg_restore_debug_regs();

	fpu_init();

@@ -1239,6 +1243,7 @@ void __cpuinit cpu_init(void)
#endif

	clear_all_debug_regs();
	dbg_restore_debug_regs();

	/*
	 * Force FPU initialization:
+8 −0
Original line number Diff line number Diff line
@@ -41,6 +41,14 @@ static void early_vga_write(struct console *con, const char *str, unsigned n)
				writew(0x720, VGABASE + 2*(max_xpos*j + i));
			current_ypos = max_ypos-1;
		}
#ifdef CONFIG_KGDB_KDB
		if (c == '\b') {
			if (current_xpos > 0)
				current_xpos--;
		} else if (c == '\r') {
			current_xpos = 0;
		} else
#endif
		if (c == '\n') {
			current_xpos = 0;
			current_ypos++;
+38 −9
Original line number Diff line number Diff line
@@ -199,6 +199,8 @@ static struct hw_breakpoint {
	struct perf_event	**pev;
} breakinfo[4];

static unsigned long early_dr7;

static void kgdb_correct_hw_break(void)
{
	int breakno;
@@ -210,6 +212,14 @@ static void kgdb_correct_hw_break(void)
		int cpu = raw_smp_processor_id();
		if (!breakinfo[breakno].enabled)
			continue;
		if (dbg_is_early) {
			set_debugreg(breakinfo[breakno].addr, breakno);
			early_dr7 |= encode_dr7(breakno,
						breakinfo[breakno].len,
						breakinfo[breakno].type);
			set_debugreg(early_dr7, 7);
			continue;
		}
		bp = *per_cpu_ptr(breakinfo[breakno].pev, cpu);
		info = counter_arch_bp(bp);
		if (bp->attr.disabled != 1)
@@ -224,6 +234,7 @@ static void kgdb_correct_hw_break(void)
		if (!val)
			bp->attr.disabled = 0;
	}
	if (!dbg_is_early)
		hw_breakpoint_restore();
}

@@ -233,6 +244,9 @@ static int hw_break_reserve_slot(int breakno)
	int cnt = 0;
	struct perf_event **pevent;

	if (dbg_is_early)
		return 0;

	for_each_online_cpu(cpu) {
		cnt++;
		pevent = per_cpu_ptr(breakinfo[breakno].pev, cpu);
@@ -258,6 +272,9 @@ static int hw_break_release_slot(int breakno)
	struct perf_event **pevent;
	int cpu;

	if (dbg_is_early)
		return 0;

	for_each_online_cpu(cpu) {
		pevent = per_cpu_ptr(breakinfo[breakno].pev, cpu);
		if (dbg_release_bp_slot(*pevent))
@@ -302,6 +319,10 @@ static void kgdb_remove_all_hw_break(void)
		bp = *per_cpu_ptr(breakinfo[i].pev, cpu);
		if (bp->attr.disabled == 1)
			continue;
		if (dbg_is_early)
			early_dr7 &= ~encode_dr7(i, breakinfo[i].len,
						 breakinfo[i].type);
		else
			arch_uninstall_hw_breakpoint(bp);
		bp->attr.disabled = 1;
	}
@@ -379,6 +400,11 @@ void kgdb_disable_hw_debug(struct pt_regs *regs)
	for (i = 0; i < 4; i++) {
		if (!breakinfo[i].enabled)
			continue;
		if (dbg_is_early) {
			early_dr7 &= ~encode_dr7(i, breakinfo[i].len,
						 breakinfo[i].type);
			continue;
		}
		bp = *per_cpu_ptr(breakinfo[i].pev, cpu);
		if (bp->attr.disabled == 1)
			continue;
@@ -595,15 +621,16 @@ static struct notifier_block kgdb_notifier = {
 *	specific callbacks.
 */
int kgdb_arch_init(void)
{
	return register_die_notifier(&kgdb_notifier);
}

void kgdb_arch_late(void)
{
	int i, cpu;
	int ret;
	struct perf_event_attr attr;
	struct perf_event **pevent;

	ret = register_die_notifier(&kgdb_notifier);
	if (ret != 0)
		return ret;
	/*
	 * Pre-allocate the hw breakpoint structions in the non-atomic
	 * portion of kgdb because this operation requires mutexs to
@@ -615,12 +642,15 @@ int kgdb_arch_init(void)
	attr.bp_type = HW_BREAKPOINT_W;
	attr.disabled = 1;
	for (i = 0; i < 4; i++) {
		if (breakinfo[i].pev)
			continue;
		breakinfo[i].pev = register_wide_hw_breakpoint(&attr, NULL);
		if (IS_ERR(breakinfo[i].pev)) {
			printk(KERN_ERR "kgdb: Could not allocate hw breakpoints\n");
			printk(KERN_ERR "kgdb: Could not allocate hw"
			       "breakpoints\nDisabling the kernel debugger\n");
			breakinfo[i].pev = NULL;
			kgdb_arch_exit();
			return -1;
			return;
		}
		for_each_online_cpu(cpu) {
			pevent = per_cpu_ptr(breakinfo[i].pev, cpu);
@@ -631,7 +661,6 @@ int kgdb_arch_init(void)
			}
		}
	}
	return ret;
}

/**
Loading