diff --git a/Changelog b/Changelog index 8468853b9..6a0c711cf 100644 --- a/Changelog +++ b/Changelog @@ -1,4 +1,4 @@ -version 0.4.4: +version 0.5.0: - full hardware level VGA emulation - graphical display with SDL @@ -16,8 +16,9 @@ version 0.4.4: - preliminary SPARC target support (Thomas M. Ogrisegg) - tun-fd option (Rusty Russell) - automatic IDE geometry detection - - renamed 'vl' to qemu and user qemu to qemu-{cpu}. + - renamed 'vl' to qemu[-fast] and user qemu to qemu-{cpu}. - added man page + - added full soft mmy mode to launch unpatched OSes. version 0.4.3: diff --git a/README b/README index c7038c21a..030306717 100644 --- a/README +++ b/README @@ -6,35 +6,17 @@ INSTALLATION Type - ./configure --interp-prefix=/usr/local/qemu-i386 + ./configure make -to build qemu and libqemu.a. +to build qemu, qemu-CPU and libqemu.a (CPU is the name of the various +supported target CPUs). Type make install -to install QEMU in /usr/local/bin - -* On x86 you should be able to launch any program by using the -libraries installed on your PC. For example: - - ./qemu -L / /bin/ls - -* On non x86 CPUs, you need first to download at least an x86 glibc -(qemu-XXX-i386-glibc21.tar.gz on the qemu web page). Ensure that -LD_LIBRARY_PATH is not set: - - unset LD_LIBRARY_PATH - -Then you can launch the precompiled 'ls' x86 executable: - - ./qemu /usr/local/qemu-i386/bin/ls-i386 - -You can look at /usr/local/qemu-i386/bin/qemu-conf.sh so that QEMU is -automatically launched by the Linux kernel when you try to launch x86 -executables. +to install QEMU in /usr/local Tested tool versions -------------------- diff --git a/README.distrib b/README.distrib index 35dff250b..a1598a299 100644 --- a/README.distrib +++ b/README.distrib @@ -6,11 +6,11 @@ x86 binary distribution: * wine-20020411 tarball - ./configure --prefix=/usr/local/qemu-i386/wine + ./configure --prefix=/usr/local/wine-i386 All exe and libs were stripped. Some compile time tools and the includes were deleted. * ldconfig was launched to build the library links: - ./qemu /usr/local/qemu-i386/bin/ldconfig-i386 -C /usr/local/qemu-i386/etc/ld.so.cache + qemu-i386 /usr/gnemul/qemu-i386/bin/ldconfig-i386 -C /usr/gnemul/qemu-i386/etc/ld.so.cache diff --git a/TODO b/TODO index 56229dfd7..fece491bc 100644 --- a/TODO +++ b/TODO @@ -1,17 +1,20 @@ +- tests for each target CPU +- ppc qemu test - optimize FPU operations (evaluate x87 stack pointer statically) and fix cr0.TS emulation +- fix some 16 bit sp push/pop overflow +- sysenter/sysexit emulation +- finish segment ops (call far, ret far, load_seg suppressed) - fix CCOP optimisation - fix all remaining thread lock issues (must put TBs in a specific invalid state, find a solution for tb_flush()). - cpu loop optimisation (optimise ret case as the cpu state does not change) - fix arm fpu rounding (at least for float->integer conversions) -- add IPC syscalls lower priority: -------------- -- sysenter/sysexit emulation +- add IPC syscalls - SMP support -- finish segment ops (call far, ret far, load_seg suppressed) - use -msoft-float on ARM - use kernel traps for unaligned accesses on ARM ? - handle rare page fault cases (in particular if page fault in heplers or diff --git a/VERSION b/VERSION index b300caa32..79a2734bb 100644 --- a/VERSION +++ b/VERSION @@ -1 +1 @@ -0.4.4 \ No newline at end of file +0.5.0 \ No newline at end of file diff --git a/qemu-doc.texi b/qemu-doc.texi index 0ff1454c1..8bb883afb 100644 --- a/qemu-doc.texi +++ b/qemu-doc.texi @@ -72,7 +72,7 @@ QEMU user mode emulation features: QEMU full system emulation features: @itemize -@item Using mmap() system calls to simulate the MMU +@item QEMU can either use a full software MMU for maximum portability or use the host system call mmap() to simulate the target MMU. @end itemize @section x86 emulation @@ -110,14 +110,7 @@ memory access. 10 byte @code{long double}s of x86 for floating point emulation to get maximum performances. -@item Full system emulation only works if no data are mapped above the virtual address -0xc0000000 (yet). - -@item Some priviledged instructions or behaviors are missing. Only the ones -needed for proper Linux kernel operation are emulated. - -@item No memory separation between the kernel and the user processes is done. -It will be implemented very soon. +@item Some priviledged instructions or behaviors are missing, especially for segment protection testing (yet). @end itemize @@ -177,9 +170,9 @@ unset LD_LIBRARY_PATH Then you can launch the precompiled @file{ls} x86 executable: @example -qemu-i386 /usr/local/qemu-i386/bin/ls-i386 +qemu-i386 tests/i386/ls @end example -You can look at @file{/usr/local/qemu-i386/bin/qemu-conf.sh} so that +You can look at @file{qemu-binfmt-conf.sh} so that QEMU is automatically launched by the Linux kernel when you try to launch x86 executables. It requires the @code{binfmt_misc} module in the Linux kernel. @@ -258,16 +251,15 @@ available: @enumerate @item -@code{qemu} uses the host Memory Management Unit (MMU) to simulate +@code{qemu-fast} uses the host Memory Management Unit (MMU) to simulate the x86 MMU. It is @emph{fast} but has limitations because the whole 4 GB address space cannot be used and some memory mapped peripherials cannot be emulated accurately yet. Therefore, a specific Linux kernel must be used (@xref{linux_compile}). @item -@code{qemu-softmmu} uses a software MMU. It is about @emph{two times -slower} but gives a more accurate emulation. (XXX: Linux cannot be ran -unpatched yet). +@code{qemu} uses a software MMU. It is about @emph{two times +slower} but gives a more accurate emulation. @end enumerate @@ -296,10 +288,10 @@ CMOS memory @section Quick Start -Download the linux image (@file{linux.img}) and type: +Download and uncompress the linux image (@file{linux.img}) and type: @example -qemu-softmmu linux.img +qemu linux.img @end example Linux should boot and give you a prompt. @@ -627,8 +619,10 @@ the real one. To know it, use the @code{ls -ls} command. @node linux_compile @section Linux Kernel Compilation -You should be able to use any kernel with QEMU provided you make the -following changes (only 2.4.x and 2.5.x were tested): +You can use any linux kernel with QEMU. However, if you want to use +@code{qemu-fast} to get maximum performances, you should make the +following changes to the Linux kernel (only 2.4.x and 2.5.x were +tested): @enumerate @item @@ -723,8 +717,6 @@ Then you can use gdb normally. For example, type 'c' to launch the kernel: (gdb) c @end example -WARNING: breakpoints and single stepping are not yet supported. - Here are some useful tips in order to use gdb on system code: @enumerate @@ -1019,16 +1011,6 @@ The new Plex86 project. In the directory @file{tests/}, various interesting testing programs are available. There are used for regression testing. -@section @file{hello-i386} - -Very simple statically linked x86 program, just to test QEMU during a -port to a new host CPU. - -@section @file{hello-arm} - -Very simple statically linked ARM program, just to test QEMU during a -port to a new host CPU. - @section @file{test-i386} This program executes most of the 16 bit and 32 bit x86 instructions and @@ -1044,6 +1026,22 @@ The Linux system call @code{vm86()} is used to test vm86 emulation. Various exceptions are raised to test most of the x86 user space exception reporting. +@section @file{linux-test} + +This program tests various Linux system calls. It is used to verify +that the system call parameters are correctly converted between target +and host CPUs. + +@section @file{hello-i386} + +Very simple statically linked x86 program, just to test QEMU during a +port to a new host CPU. + +@section @file{hello-arm} + +Very simple statically linked ARM program, just to test QEMU during a +port to a new host CPU. + @section @file{sha1} It is a simple benchmark. Care must be taken to interpret the results diff --git a/tests/linux-test.c b/tests/linux-test.c index 3ced0dd69..14cbe1385 100644 --- a/tests/linux-test.c +++ b/tests/linux-test.c @@ -71,7 +71,7 @@ int __chk_error(const char *filename, int line, int ret) #define FILE_BUF_SIZE 300 -void file_test(void) +void test_file(void) { int fd, i, len, ret; uint8_t buf[FILE_BUF_SIZE]; @@ -499,7 +499,7 @@ void test_signal(void) int main(int argc, char **argv) { - file_test(); + test_file(); test_fork(); test_time(); test_socket(); @@ -507,4 +507,3 @@ int main(int argc, char **argv) test_signal(); return 0; } - diff --git a/tests/testclone.c b/tests/testclone.c deleted file mode 100644 index 531bd5c61..000000000 --- a/tests/testclone.c +++ /dev/null @@ -1,62 +0,0 @@ -#include -#include -#include -#include -#include -#include -#include -#include -#include - -int thread1_func(void *arg) -{ - int i; - char buf[512]; - - for(i=0;i<10;i++) { - snprintf(buf, sizeof(buf), "thread1: %d %s\n", i, (char *)arg); - write(1, buf, strlen(buf)); - usleep(100 * 1000); - } - return 0; -} - -int thread2_func(void *arg) -{ - int i; - char buf[512]; - for(i=0;i<20;i++) { - snprintf(buf, sizeof(buf), "thread2: %d %s\n", i, (char *)arg); - write(1, buf, strlen(buf)); - usleep(120 * 1000); - } - return 0; -} - -#define STACK_SIZE 16384 - -void test_clone(void) -{ - uint8_t *stack1, *stack2; - int pid1, pid2, status1, status2; - - stack1 = malloc(STACK_SIZE); - pid1 = clone(thread1_func, stack1 + STACK_SIZE, - CLONE_VM | CLONE_FS | CLONE_FILES | SIGCHLD, "hello1"); - - stack2 = malloc(STACK_SIZE); - pid2 = clone(thread2_func, stack2 + STACK_SIZE, - CLONE_VM | CLONE_FS | CLONE_FILES | SIGCHLD, "hello2"); - - while (waitpid(pid1, &status1, 0) != pid1); - while (waitpid(pid2, &status2, 0) != pid2); - printf("status1=0x%x\n", status1); - printf("status2=0x%x\n", status2); - printf("End of clone test.\n"); -} - -int main(int argc, char **argv) -{ - test_clone(); - return 0; -} diff --git a/tests/testsig.c b/tests/testsig.c deleted file mode 100644 index 2eb2bfc4a..000000000 --- a/tests/testsig.c +++ /dev/null @@ -1,194 +0,0 @@ -#define _GNU_SOURCE -#include -#include -#include -#include -#include -#include -#include - -jmp_buf jmp_env; - -void alarm_handler(int sig) -{ - printf("alarm signal=%d\n", sig); - alarm(1); -} - -#ifndef REG_EAX -#define REG_EAX EAX -#define REG_EBX EBX -#define REG_ECX ECX -#define REG_EDX EDX -#define REG_ESI ESI -#define REG_EDI EDI -#define REG_EBP EBP -#define REG_ESP ESP -#define REG_EIP EIP -#define REG_EFL EFL -#define REG_TRAPNO TRAPNO -#define REG_ERR ERR -#endif - -void dump_regs(struct ucontext *uc) -{ - printf("EAX=%08x EBX=%08x ECX=%08x EDX=%08x\n" - "ESI=%08x EDI=%08x EBP=%08x ESP=%08x\n" - "EFL=%08x EIP=%08x trapno=%02x err=%08x\n", - uc->uc_mcontext.gregs[REG_EAX], - uc->uc_mcontext.gregs[REG_EBX], - uc->uc_mcontext.gregs[REG_ECX], - uc->uc_mcontext.gregs[REG_EDX], - uc->uc_mcontext.gregs[REG_ESI], - uc->uc_mcontext.gregs[REG_EDI], - uc->uc_mcontext.gregs[REG_EBP], - uc->uc_mcontext.gregs[REG_ESP], - uc->uc_mcontext.gregs[REG_EFL], - uc->uc_mcontext.gregs[REG_EIP], - uc->uc_mcontext.gregs[REG_TRAPNO], - uc->uc_mcontext.gregs[REG_ERR]); -} - -void sig_handler(int sig, siginfo_t *info, void *puc) -{ - struct ucontext *uc = puc; - - printf("%s: si_signo=%d si_errno=%d si_code=%d si_addr=0x%08lx\n", - strsignal(info->si_signo), - info->si_signo, info->si_errno, info->si_code, - (unsigned long)info->si_addr); - dump_regs(uc); - longjmp(jmp_env, 1); -} - -int v1; -int tab[2]; - -int main(int argc, char **argv) -{ - struct sigaction act; - volatile int val; - - act.sa_sigaction = sig_handler; - sigemptyset(&act.sa_mask); - act.sa_flags = SA_SIGINFO; - sigaction(SIGFPE, &act, NULL); - sigaction(SIGILL, &act, NULL); - sigaction(SIGSEGV, &act, NULL); - sigaction(SIGTRAP, &act, NULL); - - /* test division by zero reporting */ - if (setjmp(jmp_env) == 0) { - /* now divide by zero */ - v1 = 0; - v1 = 2 / v1; - } - - /* test illegal instruction reporting */ - if (setjmp(jmp_env) == 0) { - /* now execute an invalid instruction */ - asm volatile("ud2"); - } - - /* test SEGV reporting */ - if (setjmp(jmp_env) == 0) { - /* now store in an invalid address */ - *(char *)0x1234 = 1; - } - - /* test SEGV reporting */ - if (setjmp(jmp_env) == 0) { - /* read from an invalid address */ - v1 = *(char *)0x1234; - } - - printf("segment GPF exception:\n"); - if (setjmp(jmp_env) == 0) { - /* load an invalid segment */ - asm volatile ("movl %0, %%fs" : : "r" ((0x1234 << 3) | 0)); - } - - printf("INT exception:\n"); - if (setjmp(jmp_env) == 0) { - asm volatile ("int $0xfd"); - } - - printf("INT3 exception:\n"); - if (setjmp(jmp_env) == 0) { - asm volatile ("int3"); - } - - printf("CLI exception:\n"); - if (setjmp(jmp_env) == 0) { - asm volatile ("cli"); - } - - printf("STI exception:\n"); - if (setjmp(jmp_env) == 0) { - asm volatile ("cli"); - } - - printf("INTO exception:\n"); - if (setjmp(jmp_env) == 0) { - /* overflow exception */ - asm volatile ("addl $1, %0 ; into" : : "r" (0x7fffffff)); - } - - printf("BOUND exception:\n"); - if (setjmp(jmp_env) == 0) { - /* bound exception */ - tab[0] = 1; - tab[1] = 10; - asm volatile ("bound %0, %1" : : "r" (11), "m" (tab)); - } - - printf("OUTB exception:\n"); - if (setjmp(jmp_env) == 0) { - asm volatile ("outb %%al, %%dx" : : "d" (0x4321), "a" (0)); - } - - printf("INB exception:\n"); - if (setjmp(jmp_env) == 0) { - asm volatile ("inb %%dx, %%al" : "=a" (val) : "d" (0x4321)); - } - - printf("REP OUTSB exception:\n"); - if (setjmp(jmp_env) == 0) { - asm volatile ("rep outsb" : : "d" (0x4321), "S" (tab), "c" (1)); - } - - printf("REP INSB exception:\n"); - if (setjmp(jmp_env) == 0) { - asm volatile ("rep insb" : : "d" (0x4321), "D" (tab), "c" (1)); - } - - printf("HLT exception:\n"); - if (setjmp(jmp_env) == 0) { - asm volatile ("hlt"); - } - - printf("single step exception:\n"); - val = 0; - if (setjmp(jmp_env) == 0) { - asm volatile ("pushf\n" - "orl $0x00100, (%%esp)\n" - "popf\n" - "movl $0xabcd, %0\n" : "=m" (val) : : "cc", "memory"); - } - printf("val=0x%x\n", val); - -#if 1 - { - int i; - act.sa_handler = alarm_handler; - sigemptyset(&act.sa_mask); - act.sa_flags = 0; - sigaction(SIGALRM, &act, NULL); - alarm(1); - for(i = 0;i < 2; i++) { - sleep(1); - } - } -#endif - return 0; -}