[xtensa-cvscommit] linux/arch/xtensa/kernel gdb-stub.c,1.2,1.3 handlers.S,1.3,1.4
Brought to you by:
zankel
|
From: <sfo...@us...> - 2002-09-22 21:18:06
|
Update of /cvsroot/xtensa/linux/arch/xtensa/kernel
In directory usw-pr-cvs1:/tmp/cvs-serv28463
Modified Files:
gdb-stub.c handlers.S
Log Message:
Support for reading "ar" registers via kgdb, besides the ones mapped by registers a0-15.
General cleanup of gdb-stub.c
Index: gdb-stub.c
===================================================================
RCS file: /cvsroot/xtensa/linux/arch/xtensa/kernel/gdb-stub.c,v
retrieving revision 1.2
retrieving revision 1.3
diff -C2 -d -r1.2 -r1.3
*** gdb-stub.c 19 Sep 2002 07:06:11 -0000 1.2
--- gdb-stub.c 22 Sep 2002 21:18:02 -0000 1.3
***************
*** 99,103 ****
static void getpacket(char *buffer);
static void putpacket(char *buffer);
- static int computeSignal(int tt);
static int hex(unsigned char ch);
static int hexToInt(char **ptr, int *intValue);
--- 99,102 ----
***************
*** 121,126 ****
/* saved_ar_regs provide a buffer to save the ar registers on debug
! * exceptions. */
! int saved_ar_regs[XCHAL_NUM_AREGS];
/* return_from_debug_flag is used to signal the exception handler to restore
* the ar registers from saved_ar_regs on return. */
--- 120,125 ----
/* saved_ar_regs provide a buffer to save the ar registers on debug
! * exceptions. Save all ar regs, plus wb and ws on top. */
! int saved_ar_regs[XCHAL_NUM_AREGS + 2];
/* return_from_debug_flag is used to signal the exception handler to restore
* the ar registers from saved_ar_regs on return. */
***************
*** 312,338 ****
}
- /*
- * This table contains the mapping between SPARC hardware trap types, and
- * signals, which are primarily what GDB understands. It also indicates
- * which hardware traps we need to commandeer when initializing the stub.
- */
- static struct hard_trap_info {
- unsigned char tt; /* Trap type code for MIPS R3xxx and R4xxx */
- unsigned char signo; /* Signal that we map this trap into */
- } hard_trap_info[] = {
- { 6, SIGBUS }, /* instruction bus error */
- { 7, SIGBUS }, /* data bus error */
- { 9, SIGTRAP }, /* break */
- { 10, SIGILL }, /* reserved instruction */
- /* { 11, SIGILL }, */ /* CPU unusable */
- { 12, SIGFPE }, /* overflow */
- { 13, SIGTRAP }, /* trap */
- { 14, SIGSEGV }, /* virtual instruction cache coherency */
- { 15, SIGFPE }, /* floating point exception */
- { 23, SIGSEGV }, /* watch */
- { 31, SIGSEGV }, /* virtual data cache coherency */
- { 0, 0} /* Must be last */
- };
-
/*
--- 311,314 ----
***************
*** 345,349 ****
{
unsigned long flags;
- unsigned char c;
#if 0
--- 321,324 ----
***************
*** 370,387 ****
/*
- * Convert the MIPS hardware trap type code to a Unix signal number.
- */
- static int computeSignal(int tt)
- {
- struct hard_trap_info *ht;
-
- for (ht = hard_trap_info; ht->tt && ht->signo; ht++)
- if (ht->tt == tt)
- return ht->signo;
-
- return SIGHUP; /* default for things we don't know about */
- }
-
- /*
* While we find nice hex chars, build an int.
* Return number of chars processed.
--- 345,348 ----
***************
*** 408,531 ****
}
-
- /*
- * We single-step by setting breakpoints. When an exception
- * is handled, we need to restore the instructions hoisted
- * when the breakpoints were set.
- *
- * This is where we save the original instructions.
- */
- static struct gdb_bp_save {
- unsigned int addr;
- unsigned int val;
- } step_bp[2];
-
- #define BP 0x0000000d /* break opcode */
-
- #if 0
-
- /*
- * Set breakpoint instructions for single stepping.
- */
- static void single_step(struct gdb_regs *regs)
- {
- union mips_instruction insn;
- unsigned int targ;
- int is_branch, is_cond, i;
-
- targ = regs->cp0_epc;
- insn.word = *(unsigned int *)targ;
- is_branch = is_cond = 0;
-
- switch (insn.i_format.opcode) {
- /*
- * jr and jalr are in r_format format.
- */
- case spec_op:
- switch (insn.r_format.func) {
- case jalr_op:
- case jr_op:
- targ = *(®s->reg0 + insn.r_format.rs);
- is_branch = 1;
- break;
- }
- break;
-
- /*
- * This group contains:
- * bltz_op, bgez_op, bltzl_op, bgezl_op,
- * bltzal_op, bgezal_op, bltzall_op, bgezall_op.
- */
- case bcond_op:
- is_branch = is_cond = 1;
- targ += 4 + (insn.i_format.simmediate << 2);
- break;
-
- /*
- * These are unconditional and in j_format.
- */
- case jal_op:
- case j_op:
- is_branch = 1;
- targ += 4;
- targ >>= 28;
- targ <<= 28;
- targ |= (insn.j_format.target << 2);
- break;
-
- /*
- * These are conditional.
- */
- case beq_op:
- case beql_op:
- case bne_op:
- case bnel_op:
- case blez_op:
- case blezl_op:
- case bgtz_op:
- case bgtzl_op:
- case cop0_op:
- case cop1_op:
- case cop2_op:
- case cop1x_op:
- is_branch = is_cond = 1;
- targ += 4 + (insn.i_format.simmediate << 2);
- break;
- }
-
- if (is_branch) {
- i = 0;
- if (is_cond && targ != (regs->cp0_epc + 8)) {
- step_bp[i].addr = regs->cp0_epc + 8;
- step_bp[i++].val = *(unsigned *)(regs->cp0_epc + 8);
- *(unsigned *)(regs->cp0_epc + 8) = BP;
- }
- step_bp[i].addr = targ;
- step_bp[i].val = *(unsigned *)targ;
- *(unsigned *)targ = BP;
- } else {
- step_bp[0].addr = regs->cp0_epc + 4;
- step_bp[0].val = *(unsigned *)(regs->cp0_epc + 4);
- *(unsigned *)(regs->cp0_epc + 4) = BP;
- }
- }
-
- /*
- * If asynchronously interrupted by gdb, then we need to set a breakpoint
- * at the interrupted instruction so that we wind up stopped with a
- * reasonable stack frame.
- */
- static struct gdb_bp_save async_bp;
-
- void set_async_breakpoint(unsigned int epc)
- {
- async_bp.addr = epc;
- async_bp.val = *(unsigned *)epc;
- *(unsigned *)epc = BP;
- flush_cache_all();
- }
-
- #endif
-
/*
* This function does all command processing for interfacing to gdb. It
--- 369,372 ----
***************
*** 535,544 ****
void gdb_handle_exception (struct pt_regs *regs)
{
- int trap; /* Trap type */
int sigval;
int addr;
int length;
char *ptr;
- unsigned long *stack;
unsigned regno;
int value;
--- 376,383 ----
***************
*** 549,560 ****
#if 0
- putDebugChar('S');
- putDebugChar('C');
- putDebugChar('O');
- putDebugChar('T');
- putDebugChar('T');
- putDebugChar('\n');
- #endif
- #if 0
printk("in gdb_handle_exception()\n");
#endif
--- 388,391 ----
***************
*** 565,662 ****
regs->pc += 3; /* breakpoint() uses a 3-byte break insn */
- #if 0
- /*
- * First check trap type. If this is CPU_UNUSABLE and CPU_ID is 1,
- * the simply switch the FPU on and return since this is no error
- * condition. kernel/traps.c does the same.
- * FIXME: This doesn't work yet, so we don't catch CPU_UNUSABLE
- * traps for now.
- */
- trap = (regs->cp0_cause & 0x7c) >> 2;
- /* printk("trap=%d\n",trap); */
- if (trap == 11) {
- if (((regs->cp0_cause >> CAUSEB_CE) & 3) == 1) {
- regs->cp0_status |= ST0_CU1;
- return;
- }
- }
-
- /*
- * If we're in breakpoint() increment the PC
- */
- if (trap == 9 && regs->cp0_epc == (unsigned long)breakinst)
- regs->cp0_epc += 4;
-
- /*
- * If we were single_stepping, restore the opcodes hoisted
- * for the breakpoint[s].
- */
- if (step_bp[0].addr) {
- *(unsigned *)step_bp[0].addr = step_bp[0].val;
- step_bp[0].addr = 0;
-
- if (step_bp[1].addr) {
- *(unsigned *)step_bp[1].addr = step_bp[1].val;
- step_bp[1].addr = 0;
- }
- }
-
- /*
- * If we were interrupted asynchronously by gdb, then a
- * breakpoint was set at the EPC of the interrupt so
- * that we'd wind up here with an interesting stack frame.
- */
- if (async_bp.addr) {
- *(unsigned *)async_bp.addr = async_bp.val;
- async_bp.addr = 0;
- }
-
- stack = (long *)regs->reg29; /* stack ptr */
- sigval = computeSignal(trap);
-
- /*
- * reply to host that an exception has occurred
- */
- ptr = output_buffer;
-
- /*
- * Send trap type (converted to signal)
- */
- *ptr++ = 'T';
- *ptr++ = hexchars[sigval >> 4];
- *ptr++ = hexchars[sigval & 0xf];
-
- /*
- * Send Error PC
- */
- *ptr++ = hexchars[REG_EPC >> 4];
- *ptr++ = hexchars[REG_EPC & 0xf];
- *ptr++ = ':';
- ptr = mem2hex((char *)®s->cp0_epc, ptr, 4, 0);
- *ptr++ = ';';
-
- /*
- * Send frame pointer
- */
- *ptr++ = hexchars[REG_FP >> 4];
- *ptr++ = hexchars[REG_FP & 0xf];
- *ptr++ = ':';
- ptr = mem2hex((char *)®s->reg30, ptr, 4, 0);
- *ptr++ = ';';
-
- /*
- * Send stack pointer
- */
- *ptr++ = hexchars[REG_SP >> 4];
- *ptr++ = hexchars[REG_SP & 0xf];
- *ptr++ = ':';
- ptr = mem2hex((char *)®s->reg29, ptr, 4, 0);
- *ptr++ = ';';
-
- *ptr++ = 0;
- putpacket(output_buffer); /* send it off... */
-
- #endif
-
sigval = 5;
ptr = output_buffer;
--- 396,399 ----
***************
*** 692,730 ****
*/
case 'g':
! #if 0
! ptr = output_buffer;
! ptr = mem2hex((char *)®s->reg0, ptr, 32*4, 0); /* r0...r31 */
! ptr = mem2hex((char *)®s->cp0_status, ptr, 6*4, 0); /* cp0 */
! ptr = mem2hex((char *)®s->fpr0, ptr, 32*4, 0); /* f0...31 */
! ptr = mem2hex((char *)®s->cp1_fsr, ptr, 2*4, 0); /* cp1 */
! ptr = mem2hex((char *)®s->frame_ptr, ptr, 2*4, 0); /* frp */
! ptr = mem2hex((char *)®s->cp0_index, ptr, 16*4, 0); /* cp0 */
! #endif
break;
/*
* set the value of the CPU registers - return OK
- * FIXME: Needs to be written
*/
case 'G':
! {
! #if 0
! unsigned long *newsp, psr;
!
! ptr = &input_buffer[1];
! hex2mem(ptr, (char *)registers, 16 * 4, 0); /* G & O regs */
!
! /*
! * See if the stack pointer has moved. If so, then copy the
! * saved locals and ins to the new location.
! */
!
! newsp = (unsigned long *)registers[SP];
! if (sp != newsp)
! sp = memcpy(newsp, sp, 16 * 4);
!
! #endif
! strcpy(output_buffer,"OK");
! }
break;
--- 429,441 ----
*/
case 'g':
! /* Not supported */
!
break;
/*
* set the value of the CPU registers - return OK
*/
case 'G':
! /* Not supported */
break;
***************
*** 819,826 ****
*/
case 's':
! /*
! * There is no single step insn in the MIPS ISA, so we
! * use breakpoints and continue, instead.
! */
kernel_single_step = 1;
--- 530,536 ----
*/
case 's':
! /* We set a flag here that is read by the exception
! * handler, which will set up ICOUNT/ICOUNTLEVEL
! * correctly. */
kernel_single_step = 1;
***************
*** 859,862 ****
--- 569,587 ----
output_buffer, 4, 0);
}
+ else if (user_mode(regs)) {
+ if (a_reg >= first_pane*4) {
+ if (first_pane < 0)
+ strcpy(output_buffer, "E01");
+ else
+ mem2hex((char *)&(current->thread.regfile[a_reg - first_pane*4]), output_buffer, 4, 0);
+ }
+ else {
+ strcpy(output_buffer, "E01");
+ }
+ }
+ else {
+ mem2hex((char *)&(saved_ar_regs[regno - REG_AR_BASE]), output_buffer, 4, 0);
+ }
+ #if 0
#if 1
else
***************
*** 868,871 ****
--- 593,598 ----
else
#endif
+ #endif
+
#if 0
mem2hex((char *)&(regs->aregs[regno - REG_AR_BASE - regs->wb]), output_buffer, 4, 0);
Index: handlers.S
===================================================================
RCS file: /cvsroot/xtensa/linux/arch/xtensa/kernel/handlers.S,v
retrieving revision 1.3
retrieving revision 1.4
diff -C2 -d -r1.3 -r1.4
*** handlers.S 19 Sep 2002 07:06:11 -0000 1.3
--- handlers.S 22 Sep 2002 21:18:02 -0000 1.4
***************
*** 1013,1016 ****
--- 1013,1104 ----
#endif /* XCHAL_EXTRA_SA_SIZE */
+ #ifdef CONFIG_KGDB
+ /* When a kernel debug exception is taken with kgdb enabled, we must
+ * save the "ar" registers, since they are not saved by default on
+ * kernel exceptions. On user debug exceptions, we don't have to do
+ * this, since the "ar" registers are saved.
+ *
+ * We save all panes except for the one corresponding to a0-a3. We
+ * don't really need to save the panes for a4-a15, since a0-a15, are
+ * saved in pt_regs, but we do anyway because it makes the algorithm
+ * simpler.
+ * The algoritm is to first save all panes lower than the active one,
+ * and then save all the panes above the active one. We can only touch
+ * a2 and a3. */
+
+ movi a2, return_from_debug_flag // if flag not set
+ l32i a2, a2, 0 // don't spill ar regs
+ beqz kgdb_nospill
+
+ movi a2, saved_ar_regs // get point to save area
+ rsr a3, WINDOWSTART // save window start
+ s32i a3, a2, (XCHAL_NUM_AREGS +1 ) * 4
+ rsr a3, WINDOWBASE // save window base
+ s32i a3, a2, XCHAL_NUM_AREGS * 4
+ beqz a3, kgdb_done_lower // active pane is 0
+ addi a3, a3, -1 // a3 acts as counter
+ slli a3, a3, 4 // 1st pane to save is one
+ add a2, a2, a3 // below the active one
+
+ kgdb_spill_lower:
+
+ rotw -1 // rotate one pane down
+
+ s32i a0, a6, 0 // save this pane
+ s32i a1, a6, 4
+ s32i a2, a6, 8
+ s32i a3, a6, 12
+
+ beqz a7, kgdb_done_lower // pane 0 is the last one below active
+ add a3, a7, -16 // set up the counter/pointer for the
+ add a2, a6, -16 // next frame
+
+ j kgdb_spill_lower
+
+ kgdb_done_lower:
+
+ movi a7, XHCAL_NUM_AREGS / 4 - 1 // set wb to top pane
+ wsr a7, WINDOWBASE
+ rsync
+
+ movi a6, saved_ar_regs
+ addi a6, a6, XCHAL_NUM_AREGS * // set up pointer to saved wb
+ l32i a7, a6, 0 // and read wb into a7
+ addi a7, a7, -(XCHAL_NUM_AREGS / 4 - 1)
+ neg a7 // a7 = total panes - 1 - wb
+ addi a6, -16 // a6 = top pane save area
+
+ kgdb_spill_upper:
+
+ beqz a7, kgdb_done // when counter is 0, we're done
+
+ s32i a0, a6, 0 // save pane
+ s32i a1, a6, 4
+ s32i a2, a6, 8
+ s32i a3, a6, 12
+
+ add a3, a7, -1 // decrement counter
+ add a2, a6, -16 // decrement save area pointer by 1 pane
+
+ rotw -1 // rotate one pane down
+
+ j kgdb_spill_upper
+
+ kgdb_done:
+
+ movi a6, XCHAL_NUM_AREGS * 4
+ l32i a6, a6, 0 // a6 = saved wb
+ wsr a6, WINDOWBASE // restore wb
+ rsync
+
+ movi a7, 1 // make exactly 1 pane valid
+ ssl a6
+ sll a7, a7
+ wsr a7, WINDOWSTART
+ rsync
+
+ kgdb_nospill:
+ #endif /* CONFIG_KGDB */
+
_excMoreCommonException:
***************
*** 1374,1377 ****
--- 1462,1538 ----
#endif /* XCHAL_EXTRA_SA_SIZE */
+
+
+ #ifdef CONFIG_KGDB
+ /* This is the reverse of saving the "ar" registers. See the above
+ * KGDB section for more details. */
+
+ movi a2, return_from_debug_flag // if flag not set
+ l32i a2, a2, 0 // ar regs weren't spilled
+ beqz kgdb_nounspill
+
+ rsr a11, WINDOWBASE // get current wb
+ slli a11, a11, 4 // multiply by 16
+ movi a10, saved_ar_regs // pointer to save area
+ add a10, a10, a11 // adjust to a0-a3 pane
+ addi a10, a10, 16 // now one above a0-a3 pane
+ add a11, a11, -((XCHAL_NUM_AREGS - 4) * 4)
+ neg a11 // a11 = total panes - 1 - wb
+
+ kgdb_unspill_upper:
+ beqz a11, kgdb_undone_upper // counter = 0 means we're done
+
+ rotw 1 // rotate up one pane
+
+ l32i a0, a6, 0 // restore the pane
+ l32i a1, a6, 4
+ l32i a2, a6, 8
+ l32i a3, a6, 12
+
+ addi a10, a6, 16 // set up the next save area
+ addi a11, a7, -16 // decrement the counter
+ j kgdb_unspill_upper
+
+ kgdb_undone_upper:
+
+ movi a7, 0 // set wb = 0, to start saving bottom
+ wsr a7, WINDOWBASE // pane
+ rsync
+
+ movi a6, saved_ar_regs // a6 = bottom (pane 0) of save area
+ l32i a7, a6, XCHAL_NUM_AREGS * 4 // a = saved wb
+ beqz kgdb_unspill_done // if it is 0, nothing below to restore
+ addi a7, a7, -1 // decrement counter
+
+ kgdb_unspill_lower:
+
+ l32i a0, a6, 0 // restore pane
+ l32i a1, a6, 4
+ l32i a2, a6, 8
+ l32i a3, a6, 12
+
+ rotw 1 // rotate up 1 pane
+ beqz a11, kgdb_unspill_done // if counter is 0, we're done
+
+ addi a6, a2, 16 // set up pointer for next pane
+ addi a7, a3, -1 // decrement counter
+
+ j kgdb_unspill_lower
+
+ kgdb_unspill_done:
+ /* wb should be back to original value at this point. We probably
+ * don't need to restore it, but we do anyway. */
+
+ movi a2, saved_ar_regs // restore ws
+ l32i a3, a2, (XCHAL_NUM_AREGS + 1) * 4
+ wsr a3, WINDOWSTART
+ rsync
+
+ l32i a3, a2, XCHAL_NUM_AREGS * 4 // restore wb
+ wsr a3, WINDOWBASE
+ rsync
+
+ kgdb_nounspill:
+ #endif /* CONFIG_KGDB */
l32i a2, a1, PT_WMASK // for quick_unspill case later..
***************
*** 2002,2012 ****
isync
- #ifdef CONFIG_KGDB
- // Save all the ar registers on a debug exception.
- j debug_save_ar_regs
-
- dsar_ret:
- #endif
-
movi a0, handle_debug // re-setup handler and
xsr a0, EXCSAVE + XCHAL_DEBUGLEVEL // restore a0
--- 2163,2166 ----
***************
*** 2018,2028 ****
j _excCommonException // jump to common exception code
-
- #ifdef CONFIG_KGDB
- // This just saves all the ar registers sequentially on debug exceptions.
- debug_save_ar_regs:
-
- j dsar_ret
- #endif // CONFIG_KGDB
/* Only if coprocessors exist to we include handlers for Coprocessor
--- 2172,2175 ----
|