This is the mail archive of the
gdb-patches@sourceware.org
mailing list for the GDB project.
PATCH: Add common files for x86 XSAVE extended state
- From: "H.J. Lu" <hongjiu dot lu at intel dot com>
- To: GDB <gdb-patches at sourceware dot org>
- Date: Tue, 2 Mar 2010 07:28:26 -0800
- Subject: PATCH: Add common files for x86 XSAVE extended state
- Reply-to: "H.J. Lu" <hjl dot tools at gmail dot com>
Hi,
This patch adds common files for x86 XSAVE extended state. They
are used by native x86 gdb and gdbserver to discover x86 XSAVE
extended state support. You can see IA32/Intel64 SDM at
http://developer.intel.com/products/processor/manuals/index.htm
for details. OK to install?
Thanks.
H.J.
---
2010-03-02 H.J. Lu <hongjiu.lu@intel.com>
* common/i386-cpuid.h: New.
* common/i386-xstate.c: Likewise.
* common/i386-xstate.h: Likewise.
diff --git a/gdb/common/i386-cpuid.h b/gdb/common/i386-cpuid.h
new file mode 100644
index 0000000..3228414
--- /dev/null
+++ b/gdb/common/i386-cpuid.h
@@ -0,0 +1,181 @@
+/*
+ * Copyright (C) 2007, 2008, 2009 Free Software Foundation, Inc.
+ *
+ * This file 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 3, or (at your option) any
+ * later version.
+ *
+ * This file 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.
+ *
+ * Under Section 7 of GPL version 3, you are granted additional
+ * permissions described in the GCC Runtime Library Exception, version
+ * 3.1, as published by the Free Software Foundation.
+ *
+ * You should have received a copy of the GNU General Public License and
+ * a copy of the GCC Runtime Library Exception along with this program;
+ * see the files COPYING3 and COPYING.RUNTIME respectively. If not, see
+ * <http://www.gnu.org/licenses/>.
+ */
+
+/* %ecx */
+#define bit_SSE3 (1 << 0)
+#define bit_PCLMUL (1 << 1)
+#define bit_SSSE3 (1 << 9)
+#define bit_FMA (1 << 12)
+#define bit_CMPXCHG16B (1 << 13)
+#define bit_SSE4_1 (1 << 19)
+#define bit_SSE4_2 (1 << 20)
+#define bit_MOVBE (1 << 22)
+#define bit_POPCNT (1 << 23)
+#define bit_AES (1 << 25)
+#define bit_XSAVE (1 << 26)
+#define bit_OSXSAVE (1 << 27)
+#define bit_AVX (1 << 28)
+
+/* %edx */
+#define bit_CMPXCHG8B (1 << 8)
+#define bit_CMOV (1 << 15)
+#define bit_MMX (1 << 23)
+#define bit_FXSAVE (1 << 24)
+#define bit_SSE (1 << 25)
+#define bit_SSE2 (1 << 26)
+
+/* Extended Features */
+/* %ecx */
+#define bit_LAHF_LM (1 << 0)
+#define bit_ABM (1 << 5)
+#define bit_SSE4a (1 << 6)
+#define bit_XOP (1 << 11)
+#define bit_LWP (1 << 15)
+#define bit_FMA4 (1 << 16)
+
+/* %edx */
+#define bit_LM (1 << 29)
+#define bit_3DNOWP (1 << 30)
+#define bit_3DNOW (1 << 31)
+
+
+#if defined(__i386__) && defined(__PIC__)
+/* %ebx may be the PIC register. */
+#if __GNUC__ >= 3
+#define __cpuid(level, a, b, c, d) \
+ __asm__ ("xchg{l}\t{%%}ebx, %1\n\t" \
+ "cpuid\n\t" \
+ "xchg{l}\t{%%}ebx, %1\n\t" \
+ : "=a" (a), "=r" (b), "=c" (c), "=d" (d) \
+ : "0" (level))
+
+#define __cpuid_count(level, count, a, b, c, d) \
+ __asm__ ("xchg{l}\t{%%}ebx, %1\n\t" \
+ "cpuid\n\t" \
+ "xchg{l}\t{%%}ebx, %1\n\t" \
+ : "=a" (a), "=r" (b), "=c" (c), "=d" (d) \
+ : "0" (level), "2" (count))
+#else
+/* Host GCCs older than 3.0 weren't supporting Intel asm syntax
+ nor alternatives in i386 code. */
+#define __cpuid(level, a, b, c, d) \
+ __asm__ ("xchgl\t%%ebx, %1\n\t" \
+ "cpuid\n\t" \
+ "xchgl\t%%ebx, %1\n\t" \
+ : "=a" (a), "=r" (b), "=c" (c), "=d" (d) \
+ : "0" (level))
+
+#define __cpuid_count(level, count, a, b, c, d) \
+ __asm__ ("xchgl\t%%ebx, %1\n\t" \
+ "cpuid\n\t" \
+ "xchgl\t%%ebx, %1\n\t" \
+ : "=a" (a), "=r" (b), "=c" (c), "=d" (d) \
+ : "0" (level), "2" (count))
+#endif
+#else
+#define __cpuid(level, a, b, c, d) \
+ __asm__ ("cpuid\n\t" \
+ : "=a" (a), "=b" (b), "=c" (c), "=d" (d) \
+ : "0" (level))
+
+#define __cpuid_count(level, count, a, b, c, d) \
+ __asm__ ("cpuid\n\t" \
+ : "=a" (a), "=b" (b), "=c" (c), "=d" (d) \
+ : "0" (level), "2" (count))
+#endif
+
+/* Return highest supported input value for cpuid instruction. ext can
+ be either 0x0 or 0x8000000 to return highest supported value for
+ basic or extended cpuid information. Function returns 0 if cpuid
+ is not supported or whatever cpuid returns in eax register. If sig
+ pointer is non-null, then first four bytes of the signature
+ (as found in ebx register) are returned in location pointed by sig. */
+
+static __inline unsigned int
+__get_cpuid_max (unsigned int __ext, unsigned int *__sig)
+{
+ unsigned int __eax, __ebx, __ecx, __edx;
+
+#ifndef __x86_64__
+#if __GNUC__ >= 3
+ /* See if we can use cpuid. On AMD64 we always can. */
+ __asm__ ("pushf{l|d}\n\t"
+ "pushf{l|d}\n\t"
+ "pop{l}\t%0\n\t"
+ "mov{l}\t{%0, %1|%1, %0}\n\t"
+ "xor{l}\t{%2, %0|%0, %2}\n\t"
+ "push{l}\t%0\n\t"
+ "popf{l|d}\n\t"
+ "pushf{l|d}\n\t"
+ "pop{l}\t%0\n\t"
+ "popf{l|d}\n\t"
+ : "=&r" (__eax), "=&r" (__ebx)
+ : "i" (0x00200000));
+#else
+/* Host GCCs older than 3.0 weren't supporting Intel asm syntax
+ nor alternatives in i386 code. */
+ __asm__ ("pushfl\n\t"
+ "pushfl\n\t"
+ "popl\t%0\n\t"
+ "movl\t%0, %1\n\t"
+ "xorl\t%2, %0\n\t"
+ "pushl\t%0\n\t"
+ "popfl\n\t"
+ "pushfl\n\t"
+ "popl\t%0\n\t"
+ "popfl\n\t"
+ : "=&r" (__eax), "=&r" (__ebx)
+ : "i" (0x00200000));
+#endif
+
+ if (!((__eax ^ __ebx) & 0x00200000))
+ return 0;
+#endif
+
+ /* Host supports cpuid. Return highest supported cpuid input value. */
+ __cpuid (__ext, __eax, __ebx, __ecx, __edx);
+
+ if (__sig)
+ *__sig = __ebx;
+
+ return __eax;
+}
+
+/* Return cpuid data for requested cpuid level, as found in returned
+ eax, ebx, ecx and edx registers. The function checks if cpuid is
+ supported and returns 1 for valid cpuid information or 0 for
+ unsupported cpuid level. All pointers are required to be non-null. */
+
+static __inline int
+__get_cpuid (unsigned int __level,
+ unsigned int *__eax, unsigned int *__ebx,
+ unsigned int *__ecx, unsigned int *__edx)
+{
+ unsigned int __ext = __level & 0x80000000;
+
+ if (__get_cpuid_max (__ext, 0) < __level)
+ return 0;
+
+ __cpuid (__level, *__eax, *__ebx, *__ecx, *__edx);
+ return 1;
+}
diff --git a/gdb/common/i386-xstate.c b/gdb/common/i386-xstate.c
new file mode 100644
index 0000000..a4d17e7
--- /dev/null
+++ b/gdb/common/i386-xstate.c
@@ -0,0 +1,92 @@
+/* Common code for i386 XSAVE extended state.
+
+ Copyright (C) 2010 Free Software Foundation, Inc.
+
+ This file is part of GDB.
+
+ 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 3 of the License, 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.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>. */
+
+#ifdef XSTATE_MAIN
+#include <stdio.h>
+#else
+#include "config.h"
+#endif
+
+#ifdef HAVE_CPUID_H
+#include <cpuid.h>
+#else
+#include "i386-cpuid.h"
+#endif
+
+#include "i386-xstate.h"
+
+struct i386_xstate_type i386_xstate;
+
+void
+i386_xstate_init (void)
+{
+ unsigned int eax, ebx, ecx, edx, eax_mask, edx_mask, size;
+
+ if (i386_xstate.status != XSTATE_UNKNOWN)
+ return;
+
+ i386_xstate.status = XSTATE_UNSUPPORTED;
+
+ if (!__get_cpuid (1, &eax, &ebx, &ecx, &edx))
+ return;
+
+ if (!(ecx & bit_OSXSAVE))
+ return;
+
+ i386_xstate.status = XSTATE_INITIALIZED;
+
+ /* Get enabled extended state save area size. */
+ __cpuid_count (0xd, 0, eax_mask, size, ecx, edx_mask);
+ i386_xstate.size = size;
+ i386_xstate.n_of_int64
+ = (size + sizeof (long long) - 1) / sizeof (long long);
+
+ /* Get XCR0, the XFEATURE_ENABLED_MASK register. */
+ __asm__ ("xgetbv\n\t" : "=a" (eax), "=d" (edx) : "c" (0));
+ i386_xstate.xcr0 = (((unsigned long long) (edx & edx_mask) << 32)
+ | (eax & eax_mask));
+}
+
+#ifdef XSTATE_MAIN
+
+int
+main ()
+{
+ i386_xstate_init ();
+
+ if (i386_xstate.status == XSTATE_UNSUPPORTED)
+ {
+ printf ("XSAVE extended state is unsupported\n");
+ return 0;
+ }
+
+ printf ("XSAVE extended state size: %d bytes\n", i386_xstate.size);
+ printf ("XSAVE extended state enabled:");
+ if ((i386_xstate.xcr0 & bit_XSTATE_X87))
+ fputs (" X87", stdout);
+ if ((i386_xstate.xcr0 & bit_XSTATE_SSE))
+ fputs (" SSE", stdout);
+ if ((i386_xstate.xcr0 & bit_XSTATE_AVX))
+ fputs (" AVX", stdout);
+ fputs ("\n", stdout);
+
+ return 0;
+}
+
+#endif /* XSTATE_MAIN */
diff --git a/gdb/common/i386-xstate.h b/gdb/common/i386-xstate.h
new file mode 100644
index 0000000..75cdc1e
--- /dev/null
+++ b/gdb/common/i386-xstate.h
@@ -0,0 +1,73 @@
+/* Common code for i386 XSAVE extended state.
+
+ Copyright (C) 2010 Free Software Foundation, Inc.
+
+ This file is part of GDB.
+
+ 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 3 of the License, 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.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>. */
+
+#ifndef I386_XSTATE_H
+#define I386_XSTATE_H 1
+
+/* XSAVE extended state information. */
+
+/* The extended state status. */
+enum xstate_status
+{
+ XSTATE_UNKNOWN = 0,
+ XSTATE_UNSUPPORTED,
+ XSTATE_INITIALIZED
+};
+
+/* The extended state feature bits. */
+#define bit_XSTATE_X87 (1ULL << 0)
+#define bit_XSTATE_SSE (1ULL << 1)
+#define bit_XSTATE_AVX (1ULL << 2)
+
+/* Supported mask and size of the extended state. */
+#define XSTATE_SSE_MASK (bit_XSTATE_X87 | bit_XSTATE_SSE)
+#define XSTATE_AVX_MASK (XSTATE_SSE_MASK | bit_XSTATE_AVX)
+#define XSTATE_MAX_MASK XSTATE_AVX_MASK
+
+#define XSTATE_SSE_MASK_STRING "0x3"
+#define XSTATE_AVX_MASK_STRING "0x7"
+#define XSTATE_MAX_MASK_STRING "0x7"
+
+#define XSTATE_SSE_SIZE 576
+#define XSTATE_AVX_SIZE 832
+#define XSTATE_MAX_SIZE 832
+
+#define XSTATE_SSE_SIZE_STRING "576"
+#define XSTATE_AVX_SIZE_STRING "832"
+#define XSTATE_MAX_SIZE_STRING "832"
+
+struct i386_xstate_type
+ {
+ /* The extended state status. */
+ enum xstate_status status;
+ /* The extended control register 0 (the XFEATURE_ENABLED_MASK
+ register). */
+ unsigned long long xcr0;
+ /* The extended state size in bytes. */
+ unsigned int size;
+ /* The extended state size in unit of int64. We use array of
+ int64 for better alignment. */
+ unsigned int n_of_int64;
+ };
+
+extern struct i386_xstate_type i386_xstate;
+
+extern void i386_xstate_init (void);
+
+#endif /* I386_XSTATE_H */