Yavor Doganov wrote: >> Well, I happen to know for a fact that the processor actually does have a >> CPUID instruction, it's just disabled by default. It can be enabled quite >> easily, which might be an avenue of enquiry for this problem. > > I would be very grateful if you tell me how to do it. It will resolve > the issue at least for our Cyrix CPUs, but will remain for 486. > > For me this bug is RC, because Debian is supposed to support CPUs >=i486 > for the i386 architecture.
I've attached a bit of hacked-together inline x86 assembly I wrote about 6 years ago to identify CPUs, which, as you would expect, enabled CPUID on Cyrix CPUs to do it's job. It's not much use as-is, but should give you the basic idea for enabling Cyrix's CPUID. I did a bit of digging, and it seems this used to be handled correctly by 2.4 kernels, but 2.6 seems to have broken it. People have suggested patches, but nothing seems to have happened....as well, it doesn't work on mine :)
SCPUInfo TempCPU;
//The Dreaded Assembler
__asm
{
inc TempCPU.Family ;//We have to have at least a
186
//Determine whether model came before or after the 286
xor ax, ax ;//Set AX to 0
push ax ;//and push onto stack
popf ;//Pop flag register off of stack
pushf ;//Push back onto stack
pop ax ;//and pop off of AX
and ax, 0x0f000 ;//Do not clear the upper four bits
cmp ax, 0x0f000 ;//Are bits 12 - 15 all equal to 1?
je END ;//NO - It's a 186 or some other dinosaur
inc TempCPU.Family ;//YES - We have at least a 286
//Now work out if we have a 286 or above
mov ax, 0x07000 ;//Push 07000h
push ax ;//onto stack
popf ;//Pop flag register off
pushf ;//and push back onto the stack
pop ax ;//Pop into AX register
//Are Bits 12-14 NOT all 0
and ax, 0x07000 ;//Mask all except bits 12-14
je END ;//NO --> Bits 12 - 14 are all 0 so a 286
inc TempCPU.Family ;//YES -> We have at least a 386
//Now work out if we have a 386 or above
//Move the current EFLAGS into EAX
pushfd ;//Push the EFLAGS onto the stack
pop eax ;//Pop the EFLAGS into EAX
//Store our EFLAGS for later
mov ecx, eax ;//Copy the value in EAX into ECX
//Toggle bit 18 (The Alignment Check flag) in the EFLAGS register
xor eax, 0x00040000 ;
//Move the new EFLAGS from EAX to the EFLAGS register
push eax ;//Push EAX onto the stack
popfd ;//Pop the EFLAGS into EFLAGS register
//Move the new EFLAGS back into EAX
pushfd ;//Push the EFLAGS onto the stack
pop eax ;//Pop the EFLAGS into EAX
//Compare our new EFLAGS with our original EFLAGS
xor eax, ecx ;//XOR original & new EFLAGS
jz END ;//Can't toggle the AC bit, so a 386
//Restore original EFlags
push ecx ;//Push ECX onto the stack
popfd ;//Pop old flags into the EFlags register
//Increment our counter
inc TempCPU.Family ;//We have at least a 486
//Now work out if we have the CPUID instuction availible
//CPUID test counter
mov ebx, 0 ;//Clear our counter
CPUIDTEST:
//We still have the original flags in ECX
mov eax, ecx ;//Move the value in ECX into EAX
//Toggle bit 21 (The ID flag) in the EFLAGS register
xor eax, 0x00200000 ;
//Move the new EFLAGS from EAX to the EFLAGS register
push eax ;//Push EAX onto the stack
popfd ;//Pop the EFLAGS into EFLAGS register
//Move the new EFLAGS back into EAX
pushfd ;//Push the EFLAGS onto the stack
pop eax ;//Pop the EFLAGS into EAX
//Compare our new EFLAGS with our original EFLAGS
xor eax, ecx ;//XOR original and new EFLAGS
jnz POSTCPUID ;//Can't toggle the AC bit, so a 486
cmp ebx, 1 ;//See if EBX = 1;
je END ;//YES-> Failed to enable CPUID, so a 486
//But, Cyrix 6x86 processors can have the ID bit enabled
//Enable the Configuration Control Registers (MAPEN)
//Select register CCR3 (c3h) -- (Port 22h is register selection)
mov al, 0xc3 ;// c3h = index of CCR3
out 0x22, al ;// read/write of port 23h from/to CCR3
//Get MAPEN (bits 4-7) value -- (Port 23h is now CCR3)
in al, 0x23 ;// Get from port 23h (al= value of CCR3)
and al, 0x0f ;// Clear MAPEN, preserving bits 0-3
or al, 0x10 ;// MAPEN to 1 -> registers accessible
// Save future CCR3
mov ah, al ;// AH has a copy of our new CCR3
//Select register CCR3 (c3h) -- (Port 22h is register selection)
mov al, 0xc3 ;// c3h = index of CCR3
out 0x22, al ;// read/write of port 23h from/to CCR3
//Send out our (Modified) CCR3 so we can modify the CPU registers
mov al, ah ;// Copy our new CCR3 into AL
out 0x23, al ;// MAPEN (bits 4-7) in CCR3 are set
//Enable the CPUID Instruction
//Select register CCR4 (e8h) -- (Port 22h is register selection)
mov al, 0xe8 ;// e8h = index of CCR4
out 0x22, al ;// read/write of port 23h from/to CCR4
//Get the value of CCR4 -- (Port 23h is now CCR4)
in al, 0x23 ;// Get from port 23h (al= value of CCR4)
or al, 0x80 ;// Enable the CPUID Instruction bit
// Save future CCR4
mov ah, al ;// copy CCR4 where CPUID is Enabled
//Select register CCR4 (e8h) -- (Port 22h is register selection)
mov al, 0xe8 ;// e8h = index of CCR4
out 0x22, al ;// read/write of port 23h from/to CCR4
//Send out our new (Modified) CCR4 so CPUID is availible
mov al, ah ;// AH has a copy of our new CCR4
out 0x23, al ;// CPUIDEN (bit 7) in CCR4 is cleared
//Disable the Configuration Control Registers (MAPEN)
//Select register CCR3 (c3h) -- (Port 22h is register selection)
mov al, 0xc3 ;// c3h = index of CCR3
out 0x22, al ;// read/write of port 23h from/to CCR3
//Get MAPEN value -- (Port 23h is now CCR3)
in al, 0x23 ;// Get from port 23h (al= value of CCR3)
and al, 0x0f ;// Clear MAPEN (bits 4-7)
// Save future CCR3
mov ah, al ;// AH has a copy of our new CCR3
//Select register CCR3 (c3h) -- (Port 22h is register selection)
mov al, 0xc3 ;// c3h = index of CCR3
out 0x22, al ;// read/write of port 23h from/to CCR3
//Send out our new CCR3 so the CPU registers are locked
mov al, ah ;// Copy our new CCR3 into AL
out 0x23, al ;// MAPEN (bits 4-7) in CCR3 are set to 0
//Only try again once
mov ebx, 1 ;//Move 1 into EBX
//Try again
jmp CPUIDTEST ;//Jump to the CPUID test label
POSTCPUID:
//Restore original EFlags
push ecx ;//Push ECX onto the stack
popfd ;//Pop old flags into the EFlags register
//We can now use the CPUID instruction to get a lot of processor information
mov eax, 0 ;//We want function 0 of CPUID
cpuid ;//See macro at the top of this file
//This checks that we have a (GenuineIntel) processor
cmp ebx, 0x756e6547 ;//ASCII: uneG (Genu)
jne NOTINTEL
cmp edx, 0x49656e69 ;//ASCII: Ieni (ineI)
jne NOTINTEL
cmp ecx, 0x6c65746e ;//ASCII: letn (ntel)
jne NOTINTEL
mov TempCPU.Manufacturer, INTEL_CPU ;//Intel Processor
//Now lets get some more specific information
mov eax, 1 ;//We want function 1 of CPUID
cpuid ;//See macro at the top of this file
//Get processor Info from the processor signature in the EAX register
mov ebx, eax ;//Copy processor info into EBX from EAX
and ebx, 0xf ;//We want bits 0-3
mov TempCPU.Stepping, ebx ;//Fill in the stepping info
mov ebx, eax ;//Copy processor info into EBX from EAX
and ebx, 0xf0 ;//We want bits 4-7
shr ebx, 4;
mov TempCPU.Model, ebx ;//Fill in the model info
mov ebx, eax ;//Copy processor info into EBX from EAX
and ebx, 0xf00 ;//We want bits 8-11
shr ebx, 8;
mov TempCPU.Family, ebx;//Fill in the family info
mov ebx, eax ;//Copy processor info into EBX from EAX
and ebx, 0x1000 ;//We want bit 12 (13 is dual processor)
shr ebx, 12;
mov TempCPU.IsOverDrive, ebx;//Do we have an Overdrive?
mov TempCPU.Serial1, eax ;//Copy processor sig. for serial
number
//Test for MMX Capabilty using the feature flags in the EDX register
mov ebx, edx ;//Copy feature flags into EBX from EDX
and ebx, 0x00800000 ;//Check for bit 23 (MMX Present)
shr ebx, 23 ;//Shift the result to bit 1
mov TempCPU.MMX, ebx ;//After AND, 1 for
MMX, 0 for no MMX
//Test for SIMD Capabilty using the feature flags in the EDX register
mov ebx, edx ;//Copy feature flags into EBX from EDX
and ebx, 0x02000000 ;//Check for bit 25 (SIMD Present)
shr ebx, 25 ;//Shift the result to bit 1
mov TempCPU.SIMD, ebx ;//Else, we have SIMD
//Now lets get the cache information
mov eax, 2 ;//We want function 2 of CPUID
cpuid ;//See macro at the top of this file
//For now, only get the 2nd level cache size
and edx, 0xff ;
mov TempCPU.Level2Cache, edx ;
//Now lets get the serial number
mov eax, 3 ;//We want function 3 of CPUID
cpuid ;//See macro at the top of this file
mov TempCPU.Serial2, edx ;
mov TempCPU.Serial3, ecx ;
jmp END ;
NOTINTEL:
//Now lets try getting the manufacturer ID again
mov eax, 0 ;//We want function 1 of CPUID
cpuid ;//See macro at the top of this file
cmp ebx, 0x69727943 ;//ASCII: iryC (Cyri)
jne NOTCYRIX ;
cmp edx, 0x736e4978 ;//ASCII: snIx (xIns)
jne NOTCYRIX ;
cmp ecx, 0x64616574 ;//ASCII: daet (tead)
jne NOTCYRIX ;
mov TempCPU.Manufacturer, CYRIX_CPU ;//Intel Processor
//Get Misc. Processor Info
//Select register DIR0 (FEh) -- (Port 22h is register selection)
mov al, 0xfe ;// feh = index of DIR0
out 0x22, al ;// read/write of port 23h
from/to DIR0
//Get the value of DIR0 -- (Port 23h is now DIR0)
in al, 0x23 ;// Get from port 23h (al=
value of DIR0)
mov TempCPU.ClockMultiplier, eax;
//Now lets get some more specific information
mov eax, 1 ;//We want function 1 of CPUID
cpuid ;//See macro at the top of this file
//Get the processor Info from processor signature in the EAX register
mov ebx, eax ;//Copy processor info into EBX from EAX
and ebx, 0xf ;//We want bits 0-3
mov TempCPU.Stepping, ebx ;//Fill in the stepping info
mov ebx, eax ;//Copy processor info into EBX from EAX
and ebx, 0xf0 ;//We want bits 4-7
shr ebx, 4 ;
mov TempCPU.Model, ebx ;//Fill in the model info
mov ebx, eax ;//Copy processor info into EBX from EAX
and ebx, 0xf00 ;//We want bits 8-11
shr ebx, 8 ;
mov TempCPU.Family, ebx ;//Fill in the Family info
mov ebx, eax ;//Copy processor info into EBX from EAX
and ebx, 0x1000 ;//We want bit 12 (bit 13 is for dual
processors but I don't care)
shr ebx, 12 ;
mov TempCPU.IsOverDrive, ebx ;//Do we have an Overdrive?
mov TempCPU.Serial1, eax ;//Copy processor sig. for serial number
//Test for MMX Capabilty using the feature flags in the EDX register
mov ebx, edx ;//Copy feature flags into EBX from EDX
and ebx, 0x00800000 ;//Check for bit 23 (MMX Present)
shr ebx, 23 ;//Shift the result to bit 1
mov TempCPU.MMX, ebx ;//After AND, 1 for
MMX, 0 for no MMX
//Test for SIMD Capabilty using the feature flags in the EDX register
mov ebx, edx ;//Copy feature flags into EBX from EDX
and ebx, 0x02000000 ;//Check for bit 25 (SIMD Present)
shr ebx, 25 ;//Shift the result to bit 1
mov TempCPU.SIMD, ebx ;//Else, we have SIMD
jmp END ;
NOTCYRIX:
mov TempCPU.Manufacturer, AMD_CPU;//Assume AMD for now
//Now lets get some more specific information
mov eax, 1 ;//We want function 1 of CPUID
cpuid ;//See macro at the top of this file
//Test for MMX Capabilty using feature flags in the EDX register
mov ebx, edx ;//Copy feature flags into EBX from EDX
and ebx, 0x00800000 ;//Check for bit 23 (MMX Present)
shr ebx, 23 ;//Shift the result to bit 1
mov TempCPU.MMX, ebx ;//After AND, 1 for
MMX, 0 for no MMX
jmp END ;
END:
}
signature.asc
Description: OpenPGP digital signature

