Page 1 of 1

Identify this!

Posted: Wed Mar 05, 2008 5:38 pm
by Zacariaz
I have finaly figured out what i wan't to do, and thats about it.

First step involves identifying the cpu (in real mode/boot time) but i haven't been able to find much on google.

Basicly i just wanted to ask if anyone knows of any good recourses.

Thanks

edit: You are probably thinking, what an idiot, just use the CPUID, but when reading the manual, allthough it doesn't state that it can't be used in real mode, it refers only to 32bit registers, so this is a bit confusing.

Posted: Wed Mar 05, 2008 6:06 pm
by Combuster
you can use 32-bit registers in real mode, thanks.

Posted: Wed Mar 05, 2008 6:16 pm
by Zacariaz
If thats the fact that probably the reason i've had such a hard time with this. It's embaresing enough as it is but it doesn't really make sence, 16 bit real mode and 32 bit registers? There must be some limitations.

Posted: Wed Mar 05, 2008 11:12 pm
by bewing
Just the default size of the registers, and some details of the instruction set -- like the way SIB bytes are handled in opcodes.

Posted: Thu Mar 06, 2008 12:08 am
by Brendan
Hi,
Zacariaz wrote:It's embaresing enough as it is but it doesn't really make sence, 16 bit real mode and 32 bit registers? There must be some limitations.
You can use 32-bit registers and 32-bit addressing in real mode, just like you can use 16-bit registers and 16-bit addressing in 32-bit protected mode. The limitations are that you need a CPU capable of operating on 32-bits (it won't work for 80286 or older CPUs) and (for 32-bit addressing in real mode) the segment limits are still 64 KB.

This means that (for e.g.) in real mode you can use an instruction like "lea eax,[ecx*4+edx]", even though the 16-bit version of the instruction (e.g. "lea ax,[cx*4+dx]") won't work (it's not a valid addressing mode for 16-bit code).

You may want code to determine if the CPU supports 32-bit registers, etc. Here's some:

Code: Select all

;The first step is to find out if the CPU is an original 8086. This is necessary
;because the other tests will crash an 8086. This test simply determines
;if bit 15 of the flags register is set, as this bit is hardwired to 1
;on an 8086 and hardwired to 0 on everything after it.

	cli
	pushf
	pop ax				;ax = original flags
	test ah,0x80			;Is bit 15 set?
	jne .CPUold			; yes, old 8086!

;The next step is to find out if the CPU is 32 bit (80386 or later). This
;test just checks to see if the IOPL bits (bits 12 and 13) can be changed.
;On CPUs that don't support 32 bit protected mode these bits aren't
;implemented in the CPU.

	xor ah,0x30			;ax = flags with modified IOPL bits
	push ax				;Save flags
	popf				;Load flags
	pushf				;Save modified flags
	pop bx				;bx = modified flags
	xor ax,bx			;ax = flags with changed bits set
	test ah,0x30			;Did IOPL bits change?
	jne .CPUold			; no, not a 32 bit CPU

	CPU 386

;Make sure ESP is the same as SP.

	movzx esp,sp

;Now we know that the CPU is at least an 80386, so we can use
;eflags (the 32 bit version of the flags register) to see if it's
;an 80486 or later. Here we see if the bit that enables/disables
;the alignment check feature can be modified. Alignment check
;didn't exist before 80486, so this bit can't be changed on
;older CPUs.

	pushfd
	mov eax,[esp]			;eax = original eflags
	xor eax,0x00040000		;Invert AC flag
	push eax			;Store new eflags on stack
	popfd				;Read new eflags
	pushfd				;Store modified eflags
	pop ebx				;ebx = flags after changing
	xor eax,ebx			;If bits changed set them, else clear them
	popfd				;Restore original eflags
	test eax,0x40000		;Is alignment check supported?
	jne .CPUold			; no, must be older than an 80486

;After all that we know BCOS will be able to run on the CPU. We restore
;eflags to a known state and return.

	push dword 0x00000202		;Push default eflags (interrupts & reserved bit)
	popfd
	ret


;Error Handler
;_______________________________________________________________________________

;This little bit of code is responsible for displaying the "Your
;CPU is too old" error message and halting.

.CPUold:
	sti
	mov si,badCPUstring
	jmp abortBoot
The next step would be to determine if the CPUID instruction is supported or not. For this I setup an invalid opcode exception and execute CPUID to see if I get an invalid opcode exception or not. The normal method recommended by Intel (checking if the ID bit in EFLAGS can be modified) doesn't work on some CPUs (some CPUs, e.g. NexGen, support CPUID but don't support the ID bit in EFLAGS).

Also, for some CPUs (e.g. Cyrix) the CPUID instruction needs to be enabled before it's used, so if CPUID isn't supported you'd check if the CPU might be a Cyrix (using the "5/2" method) and then determine if it's an IBM "Blue Lightning" or a Cyrix (the IBM "Blue Lightning" chip supports MSRs while Cyrix chips don't).

If it is a Cyrix there's I/O ports to mess with. These I/O ports can return the "Cyrix CPU identification" information and (for later Cyrix CPUs) the I/O ports can also enable the CPUID instruction (and do other things).

In general, how much hassle CPU identification is will depend on which CPUs you support (e.g. it's easier if you don't support Pentium or older CPUs) and if you want high quality code or "average" code... ;)

IMHO at a minimum you need a reliable set of feature flags to determine if the CPU/s support a certain feature or not. This means getting the dodgy feature flags from CPUID and correcting them.


Cheers,

Brendan