Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 7e00df58 authored by H. Peter Anvin's avatar H. Peter Anvin
Browse files

x86: add NOPL as a synthetic CPU feature bit



The long noops ("NOPL") are supposed to be detected by family >= 6.
Unfortunately, several non-Intel x86 implementations, both hardware
and software, don't obey this dictum.  Instead, probe for NOPL
directly by executing a NOPL instruction and see if we get #UD.

Signed-off-by: default avatarH. Peter Anvin <hpa@zytor.com>
parent e2fe16d9
Loading
Loading
Loading
Loading
+31 −1
Original line number Original line Diff line number Diff line
@@ -13,6 +13,7 @@
#include <asm/mtrr.h>
#include <asm/mtrr.h>
#include <asm/mce.h>
#include <asm/mce.h>
#include <asm/pat.h>
#include <asm/pat.h>
#include <asm/asm.h>
#ifdef CONFIG_X86_LOCAL_APIC
#ifdef CONFIG_X86_LOCAL_APIC
#include <asm/mpspec.h>
#include <asm/mpspec.h>
#include <asm/apic.h>
#include <asm/apic.h>
@@ -341,6 +342,35 @@ static void __init early_cpu_detect(void)
	early_get_cap(c);
	early_get_cap(c);
}
}


/*
 * The NOPL instruction is supposed to exist on all CPUs with
 * family >= 6, unfortunately, that's not true in practice because
 * of early VIA chips and (more importantly) broken virtualizers that
 * are not easy to detect.  Hence, probe for it based on first
 * principles.
 */
static void __cpuinit detect_nopl(struct cpuinfo_x86 *c)
{
	const u32 nopl_signature = 0x888c53b1; /* Random number */
	u32 has_nopl = nopl_signature;

	clear_cpu_cap(c, X86_FEATURE_NOPL);
	if (c->x86 >= 6) {
		asm volatile("\n"
			     "1:      .byte 0x0f,0x1f,0xc0\n" /* nopl %eax */
			     "2:\n"
			     "        .section .fixup,\"ax\"\n"
			     "3:      xor %0,%0\n"
			     "        jmp 2b\n"
			     "        .previous\n"
			     _ASM_EXTABLE(1b,3b)
			     : "+a" (has_nopl));

		if (has_nopl == nopl_signature)
			set_cpu_cap(c, X86_FEATURE_NOPL);
	}
}

static void __cpuinit generic_identify(struct cpuinfo_x86 *c)
static void __cpuinit generic_identify(struct cpuinfo_x86 *c)
{
{
	u32 tfms, xlvl;
	u32 tfms, xlvl;
@@ -395,8 +425,8 @@ static void __cpuinit generic_identify(struct cpuinfo_x86 *c)
		}
		}


		init_scattered_cpuid_features(c);
		init_scattered_cpuid_features(c);
		detect_nopl(c);
	}
	}

}
}


static void __cpuinit squash_the_stupid_serial_number(struct cpuinfo_x86 *c)
static void __cpuinit squash_the_stupid_serial_number(struct cpuinfo_x86 *c)
+36 −0
Original line number Original line Diff line number Diff line
@@ -18,6 +18,7 @@
#include <asm/mtrr.h>
#include <asm/mtrr.h>
#include <asm/mce.h>
#include <asm/mce.h>
#include <asm/pat.h>
#include <asm/pat.h>
#include <asm/asm.h>
#include <asm/numa.h>
#include <asm/numa.h>
#ifdef CONFIG_X86_LOCAL_APIC
#ifdef CONFIG_X86_LOCAL_APIC
#include <asm/mpspec.h>
#include <asm/mpspec.h>
@@ -215,6 +216,39 @@ static void __init early_cpu_support_print(void)
	}
	}
}
}


/*
 * The NOPL instruction is supposed to exist on all CPUs with
 * family >= 6, unfortunately, that's not true in practice because
 * of early VIA chips and (more importantly) broken virtualizers that
 * are not easy to detect.  Hence, probe for it based on first
 * principles.
 *
 * Note: no 64-bit chip is known to lack these, but put the code here
 * for consistency with 32 bits, and to make it utterly trivial to
 * diagnose the problem should it ever surface.
 */
static void __cpuinit detect_nopl(struct cpuinfo_x86 *c)
{
	const u32 nopl_signature = 0x888c53b1; /* Random number */
	u32 has_nopl = nopl_signature;

	clear_cpu_cap(c, X86_FEATURE_NOPL);
	if (c->x86 >= 6) {
		asm volatile("\n"
			     "1:      .byte 0x0f,0x1f,0xc0\n" /* nopl %eax */
			     "2:\n"
			     "        .section .fixup,\"ax\"\n"
			     "3:      xor %0,%0\n"
			     "        jmp 2b\n"
			     "        .previous\n"
			     _ASM_EXTABLE(1b,3b)
			     : "+a" (has_nopl));

		if (has_nopl == nopl_signature)
			set_cpu_cap(c, X86_FEATURE_NOPL);
	}
}

static void __cpuinit early_identify_cpu(struct cpuinfo_x86 *c);
static void __cpuinit early_identify_cpu(struct cpuinfo_x86 *c);


void __init early_cpu_init(void)
void __init early_cpu_init(void)
@@ -313,6 +347,8 @@ static void __cpuinit early_identify_cpu(struct cpuinfo_x86 *c)
		c->x86_phys_bits = eax & 0xff;
		c->x86_phys_bits = eax & 0xff;
	}
	}


	detect_nopl(c);

	if (c->x86_vendor != X86_VENDOR_UNKNOWN &&
	if (c->x86_vendor != X86_VENDOR_UNKNOWN &&
	    cpu_devs[c->x86_vendor]->c_early_init)
	    cpu_devs[c->x86_vendor]->c_early_init)
		cpu_devs[c->x86_vendor]->c_early_init(c);
		cpu_devs[c->x86_vendor]->c_early_init(c);
+2 −1
Original line number Original line Diff line number Diff line
@@ -39,7 +39,8 @@ const char * const x86_cap_flags[NCAPINTS*32] = {
	NULL, NULL, NULL, NULL,
	NULL, NULL, NULL, NULL,
	"constant_tsc", "up", NULL, "arch_perfmon",
	"constant_tsc", "up", NULL, "arch_perfmon",
	"pebs", "bts", NULL, NULL,
	"pebs", "bts", NULL, NULL,
	"rep_good", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
	"rep_good", NULL, NULL, NULL,
	"nopl", NULL, NULL, NULL,
	NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
	NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,


	/* Intel-defined (#2) */
	/* Intel-defined (#2) */
+6 −5
Original line number Original line Diff line number Diff line
@@ -80,6 +80,7 @@
#define X86_FEATURE_MFENCE_RDTSC (3*32+17) /* Mfence synchronizes RDTSC */
#define X86_FEATURE_MFENCE_RDTSC (3*32+17) /* Mfence synchronizes RDTSC */
#define X86_FEATURE_LFENCE_RDTSC (3*32+18) /* Lfence synchronizes RDTSC */
#define X86_FEATURE_LFENCE_RDTSC (3*32+18) /* Lfence synchronizes RDTSC */
#define X86_FEATURE_11AP	(3*32+19) /* Bad local APIC aka 11AP */
#define X86_FEATURE_11AP	(3*32+19) /* Bad local APIC aka 11AP */
#define X86_FEATURE_NOPL	(3*32+20) /* The NOPL (0F 1F) instructions */


/* Intel-defined CPU features, CPUID level 0x00000001 (ecx), word 4 */
/* Intel-defined CPU features, CPUID level 0x00000001 (ecx), word 4 */
#define X86_FEATURE_XMM3	(4*32+ 0) /* Streaming SIMD Extensions-3 */
#define X86_FEATURE_XMM3	(4*32+ 0) /* Streaming SIMD Extensions-3 */
+7 −1
Original line number Original line Diff line number Diff line
@@ -41,6 +41,12 @@
# define NEED_3DNOW	0
# define NEED_3DNOW	0
#endif
#endif


#if defined(CONFIG_X86_P6_NOP) || defined(CONFIG_X86_64)
# define NEED_NOPL	(1<<(X86_FEATURE_NOPL & 31))
#else
# define NEED_NOPL	0
#endif

#ifdef CONFIG_X86_64
#ifdef CONFIG_X86_64
#define NEED_PSE	0
#define NEED_PSE	0
#define NEED_MSR	(1<<(X86_FEATURE_MSR & 31))
#define NEED_MSR	(1<<(X86_FEATURE_MSR & 31))
@@ -67,7 +73,7 @@
#define REQUIRED_MASK1	(NEED_LM|NEED_3DNOW)
#define REQUIRED_MASK1	(NEED_LM|NEED_3DNOW)


#define REQUIRED_MASK2	0
#define REQUIRED_MASK2	0
#define REQUIRED_MASK3	0
#define REQUIRED_MASK3	(NEED_NOPL)
#define REQUIRED_MASK4	0
#define REQUIRED_MASK4	0
#define REQUIRED_MASK5	0
#define REQUIRED_MASK5	0
#define REQUIRED_MASK6	0
#define REQUIRED_MASK6	0