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