linux-kernel.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
* [PATCH] x86/perf : Add check for CPUID instruction before using
@ 2018-02-02 14:30 Matthew Whitehead
  2018-02-02 14:37 ` Borislav Petkov
  2018-02-02 14:54 ` Arnaldo Carvalho de Melo
  0 siblings, 2 replies; 4+ messages in thread
From: Matthew Whitehead @ 2018-02-02 14:30 UTC (permalink / raw)
  To: peterz, mingo, acme, linux-kernel; +Cc: Matthew Whitehead

We still officially support the ancient i486 cpu. First generation
versions of this processor do not have the CPUID instruction, though
later versions do. Therefore you must check that the cpu supports
it before using it. At present it fails with an "Illegal Instruction"
signal on the early processors.

This code was based on similar code in the gcc package.

Signed-off-by: Matthew Whitehead <tedheadster@gmail.com>
---
 tools/perf/arch/x86/util/header.c | 51 +++++++++++++++++++++++++++++++++++++++
 tools/perf/util/header.h          |  2 ++
 2 files changed, 53 insertions(+)

diff --git a/tools/perf/arch/x86/util/header.c b/tools/perf/arch/x86/util/header.c
index fb0d71afee8b..d4d12894c64d 100644
--- a/tools/perf/arch/x86/util/header.c
+++ b/tools/perf/arch/x86/util/header.c
@@ -7,6 +7,54 @@
 
 #include "../../util/header.h"
 
+/* This code based on gcc cpuid.h __get_cpuid_max() */
+unsigned int have_cpuid(void)
+{
+	unsigned int __eax, __ebx;
+
+#ifndef __x86_64__
+/* See if we can use cpuid.  On AMD64 we always can.  */
+#if __GNUC__ >= 3
+	__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;
+	else
+		return 1;
+#endif
+
+/* All x86_64 support cpuid */
+	return 1;
+}
+
 static inline void
 cpuid(unsigned int op, unsigned int *a, unsigned int *b, unsigned int *c,
       unsigned int *d)
@@ -28,6 +76,9 @@ __get_cpuid(char *buffer, size_t sz, const char *fmt)
 	int nb;
 	char vendor[16];
 
+	if (!have_cpuid())
+		return -1;
+
 	cpuid(0, &lvl, &b, &c, &d);
 	strncpy(&vendor[0], (char *)(&b), 4);
 	strncpy(&vendor[4], (char *)(&d), 4);
diff --git a/tools/perf/util/header.h b/tools/perf/util/header.h
index f28aaaa3a440..ce31fca36077 100644
--- a/tools/perf/util/header.h
+++ b/tools/perf/util/header.h
@@ -171,6 +171,8 @@ int write_padded(struct feat_fd *fd, const void *bf,
 /*
  * arch specific callback
  */
+unsigned int have_cpuid(void);
+
 int get_cpuid(char *buffer, size_t sz);
 
 char *get_cpuid_str(struct perf_pmu *pmu __maybe_unused);
-- 
2.13.6

^ permalink raw reply related	[flat|nested] 4+ messages in thread

* Re: [PATCH] x86/perf : Add check for CPUID instruction before using
  2018-02-02 14:30 [PATCH] x86/perf : Add check for CPUID instruction before using Matthew Whitehead
@ 2018-02-02 14:37 ` Borislav Petkov
  2018-02-02 14:55   ` Arnaldo Carvalho de Melo
  2018-02-02 14:54 ` Arnaldo Carvalho de Melo
  1 sibling, 1 reply; 4+ messages in thread
From: Borislav Petkov @ 2018-02-02 14:37 UTC (permalink / raw)
  To: Matthew Whitehead; +Cc: peterz, mingo, acme, linux-kernel

On Fri, Feb 02, 2018 at 09:30:51AM -0500, Matthew Whitehead wrote:
> We still officially support the ancient i486 cpu. First generation
> versions of this processor do not have the CPUID instruction, though
> later versions do. Therefore you must check that the cpu supports
> it before using it. At present it fails with an "Illegal Instruction"
> signal on the early processors.
> 
> This code was based on similar code in the gcc package.
> 
> Signed-off-by: Matthew Whitehead <tedheadster@gmail.com>
> ---
>  tools/perf/arch/x86/util/header.c | 51 +++++++++++++++++++++++++++++++++++++++
>  tools/perf/util/header.h          |  2 ++
>  2 files changed, 53 insertions(+)
> 
> diff --git a/tools/perf/arch/x86/util/header.c b/tools/perf/arch/x86/util/header.c
> index fb0d71afee8b..d4d12894c64d 100644
> --- a/tools/perf/arch/x86/util/header.c
> +++ b/tools/perf/arch/x86/util/header.c
> @@ -7,6 +7,54 @@
>  
>  #include "../../util/header.h"
>  
> +/* This code based on gcc cpuid.h __get_cpuid_max() */
> +unsigned int have_cpuid(void)

You could've copied have_cpuid_p() from arch/x86/kernel/cpu/common.c

> +{
> +	unsigned int __eax, __ebx;
> +
> +#ifndef __x86_64__
> +/* See if we can use cpuid.  On AMD64 we always can.  */
> +#if __GNUC__ >= 3
> +	__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.

We don't support gcc < 3

#if GCC_VERSION < 30200
# error Sorry, your compiler is too old - please upgrade it.
#endif

There's even talk currently to raise the minimum version to 4.9 or so.

-- 
Regards/Gruss,
    Boris.

Good mailing practices for 400: avoid top-posting and trim the reply.

^ permalink raw reply	[flat|nested] 4+ messages in thread

* Re: [PATCH] x86/perf : Add check for CPUID instruction before using
  2018-02-02 14:30 [PATCH] x86/perf : Add check for CPUID instruction before using Matthew Whitehead
  2018-02-02 14:37 ` Borislav Petkov
@ 2018-02-02 14:54 ` Arnaldo Carvalho de Melo
  1 sibling, 0 replies; 4+ messages in thread
From: Arnaldo Carvalho de Melo @ 2018-02-02 14:54 UTC (permalink / raw)
  To: Matthew Whitehead; +Cc: peterz, mingo, linux-kernel

Em Fri, Feb 02, 2018 at 09:30:51AM -0500, Matthew Whitehead escreveu:
> We still officially support the ancient i486 cpu. First generation
> versions of this processor do not have the CPUID instruction, though
> later versions do. Therefore you must check that the cpu supports
> it before using it. At present it fails with an "Illegal Instruction"
> signal on the early processors.
> 
> This code was based on similar code in the gcc package.

Can you provide an URL for the code used as a reference, please?

- Arnaldo
 
> Signed-off-by: Matthew Whitehead <tedheadster@gmail.com>
> ---
>  tools/perf/arch/x86/util/header.c | 51 +++++++++++++++++++++++++++++++++++++++
>  tools/perf/util/header.h          |  2 ++
>  2 files changed, 53 insertions(+)
> 
> diff --git a/tools/perf/arch/x86/util/header.c b/tools/perf/arch/x86/util/header.c
> index fb0d71afee8b..d4d12894c64d 100644
> --- a/tools/perf/arch/x86/util/header.c
> +++ b/tools/perf/arch/x86/util/header.c
> @@ -7,6 +7,54 @@
>  
>  #include "../../util/header.h"
>  
> +/* This code based on gcc cpuid.h __get_cpuid_max() */
> +unsigned int have_cpuid(void)
> +{
> +	unsigned int __eax, __ebx;
> +
> +#ifndef __x86_64__
> +/* See if we can use cpuid.  On AMD64 we always can.  */
> +#if __GNUC__ >= 3
> +	__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;
> +	else
> +		return 1;
> +#endif
> +
> +/* All x86_64 support cpuid */
> +	return 1;
> +}
> +
>  static inline void
>  cpuid(unsigned int op, unsigned int *a, unsigned int *b, unsigned int *c,
>        unsigned int *d)
> @@ -28,6 +76,9 @@ __get_cpuid(char *buffer, size_t sz, const char *fmt)
>  	int nb;
>  	char vendor[16];
>  
> +	if (!have_cpuid())
> +		return -1;
> +
>  	cpuid(0, &lvl, &b, &c, &d);
>  	strncpy(&vendor[0], (char *)(&b), 4);
>  	strncpy(&vendor[4], (char *)(&d), 4);
> diff --git a/tools/perf/util/header.h b/tools/perf/util/header.h
> index f28aaaa3a440..ce31fca36077 100644
> --- a/tools/perf/util/header.h
> +++ b/tools/perf/util/header.h
> @@ -171,6 +171,8 @@ int write_padded(struct feat_fd *fd, const void *bf,
>  /*
>   * arch specific callback
>   */
> +unsigned int have_cpuid(void);
> +
>  int get_cpuid(char *buffer, size_t sz);
>  
>  char *get_cpuid_str(struct perf_pmu *pmu __maybe_unused);
> -- 
> 2.13.6

^ permalink raw reply	[flat|nested] 4+ messages in thread

* Re: [PATCH] x86/perf : Add check for CPUID instruction before using
  2018-02-02 14:37 ` Borislav Petkov
@ 2018-02-02 14:55   ` Arnaldo Carvalho de Melo
  0 siblings, 0 replies; 4+ messages in thread
From: Arnaldo Carvalho de Melo @ 2018-02-02 14:55 UTC (permalink / raw)
  To: Borislav Petkov; +Cc: Matthew Whitehead, peterz, mingo, linux-kernel

Em Fri, Feb 02, 2018 at 03:37:31PM +0100, Borislav Petkov escreveu:
> On Fri, Feb 02, 2018 at 09:30:51AM -0500, Matthew Whitehead wrote:
> > We still officially support the ancient i486 cpu. First generation
> > versions of this processor do not have the CPUID instruction, though
> > later versions do. Therefore you must check that the cpu supports
> > it before using it. At present it fails with an "Illegal Instruction"
> > signal on the early processors.
> > 
> > This code was based on similar code in the gcc package.
> > 
> > Signed-off-by: Matthew Whitehead <tedheadster@gmail.com>
> > ---
> >  tools/perf/arch/x86/util/header.c | 51 +++++++++++++++++++++++++++++++++++++++
> >  tools/perf/util/header.h          |  2 ++
> >  2 files changed, 53 insertions(+)
> > 
> > diff --git a/tools/perf/arch/x86/util/header.c b/tools/perf/arch/x86/util/header.c
> > index fb0d71afee8b..d4d12894c64d 100644
> > --- a/tools/perf/arch/x86/util/header.c
> > +++ b/tools/perf/arch/x86/util/header.c
> > @@ -7,6 +7,54 @@
> >  
> >  #include "../../util/header.h"
> >  
> > +/* This code based on gcc cpuid.h __get_cpuid_max() */
> > +unsigned int have_cpuid(void)
> 
> You could've copied have_cpuid_p() from arch/x86/kernel/cpu/common.c
> 
> > +{
> > +	unsigned int __eax, __ebx;
> > +
> > +#ifndef __x86_64__
> > +/* See if we can use cpuid.  On AMD64 we always can.  */
> > +#if __GNUC__ >= 3
> > +	__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.
> 
> We don't support gcc < 3
> 
> #if GCC_VERSION < 30200
> # error Sorry, your compiler is too old - please upgrade it.
> #endif
> 
> There's even talk currently to raise the minimum version to 4.9 or so.

But this is for the kernel build process, right? If we don't have a
strict reason to forbid archeology... 8-)

- Arnaldo

^ permalink raw reply	[flat|nested] 4+ messages in thread

end of thread, other threads:[~2018-02-02 14:56 UTC | newest]

Thread overview: 4+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2018-02-02 14:30 [PATCH] x86/perf : Add check for CPUID instruction before using Matthew Whitehead
2018-02-02 14:37 ` Borislav Petkov
2018-02-02 14:55   ` Arnaldo Carvalho de Melo
2018-02-02 14:54 ` Arnaldo Carvalho de Melo

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).