This patch augments the existing cpu initialization code in C with the the few missing pieces that were performed in assembly. Allowing us to remove cpu initialization from head.S completely. This should also allow remove the need to call cpu_detect in the paravirt initialization code paths. Signed-off-by: Eric W. Biederman <ebiederm@xxxxxxxxxxxx> --- arch/i386/kernel/cpu/common.c | 55 +++++++++++++++++++---- arch/i386/kernel/head.S | 96 +---------------------------------------- arch/i386/kernel/setup.c | 3 - 3 files changed, 47 insertions(+), 107 deletions(-) diff --git a/arch/i386/kernel/cpu/common.c b/arch/i386/kernel/cpu/common.c index 794d593..1a7b48a 100644 --- a/arch/i386/kernel/cpu/common.c +++ b/arch/i386/kernel/cpu/common.c @@ -251,6 +251,16 @@ static inline int flag_is_changeable_p(u32 flag) return ((f1^f2) & flag) != 0; } +static inline int has_x87(void) +{ + unsigned result; + asm("clts\n\t" + "fninit\n\t" + "fstsw %%ax\n\t" + : "=a"(result)); + return (result & 0xf) == 0; +} + /* Probe for the CPUID instruction */ static int __cpuinit have_cpuid_p(void) @@ -258,6 +268,23 @@ static int __cpuinit have_cpuid_p(void) return flag_is_changeable_p(X86_EFLAGS_ID); } +static int __cpuinit init_cr0(void) +{ + unsigned long cr0; + int hard_math; + cr0 = read_cr0(); + cr0 &= X86_CR0_PG | X86_CR0_ET | X86_CR0_PE; + cr0 |= X86_CR0_MP; + if (flag_is_changeable_p(X86_EFLAGS_AC)) + cr0 |= X86_CR0_AM | X86_CR0_WP | X86_CR0_NE; + write_cr0(cr0); + hard_math = has_x87(); + if (!hard_math) + /* No coprocessor: Enable emulation */ + write_cr0(cr0 | X86_CR0_EM); + return hard_math; +} + void __init cpu_detect(struct cpuinfo_x86 *c) { /* Get vendor name */ @@ -268,8 +295,10 @@ void __init cpu_detect(struct cpuinfo_x86 *c) c->x86 = 4; if (c->cpuid_level >= 0x00000001) { - u32 junk, tfms, cap0, misc; - cpuid(0x00000001, &tfms, &misc, &junk, &cap0); + u32 tfms, misc, excap, capability; + cpuid(0x00000001, &tfms, &misc, &excap, &capability); + c->x86_capability[0] = capability; + c->x86_capability[4] = excap; c->x86 = (tfms >> 8) & 15; c->x86_model = (tfms >> 4) & 15; if (c->x86 == 0xf) @@ -277,7 +306,7 @@ void __init cpu_detect(struct cpuinfo_x86 *c) if (c->x86 >= 0x6) c->x86_model += ((tfms >> 16) & 0xF) << 4; c->x86_mask = tfms & 15; - if (cap0 & (1<<19)) + if (capability & (1<<19)) c->x86_cache_alignment = ((misc >> 8) & 0xff) * 8; } } @@ -292,14 +321,21 @@ static void __init early_cpu_detect(void) { struct cpuinfo_x86 *c = &boot_cpu_data; + c->cpuid_level = -1; c->x86_cache_alignment = 32; - if (!have_cpuid_p()) - return; - - cpu_detect(c); - - get_cpu_vendor(c, 1); + if (!have_cpuid_p()) { + /* First of all, decide if this is a 486 or higher */ + /* It's a 486 if we can modify the AC flag */ + if ( flag_is_changeable_p(X86_EFLAGS_AC) ) + c->x86 = 4; + else + c->x86 = 3; + } else { + cpu_detect(c); + get_cpu_vendor(c, 1); + } + c->hard_math = init_cr0(); } static void __cpuinit generic_identify(struct cpuinfo_x86 * c) @@ -670,6 +706,7 @@ void __cpuinit cpu_init(void) printk(KERN_INFO "Initializing CPU#%d\n", cpu); + init_cr0(); if (cpu_has_vme || cpu_has_tsc || cpu_has_de) clear_in_cr4(X86_CR4_VME|X86_CR4_PVI|X86_CR4_TSD|X86_CR4_DE); if (tsc_disable && cpu_has_tsc) { diff --git a/arch/i386/kernel/head.S b/arch/i386/kernel/head.S index 0ee615b..5e3478b 100644 --- a/arch/i386/kernel/head.S +++ b/arch/i386/kernel/head.S @@ -20,19 +20,6 @@ #include <asm/setup.h> /* - * References to members of the new_cpu_data structure. - */ - -#define X86 new_cpu_data+CPUINFO_x86 -#define X86_VENDOR new_cpu_data+CPUINFO_x86_vendor -#define X86_MODEL new_cpu_data+CPUINFO_x86_model -#define X86_MASK new_cpu_data+CPUINFO_x86_mask -#define X86_HARD_MATH new_cpu_data+CPUINFO_hard_math -#define X86_CPUID new_cpu_data+CPUINFO_cpuid_level -#define X86_CAPABILITY new_cpu_data+CPUINFO_x86_capability -#define X86_VENDOR_ID new_cpu_data+CPUINFO_x86_vendor_id - -/* * 32-bit kernel entrypoint; only used by the boot CPU. On entry, * %esi points to the real-mode code as a 32-bit pointer. * CS and DS must be 4 GB flat segments, but we don't depend on @@ -182,6 +169,7 @@ ENTRY(startup_32_smp) movl $swapper_pg_dir-__PAGE_OFFSET,%eax movl %eax,%cr3 /* set the page table pointer.. */ movl %cr0,%eax + andl $0x0000011,%eax /* Save PE,ET */ orl $0x80000000,%eax movl %eax,%cr0 /* ..and set paging (PG) bit */ ljmp $__BOOT_CS,$1f /* Clear prefetch and normalize %eip */ @@ -197,69 +185,6 @@ ENTRY(startup_32_smp) pushl $0 popfl -checkCPUtype: - - movl $-1,X86_CPUID # -1 for no CPUID initially - -/* check if it is 486 or 386. */ -/* - * XXX - this does a lot of unnecessary setup. Alignment checks don't - * apply at our cpl of 0 and the stack ought to be aligned already, and - * we don't need to preserve eflags. - */ - - movb $3,X86 # at least 386 - pushfl # push EFLAGS - popl %eax # get EFLAGS - movl %eax,%ecx # save original EFLAGS - xorl $0x240000,%eax # flip AC and ID bits in EFLAGS - pushl %eax # copy to EFLAGS - popfl # set EFLAGS - pushfl # get new EFLAGS - popl %eax # put it in eax - xorl %ecx,%eax # change in flags - pushl %ecx # restore original EFLAGS - popfl - testl $0x40000,%eax # check if AC bit changed - je is386 - - movb $4,X86 # at least 486 - testl $0x200000,%eax # check if ID bit changed - je is486 - - /* get vendor info */ - xorl %eax,%eax # call CPUID with 0 -> return vendor ID - cpuid - movl %eax,X86_CPUID # save CPUID level - movl %ebx,X86_VENDOR_ID # lo 4 chars - movl %edx,X86_VENDOR_ID+4 # next 4 chars - movl %ecx,X86_VENDOR_ID+8 # last 4 chars - - orl %eax,%eax # do we have processor info as well? - je is486 - - movl $1,%eax # Use the CPUID instruction to get CPU type - cpuid - movb %al,%cl # save reg for future use - andb $0x0f,%ah # mask processor family - movb %ah,X86 - andb $0xf0,%al # mask model - shrb $4,%al - movb %al,X86_MODEL - andb $0x0f,%cl # mask mask revision - movb %cl,X86_MASK - movl %edx,X86_CAPABILITY - -is486: movl $0x50022,%ecx # set AM, WP, NE and MP - jmp 2f - -is386: movl $2,%ecx # set MP -2: movl %cr0,%eax - andl $0x80000011,%eax # Save PG,PE,ET - orl %ecx,%eax - movl %eax,%cr0 - - call check_x87 lgdt early_gdt_descr ljmp $(__KERNEL_CS),$1f 1: movl $(__KERNEL_DS),%eax # reload all the segment registers @@ -288,25 +213,6 @@ is386: movl $2,%ecx # set MP #endif /* CONFIG_SMP */ jmp i386_start_kernel -/* - * We depend on ET to be correct. This checks for 287/387. - */ -check_x87: - movb $0,X86_HARD_MATH - clts - fninit - fstsw %ax - cmpb $0,%al - je 1f - movl %cr0,%eax /* no coprocessor: have to set bits */ - xorl $4,%eax /* set EM */ - movl %eax,%cr0 - ret - ALIGN -1: movb $1,X86_HARD_MATH - .byte 0xDB,0xE4 /* fsetpm for 287, ignored by 387 */ - ret - ENTRY(early_divide_err) xor %edx,%edx pushl $0 /* fake errcode */ diff --git a/arch/i386/kernel/setup.c b/arch/i386/kernel/setup.c index 3e31591..401e48a 100644 --- a/arch/i386/kernel/setup.c +++ b/arch/i386/kernel/setup.c @@ -76,8 +76,6 @@ int disable_pse __devinitdata = 0; extern struct resource code_resource; extern struct resource data_resource; -/* cpu data as detected by the assembly code in head.S */ -struct cpuinfo_x86 new_cpu_data __cpuinitdata = { 0, 0, 0, 0, -1, 1, 0, 0, -1 }; /* common cpu data for all cpus */ struct cpuinfo_x86 boot_cpu_data __read_mostly = { 0, 0, 0, 0, -1, 1, 0, 0, -1 }; EXPORT_SYMBOL(boot_cpu_data); @@ -515,7 +513,6 @@ void __init setup_arch(char **cmdline_p) { unsigned long max_low_pfn; - memcpy(&boot_cpu_data, &new_cpu_data, sizeof(new_cpu_data)); pre_setup_arch_hook(); early_cpu_init(); -- 1.5.1.1.181.g2de0 _______________________________________________ Virtualization mailing list Virtualization@xxxxxxxxxxxxxxxxxxxxxxxxxx https://lists.linux-foundation.org/mailman/listinfo/virtualization