DosBOX 0.72 CPU signature behaviour


As one trying to develop such a project, “Programming For Kids”, I came to a realization: I was sorting out all my CD and DVD stuff, when all of a sudden I found it: “The DIV2 Games Studio CD”. Then, at that precise moment, I knew I was going to use it because it had – it still has -, a good tool-repertoire, such as The Explosions Generator, The Fonts Generator, and the “Sprites Generator”. I use Debian Lenny GNU/Linux, so my stable DosBox package reported me it was the 0.72 version. I got my DIV2 Installation CD, put it inside my CD-ROM drive, and installed it through the DosBox emulation software. I could execute the D.EXE command, and the DIV2 Games Studio screen appeared. It seemed all was going pretty well, I could edit maps, FPGs, use the “Explosions Generator”, and so on. But, oddly, as soon as I tried to open the Sprites Generator, I got such an awful and annoying error message:

This message means: "In order to use The Sprites Generator, you have to own a Pentium Processor or superior"

I was taken aback. Not knowing absolutely anything about the DosBox entrails, I decided to figure out what was happening. In order to do so, I was in need of two different things: Firstly; I had to know how a Dos program, a DOS program of that time, could find out what kind of processor was installed and, secondly, I had to connect that technique to the DosBox internals. Let’s dot it!

The old way to determine the installed processor

Thank God you still can find Borland Turbo Assembler on the Internet. I got it and installed it in my DosBox emulation software. According to Intel X86 Programing Reference, the old way for a Dos application of finding out what processor was installed consisted on a well-known routine, developed mainly in Assembler code. As a matter of fact, TASM included a lot of quite interesting Assembler programs as examples, and one of them was, precissely, the CPUID I was looking for. This code showed me the method of determining the installed processor. It was a piece of cake, indeed. I assembled it and linked it, and then I ran it and this is what I got:

Okay, so DosBox was emulating an Intel 486 SX processor!

Well, according to dosbox.conf documentation, there was a certain parameter called “cputype” in order to alter this behaviour. I chose “pentium_slow” as a CPU for my DosBox session, but nothing came to happen in the end. According to the CPUID Borland’s implementation, I still had a 486 SX processor. Damn it!

More about that old-way of determining the CPU type

Reading about that on the Wikipedia, I found that starting from Pentium processors, Intel added the instruction cpuid, which was the one to be used in order to determine the step, family, model and extended attributes for any processor from Pentium to nowadays’s.

And according to Borland’s CPUID example, the main difference between a 486 and a Pentium processor was directly related to the EFLAGS’s FLAG_ID bit. This bit can be flipped – that is, from zero to 1 or vice-versa -, on any processor supporting the cpuid instruction. Looking at the Borland’s CPUID sample, I found such an awful BUG:

112 check_Intel486:
113 .486
114         mov     cpu_type, 4             ;turn on Intel486 CPU flag
115         pushfd                          ;push original EFLAGS
116         pop     eax                     ; get original EFLAGS in eax
117         mov     ecx,eax                 ;save original EFLAGS in ecx
118         or      eax,200000h             ; flip ID bit in EFLAGS
119         push    eax                     ;save for EFLAGS
120         popfd                           ;copy to EFLAGS
121         pushfd                          ;push EFLAGS
122         pop     eax                     ;get new EFLAGS value
123         xor     eax,ecx
124         je      end_get_cpuid           ;if ID bit cannot be changed,
125                                         ;CPU=Intel486 without CPUID
126                                         ;instruction functionality

Have a carefully look at line 118. In order to flip the FLAG_ID EFLAG bit, the right instruction was xor, not or! Fixing that, I executed the same tool again. This time I got the same awful and annoying result: I had a 486 SX processor. Shit, man! I order to find out if that was because of DosBox emulation layer or because of some awful and not documented behaviour concerning Borland TASM, I decided to debug CPUID.EXE. Clearly, I found out that the EFLAGS’s FLAG_ID was not flipped at all.

Clearly, the EFLAGS's FLAG_ID bit (the 21th one) has not changed at all!

The previous screen-shot shows, obviously, that the stored EFLAGS after trying to flip the FLAG_ID bit, and the previous ones stored on ECX register, were the same: 0x207206. So, the XOR came to be a 0x0, and the code jumped to end_get_cpuid procedure, not even trying to execute the cpuid instruction some lines below. Somehow, I had to cheat that behaviour, and the only way to accomplish something like that would be patching the D.EXE binary directly.

Altering the CPU signature

If I was to be sure that the cpuid instruction was executed, I had to alter the CPUID.ASM code trivially. So I did; I changed the je end_get_cpuid shown some lines above for a jne – just the opposite 😉 -. Then I ran the command again through the debugger, and I could get the result of executing the cpuid instruction after passing a 0x1 to the EAX register:

cpuid instruction returns a 0x402 on EAX CPU register.

As you can see, EAX‘s value was 0x402. Despite the fact this time I could use the cpuid instruction, the result was exactly the same: it was a 486 SX processor! I got the cpuid Linux implementation tool sources, and I came to realize that 0x402 was a 486 SX processor, indeed:

 31     168     printf("Family %d - ",family);
 32  169     switch(family){
 33  170     case 3:
 34  171       printf("i386");
 35  172       break;
 36  173     case 4:
 37  174       printf("i486");
 38  175       break;
 39  176     case 5:
 40  177       printf("Pentium");
 41  178       break;
 42  179     case 6:
 43  180       printf("Pentium Pro");
 44  181       break;
 45  182     case 15:
 46  183       printf("Pentium 4");
 47  184     }

The number 4 was obtained due to:

family = (eax >> 8) & 0xf;

So, it seemed pretty obvious that DosBox was jeopardizing me all the fucking time! I had a quick look at his sources, looking for the hexadecimal number 0x402, and … gotcha! It was hard-coded in src/cpu/cpu.cpp source file, to be exact inside the CPU_CPUID() function. Here:

void CPU_CPUID(void){
case 0:
case 1:
/* get processor type/family/model/stepping and feature flags */
1928         reg_eax=0x402;      /* intel 486 sx? */

Okay, according to that code snippet, no matter what I did; DosBox was reporting all the time the processor was a 486 SX one. Okay, I assumed that could be the reason for impeding the FLAG_ID from being flipped. After all, DosBox was emulating a 486 SX processor and according to the Intel specs, there was no such facility on a 486 SX processor at all! Coherent, isn’t it?

I was not going to give it up …

I came back to the Borland’s CPUID.EXE implementation. My idea was to determine the more or less exact OPCODES correlation in order to search these same patterns inside the D.EXE binary through a hexadecimal editor.  I was totally sure that the OPCODE for cpuid was 0xFA2, it is not a secret, it is well-documented on Intel X86 Reference programming manual. So, I looked for this opcode inside the D.EXE, but I did not find it. Clearly, then, D.EXE, I mean, DIV2 Games Studio, was using the old-way of determining the kind of processor where it ran. Thanks to the Borland’s CPUID implementation code and its debugger, I could work out this OPCODES correlation in case it was NOT a Pentium processor:

6658 ; pop eax
6633C1 ; xor eax, ecx
7470 ; je 0x70

As it has to seem clear, I had to look for this OPCODES inside the D.EXE binary file. Obviously, the 7470 OPCODE could be 74XX, because the 0x70 OFFSET was the address for the end_get_cpuid procedure. The most remarkable OPCODES were 669C -> 6633C1 -> 74XX. I opened the D.EXE file with hexedit and I found four different sections of the code segment where you can find 6658 -> 6633C1, but only two of them where you can find 6658 -> 6633C1 -> 74XX. So, I tried the first one:

000002D0   8B C1 66 35  00 00 20 00  66 50 66 9D  66 9C 66 58  66 33 C1 74  ..f5.. .fPf.f.fXf3.t
000002E4   05 C6 06 2A  04 05 C3 00  8C 16 2C 04  C3 39 E0 73  13 29 E0 F7  ...*......,..9.s.)..

The OPCODE for jne was 0x75. Thus, I changed the byte 0x74 to be 0x75 this way:

000002D0   8B C1 66 35  00 00 20 00  66 50 66 9D  66 9C 66 58  66 33 C1 75  ..f5.. .fPf.f.fXf3.t
000002E4   05 C6 06 2A  04 05 C3 00  8C 16 2C 04  C3 39 E0 73  13 29 E0 F7  ...*......,..9.s.)..

As a result, D.EXE was patched. Then, I realized there was another binary, called by D.EXE, inside SYSTEM\ folder: it was the D.386 binary file. I did exactly the same in this file.

The result …

Well, it worked! I executed D.EXE again, and I tried to open the Sprites Generator. It opened, as shown in the next screen-shot:

Sprites Generator editor Window running on DosBox 0.72

An example of the generated FPG and showing information about a concrete graphic

So, now, I can use this useful aid in order to create animated human-being-based sprites. Isn’t that marvellous?

The final joke … (I’m bloody frustrated, man! :-()

I downloaded the latest DosBox version, say 0.74, and peered at its sources. Curiously, this time I found this piece of code for the CPU_CPUID function:

2386         } else if (cputype == "pentium_slow") {
2387             CPU_ArchitectureType = CPU_ARCHTYPE_PENTIUMSLOW;
2388         }
2390         if (CPU_ArchitectureType>=CPU_ARCHTYPE_486NEWSLOW) CPU_flag_id_toggle=FLAG_ID;
2391         else CPU_flag_id_toggle=0;

And also, in the CPU_SetFlags routine, I found this right behaviour – now – :

172 void CPU_SetFlags(Bitu word,Bitu mask) {
 173     mask|=CPU_flag_id_toggle;   // ID-flag can be toggled on cpuid-supporting CPUs
 174     reg_flags=(reg_flags & ~mask)|(word & mask)|2;
 175     cpu.direction=1-((reg_flags & FLAG_DF) >> 9);
 176 }

Do you see? God damn it! In DosBox 0.74, the cputype directive does apply. Motherfuckers!

References and more information

CPUID Instruction reference and code sample snippets

DIV2 Games Studio – reminiscenses of the past 😉 –

Borland Turbo Assembler 5.X

D.EXE and D.386 patched

Download and put D.EXE on C:\DIV2; D.386 on C:\DIV2\SYSTEM, and that’s it!!!