My first open source contribution to QEMU

I am glad to step into the open source community with my first contribution to QEMU.

For my introduction to and understanding so far about the open source community, click here.

What is QEMU

qemuQEMU is an open source machine emulator, allowing users to specify a range of properties to describe the emulated machine; ranging from the processor architecture and number of cores to peripherals attached and display properties. Furthermore, it is possible to configure network parameters, as well as a debugger connection, if required. QEMU is capable of emulating machines running full fledge operating systems, complete with a graphics stack and networking capabilities.

Two different modes of QEMU operation are:

  • User mode – emulating a, relatively simpler, machine as a process in your host OS
  • Kernel mode – advanced operation, taking over low level hardware access, with little interference from the host OS

At the lowest level, QEMU operation can be summarized by the following diagram:qemu-instruction-cycle

Given an assembly opcode in target machines instruction set architecture (ISA), QEMU parses it into a sequence of ISA-neutral operations. Subsequently, these ISA-neutral operations are translated into assembly instructions for the host machine instruction set architecture. Finally, these generated host machine instructions are executed on the host and the output is mapped back to target machine architecture to update target machine state.

A number of optimizations and caching features are incorporated for speeding up the above process.

QEMU PowerPC User mode bugs

Importance of automated test suites for ensuring quality of open source software was highlighted in my introduction to open source software. Running GNU C Compiler (GCC) test suite on QEMU emulating a PowerPC e500 architecture based machine pointed out some bugs in floating point comparison operations test cases.

I was able to pin point the problem to an error in parsing of efscmp* instructions by QEMU. I have copied my patch submission in QEMU mailing lists for more information regarding the investigation and subsequent solution:

From: Talha Imran <address@hidden>

With specification at hand from the reference manual from Freescale
http://cache.nxp.com/files/32bit/doc/ref_manual/SPEPEM.pdf , I have found a fix
to efscmp* instructions handling in QEMU.

efscmp* instructions in QEMU set crD (Condition Register nibble) values as
(0b0100 << 2) = 0b10000 (consider the HELPER_SINGLE_SPE_CMP macro which left
shifts the value returned by efscmp* handler by 2 bits). A value of 0b10000 is
not correct according the to the reference manual.

The reference manual expects efscmp* instructions to return a value of 0bx1xx.
Please find attached a patch which disables left shifting in
HELPER_SINGLE_SPE_CMP macro. This macro is used by efscmp* and efstst*
instructions only. efstst* instruction handlers, in turn, call efscmp* handlers
too.

*Explanation:*
Traditionally, each crD (condition register nibble) consist of 4 bits, which is
set by comparisons as follows:
crD = W X Y Z
where
W = Less than
X = Greater than
Y = Equal to

However, efscmp* instructions being a special case return a binary result.
(efscmpeq will set the crD = 0bx1xx iff when op1 == op2 and 0bx0xx otherwise;
i.e. there is no notion of different crD values based on Less than, Greater
than and Equal to).

This effectively means that crD will store a "Greater than" comparison result
iff efscmp* instruction comparison is TRUE. Compiler exploits this feature by
checking for "Branch if Less than or Equal to" (ble instruction) OR "Branch if
Greater than" (bgt instruction) for Branch if FALSE OR Branch if TRUE
respectively after an efscmp* instruction. This can be seen in a assembly code
snippet below:

27          if (__real__ x != 3.0f || __imag__ x != 4.0f)
10000498:   lwz r10,8(r31)
1000049c:   lis r9,16448
100004a0:   efscmpeq cr7,r10,r9
100004a4:   ble- cr7,0x100004b8 <bar+60>  //jump to abort() call
100004a8:   lwz r10,12(r31)
100004ac:   lis r9,16512
100004b0:   efscmpeq cr7,r10,r9
100004b4:   bgt- cr7,0x100004bc <bar+64>  //skip abort() call
28            abort ();
100004b8:   bl 0x10000808 

Signed-off-by: Talha Imran <address@hidden>
Signed-off-by: David Gibson <address@hidden>
---
 target-ppc/fpu_helper.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/target-ppc/fpu_helper.c b/target-ppc/fpu_helper.c
index b67ebca..6fd56a8 100644
--- a/target-ppc/fpu_helper.c
+++ b/target-ppc/fpu_helper.c
@@ -1442,7 +1442,7 @@ static inline uint32_t efststeq(CPUPPCState *env, 
uint32_t op1, uint32_t op2)
 #define HELPER_SINGLE_SPE_CMP(name)                                     \
     uint32_t helper_e##name(CPUPPCState *env, uint32_t op1, uint32_t op2) \
     {                                                                   \
-        return e##name(env, op1, op2) << 2;                             \
+        return e##name(env, op1, op2);                                  \
     }
 /* efststlt */
 HELPER_SINGLE_SPE_CMP(fststlt);
-- 
2.5.5

Pushing patch upstream

Confident with my fix for the bug, I posted it for review in QEMU mailing list. To ensure I followed the guidlines prevalent in QEMU community, I tried to closely follow the instructions listed at QEMU official website for submitting a patch. The patch was reviewed by David Gibson on the mailing list after two weeks.

In QEMU community, patches for different areas are committed to respective branches owned by maintainers (ppc-for-2.7 branch in this case). The commits are then pulled into mainline QEMU from these branches periodically.

My first open source commit has the Git commit hash: a575d9ab2e1cdfe61bc5cc8d94bd96e2adda5b44

Patch review email is available here.

Conclusion

It was a wonderfully fulfilling feeling to contribute to the community we are so used to only consuming from. Furthermore, it corroborated the sense of growth as a programmer to have stepped up to a recognized platform.

May this be the first of many contributions of come…

One comment

Leave a Reply

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