# HG changeset patch # User yamahata@xxxxxxxxxxxxx # Node ID aeebe099dae6d13beebd8c879dc011d5a1e4ff78 # Parent ea582eba5cd2bc3edc3c1dd7416a902c574602d2 ia64 specific part of gdbstub. Signed-off-by: Isaku Yamahtata diff -r ea582eba5cd2 -r aeebe099dae6 xen/arch/ia64/Makefile --- a/xen/arch/ia64/Makefile Mon Jan 23 12:25:55 2006 +0900 +++ b/xen/arch/ia64/Makefile Mon Jan 23 16:46:19 2006 +0900 @@ -22,6 +22,10 @@ memset.o strlen.o memcpy_mck.o \ __divsi3.o __udivsi3.o __modsi3.o __umodsi3.o \ __divdi3.o __udivdi3.o __moddi3.o __umoddi3.o + +ifeq ($(crash_debug),y) +OBJS += gdbstub.o +endif # xen stack unwinder # unwind_decoder.c is included in unwind.c diff -r ea582eba5cd2 -r aeebe099dae6 xen/arch/ia64/vmx/vmx_process.c --- a/xen/arch/ia64/vmx/vmx_process.c Mon Jan 23 12:25:55 2006 +0900 +++ b/xen/arch/ia64/vmx/vmx_process.c Mon Jan 23 16:46:19 2006 +0900 @@ -41,6 +41,7 @@ #include #include #include +#include //#include #include #include @@ -107,6 +108,14 @@ if (running_on_sim) do_ssc(vcpu_get_gr_nat(current,36), regs); else do_ssc(vcpu_get_gr_nat(current,36), regs); } +#endif +#ifdef CRASH_DEBUG + if ((iim == 0 || iim == CDB_BREAK_NUM) && !user_mode(regs) && + IS_VMM_ADDRESS(regs->cr_iip)) { + if (iim == 0) + show_registers(regs); + debugger_trap_fatal(0 /* don't care */, regs); + } else #endif if (iim == d->arch.breakimm) { struct ia64_pal_retval y; diff -r ea582eba5cd2 -r aeebe099dae6 xen/arch/ia64/xen/hyperprivop.S --- a/xen/arch/ia64/xen/hyperprivop.S Mon Jan 23 12:25:55 2006 +0900 +++ b/xen/arch/ia64/xen/hyperprivop.S Mon Jan 23 16:46:19 2006 +0900 @@ -12,6 +12,7 @@ #include #include #include +#include #include @@ -549,7 +550,12 @@ (p7) br.spnt.many 1f ;; cmp.eq p7,p0=r17,r0 (p7) br.spnt.few dispatch_break_fault ;; -1: +#ifdef CRASH_DEBUG + movl r21=CDB_BREAK_NUM ;; + cmp.eq p7,p0=r17,r21 +(p7) br.spnt.few dispatch_break_fault ;; +#endif +1: #if 1 /* special handling in case running on simulator */ movl r20=first_break;; ld4 r23=[r20];; diff -r ea582eba5cd2 -r aeebe099dae6 xen/arch/ia64/xen/ivt.S --- a/xen/arch/ia64/xen/ivt.S Mon Jan 23 12:25:55 2006 +0900 +++ b/xen/arch/ia64/xen/ivt.S Mon Jan 23 16:46:19 2006 +0900 @@ -15,6 +15,7 @@ #define sys_call_table 0 #define sys_ni_syscall 0 #include +#include #endif /* * arch/ia64/kernel/ivt.S @@ -841,6 +842,13 @@ ;; cmp.eq p7,p0=r17,r0 (p7) br.spnt.few dispatch_break_fault ;; +#ifdef CRASH_DEBUG + // panic can occur before domain0 is created. + // in such case referencing XSI_PSR_IC causes nested_dtlb_miss + movl r18=CDB_BREAK_NUM ;; + cmp.eq p7,p0=r17,r18 ;; +(p7) br.spnt.few dispatch_break_fault ;; +#endif movl r18=XSI_PSR_IC ;; ld8 r19=[r18] diff -r ea582eba5cd2 -r aeebe099dae6 xen/arch/ia64/xen/process.c --- a/xen/arch/ia64/xen/process.c Mon Jan 23 12:25:55 2006 +0900 +++ b/xen/arch/ia64/xen/process.c Mon Jan 23 16:46:19 2006 +0900 @@ -31,6 +31,7 @@ #include #include "hpsim_ssc.h" #include +#include extern unsigned long vcpu_get_itir_on_fault(struct vcpu *, UINT64); extern void die_if_kernel(char *str, struct pt_regs *regs, long err); @@ -652,7 +653,7 @@ ia64_handle_break (unsigned long ifa, struct pt_regs *regs, unsigned long isr, unsigned long iim) { struct domain *d = (struct domain *) current->domain; - struct vcpu *v = (struct domain *) current; + struct vcpu *v = current; extern unsigned long running_on_sim; if (first_break) { @@ -663,7 +664,14 @@ if (iim == 0x80001 || iim == 0x80002) { //FIXME: don't hardcode constant if (running_on_sim) do_ssc(vcpu_get_gr(current,36), regs); else do_ssc(vcpu_get_gr(current,36), regs); - } + } +#ifdef CRASH_DEBUG + else if ((iim == 0 || iim == CDB_BREAK_NUM) && !user_mode(regs)) { + if (iim == 0) + show_registers(regs); + debugger_trap_fatal(0 /* don't care */, regs); + } +#endif else if (iim == d->arch.breakimm) { /* by default, do not continue */ v->arch.hypercall_continuation = 0; diff -r ea582eba5cd2 -r aeebe099dae6 xen/arch/ia64/xen/xenmisc.c --- a/xen/arch/ia64/xen/xenmisc.c Mon Jan 23 12:25:55 2006 +0900 +++ b/xen/arch/ia64/xen/xenmisc.c Mon Jan 23 16:46:19 2006 +0900 @@ -18,6 +18,7 @@ #include #include #include +#include efi_memory_desc_t ia64_efi_io_md; EXPORT_SYMBOL(ia64_efi_io_md); @@ -356,6 +357,11 @@ va_end(args); printf(buf); if (regs) show_registers(regs); + if (regs) { + debugger_trap_fatal(0 /* don't care */, regs); + } else { + debugger_trap_immediate(); + } domain_pause_by_systemcontroller(current->domain); v->domain->shutdown_code = SHUTDOWN_crash; set_bit(_DOMF_shutdown, v->domain->domain_flags); diff -r ea582eba5cd2 -r aeebe099dae6 xen/common/Makefile --- a/xen/common/Makefile Mon Jan 23 12:25:55 2006 +0900 +++ b/xen/common/Makefile Mon Jan 23 16:46:19 2006 +0900 @@ -3,6 +3,9 @@ ifneq ($(perfc),y) OBJS := $(subst perfc.o,,$(OBJS)) +endif +ifneq ($(crash_debug),y) +OBJS := $(patsubst cdb.o,,$(OBJS)) endif ifneq ($(crash_debug),y) OBJS := $(patsubst gdbstub.o,,$(OBJS)) diff -r ea582eba5cd2 -r aeebe099dae6 xen/include/asm-ia64/debugger.h --- a/xen/include/asm-ia64/debugger.h Mon Jan 23 12:25:55 2006 +0900 +++ b/xen/include/asm-ia64/debugger.h Mon Jan 23 16:46:19 2006 +0900 @@ -24,6 +24,54 @@ #include +// this number is an arbitary number which is not used for any other purpose +// __builtin_trap(), FORCE_CRASH() 0x0 +// ski 0x80001, 0x80002 +// kdb 0x80100, 0x80101 +// kprobe 0x80200, jprobe 0x80300 +// kgdb 0x6665 +// gdb 0x99998 (#define IA64_BREAKPOINT 0x00003333300LL) + +// cdb should handle 0 and CDB_BREAK_NUM. +#define CDB_BREAK_NUM 0x80800 + + +#ifndef __ASSEMBLY__ + +#include + +// NOTE: on xen struct pt_regs = struct cpu_user_regs +// see include/asm-ia64/linux-xen/asm/ptrace.h +#ifdef CRASH_DEBUG +// crash_debug=y + +/* The main trap handlers use these helper macros which include early bail. */ +static inline int debugger_trap_entry( + unsigned int vector, struct cpu_user_regs *regs) +{ + return 0; +} + +extern int __trap_to_cdb(struct cpu_user_regs *r); +static inline int debugger_trap_fatal( + unsigned int vector, struct cpu_user_regs *regs) +{ + (void)__trap_to_gdb(regs, vector); + return 0; +} + +#define ____debugger_trap_immediate(b) __asm__ __volatile__ ("break.m "#b"\n") +#define __debugger_trap_immediate(b) ____debugger_trap_immediate(b) +#define debugger_trap_immediate() __debugger_trap_immediate(CDB_BREAK_NUM) + +//XXX temporal work around +#ifndef CONFIG_SMP +#define smp_send_stop() /* nothing */ +#endif + +#elif defined DOMU_DEBUG +// domu_debug=y +#warning "domu_debug is not implemented yet." /* The main trap handlers use these helper macros which include early bail. */ static inline int debugger_trap_entry( unsigned int vector, struct cpu_user_regs *regs) @@ -37,6 +85,23 @@ return 0; } -#define debugger_trap_immediate() do {} while(0) +#define debugger_trap_immediate() ((void)0) +#else +/* The main trap handlers use these helper macros which include early bail. */ +static inline int debugger_trap_entry( + unsigned int vector, struct cpu_user_regs *regs) +{ + return 0; +} + +static inline int debugger_trap_fatal( + unsigned int vector, struct cpu_user_regs *regs) +{ + return 0; +} + +#define debugger_trap_immediate() ((void)0) +#endif +#endif // __ASSEMBLLY__ #endif /* __ASM_DEBUGGER_H__ */ diff -r ea582eba5cd2 -r aeebe099dae6 xen/arch/ia64/xen/gdbstub.c --- /dev/null Thu Jan 1 00:00:00 1970 +0000 +++ b/xen/arch/ia64/xen/gdbstub.c Mon Jan 23 16:46:19 2006 +0900 @@ -0,0 +1,811 @@ +/* + * ia64-specific cdb routines + * cdb xen/ia64 by Isaku Yamahta + * VA Linux Systems Japan K.K. + * some routines are stolen from kgdb/ia64. + */ +/* + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2, or (at your option) any + * later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + */ + +/* + * Copyright (C) 2000-2001 VERITAS Software Corporation. + */ +/* + * Contributor: Lake Stevens Instrument Division$ + * Written by: Glenn Engel $ + * Updated by: Amit Kale + * Modified for 386 by Jim Kingdon, Cygnus Support. + * Origianl kgdb, compatibility with 2.1.xx kernel by David Grothe + * + */ + + +#include +#include +#include +#include + +#define USE_UNWIND + +#ifdef USE_UNWIND +#include +#endif + +/* Printk isn't particularly safe just after we've trapped to the + debugger. so avoid it. */ +#define dbg_printk(...) +//#define dbg_printk(...) printk(__VA_ARGS__) + +u16 +gdb_arch_signal_num(struct cpu_user_regs *regs, unsigned long cookie) +{ + /* XXX */ + return 1; +} + +void +gdb_arch_read_reg_array(struct cpu_user_regs *regs, struct gdb_context *ctx) +{ + gdb_send_reply("", ctx); +} + +void +gdb_arch_write_reg_array(struct cpu_user_regs *regs, const char* buf, + struct gdb_context *ctx) +{ + /* XXX TODO */ + gdb_send_reply("E02", ctx); +} + +/* Like copy_from_user, but safe to call with interrupts disabled. + Trust me, and don't look behind the curtain. */ +unsigned +gdb_arch_copy_from_user(void *dest, const void *src, unsigned len) +{ + int val; + __asm__ __volatile__( + "cmp4.eq p6, p0 = r0, %1\n" + "(p6) br.cond.dptk 2f\n" + "[1:]\n" + ".xdata4 \"__ex_table\", 99f-., 2f-.;\n" + "[99:] ld1 %0 = [%3], 1\n" + ";;\n" + ".xdata4 \"__ex_table\", 99f-., 2f-.;\n" + "[99:] st1 [%2] = %0, 1\n" + "adds %1 = -1, %1\n" + ";;\n" + "cmp4.eq p0, p6 = r0, %1\n" + "(p6) br.cond.dptk 1b\n" + "[2:]\n" + : "=r"(val), "=r"(len), "=r"(dest), "=r"(src) + : "1"(len), "2"(dest), "3"(src) + : "memory", "p6"); + return len; +} + +unsigned int +gdb_arch_copy_to_user(void *dest, const void *src, unsigned len) +{ + /* XXX */ + return len; +} + +#define NUM_REGS 590 +#define REGISTER_BYTES (NUM_REGS*8+128*8) +#define REGISTER_BYTE(N) (((N) * 8) \ + + ((N) <= IA64_FR0_REGNUM ? \ + 0 : 8 * (((N) > IA64_FR127_REGNUM) ? 128 : (N) - IA64_FR0_REGNUM))) +#define REGISTER_SIZE(N) \ + (((N) >= IA64_FR0_REGNUM && (N) <= IA64_FR127_REGNUM) ? 16 : 8) +#define IA64_GR0_REGNUM 0 +#define IA64_FR0_REGNUM 128 +#define IA64_FR127_REGNUM (IA64_FR0_REGNUM+127) +#define IA64_PR0_REGNUM 256 +#define IA64_BR0_REGNUM 320 +#define IA64_VFP_REGNUM 328 +#define IA64_PR_REGNUM 330 +#define IA64_IP_REGNUM 331 +#define IA64_PSR_REGNUM 332 +#define IA64_CFM_REGNUM 333 +#define IA64_AR0_REGNUM 334 +#define IA64_NAT0_REGNUM 462 +#define IA64_NAT31_REGNUM (IA64_NAT0_REGNUM+31) +#define IA64_NAT32_REGNUM (IA64_NAT0_REGNUM+32) +#define IA64_RSC_REGNUM (IA64_AR0_REGNUM+16) +#define IA64_BSP_REGNUM (IA64_AR0_REGNUM+17) +#define IA64_BSPSTORE_REGNUM (IA64_AR0_REGNUM+18) +#define IA64_RNAT_REGNUM (IA64_AR0_REGNUM+19) +#define IA64_FCR_REGNUM (IA64_AR0_REGNUM+21) +#define IA64_EFLAG_REGNUM (IA64_AR0_REGNUM+24) +#define IA64_CSD_REGNUM (IA64_AR0_REGNUM+25) +#define IA64_SSD_REGNUM (IA64_AR0_REGNUM+26) +#define IA64_CFLG_REGNUM (IA64_AR0_REGNUM+27) +#define IA64_FSR_REGNUM (IA64_AR0_REGNUM+28) +#define IA64_FIR_REGNUM (IA64_AR0_REGNUM+29) +#define IA64_FDR_REGNUM (IA64_AR0_REGNUM+30) +#define IA64_CCV_REGNUM (IA64_AR0_REGNUM+32) +#define IA64_UNAT_REGNUM (IA64_AR0_REGNUM+36) +#define IA64_FPSR_REGNUM (IA64_AR0_REGNUM+40) +#define IA64_ITC_REGNUM (IA64_AR0_REGNUM+44) +#define IA64_PFS_REGNUM (IA64_AR0_REGNUM+64) +#define IA64_LC_REGNUM (IA64_AR0_REGNUM+65) +#define IA64_EC_REGNUM (IA64_AR0_REGNUM+66) + +#ifndef USE_UNWIND +struct regs_to_cpu_user_resgs_index { + unsigned int reg; + unsigned int ptregoff; +}; + +#define ptoff(V) ((unsigned int)&((struct cpu_user_regs*)0x0)->V) + +// gr +static const struct regs_to_cpu_user_resgs_index +gr_reg_to_cpu_user_regs_index[] = { + {IA64_GR0_REGNUM + 8, ptoff(r8)}, + {IA64_GR0_REGNUM + 9, ptoff(r9)}, + {IA64_GR0_REGNUM + 10, ptoff(r10)}, + {IA64_GR0_REGNUM + 11, ptoff(r11)}, + {IA64_GR0_REGNUM + 1, ptoff(r1)}, + {IA64_GR0_REGNUM + 12, ptoff(r12)}, + {IA64_GR0_REGNUM + 13, ptoff(r13)}, + {IA64_GR0_REGNUM + 15, ptoff(r15)}, + + {IA64_GR0_REGNUM + 14, ptoff(r14)}, + {IA64_GR0_REGNUM + 2, ptoff(r2)}, + {IA64_GR0_REGNUM + 3, ptoff(r3)}, + {IA64_GR0_REGNUM + 16, ptoff(r16)}, + {IA64_GR0_REGNUM + 17, ptoff(r17)}, + {IA64_GR0_REGNUM + 18, ptoff(r18)}, + {IA64_GR0_REGNUM + 19, ptoff(r19)}, + {IA64_GR0_REGNUM + 20, ptoff(r20)}, + {IA64_GR0_REGNUM + 21, ptoff(r21)}, + {IA64_GR0_REGNUM + 22, ptoff(r22)}, + {IA64_GR0_REGNUM + 23, ptoff(r23)}, + {IA64_GR0_REGNUM + 24, ptoff(r24)}, + {IA64_GR0_REGNUM + 25, ptoff(r25)}, + {IA64_GR0_REGNUM + 26, ptoff(r26)}, + {IA64_GR0_REGNUM + 27, ptoff(r27)}, + {IA64_GR0_REGNUM + 28, ptoff(r28)}, + {IA64_GR0_REGNUM + 29, ptoff(r29)}, + {IA64_GR0_REGNUM + 30, ptoff(r30)}, + {IA64_GR0_REGNUM + 31, ptoff(r31)}, + + {IA64_GR0_REGNUM + 4, ptoff(r4)}, + {IA64_GR0_REGNUM + 5, ptoff(r5)}, + {IA64_GR0_REGNUM + 6, ptoff(r6)}, + {IA64_GR0_REGNUM + 7, ptoff(r7)}, +}; +static const int gr_reg_to_cpu_user_regs_index_max = + sizeof(gr_reg_to_cpu_user_regs_index) / + sizeof(gr_reg_to_cpu_user_regs_index[0]); + +// br +static const struct regs_to_cpu_user_resgs_index +br_reg_to_cpu_user_regs_index[] = { + {IA64_BR0_REGNUM + 0, ptoff(b0)}, + {IA64_BR0_REGNUM + 6, ptoff(b6)}, + {IA64_BR0_REGNUM + 7, ptoff(b7)}, +}; +static const int br_reg_to_cpu_user_regs_index_max = + sizeof(br_reg_to_cpu_user_regs_index) / + sizeof(br_reg_to_cpu_user_regs_index[0]); + +// f +static const struct regs_to_cpu_user_resgs_index +fr_reg_to_cpu_user_regs_index[] = { + {IA64_FR0_REGNUM + 6, ptoff(f6)}, + {IA64_FR0_REGNUM + 7, ptoff(f7)}, + {IA64_FR0_REGNUM + 8, ptoff(f8)}, + {IA64_FR0_REGNUM + 9, ptoff(f9)}, + {IA64_FR0_REGNUM + 10, ptoff(f10)}, + {IA64_FR0_REGNUM + 11, ptoff(f11)}, +}; +static const int fr_reg_to_cpu_user_regs_index_max = + sizeof(fr_reg_to_cpu_user_regs_index) / + sizeof(fr_reg_to_cpu_user_regs_index[0]); + + +void +gdb_arch_read_reg(unsigned long regnum, struct cpu_user_regs *regs, + struct gdb_context *ctx) +{ + unsigned long reg = IA64_IP_REGNUM; + char buf[9]; + int i; + + dbg_printk("Register read regnum = 0x%lx\n", regnum); + if (IA64_GR0_REGNUM <= regnum && regnum <= IA64_GR0_REGNUM + 31) { + for (i = 0; i < gr_reg_to_cpu_user_regs_index_max; i++) { + if (gr_reg_to_cpu_user_regs_index[i].reg == regnum) { + reg = *(unsigned long*)(((char*)regs) + gr_reg_to_cpu_user_regs_index[i].ptregoff); + break; + } + } + if (i == gr_reg_to_cpu_user_regs_index_max) { + goto out_err; + } + } else if (IA64_BR0_REGNUM <= regnum && regnum <= IA64_BR0_REGNUM + 7) { + for (i = 0; i < br_reg_to_cpu_user_regs_index_max; i++) { + if (br_reg_to_cpu_user_regs_index[i].reg == regnum) { + reg = *(unsigned long*)(((char*)regs) + br_reg_to_cpu_user_regs_index[i].ptregoff); + break; + } + } + if (i == br_reg_to_cpu_user_regs_index_max) { + goto out_err; + } + } else if (IA64_FR0_REGNUM + 6 <= regnum && regnum <= IA64_FR0_REGNUM + 11) { + for (i = 0; i < fr_reg_to_cpu_user_regs_index_max; i++) { + if (fr_reg_to_cpu_user_regs_index[i].reg == regnum) { + reg = *(unsigned long*)(((char*)regs) + fr_reg_to_cpu_user_regs_index[i].ptregoff); + break; + } + } + if (i == fr_reg_to_cpu_user_regs_index_max) { + goto out_err; + } + } else if (regnum == IA64_CSD_REGNUM) { + reg = regs->ar_csd; + } else if (regnum == IA64_SSD_REGNUM) { + reg = regs->ar_ssd; + } else if (regnum == IA64_PSR_REGNUM) { + reg = regs->cr_ipsr; + } else if (regnum == IA64_IP_REGNUM) { + reg = regs->cr_iip; + } else if (regnum == IA64_CFM_REGNUM) { + reg = regs->cr_ifs; + } else if (regnum == IA64_UNAT_REGNUM) { + reg = regs->ar_unat; + } else if (regnum == IA64_PFS_REGNUM) { + reg = regs->ar_pfs; + } else if (regnum == IA64_RSC_REGNUM) { + reg = regs->ar_rsc; + } else if (regnum == IA64_RNAT_REGNUM) { + reg = regs->ar_rnat; + } else if (regnum == IA64_BSPSTORE_REGNUM) { + reg = regs->ar_bspstore; + } else if (regnum == IA64_PR_REGNUM) { + reg = regs->pr; + } else if (regnum == IA64_FPSR_REGNUM) { + reg = regs->ar_fpsr; + } else if (regnum == IA64_CCV_REGNUM) { + reg = regs->ar_ccv; + } else { + // emul_unat, rfi_pfs + goto out_err; + } + + dbg_printk("Register read regnum = 0x%lx, val = 0x%lx\n", regnum, reg); + sprintf(buf, "%.08lx", swab64(reg)); +out: + return gdb_send_reply(buf, ctx); + +out_err: + dbg_printk("Register read unsupported regnum = 0x%lx\n", regnum); + sprintf(buf, "%s", "x"); + goto out; +} +#else + +#define ptoff(V) ((unsigned int) &((struct pt_regs *)0x0)->V) +struct reg_to_ptreg_index { + unsigned int reg; + unsigned int ptregoff; +}; + +static struct reg_to_ptreg_index gr_reg_to_ptreg_index[] = { + {IA64_GR0_REGNUM + 1, ptoff(r1)}, + {IA64_GR0_REGNUM + 2, ptoff(r2)}, + {IA64_GR0_REGNUM + 3, ptoff(r3)}, + {IA64_GR0_REGNUM + 8, ptoff(r8)}, + {IA64_GR0_REGNUM + 9, ptoff(r9)}, + {IA64_GR0_REGNUM + 10, ptoff(r10)}, + {IA64_GR0_REGNUM + 11, ptoff(r11)}, + {IA64_GR0_REGNUM + 12, ptoff(r12)}, + {IA64_GR0_REGNUM + 13, ptoff(r13)}, + {IA64_GR0_REGNUM + 14, ptoff(r14)}, + {IA64_GR0_REGNUM + 15, ptoff(r15)}, + {IA64_GR0_REGNUM + 16, ptoff(r16)}, + {IA64_GR0_REGNUM + 17, ptoff(r17)}, + {IA64_GR0_REGNUM + 18, ptoff(r18)}, + {IA64_GR0_REGNUM + 19, ptoff(r19)}, + {IA64_GR0_REGNUM + 20, ptoff(r20)}, + {IA64_GR0_REGNUM + 21, ptoff(r21)}, + {IA64_GR0_REGNUM + 22, ptoff(r22)}, + {IA64_GR0_REGNUM + 23, ptoff(r23)}, + {IA64_GR0_REGNUM + 24, ptoff(r24)}, + {IA64_GR0_REGNUM + 25, ptoff(r25)}, + {IA64_GR0_REGNUM + 26, ptoff(r26)}, + {IA64_GR0_REGNUM + 27, ptoff(r27)}, + {IA64_GR0_REGNUM + 28, ptoff(r28)}, + {IA64_GR0_REGNUM + 29, ptoff(r29)}, + {IA64_GR0_REGNUM + 30, ptoff(r30)}, + {IA64_GR0_REGNUM + 31, ptoff(r31)}, +}; + +static struct reg_to_ptreg_index br_reg_to_ptreg_index[] = { + {IA64_BR0_REGNUM, ptoff(b0)}, + {IA64_BR0_REGNUM + 6, ptoff(b6)}, + {IA64_BR0_REGNUM + 7, ptoff(b7)}, +}; + +static struct reg_to_ptreg_index ar_reg_to_ptreg_index[] = { + {IA64_PFS_REGNUM, ptoff(ar_pfs)}, + {IA64_UNAT_REGNUM, ptoff(ar_unat)}, + {IA64_RNAT_REGNUM, ptoff(ar_rnat)}, + {IA64_BSPSTORE_REGNUM, ptoff(ar_bspstore)}, + {IA64_RSC_REGNUM, ptoff(ar_rsc)}, + {IA64_CSD_REGNUM, ptoff(ar_csd)}, + {IA64_SSD_REGNUM, ptoff(ar_ssd)}, + {IA64_FPSR_REGNUM, ptoff(ar_fpsr)}, + {IA64_CCV_REGNUM, ptoff(ar_ccv)}, +}; + +#ifndef XEN +extern atomic_t cpu_doing_single_step; +#endif + +static int kgdb_gr_reg(int regnum, struct unw_frame_info *info, + unsigned long *reg, int rw) +{ + char nat; + + if ((regnum >= IA64_GR0_REGNUM && regnum <= (IA64_GR0_REGNUM + 1)) || + (regnum >= (IA64_GR0_REGNUM + 4) && + regnum <= (IA64_GR0_REGNUM + 7))) + return !unw_access_gr(info, regnum - IA64_GR0_REGNUM, + reg, &nat, rw); + else + return 0; +} +static int kgdb_gr_ptreg(int regnum, struct pt_regs * ptregs, + struct unw_frame_info *info, unsigned long *reg, int rw) +{ + int i, result = 1; + char nat; + + if (!((regnum >= (IA64_GR0_REGNUM + 2) && + regnum <= (IA64_GR0_REGNUM + 3)) || + (regnum >= (IA64_GR0_REGNUM + 8) && + regnum <= (IA64_GR0_REGNUM + 15)) || + (regnum >= (IA64_GR0_REGNUM + 16) && + regnum <= (IA64_GR0_REGNUM + 31)))) + return 0; + else if (rw && ptregs) { + for (i = 0; i < ARRAY_SIZE(gr_reg_to_ptreg_index); i++) + if (gr_reg_to_ptreg_index[i].reg == regnum) { + *((unsigned long *)(((void *)ptregs) + + gr_reg_to_ptreg_index[i].ptregoff)) = *reg; + break; + } + } else if (!rw && ptregs) { + for (i = 0; i < ARRAY_SIZE(gr_reg_to_ptreg_index); i++) + if (gr_reg_to_ptreg_index[i].reg == regnum) { + *reg = *((unsigned long *) + (((void *)ptregs) + + gr_reg_to_ptreg_index[i].ptregoff)); + break; + } + } else + result = !unw_access_gr(info, regnum - IA64_GR0_REGNUM, + reg, &nat, rw); + return result; +} + +static int kgdb_br_reg(int regnum, struct pt_regs * ptregs, + struct unw_frame_info *info, unsigned long *reg, int rw) +{ + int i, result = 1; + + if (!(regnum >= IA64_BR0_REGNUM && regnum <= (IA64_BR0_REGNUM + 7))) + return 0; + + switch (regnum) { + case IA64_BR0_REGNUM: + case IA64_BR0_REGNUM + 6: + case IA64_BR0_REGNUM + 7: + if (rw) { + for (i = 0; i < ARRAY_SIZE(br_reg_to_ptreg_index); i++) + if (br_reg_to_ptreg_index[i].reg == regnum) { + *((unsigned long *) + (((void *)ptregs) + + br_reg_to_ptreg_index[i].ptregoff)) = + *reg; + break; + } + } else + for (i = 0; i < ARRAY_SIZE(br_reg_to_ptreg_index); i++) + if (br_reg_to_ptreg_index[i].reg == regnum) { + *reg = *((unsigned long *) + (((void *)ptregs) + + br_reg_to_ptreg_index[i]. + ptregoff)); + break; + } + break; + case IA64_BR0_REGNUM + 1: + case IA64_BR0_REGNUM + 2: + case IA64_BR0_REGNUM + 3: + case IA64_BR0_REGNUM + 4: + case IA64_BR0_REGNUM + 5: + result = !unw_access_br(info, regnum - IA64_BR0_REGNUM, + reg, rw); + break; + } + + return result; +} + +static int kgdb_fr_reg(int regnum, char *inbuffer, struct pt_regs * ptregs, + struct unw_frame_info *info, unsigned long *reg, + struct ia64_fpreg *freg, int rw) +{ + int result = 1; + + if (!(regnum >= IA64_FR0_REGNUM && regnum <= (IA64_FR0_REGNUM + 127))) + return 0; + + switch (regnum) { + case IA64_FR0_REGNUM + 6: + case IA64_FR0_REGNUM + 7: + case IA64_FR0_REGNUM + 8: + case IA64_FR0_REGNUM + 9: + case IA64_FR0_REGNUM + 10: + case IA64_FR0_REGNUM + 11: + case IA64_FR0_REGNUM + 12: + if (rw) { +#ifndef XEN + char *ptr = inbuffer; + + freg->u.bits[0] = *reg; + kgdb_hex2long(&ptr, &freg->u.bits[1]); + *(&ptregs->f6 + (regnum - (IA64_FR0_REGNUM + 6))) = + *freg; +#else + printk("%s: %d: writing to fpreg is not supported.\n", + __func__, __LINE__); +#endif + break; + } else if (!ptregs) + result = !unw_access_fr(info, regnum - IA64_FR0_REGNUM, + freg, rw); + else +#ifndef XEN + *freg = + *(&ptregs->f6 + (regnum - (IA64_FR0_REGNUM + 6))); +#else + //XXX struct ia64_fpreg and struct pt_fpreg are same. + *freg = *((struct ia64_fpreg*)(&ptregs->f6 + + (regnum - (IA64_FR0_REGNUM + 6)))); +#endif + break; + default: + if (!rw) + result = !unw_access_fr(info, regnum - IA64_FR0_REGNUM, + freg, rw); + else + result = 0; + break; + } + + return result; +} + +static int kgdb_ar_reg(int regnum, struct pt_regs * ptregs, + struct unw_frame_info *info, unsigned long *reg, int rw) +{ + int result = 0, i; + + if (!(regnum >= IA64_AR0_REGNUM && regnum <= IA64_EC_REGNUM)) + return 0; + + if (rw && ptregs) { + for (i = 0; i < ARRAY_SIZE(ar_reg_to_ptreg_index); i++) + if (ar_reg_to_ptreg_index[i].reg == regnum) { + *((unsigned long *) (((void *)ptregs) + + ar_reg_to_ptreg_index[i].ptregoff)) = + *reg; + result = 1; + break; + } + } else if (ptregs) { + for (i = 0; i < ARRAY_SIZE(ar_reg_to_ptreg_index); i++) + if (ar_reg_to_ptreg_index[i].reg == regnum) { + *reg = *((unsigned long *) (((void *)ptregs) + + ar_reg_to_ptreg_index[i].ptregoff)); + result = 1; + break; + } + } + + if (result) + return result; + + result = 1; + + switch (regnum) { + case IA64_CSD_REGNUM: + result = !unw_access_ar(info, UNW_AR_CSD, reg, rw); + break; + case IA64_SSD_REGNUM: + result = !unw_access_ar(info, UNW_AR_SSD, reg, rw); + break; + case IA64_UNAT_REGNUM: + result = !unw_access_ar(info, UNW_AR_RNAT, reg, rw); + break; + case IA64_RNAT_REGNUM: + result = !unw_access_ar(info, UNW_AR_RNAT, reg, rw); + break; + case IA64_BSPSTORE_REGNUM: + result = !unw_access_ar(info, UNW_AR_RNAT, reg, rw); + break; + case IA64_PFS_REGNUM: + result = !unw_access_ar(info, UNW_AR_RNAT, reg, rw); + break; + case IA64_LC_REGNUM: + result = !unw_access_ar(info, UNW_AR_LC, reg, rw); + break; + case IA64_EC_REGNUM: + result = !unw_access_ar(info, UNW_AR_EC, reg, rw); + break; + case IA64_FPSR_REGNUM: + result = !unw_access_ar(info, UNW_AR_FPSR, reg, rw); + break; + case IA64_RSC_REGNUM: + result = !unw_access_ar(info, UNW_AR_RSC, reg, rw); + break; + case IA64_CCV_REGNUM: + result = !unw_access_ar(info, UNW_AR_CCV, reg, rw); + break; + default: + result = 0; + } + + return result; +} + +#ifndef XEN +void kgdb_get_reg(char *outbuffer, int regnum, struct unw_frame_info *info, + struct pt_regs *ptregs) +#else +static int +kgdb_get_reg(int regnum, struct unw_frame_info *info, + struct cpu_user_regs* ptregs, + unsigned long* __reg, struct ia64_fpreg* __freg) +#endif +{ + unsigned long reg, size = 0, *mem = ® + struct ia64_fpreg freg; + + if (kgdb_gr_reg(regnum, info, ®, 0) || + kgdb_gr_ptreg(regnum, ptregs, info, ®, 0) || + kgdb_br_reg(regnum, ptregs, info, ®, 0) || + kgdb_ar_reg(regnum, ptregs, info, ®, 0)) + size = sizeof(reg); + else if (kgdb_fr_reg(regnum, NULL, ptregs, info, ®, &freg, 0)) { + size = sizeof(freg); + mem = (unsigned long *)&freg; + } else if (regnum == IA64_IP_REGNUM) { + if (!ptregs) { + unw_get_ip(info, ®); + size = sizeof(reg); + } else { + reg = ptregs->cr_iip; + size = sizeof(reg); + } + } else if (regnum == IA64_CFM_REGNUM) { + if (!ptregs) + unw_get_cfm(info, ®); + else + reg = ptregs->cr_ifs; + size = sizeof(reg); + } else if (regnum == IA64_PSR_REGNUM) { +#ifndef XEN + if (!ptregs && kgdb_usethread) + ptregs = (struct pt_regs *) + ((unsigned long)kgdb_usethread + + IA64_STK_OFFSET) - 1; +#endif + if (ptregs) + reg = ptregs->cr_ipsr; + size = sizeof(reg); + } else if (regnum == IA64_PR_REGNUM) { + if (ptregs) + reg = ptregs->pr; + else + unw_access_pr(info, ®, 0); + size = sizeof(reg); + } else if (regnum == IA64_BSP_REGNUM) { + unw_get_bsp(info, ®); + size = sizeof(reg); + } + +#ifndef XEN + if (size) { + kgdb_mem2hex((char *) mem, outbuffer, size); + outbuffer[size*2] = 0; + } + else + strcpy(outbuffer, "E0"); + + return; +#else + if (size) { + if (size == sizeof(reg)) { + *__reg = reg; + } else { + BUG_ON(size != sizeof(freg)); + *__freg = freg; + } + return 0; + } + + return -1; +#endif +} + +#ifndef XEN +static int inline kgdb_get_blocked_state(struct task_struct *p, + struct unw_frame_info *unw) +#else +static int +kgdb_get_blocked_state(struct vcpu *p, + struct cpu_user_regs *regs, + struct unw_frame_info *unw) +#endif +{ + unsigned long ip; + int count = 0; + +#ifndef XEN + unw_init_from_blocked_task(unw, p); +#endif + ip = 0UL; + do { + if (unw_unwind(unw) < 0) + return -1; + unw_get_ip(unw, &ip); +#ifndef XEN + if (!in_sched_functions(ip)) + break; +#else + dbg_printk("ip 0x%lx cr_iip 0x%lx\n", ip, regs->cr_iip); + if (ip == regs->cr_iip) + break; +#endif + } while (count++ < 16); + + if (!ip) + return -1; + else + return 0; +} + +struct gdb_callback_arg +{ + struct cpu_user_regs* regs; + unsigned long regnum; + unsigned long* reg; + struct pt_fpreg* freg; + + int error; + // 1: not supported + // 0: success + // -1: failure +}; + +static void +gdb_get_reg_callback(struct unw_frame_info* info, void* __arg) +{ + struct gdb_callback_arg* arg = (struct gdb_callback_arg*)__arg; + + if (kgdb_get_blocked_state(current, arg->regs, info) < 0) { + dbg_printk("%s: kgdb_get_blocked_state failed\n", __func__); + arg->error = -1; + return; + } + //XXX struct ia64_fpreg and struct pt_fpreg are same. + if (kgdb_get_reg(arg->regnum, info, arg->regs, arg->reg, + (struct ia64_fpreg*)arg->freg) < 0) { + dbg_printk("%s: kgdb_get_reg failed\n", __func__); + arg->error = 1; + return; + } + arg->error = 0; + return; +} + +void +gdb_arch_read_reg(unsigned long regnum, struct cpu_user_regs *regs, + struct gdb_context *ctx) +{ + struct gdb_callback_arg arg; + unsigned long reg; + struct pt_fpreg freg; + char buf[16 * 2 + 1]; + + if (regnum >= NUM_REGS) { + dbg_printk("%s: regnum %ld\n", __func__, regnum); + goto out_err; + } + + arg.regs = regs; + arg.regnum = regnum; + arg.reg = ® + arg.freg = &freg; + arg.error = 0; + unw_init_running(&gdb_get_reg_callback, (void*)&arg); + if (arg.error < 0) { + dbg_printk("%s: gdb_get_reg_callback failed\n", __func__); + goto out_err; + } + + if (arg.error > 0) { + // notify gdb that this register is not supported. + // see fetch_register_using_p() in gdb/remote.c. + sprintf(buf, "%s", "x"); + } else if (IA64_FR0_REGNUM <= regnum && regnum <= IA64_FR0_REGNUM + 127) { + sprintf(buf, "%.016lx", swab64(freg.u.bits[0])); + sprintf(buf + 16, "%.016lx", swab64(freg.u.bits[1])); + } else { + sprintf(buf, "%.016lx", swab64(reg)); + } +out: + return gdb_send_reply(buf, ctx); + +out_err: + dbg_printk("Register read unsupported regnum = 0x%lx\n", regnum); + sprintf(buf, "%s", "E0"); + goto out; +} +#endif + +void +gdb_arch_resume(struct cpu_user_regs *regs, + unsigned long addr, unsigned long type, + struct gdb_context *ctx) +{ + /* XXX */ + if (type == GDB_STEP) { + gdb_send_reply("S01", ctx); + } +} + +void +gdb_arch_print_state(struct cpu_user_regs *regs) +{ + /* XXX */ +} + +void +gdb_arch_enter(struct cpu_user_regs *regs) +{ + /* nothing */ +} + +void +gdb_arch_exit(struct cpu_user_regs *regs) +{ + /* nothing */ +} + +/* + * Local variables: + * mode: C + * c-set-style: "BSD" + * c-basic-offset: 4 + * tab-width: 4 + * End: + */