📄 qemu-tech.texi
字号:
Since QEMU uses fixed simple instructions, no efficient registerallocation can be done. However, because RISC CPUs have a lot ofregister, most of the virtual CPU state can be put in registers withoutdoing complicated register allocation.@node Condition code optimisations@section Condition code optimisationsGood CPU condition codes emulation (@code{EFLAGS} register on x86) is acritical point to get good performances. QEMU uses lazy condition codeevaluation: instead of computing the condition codes after each x86instruction, it just stores one operand (called @code{CC_SRC}), theresult (called @code{CC_DST}) and the type of operation (called@code{CC_OP}).@code{CC_OP} is almost never explicitely set in the generated codebecause it is known at translation time.In order to increase performances, a backward pass is performed on thegenerated simple instructions (see@code{target-i386/translate.c:optimize_flags()}). When it can be proved thatthe condition codes are not needed by the next instructions, nocondition codes are computed at all.@node CPU state optimisations@section CPU state optimisationsThe x86 CPU has many internal states which change the way it evaluatesinstructions. In order to achieve a good speed, the translation phaseconsiders that some state information of the virtual x86 CPU cannotchange in it. For example, if the SS, DS and ES segments have a zerobase, then the translator does not even generate an addition for thesegment base.[The FPU stack pointer register is not handled that way yet].@node Translation cache@section Translation cacheA 16 MByte cache holds the most recently used translations. Forsimplicity, it is completely flushed when it is full. A translation unitcontains just a single basic block (a block of x86 instructionsterminated by a jump or by a virtual CPU state change which thetranslator cannot deduce statically).@node Direct block chaining@section Direct block chainingAfter each translated basic block is executed, QEMU uses the simulatedProgram Counter (PC) and other cpu state informations (such as the CSsegment base value) to find the next basic block.In order to accelerate the most common cases where the new simulated PCis known, QEMU can patch a basic block so that it jumps directly to thenext one.The most portable code uses an indirect jump. An indirect jump makesit easier to make the jump target modification atomic. On some hostarchitectures (such as x86 or PowerPC), the @code{JUMP} opcode isdirectly patched so that the block chaining has no overhead.@node Self-modifying code and translated code invalidation@section Self-modifying code and translated code invalidationSelf-modifying code is a special challenge in x86 emulation because noinstruction cache invalidation is signaled by the application when codeis modified.When translated code is generated for a basic block, the correspondinghost page is write protected if it is not already read-only (with thesystem call @code{mprotect()}). Then, if a write access is done to thepage, Linux raises a SEGV signal. QEMU then invalidates all thetranslated code in the page and enables write accesses to the page.Correct translated code invalidation is done efficiently by maintaininga linked list of every translated block contained in a given page. Otherlinked lists are also maintained to undo direct block chaining. Although the overhead of doing @code{mprotect()} calls is important,most MSDOS programs can be emulated at reasonnable speed with QEMU andDOSEMU.Note that QEMU also invalidates pages of translated code when it detectsthat memory mappings are modified with @code{mmap()} or @code{munmap()}.When using a software MMU, the code invalidation is more efficient: ifa given code page is invalidated too often because of write accesses,then a bitmap representing all the code inside the page isbuilt. Every store into that page checks the bitmap to see if the codereally needs to be invalidated. It avoids invalidating the code whenonly data is modified in the page.@node Exception support@section Exception supportlongjmp() is used when an exception such as division by zero isencountered. The host SIGSEGV and SIGBUS signal handlers are used to get invalidmemory accesses. The exact CPU state can be retrieved because all thex86 registers are stored in fixed host registers. The simulated programcounter is found by retranslating the corresponding basic block and bylooking where the host program counter was at the exception point.The virtual CPU cannot retrieve the exact @code{EFLAGS} register becausein some cases it is not computed because of condition codeoptimisations. It is not a big concern because the emulated code canstill be restarted in any cases.@node MMU emulation@section MMU emulationFor system emulation, QEMU uses the mmap() system call to emulate thetarget CPU MMU. It works as long the emulated OS does not use an areareserved by the host OS (such as the area above 0xc0000000 on x86Linux).In order to be able to launch any OS, QEMU also supports a softMMU. In that mode, the MMU virtual to physical address translation isdone at every memory access. QEMU uses an address translation cache tospeed up the translation.In order to avoid flushing the translated code each time the MMUmappings change, QEMU uses a physically indexed translation cache. Itmeans that each basic block is indexed with its physical address. When MMU mappings change, only the chaining of the basic blocks isreset (i.e. a basic block can no longer jump directly to another one).@node Hardware interrupts@section Hardware interruptsIn order to be faster, QEMU does not check at every basic block if anhardware interrupt is pending. Instead, the user must asynchrouslycall a specific function to tell that an interrupt is pending. Thisfunction resets the chaining of the currently executing basicblock. It ensures that the execution will return soon in the main loopof the CPU emulator. Then the main loop can test if the interrupt ispending and handle it.@node User emulation specific details@section User emulation specific details@subsection Linux system call translationQEMU includes a generic system call translator for Linux. It means thatthe parameters of the system calls can be converted to fix theendianness and 32/64 bit issues. The IOCTLs are converted with a generictype description system (see @file{ioctls.h} and @file{thunk.c}).QEMU supports host CPUs which have pages bigger than 4KB. It records allthe mappings the process does and try to emulated the @code{mmap()}system calls in cases where the host @code{mmap()} call would failbecause of bad page alignment.@subsection Linux signalsNormal and real-time signals are queued along with their information(@code{siginfo_t}) as it is done in the Linux kernel. Then an interruptrequest is done to the virtual CPU. When it is interrupted, one queuedsignal is handled by generating a stack frame in the virtual CPU as theLinux kernel does. The @code{sigreturn()} system call is emulated to returnfrom the virtual signal handler.Some signals (such as SIGALRM) directly come from the host. Othersignals are synthetized from the virtual CPU exceptions such as SIGFPEwhen a division by zero is done (see @code{main.c:cpu_loop()}).The blocked signal mask is still handled by the host Linux kernel sothat most signal system calls can be redirected directly to the hostLinux kernel. Only the @code{sigaction()} and @code{sigreturn()} systemcalls need to be fully emulated (see @file{signal.c}).@subsection clone() system call and threadsThe Linux clone() system call is usually used to create a thread. QEMUuses the host clone() system call so that real host threads are createdfor each emulated thread. One virtual CPU instance is created for eachthread.The virtual x86 CPU atomic operations are emulated with a global lock sothat their semantic is preserved.Note that currently there are still some locking issues in QEMU. Inparticular, the translated cache flush is not protected yet againstreentrancy.@subsection Self-virtualizationQEMU was conceived so that ultimately it can emulate itself. Althoughit is not very useful, it is an important test to show the power of theemulator.Achieving self-virtualization is not easy because there may be addressspace conflicts. QEMU solves this problem by being an executable ELFshared object as the ld-linux.so ELF interpreter. That way, it can berelocated at load time.@node Bibliography@section Bibliography@table @asis@item [1] @url{http://citeseer.nj.nec.com/piumarta98optimizing.html}, Optimizingdirect threaded code by selective inlining (1998) by Ian Piumarta, FabioRiccardi.@item [2]@url{http://developer.kde.org/~sewardj/}, Valgrind, an open-sourcememory debugger for x86-GNU/Linux, by Julian Seward.@item [3]@url{http://bochs.sourceforge.net/}, the Bochs IA-32 Emulator Project,by Kevin Lawton et al.@item [4]@url{http://www.cs.rose-hulman.edu/~donaldlf/em86/index.html}, the EM86x86 emulator on Alpha-Linux.@item [5]@url{http://www.usenix.org/publications/library/proceedings/usenix-nt97/@/full_papers/chernoff/chernoff.pdf},DIGITAL FX!32: Running 32-Bit x86 Applications on Alpha NT, by AntonChernoff and Ray Hookway.@item [6]@url{http://www.willows.com/}, Windows API library emulation fromWillows Software.@item [7]@url{http://user-mode-linux.sourceforge.net/}, The User-mode Linux Kernel.@item [8]@url{http://www.plex86.org/}, The new Plex86 project.@item [9]@url{http://www.vmware.com/}, The VMWare PC virtualizer.@item [10]@url{http://www.microsoft.com/windowsxp/virtualpc/}, The VirtualPC PC virtualizer.@item [11]@url{http://www.twoostwo.org/}, The TwoOStwo PC virtualizer.@end table@node Regression Tests@chapter Regression TestsIn the directory @file{tests/}, various interesting testing programsare available. There are used for regression testing.@menu* test-i386::* linux-test::* qruncom.c::@end menu@node test-i386@section @file{test-i386}This program executes most of the 16 bit and 32 bit x86 instructions andgenerates a text output. It can be compared with the output obtained witha real CPU or another emulator. The target @code{make test} runs thisprogram and a @code{diff} on the generated output.The Linux system call @code{modify_ldt()} is used to create x86 selectorsto test some 16 bit addressing and 32 bit with segmentation cases.The Linux system call @code{vm86()} is used to test vm86 emulation.Various exceptions are raised to test most of the x86 user spaceexception reporting.@node linux-test@section @file{linux-test}This program tests various Linux system calls. It is used to verifythat the system call parameters are correctly converted between targetand host CPUs.@node qruncom.c@section @file{qruncom.c}Example of usage of @code{libqemu} to emulate a user mode i386 CPU.@node Index@chapter Index@printindex cp@bye
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -