From f536a213497b948ab2cc1bb58fb02a14296a2025 Mon Sep 17 00:00:00 2001 From: Andi Kleen Date: Sat, 22 Feb 2003 18:50:20 -0800 Subject: [PATCH] [PATCH] Fix x86-64 loose ends - Make MTRR driver compatible with 2.4/x86-64 again. This fixes an endless loop in the XFree86 4.3pre server. - Fix the boot code that rejected earlier: rewrote early CPU detection and SSE is forced now - Always force inlining in vsyscalls --- arch/x86_64/boot/compressed/misc.c | 124 ++++++++++++----------------- arch/x86_64/kernel/vsyscall.c | 9 ++- include/asm-x86_64/mtrr.h | 6 +- 3 files changed, 59 insertions(+), 80 deletions(-) diff --git a/arch/x86_64/boot/compressed/misc.c b/arch/x86_64/boot/compressed/misc.c index 3b56460d43d22..780b43933eb6f 100644 --- a/arch/x86_64/boot/compressed/misc.c +++ b/arch/x86_64/boot/compressed/misc.c @@ -329,84 +329,46 @@ void close_output_buffer_if_we_run_high(struct moveparams *mv) void check_cpu(void) { - int res = 0; - int tmp, flags; - - asm volatile( " \n\ - movl $3,%%edx # at least 386 \n\ - pushfl # push EFLAGS \n\ - popl %%eax # get EFLAGS \n\ - movl %%eax,%%ecx # save original EFLAGS \n\ - xorl $0x40000,%%eax # flip AC bit in EFLAGS \n\ - pushl %%eax # copy to EFLAGS \n\ - popfl # set EFLAGS \n\ - pushfl # get new EFLAGS \n\ - popl %%eax # put it in eax \n\ - xorl %%ecx,%%eax # change in flags \n\ - andl $0x40000,%%eax # check if AC bit changed \n\ - je 1f \n\ -\n\ - movl $4,%%edx # at least 486 \n\ - movl %%ecx,%%eax \n\ - xorl $0x200000,%%eax # check ID flag \n\ - pushl %%eax \n\ - popfl # if we are on a straight 486DX, SX, or \n\ - pushfl # 487SX we can't change it \n\ - popl %%eax \n\ - xorl %%ecx,%%eax \n\ - pushl %%ecx # restore original EFLAGS \n\ - popfl \n\ - andl $0x200000,%%eax \n\ - je 1f \n\ -\n\ - /* get vendor info */ \n\ -# xorl %%eax,%%eax # call CPUID with 0 -> return vendor ID \n\ -# cpuid \n\ -# movl $5, %%edx \n\ -# cmpl $0x41757468,%%ebx # check thats amd \n\ -# jne 1f \n\ -\n\ - mov $0x80000000,%%eax # Is extended cpuid supported?\n\ - cpuid\n\ - test $0x80000000,%%eax\n\ - movl $5, %%edx \n\ - jz 1f\n\ -\n\ - movl $0x80000001,%%eax \n\ - cpuid \n\ - andl $0x20000000,%%edx \n\ - movl $6, %%edx \n\ - jz 1f \n\ -\n\ - movl $7, %%edx \n\ -1:" : "=d" (res) : : "eax", "ebx", "ecx" ); - - switch (res) { - case 3: puts( "386" ); - break; - case 4: puts( "486" ); - break; - case 5: puts( "no extended cpuid" ); - break; - case 6: puts( "non-64bit 586+" ); - break; - case 7: puts( "64bit" ); - break; - default:puts( "internal error" ); - break; - } - if (res !=7) - error( "Sorry, your CPU is not capable of running 64-bit kernel." ); + unsigned before, after, flags; + unsigned a,b,c,d; + int isamd; + + /* check if the CPU supports CPUID. This is done by testing if the CPU + supports changing the ID bit (21) in EFLAGS. */ + asm("pushfl ; " + "popl %0 ; " /* get EFLAGS */ + "movl %0,%1 ; " + "xorl $(1<<21),%0 ; " /* toggle bit 21 */ + "pushl %0 ; " + "popfl ; " + "pushfl ; " /* get EFLAGS again */ + "popl %0 " : "=r" (after), "=r" (before)); + if (before == after) + error("Your CPU doesn't support CPUID."); + + /* check if it supports AMD extended cpuid reporting */ + asm("cpuid" : "=a" (a), "=b" (b), "=c" (c), "=d" (d) : "0" (0x80000000)); + + if (a < 0x80000001) + error("Your CPU doesn't support AMD extended CPUIDs."); + + /* AuthenticAMD */ + isamd = (b == 0x68747541) && (d == 0x69746e65) && (c == 0x444d4163); + /* check required feature flags */ /* see http://www.x86-64.org/lists/discuss/msg02971.html */ #define REQUIRED_MASK1 ((1<<0)|(1<<3)|(1<<4)|(1<<5)|(1<<6)|(1<<8)|(1<<11)| \ (1<<13)|(1<<15)|(1<<24)) - asm("cpuid" : "=d" (flags), "=a" (tmp) : "1" (0x80000001) : "ebx", "ecx"); + asm("cpuid" : "=d" (flags), "=a" (a) : "1" (0x80000001) : "ebx", "ecx"); flags &= REQUIRED_MASK1; flags ^= REQUIRED_MASK1; + if (flags & (1<<9)) { + puts("WARNING: non APIC mode for long mode kernel is untested."); + puts("In case of trouble use 32bit kernel or enable APIC."); + } if (flags & (1<<0)) - error("CPU misses x87"); + error("CPU misses x87 FPU"); if (flags & (1<<3)) error("CPU doesn't support page size extension (PSE)"); if (flags & (1<<4)) @@ -425,11 +387,23 @@ void check_cpu(void) error("CPU doesn't support CMOV"); if (flags & (1<<24)) error("CPU doesn't support FXSAVE/FXRSTOR"); - -#define REQUIRED_MASK2 ((1<<25)|(1<<26)) - asm("cpuid" : "=d" (flags), "=a" (tmp) : "1" (1) : "ebx", "ecx"); - flags &= REQUIRED_MASK2; - flags ^= REQUIRED_MASK2; + if (flags & (1<<29)) + error("CPU doesn't support long mode"); + +#define SSE_MASK ((1<<25)|(1<<26)) + asm("cpuid" : "=d" (flags), "=a" (a) : "1" (1) : "ebx", "ecx"); + if ((flags & SSE_MASK) != SSE_MASK && isamd) { + /* Only try this on AMD CPUs. */ + /* Enable SSE in HWCFG MSR */ + asm volatile("rdmsr" : "=d" (d), "=a" (flags) : "c" (0xc0010015)); + flags &= ~(1<<15); + asm volatile("wrmsr" :: "d" (d), "a" (flags), "c" (0xc0010015)); + } + + /* Try again */ + asm("cpuid" : "=d" (flags), "=a" (a) : "1" (1) : "ebx", "ecx"); + flags &= SSE_MASK; + flags ^= SSE_MASK; if (flags & (1<<25)) error("CPU doesn't support SSE1"); if (flags & (1<<26)) diff --git a/arch/x86_64/kernel/vsyscall.c b/arch/x86_64/kernel/vsyscall.c index e714c01d35d47..4162dd9bf8dc1 100644 --- a/arch/x86_64/kernel/vsyscall.c +++ b/arch/x86_64/kernel/vsyscall.c @@ -51,13 +51,14 @@ #include #define __vsyscall(nr) __attribute__ ((unused,__section__(".vsyscall_" #nr))) +#define force_inline __attribute__((always_inline)) inline int __sysctl_vsyscall __section_sysctl_vsyscall = 1; seqlock_t __xtime_lock __section_xtime_lock = SEQLOCK_UNLOCKED; #include -static inline void timeval_normalize(struct timeval * tv) +static force_inline void timeval_normalize(struct timeval * tv) { time_t __sec; @@ -69,7 +70,7 @@ static inline void timeval_normalize(struct timeval * tv) } } -static inline void do_vgettimeofday(struct timeval * tv) +static force_inline void do_vgettimeofday(struct timeval * tv) { long sequence, t; unsigned long sec, usec; @@ -91,12 +92,12 @@ static inline void do_vgettimeofday(struct timeval * tv) } /* RED-PEN may want to readd seq locking, but then the variable should be write-once. */ -static inline void do_get_tz(struct timezone * tz) +static force_inline void do_get_tz(struct timezone * tz) { *tz = __sys_tz; } -static inline int gettimeofday(struct timeval *tv, struct timezone *tz) +static force_inline int gettimeofday(struct timeval *tv, struct timezone *tz) { int ret; asm volatile("syscall" diff --git a/include/asm-x86_64/mtrr.h b/include/asm-x86_64/mtrr.h index 96a97091c0f7a..318b380a042da 100644 --- a/include/asm-x86_64/mtrr.h +++ b/include/asm-x86_64/mtrr.h @@ -35,11 +35,15 @@ struct mtrr_sentry unsigned int type; /* Type of region */ }; +/* Warning: this structure has a different order from i386 + on x86-64. The 32bit emulation code takes care of that. + But you need to use this for 64bit, otherwise your X server + will break. */ struct mtrr_gentry { unsigned long base; /* Base address */ - unsigned int regnum; /* Register number */ unsigned int size; /* Size of region */ + unsigned int regnum; /* Register number */ unsigned int type; /* Type of region */ }; -- 2.53.0