forked from torvalds/linux
-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Showing
6 changed files
with
289 additions
and
2 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -153,4 +153,4 @@ endmenu | |
|
||
config KERNEL_DEBUGGER | ||
def_bool y | ||
depends on GDBSTUB | ||
depends on GDBSTUB || KGDB |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,81 @@ | ||
/* Kernel debugger for MN10300 | ||
* | ||
* Copyright (C) 2010 Red Hat, Inc. All Rights Reserved. | ||
* Written by David Howells ([email protected]) | ||
* | ||
* This program is free software; you can redistribute it and/or | ||
* modify it under the terms of the GNU General Public Licence | ||
* as published by the Free Software Foundation; either version | ||
* 2 of the Licence, or (at your option) any later version. | ||
*/ | ||
|
||
#ifndef _ASM_KGDB_H | ||
#define _ASM_KGDB_H | ||
|
||
/* | ||
* BUFMAX defines the maximum number of characters in inbound/outbound | ||
* buffers at least NUMREGBYTES*2 are needed for register packets | ||
* Longer buffer is needed to list all threads | ||
*/ | ||
#define BUFMAX 1024 | ||
|
||
/* | ||
* Note that this register image is in a different order than the register | ||
* image that Linux produces at interrupt time. | ||
*/ | ||
enum regnames { | ||
GDB_FR_D0 = 0, | ||
GDB_FR_D1 = 1, | ||
GDB_FR_D2 = 2, | ||
GDB_FR_D3 = 3, | ||
GDB_FR_A0 = 4, | ||
GDB_FR_A1 = 5, | ||
GDB_FR_A2 = 6, | ||
GDB_FR_A3 = 7, | ||
|
||
GDB_FR_SP = 8, | ||
GDB_FR_PC = 9, | ||
GDB_FR_MDR = 10, | ||
GDB_FR_EPSW = 11, | ||
GDB_FR_LIR = 12, | ||
GDB_FR_LAR = 13, | ||
GDB_FR_MDRQ = 14, | ||
|
||
GDB_FR_E0 = 15, | ||
GDB_FR_E1 = 16, | ||
GDB_FR_E2 = 17, | ||
GDB_FR_E3 = 18, | ||
GDB_FR_E4 = 19, | ||
GDB_FR_E5 = 20, | ||
GDB_FR_E6 = 21, | ||
GDB_FR_E7 = 22, | ||
|
||
GDB_FR_SSP = 23, | ||
GDB_FR_MSP = 24, | ||
GDB_FR_USP = 25, | ||
GDB_FR_MCRH = 26, | ||
GDB_FR_MCRL = 27, | ||
GDB_FR_MCVF = 28, | ||
|
||
GDB_FR_FPCR = 29, | ||
GDB_FR_DUMMY0 = 30, | ||
GDB_FR_DUMMY1 = 31, | ||
|
||
GDB_FR_FS0 = 32, | ||
|
||
GDB_FR_SIZE = 64, | ||
}; | ||
|
||
#define GDB_ORIG_D0 41 | ||
#define NUMREGBYTES (GDB_FR_SIZE*4) | ||
|
||
static inline void arch_kgdb_breakpoint(void) | ||
{ | ||
asm(".globl __arch_kgdb_breakpoint; __arch_kgdb_breakpoint: break"); | ||
} | ||
extern u8 __arch_kgdb_breakpoint; | ||
|
||
#define BREAK_INSTR_SIZE 1 | ||
#define CACHE_FLUSH_IS_SAFE 1 | ||
|
||
#endif /* _ASM_KGDB_H */ |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,202 @@ | ||
/* kgdb support for MN10300 | ||
* | ||
* Copyright (C) 2010 Red Hat, Inc. All Rights Reserved. | ||
* Written by David Howells ([email protected]) | ||
* | ||
* This program is free software; you can redistribute it and/or | ||
* modify it under the terms of the GNU General Public Licence | ||
* as published by the Free Software Foundation; either version | ||
* 2 of the Licence, or (at your option) any later version. | ||
*/ | ||
|
||
#include <linux/ptrace.h> | ||
#include <linux/kgdb.h> | ||
#include <linux/uaccess.h> | ||
#include <unit/leds.h> | ||
#include <unit/serial.h> | ||
#include <asm/debugger.h> | ||
#include <asm/serial-regs.h> | ||
#include "internal.h" | ||
|
||
/* | ||
* Copy kernel exception frame registers to the GDB register file | ||
*/ | ||
void pt_regs_to_gdb_regs(unsigned long *gdb_regs, struct pt_regs *regs) | ||
{ | ||
unsigned long ssp = (unsigned long) (regs + 1); | ||
|
||
gdb_regs[GDB_FR_D0] = regs->d0; | ||
gdb_regs[GDB_FR_D1] = regs->d1; | ||
gdb_regs[GDB_FR_D2] = regs->d2; | ||
gdb_regs[GDB_FR_D3] = regs->d3; | ||
gdb_regs[GDB_FR_A0] = regs->a0; | ||
gdb_regs[GDB_FR_A1] = regs->a1; | ||
gdb_regs[GDB_FR_A2] = regs->a2; | ||
gdb_regs[GDB_FR_A3] = regs->a3; | ||
gdb_regs[GDB_FR_SP] = (regs->epsw & EPSW_nSL) ? regs->sp : ssp; | ||
gdb_regs[GDB_FR_PC] = regs->pc; | ||
gdb_regs[GDB_FR_MDR] = regs->mdr; | ||
gdb_regs[GDB_FR_EPSW] = regs->epsw; | ||
gdb_regs[GDB_FR_LIR] = regs->lir; | ||
gdb_regs[GDB_FR_LAR] = regs->lar; | ||
gdb_regs[GDB_FR_MDRQ] = regs->mdrq; | ||
gdb_regs[GDB_FR_E0] = regs->e0; | ||
gdb_regs[GDB_FR_E1] = regs->e1; | ||
gdb_regs[GDB_FR_E2] = regs->e2; | ||
gdb_regs[GDB_FR_E3] = regs->e3; | ||
gdb_regs[GDB_FR_E4] = regs->e4; | ||
gdb_regs[GDB_FR_E5] = regs->e5; | ||
gdb_regs[GDB_FR_E6] = regs->e6; | ||
gdb_regs[GDB_FR_E7] = regs->e7; | ||
gdb_regs[GDB_FR_SSP] = ssp; | ||
gdb_regs[GDB_FR_MSP] = 0; | ||
gdb_regs[GDB_FR_USP] = regs->sp; | ||
gdb_regs[GDB_FR_MCRH] = regs->mcrh; | ||
gdb_regs[GDB_FR_MCRL] = regs->mcrl; | ||
gdb_regs[GDB_FR_MCVF] = regs->mcvf; | ||
gdb_regs[GDB_FR_DUMMY0] = 0; | ||
gdb_regs[GDB_FR_DUMMY1] = 0; | ||
gdb_regs[GDB_FR_FS0] = 0; | ||
} | ||
|
||
/* | ||
* Extracts kernel SP/PC values understandable by gdb from the values | ||
* saved by switch_to(). | ||
*/ | ||
void sleeping_thread_to_gdb_regs(unsigned long *gdb_regs, struct task_struct *p) | ||
{ | ||
gdb_regs[GDB_FR_SSP] = p->thread.sp; | ||
gdb_regs[GDB_FR_PC] = p->thread.pc; | ||
gdb_regs[GDB_FR_A3] = p->thread.a3; | ||
gdb_regs[GDB_FR_USP] = p->thread.usp; | ||
gdb_regs[GDB_FR_FPCR] = p->thread.fpu_state.fpcr; | ||
} | ||
|
||
/* | ||
* Fill kernel exception frame registers from the GDB register file | ||
*/ | ||
void gdb_regs_to_pt_regs(unsigned long *gdb_regs, struct pt_regs *regs) | ||
{ | ||
regs->d0 = gdb_regs[GDB_FR_D0]; | ||
regs->d1 = gdb_regs[GDB_FR_D1]; | ||
regs->d2 = gdb_regs[GDB_FR_D2]; | ||
regs->d3 = gdb_regs[GDB_FR_D3]; | ||
regs->a0 = gdb_regs[GDB_FR_A0]; | ||
regs->a1 = gdb_regs[GDB_FR_A1]; | ||
regs->a2 = gdb_regs[GDB_FR_A2]; | ||
regs->a3 = gdb_regs[GDB_FR_A3]; | ||
regs->sp = gdb_regs[GDB_FR_SP]; | ||
regs->pc = gdb_regs[GDB_FR_PC]; | ||
regs->mdr = gdb_regs[GDB_FR_MDR]; | ||
regs->epsw = gdb_regs[GDB_FR_EPSW]; | ||
regs->lir = gdb_regs[GDB_FR_LIR]; | ||
regs->lar = gdb_regs[GDB_FR_LAR]; | ||
regs->mdrq = gdb_regs[GDB_FR_MDRQ]; | ||
regs->e0 = gdb_regs[GDB_FR_E0]; | ||
regs->e1 = gdb_regs[GDB_FR_E1]; | ||
regs->e2 = gdb_regs[GDB_FR_E2]; | ||
regs->e3 = gdb_regs[GDB_FR_E3]; | ||
regs->e4 = gdb_regs[GDB_FR_E4]; | ||
regs->e5 = gdb_regs[GDB_FR_E5]; | ||
regs->e6 = gdb_regs[GDB_FR_E6]; | ||
regs->e7 = gdb_regs[GDB_FR_E7]; | ||
regs->sp = gdb_regs[GDB_FR_SSP]; | ||
/* gdb_regs[GDB_FR_MSP]; */ | ||
// regs->usp = gdb_regs[GDB_FR_USP]; | ||
regs->mcrh = gdb_regs[GDB_FR_MCRH]; | ||
regs->mcrl = gdb_regs[GDB_FR_MCRL]; | ||
regs->mcvf = gdb_regs[GDB_FR_MCVF]; | ||
/* gdb_regs[GDB_FR_DUMMY0]; */ | ||
/* gdb_regs[GDB_FR_DUMMY1]; */ | ||
|
||
// regs->fpcr = gdb_regs[GDB_FR_FPCR]; | ||
// regs->fs0 = gdb_regs[GDB_FR_FS0]; | ||
} | ||
|
||
struct kgdb_arch arch_kgdb_ops = { | ||
.gdb_bpt_instr = { 0xff }, | ||
.flags = KGDB_HW_BREAKPOINT, | ||
}; | ||
|
||
/* | ||
* Handle unknown packets and [Ccs] packets | ||
*/ | ||
int kgdb_arch_handle_exception(int vector, int signo, int err_code, | ||
char *remcom_in_buffer, char *remcom_out_buffer, | ||
struct pt_regs *regs) | ||
{ | ||
long addr; | ||
char *ptr; | ||
|
||
switch (remcom_in_buffer[0]) { | ||
case 'c': | ||
if (kgdb_contthread && kgdb_contthread != current) { | ||
strcpy(remcom_out_buffer, "E00"); | ||
break; | ||
} | ||
|
||
kgdb_contthread = NULL; | ||
|
||
/* try to read optional parameter, pc unchanged if no parm */ | ||
ptr = &remcom_in_buffer[1]; | ||
if (kgdb_hex2long(&ptr, &addr)) | ||
regs->pc = addr; | ||
return 0; | ||
|
||
case 's': | ||
break; /* we don't do hardware single stepping */ | ||
} | ||
return -1; /* this means that we do not want to exit from the handler */ | ||
} | ||
|
||
/* | ||
* Handle event interception | ||
* - returns 0 if the exception should be skipped, -ERROR otherwise. | ||
*/ | ||
int debugger_intercept(enum exception_code excep, int signo, int si_code, | ||
struct pt_regs *regs) | ||
{ | ||
int ret; | ||
|
||
ret = kgdb_handle_exception(excep, signo, si_code, regs); | ||
|
||
debugger_local_cache_flushinv(); | ||
|
||
return ret; | ||
} | ||
|
||
/* | ||
* Determine if we've hit a debugger special breakpoint | ||
*/ | ||
int at_debugger_breakpoint(struct pt_regs *regs) | ||
{ | ||
return regs->pc == (unsigned long)&__arch_kgdb_breakpoint; | ||
} | ||
|
||
/* | ||
* Initialise kgdb | ||
*/ | ||
int kgdb_arch_init(void) | ||
{ | ||
return 0; | ||
} | ||
|
||
/* | ||
* Do something, perhaps, but don't know what. | ||
*/ | ||
void kgdb_arch_exit(void) | ||
{ | ||
} | ||
|
||
#ifdef CONFIG_SMP | ||
void debugger_nmi_interrupt(struct pt_regs *regs, enum exception_code code) | ||
{ | ||
kgdb_nmicallback(arch_smp_processor_id(), regs); | ||
debugger_local_cache_flushinv(); | ||
} | ||
|
||
void kgdb_roundup_cpus(unsigned long flags) | ||
{ | ||
smp_jump_to_debugger(); | ||
} | ||
#endif |