ok, here are a few things that ring a bell, there are probably a lot others:
the software mmu implementation in system mode is *really* hard to understand at
first. It took me a long time to grasp the various aspects of it, including these:
- loads/stores in kernel or userspace map to different translated code fragments
- loads/stores in different emulated CPUs also map to different translated code.
- the way i/o memory access is controlled in fine details and relates to the rest of the MMU.
most of what happens in exe.c is black-magic :-)
how the audio-subsystem works and its relationship with hardware emulation is subtle.
For my work on the Android emulator, I have modified three audio-backends and wrote
one from scratch. It took me several tries to get things to an acceptable state. What I
didn't understand first is that there is no common time-based used by all components
dyngen used to be pretty radical too. Thanks god it is gone for any target and host platform
combination I care about :-)
slirp is an hideous pile of goo which mixes network-ordered fields and host-ordered ones,
including pointers, into the same structures, liberally and at different times, depending on
context. Which is probably why it took so long to fix 64-bit issues in it. I would like to add
support for IPv6 to this code, but sadly, I have the feeling that rewriting most of it from
scratch would be slightly easier.
the CharDriverState interface takes some time to fully understand. In the Android emulator,
I sometimes need to connect two CharDriverState users together, and had to write a special
purpose object just to do that, but was surprised how hard writing a bug-less one was.
I also think that the event loop implementation is confusing compared to more common interfaces
provides by things like libevent. It is also extremely tied to select(), which prevents using better
mechanisms on various platforms, and even performs rather poorly on Windows, but I digress.
qemu_get_clock(vm_clock) will return time in nano-seconds, but qemu_get_clock(rt_clock)
will return time in milli-seconds. This is totally undocumented, and the code that uses the result
tend to use magic numbers like 1000000 or 1000 to perform conversions which are never clear
on first sight. Maybe this is fixed in upstream QEMU but, my, how this hurted me in the past.
For the record, here are attached a few documents I wrote to detail what I've "discovered"
until now. Hope some one can find them useful (Sorry if some of them are focused on ARM
system emulation only).