From: Robert Picco This patch fixes some bugs and removes some obsolete gdb packet support. Signed-off-by: Andrew Morton --- 25-akpm/arch/ia64/kernel/kgdb_stub.c | 430 ++++++++++++++++++----------------- 25-akpm/arch/ia64/lib/kgdb_serial.c | 38 ++- 2 files changed, 261 insertions(+), 207 deletions(-) diff -puN arch/ia64/kernel/kgdb_stub.c~kgdb-ia64-fixes arch/ia64/kernel/kgdb_stub.c --- 25/arch/ia64/kernel/kgdb_stub.c~kgdb-ia64-fixes Wed Jun 2 14:47:32 2004 +++ 25-akpm/arch/ia64/kernel/kgdb_stub.c Wed Jun 2 14:47:32 2004 @@ -200,132 +200,6 @@ extern void eth_flushDebugChar(void); /* static char remcomInBuffer[BUFMAX]; static char remcomOutBuffer[BUFMAX]; static short error; -/* - * gdb 'qPart' packet support - */ - -struct reg_offset { - int regnum; - int offset; -} reg_offset[] = { -{IA64_GR0_REGNUM+1, 0}, /* r1 */ -{IA64_GR0_REGNUM+2, 8}, -{IA64_GR0_REGNUM+3, 16}, -{IA64_GR0_REGNUM+4, 24}, -{IA64_GR0_REGNUM+5, 32}, -{IA64_GR0_REGNUM+6, 40}, -{IA64_GR0_REGNUM+7, 48}, -{IA64_GR0_REGNUM+8, 56}, -{IA64_GR0_REGNUM+9, 64}, -{IA64_GR0_REGNUM+10, 72}, -{IA64_GR0_REGNUM+11, 80}, -{IA64_GR0_REGNUM+12, 88}, -{IA64_GR0_REGNUM+13, 96}, -{IA64_GR0_REGNUM+14, 104}, -{IA64_GR0_REGNUM+15, 112}, -{IA64_GR0_REGNUM+16, 120}, -{IA64_GR0_REGNUM+17, 128}, -{IA64_GR0_REGNUM+18, 136}, -{IA64_GR0_REGNUM+19, 144}, -{IA64_GR0_REGNUM+20, 152}, -{IA64_GR0_REGNUM+21, 160}, -{IA64_GR0_REGNUM+22, 168}, -{IA64_GR0_REGNUM+23, 176}, -{IA64_GR0_REGNUM+24, 184}, -{IA64_GR0_REGNUM+25, 192}, -{IA64_GR0_REGNUM+26, 200}, -{IA64_GR0_REGNUM+27, 208}, -{IA64_GR0_REGNUM+28, 216}, -{IA64_GR0_REGNUM+29, 224}, -{IA64_GR0_REGNUM+30, 232}, -{IA64_GR0_REGNUM+31, 240}, /* r31 */ -{IA64_FR0_REGNUM+6, 248}, /* fr6 */ -{IA64_FR0_REGNUM+7, 264}, -{IA64_FR0_REGNUM+8, 280}, -{IA64_FR0_REGNUM+9, 296}, -{IA64_FR0_REGNUM+10, 312}, -{IA64_FR0_REGNUM+11, 328}, /* fr11 */ -{IA64_PR_REGNUM, 344}, /* pr */ -{IA64_BR0_REGNUM, 352}, /* b0 */ -{IA64_BR0_REGNUM+1, 360}, -{IA64_BR0_REGNUM+2, 368}, -{IA64_BR0_REGNUM+3, 376}, -{IA64_BR0_REGNUM+4, 384}, -{IA64_BR0_REGNUM+5, 392}, -{IA64_BR0_REGNUM+6, 400}, -{IA64_BR0_REGNUM+7, 408}, /* br7 */ -{IA64_IP_REGNUM, 416}, /* ip */ -{IA64_CFM_REGNUM, 424}, /* cfm */ -{IA64_RSC_REGNUM, 432}, /* rsc */ -{IA64_BSP_REGNUM, 440}, /* bp */ -{IA64_BSPSTORE_REGNUM, 448}, /* bpstore */ -{IA64_RNAT_REGNUM, 456}, /* rnat */ -{IA64_UNAT_REGNUM, 464}, /* unat */ -{IA64_FPSR_REGNUM, 472}, /* fpsr */ -{IA64_PSR_REGNUM, 480}, /* psr */ -{IA64_PFS_REGNUM, 488}, /* pfs */ -}; - -static int rpacket_size; -int norpacket_udelay = 10000; -char * hex2mem(char *buf, char *mem, int count, int may_fault); -char * mem2hex(char *mem, char *buf, int count, int may_fault); - -long -find_roffset(long regnum) -{ - int i; - - for (i = 0; i < (sizeof (reg_offset) / sizeof (reg_offset[0])); i++) - if (reg_offset[i].regnum == regnum) - return reg_offset[i].offset; - - return -1L; -} - -static void -process_gpacket_request(void) -{ - int regnum, offset, size; - - if (!rpacket_size) - rpacket_size = reg_offset[(sizeof (reg_offset) / sizeof (reg_offset[0])) - 1]. - offset + 8; - hex2mem(&remcomInBuffer[20], (char *) ®num, sizeof(regnum), 0); - if (remcomInBuffer[20 + sizeof(regnum)*2] != ',') - goto bad; - hex2mem(&remcomInBuffer[20 + sizeof(regnum)*2 + 1], (char *) &size, sizeof(size), 0); - if (size != sizeof (size)) - goto bad; - offset = find_roffset(regnum); - mem2hex((char *) &offset, &remcomOutBuffer[0], sizeof (offset), 0); - remcomOutBuffer[sizeof(offset) * 2] = 0; - return; -bad: - remcomOutBuffer[0] = 'E'; - remcomOutBuffer[1] = 0; - return; -} - -void -rpacket_process(unsigned long *reg, char *buf, int direction) -{ - int i; - - for (i = 0; i < (sizeof (reg_offset) / sizeof (reg_offset[0])); i++) - if (!direction) - hex2mem(buf + reg_offset[i].offset * 2, - (char *) ®[REGISTER_INDEX(reg_offset[i].regnum)], - REGISTER_SIZE(reg_offset[i].regnum), 0); - else - mem2hex((char *) ®[REGISTER_INDEX(reg_offset[i].regnum)], - buf + reg_offset[i].offset * 2, - REGISTER_SIZE(reg_offset[i].regnum), 0); - - if (direction) - buf[rpacket_size * 2] = 0; -} - char *kgdb_version = KGDB_VERSION; @@ -340,7 +214,7 @@ static const char hexchars[] = "01234567 /* Number of bytes of registers. */ #define NUMREGBYTES REGISTER_BYTES -#define BREAKNUM 0x6666UL +#define BREAKNUM 0x00003333300LL #define KGDBBREAKNUM 0x6665UL static void inline @@ -711,8 +585,6 @@ putpacket(char *buffer) putDebugChar(ch); checksum += ch; count += 1; - if (!rpacket_size && ((count % 200) == 0)) - udelay(norpacket_udelay); } putDebugChar('#'); @@ -809,22 +681,42 @@ unw_get_regs(struct unw_frame_info *unw, { int i, j; char nat; + unsigned long *preg; struct ia64_fpreg *fr, freg; memset(regs, 0, sizeof (kgdb_info.ia64_regs)); for (i = 1; i < 32; i++) { + if (ptregs && ((i >= 8 && i <= 11) || (i >= 12 && i <= 15))) + continue; unw_access_gr(unw, i, ®s[REGISTER_INDEX(IA64_GR0_REGNUM + i)], &nat, 0); regs[REGISTER_INDEX(IA64_NAT0_REGNUM + i)] = nat; } - for (i = 1; i < 8; i++) + if (ptregs) { + for (preg = &ptregs->r8, i = 8; i < 12; i++, preg++) + regs[REGISTER_INDEX(IA64_GR0_REGNUM + i)] = *preg; + regs[REGISTER_INDEX(IA64_GR0_REGNUM + 12)] = ptregs->r12; + regs[REGISTER_INDEX(IA64_GR0_REGNUM + 13)] = ptregs->r13; + regs[REGISTER_INDEX(IA64_GR0_REGNUM + 14)] = ptregs->r14; + regs[REGISTER_INDEX(IA64_GR0_REGNUM + 15)] = ptregs->r15; + } + + for (i = 1; i < 8; i++) { + if (ptregs && (i == 6 || i == 7)) + continue; unw_access_br(unw, i, ®s[REGISTER_INDEX(IA64_BR0_REGNUM + i)], 0); + } - if (ptregs) + if (ptregs) { regs[REGISTER_INDEX(IA64_BR0_REGNUM)] = ptregs->b0; - else + regs[REGISTER_INDEX(IA64_BR0_REGNUM + 6)] = ptregs->b6; + regs[REGISTER_INDEX(IA64_BR0_REGNUM + 7)] = ptregs->b7; + } else { + unw_access_br(unw, i, ®s[REGISTER_INDEX(IA64_BR0_REGNUM + 6)], 0); + unw_access_br(unw, i, ®s[REGISTER_INDEX(IA64_BR0_REGNUM + 7)], 0); unw_access_br(unw, 0, ®s[REGISTER_INDEX(IA64_BR0_REGNUM)], 0); + } if (ptregs) fr = &ptregs->f6; @@ -897,7 +789,7 @@ gdb_regs_to_regs(struct kgdb_state *stat { int i; char nat; - unsigned long *regs; + unsigned long *regs, *preg; struct ia64_fpreg *fr; struct unw_frame_info *unw; @@ -905,12 +797,27 @@ gdb_regs_to_regs(struct kgdb_state *stat regs = kgdb_info.ia64_regs; for (i = 1; i < 32; i++) { + if ((i >= 8 && i <= 11) || (i >= 12 && i <= 15)) + continue; nat = (char) regs[REGISTER_INDEX(IA64_NAT0_REGNUM + i)]; unw_access_gr(unw, i, ®s[REGISTER_INDEX(IA64_GR0_REGNUM + i)], &nat, 1); } - for (i = 0; i < 8; i++) + for (preg = &state->regs->r8, i = 8; i < 12; i++, preg++) + regs[REGISTER_INDEX(IA64_GR0_REGNUM + i)] = *preg; + state->regs->r12 = regs[REGISTER_INDEX(IA64_GR0_REGNUM + 12)]; + state->regs->r12 = regs[REGISTER_INDEX(IA64_GR0_REGNUM + 13)]; + state->regs->r12 = regs[REGISTER_INDEX(IA64_GR0_REGNUM + 14)]; + state->regs->r12 = regs[REGISTER_INDEX(IA64_GR0_REGNUM + 15)]; + + for (i = 1; i < 8; i++) { + if ((i == 6 || i == 7)) + continue; unw_access_br(unw, i, ®s[REGISTER_INDEX(IA64_BR0_REGNUM + i)], 1); + } + state->regs->b0 = regs[REGISTER_INDEX(IA64_BR0_REGNUM)]; + state->regs->b6 = regs[REGISTER_INDEX(IA64_BR0_REGNUM + 6)]; + state->regs->b7 = regs[REGISTER_INDEX(IA64_BR0_REGNUM + 7)]; for (fr = &state->regs->f6, i = 6; i < 12; i++, fr++) { fr->u.bits[0] = regs[REGISTER_INDEX(IA64_FR0_REGNUM + 6 + i)]; @@ -975,27 +882,47 @@ static volatile int mem_err_expected = 0 static volatile int mem_err_cnt = 0; int -get_char(char *addr) +get_char(char *addr, unsigned char *data) { - return *addr; + mm_segment_t fs; + int ret; + + if ((unsigned long) addr < DEFAULT_TASK_SIZE) + return -EFAULT; + + wmb(); + fs = get_fs(); + set_fs(KERNEL_DS); + + if (get_user(*data, addr) != 0) + ret = -EFAULT; + else + ret = 0; + + set_fs(fs); + return ret; } -void -set_char(char *addr, int val, int may_fault) +int +set_char(char *addr, int val) { - if (may_fault) { - unsigned long valid; - if ((unsigned long) addr < PAGE_SIZE) - valid = 0; - else - asm volatile("probe.w %0 = %1, 0" : "=r" (valid) : "r" (addr) : "memory"); - if (!valid) { - mem_err = 1; - return; - } + mm_segment_t fs; + int ret; - } - *addr = val; + if ((unsigned long) addr < DEFAULT_TASK_SIZE) + return -EFAULT; + + wmb(); + fs = get_fs(); + set_fs(KERNEL_DS); + + if (put_user(val, addr) != 0) + ret = -EFAULT; + else + ret = 0; + + set_fs(fs); + return ret; } /* convert the memory pointed to by mem into hex, placing result in buf */ @@ -1012,31 +939,15 @@ mem2hex(char *mem, char *buf, int count, mem_err_expected = 1; mem_err = 0; } + for (i = 0; i < count; i++) { /* printk("%lx = ", mem) ; */ - if (may_fault) { - unsigned long valid; - if ((unsigned long) mem < PAGE_SIZE) - valid = 0; - else - asm volatile("probe.r %0 = %1, 0" : - "=r" (valid) : "r" (mem) : "memory"); - if (!valid) - mem_err = 1; - else - ch = get_char(mem++); - } - else - ch = get_char(mem++); - - /* printk("%02x\n", ch & 0xFF) ; */ - if (may_fault && mem_err) { + if (get_char(mem++, &ch)) { if (remote_debug) - printk("Mem fault fetching from addr %lx\n", - (long) (mem - 1)); + printk("Mem fault fetching from addr %lx\n", (long) (mem - 1)); *buf = 0; /* truncate buffer */ - return (buf); + return buf; } *buf++ = hexchars[ch >> 4]; *buf++ = hexchars[ch % 16]; @@ -1065,9 +976,7 @@ hex2mem(char *buf, char *mem, int count, for (i = 0; i < count; i++) { ch = hex(*buf++) << 4; ch = ch + hex(*buf++); - set_char(mem++, ch, may_fault); - - if (may_fault && mem_err) { + if (set_char(mem++, ch)) { if (remote_debug) printk("Mem fault storing to addr %lx\n", (long) (mem - 1)); @@ -1296,6 +1205,139 @@ getthread(int pid) } /* *INDENT-OFF* */ +enum instruction_type {A, I, M, F, B, L, X, u}; + +static enum instruction_type bundle_encoding[32][3] = { + { M, I, I }, /* 00 */ + { M, I, I }, /* 01 */ + { M, I, I }, /* 02 */ + { M, I, I }, /* 03 */ + { M, L, X }, /* 04 */ + { M, L, X }, /* 05 */ + { u, u, u }, /* 06 */ + { u, u, u }, /* 07 */ + { M, M, I }, /* 08 */ + { M, M, I }, /* 09 */ + { M, M, I }, /* 0A */ + { M, M, I }, /* 0B */ + { M, F, I }, /* 0C */ + { M, F, I }, /* 0D */ + { M, M, F }, /* 0E */ + { M, M, F }, /* 0F */ + { M, I, B }, /* 10 */ + { M, I, B }, /* 11 */ + { M, B, B }, /* 12 */ + { M, B, B }, /* 13 */ + { u, u, u }, /* 14 */ + { u, u, u }, /* 15 */ + { B, B, B }, /* 16 */ + { B, B, B }, /* 17 */ + { M, M, B }, /* 18 */ + { M, M, B }, /* 19 */ + { u, u, u }, /* 1A */ + { u, u, u }, /* 1B */ + { M, F, B }, /* 1C */ + { M, F, B }, /* 1D */ + { u, u, u }, /* 1E */ + { u, u, u }, /* 1F */ +}; + +#define MAX_BREAK_POINTS (20) + +struct z0_break_point { + unsigned long addr; + unsigned long bundle[2]; + unsigned int enabled; +} z0_break_point[MAX_BREAK_POINTS]; + +int kgdb_arch_set_breakpoint(unsigned long addr) +{ + unsigned long slot = addr & 0xf, bundle_addr; + unsigned long template; + struct bundle { + struct { + unsigned long long template : 5; + unsigned long long slot0 : 41; + unsigned long long slot1_p0 : 64-46; + } quad0; + struct { + unsigned long long slot1_p1 : 41 - (64-46); + unsigned long long slot2 : 41; + } quad1; + } bundle; + int i; + struct z0_break_point *z0 = NULL; + unsigned long valid; + + asm volatile("probe.w %0 = %1, 0" : "=r" (valid) : "r" (addr) : "memory"); + if (!valid) + return 0; + asm volatile("probe.w %0 = %1, 0" : "=r" (valid) : "r" (addr+8) : "memory"); + if (!valid) + return 0; + + + for (i = 0; i < MAX_BREAK_POINTS; i++) + if (!z0_break_point[i].enabled) { + z0 = &z0_break_point[i]; + break; + } + + if (!z0) + return 0; + + if (slot > 2) + slot = 0; + + bundle_addr = addr & ~0xFULL; + memcpy(&bundle, (unsigned long *)bundle_addr, sizeof(bundle)); + memcpy(z0->bundle, &bundle, sizeof(bundle)); + + template = bundle.quad0.template; + if (slot == 1 && bundle_encoding[template][1] == L) + slot = 2; + switch (slot) { + case 0: + bundle.quad0.slot0 = BREAKNUM; + break; + case 1: + bundle.quad0.slot1_p0 = BREAKNUM; + bundle.quad1.slot1_p1 = (BREAKNUM >> (64-46)); + break; + case 2: + bundle.quad1.slot2 = BREAKNUM; + break; + } + + memcpy((char *) bundle_addr, (char *) &bundle, sizeof(bundle)); + flush_icache_range(bundle_addr, bundle_addr + sizeof(bundle)); + z0->addr = addr; + z0->enabled = 1; + + return 1; +} + +int kgdb_arch_remove_breakpoint(unsigned long addr) +{ + struct z0_break_point *z0 = NULL; + int i; + + for (i = 0; i < MAX_BREAK_POINTS; i++) + if (z0_break_point[i].enabled && z0_break_point[i].addr == addr) { + z0 = &z0_break_point[i]; + break; + } + + if (!z0) + return 0; + + addr = addr & ~0xFULL; + (void) memcpy((char *) addr, (char *) z0->bundle, sizeof (z0->bundle)); + flush_icache_range(addr, addr + sizeof(z0->bundle)); + z0->enabled = 0; + return 1; +} + unsigned long hw_breakpoint_status; @@ -2036,18 +2078,10 @@ do_kgdb_handle_exception(struct unw_fram } case 'g': /* return the value of the CPU registers */ get_gdb_regs(usethread, info); - if (rpacket_size) - rpacket_process(gdb_regs, remcomOutBuffer, 1); - else - mem2hex((char *) gdb_regs, - remcomOutBuffer, NUMREGBYTES, 0); + mem2hex((char *) gdb_regs, remcomOutBuffer, NUMREGBYTES, 0); break; case 'G': /* set the value of the CPU registers - return OK */ - if (rpacket_size) - rpacket_process(gdb_regs, &remcomInBuffer[1], 0); - else - hex2mem(&remcomInBuffer[1], - (char *) gdb_regs, NUMREGBYTES, 0); + hex2mem(&remcomInBuffer[1], (char *) gdb_regs, NUMREGBYTES, 0); if (!usethread || usethread == current) { gdb_regs_to_regs(info); strcpy(remcomOutBuffer, "OK"); @@ -2224,18 +2258,6 @@ do_kgdb_handle_exception(struct unw_fram case 'q': nothreads = 0; switch (remcomInBuffer[1]) { - case 'P': - /* qPart:gpacket:read::, */ - if (strncmp(&remcomInBuffer[1], "Part", 4) || - remcomInBuffer[5] != ':' || - strncmp(&remcomInBuffer[6], "gpacket", 7) || - remcomInBuffer[13] != ':' || - strncmp(&remcomInBuffer[14], "read", 4) || - remcomInBuffer[18] != ':' || - remcomInBuffer[19] != ':') - break; - process_gpacket_request(); - break; case 'f': threadid = 1; thread_list = 2; @@ -2408,6 +2430,7 @@ do_kgdb_handle_exception(struct unw_fram * nothing. */ usethread = thread; + have_regs = 0; if ((thread_list == 1) && (thread == thread_list_start)) { thread_list = 0; @@ -2490,6 +2513,8 @@ do_kgdb_handle_exception(struct unw_fram case '2': /* write watchpoint */ case '3': /* read watchpoint */ case '4': /* access watchpoint */ + { + int ret; if (remcomInBuffer[2] != ',') { strcpy(remcomOutBuffer, "ERROR"); break; @@ -2507,14 +2532,21 @@ do_kgdb_handle_exception(struct unw_fram break; } - if (hardware_breakpoint(addr, length, - (remcomInBuffer[1] != '0' ? - remcomInBuffer[1] - '1' : WATCH_INSTRUCTION), - remcomInBuffer[0] == 'Z')) + if (remcomInBuffer[1] == '0') { + if (remcomInBuffer[0] == 'z') + ret = kgdb_arch_remove_breakpoint(addr); + else + ret = kgdb_arch_set_breakpoint(addr); + } + else ret = hardware_breakpoint(addr, length, + remcomInBuffer[1] - '1', + remcomInBuffer[0] == 'Z'); + if (ret) strcpy(remcomOutBuffer, "OK"); else strcpy(remcomOutBuffer, "ERROR"); break; + } default: strcpy(remcomOutBuffer, "ERROR"); break; diff -puN arch/ia64/lib/kgdb_serial.c~kgdb-ia64-fixes arch/ia64/lib/kgdb_serial.c --- 25/arch/ia64/lib/kgdb_serial.c~kgdb-ia64-fixes Wed Jun 2 14:47:32 2004 +++ 25-akpm/arch/ia64/lib/kgdb_serial.c Wed Jun 2 14:47:32 2004 @@ -567,16 +567,38 @@ void tty_flushDebugChar(void) void __init kgdb_serial_init(void) { - kgdb_enable_ints(); - if (!ints_disabled) { - extern char saved_command_line[]; - char *cp; - for (cp = saved_command_line; *cp; cp++) - if (memcmp(cp, "kgdb=1", 6) == 0) { - BREAKPOINT; - break; + extern char saved_command_line[]; + char *cp, *str; + int kgdbbreak = 0; + + for (cp = saved_command_line; *cp; cp++) { + if (memcmp(cp, "kgdb=1", 6) == 0) { + kgdbbreak = 1; + } + else if (memcmp(cp,"kgdbio=", 7) == 0) { + int baud; + + cp += 7; + baud = simple_strtoul(cp, &str, 10); + state.custom_divisor = SB_BASE/baud; + if (*str == ',') { + str++; + state.irq = simple_strtoul(str, &str, 10); + if (*str == ',') { + str++; + local_info.iomem_base = state.iomem_base = (char *) + simple_strtoul(str, &str, 0); + local_info.io_type = state.io_type = SERIAL_IO_MEM; + } } + printk("kgdb_serial_init: irq = %d iomem_base = 0x%lx baud = %d\n", + state.irq, state.iomem_base, baud); + } } + + kgdb_enable_ints(); + if (!ints_disabled && kgdbbreak) + BREAKPOINT; } #ifndef CONFIG_IA64_HP_SIM _