Compiling WinQEMU v0.10.2 using Visual Studio 2008 and Visual Studio 2012

3.00 avg. rating (74% score) - 1 vote

Earlier this year I managed to get DOSBox-X to boot Ubuntu 9.10, as least as far as dropping into the initramfs shell, in an attempt to reverse engineer a legacy Linux device driver. Although DOSBox-X worked just fine, eventually there was a need to study the device driver behavior in a full Linux environment, and the time has come for me to search for a better solution.

QEMU is definitely a better choice as it is still actively maintained and can run anything from MS-DOS to the most recent 64-bit OS. However, recent versions of QEMU can only be built on Linux, or at least MinGW, and debugging using GDB has never been my cup of tea. I know some developers hate Visual Studio, but I usually prefer a GUI way of debugging things, where possible.

After some efforts I located a port of QEMU v0.10.2 for Visual Studio 2008 (see also github repository). It was done by some Chinese developer (judging from the Chinese language in the included readme.txt file), was not subsequently maintained and eventually abandoned in 2009. Nevertheless I decided this would be my best shot and focused my efforts in getting WinQEMU to work.

Visual Studio 2008 will no longer work properly in Windows 11, so I installed it on Windows XP running in VirtualBox. After that, install the DirectX November 2007 SDK (filename: dxsdk_november2007.exe) and configure Visual Studio to parse the relevant header and library files. This can be done from Tools > Options > Projects and Solutions > VC++ directories:

vcpp

Then, I fixed a few hard-coded include paths as well as a missing header file (opcode-cris.h). Although the file is available on the WinQEMU’s Github repository, its content has been changed over the years. It took me a while to search Github commit history and locate an old version which will work with WinQEMU. With this, WinQEMU successfully compiled on Visual Studio 2008.

The next challenge is to find the correct ROM BIOS and VGA BIOS which will work with this version of QEMU by seaching the SeaBIOS archives here. Again, it took me a while to find the correct BIOS, without this the emulated computer will not boot and will just show a black screen.

Next, we need to set up the command line parameters telling WinQEMU the configuration of the emulated machine. This is done by setting Debugging > Command Arguments from the property pages of WinQEMUTest:

-net none -cpu coreduo -m 480 -M pc -vga std -hda d:\Images\WINME.img

The above setting emulates a Core Duo PC, 480MB of RAM, with VGA display having WINME.IMG as the hard disk drive. WinQEMU will then load the ROM BIOS and VGA BIOS from the directory specified by CONFIG_QEMU_SHAREDIR in config-host.h:

#define CONFIG_QEMU_SHAREDIR "d:\\Images"
#define HOST_I386 1
#define HOST_LONG_BITS 32
#define CONFIG_WIN32 1
//#define CONFIG_GDBSTUB 1
#define CONFIG_STATIC 1
#define CONFIG_SLIRP 1
#define CONFIG_ADLIB 1
#define QEMU_VERSION "0.10.0"
#define CONFIG_UNAME_RELEASE ""

With everything setup correctly, Visual Studio 2008 is finally able to debug WinQEMU booting up Windows ME:

qemu

Take note that you should disable Virtual Box mouse integration, else the mouse cursor will move randomly. This issue is not unique to VirtualBox or QEMU and is common for emulator-within-emulator scenarios. Recent versions of Virtual Box added a message panel covering the right portion of the virtual machine, making the situation worse. Also for the record, Windows ME is the last Windows version to work on DOSBox. Later Windows versions (Windows 2000 onwards) will fail to find the IDE controller on DOSBox but work well on WinQEMU (I tested up to XP).

After successfully setting up the project with VS2008, I also managed to get the project compiled under Visual Studio 2012. After going through VS2012 upgrade wizard, not many extra steps were needed, except to add the DirectX SDK files to the VC++ Directories page in the project property. In VS2008, these settings were set on a global basis from Tools > Options.

vs2012

WinQEMU now boots Window XP 32-bit just fine:

qemuxp

Ubuntu 10 works fine too:

ubu10

You can boot newer 32-bit OSes if you configure a higher amount of RAM for the emulated machine. WinQEMU is a 32-bit application and can only theoretically support up to 4GB of RAM. Under Visual Studio 2012, to be safe, you should configure the emulated RAM to be 3GB or less.

To note, during the process I discovered that WinQEMU always disassembles a bunch of instructions and executes them at once, independent of any caching that would be done by the OS. In cpu-exec.c around line 640 you will find the following lines of codes

/* execute the generated code */
#if defined(__sparc__) && !defined(HOST_SOLARIS)
#undef env
	env = cpu_single_env;
#define env cpu_single_env
#endif

#ifdef _MSC_VER
	pGenCodeBuffer = &(code_gen_prologue [0]);

	if ((env->eip == 0x9016ee30) || (env->eip == 0x9117a000))
	{
		pGenCodeBuffer = &(code_gen_prologue [0]);
	}

	__asm
	{
		mov eax, tc_ptr;

		mov nEbpBackup, ebp;
		mov ebp, env;
		call pGenCodeBuffer;

		mov ebp, nEbpBackup;
		mov next_tb,eax;
	}
#else
	next_tb = tcg_qemu_tb_exec(tc_ptr);
#endif

Here the generated code is stored in pGenCodeBuffer, which is essentially array of pointers to functions which will perform the relevant CPU instructions (e.g. MOV, CMP, JMP etc.) once executed. The usage of inline assembly instructions to execute these functions, specifically the line call pGenCodeBuffer, will confuse the debugger. If you run OUT DX, AL and trace how QEMU actually handles this instruction, you will find that the stack trace starts from helper_outb(uint32_t port, uint32_t data) (file op_helper.c) and ended with ioport_write(int index, uint32_t address, uint32_t data) (file vl.c), with no records of what leads to the helper_outb call. You will then have to perform a text search of the QEMU source code to realize that this function originates from the gen_helper_outb call within gen_helper_out_func (file translate.c line 747), which could be then traced back to function disas_insn() also within translate.c, where the majority of the code generation is performed. And for some reasons, the code generation buffer is only performed if compiling using Visual C++ (see the #ifdef _MSC_VER preprocessor).

I have to say that the structure of QEMU is far more complex than that of DOSBox or other emulators.┬áDOSBox usually disassembles and execute instructions one by one. But then again, QEMU is a much more advanced emulator …

WinQEMU does not compile on newer versions of Visual Studio. I tried, only to be presented with zillions of error messages within various C headers and did not have the time to fix the issue. Visual Studio 2012 works well on Windows 11 and can be installed concurrently with newer versions of Visual Studio. The WinQEMU VS2012 setup is therefore good enough for me.

You can download the VS2008 and VS2012 solution files here. The BIOS files are located in the BIOS folder.

See also:
Getting Linux to boot on DOSBox-X

 

 

 

3.00 avg. rating (74% score) - 1 vote
ToughDev

ToughDev

A tough developer who likes to work on just about anything, from software development to electronics, and share his knowledge with the rest of the world.

Leave a Reply

Your email address will not be published. Required fields are marked *

You may use these HTML tags and attributes: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <strike> <strong>