From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: (qmail 14725 invoked by alias); 28 Feb 2008 16:57:36 -0000 Received: (qmail 14709 invoked by uid 22791); 28 Feb 2008 16:57:34 -0000 X-Spam-Check-By: sourceware.org Received: from mtagate1.de.ibm.com (HELO mtagate1.de.ibm.com) (195.212.29.150) by sourceware.org (qpsmtpd/0.31) with ESMTP; Thu, 28 Feb 2008 16:57:10 +0000 Received: from d12nrmr1507.megacenter.de.ibm.com (d12nrmr1507.megacenter.de.ibm.com [9.149.167.1]) by mtagate1.de.ibm.com (8.13.8/8.13.8) with ESMTP id m1SGv8jc159042 for ; Thu, 28 Feb 2008 16:57:08 GMT Received: from d12av02.megacenter.de.ibm.com (d12av02.megacenter.de.ibm.com [9.149.165.228]) by d12nrmr1507.megacenter.de.ibm.com (8.13.8/8.13.8/NCO v8.7) with ESMTP id m1SGv7do1970382 for ; Thu, 28 Feb 2008 17:57:07 +0100 Received: from d12av02.megacenter.de.ibm.com (loopback [127.0.0.1]) by d12av02.megacenter.de.ibm.com (8.12.11.20060308/8.13.3) with ESMTP id m1SGv6p7001196 for ; Thu, 28 Feb 2008 16:57:07 GMT Received: from tuxmaker.boeblingen.de.ibm.com (tuxmaker.boeblingen.de.ibm.com [9.152.85.9]) by d12av02.megacenter.de.ibm.com (8.12.11.20060308/8.12.11) with SMTP id m1SGv67A001187; Thu, 28 Feb 2008 16:57:06 GMT Message-Id: <200802281657.m1SGv67A001187@d12av02.megacenter.de.ibm.com> Received: by tuxmaker.boeblingen.de.ibm.com (sSMTP sendmail emulation); Thu, 28 Feb 2008 17:57:06 +0100 Subject: [rfc/rft] ppc gdbserver: autodetect AltiVec and SPE To: drow@false.org (Daniel Jacobowitz) Date: Thu, 28 Feb 2008 17:03:00 -0000 From: "Ulrich Weigand" Cc: gdb-patches@sourceware.org In-Reply-To: <20080228135240.GA8988@caradoc.them.org> from "Daniel Jacobowitz" at Feb 28, 2008 08:52:40 AM X-Mailer: ELM [version 2.5 PL2] MIME-Version: 1.0 Content-Type: text/plain; charset=us-ascii Content-Transfer-Encoding: 7bit Mailing-List: contact gdb-patches-help@sourceware.org; run by ezmlm Precedence: bulk List-Id: List-Subscribe: List-Archive: List-Post: List-Help: , Sender: gdb-patches-owner@sourceware.org X-SW-Source: 2008-02/txt/msg00479.txt.bz2 Daniel Jacobowitz wrote: > > Agreed. I'll see if I can put a patch along those lines together. > > However, I don't have any non-AltiVec or SPE systems available; > > would you be able to test on those? > > Yes, definitely. We've got both. That would be great, thanks! What you do think about this patch? It uses the AT_HWCAP auxv entry to check for AltiVec and SPE. One minor annoyance is that you need to know the target wordsize in order to correctly interpret the auxv array. Therefore, we have to do the 64/32 check first, and only then can we read auxv. AltiVec and SPE regset access is now enabled uncoditionally, but the fill/store routines make sure the corresponding HWCAP is set to avoid accessing registers that are not present in the select register map. With SPE there were a number of additional issues: - The ppc_regmap used conditional defines to disable access to floating point registers; I'm now using two different regmaps and switch them in the arch_setup routine. - As the regmap was defined only for 32-bit host machines, I've disabled SPE support on 64-bit hosts. I don't think there are any 64-bit machines with SPE anyway, right? - There was a conditional check for fpscr in ppc_cannot_store_register; but as this routine is never called for fpscr in SPE mode, the check seems superfluous and I just removed it. Tested on powerpc-linux and powerpc64-linux (-m64 and -m32) with no regressions; properly detects AltiVec support. Bye, Ulrich ChangeLog: * configure.srv [powerpc64-*-linux*]: Remove powerpc-e500.o from srv_regobj. Remove rs6000/powerpc-e500.xml and rs6000/power-spe.xml from reg_xmlfiles. * linux-ppc-low.c: Include . (PPC_FEATURE_HAS_ALTIVEC, PPC_FEATURE_HAS_SPE): Define. (ppc_hwcap): New global variable. (ppc_regmap): Remove __SPE__ #ifdef sections. (ppc_regmap_e500): New global variable. (ppc_cannot_store_register): Remove __SPE__ special case. (ppc_get_hwcap): New function. (ppc_arch_setup): Use it to determine whether inferior supports AltiVec or SPE registers. Set the_low_target.regmap if appropriate. (ppc_fill_vrregset, ppc_store_vrregset): Define unconditionally. Do not access registers if target does not support AltiVec. (ppc_fill_evrregset, ppc_store_evrregset): Define unconditionally. Do not access registers if target does not support SPE. (target_regsets): Unconditionally include AltiVec and SPE regsets. diff -urNp gdb-orig/gdb/gdbserver/configure.srv gdb-head/gdb/gdbserver/configure.srv --- gdb-orig/gdb/gdbserver/configure.srv 2008-02-28 06:56:04.000000000 +0100 +++ gdb-head/gdb/gdbserver/configure.srv 2008-02-28 17:17:47.488329501 +0100 @@ -106,15 +106,13 @@ case "${target}" in srv_linux_usrregs=yes srv_linux_thread_db=yes ;; - powerpc64-*-linux*) srv_regobj="reg-ppc.o powerpc-32.o powerpc-e500.o" + powerpc64-*-linux*) srv_regobj="reg-ppc.o powerpc-32.o" srv_regobj="${srv_regobj} reg-ppc64.o powerpc-64.o" srv_tgtobj="linux-low.o linux-ppc-low.o" srv_xmlfiles="rs6000/powerpc-32.xml" srv_xmlfiles="${srv_xmlfiles} rs6000/power-altivec.xml" srv_xmlfiles="${srv_xmlfiles} rs6000/power-core.xml" srv_xmlfiles="${srv_xmlfiles} rs6000/power-fpu.xml" - srv_xmlfiles="${srv_xmlfiles} rs6000/powerpc-e500.xml" - srv_xmlfiles="${srv_xmlfiles} rs6000/power-spe.xml" srv_xmlfiles="${srv_xmlfiles} rs6000/powerpc-64.xml" srv_xmlfiles="${srv_xmlfiles} rs6000/power64-core.xml" srv_linux_usrregs=yes diff -urNp gdb-orig/gdb/gdbserver/linux-ppc-low.c gdb-head/gdb/gdbserver/linux-ppc-low.c --- gdb-orig/gdb/gdbserver/linux-ppc-low.c 2008-02-28 06:56:04.000000000 +0100 +++ gdb-head/gdb/gdbserver/linux-ppc-low.c 2008-02-28 17:18:50.462849876 +0100 @@ -21,8 +21,16 @@ #include "server.h" #include "linux-low.h" +#include #include +/* These are in in current kernels. */ +#define PPC_FEATURE_HAS_ALTIVEC 0x10000000 +#define PPC_FEATURE_HAS_SPE 0x00800000 + +static unsigned long ppc_hwcap; + + /* Defined in auto-generated file reg-ppc.c. */ void init_registers_ppc (void); /* Defined in auto-generated file powerpc-32.c. */ @@ -69,16 +77,6 @@ static int ppc_regmap[] = PT_R20 * 4, PT_R21 * 4, PT_R22 * 4, PT_R23 * 4, PT_R24 * 4, PT_R25 * 4, PT_R26 * 4, PT_R27 * 4, PT_R28 * 4, PT_R29 * 4, PT_R30 * 4, PT_R31 * 4, -#ifdef __SPE__ - -1, -1, -1, -1, - -1, -1, -1, -1, - -1, -1, -1, -1, - -1, -1, -1, -1, - -1, -1, -1, -1, - -1, -1, -1, -1, - -1, -1, -1, -1, - -1, -1, -1, -1, -#else PT_FPR0*4, PT_FPR0*4 + 8, PT_FPR0*4+16, PT_FPR0*4+24, PT_FPR0*4+32, PT_FPR0*4+40, PT_FPR0*4+48, PT_FPR0*4+56, PT_FPR0*4+64, PT_FPR0*4+72, PT_FPR0*4+80, PT_FPR0*4+88, @@ -87,20 +85,36 @@ static int ppc_regmap[] = PT_FPR0*4+160, PT_FPR0*4+168, PT_FPR0*4+176, PT_FPR0*4+184, PT_FPR0*4+192, PT_FPR0*4+200, PT_FPR0*4+208, PT_FPR0*4+216, PT_FPR0*4+224, PT_FPR0*4+232, PT_FPR0*4+240, PT_FPR0*4+248, -#endif PT_NIP * 4, PT_MSR * 4, PT_CCR * 4, PT_LNK * 4, -#ifdef __SPE__ - PT_CTR * 4, PT_XER * 4, -1 -#else PT_CTR * 4, PT_XER * 4, PT_FPSCR * 4 -#endif + }; + +static int ppc_regmap_e500[] = + {PT_R0 * 4, PT_R1 * 4, PT_R2 * 4, PT_R3 * 4, + PT_R4 * 4, PT_R5 * 4, PT_R6 * 4, PT_R7 * 4, + PT_R8 * 4, PT_R9 * 4, PT_R10 * 4, PT_R11 * 4, + PT_R12 * 4, PT_R13 * 4, PT_R14 * 4, PT_R15 * 4, + PT_R16 * 4, PT_R17 * 4, PT_R18 * 4, PT_R19 * 4, + PT_R20 * 4, PT_R21 * 4, PT_R22 * 4, PT_R23 * 4, + PT_R24 * 4, PT_R25 * 4, PT_R26 * 4, PT_R27 * 4, + PT_R28 * 4, PT_R29 * 4, PT_R30 * 4, PT_R31 * 4, + -1, -1, -1, -1, + -1, -1, -1, -1, + -1, -1, -1, -1, + -1, -1, -1, -1, + -1, -1, -1, -1, + -1, -1, -1, -1, + -1, -1, -1, -1, + -1, -1, -1, -1, + PT_NIP * 4, PT_MSR * 4, PT_CCR * 4, PT_LNK * 4, + PT_CTR * 4, PT_XER * 4, -1 }; #endif static int ppc_cannot_store_register (int regno) { -#if !defined (__powerpc64__) && !defined (__SPE__) +#ifndef __powerpc64__ /* Some kernels do not allow us to store fpscr. */ if (regno == find_regno ("fpscr")) return 2; @@ -167,6 +181,42 @@ ppc_set_pc (CORE_ADDR pc) } } + +static int +ppc_get_hwcap (unsigned long *valp) +{ + int wordsize = register_size (0); + unsigned char *data = alloca (2 * wordsize); + int offset = 0; + + while ((*the_target->read_auxv) (offset, data, 2 * wordsize) == 2 * wordsize) + { + if (wordsize == 4) + { + unsigned int *data_p = (unsigned int *)data; + if (data_p[0] == AT_HWCAP) + { + *valp = data_p[1]; + return 1; + } + } + else + { + unsigned long *data_p = (unsigned long *)data; + if (data_p[0] == AT_HWCAP) + { + *valp = data_p[1]; + return 1; + } + } + + offset += 2 * wordsize; + } + + *valp = 0; + return 0; +} + static void ppc_arch_setup (void) { @@ -174,28 +224,37 @@ ppc_arch_setup (void) long msr; /* On a 64-bit host, assume 64-bit inferior process. */ -#ifdef __ALTIVEC__ - init_registers_powerpc_64 (); -#else init_registers_ppc64 (); -#endif /* Only if the high bit of the MSR is set, we actually have a 64-bit inferior. */ collect_register_by_name ("msr", &msr); if (msr < 0) - return; + { + ppc_get_hwcap (&ppc_hwcap); + if (ppc_hwcap & PPC_FEATURE_HAS_ALTIVEC) + init_registers_powerpc_64 (); + + return; + } #endif /* OK, we have a 32-bit inferior. */ -#ifdef __ALTIVEC__ - init_registers_powerpc_32 (); -#else -#ifdef __SPE__ - init_registers_powerpc_e500 (); -#else init_registers_ppc (); -#endif + + ppc_get_hwcap (&ppc_hwcap); + if (ppc_hwcap & PPC_FEATURE_HAS_ALTIVEC) + init_registers_powerpc_32 (); + + /* On 32-bit machines, check for SPE registers. + Set the low target's regmap field as appropriately. */ +#ifndef __powerpc64__ + the_low_target.regmap = ppc_regmap; + if (ppc_hwcap & PPC_FEATURE_HAS_SPE) + { + init_registers_powerpc_e500 (); + the_low_target.regmap = ppc_regmap_e500; + } #endif } @@ -232,8 +291,6 @@ static void ppc_fill_gregset (void *buf) ppc_collect_ptrace_register (i, (char *) buf + ppc_regmap[i]); } -#ifdef __ALTIVEC__ - #ifndef PTRACE_GETVRREGS #define PTRACE_GETVRREGS 18 #define PTRACE_SETVRREGS 19 @@ -247,6 +304,9 @@ ppc_fill_vrregset (void *buf) int i, base; char *regset = buf; + if (!(ppc_hwcap & PPC_FEATURE_HAS_ALTIVEC)) + return; + base = find_regno ("vr0"); for (i = 0; i < 32; i++) collect_register (base + i, ®set[i * 16]); @@ -261,6 +321,9 @@ ppc_store_vrregset (const void *buf) int i, base; const char *regset = buf; + if (!(ppc_hwcap & PPC_FEATURE_HAS_ALTIVEC)) + return; + base = find_regno ("vr0"); for (i = 0; i < 32; i++) supply_register (base + i, ®set[i * 16]); @@ -269,10 +332,6 @@ ppc_store_vrregset (const void *buf) supply_register_by_name ("vrsave", ®set[33 * 16]); } -#endif /* __ALTIVEC__ */ - -#ifdef __SPE__ - #ifndef PTRACE_GETEVRREGS #define PTRACE_GETEVRREGS 20 #define PTRACE_SETEVRREGS 21 @@ -291,6 +350,9 @@ ppc_fill_evrregset (void *buf) int i, ev0; struct gdb_evrregset_t *regset = buf; + if (!(ppc_hwcap & PPC_FEATURE_HAS_SPE)) + return; + ev0 = find_regno ("ev0h"); for (i = 0; i < 32; i++) collect_register (ev0 + i, ®set->evr[i]); @@ -305,6 +367,9 @@ ppc_store_evrregset (const void *buf) int i, ev0; const struct gdb_evrregset_t *regset = buf; + if (!(ppc_hwcap & PPC_FEATURE_HAS_SPE)) + return; + ev0 = find_regno ("ev0h"); for (i = 0; i < 32; i++) supply_register (ev0 + i, ®set->evr[i]); @@ -312,21 +377,16 @@ ppc_store_evrregset (const void *buf) supply_register_by_name ("acc", ®set->acc); supply_register_by_name ("spefscr", ®set->spefscr); } -#endif /* __SPE__ */ struct regset_info target_regsets[] = { /* List the extra register sets before GENERAL_REGS. That way we will fetch them every time, but still fall back to PTRACE_PEEKUSER for the general registers. Some kernels support these, but not the newer PPC_PTRACE_GETREGS. */ -#ifdef __ALTIVEC__ { PTRACE_GETVRREGS, PTRACE_SETVRREGS, SIZEOF_VRREGS, EXTENDED_REGS, ppc_fill_vrregset, ppc_store_vrregset }, -#endif -#ifdef __SPE__ { PTRACE_GETEVRREGS, PTRACE_SETEVRREGS, 32 * 4 + 8 + 4, EXTENDED_REGS, ppc_fill_evrregset, ppc_store_evrregset }, -#endif { 0, 0, 0, GENERAL_REGS, ppc_fill_gregset, NULL }, { 0, 0, -1, -1, NULL, NULL } }; -- Dr. Ulrich Weigand GNU Toolchain for Linux on System z and Cell BE Ulrich.Weigand@de.ibm.com