Compare commits

..
84 Commits
Author SHA1 Message Date
bellard 9d0fe224f4 update
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@330 c046a42c-6fe2-441c-8c8c-71466251a162
2003-07-13 22:08:50 +00:00
bellard 6e0374f6b5 debug print
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@329 c046a42c-6fe2-441c-8c8c-71466251a162
2003-07-13 17:34:37 +00:00
bellard 9e5f5284b3 convert signal numbers
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@328 c046a42c-6fe2-441c-8c8c-71466251a162
2003-07-13 17:33:54 +00:00
bellard c596ed1713 times() fix
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@327 c046a42c-6fe2-441c-8c8c-71466251a162
2003-07-13 17:32:31 +00:00
bellard 91cf4d88fb gcc 3.2.2 bug workaround (RedHat 9 fix)
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@326 c046a42c-6fe2-441c-8c8c-71466251a162
2003-07-13 17:31:01 +00:00
bellard a96fc003bd sparc fix
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@325 c046a42c-6fe2-441c-8c8c-71466251a162
2003-07-13 17:30:15 +00:00
bellard d44b29c21e address printing fix
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@324 c046a42c-6fe2-441c-8c8c-71466251a162
2003-07-13 17:29:55 +00:00
bellard 070893f425 RedHat 9 fix
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@323 c046a42c-6fe2-441c-8c8c-71466251a162
2003-07-13 17:27:19 +00:00
bellard 9621339dca changed basic block exit generation
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@322 c046a42c-6fe2-441c-8c8c-71466251a162
2003-07-11 15:17:41 +00:00
bellard ede28208d8 added nop test for exception
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@321 c046a42c-6fe2-441c-8c8c-71466251a162
2003-07-11 14:49:58 +00:00
bellard 7739f36e38 fixed EIP exception bug in case of nop operations (kernel 2.5.74 copy_from_user() bug)
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@320 c046a42c-6fe2-441c-8c8c-71466251a162
2003-07-11 14:49:22 +00:00
bellard f8c8799840 added return for ARM case (may be incorrect - need checking)
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@319 c046a42c-6fe2-441c-8c8c-71466251a162
2003-07-09 19:41:41 +00:00
bellard 43fff2384e ARM signal support
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@318 c046a42c-6fe2-441c-8c8c-71466251a162
2003-07-09 19:31:39 +00:00
bellard 1b21b62ab4 ARM fixes
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@317 c046a42c-6fe2-441c-8c8c-71466251a162
2003-07-09 17:16:27 +00:00
bellard a1516e92b6 ARM init fix
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@316 c046a42c-6fe2-441c-8c8c-71466251a162
2003-07-09 17:13:37 +00:00
bellard 6fb883e8e3 ARM fix: mmap
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@315 c046a42c-6fe2-441c-8c8c-71466251a162
2003-07-09 17:12:39 +00:00
bellard 6e295807ac ARM fixes
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@314 c046a42c-6fe2-441c-8c8c-71466251a162
2003-07-09 17:10:32 +00:00
bellard f2674e31e0 old select support
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@313 c046a42c-6fe2-441c-8c8c-71466251a162
2003-07-09 12:26:09 +00:00
bellard 4690764bba update
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@312 c046a42c-6fe2-441c-8c8c-71466251a162
2003-07-07 12:17:46 +00:00
bellard 3c1cf9fa86 dummy rdmsr and wrmsr support - xor reg, reg optimization
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@311 c046a42c-6fe2-441c-8c8c-71466251a162
2003-07-07 11:30:47 +00:00
bellard 1f47a9223e added disk image help
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@310 c046a42c-6fe2-441c-8c8c-71466251a162
2003-07-06 19:01:55 +00:00
bellard 33e3963e1b added user mode Linux Copy On Write disk image support - added -snapshot support (initial patch by Rusty Russell)
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@309 c046a42c-6fe2-441c-8c8c-71466251a162
2003-07-06 17:15:21 +00:00
bellard cd4c3e888a added IDE WIN_READ_NATIVE_MAX command (2.5.xx fix) - added support for proper system shutdown
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@308 c046a42c-6fe2-441c-8c8c-71466251a162
2003-07-04 14:38:25 +00:00
bellard 7916e2245d allow up to 256 MB of ram
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@307 c046a42c-6fe2-441c-8c8c-71466251a162
2003-07-01 16:27:45 +00:00
bellard abd0aaff03 fixed date storage in CMOS
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@306 c046a42c-6fe2-441c-8c8c-71466251a162
2003-07-01 15:07:57 +00:00
bellard c39d5b78f6 make FPU load exception safe
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@305 c046a42c-6fe2-441c-8c8c-71466251a162
2003-07-01 15:07:14 +00:00
bellard 4d40895f2c more accurate bcd convert - fixed FPU exceptions
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@304 c046a42c-6fe2-441c-8c8c-71466251a162
2003-07-01 15:05:19 +00:00
bellard e477b8b81b correct eflags evaluation order for all operations - fixed important CPU state restoring bug in some exception cases - disabled unsafe inc flags optimisation
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@303 c046a42c-6fe2-441c-8c8c-71466251a162
2003-06-30 23:36:57 +00:00
bellard b118d61e55 added PIC debug
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@302 c046a42c-6fe2-441c-8c8c-71466251a162
2003-06-30 23:36:21 +00:00
bellard 2f62b397b5 dummy label to avoid gcc optimisations
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@301 c046a42c-6fe2-441c-8c8c-71466251a162
2003-06-30 23:18:59 +00:00
bellard 907a5b2690 fixed invalid irq jump chaining
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@300 c046a42c-6fe2-441c-8c8c-71466251a162
2003-06-30 23:18:22 +00:00
bellard 0849bf0821 allow read only images
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@299 c046a42c-6fe2-441c-8c8c-71466251a162
2003-06-30 23:17:31 +00:00
bellard 305034817d removed unused assignment
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@298 c046a42c-6fe2-441c-8c8c-71466251a162
2003-06-30 23:17:08 +00:00
bellard ec410fc9ce update
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@297 c046a42c-6fe2-441c-8c8c-71466251a162
2003-06-30 23:16:33 +00:00
bellard 68a7931591 reduced irq latency
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@296 c046a42c-6fe2-441c-8c8c-71466251a162
2003-06-30 13:12:32 +00:00
bellard c9159e5321 added IDE mult support - reduced irq latency (IDE should have good performances now)
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@295 c046a42c-6fe2-441c-8c8c-71466251a162
2003-06-30 13:06:39 +00:00
bellard 8c9b861e74 added block.c
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@294 c046a42c-6fe2-441c-8c8c-71466251a162
2003-06-30 10:12:19 +00:00
bellard 5797fa5d7e first step to fix precise eflags update in case of exception
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@293 c046a42c-6fe2-441c-8c8c-71466251a162
2003-06-30 10:11:50 +00:00
bellard 8ef9a8ece3 added nop operations
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@292 c046a42c-6fe2-441c-8c8c-71466251a162
2003-06-30 10:04:47 +00:00
bellard fc01f7e7f9 IDE emulation
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@291 c046a42c-6fe2-441c-8c8c-71466251a162
2003-06-30 10:03:06 +00:00
bellard 3b0dca51b0 gdb stub defines
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@290 c046a42c-6fe2-441c-8c8c-71466251a162
2003-06-27 18:52:23 +00:00
bellard da415d54bf gdb usage information
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@289 c046a42c-6fe2-441c-8c8c-71466251a162
2003-06-27 18:50:50 +00:00
bellard b4608c0455 added gdb support to vl
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@288 c046a42c-6fe2-441c-8c8c-71466251a162
2003-06-27 17:34:32 +00:00
bellard d5a0b50c6f update
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@287 c046a42c-6fe2-441c-8c8c-71466251a162
2003-06-27 12:02:03 +00:00
bellard 87858c89ca more precise timer emulation - fixed NE2000 probe problems - added VLTMPDIR support
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@286 c046a42c-6fe2-441c-8c8c-71466251a162
2003-06-27 12:01:39 +00:00
bellard a6f816d697 fixed endianness (Jocelyn Mayer)
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@285 c046a42c-6fe2-441c-8c8c-71466251a162
2003-06-26 17:09:07 +00:00
bellard 0ad041d476 fixed inline pb
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@284 c046a42c-6fe2-441c-8c8c-71466251a162
2003-06-25 22:11:41 +00:00
bellard 1eb20527c8 update
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@283 c046a42c-6fe2-441c-8c8c-71466251a162
2003-06-25 16:21:49 +00:00
bellard e3e86d56c4 gcc3 compile fixes
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@282 c046a42c-6fe2-441c-8c8c-71466251a162
2003-06-25 16:21:11 +00:00
bellard 1df912cf9e VL license of the day is MIT/BSD
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@281 c046a42c-6fe2-441c-8c8c-71466251a162
2003-06-25 16:20:35 +00:00
bellard 4351832355 added invlpg emulation
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@280 c046a42c-6fe2-441c-8c8c-71466251a162
2003-06-25 16:19:50 +00:00
bellard 59faf6d6a6 compile fixes
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@279 c046a42c-6fe2-441c-8c8c-71466251a162
2003-06-25 16:18:50 +00:00
bellard 725af7d460 untested RH9 fixes
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@278 c046a42c-6fe2-441c-8c8c-71466251a162
2003-06-25 16:18:32 +00:00
bellard a363e34cc5 fixed VM86 support in Virtual Linux - fixed compilation issues with gcc 2.96 - cpuid returns now pentium pro in order to avoid F00F bug workaround in Linux kernel
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@277 c046a42c-6fe2-441c-8c8c-71466251a162
2003-06-25 16:18:05 +00:00
bellard ea041c0e33 more precise cpu_interrupt()
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@276 c046a42c-6fe2-441c-8c8c-71466251a162
2003-06-25 16:16:50 +00:00
bellard 83479e770d suppressed ring 0 hacks
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@275 c046a42c-6fe2-441c-8c8c-71466251a162
2003-06-25 16:12:37 +00:00
bellard e2f2289897 arm fixes
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@274 c046a42c-6fe2-441c-8c8c-71466251a162
2003-06-25 16:09:48 +00:00
bellard 844c72eccc more compiler tests
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@273 c046a42c-6fe2-441c-8c8c-71466251a162
2003-06-25 16:09:14 +00:00
bellard 6b1534cc67 fixed compilation for gcc 2.96 - added QEMU system emulator
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@272 c046a42c-6fe2-441c-8c8c-71466251a162
2003-06-25 16:08:39 +00:00
bellard e8cd23de30 fixed compilation for gcc 2.96
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@271 c046a42c-6fe2-441c-8c8c-71466251a162
2003-06-25 16:08:13 +00:00
bellard 7c2d6a781c faster task switch
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@270 c046a42c-6fe2-441c-8c8c-71466251a162
2003-06-25 00:08:13 +00:00
bellard f1510b2cc3 added NE2000 emulation
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@269 c046a42c-6fe2-441c-8c8c-71466251a162
2003-06-25 00:07:40 +00:00
bellard 357a94326c added link script for vl
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@268 c046a42c-6fe2-441c-8c8c-71466251a162
2003-06-24 14:39:12 +00:00
bellard 0824d6fc67 for hard core developpers only: a new user mode linux project :-)
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@267 c046a42c-6fe2-441c-8c8c-71466251a162
2003-06-24 13:42:40 +00:00
bellard 6c0372d30b updated
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@266 c046a42c-6fe2-441c-8c8c-71466251a162
2003-06-24 13:40:52 +00:00
bellard 92ccca6aa8 declare user mode only simulation for QEMU
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@265 c046a42c-6fe2-441c-8c8c-71466251a162
2003-06-24 13:30:31 +00:00
bellard dd3587f38e iret and popl (%esp) tests
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@264 c046a42c-6fe2-441c-8c8c-71466251a162
2003-06-24 13:29:40 +00:00
bellard 7d83131cc5 use inline function
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@263 c046a42c-6fe2-441c-8c8c-71466251a162
2003-06-24 13:28:48 +00:00
bellard 66e85a21c7 MMU support
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@262 c046a42c-6fe2-441c-8c8c-71466251a162
2003-06-24 13:28:12 +00:00
bellard 90a9fdae1f more ring 0 operations
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@261 c046a42c-6fe2-441c-8c8c-71466251a162
2003-06-24 13:27:18 +00:00
bellard 3fb2ded1d5 hardware interrupt support - support forfull ring 0 exception simulation
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@260 c046a42c-6fe2-441c-8c8c-71466251a162
2003-06-24 13:22:59 +00:00
bellard f76af4b3f3 correct restoring of CC_OP in case of exception
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@259 c046a42c-6fe2-441c-8c8c-71466251a162
2003-06-24 13:21:23 +00:00
bellard 717fc2ad8d more ring 0 instructions - full x86 MMU emulation based on mmap() syscall - fixed popl (%esp)
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@258 c046a42c-6fe2-441c-8c8c-71466251a162
2003-06-24 13:20:53 +00:00
bellard c05bab779e force IOPL=3
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@257 c046a42c-6fe2-441c-8c8c-71466251a162
2003-06-21 13:14:43 +00:00
bellard a52c757c9f fixed case where SS != USER_DS (fixes dosemu DPMI emulation)
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@256 c046a42c-6fe2-441c-8c8c-71466251a162
2003-06-21 13:14:12 +00:00
bellard 970a87a6bb new segment access
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@255 c046a42c-6fe2-441c-8c8c-71466251a162
2003-06-21 13:13:25 +00:00
bellard d8bc1fd0ae ring 0 ops
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@254 c046a42c-6fe2-441c-8c8c-71466251a162
2003-06-21 13:13:13 +00:00
bellard 7501267e22 cpu_abort()
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@253 c046a42c-6fe2-441c-8c8c-71466251a162
2003-06-21 13:11:07 +00:00
bellard 13b55754af ring 0 data structures
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@252 c046a42c-6fe2-441c-8c8c-71466251a162
2003-06-21 13:09:53 +00:00
bellard 972ddf7840 added cpu_abort()
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@251 c046a42c-6fe2-441c-8c8c-71466251a162
2003-06-21 13:08:39 +00:00
bellard 322d0c6657 update
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@250 c046a42c-6fe2-441c-8c8c-71466251a162
2003-06-15 23:29:28 +00:00
bellard 2054396a04 fixed include macro pb
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@249 c046a42c-6fe2-441c-8c8c-71466251a162
2003-06-15 23:28:43 +00:00
bellard 039de852ec fixed op_label computation on ppc
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@248 c046a42c-6fe2-441c-8c8c-71466251a162
2003-06-15 22:50:44 +00:00
bellard 144c345daf consistent hello naming
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@247 c046a42c-6fe2-441c-8c8c-71466251a162
2003-06-15 20:42:31 +00:00
50 changed files with 8219 additions and 1208 deletions

No files matched your search

+36 -5
View File
@@ -1,19 +1,50 @@
version 0.4.3:
- x86 exception fix in case of nop instruction.
- gcc 3.2.2 bug workaround (RedHat 9 fix)
- sparc and Alpha host fixes
- many ARM target fixes: 'ls' and 'bash' can be launched.
version 0.4.2:
- many exception handling fixes (can compile a Linux kernel inside vl)
- IDE emulation support
- initial GDB stub support
- deferred update support for disk images (Rusty Russell)
- accept User Mode Linux Copy On Write disk images
- SMP kernels can at least be booted
version 0.4.1:
- more accurate timer support in vl.
- more reliable NE2000 probe in vl.
- added 2.5.66 kernel in vl-test.
- added VLTMPDIR environment variable in vl.
version 0.4:
- initial support for ring 0 x86 processor emulation
- fixed signal handling for correct dosemu DPMI emulation
- fast x86 MMU emulation with mmap()
- fixed popl (%esp) case
- Linux kernel can be executed by QEMU with the 'vl' command.
version 0.3:
- initial support for ARM emulation
- added fnsave, frstor, fnstenv, fldenv FPU instructions
- added FPU register save in signal emulation
- ARM port
- initial ARM port
- Sparc and Alpha ports work on the regression test
- generic ioctl number conversion
- fixed ioctl type conversion
version 0.2:
- PowerPC disassembly and ELF symbols output (Rusty Russel)
- flock support (Rusty Russel)
- ugetrlimit support (Rusty Russel)
- fstat64 fix (Rusty Russel)
- PowerPC disassembly and ELF symbols output (Rusty Russell)
- flock support (Rusty Russell)
- ugetrlimit support (Rusty Russell)
- fstat64 fix (Rusty Russell)
- initial Alpha port (Falk Hueffner)
- initial IA64 port (Matt Wilson)
- initial Sparc and Sparc64 port (David S. Miller)
+26 -12
View File
@@ -5,6 +5,7 @@ LDFLAGS=-g
LIBS=
DEFINES=-DHAVE_BYTESWAP_H
HELPER_CFLAGS=$(CFLAGS)
PROGS=qemu
ifdef CONFIG_STATIC
LDFLAGS+=-static
@@ -13,7 +14,7 @@ endif
ifeq ($(ARCH),i386)
CFLAGS+=-fomit-frame-pointer
OP_CFLAGS=$(CFLAGS) -mpreferred-stack-boundary=2
ifeq ($(GCC_MAJOR),3)
ifeq ($(HAVE_GCC3_OPTIONS),yes)
OP_CFLAGS+= -falign-functions=0
else
OP_CFLAGS+= -malign-functions=0
@@ -26,6 +27,9 @@ else
# is the simplest way to make it self virtualizable!
LDFLAGS+=-Wl,-shared
endif
ifeq ($(TARGET_ARCH), i386)
PROGS+=vl vlmkcow
endif
endif
ifeq ($(ARCH),ppc)
@@ -43,7 +47,8 @@ CFLAGS+=-m32 -ffixed-g1 -ffixed-g2 -ffixed-g3 -ffixed-g6
LDFLAGS+=-m32
OP_CFLAGS=$(CFLAGS) -fno-delayed-branch -ffixed-i0
HELPER_CFLAGS=$(CFLAGS) -ffixed-i0 -mflat
LDFLAGS+=-Wl,-T,sparc.ld
# -static is used to avoid g1/g3 usage by the dynamic linker
LDFLAGS+=-Wl,-T,sparc.ld -static
endif
ifeq ($(ARCH),sparc64)
@@ -70,7 +75,7 @@ OP_CFLAGS=$(CFLAGS) -mno-sched-prolog
LDFLAGS+=-Wl,-T,arm.ld
endif
ifeq ($(GCC_MAJOR),3)
ifeq ($(HAVE_GCC3_OPTIONS),yes)
# very important to generate a return at the end of every operation
OP_CFLAGS+=-fno-reorder-blocks -fno-optimize-sibling-calls
endif
@@ -94,7 +99,7 @@ SRCS:= $(OBJS:.o=.c)
OBJS+= libqemu.a
# cpu emulator library
LIBOBJS=thunk.o exec.o translate.o cpu-exec.o
LIBOBJS=thunk.o exec.o translate.o cpu-exec.o gdbstub.o
ifeq ($(TARGET_ARCH), i386)
LIBOBJS+=translate-i386.o op-i386.o helper-i386.o
@@ -125,7 +130,7 @@ ifeq ($(ARCH),ia64)
OBJS += ia64-syscall.o
endif
all: qemu qemu-doc.html
all: $(PROGS) qemu-doc.html
qemu: $(OBJS)
$(CC) $(LDFLAGS) -o $@ $^ $(LIBS)
@@ -135,6 +140,13 @@ ifeq ($(ARCH),alpha)
echo -ne '\001\000\000\000' | dd of=qemu bs=1 seek=48 count=4 conv=notrunc
endif
# must use static linking to avoid leaving stuff in virtual address space
vl: vl.o block.o libqemu.a
$(CC) -static -Wl,-T,i386-vl.ld -o $@ $^ $(LIBS)
vlmkcow: vlmkcow.o
$(CC) -o $@ $^ $(LIBS)
depend: $(SRCS)
$(CC) -MM $(CFLAGS) $^ 1>.depend
@@ -166,7 +178,7 @@ op-$(TARGET_ARCH).o: op-$(TARGET_ARCH).c
helper-$(TARGET_ARCH).o: helper-$(TARGET_ARCH).c
$(CC) $(HELPER_CFLAGS) $(DEFINES) -c -o $@ $<
op-i386.o: op-i386.c opreg_template.h ops_template.h
op-i386.o: op-i386.c opreg_template.h ops_template.h ops_template_mem.h
op-arm.o: op-arm.c op-arm-template.h
@@ -180,8 +192,9 @@ clean:
distclean: clean
rm -f config.mak config.h
install: qemu
install -m 755 -s qemu $(prefix)/bin
install: $(PROGS)
mkdir -p $(prefix)/bin
install -m 755 -s $(PROGS) $(prefix)/bin
# various test targets
test speed: qemu
@@ -200,18 +213,19 @@ configure \
dyngen.c dyngen.h dyngen-exec.h ioctls.h syscall_types.h \
Makefile elf.h elfload.c main.c signal.c qemu.h \
syscall.c syscall_defs.h vm86.c path.c mmap.c \
ppc.ld alpha.ld s390.ld sparc.ld arm.ld\
i386.ld ppc.ld alpha.ld s390.ld sparc.ld arm.ld\
vl.c i386-vl.ld vl.h block.c vlmkcow.c\
thunk.c cpu-exec.c translate.c cpu-all.h thunk.h exec.h\
exec.c cpu-exec.c\
exec.c cpu-exec.c gdbstub.c\
cpu-i386.h op-i386.c helper-i386.c syscall-i386.h translate-i386.c \
exec-i386.h ops_template.h op_string.h opreg_template.h \
exec-i386.h ops_template.h ops_template_mem.h op_string.h opreg_template.h \
cpu-arm.h syscall-arm.h exec-arm.h op-arm.c translate-arm.c op-arm-template.h \
dis-asm.h disas.c disas.h alpha-dis.c ppc-dis.c i386-dis.c sparc-dis.c \
arm-dis.c \
tests/Makefile \
tests/test-i386.c tests/test-i386-shift.h tests/test-i386.h \
tests/test-i386-muldiv.h tests/test-i386-code16.S tests/test-i386-vm86.S \
tests/hello.c tests/hello \
tests/hello-i386.c tests/hello-i386 \
tests/hello-arm.c tests/hello-arm \
tests/sha1.c \
tests/testsig.c tests/testclone.c tests/testthread.c \
+11 -7
View File
@@ -45,22 +45,26 @@ that QEMU works if you do not use a tested gcc version. Look at
'configure' and 'Makefile' if you want to make a different gcc
version work.
host gcc binutils glibc linux
-------------------------------------------------------
x86 2.95.2 2.13.2 2.1.3 2.4.18
host gcc binutils glibc linux distribution
----------------------------------------------------------------------
x86 2.95.2 2.13.2 2.1.3 2.4.18
3.2 2.13.2 2.1.3 2.4.18
2.96 2.11.93.0.2 2.2.5 2.4.18 Red Hat 7.3
3.2.2 2.13.90.0.18 2.3.2 2.4.20 Red Hat 9
PowerPC 2.95.4 2.12.90.0.1 2.2.5 2.4.20-pre2
PowerPC 2.95.4 2.12.90.0.1 2.2.5 2.4.20-pre2 Debian 3.0
Alpha 3.3 [1] 2.14.90.0.4 2.2.5 2.2.20 [2]
Alpha 3.3 [1] 2.14.90.0.4 2.2.5 2.2.20 [2] Debian 3.0
Sparc32 2.95.4 2.12.90.0.1 2.2.5 2.4.18
Sparc32 2.95.4 2.12.90.0.1 2.2.5 2.4.18 Debian 3.0
ARM 2.95.4 2.12.90.0.1 2.2.5 2.4.9-ac10-rmk2-np1-cerf2
ARM 2.95.4 2.12.90.0.1 2.2.5 2.4.9 [3] Debian 3.0
[1] On Alpha, QEMU needs the gcc 'visibility' attribute only available
for gcc version >= 3.3.
[2] Linux >= 2.4.20 is necessary for precise exception support
(untested).
[3] 2.4.9-ac10-rmk2-np1-cerf2
Documentation
-------------
+7 -6
View File
@@ -1,16 +1,17 @@
- fix arm fpu rounding (at least for float->integer conversions)
- optimize FPU operations (evaluate x87 stack pointer statically) and
fix cr0.TS emulation
- fix CCOP optimisation
- optimize FPU operations (evaluate x87 stack pointer statically)
- fpush not before mem load restarting
- fix all remaining thread lock issues (must put TBs in a specific invalid
state, find a solution for tb_flush()).
- add gcc 2.96 test configure (some gcc3 flags are needed)
- 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
- submit a patch to fix DOSEMU coopthreads
lower priority:
--------------
- sysenter/sysexit emulation
- 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
+1 -1
View File
@@ -1 +1 @@
0.3
0.4.3
+2 -2
View File
@@ -560,8 +560,8 @@ static arm_regname regnames[] =
{ "a1", "a2", "a3", "a4", "v1", "v2", "v3", "WR", "v5", "SB", "SL", "FP", "IP", "SP", "LR", "PC" }}
};
/* Default to GCC register name set. */
static unsigned int regname_selected = 1;
/* Default to STD register name set. */
static unsigned int regname_selected = 2;
#define NUM_ARM_REGNAMES NUM_ELEM (regnames)
#define arm_regnames regnames[regname_selected].reg_names
+326
View File
@@ -0,0 +1,326 @@
/*
* QEMU System Emulator block driver
*
* Copyright (c) 2003 Fabrice Bellard
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
#include <stdlib.h>
#include <stdio.h>
#include <stdarg.h>
#include <string.h>
#include <getopt.h>
#include <inttypes.h>
#include <unistd.h>
#include <sys/mman.h>
#include <fcntl.h>
#include <signal.h>
#include <time.h>
#include <sys/time.h>
#include <malloc.h>
#include <termios.h>
#include <sys/poll.h>
#include <errno.h>
#include <sys/wait.h>
#include <netinet/in.h>
#include "vl.h"
#define NO_THUNK_TYPE_SIZE
#include "thunk.h"
struct BlockDriverState {
int fd; /* if -1, only COW mappings */
int64_t total_sectors;
int read_only;
uint8_t *cow_bitmap; /* if non NULL, COW mappings are used first */
uint8_t *cow_bitmap_addr; /* mmap address of cow_bitmap */
int cow_bitmap_size;
int cow_fd;
int64_t cow_sectors_offset;
char filename[1024];
};
BlockDriverState *bdrv_open(const char *filename, int snapshot)
{
BlockDriverState *bs;
int fd, cow_fd;
int64_t size;
char template[] = "/tmp/vl.XXXXXX";
struct cow_header_v2 cow_header;
struct stat st;
bs = malloc(sizeof(BlockDriverState));
if(!bs)
return NULL;
bs->read_only = 0;
bs->fd = -1;
bs->cow_fd = -1;
bs->cow_bitmap = NULL;
strcpy(bs->filename, filename);
/* open standard HD image */
fd = open(filename, O_RDWR | O_LARGEFILE);
if (fd < 0) {
/* read only image on disk */
fd = open(filename, O_RDONLY | O_LARGEFILE);
if (fd < 0) {
perror(filename);
goto fail;
}
if (!snapshot)
bs->read_only = 1;
}
bs->fd = fd;
/* see if it is a cow image */
if (read(fd, &cow_header, sizeof(cow_header)) != sizeof(cow_header)) {
fprintf(stderr, "%s: could not read header\n", filename);
goto fail;
}
if (cow_header.magic == htonl(COW_MAGIC) &&
cow_header.version == htonl(COW_VERSION)) {
/* cow image found */
size = cow_header.size;
#ifndef WORDS_BIGENDIAN
size = bswap64(size);
#endif
bs->total_sectors = size / 512;
bs->cow_fd = fd;
bs->fd = -1;
if (cow_header.backing_file[0] != '\0') {
if (stat(cow_header.backing_file, &st) != 0) {
fprintf(stderr, "%s: could not find original disk image '%s'\n", filename, cow_header.backing_file);
goto fail;
}
if (st.st_mtime != htonl(cow_header.mtime)) {
fprintf(stderr, "%s: original raw disk image '%s' does not match saved timestamp\n", filename, cow_header.backing_file);
goto fail;
}
fd = open(cow_header.backing_file, O_RDONLY | O_LARGEFILE);
if (fd < 0)
goto fail;
bs->fd = fd;
}
/* mmap the bitmap */
bs->cow_bitmap_size = ((bs->total_sectors + 7) >> 3) + sizeof(cow_header);
bs->cow_bitmap_addr = mmap(get_mmap_addr(bs->cow_bitmap_size),
bs->cow_bitmap_size,
PROT_READ | PROT_WRITE,
MAP_SHARED, bs->cow_fd, 0);
if (bs->cow_bitmap_addr == MAP_FAILED)
goto fail;
bs->cow_bitmap = bs->cow_bitmap_addr + sizeof(cow_header);
bs->cow_sectors_offset = (bs->cow_bitmap_size + 511) & ~511;
snapshot = 0;
} else {
/* standard raw image */
size = lseek64(fd, 0, SEEK_END);
bs->total_sectors = size / 512;
bs->fd = fd;
}
if (snapshot) {
/* create a temporary COW file */
cow_fd = mkstemp(template);
if (cow_fd < 0)
goto fail;
bs->cow_fd = cow_fd;
unlink(template);
/* just need to allocate bitmap */
bs->cow_bitmap_size = (bs->total_sectors + 7) >> 3;
bs->cow_bitmap_addr = mmap(get_mmap_addr(bs->cow_bitmap_size),
bs->cow_bitmap_size,
PROT_READ | PROT_WRITE,
MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
if (bs->cow_bitmap_addr == MAP_FAILED)
goto fail;
bs->cow_bitmap = bs->cow_bitmap_addr;
bs->cow_sectors_offset = 0;
}
return bs;
fail:
bdrv_close(bs);
return NULL;
}
void bdrv_close(BlockDriverState *bs)
{
/* we unmap the mapping so that it is written to the COW file */
if (bs->cow_bitmap_addr)
munmap(bs->cow_bitmap_addr, bs->cow_bitmap_size);
if (bs->cow_fd >= 0)
close(bs->cow_fd);
if (bs->fd >= 0)
close(bs->fd);
free(bs);
}
static inline void set_bit(uint8_t *bitmap, int64_t bitnum)
{
bitmap[bitnum / 8] |= (1 << (bitnum%8));
}
static inline int is_bit_set(const uint8_t *bitmap, int64_t bitnum)
{
return !!(bitmap[bitnum / 8] & (1 << (bitnum%8)));
}
/* Return true if first block has been changed (ie. current version is
* in COW file). Set the number of continuous blocks for which that
* is true. */
static int is_changed(uint8_t *bitmap,
int64_t sector_num, int nb_sectors,
int *num_same)
{
int changed;
if (!bitmap || nb_sectors == 0) {
*num_same = nb_sectors;
return 0;
}
changed = is_bit_set(bitmap, sector_num);
for (*num_same = 1; *num_same < nb_sectors; (*num_same)++) {
if (is_bit_set(bitmap, sector_num + *num_same) != changed)
break;
}
return changed;
}
/* commit COW file into the raw image */
int bdrv_commit(BlockDriverState *bs)
{
int64_t i;
uint8_t *cow_bitmap;
if (!bs->cow_bitmap) {
fprintf(stderr, "Already committed to %s\n", bs->filename);
return 0;
}
if (bs->read_only) {
fprintf(stderr, "Can't commit to %s: read-only\n", bs->filename);
return -1;
}
cow_bitmap = bs->cow_bitmap;
for (i = 0; i < bs->total_sectors; i++) {
if (is_bit_set(cow_bitmap, i)) {
unsigned char sector[512];
if (bdrv_read(bs, i, sector, 1) != 0) {
fprintf(stderr, "Error reading sector %lli: aborting commit\n",
(long long)i);
return -1;
}
/* Make bdrv_write write to real file for a moment. */
bs->cow_bitmap = NULL;
if (bdrv_write(bs, i, sector, 1) != 0) {
fprintf(stderr, "Error writing sector %lli: aborting commit\n",
(long long)i);
bs->cow_bitmap = cow_bitmap;
return -1;
}
bs->cow_bitmap = cow_bitmap;
}
}
fprintf(stderr, "Committed snapshot to %s\n", bs->filename);
return 0;
}
/* return -1 if error */
int bdrv_read(BlockDriverState *bs, int64_t sector_num,
uint8_t *buf, int nb_sectors)
{
int ret, n, fd;
int64_t offset;
while (nb_sectors > 0) {
if (is_changed(bs->cow_bitmap, sector_num, nb_sectors, &n)) {
fd = bs->cow_fd;
offset = bs->cow_sectors_offset;
} else {
fd = bs->fd;
offset = 0;
}
if (fd < 0) {
/* no file, just return empty sectors */
memset(buf, 0, n * 512);
} else {
offset += sector_num * 512;
lseek64(fd, offset, SEEK_SET);
ret = read(fd, buf, n * 512);
if (ret != n * 512) {
return -1;
}
}
nb_sectors -= n;
sector_num += n;
buf += n * 512;
}
return 0;
}
/* return -1 if error */
int bdrv_write(BlockDriverState *bs, int64_t sector_num,
const uint8_t *buf, int nb_sectors)
{
int ret, fd, i;
int64_t offset, retl;
if (bs->read_only)
return -1;
if (bs->cow_bitmap) {
fd = bs->cow_fd;
offset = bs->cow_sectors_offset;
} else {
fd = bs->fd;
offset = 0;
}
offset += sector_num * 512;
retl = lseek64(fd, offset, SEEK_SET);
if (retl == -1) {
return -1;
}
ret = write(fd, buf, nb_sectors * 512);
if (ret != nb_sectors * 512) {
return -1;
}
if (bs->cow_bitmap) {
for (i = 0; i < nb_sectors; i++)
set_bit(bs->cow_bitmap, sector_num + i);
}
return 0;
}
void bdrv_get_geometry(BlockDriverState *bs, int64_t *nb_sectors_ptr)
{
*nb_sectors_ptr = bs->total_sectors;
}
Vendored
+7 -10
View File
@@ -153,20 +153,15 @@ fi
fi
# check gcc version
# check gcc options support
cat > $TMPC <<EOF
int main(void) {
#if __GNUC__ > 3 || (__GNUC__ == 3 && __GNUC_MINOR__ >= 2)
return 0;
#else
#error gcc < 3.2
#endif
}
EOF
gcc_major="2"
if $cc -o $TMPO $TMPC 2> /dev/null ; then
gcc_major="3"
have_gcc3_options="no"
if $cc -fno-reorder-blocks -fno-optimize-sibling-calls -o $TMPO $TMPC 2> /dev/null ; then
have_gcc3_options="yes"
fi
if test "$target_bigendian" = "default" ; then
@@ -224,7 +219,9 @@ echo "prefix=$prefix" >> config.mak
echo "#define CONFIG_QEMU_PREFIX \"$interp_prefix\"" >> $TMPH
echo "MAKE=$make" >> config.mak
echo "CC=$cc" >> config.mak
echo "GCC_MAJOR=$gcc_major" >> config.mak
if test "$have_gcc3_options" = "yes" ; then
echo "HAVE_GCC3_OPTIONS=yes" >> config.mak
fi
echo "HOST_CC=$host_cc" >> config.mak
echo "AR=$ar" >> config.mak
echo "STRIP=$strip -s -R .comment -R .note" >> config.mak
+15 -1
View File
@@ -302,6 +302,20 @@ void page_unprotect_range(uint8_t *data, unsigned long data_size);
#endif
#endif
#endif /* SINGLE_CPU_DEFINES */
#define DEFAULT_GDBSTUB_PORT 1234
void cpu_abort(CPUState *env, const char *fmt, ...);
extern CPUState *cpu_single_env;
#define CPU_INTERRUPT_EXIT 0x01 /* wants exit from main loop */
#define CPU_INTERRUPT_HARD 0x02 /* hardware interrupt pending */
void cpu_interrupt(CPUState *s, int mask);
/* gdb stub API */
extern int gdbstub_fd;
CPUState *cpu_gdbstub_get_env(void *opaque);
int cpu_gdbstub(void *opaque, void (*main_loop)(void *opaque), int port);
#endif /* CPU_ALL_H */
+2 -1
View File
@@ -40,6 +40,8 @@ typedef struct CPUARMState {
jmp_buf jmp_env;
int exception_index;
int interrupt_request;
struct TranslationBlock *current_tb;
int user_mode_only;
/* user data */
void *opaque;
@@ -47,7 +49,6 @@ typedef struct CPUARMState {
CPUARMState *cpu_arm_init(void);
int cpu_arm_exec(CPUARMState *s);
void cpu_arm_interrupt(CPUARMState *s);
void cpu_arm_close(CPUARMState *s);
/* you can call this signal handler from your SIGBUS and SIGSEGV
signal handlers to inform the virtual CPU of exceptions. non zero
+216 -152
View File
@@ -71,7 +71,7 @@ int cpu_exec(CPUState *env1)
#ifdef __sparc__
int saved_i7, tmp_T0;
#endif
int code_gen_size, ret;
int code_gen_size, ret, interrupt_request;
void (*gen_func)(void);
TranslationBlock *tb, **ptb;
uint8_t *tc_ptr, *cs_base, *pc;
@@ -139,147 +139,210 @@ int cpu_exec(CPUState *env1)
#else
#error unsupported target CPU
#endif
env->interrupt_request = 0;
env->exception_index = -1;
/* prepare setjmp context for exception handling */
if (setjmp(env->jmp_env) == 0) {
T0 = 0; /* force lookup of first TB */
for(;;) {
#ifdef __sparc__
/* g1 can be modified by some libc? functions */
tmp_T0 = T0;
#endif
if (env->interrupt_request) {
env->exception_index = EXCP_INTERRUPT;
cpu_loop_exit();
}
#ifdef DEBUG_EXEC
if (loglevel) {
for(;;) {
if (setjmp(env->jmp_env) == 0) {
/* if an exception is pending, we execute it here */
if (env->exception_index >= 0) {
if (env->exception_index >= EXCP_INTERRUPT) {
/* exit request from the cpu execution loop */
ret = env->exception_index;
break;
} else if (env->user_mode_only) {
/* if user mode only, we simulate a fake exception
which will be hanlded outside the cpu execution
loop */
#if defined(TARGET_I386)
/* restore flags in standard format */
env->regs[R_EAX] = EAX;
env->regs[R_EBX] = EBX;
env->regs[R_ECX] = ECX;
env->regs[R_EDX] = EDX;
env->regs[R_ESI] = ESI;
env->regs[R_EDI] = EDI;
env->regs[R_EBP] = EBP;
env->regs[R_ESP] = ESP;
env->eflags = env->eflags | cc_table[CC_OP].compute_all() | (DF & DF_MASK);
cpu_x86_dump_state(env, logfile, 0);
env->eflags &= ~(DF_MASK | CC_O | CC_S | CC_Z | CC_A | CC_P | CC_C);
do_interrupt_user(env->exception_index,
env->exception_is_int,
env->error_code,
env->exception_next_eip);
#endif
ret = env->exception_index;
break;
} else {
#if defined(TARGET_I386)
/* simulate a real cpu exception. On i386, it can
trigger new exceptions, but we do not handle
double or triple faults yet. */
do_interrupt(env->exception_index,
env->exception_is_int,
env->error_code,
env->exception_next_eip);
#endif
}
env->exception_index = -1;
}
T0 = 0; /* force lookup of first TB */
for(;;) {
#ifdef __sparc__
/* g1 can be modified by some libc? functions */
tmp_T0 = T0;
#endif
interrupt_request = env->interrupt_request;
if (interrupt_request) {
#if defined(TARGET_I386)
/* if hardware interrupt pending, we execute it */
if ((interrupt_request & CPU_INTERRUPT_HARD) &&
(env->eflags & IF_MASK)) {
int intno;
intno = cpu_x86_get_pic_interrupt(env);
if (loglevel) {
fprintf(logfile, "Servicing hardware INT=0x%02x\n", intno);
}
do_interrupt(intno, 0, 0, 0);
env->interrupt_request &= ~CPU_INTERRUPT_HARD;
/* ensure that no TB jump will be modified as
the program flow was changed */
#ifdef __sparc__
tmp_T0 = 0;
#else
T0 = 0;
#endif
}
#endif
if (interrupt_request & CPU_INTERRUPT_EXIT) {
env->interrupt_request &= ~CPU_INTERRUPT_EXIT;
env->exception_index = EXCP_INTERRUPT;
cpu_loop_exit();
}
}
#ifdef DEBUG_EXEC
if (loglevel) {
#if defined(TARGET_I386)
/* restore flags in standard format */
env->regs[R_EAX] = EAX;
env->regs[R_EBX] = EBX;
env->regs[R_ECX] = ECX;
env->regs[R_EDX] = EDX;
env->regs[R_ESI] = ESI;
env->regs[R_EDI] = EDI;
env->regs[R_EBP] = EBP;
env->regs[R_ESP] = ESP;
env->eflags = env->eflags | cc_table[CC_OP].compute_all() | (DF & DF_MASK);
cpu_x86_dump_state(env, logfile, X86_DUMP_CCOP);
env->eflags &= ~(DF_MASK | CC_O | CC_S | CC_Z | CC_A | CC_P | CC_C);
#elif defined(TARGET_ARM)
cpu_arm_dump_state(env, logfile, 0);
env->cpsr = compute_cpsr();
cpu_arm_dump_state(env, logfile, 0);
env->cpsr &= ~0xf0000000;
#else
#error unsupported target CPU
#endif
}
}
#endif
/* we compute the CPU state. We assume it will not
change during the whole generated block. */
/* we compute the CPU state. We assume it will not
change during the whole generated block. */
#if defined(TARGET_I386)
flags = env->seg_cache[R_CS].seg_32bit << GEN_FLAG_CODE32_SHIFT;
flags |= env->seg_cache[R_SS].seg_32bit << GEN_FLAG_SS32_SHIFT;
flags |= (((unsigned long)env->seg_cache[R_DS].base |
(unsigned long)env->seg_cache[R_ES].base |
(unsigned long)env->seg_cache[R_SS].base) != 0) <<
GEN_FLAG_ADDSEG_SHIFT;
if (!(env->eflags & VM_MASK)) {
flags |= (env->segs[R_CS] & 3) << GEN_FLAG_CPL_SHIFT;
} else {
/* NOTE: a dummy CPL is kept */
flags |= (1 << GEN_FLAG_VM_SHIFT);
flags |= (3 << GEN_FLAG_CPL_SHIFT);
}
flags |= (env->eflags & (IOPL_MASK | TF_MASK));
cs_base = env->seg_cache[R_CS].base;
pc = cs_base + env->eip;
flags = (env->segs[R_CS].flags & DESC_B_MASK)
>> (DESC_B_SHIFT - GEN_FLAG_CODE32_SHIFT);
flags |= (env->segs[R_SS].flags & DESC_B_MASK)
>> (DESC_B_SHIFT - GEN_FLAG_SS32_SHIFT);
flags |= (((unsigned long)env->segs[R_DS].base |
(unsigned long)env->segs[R_ES].base |
(unsigned long)env->segs[R_SS].base) != 0) <<
GEN_FLAG_ADDSEG_SHIFT;
if (!(env->eflags & VM_MASK)) {
flags |= (env->segs[R_CS].selector & 3) << GEN_FLAG_CPL_SHIFT;
} else {
/* NOTE: a dummy CPL is kept */
flags |= (1 << GEN_FLAG_VM_SHIFT);
flags |= (3 << GEN_FLAG_CPL_SHIFT);
}
flags |= (env->eflags & (IOPL_MASK | TF_MASK));
cs_base = env->segs[R_CS].base;
pc = cs_base + env->eip;
#elif defined(TARGET_ARM)
flags = 0;
cs_base = 0;
pc = (uint8_t *)env->regs[15];
flags = 0;
cs_base = 0;
pc = (uint8_t *)env->regs[15];
#else
#error unsupported CPU
#endif
tb = tb_find(&ptb, (unsigned long)pc, (unsigned long)cs_base,
flags);
if (!tb) {
spin_lock(&tb_lock);
/* if no translated code available, then translate it now */
tb = tb_alloc((unsigned long)pc);
tb = tb_find(&ptb, (unsigned long)pc, (unsigned long)cs_base,
flags);
if (!tb) {
/* flush must be done */
tb_flush();
/* cannot fail at this point */
spin_lock(&tb_lock);
/* if no translated code available, then translate it now */
tb = tb_alloc((unsigned long)pc);
/* don't forget to invalidate previous TB info */
ptb = &tb_hash[tb_hash_func((unsigned long)pc)];
T0 = 0;
}
tc_ptr = code_gen_ptr;
tb->tc_ptr = tc_ptr;
tb->cs_base = (unsigned long)cs_base;
tb->flags = flags;
ret = cpu_gen_code(tb, CODE_GEN_MAX_SIZE, &code_gen_size);
if (!tb) {
/* flush must be done */
tb_flush();
/* cannot fail at this point */
tb = tb_alloc((unsigned long)pc);
/* don't forget to invalidate previous TB info */
ptb = &tb_hash[tb_hash_func((unsigned long)pc)];
T0 = 0;
}
tc_ptr = code_gen_ptr;
tb->tc_ptr = tc_ptr;
tb->cs_base = (unsigned long)cs_base;
tb->flags = flags;
ret = cpu_gen_code(tb, CODE_GEN_MAX_SIZE, &code_gen_size);
#if defined(TARGET_I386)
/* XXX: suppress that, this is incorrect */
/* if invalid instruction, signal it */
if (ret != 0) {
/* NOTE: the tb is allocated but not linked, so we
can leave it */
spin_unlock(&tb_lock);
raise_exception(EXCP06_ILLOP);
}
/* XXX: suppress that, this is incorrect */
/* if invalid instruction, signal it */
if (ret != 0) {
/* NOTE: the tb is allocated but not linked, so we
can leave it */
spin_unlock(&tb_lock);
raise_exception(EXCP06_ILLOP);
}
#endif
*ptb = tb;
tb->hash_next = NULL;
tb_link(tb);
code_gen_ptr = (void *)(((unsigned long)code_gen_ptr + code_gen_size + CODE_GEN_ALIGN - 1) & ~(CODE_GEN_ALIGN - 1));
spin_unlock(&tb_lock);
}
*ptb = tb;
tb->hash_next = NULL;
tb_link(tb);
code_gen_ptr = (void *)(((unsigned long)code_gen_ptr + code_gen_size + CODE_GEN_ALIGN - 1) & ~(CODE_GEN_ALIGN - 1));
spin_unlock(&tb_lock);
}
#ifdef DEBUG_EXEC
if (loglevel) {
fprintf(logfile, "Trace 0x%08lx [0x%08lx] %s\n",
(long)tb->tc_ptr, (long)tb->pc,
lookup_symbol((void *)tb->pc));
}
if (loglevel) {
fprintf(logfile, "Trace 0x%08lx [0x%08lx] %s\n",
(long)tb->tc_ptr, (long)tb->pc,
lookup_symbol((void *)tb->pc));
}
#endif
#ifdef __sparc__
T0 = tmp_T0;
T0 = tmp_T0;
#endif
/* see if we can patch the calling TB. XXX: remove TF test */
if (T0 != 0
/* see if we can patch the calling TB. XXX: remove TF test */
if (T0 != 0
#if defined(TARGET_I386)
&& !(env->eflags & TF_MASK)
&& !(env->eflags & TF_MASK)
#endif
) {
spin_lock(&tb_lock);
tb_add_jump((TranslationBlock *)(T0 & ~3), T0 & 3, tb);
spin_unlock(&tb_lock);
}
tc_ptr = tb->tc_ptr;
/* execute the generated code */
gen_func = (void *)tc_ptr;
) {
spin_lock(&tb_lock);
tb_add_jump((TranslationBlock *)(T0 & ~3), T0 & 3, tb);
spin_unlock(&tb_lock);
}
tc_ptr = tb->tc_ptr;
env->current_tb = tb;
/* execute the generated code */
gen_func = (void *)tc_ptr;
#if defined(__sparc__)
__asm__ __volatile__("call %0\n\t"
"mov %%o7,%%i0"
: /* no outputs */
: "r" (gen_func)
: "i0", "i1", "i2", "i3", "i4", "i5");
__asm__ __volatile__("call %0\n\t"
"mov %%o7,%%i0"
: /* no outputs */
: "r" (gen_func)
: "i0", "i1", "i2", "i3", "i4", "i5");
#elif defined(__arm__)
asm volatile ("mov pc, %0\n\t"
".global exec_loop\n\t"
"exec_loop:\n\t"
: /* no outputs */
: "r" (gen_func)
: "r1", "r2", "r3", "r8", "r9", "r10", "r12", "r14");
asm volatile ("mov pc, %0\n\t"
".global exec_loop\n\t"
"exec_loop:\n\t"
: /* no outputs */
: "r" (gen_func)
: "r1", "r2", "r3", "r8", "r9", "r10", "r12", "r14");
#else
gen_func();
gen_func();
#endif
env->current_tb = NULL;
}
} else {
}
}
ret = env->exception_index;
} /* for(;;) */
#if defined(TARGET_I386)
/* restore flags in standard format */
@@ -311,12 +374,7 @@ int cpu_exec(CPUState *env1)
EDI = saved_EDI;
#endif
#elif defined(TARGET_ARM)
{
int ZF;
ZF = (env->NZF == 0);
env->cpsr = env->cpsr | (env->NZF & 0x80000000) | (ZF << 30) |
(env->CF << 29) | ((env->VF & 0x80000000) >> 3);
}
env->cpsr = compute_cpsr();
#else
#error unsupported target CPU
#endif
@@ -330,12 +388,6 @@ int cpu_exec(CPUState *env1)
return ret;
}
void cpu_interrupt(CPUState *s)
{
s->interrupt_request = 1;
}
#if defined(TARGET_I386)
void cpu_x86_load_seg(CPUX86State *s, int seg_reg, int selector)
@@ -347,13 +399,13 @@ void cpu_x86_load_seg(CPUX86State *s, int seg_reg, int selector)
if (env->eflags & VM_MASK) {
SegmentCache *sc;
selector &= 0xffff;
sc = &env->seg_cache[seg_reg];
/* NOTE: in VM86 mode, limit and seg_32bit are never reloaded,
sc = &env->segs[seg_reg];
/* NOTE: in VM86 mode, limit and flags are never reloaded,
so we must load them here */
sc->base = (void *)(selector << 4);
sc->limit = 0xffff;
sc->seg_32bit = 0;
env->segs[seg_reg] = selector;
sc->flags = 0;
sc->selector = selector;
} else {
load_seg(seg_reg, selector, 0);
}
@@ -398,6 +450,8 @@ void cpu_x86_frstor(CPUX86State *s, uint8_t *ptr, int data32)
#include <signal.h>
#include <sys/ucontext.h>
#if defined(TARGET_I386)
/* 'pc' is the host PC at which the exception was raised. 'address' is
the effective address of the memory exception. 'is_write' is 1 if a
write caused the exception and otherwise 0'. 'old_set' is the
@@ -407,42 +461,52 @@ static inline int handle_cpu_signal(unsigned long pc, unsigned long address,
{
TranslationBlock *tb;
int ret;
uint32_t found_pc;
if (cpu_single_env)
env = cpu_single_env; /* XXX: find a correct solution for multithread */
#if defined(DEBUG_SIGNAL)
printf("qemu: SIGSEGV pc=0x%08lx address=%08lx wr=%d oldset=0x%08lx\n",
printf("qemu: SIGSEGV pc=0x%08lx address=%08lx w=%d oldset=0x%08lx\n",
pc, address, is_write, *(unsigned long *)old_set);
#endif
/* XXX: locking issue */
if (is_write && page_unprotect(address)) {
return 1;
}
/* see if it is an MMU fault */
ret = cpu_x86_handle_mmu_fault(env, address, is_write);
if (ret < 0)
return 0; /* not an MMU fault */
if (ret == 0)
return 1; /* the MMU fault was handled without causing real CPU fault */
/* now we have a real cpu fault */
tb = tb_find_pc(pc);
if (tb) {
/* the PC is inside the translated code. It means that we have
a virtual CPU fault */
ret = cpu_search_pc(tb, &found_pc, pc);
if (ret < 0)
return 0;
#if defined(TARGET_I386)
env->eip = found_pc - tb->cs_base;
env->cr2 = address;
/* we restore the process signal mask as the sigreturn should
do it (XXX: use sigsetjmp) */
sigprocmask(SIG_SETMASK, old_set, NULL);
raise_exception_err(EXCP0E_PAGE, 4 | (is_write << 1));
cpu_restore_state(tb, env, pc);
}
#if 0
printf("PF exception: EIP=0x%08x CR2=0x%08x error=0x%x\n",
env->eip, env->cr[2], env->error_code);
#endif
/* we restore the process signal mask as the sigreturn should
do it (XXX: use sigsetjmp) */
sigprocmask(SIG_SETMASK, old_set, NULL);
raise_exception_err(EXCP0E_PAGE, env->error_code);
/* never comes here */
return 1;
}
#elif defined(TARGET_ARM)
env->regs[15] = found_pc;
/* XXX: do more */
static inline int handle_cpu_signal(unsigned long pc, unsigned long address,
int is_write, sigset_t *old_set)
{
/* XXX: do more */
return 0;
}
#else
#error unsupported target CPU
#endif
/* never comes here */
return 1;
} else {
return 0;
}
}
#if defined(__i386__)
@@ -570,6 +634,6 @@ int cpu_signal_handler(int host_signum, struct siginfo *info,
#else
#error CPU specific signal handler needed
#error host CPU specific signal handler needed
#endif
+79 -20
View File
@@ -50,7 +50,8 @@
/* segment descriptor fields */
#define DESC_G_MASK (1 << 23)
#define DESC_B_MASK (1 << 22)
#define DESC_B_SHIFT 22
#define DESC_B_MASK (1 << DESC_B_SHIFT)
#define DESC_AVL_MASK (1 << 20)
#define DESC_P_MASK (1 << 15)
#define DESC_DPL_SHIFT 13
@@ -85,6 +86,54 @@
#define VIP_MASK 0x00100000
#define ID_MASK 0x00200000
#define CR0_PE_MASK (1 << 0)
#define CR0_TS_MASK (1 << 3)
#define CR0_WP_MASK (1 << 16)
#define CR0_AM_MASK (1 << 18)
#define CR0_PG_MASK (1 << 31)
#define CR4_VME_MASK (1 << 0)
#define CR4_PVI_MASK (1 << 1)
#define CR4_TSD_MASK (1 << 2)
#define CR4_DE_MASK (1 << 3)
#define CR4_PSE_MASK (1 << 4)
#define PG_PRESENT_BIT 0
#define PG_RW_BIT 1
#define PG_USER_BIT 2
#define PG_PWT_BIT 3
#define PG_PCD_BIT 4
#define PG_ACCESSED_BIT 5
#define PG_DIRTY_BIT 6
#define PG_PSE_BIT 7
#define PG_GLOBAL_BIT 8
#define PG_PRESENT_MASK (1 << PG_PRESENT_BIT)
#define PG_RW_MASK (1 << PG_RW_BIT)
#define PG_USER_MASK (1 << PG_USER_BIT)
#define PG_PWT_MASK (1 << PG_PWT_BIT)
#define PG_PCD_MASK (1 << PG_PCD_BIT)
#define PG_ACCESSED_MASK (1 << PG_ACCESSED_BIT)
#define PG_DIRTY_MASK (1 << PG_DIRTY_BIT)
#define PG_PSE_MASK (1 << PG_PSE_BIT)
#define PG_GLOBAL_MASK (1 << PG_GLOBAL_BIT)
#define PG_ERROR_W_BIT 1
#define PG_ERROR_P_MASK 0x01
#define PG_ERROR_W_MASK (1 << PG_ERROR_W_BIT)
#define PG_ERROR_U_MASK 0x04
#define PG_ERROR_RSVD_MASK 0x08
#define MSR_IA32_APICBASE 0x1b
#define MSR_IA32_APICBASE_BSP (1<<8)
#define MSR_IA32_APICBASE_ENABLE (1<<11)
#define MSR_IA32_APICBASE_BASE (0xfffff<<12)
#define MSR_IA32_SYSENTER_CS 0x174
#define MSR_IA32_SYSENTER_ESP 0x175
#define MSR_IA32_SYSENTER_EIP 0x176
#define EXCP00_DIVZ 0
#define EXCP01_SSTP 1
#define EXCP02_NMI 2
@@ -105,6 +154,7 @@
#define EXCP12_MCHK 18
#define EXCP_INTERRUPT 256 /* async interruption */
#define EXCP_HLT 257 /* hlt instruction reached */
enum {
CC_OP_DYNAMIC, /* must use dynamic code to get cc_op */
@@ -161,19 +211,12 @@ typedef double CPU86_LDouble;
#endif
typedef struct SegmentCache {
uint32_t selector;
uint8_t *base;
unsigned long limit;
uint8_t seg_32bit;
uint32_t limit;
uint32_t flags;
} SegmentCache;
typedef struct SegmentDescriptorTable {
uint8_t *base;
unsigned long limit;
/* this is the returned base when reading the register, just to
avoid that the emulated program modifies it */
unsigned long emu_base;
} SegmentDescriptorTable;
typedef struct CPUX86State {
/* standard registers */
uint32_t regs[8];
@@ -205,19 +248,29 @@ typedef struct CPUX86State {
} fp_convert;
/* segments */
uint32_t segs[6]; /* selector values */
SegmentCache seg_cache[6]; /* info taken from LDT/GDT */
SegmentDescriptorTable gdt;
SegmentDescriptorTable ldt;
SegmentDescriptorTable idt;
SegmentCache segs[6]; /* selector values */
SegmentCache ldt;
SegmentCache tr;
SegmentCache gdt; /* only base and limit are used */
SegmentCache idt; /* only base and limit are used */
/* sysenter registers */
uint32_t sysenter_cs;
uint32_t sysenter_esp;
uint32_t sysenter_eip;
/* exception/interrupt handling */
jmp_buf jmp_env;
int exception_index;
int error_code;
uint32_t cr2;
int interrupt_request;
int exception_is_int;
int exception_next_eip;
struct TranslationBlock *current_tb; /* currently executing TB */
uint32_t cr[5]; /* NOTE: cr1 is unused */
uint32_t dr[8]; /* debug registers */
int interrupt_request;
int user_mode_only; /* user mode only simulation */
/* user data */
void *opaque;
} CPUX86State;
@@ -233,8 +286,8 @@ int cpu_x86_inl(CPUX86State *env, int addr);
CPUX86State *cpu_x86_init(void);
int cpu_x86_exec(CPUX86State *s);
void cpu_x86_interrupt(CPUX86State *s);
void cpu_x86_close(CPUX86State *s);
int cpu_x86_get_pic_interrupt(CPUX86State *s);
/* needed to load some predefinied segment registers */
void cpu_x86_load_seg(CPUX86State *s, int seg_reg, int selector);
@@ -250,6 +303,12 @@ struct siginfo;
int cpu_x86_signal_handler(int host_signum, struct siginfo *info,
void *puc);
/* MMU defines */
void cpu_x86_init_mmu(CPUX86State *env);
extern int phys_ram_size;
extern int phys_ram_fd;
extern uint8_t *phys_ram_base;
/* used to debug */
#define X86_DUMP_FPU 0x0001 /* dump FPU state too */
#define X86_DUMP_CCOP 0x0002 /* dump qemu flag cache */
+2 -2
View File
@@ -42,7 +42,7 @@ perror_memory (status, memaddr, info)
/* Actually, address between memaddr and memaddr + len was
out of bounds. */
(*info->fprintf_func) (info->stream,
"Address 0x%x is out of bounds.\n", memaddr);
"Address 0x%llx is out of bounds.\n", memaddr);
}
/* This could be in a separate file, to save miniscule amounts of space
@@ -57,7 +57,7 @@ generic_print_address (addr, info)
bfd_vma addr;
struct disassemble_info *info;
{
(*info->fprintf_func) (info->stream, "0x%x", addr);
(*info->fprintf_func) (info->stream, "0x%llx", addr);
}
/* Just return the given address. */
+26
View File
@@ -125,6 +125,8 @@ extern int printf(const char *, ...);
#define xglue(x, y) x ## y
#define glue(x, y) xglue(x, y)
#define stringify(s) tostring(s)
#define tostring(s) #s
#ifdef __alpha__
/* the symbols are considered non exported so a br immediate is generated */
@@ -153,3 +155,27 @@ extern int __op_param1, __op_param2, __op_param3;
#endif
extern int __op_jmp0, __op_jmp1;
#ifdef __i386__
#define EXIT_TB() asm volatile ("ret")
#endif
#ifdef __powerpc__
#define EXIT_TB() asm volatile ("blr")
#endif
#ifdef __s390__
#define EXIT_TB() asm volatile ("br %r14")
#endif
#ifdef __alpha__
#define EXIT_TB() asm volatile ("ret")
#endif
#ifdef __ia64__
#define EXIT_TB() asm volatile ("br.ret.sptk.many b0;;")
#endif
#ifdef __sparc__
#define EXIT_TB() asm volatile ("jmpl %i0 + 8, %g0\n" \
"nop")
#endif
#ifdef __arm__
#define EXIT_TB() asm volatile ("b exec_loop")
#endif
+22 -37
View File
@@ -108,6 +108,7 @@ typedef uint64_t host_ulong;
#define SHT_RELOC SHT_REL
#endif
#define NO_THUNK_TYPE_SIZE
#include "thunk.h"
enum {
@@ -654,7 +655,6 @@ void gen_code(const char *name, host_ulong offset, host_ulong size,
sym_name = strtab + sym->st_name;
if (strstart(sym_name, "__op_label", &p)) {
uint8_t *ptr;
int addend;
unsigned long offset;
/* test if the variable refers to a label inside
@@ -663,7 +663,7 @@ void gen_code(const char *name, host_ulong offset, host_ulong size,
if (!ptr)
error("__op_labelN in invalid section");
offset = sym->st_value;
addend = 0;
val = *(target_ulong *)(ptr + offset);
#ifdef ELF_USES_RELOCA
{
int reloc_shndx, nb_relocs1, j;
@@ -676,7 +676,7 @@ void gen_code(const char *name, host_ulong offset, host_ulong size,
rel = (ELF_RELOC *)sdata[reloc_shndx];
for(j = 0; j < nb_relocs1; j++) {
if (rel->r_offset == offset) {
addend = rel->r_addend;
val = rel->r_addend;
break;
}
rel++;
@@ -684,8 +684,6 @@ void gen_code(const char *name, host_ulong offset, host_ulong size,
}
}
#endif
val = *(target_ulong *)(ptr + offset);
val += addend;
if (val >= start_offset && val < start_offset + copy_size) {
n = strtol(p, NULL, 10);
@@ -1203,6 +1201,10 @@ int load_elf(const char *filename, FILE *outfile, int out_type)
if (out_type == OUT_INDEX_OP) {
fprintf(outfile, "DEF(end, 0, 0)\n");
fprintf(outfile, "DEF(nop, 0, 0)\n");
fprintf(outfile, "DEF(nop1, 1, 0)\n");
fprintf(outfile, "DEF(nop2, 2, 0)\n");
fprintf(outfile, "DEF(nop3, 3, 0)\n");
for(i = 0, sym = symtab; i < nb_syms; i++, sym++) {
const char *name, *p;
name = strtab + sym->st_name;
@@ -1272,6 +1274,17 @@ fprintf(outfile,
}
fprintf(outfile,
" case INDEX_op_nop:\n"
" break;\n"
" case INDEX_op_nop1:\n"
" opparam_ptr++;\n"
" break;\n"
" case INDEX_op_nop2:\n"
" opparam_ptr += 2;\n"
" break;\n"
" case INDEX_op_nop3:\n"
" opparam_ptr += 3;\n"
" break;\n"
" default:\n"
" goto the_end;\n"
" }\n");
@@ -1293,38 +1306,10 @@ fprintf(outfile,
" the_end:\n"
);
/* generate epilogue */
switch(ELF_ARCH) {
case EM_386:
fprintf(outfile, "*gen_code_ptr++ = 0xc3; /* ret */\n");
break;
case EM_PPC:
fprintf(outfile, "*((uint32_t *)gen_code_ptr)++ = 0x4e800020; /* blr */\n");
break;
case EM_S390:
fprintf(outfile, "*((uint16_t *)gen_code_ptr)++ = 0x07fe; /* br %%r14 */\n");
break;
case EM_ALPHA:
fprintf(outfile, "*((uint32_t *)gen_code_ptr)++ = 0x6bfa8001; /* ret */\n");
break;
case EM_IA_64:
fprintf(outfile, "*((uint32_t *)gen_code_ptr)++ = 0x00840008; /* br.ret.sptk.many b0;; */\n");
break;
case EM_SPARC:
case EM_SPARC32PLUS:
fprintf(outfile, "*((uint32_t *)gen_code_ptr)++ = 0x81c62008; /* jmpl %%i0 + 8, %%g0 */\n");
fprintf(outfile, "*((uint32_t *)gen_code_ptr)++ = 0x01000000; /* nop */\n");
break;
case EM_SPARCV9:
fprintf(outfile, "*((uint32_t *)gen_code_ptr)++ = 0x81c7e008; /* ret */\n");
fprintf(outfile, "*((uint32_t *)gen_code_ptr)++ = 0x81e80000; /* restore */\n");
break;
case EM_ARM:
fprintf(outfile, "gen_code_ptr = arm_flush_ldr(gen_code_ptr, arm_ldr_table, arm_ldr_ptr, arm_data_table, arm_data_ptr, 0);\n");
break;
default:
error("unknown ELF architecture");
}
/* generate some code patching */
#ifdef HOST_ARM
fprintf(outfile, "gen_code_ptr = arm_flush_ldr(gen_code_ptr, arm_ldr_table, arm_ldr_ptr, arm_data_table, arm_data_ptr, 0);\n");
#endif
/* flush instruction cache */
fprintf(outfile, "flush_icache_range((unsigned long)gen_code_buf, (unsigned long)gen_code_ptr);\n");
+1 -5
View File
@@ -152,11 +152,7 @@ static uint8_t *arm_flush_ldr(uint8_t *gen_code_ptr,
data_size = (uint8_t *)data_end - (uint8_t *)data_start;
if (!gen_jmp) {
/* b exec_loop */
arm_reloc_pc24((uint32_t *)gen_code_ptr, 0xeafffffe, (long)(&exec_loop));
gen_code_ptr += 4;
} else {
if (gen_jmp) {
/* generate branch to skip the data */
if (data_size == 0)
return gen_code_ptr;
+8
View File
@@ -30,3 +30,11 @@ register uint32_t T2 asm(AREG3);
void cpu_lock(void);
void cpu_unlock(void);
void cpu_loop_exit(void);
static inline int compute_cpsr(void)
{
int ZF;
ZF = (env->NZF == 0);
return env->cpsr | (env->NZF & 0x80000000) | (ZF << 30) |
(env->CF << 29) | ((env->VF & 0x80000000) >> 3);
}
+36
View File
@@ -123,8 +123,23 @@ typedef struct CCTable {
extern CCTable cc_table[];
void load_seg(int seg_reg, int selector, unsigned cur_eip);
void jmp_seg(int selector, unsigned int new_eip);
void helper_iret_protected(int shift);
void helper_lldt_T0(void);
void helper_ltr_T0(void);
void helper_movl_crN_T0(int reg);
void helper_movl_drN_T0(int reg);
void helper_invlpg(unsigned int addr);
void cpu_x86_update_cr0(CPUX86State *env);
void cpu_x86_update_cr3(CPUX86State *env);
void cpu_x86_flush_tlb(CPUX86State *env, uint32_t addr);
int cpu_x86_handle_mmu_fault(CPUX86State *env, uint32_t addr, int is_write);
void __hidden cpu_lock(void);
void __hidden cpu_unlock(void);
void do_interrupt(int intno, int is_int, int error_code,
unsigned int next_eip);
void do_interrupt_user(int intno, int is_int, int error_code,
unsigned int next_eip);
void raise_interrupt(int intno, int is_int, int error_code,
unsigned int next_eip);
void raise_exception_err(int exception_index, int error_code);
@@ -144,6 +159,8 @@ void helper_idivl_EAX_T0(uint32_t eip);
void helper_cmpxchg8b(void);
void helper_cpuid(void);
void helper_rdtsc(void);
void helper_rdmsr(void);
void helper_wrmsr(void);
void helper_lsl(void);
void helper_lar(void);
@@ -324,3 +341,22 @@ void helper_frstor(uint8_t *ptr, int data32);
const uint8_t parity_table[256];
const uint8_t rclw_table[32];
const uint8_t rclb_table[32];
static inline uint32_t compute_eflags(void)
{
return env->eflags | cc_table[CC_OP].compute_all() | (DF & DF_MASK);
}
#define FL_UPDATE_MASK32 (TF_MASK | AC_MASK | ID_MASK)
#define FL_UPDATE_CPL0_MASK (TF_MASK | IF_MASK | IOPL_MASK | NT_MASK | \
RF_MASK | AC_MASK | ID_MASK)
/* NOTE: CC_OP must be modified manually to CC_OP_EFLAGS */
static inline void load_eflags(int eflags, int update_mask)
{
CC_SRC = eflags & (CC_O | CC_S | CC_Z | CC_A | CC_P | CC_C);
DF = 1 - (2 * ((eflags >> 10) & 1));
env->eflags = (env->eflags & ~update_mask) |
(eflags & update_mask);
}
+125 -1
View File
@@ -26,11 +26,17 @@
#include <inttypes.h>
#include <sys/mman.h>
#include "config.h"
#ifdef TARGET_I386
#include "cpu-i386.h"
#endif
#ifdef TARGET_ARM
#include "cpu-arm.h"
#endif
#include "exec.h"
//#define DEBUG_TB_INVALIDATE
#define DEBUG_FLUSH
//#define DEBUG_FLUSH
/* make various TB consistency checks */
//#define DEBUG_TB_CHECK
@@ -563,3 +569,121 @@ TranslationBlock *tb_find_pc(unsigned long tc_ptr)
}
return &tbs[m_max];
}
static void tb_reset_jump_recursive(TranslationBlock *tb);
static inline void tb_reset_jump_recursive2(TranslationBlock *tb, int n)
{
TranslationBlock *tb1, *tb_next, **ptb;
unsigned int n1;
tb1 = tb->jmp_next[n];
if (tb1 != NULL) {
/* find head of list */
for(;;) {
n1 = (long)tb1 & 3;
tb1 = (TranslationBlock *)((long)tb1 & ~3);
if (n1 == 2)
break;
tb1 = tb1->jmp_next[n1];
}
/* we are now sure now that tb jumps to tb1 */
tb_next = tb1;
/* remove tb from the jmp_first list */
ptb = &tb_next->jmp_first;
for(;;) {
tb1 = *ptb;
n1 = (long)tb1 & 3;
tb1 = (TranslationBlock *)((long)tb1 & ~3);
if (n1 == n && tb1 == tb)
break;
ptb = &tb1->jmp_next[n1];
}
*ptb = tb->jmp_next[n];
tb->jmp_next[n] = NULL;
/* suppress the jump to next tb in generated code */
tb_reset_jump(tb, n);
/* suppress jumps in the tb on which we could have jump */
tb_reset_jump_recursive(tb_next);
}
}
static void tb_reset_jump_recursive(TranslationBlock *tb)
{
tb_reset_jump_recursive2(tb, 0);
tb_reset_jump_recursive2(tb, 1);
}
/* mask must never be zero */
void cpu_interrupt(CPUState *env, int mask)
{
TranslationBlock *tb;
env->interrupt_request |= mask;
/* if the cpu is currently executing code, we must unlink it and
all the potentially executing TB */
tb = env->current_tb;
if (tb) {
tb_reset_jump_recursive(tb);
}
}
void cpu_abort(CPUState *env, const char *fmt, ...)
{
va_list ap;
va_start(ap, fmt);
fprintf(stderr, "qemu: fatal: ");
vfprintf(stderr, fmt, ap);
fprintf(stderr, "\n");
#ifdef TARGET_I386
cpu_x86_dump_state(env, stderr, X86_DUMP_FPU | X86_DUMP_CCOP);
#endif
va_end(ap);
abort();
}
#ifdef TARGET_I386
/* unmap all maped pages and flush all associated code */
void page_unmap(void)
{
PageDesc *p, *pmap;
unsigned long addr;
int i, j, ret, j1;
for(i = 0; i < L1_SIZE; i++) {
pmap = l1_map[i];
if (pmap) {
p = pmap;
for(j = 0;j < L2_SIZE;) {
if (p->flags & PAGE_VALID) {
addr = (i << (32 - L1_BITS)) | (j << TARGET_PAGE_BITS);
/* we try to find a range to make less syscalls */
j1 = j;
p++;
j++;
while (j < L2_SIZE && (p->flags & PAGE_VALID)) {
p++;
j++;
}
ret = munmap((void *)addr, (j - j1) << TARGET_PAGE_BITS);
if (ret != 0) {
fprintf(stderr, "Could not unmap page 0x%08lx\n", addr);
exit(1);
}
} else {
p++;
j++;
}
}
free(pmap);
l1_map[i] = NULL;
}
}
tb_flush();
}
#endif
+24 -3
View File
@@ -39,6 +39,7 @@ struct TranslationBlock;
extern uint16_t gen_opc_buf[OPC_BUF_SIZE];
extern uint32_t gen_opparam_buf[OPPARAM_BUF_SIZE];
extern uint32_t gen_opc_pc[OPC_BUF_SIZE];
extern uint8_t gen_opc_cc_op[OPC_BUF_SIZE];
extern uint8_t gen_opc_instr_start[OPC_BUF_SIZE];
#if defined(TARGET_I386)
@@ -57,14 +58,16 @@ extern uint8_t gen_opc_instr_start[OPC_BUF_SIZE];
extern FILE *logfile;
extern int loglevel;
int gen_intermediate_code(struct TranslationBlock *tb, int search_pc);
int gen_intermediate_code(struct TranslationBlock *tb);
int gen_intermediate_code_pc(struct TranslationBlock *tb);
void dump_ops(const uint16_t *opc_buf, const uint32_t *opparam_buf);
int cpu_gen_code(struct TranslationBlock *tb,
int max_code_size, int *gen_code_size_ptr);
int cpu_search_pc(struct TranslationBlock *tb,
uint32_t *found_pc, unsigned long searched_pc);
int cpu_restore_state(struct TranslationBlock *tb,
CPUState *env, unsigned long searched_pc);
void cpu_exec_init(void);
int page_unprotect(unsigned long address);
void page_unmap(void);
#define CODE_GEN_MAX_SIZE 65536
#define CODE_GEN_ALIGN 16 /* must be >= of the size of a icache line */
@@ -216,10 +219,13 @@ label ## n:\
#define JUMP_TB(tbparam, n, eip)\
do {\
static void __attribute__((unused)) *__op_label ## n = &&label ## n;\
static void __attribute__((unused)) *dummy ## n = &&dummy_label ## n;\
goto *(void *)(((TranslationBlock *)tbparam)->tb_next[n]);\
label ## n:\
T0 = (long)(tbparam) + (n);\
EIP = eip;\
dummy_label ## n:\
EXIT_TB();\
} while (0)
#endif
@@ -319,6 +325,7 @@ typedef int spinlock_t;
#define SPIN_LOCK_UNLOCKED 0
#if 1
static inline void spin_lock(spinlock_t *lock)
{
while (testandset(lock));
@@ -333,6 +340,20 @@ static inline int spin_trylock(spinlock_t *lock)
{
return !testandset(lock);
}
#else
static inline void spin_lock(spinlock_t *lock)
{
}
static inline void spin_unlock(spinlock_t *lock)
{
}
static inline int spin_trylock(spinlock_t *lock)
{
return 1;
}
#endif
extern spinlock_t tb_lock;
+390
View File
@@ -0,0 +1,390 @@
/*
* gdb server stub
*
* Copyright (c) 2003 Fabrice Bellard
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <unistd.h>
#include <errno.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <netinet/tcp.h>
#include <signal.h>
#include "config.h"
#ifdef TARGET_I386
#include "cpu-i386.h"
#endif
#ifdef TARGET_ARM
#include "cpu-arm.h"
#endif
#include "thunk.h"
#include "exec.h"
//#define DEBUG_GDB
int gdbstub_fd = -1;
/* return 0 if OK */
static int gdbstub_open(int port)
{
struct sockaddr_in sockaddr;
socklen_t len;
int fd, val, ret;
fd = socket(PF_INET, SOCK_STREAM, 0);
if (fd < 0) {
perror("socket");
return -1;
}
/* allow fast reuse */
val = 1;
setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, &val, sizeof(val));
sockaddr.sin_family = AF_INET;
sockaddr.sin_port = htons(port);
sockaddr.sin_addr.s_addr = 0;
ret = bind(fd, (struct sockaddr *)&sockaddr, sizeof(sockaddr));
if (ret < 0) {
perror("bind");
return -1;
}
ret = listen(fd, 0);
if (ret < 0) {
perror("listen");
return -1;
}
/* now wait for one connection */
for(;;) {
len = sizeof(sockaddr);
gdbstub_fd = accept(fd, (struct sockaddr *)&sockaddr, &len);
if (gdbstub_fd < 0 && errno != EINTR) {
perror("accept");
return -1;
} else if (gdbstub_fd >= 0) {
break;
}
}
/* set short latency */
val = 1;
setsockopt(gdbstub_fd, SOL_TCP, TCP_NODELAY, &val, sizeof(val));
return 0;
}
static int get_char(void)
{
uint8_t ch;
int ret;
for(;;) {
ret = read(gdbstub_fd, &ch, 1);
if (ret < 0) {
if (errno != EINTR && errno != EAGAIN)
return -1;
} else if (ret == 0) {
return -1;
} else {
break;
}
}
return ch;
}
static void put_buffer(const uint8_t *buf, int len)
{
int ret;
while (len > 0) {
ret = write(gdbstub_fd, buf, len);
if (ret < 0) {
if (errno != EINTR && errno != EAGAIN)
return;
} else {
buf += ret;
len -= ret;
}
}
}
static inline int fromhex(int v)
{
if (v >= '0' && v <= '9')
return v - '0';
else if (v >= 'A' && v <= 'F')
return v - 'A' + 10;
else if (v >= 'a' && v <= 'f')
return v - 'a' + 10;
else
return 0;
}
static inline int tohex(int v)
{
if (v < 10)
return v + '0';
else
return v - 10 + 'a';
}
static void memtohex(char *buf, const uint8_t *mem, int len)
{
int i, c;
char *q;
q = buf;
for(i = 0; i < len; i++) {
c = mem[i];
*q++ = tohex(c >> 4);
*q++ = tohex(c & 0xf);
}
*q = '\0';
}
static void hextomem(uint8_t *mem, const char *buf, int len)
{
int i;
for(i = 0; i < len; i++) {
mem[i] = (fromhex(buf[0]) << 4) | fromhex(buf[1]);
buf += 2;
}
}
/* return -1 if error or EOF */
static int get_packet(char *buf, int buf_size)
{
int ch, len, csum, csum1;
char reply[1];
for(;;) {
for(;;) {
ch = get_char();
if (ch < 0)
return -1;
if (ch == '$')
break;
}
len = 0;
csum = 0;
for(;;) {
ch = get_char();
if (ch < 0)
return -1;
if (ch == '#')
break;
if (len > buf_size - 1)
return -1;
buf[len++] = ch;
csum += ch;
}
buf[len] = '\0';
ch = get_char();
if (ch < 0)
return -1;
csum1 = fromhex(ch) << 4;
ch = get_char();
if (ch < 0)
return -1;
csum1 |= fromhex(ch);
if ((csum & 0xff) != csum1) {
reply[0] = '-';
put_buffer(reply, 1);
} else {
reply[0] = '+';
put_buffer(reply, 1);
break;
}
}
#ifdef DEBUG_GDB
printf("command='%s'\n", buf);
#endif
return len;
}
/* return -1 if error, 0 if OK */
static int put_packet(char *buf)
{
char buf1[3];
int len, csum, ch, i;
#ifdef DEBUG_GDB
printf("reply='%s'\n", buf);
#endif
for(;;) {
buf1[0] = '$';
put_buffer(buf1, 1);
len = strlen(buf);
put_buffer(buf, len);
csum = 0;
for(i = 0; i < len; i++) {
csum += buf[i];
}
buf1[0] = '#';
buf1[1] = tohex((csum >> 4) & 0xf);
buf1[2] = tohex((csum) & 0xf);
put_buffer(buf1, 3);
ch = get_char();
if (ch < 0)
return -1;
if (ch == '+')
break;
}
return 0;
}
static int memory_rw(uint8_t *buf, uint32_t addr, int len, int is_write)
{
int l, flags;
uint32_t page;
while (len > 0) {
page = addr & TARGET_PAGE_MASK;
l = (page + TARGET_PAGE_SIZE) - addr;
if (l > len)
l = len;
flags = page_get_flags(page);
if (!(flags & PAGE_VALID))
return -1;
if (is_write) {
if (!(flags & PAGE_WRITE))
return -1;
memcpy((uint8_t *)addr, buf, l);
} else {
if (!(flags & PAGE_READ))
return -1;
memcpy(buf, (uint8_t *)addr, l);
}
len -= l;
buf += l;
addr += l;
}
return 0;
}
/* port = 0 means default port */
int cpu_gdbstub(void *opaque, void (*main_loop)(void *opaque), int port)
{
CPUState *env;
const char *p;
int ret, ch, nb_regs, i;
char buf[4096];
uint8_t mem_buf[2000];
uint32_t *registers;
uint32_t addr, len;
printf("Waiting gdb connection on port %d\n", port);
if (gdbstub_open(port) < 0)
return -1;
printf("Connected\n");
for(;;) {
ret = get_packet(buf, sizeof(buf));
if (ret < 0)
break;
p = buf;
ch = *p++;
switch(ch) {
case '?':
snprintf(buf, sizeof(buf), "S%02x", SIGTRAP);
put_packet(buf);
break;
case 'c':
main_loop(opaque);
snprintf(buf, sizeof(buf), "S%02x", 0);
put_packet(buf);
break;
case 'g':
env = cpu_gdbstub_get_env(opaque);
registers = (void *)mem_buf;
#if defined(TARGET_I386)
for(i = 0; i < 8; i++) {
registers[i] = tswapl(env->regs[i]);
}
registers[8] = env->eip;
registers[9] = env->eflags;
registers[10] = env->segs[R_CS].selector;
registers[11] = env->segs[R_SS].selector;
registers[12] = env->segs[R_DS].selector;
registers[13] = env->segs[R_ES].selector;
registers[14] = env->segs[R_FS].selector;
registers[15] = env->segs[R_GS].selector;
nb_regs = 16;
#endif
memtohex(buf, (const uint8_t *)registers,
sizeof(registers[0]) * nb_regs);
put_packet(buf);
break;
case 'G':
env = cpu_gdbstub_get_env(opaque);
registers = (void *)mem_buf;
#if defined(TARGET_I386)
hextomem((uint8_t *)registers, p, 16 * 4);
for(i = 0; i < 8; i++) {
env->regs[i] = tswapl(registers[i]);
}
env->eip = registers[8];
env->eflags = registers[9];
#define LOAD_SEG(index, sreg)\
if (tswapl(registers[index]) != env->segs[sreg].selector)\
cpu_x86_load_seg(env, sreg, tswapl(registers[index]));
LOAD_SEG(10, R_CS);
LOAD_SEG(11, R_SS);
LOAD_SEG(12, R_DS);
LOAD_SEG(13, R_ES);
LOAD_SEG(14, R_FS);
LOAD_SEG(15, R_GS);
#endif
put_packet("OK");
break;
case 'm':
addr = strtoul(p, (char **)&p, 16);
if (*p == ',')
p++;
len = strtoul(p, NULL, 16);
if (memory_rw(mem_buf, addr, len, 0) != 0)
memset(mem_buf, 0, len);
memtohex(buf, mem_buf, len);
put_packet(buf);
break;
case 'M':
addr = strtoul(p, (char **)&p, 16);
if (*p == ',')
p++;
len = strtoul(p, (char **)&p, 16);
if (*p == ',')
p++;
hextomem(mem_buf, p, len);
if (memory_rw(mem_buf, addr, len, 1) != 0)
put_packet("ENN");
else
put_packet("OK");
break;
default:
/* put empty packet */
buf[0] = '\0';
put_packet(buf);
break;
}
}
return 0;
}
+651 -138
View File
@@ -126,17 +126,74 @@ void cpu_loop_exit(void)
longjmp(env->jmp_env, 1);
}
#if 0
/* full interrupt support (only useful for real CPU emulation, not
finished) - I won't do it any time soon, finish it if you want ! */
void raise_interrupt(int intno, int is_int, int error_code,
unsigned int next_eip)
static inline void get_ss_esp_from_tss(uint32_t *ss_ptr,
uint32_t *esp_ptr, int dpl)
{
SegmentDescriptorTable *dt;
uint8_t *ptr;
int type, dpl, cpl;
uint32_t e1, e2;
int type, index, shift;
#if 0
{
int i;
printf("TR: base=%p limit=%x\n", env->tr.base, env->tr.limit);
for(i=0;i<env->tr.limit;i++) {
printf("%02x ", env->tr.base[i]);
if ((i & 7) == 7) printf("\n");
}
printf("\n");
}
#endif
if (!(env->tr.flags & DESC_P_MASK))
cpu_abort(env, "invalid tss");
type = (env->tr.flags >> DESC_TYPE_SHIFT) & 0xf;
if ((type & 7) != 1)
cpu_abort(env, "invalid tss type");
shift = type >> 3;
index = (dpl * 4 + 2) << shift;
if (index + (4 << shift) - 1 > env->tr.limit)
raise_exception_err(EXCP0A_TSS, env->tr.selector & 0xfffc);
if (shift == 0) {
*esp_ptr = lduw(env->tr.base + index);
*ss_ptr = lduw(env->tr.base + index + 2);
} else {
*esp_ptr = ldl(env->tr.base + index);
*ss_ptr = lduw(env->tr.base + index + 4);
}
}
/* return non zero if error */
static inline int load_segment(uint32_t *e1_ptr, uint32_t *e2_ptr,
int selector)
{
SegmentCache *dt;
int index;
uint8_t *ptr;
if (selector & 0x4)
dt = &env->ldt;
else
dt = &env->gdt;
index = selector & ~7;
if ((index + 7) > dt->limit)
return -1;
ptr = dt->base + index;
*e1_ptr = ldl(ptr);
*e2_ptr = ldl(ptr + 4);
return 0;
}
/* protected mode interrupt */
static void do_interrupt_protected(int intno, int is_int, int error_code,
unsigned int next_eip)
{
SegmentCache *dt;
uint8_t *ptr, *ssp;
int type, dpl, cpl, selector, ss_dpl;
int has_error_code, new_stack, shift;
uint32_t e1, e2, offset, ss, esp, ss_e1, ss_e2, push_size;
uint32_t old_cs, old_ss, old_esp, old_eip;
dt = &env->idt;
if (intno * 8 + 7 > dt->limit)
raise_exception_err(EXCP0D_GPF, intno * 8 + 2);
@@ -147,6 +204,8 @@ void raise_interrupt(int intno, int is_int, int error_code,
type = (e2 >> DESC_TYPE_SHIFT) & 0x1f;
switch(type) {
case 5: /* task gate */
cpu_abort(env, "task gate not supported");
break;
case 6: /* 286 interrupt gate */
case 7: /* 286 trap gate */
case 14: /* 386 interrupt gate */
@@ -157,26 +216,196 @@ void raise_interrupt(int intno, int is_int, int error_code,
break;
}
dpl = (e2 >> DESC_DPL_SHIFT) & 3;
cpl = env->segs[R_CS] & 3;
if (env->eflags & VM_MASK)
cpl = 3;
else
cpl = env->segs[R_CS].selector & 3;
/* check privledge if software int */
if (is_int && dpl < cpl)
raise_exception_err(EXCP0D_GPF, intno * 8 + 2);
/* check valid bit */
if (!(e2 & DESC_P_MASK))
raise_exception_err(EXCP0B_NOSEG, intno * 8 + 2);
selector = e1 >> 16;
offset = (e2 & 0xffff0000) | (e1 & 0x0000ffff);
if ((selector & 0xfffc) == 0)
raise_exception_err(EXCP0D_GPF, 0);
if (load_segment(&e1, &e2, selector) != 0)
raise_exception_err(EXCP0D_GPF, selector & 0xfffc);
if (!(e2 & DESC_S_MASK) || !(e2 & (DESC_CS_MASK)))
raise_exception_err(EXCP0D_GPF, selector & 0xfffc);
dpl = (e2 >> DESC_DPL_SHIFT) & 3;
if (dpl > cpl)
raise_exception_err(EXCP0D_GPF, selector & 0xfffc);
if (!(e2 & DESC_P_MASK))
raise_exception_err(EXCP0B_NOSEG, selector & 0xfffc);
if (!(e2 & DESC_C_MASK) && dpl < cpl) {
/* to inner priviledge */
get_ss_esp_from_tss(&ss, &esp, dpl);
if ((ss & 0xfffc) == 0)
raise_exception_err(EXCP0A_TSS, ss & 0xfffc);
if ((ss & 3) != dpl)
raise_exception_err(EXCP0A_TSS, ss & 0xfffc);
if (load_segment(&ss_e1, &ss_e2, ss) != 0)
raise_exception_err(EXCP0A_TSS, ss & 0xfffc);
ss_dpl = (ss_e2 >> DESC_DPL_SHIFT) & 3;
if (ss_dpl != dpl)
raise_exception_err(EXCP0A_TSS, ss & 0xfffc);
if (!(ss_e2 & DESC_S_MASK) ||
(ss_e2 & DESC_CS_MASK) ||
!(ss_e2 & DESC_W_MASK))
raise_exception_err(EXCP0A_TSS, ss & 0xfffc);
if (!(ss_e2 & DESC_P_MASK))
raise_exception_err(EXCP0A_TSS, ss & 0xfffc);
new_stack = 1;
} else if ((e2 & DESC_C_MASK) || dpl == cpl) {
/* to same priviledge */
new_stack = 0;
} else {
raise_exception_err(EXCP0D_GPF, selector & 0xfffc);
new_stack = 0; /* avoid warning */
}
shift = type >> 3;
has_error_code = 0;
if (!is_int) {
switch(intno) {
case 8:
case 10:
case 11:
case 12:
case 13:
case 14:
case 17:
has_error_code = 1;
break;
}
}
push_size = 6 + (new_stack << 2) + (has_error_code << 1);
if (env->eflags & VM_MASK)
push_size += 8;
push_size <<= shift;
/* XXX: check that enough room is available */
if (new_stack) {
old_esp = env->regs[R_ESP];
old_ss = env->segs[R_SS].selector;
load_seg(R_SS, ss, env->eip);
} else {
old_esp = 0;
old_ss = 0;
esp = env->regs[R_ESP];
}
if (is_int)
old_eip = next_eip;
else
old_eip = env->eip;
old_cs = env->segs[R_CS].selector;
load_seg(R_CS, selector, env->eip);
env->eip = offset;
env->regs[R_ESP] = esp - push_size;
ssp = env->segs[R_SS].base + esp;
if (shift == 1) {
int old_eflags;
if (env->eflags & VM_MASK) {
ssp -= 4;
stl(ssp, env->segs[R_GS].selector);
ssp -= 4;
stl(ssp, env->segs[R_FS].selector);
ssp -= 4;
stl(ssp, env->segs[R_DS].selector);
ssp -= 4;
stl(ssp, env->segs[R_ES].selector);
}
if (new_stack) {
ssp -= 4;
stl(ssp, old_ss);
ssp -= 4;
stl(ssp, old_esp);
}
ssp -= 4;
old_eflags = compute_eflags();
stl(ssp, old_eflags);
ssp -= 4;
stl(ssp, old_cs);
ssp -= 4;
stl(ssp, old_eip);
if (has_error_code) {
ssp -= 4;
stl(ssp, error_code);
}
} else {
if (new_stack) {
ssp -= 2;
stw(ssp, old_ss);
ssp -= 2;
stw(ssp, old_esp);
}
ssp -= 2;
stw(ssp, compute_eflags());
ssp -= 2;
stw(ssp, old_cs);
ssp -= 2;
stw(ssp, old_eip);
if (has_error_code) {
ssp -= 2;
stw(ssp, error_code);
}
}
/* interrupt gate clear IF mask */
if ((type & 1) == 0) {
env->eflags &= ~IF_MASK;
}
env->eflags &= ~(TF_MASK | VM_MASK | RF_MASK | NT_MASK);
}
#else
/*
* is_int is TRUE if coming from the int instruction. next_eip is the
* EIP value AFTER the interrupt instruction. It is only relevant if
* is_int is TRUE.
*/
void raise_interrupt(int intno, int is_int, int error_code,
unsigned int next_eip)
/* real mode interrupt */
static void do_interrupt_real(int intno, int is_int, int error_code,
unsigned int next_eip)
{
SegmentDescriptorTable *dt;
SegmentCache *dt;
uint8_t *ptr, *ssp;
int selector;
uint32_t offset, esp;
uint32_t old_cs, old_eip;
/* real mode (simpler !) */
dt = &env->idt;
if (intno * 4 + 3 > dt->limit)
raise_exception_err(EXCP0D_GPF, intno * 8 + 2);
ptr = dt->base + intno * 4;
offset = lduw(ptr);
selector = lduw(ptr + 2);
esp = env->regs[R_ESP] & 0xffff;
ssp = env->segs[R_SS].base + esp;
if (is_int)
old_eip = next_eip;
else
old_eip = env->eip;
old_cs = env->segs[R_CS].selector;
ssp -= 2;
stw(ssp, compute_eflags());
ssp -= 2;
stw(ssp, old_cs);
ssp -= 2;
stw(ssp, old_eip);
esp -= 6;
/* update processor state */
env->regs[R_ESP] = (env->regs[R_ESP] & ~0xffff) | (esp & 0xffff);
env->eip = offset;
env->segs[R_CS].selector = selector;
env->segs[R_CS].base = (uint8_t *)(selector << 4);
env->eflags &= ~(IF_MASK | TF_MASK | AC_MASK | RF_MASK);
}
/* fake user mode interrupt */
void do_interrupt_user(int intno, int is_int, int error_code,
unsigned int next_eip)
{
SegmentCache *dt;
uint8_t *ptr;
int dpl, cpl;
uint32_t e2;
@@ -196,13 +425,38 @@ void raise_interrupt(int intno, int is_int, int error_code,
code */
if (is_int)
EIP = next_eip;
env->exception_index = intno;
env->error_code = error_code;
cpu_loop_exit();
}
#endif
/*
* Begin excution of an interruption. is_int is TRUE if coming from
* the int instruction. next_eip is the EIP value AFTER the interrupt
* instruction. It is only relevant if is_int is TRUE.
*/
void do_interrupt(int intno, int is_int, int error_code,
unsigned int next_eip)
{
if (env->cr[0] & CR0_PE_MASK) {
do_interrupt_protected(intno, is_int, error_code, next_eip);
} else {
do_interrupt_real(intno, is_int, error_code, next_eip);
}
}
/*
* Signal an interruption. It is executed in the main CPU loop.
* is_int is TRUE if coming from the int instruction. next_eip is the
* EIP value AFTER the interrupt instruction. It is only relevant if
* is_int is TRUE.
*/
void raise_interrupt(int intno, int is_int, int error_code,
unsigned int next_eip)
{
env->exception_index = intno;
env->error_code = error_code;
env->exception_is_int = is_int;
env->exception_next_eip = next_eip;
cpu_loop_exit();
}
/* shortcuts to generate exceptions */
void raise_exception_err(int exception_index, int error_code)
@@ -321,50 +575,129 @@ void helper_cpuid(void)
ECX = 0x6c65746e;
EDX = 0x49656e69;
} else if (EAX == 1) {
int family, model, stepping;
/* EAX = 1 info */
EAX = 0x52b;
#if 0
/* pentium 75-200 */
family = 5;
model = 2;
stepping = 11;
#else
/* pentium pro */
family = 6;
model = 1;
stepping = 3;
#endif
EAX = (family << 8) | (model << 4) | stepping;
EBX = 0;
ECX = 0;
EDX = CPUID_FP87 | CPUID_DE | CPUID_PSE |
CPUID_TSC | CPUID_MSR | CPUID_MCE |
CPUID_CX8;
CPUID_CX8 | CPUID_PGE | CPUID_CMOV;
}
}
static inline void load_seg_cache(SegmentCache *sc, uint32_t e1, uint32_t e2)
{
sc->base = (void *)((e1 >> 16) | ((e2 & 0xff) << 16) | (e2 & 0xff000000));
sc->limit = (e1 & 0xffff) | (e2 & 0x000f0000);
if (e2 & DESC_G_MASK)
sc->limit = (sc->limit << 12) | 0xfff;
sc->flags = e2;
}
void helper_lldt_T0(void)
{
int selector;
SegmentCache *dt;
uint32_t e1, e2;
int index;
uint8_t *ptr;
selector = T0 & 0xffff;
if ((selector & 0xfffc) == 0) {
/* XXX: NULL selector case: invalid LDT */
env->ldt.base = NULL;
env->ldt.limit = 0;
} else {
if (selector & 0x4)
raise_exception_err(EXCP0D_GPF, selector & 0xfffc);
dt = &env->gdt;
index = selector & ~7;
if ((index + 7) > dt->limit)
raise_exception_err(EXCP0D_GPF, selector & 0xfffc);
ptr = dt->base + index;
e1 = ldl(ptr);
e2 = ldl(ptr + 4);
if ((e2 & DESC_S_MASK) || ((e2 >> DESC_TYPE_SHIFT) & 0xf) != 2)
raise_exception_err(EXCP0D_GPF, selector & 0xfffc);
if (!(e2 & DESC_P_MASK))
raise_exception_err(EXCP0B_NOSEG, selector & 0xfffc);
load_seg_cache(&env->ldt, e1, e2);
}
env->ldt.selector = selector;
}
void helper_ltr_T0(void)
{
int selector;
SegmentCache *dt;
uint32_t e1, e2;
int index, type;
uint8_t *ptr;
selector = T0 & 0xffff;
if ((selector & 0xfffc) == 0) {
/* NULL selector case: invalid LDT */
env->tr.base = NULL;
env->tr.limit = 0;
env->tr.flags = 0;
} else {
if (selector & 0x4)
raise_exception_err(EXCP0D_GPF, selector & 0xfffc);
dt = &env->gdt;
index = selector & ~7;
if ((index + 7) > dt->limit)
raise_exception_err(EXCP0D_GPF, selector & 0xfffc);
ptr = dt->base + index;
e1 = ldl(ptr);
e2 = ldl(ptr + 4);
type = (e2 >> DESC_TYPE_SHIFT) & 0xf;
if ((e2 & DESC_S_MASK) ||
(type != 2 && type != 9))
raise_exception_err(EXCP0D_GPF, selector & 0xfffc);
if (!(e2 & DESC_P_MASK))
raise_exception_err(EXCP0B_NOSEG, selector & 0xfffc);
load_seg_cache(&env->tr, e1, e2);
e2 |= 0x00000200; /* set the busy bit */
stl(ptr + 4, e2);
}
env->tr.selector = selector;
}
/* only works if protected mode and not VM86 */
void load_seg(int seg_reg, int selector, unsigned cur_eip)
void load_seg(int seg_reg, int selector, unsigned int cur_eip)
{
SegmentCache *sc;
SegmentDescriptorTable *dt;
int index;
uint32_t e1, e2;
uint8_t *ptr;
sc = &env->seg_cache[seg_reg];
sc = &env->segs[seg_reg];
if ((selector & 0xfffc) == 0) {
/* null selector case */
if (seg_reg == R_SS) {
EIP = cur_eip;
raise_exception_err(EXCP0D_GPF, selector & 0xfffc);
raise_exception_err(EXCP0D_GPF, 0);
} else {
/* XXX: each access should trigger an exception */
sc->base = NULL;
sc->limit = 0;
sc->seg_32bit = 1;
sc->flags = 0;
}
} else {
if (selector & 0x4)
dt = &env->ldt;
else
dt = &env->gdt;
index = selector & ~7;
if ((index + 7) > dt->limit) {
if (load_segment(&e1, &e2, selector) != 0) {
EIP = cur_eip;
raise_exception_err(EXCP0D_GPF, selector & 0xfffc);
}
ptr = dt->base + index;
e1 = ldl(ptr);
e2 = ldl(ptr + 4);
if (!(e2 & DESC_S_MASK) ||
(e2 & (DESC_CS_MASK | DESC_R_MASK)) == DESC_CS_MASK) {
EIP = cur_eip;
@@ -390,18 +723,210 @@ void load_seg(int seg_reg, int selector, unsigned cur_eip)
else
raise_exception_err(EXCP0B_NOSEG, selector & 0xfffc);
}
sc->base = (void *)((e1 >> 16) | ((e2 & 0xff) << 16) | (e2 & 0xff000000));
sc->limit = (e1 & 0xffff) | (e2 & 0x000f0000);
if (e2 & (1 << 23))
sc->limit = (sc->limit << 12) | 0xfff;
sc->seg_32bit = (e2 >> 22) & 1;
load_seg_cache(sc, e1, e2);
#if 0
fprintf(logfile, "load_seg: sel=0x%04x base=0x%08lx limit=0x%08lx seg_32bit=%d\n",
selector, (unsigned long)sc->base, sc->limit, sc->seg_32bit);
fprintf(logfile, "load_seg: sel=0x%04x base=0x%08lx limit=0x%08lx flags=%08x\n",
selector, (unsigned long)sc->base, sc->limit, sc->flags);
#endif
}
env->segs[seg_reg] = selector;
sc->selector = selector;
}
/* protected mode jump */
void jmp_seg(int selector, unsigned int new_eip)
{
SegmentCache sc1;
uint32_t e1, e2, cpl, dpl, rpl;
if ((selector & 0xfffc) == 0) {
raise_exception_err(EXCP0D_GPF, 0);
}
if (load_segment(&e1, &e2, selector) != 0)
raise_exception_err(EXCP0D_GPF, selector & 0xfffc);
cpl = env->segs[R_CS].selector & 3;
if (e2 & DESC_S_MASK) {
if (!(e2 & DESC_CS_MASK))
raise_exception_err(EXCP0D_GPF, selector & 0xfffc);
dpl = (e2 >> DESC_DPL_SHIFT) & 3;
if (e2 & DESC_CS_MASK) {
/* conforming code segment */
if (dpl > cpl)
raise_exception_err(EXCP0D_GPF, selector & 0xfffc);
} else {
/* non conforming code segment */
rpl = selector & 3;
if (rpl > cpl)
raise_exception_err(EXCP0D_GPF, selector & 0xfffc);
if (dpl != cpl)
raise_exception_err(EXCP0D_GPF, selector & 0xfffc);
}
if (!(e2 & DESC_P_MASK))
raise_exception_err(EXCP0B_NOSEG, selector & 0xfffc);
load_seg_cache(&sc1, e1, e2);
if (new_eip > sc1.limit)
raise_exception_err(EXCP0D_GPF, selector & 0xfffc);
env->segs[R_CS].base = sc1.base;
env->segs[R_CS].limit = sc1.limit;
env->segs[R_CS].flags = sc1.flags;
env->segs[R_CS].selector = (selector & 0xfffc) | cpl;
EIP = new_eip;
} else {
cpu_abort(env, "jmp to call/task gate not supported 0x%04x:0x%08x",
selector, new_eip);
}
}
/* init the segment cache in vm86 mode */
static inline void load_seg_vm(int seg, int selector)
{
SegmentCache *sc = &env->segs[seg];
selector &= 0xffff;
sc->base = (uint8_t *)(selector << 4);
sc->selector = selector;
sc->flags = 0;
sc->limit = 0xffff;
}
/* protected mode iret */
void helper_iret_protected(int shift)
{
uint32_t sp, new_cs, new_eip, new_eflags, new_esp, new_ss;
uint32_t new_es, new_ds, new_fs, new_gs;
uint32_t e1, e2;
int cpl, dpl, rpl, eflags_mask;
uint8_t *ssp;
sp = env->regs[R_ESP];
if (!(env->segs[R_SS].flags & DESC_B_MASK))
sp &= 0xffff;
ssp = env->segs[R_SS].base + sp;
if (shift == 1) {
/* 32 bits */
new_eflags = ldl(ssp + 8);
new_cs = ldl(ssp + 4) & 0xffff;
new_eip = ldl(ssp);
if (new_eflags & VM_MASK)
goto return_to_vm86;
} else {
/* 16 bits */
new_eflags = lduw(ssp + 4);
new_cs = lduw(ssp + 2);
new_eip = lduw(ssp);
}
if ((new_cs & 0xfffc) == 0)
raise_exception_err(EXCP0D_GPF, new_cs & 0xfffc);
if (load_segment(&e1, &e2, new_cs) != 0)
raise_exception_err(EXCP0D_GPF, new_cs & 0xfffc);
if (!(e2 & DESC_S_MASK) ||
!(e2 & DESC_CS_MASK))
raise_exception_err(EXCP0D_GPF, new_cs & 0xfffc);
cpl = env->segs[R_CS].selector & 3;
rpl = new_cs & 3;
if (rpl < cpl)
raise_exception_err(EXCP0D_GPF, new_cs & 0xfffc);
dpl = (e2 >> DESC_DPL_SHIFT) & 3;
if (e2 & DESC_CS_MASK) {
if (dpl > rpl)
raise_exception_err(EXCP0D_GPF, new_cs & 0xfffc);
} else {
if (dpl != rpl)
raise_exception_err(EXCP0D_GPF, new_cs & 0xfffc);
}
if (!(e2 & DESC_P_MASK))
raise_exception_err(EXCP0B_NOSEG, new_cs & 0xfffc);
if (rpl == cpl) {
/* return to same priledge level */
load_seg(R_CS, new_cs, env->eip);
new_esp = sp + (6 << shift);
} else {
/* return to differentr priviledge level */
if (shift == 1) {
/* 32 bits */
new_esp = ldl(ssp + 12);
new_ss = ldl(ssp + 16) & 0xffff;
} else {
/* 16 bits */
new_esp = lduw(ssp + 6);
new_ss = lduw(ssp + 8);
}
if ((new_ss & 3) != rpl)
raise_exception_err(EXCP0D_GPF, new_ss & 0xfffc);
if (load_segment(&e1, &e2, new_ss) != 0)
raise_exception_err(EXCP0D_GPF, new_ss & 0xfffc);
if (!(e2 & DESC_S_MASK) ||
(e2 & DESC_CS_MASK) ||
!(e2 & DESC_W_MASK))
raise_exception_err(EXCP0D_GPF, new_ss & 0xfffc);
dpl = (e2 >> DESC_DPL_SHIFT) & 3;
if (dpl != rpl)
raise_exception_err(EXCP0D_GPF, new_ss & 0xfffc);
if (!(e2 & DESC_P_MASK))
raise_exception_err(EXCP0B_NOSEG, new_ss & 0xfffc);
load_seg(R_CS, new_cs, env->eip);
load_seg(R_SS, new_ss, env->eip);
}
if (env->segs[R_SS].flags & DESC_B_MASK)
env->regs[R_ESP] = new_esp;
else
env->regs[R_ESP] = (env->regs[R_ESP] & 0xffff0000) |
(new_esp & 0xffff);
env->eip = new_eip;
if (cpl == 0)
eflags_mask = FL_UPDATE_CPL0_MASK;
else
eflags_mask = FL_UPDATE_MASK32;
if (shift == 0)
eflags_mask &= 0xffff;
load_eflags(new_eflags, eflags_mask);
return;
return_to_vm86:
new_esp = ldl(ssp + 12);
new_ss = ldl(ssp + 16);
new_es = ldl(ssp + 20);
new_ds = ldl(ssp + 24);
new_fs = ldl(ssp + 28);
new_gs = ldl(ssp + 32);
/* modify processor state */
load_eflags(new_eflags, FL_UPDATE_CPL0_MASK | VM_MASK | VIF_MASK | VIP_MASK);
load_seg_vm(R_CS, new_cs);
load_seg_vm(R_SS, new_ss);
load_seg_vm(R_ES, new_es);
load_seg_vm(R_DS, new_ds);
load_seg_vm(R_FS, new_fs);
load_seg_vm(R_GS, new_gs);
env->eip = new_eip;
env->regs[R_ESP] = new_esp;
}
void helper_movl_crN_T0(int reg)
{
env->cr[reg] = T0;
switch(reg) {
case 0:
cpu_x86_update_cr0(env);
break;
case 3:
cpu_x86_update_cr3(env);
break;
}
}
/* XXX: do more */
void helper_movl_drN_T0(int reg)
{
env->dr[reg] = T0;
}
void helper_invlpg(unsigned int addr)
{
cpu_x86_flush_tlb(env, addr);
}
/* rdtsc */
@@ -422,26 +947,54 @@ void helper_rdtsc(void)
EDX = val >> 32;
}
void helper_wrmsr(void)
{
switch(ECX) {
case MSR_IA32_SYSENTER_CS:
env->sysenter_cs = EAX & 0xffff;
break;
case MSR_IA32_SYSENTER_ESP:
env->sysenter_esp = EAX;
break;
case MSR_IA32_SYSENTER_EIP:
env->sysenter_eip = EAX;
break;
default:
/* XXX: exception ? */
break;
}
}
void helper_rdmsr(void)
{
switch(ECX) {
case MSR_IA32_SYSENTER_CS:
EAX = env->sysenter_cs;
EDX = 0;
break;
case MSR_IA32_SYSENTER_ESP:
EAX = env->sysenter_esp;
EDX = 0;
break;
case MSR_IA32_SYSENTER_EIP:
EAX = env->sysenter_eip;
EDX = 0;
break;
default:
/* XXX: exception ? */
break;
}
}
void helper_lsl(void)
{
unsigned int selector, limit;
SegmentDescriptorTable *dt;
int index;
uint32_t e1, e2;
uint8_t *ptr;
CC_SRC = cc_table[CC_OP].compute_all() & ~CC_Z;
selector = T0 & 0xffff;
if (selector & 0x4)
dt = &env->ldt;
else
dt = &env->gdt;
index = selector & ~7;
if ((index + 7) > dt->limit)
if (load_segment(&e1, &e2, selector) != 0)
return;
ptr = dt->base + index;
e1 = ldl(ptr);
e2 = ldl(ptr + 4);
limit = (e1 & 0xffff) | (e2 & 0x000f0000);
if (e2 & (1 << 23))
limit = (limit << 12) | 0xfff;
@@ -452,22 +1005,12 @@ void helper_lsl(void)
void helper_lar(void)
{
unsigned int selector;
SegmentDescriptorTable *dt;
int index;
uint32_t e2;
uint8_t *ptr;
uint32_t e1, e2;
CC_SRC = cc_table[CC_OP].compute_all() & ~CC_Z;
selector = T0 & 0xffff;
if (selector & 0x4)
dt = &env->ldt;
else
dt = &env->gdt;
index = selector & ~7;
if ((index + 7) > dt->limit)
if (load_segment(&e1, &e2, selector) != 0)
return;
ptr = dt->base + index;
e2 = ldl(ptr + 4);
T1 = e2 & 0x00f0ff00;
CC_SRC |= CC_Z;
}
@@ -477,7 +1020,11 @@ void helper_lar(void)
#ifndef USE_X86LDOUBLE
void helper_fldt_ST0_A0(void)
{
ST0 = helper_fldt((uint8_t *)A0);
int new_fpstt;
new_fpstt = (env->fpstt - 1) & 7;
env->fpregs[new_fpstt] = helper_fldt((uint8_t *)A0);
env->fpstt = new_fpstt;
env->fptags[new_fpstt] = 0; /* validate stack entry */
}
void helper_fstt_ST0_A0(void)
@@ -492,81 +1039,47 @@ void helper_fstt_ST0_A0(void)
void helper_fbld_ST0_A0(void)
{
uint8_t *seg;
CPU86_LDouble fpsrcop;
int m32i;
CPU86_LDouble tmp;
uint64_t val;
unsigned int v;
int i;
/* in this code, seg/m32i will be used as temporary ptr/int */
seg = (uint8_t *)A0 + 8;
v = ldub(seg--);
/* XXX: raise exception */
if (v != 0)
return;
v = ldub(seg--);
/* XXX: raise exception */
if ((v & 0xf0) != 0)
return;
m32i = v; /* <-- d14 */
v = ldub(seg--);
m32i = MUL10(m32i) + (v >> 4); /* <-- val * 10 + d13 */
m32i = MUL10(m32i) + (v & 0xf); /* <-- val * 10 + d12 */
v = ldub(seg--);
m32i = MUL10(m32i) + (v >> 4); /* <-- val * 10 + d11 */
m32i = MUL10(m32i) + (v & 0xf); /* <-- val * 10 + d10 */
v = ldub(seg--);
m32i = MUL10(m32i) + (v >> 4); /* <-- val * 10 + d9 */
m32i = MUL10(m32i) + (v & 0xf); /* <-- val * 10 + d8 */
fpsrcop = ((CPU86_LDouble)m32i) * 100000000.0;
v = ldub(seg--);
m32i = (v >> 4); /* <-- d7 */
m32i = MUL10(m32i) + (v & 0xf); /* <-- val * 10 + d6 */
v = ldub(seg--);
m32i = MUL10(m32i) + (v >> 4); /* <-- val * 10 + d5 */
m32i = MUL10(m32i) + (v & 0xf); /* <-- val * 10 + d4 */
v = ldub(seg--);
m32i = MUL10(m32i) + (v >> 4); /* <-- val * 10 + d3 */
m32i = MUL10(m32i) + (v & 0xf); /* <-- val * 10 + d2 */
v = ldub(seg);
m32i = MUL10(m32i) + (v >> 4); /* <-- val * 10 + d1 */
m32i = MUL10(m32i) + (v & 0xf); /* <-- val * 10 + d0 */
fpsrcop += ((CPU86_LDouble)m32i);
if ( ldub(seg+9) & 0x80 )
fpsrcop = -fpsrcop;
ST0 = fpsrcop;
val = 0;
for(i = 8; i >= 0; i--) {
v = ldub((uint8_t *)A0 + i);
val = (val * 100) + ((v >> 4) * 10) + (v & 0xf);
}
tmp = val;
if (ldub((uint8_t *)A0 + 9) & 0x80)
tmp = -tmp;
fpush();
ST0 = tmp;
}
void helper_fbst_ST0_A0(void)
{
CPU86_LDouble fptemp;
CPU86_LDouble fpsrcop;
CPU86_LDouble tmp;
int v;
uint8_t *mem_ref, *mem_end;
int64_t val;
fpsrcop = rint(ST0);
tmp = rint(ST0);
val = (int64_t)tmp;
mem_ref = (uint8_t *)A0;
mem_end = mem_ref + 8;
if ( fpsrcop < 0.0 ) {
stw(mem_end, 0x8000);
fpsrcop = -fpsrcop;
mem_end = mem_ref + 9;
if (val < 0) {
stb(mem_end, 0x80);
val = -val;
} else {
stw(mem_end, 0x0000);
stb(mem_end, 0x00);
}
while (mem_ref < mem_end) {
if (fpsrcop == 0.0)
if (val == 0)
break;
fptemp = floor(fpsrcop/10.0);
v = ((int)(fpsrcop - fptemp*10.0));
if (fptemp == 0.0) {
stb(mem_ref++, v);
break;
}
fpsrcop = fptemp;
fptemp = floor(fpsrcop/10.0);
v |= (((int)(fpsrcop - fptemp*10.0)) << 4);
v = val % 100;
val = val / 100;
v = ((v / 10) << 4) | (v % 10);
stb(mem_ref++, v);
fpsrcop = fptemp;
}
while (mem_ref < mem_end) {
stb(mem_ref++, 0);
+140
View File
@@ -0,0 +1,140 @@
/* ld script to make i386 Linux kernel
* Written by Martin Mares <mj@atrey.karlin.mff.cuni.cz>;
*/
OUTPUT_FORMAT("elf32-i386", "elf32-i386", "elf32-i386")
OUTPUT_ARCH(i386)
SEARCH_DIR(/lib); SEARCH_DIR(/usr/lib); SEARCH_DIR(/usr/local/lib); SEARCH_DIR(/usr/alpha-unknown-linux-gnu/lib);
ENTRY(_start)
SECTIONS
{
/* Read-only sections, merged into text segment: */
. = 0xa8000000 + SIZEOF_HEADERS;
.interp : { *(.interp) }
.hash : { *(.hash) }
.dynsym : { *(.dynsym) }
.dynstr : { *(.dynstr) }
.gnu.version : { *(.gnu.version) }
.gnu.version_d : { *(.gnu.version_d) }
.gnu.version_r : { *(.gnu.version_r) }
.rel.text :
{ *(.rel.text) *(.rel.gnu.linkonce.t*) }
.rela.text :
{ *(.rela.text) *(.rela.gnu.linkonce.t*) }
.rel.data :
{ *(.rel.data) *(.rel.gnu.linkonce.d*) }
.rela.data :
{ *(.rela.data) *(.rela.gnu.linkonce.d*) }
.rel.rodata :
{ *(.rel.rodata) *(.rel.gnu.linkonce.r*) }
.rela.rodata :
{ *(.rela.rodata) *(.rela.gnu.linkonce.r*) }
.rel.got : { *(.rel.got) }
.rela.got : { *(.rela.got) }
.rel.ctors : { *(.rel.ctors) }
.rela.ctors : { *(.rela.ctors) }
.rel.dtors : { *(.rel.dtors) }
.rela.dtors : { *(.rela.dtors) }
.rel.init : { *(.rel.init) }
.rela.init : { *(.rela.init) }
.rel.fini : { *(.rel.fini) }
.rela.fini : { *(.rela.fini) }
.rel.bss : { *(.rel.bss) }
.rela.bss : { *(.rela.bss) }
.rel.plt : { *(.rel.plt) }
.rela.plt : { *(.rela.plt) }
.init : { *(.init) } =0x47ff041f
.text :
{
*(.text)
/* .gnu.warning sections are handled specially by elf32.em. */
*(.gnu.warning)
*(.gnu.linkonce.t*)
} =0x47ff041f
_etext = .;
PROVIDE (etext = .);
.fini : { *(.fini) } =0x47ff041f
.rodata : { *(.rodata) *(.gnu.linkonce.r*) }
.rodata1 : { *(.rodata1) }
.reginfo : { *(.reginfo) }
__preinit_array_start = .;
.preinit_array : { *(.preinit_array) }
__preinit_array_end = .;
__init_array_start = .;
.init_array : { *(.init_array) }
__init_array_end = .;
__fini_array_start = .;
.fini_array : { *(.fini_array) }
__fini_array_end = .;
/* Adjust the address for the data segment. We want to adjust up to
the same address within the page on the next page up. */
. = ALIGN(0x100000) + (. & (0x100000 - 1));
.data :
{
*(.data)
*(.gnu.linkonce.d*)
CONSTRUCTORS
}
.data1 : { *(.data1) }
.ctors :
{
*(.ctors)
}
.dtors :
{
*(.dtors)
}
.plt : { *(.plt) }
.got : { *(.got.plt) *(.got) }
.dynamic : { *(.dynamic) }
/* We want the small data sections together, so single-instruction offsets
can access them all, and initialized data all before uninitialized, so
we can shorten the on-disk segment size. */
.sdata : { *(.sdata) }
_edata = .;
PROVIDE (edata = .);
__bss_start = .;
.sbss : { *(.sbss) *(.scommon) }
.bss :
{
*(.dynbss)
*(.bss)
*(COMMON)
}
_end = . ;
PROVIDE (end = .);
/* Stabs debugging sections. */
.stab 0 : { *(.stab) }
.stabstr 0 : { *(.stabstr) }
.stab.excl 0 : { *(.stab.excl) }
.stab.exclstr 0 : { *(.stab.exclstr) }
.stab.index 0 : { *(.stab.index) }
.stab.indexstr 0 : { *(.stab.indexstr) }
.comment 0 : { *(.comment) }
/* DWARF debug sections.
Symbols in the DWARF debugging sections are relative to the beginning
of the section so we begin them at 0. */
/* DWARF 1 */
.debug 0 : { *(.debug) }
.line 0 : { *(.line) }
/* GNU DWARF 1 extensions */
.debug_srcinfo 0 : { *(.debug_srcinfo) }
.debug_sfnames 0 : { *(.debug_sfnames) }
/* DWARF 1.1 and DWARF 2 */
.debug_aranges 0 : { *(.debug_aranges) }
.debug_pubnames 0 : { *(.debug_pubnames) }
/* DWARF 2 */
.debug_info 0 : { *(.debug_info) }
.debug_abbrev 0 : { *(.debug_abbrev) }
.debug_line 0 : { *(.debug_line) }
.debug_frame 0 : { *(.debug_frame) }
.debug_str 0 : { *(.debug_str) }
.debug_loc 0 : { *(.debug_loc) }
.debug_macinfo 0 : { *(.debug_macinfo) }
/* SGI/MIPS DWARF 2 extensions */
.debug_weaknames 0 : { *(.debug_weaknames) }
.debug_funcnames 0 : { *(.debug_funcnames) }
.debug_typenames 0 : { *(.debug_typenames) }
.debug_varnames 0 : { *(.debug_varnames) }
/* These must appear regardless of . */
}
+16 -16
View File
@@ -74,7 +74,8 @@ static inline void init_thread(struct target_pt_regs *regs, struct image_info *i
regs->ARM_sp = infop->start_stack;
regs->ARM_r2 = tswapl(stack[2]); /* envp */
regs->ARM_r1 = tswapl(stack[1]); /* argv */
regs->ARM_r0 = tswapl(stack[0]); /* argc */
/* XXX: it seems that r0 is zeroed after ! */
// regs->ARM_r0 = tswapl(stack[0]); /* argc */
}
#define USE_ELF_CORE_DUMP
@@ -490,7 +491,7 @@ static unsigned int * create_elf_tables(char *p, int argc, int envc,
* Force 16 byte alignment here for generality.
*/
sp = (unsigned int *) (~15UL & (unsigned long) p);
sp -= exec ? DLINFO_ITEMS*2 : 2;
sp -= DLINFO_ITEMS*2;
dlinfo = sp;
sp -= envc+1;
envp = sp;
@@ -505,21 +506,20 @@ static unsigned int * create_elf_tables(char *p, int argc, int envc,
put_user (tswapl(id), dlinfo++); \
put_user (tswapl(val), dlinfo++)
if (exec) { /* Put this here for an ELF program interpreter */
NEW_AUX_ENT (AT_PHDR, (target_ulong)(load_addr + exec->e_phoff));
NEW_AUX_ENT (AT_PHENT, (target_ulong)(sizeof (struct elf_phdr)));
NEW_AUX_ENT (AT_PHNUM, (target_ulong)(exec->e_phnum));
NEW_AUX_ENT (AT_PAGESZ, (target_ulong)(TARGET_PAGE_SIZE));
NEW_AUX_ENT (AT_BASE, (target_ulong)(interp_load_addr));
NEW_AUX_ENT (AT_FLAGS, (target_ulong)0);
NEW_AUX_ENT (AT_ENTRY, load_bias + exec->e_entry);
NEW_AUX_ENT (AT_UID, (target_ulong) getuid());
NEW_AUX_ENT (AT_EUID, (target_ulong) geteuid());
NEW_AUX_ENT (AT_GID, (target_ulong) getgid());
NEW_AUX_ENT (AT_EGID, (target_ulong) getegid());
}
NEW_AUX_ENT (AT_PHDR, (target_ulong)(load_addr + exec->e_phoff));
NEW_AUX_ENT (AT_PHENT, (target_ulong)(sizeof (struct elf_phdr)));
NEW_AUX_ENT (AT_PHNUM, (target_ulong)(exec->e_phnum));
NEW_AUX_ENT (AT_PAGESZ, (target_ulong)(TARGET_PAGE_SIZE));
NEW_AUX_ENT (AT_BASE, (target_ulong)(interp_load_addr));
NEW_AUX_ENT (AT_FLAGS, (target_ulong)0);
NEW_AUX_ENT (AT_ENTRY, load_bias + exec->e_entry);
NEW_AUX_ENT (AT_UID, (target_ulong) getuid());
NEW_AUX_ENT (AT_EUID, (target_ulong) geteuid());
NEW_AUX_ENT (AT_GID, (target_ulong) getgid());
NEW_AUX_ENT (AT_EGID, (target_ulong) getegid());
NEW_AUX_ENT (AT_NULL, 0);
#undef NEW_AUX_ENT
put_user(tswapl(argc),--sp);
info->arg_start = (unsigned int)((unsigned long)p & 0xffffffff);
while (argc-->0) {
@@ -1087,7 +1087,7 @@ static int load_elf_binary(struct linux_binprm * bprm, struct target_pt_regs * r
create_elf_tables((char *)bprm->p,
bprm->argc,
bprm->envc,
(interpreter_type == INTERPRETER_ELF ? &elf_ex : NULL),
&elf_ex,
load_addr, load_bias,
interp_load_addr,
(interpreter_type == INTERPRETER_AOUT ? 0 : 1),
+16 -7
View File
@@ -26,8 +26,6 @@
#include "qemu.h"
#include "cpu-i386.h"
#define DEBUG_LOGFILE "/tmp/qemu.log"
FILE *logfile = NULL;
@@ -100,6 +98,11 @@ int cpu_x86_inl(CPUX86State *env, int addr)
return 0;
}
int cpu_x86_get_pic_interrupt(CPUX86State *env)
{
return -1;
}
static void write_dt(void *ptr, unsigned long addr, unsigned long limit,
int flags)
{
@@ -176,7 +179,7 @@ void cpu_loop(CPUX86State *env)
info.si_code = TARGET_SEGV_MAPERR;
else
info.si_code = TARGET_SEGV_ACCERR;
info._sifields._sigfault._addr = env->cr2;
info._sifields._sigfault._addr = env->cr[2];
queue_signal(info.si_signo, &info);
break;
case EXCP00_DIVZ:
@@ -231,7 +234,7 @@ void cpu_loop(CPUX86State *env)
/* just indicate that signals should be handled asap */
break;
default:
pc = env->seg_cache[R_CS].base + env->eip;
pc = env->segs[R_CS].base + env->eip;
fprintf(stderr, "qemu: 0x%08lx: unhandled CPU exception 0x%x - aborting\n",
(long)pc, trapnr);
abort();
@@ -243,8 +246,6 @@ void cpu_loop(CPUX86State *env)
#ifdef TARGET_ARM
#define ARM_SYSCALL_BASE 0x900000
void cpu_loop(CPUARMState *env)
{
int trapnr;
@@ -282,6 +283,9 @@ void cpu_loop(CPUARMState *env)
}
}
break;
case EXCP_INTERRUPT:
/* just indicate that signals should be handled asap */
break;
default:
error:
fprintf(stderr, "qemu: unhandled CPU exception 0x%x - aborting\n",
@@ -317,6 +321,9 @@ void usage(void)
/* XXX: currently only used for async signals (see signal.c) */
CPUState *global_env;
/* used only if single thread */
CPUState *cpu_single_env = NULL;
/* used to free thread contexts */
TaskState *first_task_state;
@@ -395,7 +402,7 @@ int main(int argc, char **argv)
/* NOTE: we need to init the CPU at this stage to get the
host_page_size */
env = cpu_init();
if (elf_exec(filename, argv+optind, environ, regs, info) != 0) {
printf("Error loading %s\n", filename);
_exit(1);
@@ -423,6 +430,7 @@ int main(int argc, char **argv)
memset(ts, 0, sizeof(TaskState));
env->opaque = ts;
ts->used = 1;
env->user_mode_only = 1;
#if defined(TARGET_I386)
/* linux register setup */
@@ -476,6 +484,7 @@ int main(int argc, char **argv)
cpu_x86_load_seg(env, R_SS, __USER_DS);
cpu_x86_load_seg(env, R_FS, __USER_DS);
cpu_x86_load_seg(env, R_GS, __USER_DS);
#elif defined(TARGET_ARM)
{
int i;
+9 -2
View File
@@ -6,8 +6,15 @@
#include <signal.h>
#include "syscall_defs.h"
#include "cpu-" TARGET_ARCH ".h"
#include "syscall-" TARGET_ARCH ".h"
#if defined(TARGET_I386)
#include "cpu-i386.h"
#include "syscall-i386.h"
#elif defined(TARGET_ARM)
#include "cpu-arm.h"
#include "syscall-arm.h"
#else
#error unsupported target CPU
#endif
/* This struct is used to hold certain information about the image.
* Basically, it replicates in user space what would be certain
+559 -63
View File
@@ -60,44 +60,122 @@ static int signal_pending; /* non zero if a signal may be pending */
static void host_signal_handler(int host_signum, siginfo_t *info,
void *puc);
/* XXX: do it properly */
static uint8_t host_to_target_signal_table[65] = {
[SIGHUP] = TARGET_SIGHUP,
[SIGINT] = TARGET_SIGINT,
[SIGQUIT] = TARGET_SIGQUIT,
[SIGILL] = TARGET_SIGILL,
[SIGTRAP] = TARGET_SIGTRAP,
[SIGABRT] = TARGET_SIGABRT,
[SIGIOT] = TARGET_SIGIOT,
[SIGBUS] = TARGET_SIGBUS,
[SIGFPE] = TARGET_SIGFPE,
[SIGKILL] = TARGET_SIGKILL,
[SIGUSR1] = TARGET_SIGUSR1,
[SIGSEGV] = TARGET_SIGSEGV,
[SIGUSR2] = TARGET_SIGUSR2,
[SIGPIPE] = TARGET_SIGPIPE,
[SIGALRM] = TARGET_SIGALRM,
[SIGTERM] = TARGET_SIGTERM,
#ifdef SIGSTKFLT
[SIGSTKFLT] = TARGET_SIGSTKFLT,
#endif
[SIGCHLD] = TARGET_SIGCHLD,
[SIGCONT] = TARGET_SIGCONT,
[SIGSTOP] = TARGET_SIGSTOP,
[SIGTSTP] = TARGET_SIGTSTP,
[SIGTTIN] = TARGET_SIGTTIN,
[SIGTTOU] = TARGET_SIGTTOU,
[SIGURG] = TARGET_SIGURG,
[SIGXCPU] = TARGET_SIGXCPU,
[SIGXFSZ] = TARGET_SIGXFSZ,
[SIGVTALRM] = TARGET_SIGVTALRM,
[SIGPROF] = TARGET_SIGPROF,
[SIGWINCH] = TARGET_SIGWINCH,
[SIGIO] = TARGET_SIGIO,
[SIGPWR] = TARGET_SIGPWR,
[SIGSYS] = TARGET_SIGSYS,
/* next signals stay the same */
};
static uint8_t target_to_host_signal_table[65];
static inline int host_to_target_signal(int sig)
{
return sig;
return host_to_target_signal_table[sig];
}
static inline int target_to_host_signal(int sig)
{
return sig;
return target_to_host_signal_table[sig];
}
void host_to_target_sigset(target_sigset_t *d, sigset_t *s)
void host_to_target_sigset(target_sigset_t *d, const sigset_t *s)
{
int i;
for(i = 0;i < TARGET_NSIG_WORDS; i++) {
unsigned long sigmask;
uint32_t target_sigmask;
sigmask = ((unsigned long *)s)[0];
target_sigmask = 0;
for(i = 0; i < 32; i++) {
if (sigmask & (1 << i))
target_sigmask |= 1 << (host_to_target_signal(i + 1) - 1);
}
#if TARGET_LONG_BITS == 32 && HOST_LONG_BITS == 32
d->sig[0] = tswapl(target_sigmask);
for(i = 1;i < TARGET_NSIG_WORDS; i++) {
d->sig[i] = tswapl(((unsigned long *)s)[i]);
}
#elif TARGET_LONG_BITS == 32 && HOST_LONG_BITS == 64 && TARGET_NSIG_WORDS == 2
d->sig[0] = tswapl(target_sigmask);
d->sig[1] = tswapl(sigmask >> 32);
#else
#error host_to_target_sigset
#endif
}
void target_to_host_sigset(sigset_t *d, target_sigset_t *s)
void target_to_host_sigset(sigset_t *d, const target_sigset_t *s)
{
int i;
for(i = 0;i < TARGET_NSIG_WORDS; i++) {
unsigned long sigmask;
target_ulong target_sigmask;
target_sigmask = tswapl(s->sig[0]);
sigmask = 0;
for(i = 0; i < 32; i++) {
if (target_sigmask & (1 << i))
sigmask |= 1 << (target_to_host_signal(i + 1) - 1);
}
#if TARGET_LONG_BITS == 32 && HOST_LONG_BITS == 32
((unsigned long *)d)[0] = sigmask;
for(i = 1;i < TARGET_NSIG_WORDS; i++) {
((unsigned long *)d)[i] = tswapl(s->sig[i]);
}
#elif TARGET_LONG_BITS == 32 && HOST_LONG_BITS == 64 && TARGET_NSIG_WORDS == 2
((unsigned long *)d)[0] = sigmask | (tswapl(s->sig[1]) << 32);
#else
#error target_to_host_sigset
#endif /* TARGET_LONG_BITS */
}
void host_to_target_old_sigset(target_ulong *old_sigset,
const sigset_t *sigset)
{
*old_sigset = tswap32(*(unsigned long *)sigset & 0xffffffff);
target_sigset_t d;
host_to_target_sigset(&d, sigset);
*old_sigset = d.sig[0];
}
void target_to_host_old_sigset(sigset_t *sigset,
const target_ulong *old_sigset)
{
sigemptyset(sigset);
*(unsigned long *)sigset = tswapl(*old_sigset);
target_sigset_t d;
int i;
d.sig[0] = *old_sigset;
for(i = 1;i < TARGET_NSIG_WORDS; i++)
d.sig[i] = 0;
target_to_host_sigset(sigset, &d);
}
/* siginfo conversion */
@@ -167,8 +245,18 @@ void target_to_host_siginfo(siginfo_t *info, const target_siginfo_t *tinfo)
void signal_init(void)
{
struct sigaction act;
int i;
int i, j;
/* generate signal conversion tables */
for(i = 1; i <= 64; i++) {
if (host_to_target_signal_table[i] == 0)
host_to_target_signal_table[i] = i;
}
for(i = 1; i <= 64; i++) {
j = host_to_target_signal_table[i];
target_to_host_signal_table[j] = i;
}
/* set all host signal handlers. ALL signals are blocked during
the handlers to serialize them. */
sigfillset(&act.sa_mask);
@@ -333,7 +421,7 @@ static void host_signal_handler(int host_signum, siginfo_t *info,
host_to_target_siginfo_noswap(&tinfo, info);
if (queue_signal(sig, &tinfo) == 1) {
/* interrupt the virtual CPU as soon as possible */
cpu_interrupt(global_env);
cpu_interrupt(global_env, CPU_INTERRUPT_EXIT);
}
}
@@ -364,6 +452,80 @@ int do_sigaction(int sig, const struct target_sigaction *act,
return 0;
}
#define __put_user(x,ptr)\
({\
int size = sizeof(*ptr);\
switch(size) {\
case 1:\
stb(ptr, (typeof(*ptr))(x));\
break;\
case 2:\
stw(ptr, (typeof(*ptr))(x));\
break;\
case 4:\
stl(ptr, (typeof(*ptr))(x));\
break;\
case 8:\
stq(ptr, (typeof(*ptr))(x));\
break;\
default:\
abort();\
}\
0;\
})
#define __get_user(x, ptr) \
({\
int size = sizeof(*ptr);\
switch(size) {\
case 1:\
x = (typeof(*ptr))ldub(ptr);\
break;\
case 2:\
x = (typeof(*ptr))lduw(ptr);\
break;\
case 4:\
x = (typeof(*ptr))ldl(ptr);\
break;\
case 8:\
x = (typeof(*ptr))ldq(ptr);\
break;\
default:\
abort();\
}\
0;\
})
#define __copy_to_user(dst, src, size)\
({\
memcpy(dst, src, size);\
0;\
})
#define __copy_from_user(dst, src, size)\
({\
memcpy(dst, src, size);\
0;\
})
#define __clear_user(dst, size)\
({\
memset(dst, 0, size);\
0;\
})
#ifndef offsetof
#define offsetof(type, field) ((size_t) &((type *)0)->field)
#endif
static inline int copy_siginfo_to_user(target_siginfo_t *tinfo,
const target_siginfo_t *info)
{
tswap_siginfo(tinfo, info);
return 0;
}
#ifdef TARGET_I386
/* from the Linux kernel */
@@ -472,44 +634,6 @@ struct rt_sigframe
* Set up a signal frame.
*/
#define __put_user(x,ptr)\
({\
int size = sizeof(*ptr);\
switch(size) {\
case 1:\
stb(ptr, (typeof(*ptr))(x));\
break;\
case 2:\
stw(ptr, (typeof(*ptr))(x));\
break;\
case 4:\
stl(ptr, (typeof(*ptr))(x));\
break;\
case 8:\
stq(ptr, (typeof(*ptr))(x));\
break;\
default:\
abort();\
}\
0;\
})
#define get_user(val, ptr) (typeof(*ptr))(*(ptr))
#define __copy_to_user(dst, src, size)\
({\
memcpy(dst, src, size);\
0;\
})
static inline int copy_siginfo_to_user(target_siginfo_t *tinfo,
const target_siginfo_t *info)
{
tswap_siginfo(tinfo, info);
return 0;
}
/* XXX: save x87 state */
static int
setup_sigcontext(struct target_sigcontext *sc, struct target_fpstate *fpstate,
@@ -517,10 +641,10 @@ setup_sigcontext(struct target_sigcontext *sc, struct target_fpstate *fpstate,
{
int err = 0;
err |= __put_user(env->segs[R_GS], (unsigned int *)&sc->gs);
err |= __put_user(env->segs[R_FS], (unsigned int *)&sc->fs);
err |= __put_user(env->segs[R_ES], (unsigned int *)&sc->es);
err |= __put_user(env->segs[R_DS], (unsigned int *)&sc->ds);
err |= __put_user(env->segs[R_GS].selector, (unsigned int *)&sc->gs);
err |= __put_user(env->segs[R_FS].selector, (unsigned int *)&sc->fs);
err |= __put_user(env->segs[R_ES].selector, (unsigned int *)&sc->es);
err |= __put_user(env->segs[R_DS].selector, (unsigned int *)&sc->ds);
err |= __put_user(env->regs[R_EDI], &sc->edi);
err |= __put_user(env->regs[R_ESI], &sc->esi);
err |= __put_user(env->regs[R_EBP], &sc->ebp);
@@ -532,10 +656,10 @@ setup_sigcontext(struct target_sigcontext *sc, struct target_fpstate *fpstate,
err |= __put_user(env->exception_index, &sc->trapno);
err |= __put_user(env->error_code, &sc->err);
err |= __put_user(env->eip, &sc->eip);
err |= __put_user(env->segs[R_CS], (unsigned int *)&sc->cs);
err |= __put_user(env->segs[R_CS].selector, (unsigned int *)&sc->cs);
err |= __put_user(env->eflags, &sc->eflags);
err |= __put_user(env->regs[R_ESP], &sc->esp_at_signal);
err |= __put_user(env->segs[R_SS], (unsigned int *)&sc->ss);
err |= __put_user(env->segs[R_SS].selector, (unsigned int *)&sc->ss);
cpu_x86_fsave(env, (void *)fpstate, 1);
fpstate->status = fpstate->sw;
@@ -544,7 +668,7 @@ setup_sigcontext(struct target_sigcontext *sc, struct target_fpstate *fpstate,
/* non-iBCS2 extensions.. */
err |= __put_user(mask, &sc->oldmask);
err |= __put_user(env->cr2, &sc->cr2);
err |= __put_user(env->cr[2], &sc->cr2);
return err;
}
@@ -567,13 +691,14 @@ get_sigframe(struct emulated_sigaction *ka, CPUX86State *env, size_t frame_size)
}
/* This is the legacy signal stack switching. */
else if ((regs->xss & 0xffff) != __USER_DS &&
!(ka->sa.sa_flags & SA_RESTORER) &&
ka->sa.sa_restorer) {
esp = (unsigned long) ka->sa.sa_restorer;
}
else
#endif
return (void *)((esp - frame_size) & -8ul);
if ((env->segs[R_SS].selector & 0xffff) != __USER_DS &&
!(ka->sa.sa_flags & TARGET_SA_RESTORER) &&
ka->sa.sa_restorer) {
esp = (unsigned long) ka->sa.sa_restorer;
}
return (void *)((esp - frame_size) & -8ul);
}
static void setup_frame(int sig, struct emulated_sigaction *ka,
@@ -824,6 +949,377 @@ badframe:
return 0;
}
#elif defined(TARGET_ARM)
struct target_sigcontext {
target_ulong trap_no;
target_ulong error_code;
target_ulong oldmask;
target_ulong arm_r0;
target_ulong arm_r1;
target_ulong arm_r2;
target_ulong arm_r3;
target_ulong arm_r4;
target_ulong arm_r5;
target_ulong arm_r6;
target_ulong arm_r7;
target_ulong arm_r8;
target_ulong arm_r9;
target_ulong arm_r10;
target_ulong arm_fp;
target_ulong arm_ip;
target_ulong arm_sp;
target_ulong arm_lr;
target_ulong arm_pc;
target_ulong arm_cpsr;
target_ulong fault_address;
};
typedef struct target_sigaltstack {
target_ulong ss_sp;
int ss_flags;
target_ulong ss_size;
} target_stack_t;
struct target_ucontext {
target_ulong uc_flags;
target_ulong uc_link;
target_stack_t uc_stack;
struct target_sigcontext uc_mcontext;
target_sigset_t uc_sigmask; /* mask last for extensibility */
};
struct sigframe
{
struct target_sigcontext sc;
target_ulong extramask[TARGET_NSIG_WORDS-1];
target_ulong retcode;
};
struct rt_sigframe
{
struct target_siginfo *pinfo;
void *puc;
struct target_siginfo info;
struct target_ucontext uc;
target_ulong retcode;
};
#define TARGET_CONFIG_CPU_32 1
/*
* For ARM syscalls, we encode the syscall number into the instruction.
*/
#define SWI_SYS_SIGRETURN (0xef000000|(TARGET_NR_sigreturn + ARM_SYSCALL_BASE))
#define SWI_SYS_RT_SIGRETURN (0xef000000|(TARGET_NR_rt_sigreturn + ARM_SYSCALL_BASE))
/*
* For Thumb syscalls, we pass the syscall number via r7. We therefore
* need two 16-bit instructions.
*/
#define SWI_THUMB_SIGRETURN (0xdf00 << 16 | 0x2700 | (TARGET_NR_sigreturn))
#define SWI_THUMB_RT_SIGRETURN (0xdf00 << 16 | 0x2700 | (TARGET_NR_rt_sigreturn))
static const target_ulong retcodes[4] = {
SWI_SYS_SIGRETURN, SWI_THUMB_SIGRETURN,
SWI_SYS_RT_SIGRETURN, SWI_THUMB_RT_SIGRETURN
};
#define __put_user_error(x,p,e) __put_user(x, p)
#define __get_user_error(x,p,e) __get_user(x, p)
static inline int valid_user_regs(CPUState *regs)
{
return 1;
}
static int
setup_sigcontext(struct target_sigcontext *sc, /*struct _fpstate *fpstate,*/
CPUState *env, unsigned long mask)
{
int err = 0;
__put_user_error(env->regs[0], &sc->arm_r0, err);
__put_user_error(env->regs[1], &sc->arm_r1, err);
__put_user_error(env->regs[2], &sc->arm_r2, err);
__put_user_error(env->regs[3], &sc->arm_r3, err);
__put_user_error(env->regs[4], &sc->arm_r4, err);
__put_user_error(env->regs[5], &sc->arm_r5, err);
__put_user_error(env->regs[6], &sc->arm_r6, err);
__put_user_error(env->regs[7], &sc->arm_r7, err);
__put_user_error(env->regs[8], &sc->arm_r8, err);
__put_user_error(env->regs[9], &sc->arm_r9, err);
__put_user_error(env->regs[10], &sc->arm_r10, err);
__put_user_error(env->regs[11], &sc->arm_fp, err);
__put_user_error(env->regs[12], &sc->arm_ip, err);
__put_user_error(env->regs[13], &sc->arm_sp, err);
__put_user_error(env->regs[14], &sc->arm_lr, err);
__put_user_error(env->regs[15], &sc->arm_pc, err);
#ifdef TARGET_CONFIG_CPU_32
__put_user_error(env->cpsr, &sc->arm_cpsr, err);
#endif
__put_user_error(/* current->thread.trap_no */ 0, &sc->trap_no, err);
__put_user_error(/* current->thread.error_code */ 0, &sc->error_code, err);
__put_user_error(/* current->thread.address */ 0, &sc->fault_address, err);
__put_user_error(mask, &sc->oldmask, err);
return err;
}
static inline void *
get_sigframe(struct emulated_sigaction *ka, CPUState *regs, int framesize)
{
unsigned long sp = regs->regs[13];
#if 0
/*
* This is the X/Open sanctioned signal stack switching.
*/
if ((ka->sa.sa_flags & SA_ONSTACK) && !sas_ss_flags(sp))
sp = current->sas_ss_sp + current->sas_ss_size;
#endif
/*
* ATPCS B01 mandates 8-byte alignment
*/
return (void *)((sp - framesize) & ~7);
}
static int
setup_return(CPUState *env, struct emulated_sigaction *ka,
target_ulong *rc, void *frame, int usig)
{
target_ulong handler = (target_ulong)ka->sa._sa_handler;
target_ulong retcode;
int thumb = 0;
#if defined(TARGET_CONFIG_CPU_32)
target_ulong cpsr = env->cpsr;
#if 0
/*
* Maybe we need to deliver a 32-bit signal to a 26-bit task.
*/
if (ka->sa.sa_flags & SA_THIRTYTWO)
cpsr = (cpsr & ~MODE_MASK) | USR_MODE;
#ifdef CONFIG_ARM_THUMB
if (elf_hwcap & HWCAP_THUMB) {
/*
* The LSB of the handler determines if we're going to
* be using THUMB or ARM mode for this signal handler.
*/
thumb = handler & 1;
if (thumb)
cpsr |= T_BIT;
else
cpsr &= ~T_BIT;
}
#endif
#endif
#endif /* TARGET_CONFIG_CPU_32 */
if (ka->sa.sa_flags & TARGET_SA_RESTORER) {
retcode = (target_ulong)ka->sa.sa_restorer;
} else {
unsigned int idx = thumb;
if (ka->sa.sa_flags & TARGET_SA_SIGINFO)
idx += 2;
if (__put_user(retcodes[idx], rc))
return 1;
#if 0
flush_icache_range((target_ulong)rc,
(target_ulong)(rc + 1));
#endif
retcode = ((target_ulong)rc) + thumb;
}
env->regs[0] = usig;
env->regs[13] = (target_ulong)frame;
env->regs[14] = retcode;
env->regs[15] = handler & (thumb ? ~1 : ~3);
#ifdef TARGET_CONFIG_CPU_32
env->cpsr = cpsr;
#endif
return 0;
}
static void setup_frame(int usig, struct emulated_sigaction *ka,
target_sigset_t *set, CPUState *regs)
{
struct sigframe *frame = get_sigframe(ka, regs, sizeof(*frame));
int err = 0;
err |= setup_sigcontext(&frame->sc, /*&frame->fpstate,*/ regs, set->sig[0]);
if (TARGET_NSIG_WORDS > 1) {
err |= __copy_to_user(frame->extramask, &set->sig[1],
sizeof(frame->extramask));
}
if (err == 0)
err = setup_return(regs, ka, &frame->retcode, frame, usig);
// return err;
}
static void setup_rt_frame(int usig, struct emulated_sigaction *ka,
target_siginfo_t *info,
target_sigset_t *set, CPUState *env)
{
struct rt_sigframe *frame = get_sigframe(ka, env, sizeof(*frame));
int err = 0;
#if 0
if (!access_ok(VERIFY_WRITE, frame, sizeof (*frame)))
return 1;
#endif
__put_user_error(&frame->info, (target_ulong *)&frame->pinfo, err);
__put_user_error(&frame->uc, (target_ulong *)&frame->puc, err);
err |= copy_siginfo_to_user(&frame->info, info);
/* Clear all the bits of the ucontext we don't use. */
err |= __clear_user(&frame->uc, offsetof(struct ucontext, uc_mcontext));
err |= setup_sigcontext(&frame->uc.uc_mcontext, /*&frame->fpstate,*/
env, set->sig[0]);
err |= __copy_to_user(&frame->uc.uc_sigmask, set, sizeof(*set));
if (err == 0)
err = setup_return(env, ka, &frame->retcode, frame, usig);
if (err == 0) {
/*
* For realtime signals we must also set the second and third
* arguments for the signal handler.
* -- Peter Maydell <pmaydell@chiark.greenend.org.uk> 2000-12-06
*/
env->regs[1] = (target_ulong)frame->pinfo;
env->regs[2] = (target_ulong)frame->puc;
}
// return err;
}
static int
restore_sigcontext(CPUState *env, struct target_sigcontext *sc)
{
int err = 0;
__get_user_error(env->regs[0], &sc->arm_r0, err);
__get_user_error(env->regs[1], &sc->arm_r1, err);
__get_user_error(env->regs[2], &sc->arm_r2, err);
__get_user_error(env->regs[3], &sc->arm_r3, err);
__get_user_error(env->regs[4], &sc->arm_r4, err);
__get_user_error(env->regs[5], &sc->arm_r5, err);
__get_user_error(env->regs[6], &sc->arm_r6, err);
__get_user_error(env->regs[7], &sc->arm_r7, err);
__get_user_error(env->regs[8], &sc->arm_r8, err);
__get_user_error(env->regs[9], &sc->arm_r9, err);
__get_user_error(env->regs[10], &sc->arm_r10, err);
__get_user_error(env->regs[11], &sc->arm_fp, err);
__get_user_error(env->regs[12], &sc->arm_ip, err);
__get_user_error(env->regs[13], &sc->arm_sp, err);
__get_user_error(env->regs[14], &sc->arm_lr, err);
__get_user_error(env->regs[15], &sc->arm_pc, err);
#ifdef TARGET_CONFIG_CPU_32
__get_user_error(env->cpsr, &sc->arm_cpsr, err);
#endif
err |= !valid_user_regs(env);
return err;
}
long do_sigreturn(CPUState *env)
{
struct sigframe *frame;
target_sigset_t set;
sigset_t host_set;
/*
* Since we stacked the signal on a 64-bit boundary,
* then 'sp' should be word aligned here. If it's
* not, then the user is trying to mess with us.
*/
if (env->regs[13] & 7)
goto badframe;
frame = (struct sigframe *)env->regs[13];
#if 0
if (verify_area(VERIFY_READ, frame, sizeof (*frame)))
goto badframe;
#endif
if (__get_user(set.sig[0], &frame->sc.oldmask)
|| (TARGET_NSIG_WORDS > 1
&& __copy_from_user(&set.sig[1], &frame->extramask,
sizeof(frame->extramask))))
goto badframe;
target_to_host_sigset(&host_set, &set);
sigprocmask(SIG_SETMASK, &host_set, NULL);
if (restore_sigcontext(env, &frame->sc))
goto badframe;
#if 0
/* Send SIGTRAP if we're single-stepping */
if (ptrace_cancel_bpt(current))
send_sig(SIGTRAP, current, 1);
#endif
return env->regs[0];
badframe:
force_sig(SIGSEGV /* , current */);
return 0;
}
long do_rt_sigreturn(CPUState *env)
{
struct rt_sigframe *frame;
target_sigset_t set;
sigset_t host_set;
/*
* Since we stacked the signal on a 64-bit boundary,
* then 'sp' should be word aligned here. If it's
* not, then the user is trying to mess with us.
*/
if (env->regs[13] & 7)
goto badframe;
frame = (struct rt_sigframe *)env->regs[13];
#if 0
if (verify_area(VERIFY_READ, frame, sizeof (*frame)))
goto badframe;
#endif
if (__copy_from_user(&set, &frame->uc.uc_sigmask, sizeof(set)))
goto badframe;
target_to_host_sigset(&host_set, &set);
sigprocmask(SIG_SETMASK, &host_set, NULL);
if (restore_sigcontext(env, &frame->uc.uc_mcontext))
goto badframe;
#if 0
/* Send SIGTRAP if we're single-stepping */
if (ptrace_cancel_bpt(current))
send_sig(SIGTRAP, current, 1);
#endif
return env->regs[0];
badframe:
force_sig(SIGSEGV /* , current */);
return 0;
}
#else
static void setup_frame(int sig, struct emulated_sigaction *ka,
+39 -11
View File
@@ -210,6 +210,21 @@ static inline void host_to_target_fds(target_long *target_fds,
#endif
}
#if defined(__alpha__)
#define HOST_HZ 1024
#else
#define HOST_HZ 100
#endif
static inline long host_to_target_clock_t(long ticks)
{
#if HOST_HZ == TARGET_HZ
return ticks;
#else
return ((int64_t)ticks * TARGET_HZ) / HOST_HZ;
#endif
}
static inline void host_to_target_rusage(struct target_rusage *target_rusage,
const struct rusage *rusage)
{
@@ -1423,11 +1438,13 @@ long do_syscall(void *cpu_env, int num, long arg1, long arg2, long arg3,
struct tms tms;
ret = get_errno(times(&tms));
if (tmsp) {
tmsp->tms_utime = tswapl(tms.tms_utime);
tmsp->tms_stime = tswapl(tms.tms_stime);
tmsp->tms_cutime = tswapl(tms.tms_cutime);
tmsp->tms_cstime = tswapl(tms.tms_cstime);
tmsp->tms_utime = tswapl(host_to_target_clock_t(tms.tms_utime));
tmsp->tms_stime = tswapl(host_to_target_clock_t(tms.tms_stime));
tmsp->tms_cutime = tswapl(host_to_target_clock_t(tms.tms_cutime));
tmsp->tms_cstime = tswapl(host_to_target_clock_t(tms.tms_cstime));
}
if (!is_error(ret))
ret = host_to_target_clock_t(ret);
}
break;
case TARGET_NR_prof:
@@ -1763,7 +1780,17 @@ long do_syscall(void *cpu_env, int num, long arg1, long arg2, long arg3,
}
break;
case TARGET_NR_select:
goto unimplemented;
{
struct target_sel_arg_struct *sel = (void *)arg1;
sel->n = tswapl(sel->n);
sel->inp = tswapl(sel->inp);
sel->outp = tswapl(sel->outp);
sel->exp = tswapl(sel->exp);
sel->tvp = tswapl(sel->tvp);
ret = do_select(sel->n, (void *)sel->inp, (void *)sel->outp,
(void *)sel->exp, (void *)sel->tvp);
}
break;
case TARGET_NR_symlink:
ret = get_errno(symlink((const char *)arg1, (const char *)arg2));
break;
@@ -1781,8 +1808,8 @@ long do_syscall(void *cpu_env, int num, long arg1, long arg2, long arg3,
goto unimplemented;
case TARGET_NR_readdir:
goto unimplemented;
#ifdef TARGET_I386
case TARGET_NR_mmap:
#if defined(TARGET_I386) || defined(TARGET_ARM)
{
uint32_t v1, v2, v3, v4, v5, v6, *vptr;
vptr = (uint32_t *)arg1;
@@ -1796,13 +1823,14 @@ long do_syscall(void *cpu_env, int num, long arg1, long arg2, long arg3,
target_to_host_bitmask(v4, mmap_flags_tbl),
v5, v6));
}
break;
#endif
#ifdef TARGET_I386
case TARGET_NR_mmap2:
#else
case TARGET_NR_mmap:
ret = get_errno(target_mmap(arg1, arg2, arg3,
target_to_host_bitmask(arg4, mmap_flags_tbl),
arg5,
arg6));
#endif
break;
case TARGET_NR_mmap2:
ret = get_errno(target_mmap(arg1, arg2, arg3,
target_to_host_bitmask(arg4, mmap_flags_tbl),
arg5,
+12 -2
View File
@@ -383,6 +383,8 @@ struct target_itimerval {
typedef target_long target_clock_t;
#define TARGET_HZ 100
struct target_tms {
target_clock_t tms_utime;
target_clock_t tms_stime;
@@ -390,6 +392,12 @@ struct target_tms {
target_clock_t tms_cstime;
};
struct target_sel_arg_struct {
target_long n;
target_long inp, outp, exp;
target_long tvp;
};
struct target_iovec {
target_long iov_base; /* Starting address */
target_long iov_len; /* Number of bytes */
@@ -533,8 +541,8 @@ static inline void target_siginitset(target_sigset_t *d, target_ulong set)
d->sig[i] = 0;
}
void host_to_target_sigset(target_sigset_t *d, sigset_t *s);
void target_to_host_sigset(sigset_t *d, target_sigset_t *s);
void host_to_target_sigset(target_sigset_t *d, const sigset_t *s);
void target_to_host_sigset(sigset_t *d, const target_sigset_t *s);
void host_to_target_old_sigset(target_ulong *old_sigset,
const sigset_t *sigset);
void target_to_host_old_sigset(sigset_t *sigset,
@@ -584,6 +592,8 @@ int do_sigaction(int sig, const struct target_sigaction *act,
#define TARGET_SIGPROF 27
#define TARGET_SIGWINCH 28
#define TARGET_SIGIO 29
#define TARGET_SIGPWR 30
#define TARGET_SIGSYS 31
#define TARGET_SIGRTMIN 32
#define TARGET_SIG_BLOCK 0 /* for blocking signals */
+22 -20
View File
@@ -73,17 +73,17 @@ void save_v86_state(CPUX86State *env)
ts->target_v86->regs.ebp = tswap32(env->regs[R_EBP]);
ts->target_v86->regs.esp = tswap32(env->regs[R_ESP]);
ts->target_v86->regs.eip = tswap32(env->eip);
ts->target_v86->regs.cs = tswap16(env->segs[R_CS]);
ts->target_v86->regs.ss = tswap16(env->segs[R_SS]);
ts->target_v86->regs.ds = tswap16(env->segs[R_DS]);
ts->target_v86->regs.es = tswap16(env->segs[R_ES]);
ts->target_v86->regs.fs = tswap16(env->segs[R_FS]);
ts->target_v86->regs.gs = tswap16(env->segs[R_GS]);
ts->target_v86->regs.cs = tswap16(env->segs[R_CS].selector);
ts->target_v86->regs.ss = tswap16(env->segs[R_SS].selector);
ts->target_v86->regs.ds = tswap16(env->segs[R_DS].selector);
ts->target_v86->regs.es = tswap16(env->segs[R_ES].selector);
ts->target_v86->regs.fs = tswap16(env->segs[R_FS].selector);
ts->target_v86->regs.gs = tswap16(env->segs[R_GS].selector);
set_flags(env->eflags, ts->v86flags, VIF_MASK | ts->v86mask);
ts->target_v86->regs.eflags = tswap32(env->eflags);
#ifdef DEBUG_VM86
fprintf(logfile, "save_v86_state: eflags=%08x cs:ip=%04x:%04x\n",
env->eflags, env->segs[R_CS], env->eip);
env->eflags, env->segs[R_CS].selector, env->eip);
#endif
/* restore 32 bit registers */
@@ -180,6 +180,7 @@ static inline unsigned int get_vflags(CPUX86State *env)
flags = env->eflags & RETURN_MASK;
if (ts->v86flags & VIF_MASK)
flags |= IF_MASK;
flags |= IOPL_MASK;
return flags | (ts->v86flags & ts->v86mask);
}
@@ -194,7 +195,7 @@ static void do_int(CPUX86State *env, int intno)
uint8_t *ssp;
unsigned int sp;
if (env->segs[R_CS] == TARGET_BIOSSEG)
if (env->segs[R_CS].selector == TARGET_BIOSSEG)
goto cannot_handle;
if (is_revectored(intno, &ts->vm86plus.int_revectored))
goto cannot_handle;
@@ -210,10 +211,10 @@ static void do_int(CPUX86State *env, int intno)
intno, segoffs >> 16, segoffs & 0xffff);
#endif
/* save old state */
ssp = (uint8_t *)(env->segs[R_SS] << 4);
ssp = (uint8_t *)(env->segs[R_SS].selector << 4);
sp = env->regs[R_ESP] & 0xffff;
vm_putw(ssp, sp - 2, get_vflags(env));
vm_putw(ssp, sp - 4, env->segs[R_CS]);
vm_putw(ssp, sp - 4, env->segs[R_CS].selector);
vm_putw(ssp, sp - 6, env->eip);
ADD16(env->regs[R_ESP], -6);
/* goto interrupt handler */
@@ -257,16 +258,16 @@ void handle_vm86_fault(CPUX86State *env)
unsigned int ip, sp, newflags, newip, newcs, opcode, intno;
int data32, pref_done;
csp = (uint8_t *)(env->segs[R_CS] << 4);
csp = (uint8_t *)(env->segs[R_CS].selector << 4);
ip = env->eip & 0xffff;
pc = csp + ip;
ssp = (uint8_t *)(env->segs[R_SS] << 4);
ssp = (uint8_t *)(env->segs[R_SS].selector << 4);
sp = env->regs[R_ESP] & 0xffff;
#if defined(DEBUG_VM86)
fprintf(logfile, "VM86 exception %04x:%08x %02x %02x\n",
env->segs[R_CS], env->eip, pc[0], pc[1]);
env->segs[R_CS].selector, env->eip, pc[0], pc[1]);
#endif
data32 = 0;
@@ -413,12 +414,12 @@ int do_vm86(CPUX86State *env, long subfunction,
ts->vm86_saved_regs.esp = env->regs[R_ESP];
ts->vm86_saved_regs.eflags = env->eflags;
ts->vm86_saved_regs.eip = env->eip;
ts->vm86_saved_regs.cs = env->segs[R_CS];
ts->vm86_saved_regs.ss = env->segs[R_SS];
ts->vm86_saved_regs.ds = env->segs[R_DS];
ts->vm86_saved_regs.es = env->segs[R_ES];
ts->vm86_saved_regs.fs = env->segs[R_FS];
ts->vm86_saved_regs.gs = env->segs[R_GS];
ts->vm86_saved_regs.cs = env->segs[R_CS].selector;
ts->vm86_saved_regs.ss = env->segs[R_SS].selector;
ts->vm86_saved_regs.ds = env->segs[R_DS].selector;
ts->vm86_saved_regs.es = env->segs[R_ES].selector;
ts->vm86_saved_regs.fs = env->segs[R_FS].selector;
ts->vm86_saved_regs.gs = env->segs[R_GS].selector;
/* build vm86 CPU state */
ts->v86flags = tswap32(target_v86->regs.eflags);
@@ -466,7 +467,8 @@ int do_vm86(CPUX86State *env, long subfunction,
target_v86->vm86plus.vm86dbg_intxxtab, 32);
#ifdef DEBUG_VM86
fprintf(logfile, "do_vm86: cs:ip=%04x:%04x\n", env->segs[R_CS], env->eip);
fprintf(logfile, "do_vm86: cs:ip=%04x:%04x\n",
env->segs[R_CS].selector, env->eip);
#endif
/* now the virtual CPU is ready for vm86 execution ! */
out:
+22 -14
View File
@@ -154,11 +154,11 @@ void OPPROTO op_adcl_T0_T1_cc(void)
FORCE_RET();
}
#define OPSUB(sub, sbc, T0, T1) \
#define OPSUB(sub, sbc, res, T0, T1) \
\
void OPPROTO op_ ## sub ## l_T0_T1(void) \
{ \
T0 -= T1; \
res = T0 - T1; \
} \
\
void OPPROTO op_ ## sub ## l_T0_T1_cc(void) \
@@ -167,13 +167,14 @@ void OPPROTO op_ ## sub ## l_T0_T1_cc(void) \
src1 = T0; \
T0 -= T1; \
env->NZF = T0; \
env->CF = src1 < T1; \
env->CF = src1 >= T1; \
env->VF = (src1 ^ T1) & (src1 ^ T0); \
res = T0; \
} \
\
void OPPROTO op_ ## sbc ## l_T0_T1(void) \
{ \
T0 = T0 - T1 + env->CF - 1; \
res = T0 - T1 + env->CF - 1; \
} \
\
void OPPROTO op_ ## sbc ## l_T0_T1_cc(void) \
@@ -182,20 +183,20 @@ void OPPROTO op_ ## sbc ## l_T0_T1_cc(void) \
src1 = T0; \
if (!env->CF) { \
T0 = T0 - T1 - 1; \
T0 += T1; \
env->CF = src1 < T1; \
env->CF = src1 >= T1; \
} else { \
T0 = T0 - T1; \
env->CF = src1 <= T1; \
env->CF = src1 > T1; \
} \
env->VF = (src1 ^ T1) & (src1 ^ T0); \
env->NZF = T0; \
res = T0; \
FORCE_RET(); \
}
OPSUB(sub, sbc, T0, T1)
OPSUB(sub, sbc, T0, T0, T1)
OPSUB(rsb, rsc, T1, T0)
OPSUB(rsb, rsc, T0, T1, T0)
void OPPROTO op_andl_T0_T1(void)
{
@@ -222,11 +223,16 @@ void OPPROTO op_notl_T1(void)
T1 = ~T1;
}
void OPPROTO op_logic_cc(void)
void OPPROTO op_logic_T0_cc(void)
{
env->NZF = T0;
}
void OPPROTO op_logic_T1_cc(void)
{
env->NZF = T1;
}
#define EIP (env->regs[15])
void OPPROTO op_test_eq(void)
@@ -332,12 +338,14 @@ void OPPROTO op_jmp(void)
JUMP_TB(PARAM1, 1, PARAM2);
}
void OPPROTO op_exit_tb(void)
{
EXIT_TB();
}
void OPPROTO op_movl_T0_psr(void)
{
int ZF;
ZF = (env->NZF == 0);
T0 = env->cpsr | (env->NZF & 0x80000000) | (ZF << 30) |
(env->CF << 29) | ((env->VF & 0x80000000) >> 3);
T0 = compute_cpsr();
}
/* NOTE: N = 1 and Z = 1 cannot be stored currently */
+178 -67
View File
@@ -80,62 +80,34 @@ static inline int lshift(int x, int n)
/* operations with flags */
void OPPROTO op_addl_T0_T1_cc(void)
/* update flags with T0 and T1 (add/sub case) */
void OPPROTO op_update2_cc(void)
{
CC_SRC = T0;
T0 += T1;
CC_SRC = T1;
CC_DST = T0;
}
void OPPROTO op_orl_T0_T1_cc(void)
/* update flags with T0 (logic operation case) */
void OPPROTO op_update1_cc(void)
{
T0 |= T1;
CC_DST = T0;
}
void OPPROTO op_andl_T0_T1_cc(void)
void OPPROTO op_update_neg_cc(void)
{
T0 &= T1;
CC_DST = T0;
}
void OPPROTO op_subl_T0_T1_cc(void)
{
CC_SRC = T0;
T0 -= T1;
CC_DST = T0;
}
void OPPROTO op_xorl_T0_T1_cc(void)
{
T0 ^= T1;
CC_SRC = -T0;
CC_DST = T0;
}
void OPPROTO op_cmpl_T0_T1_cc(void)
{
CC_SRC = T0;
CC_SRC = T1;
CC_DST = T0 - T1;
}
void OPPROTO op_negl_T0_cc(void)
{
CC_SRC = 0;
T0 = -T0;
CC_DST = T0;
}
void OPPROTO op_incl_T0_cc(void)
void OPPROTO op_update_inc_cc(void)
{
CC_SRC = cc_table[CC_OP].compute_c();
T0++;
CC_DST = T0;
}
void OPPROTO op_decl_T0_cc(void)
{
CC_SRC = cc_table[CC_OP].compute_c();
T0--;
CC_DST = T0;
}
@@ -357,6 +329,11 @@ void OPPROTO op_andl_T0_ffff(void)
T0 = T0 & 0xffff;
}
void OPPROTO op_andl_T0_im(void)
{
T0 = T0 & PARAM1;
}
void OPPROTO op_movl_T0_T1(void)
{
T0 = T1;
@@ -488,6 +465,12 @@ void OPPROTO op_jmp_im(void)
EIP = PARAM1;
}
void OPPROTO op_hlt(void)
{
env->exception_index = EXCP_HLT;
cpu_loop_exit();
}
void OPPROTO op_raise_interrupt(void)
{
int intno;
@@ -583,6 +566,11 @@ void OPPROTO op_movl_T0_0(void)
T0 = 0;
}
void OPPROTO op_exit_tb(void)
{
EXIT_TB();
}
/* multiple size ops */
#define ldul ldl
@@ -665,7 +653,7 @@ void op_pushl_ss32_T0(void)
{
uint32_t offset;
offset = ESP - 4;
stl(env->seg_cache[R_SS].base + offset, T0);
stl(env->segs[R_SS].base + offset, T0);
/* modify ESP after to handle exceptions correctly */
ESP = offset;
}
@@ -674,7 +662,7 @@ void op_pushw_ss32_T0(void)
{
uint32_t offset;
offset = ESP - 2;
stw(env->seg_cache[R_SS].base + offset, T0);
stw(env->segs[R_SS].base + offset, T0);
/* modify ESP after to handle exceptions correctly */
ESP = offset;
}
@@ -683,7 +671,7 @@ void op_pushl_ss16_T0(void)
{
uint32_t offset;
offset = (ESP - 4) & 0xffff;
stl(env->seg_cache[R_SS].base + offset, T0);
stl(env->segs[R_SS].base + offset, T0);
/* modify ESP after to handle exceptions correctly */
ESP = (ESP & ~0xffff) | offset;
}
@@ -692,7 +680,7 @@ void op_pushw_ss16_T0(void)
{
uint32_t offset;
offset = (ESP - 2) & 0xffff;
stw(env->seg_cache[R_SS].base + offset, T0);
stw(env->segs[R_SS].base + offset, T0);
/* modify ESP after to handle exceptions correctly */
ESP = (ESP & ~0xffff) | offset;
}
@@ -710,22 +698,22 @@ void op_popw_T0(void)
void op_popl_ss32_T0(void)
{
T0 = ldl(env->seg_cache[R_SS].base + ESP);
T0 = ldl(env->segs[R_SS].base + ESP);
}
void op_popw_ss32_T0(void)
{
T0 = lduw(env->seg_cache[R_SS].base + ESP);
T0 = lduw(env->segs[R_SS].base + ESP);
}
void op_popl_ss16_T0(void)
{
T0 = ldl(env->seg_cache[R_SS].base + (ESP & 0xffff));
T0 = ldl(env->segs[R_SS].base + (ESP & 0xffff));
}
void op_popw_ss16_T0(void)
{
T0 = lduw(env->seg_cache[R_SS].base + (ESP & 0xffff));
T0 = lduw(env->segs[R_SS].base + (ESP & 0xffff));
}
void op_addl_ESP_4(void)
@@ -768,6 +756,16 @@ void OPPROTO op_cpuid(void)
helper_cpuid();
}
void OPPROTO op_rdmsr(void)
{
helper_rdmsr();
}
void OPPROTO op_wrmsr(void)
{
helper_wrmsr();
}
/* bcd */
/* XXX: exception */
@@ -909,17 +907,18 @@ void OPPROTO op_movl_seg_T0(void)
void OPPROTO op_movl_seg_T0_vm(void)
{
int selector;
SegmentCache *sc;
selector = T0 & 0xffff;
/* env->segs[] access */
*(uint32_t *)((char *)env + PARAM1) = selector;
/* env->seg_cache[] access */
((SegmentCache *)((char *)env + PARAM2))->base = (void *)(selector << 4);
sc = (SegmentCache *)((char *)env + PARAM1);
sc->selector = selector;
sc->base = (void *)(selector << 4);
}
void OPPROTO op_movl_T0_seg(void)
{
T0 = env->segs[PARAM1];
T0 = env->segs[PARAM1].selector;
}
void OPPROTO op_movl_A0_seg(void)
@@ -942,6 +941,71 @@ void OPPROTO op_lar(void)
helper_lar();
}
/* T0: segment, T1:eip */
void OPPROTO op_ljmp_T0_T1(void)
{
jmp_seg(T0 & 0xffff, T1);
}
void OPPROTO op_iret_protected(void)
{
helper_iret_protected(PARAM1);
}
void OPPROTO op_lldt_T0(void)
{
helper_lldt_T0();
}
void OPPROTO op_ltr_T0(void)
{
helper_ltr_T0();
}
/* CR registers access */
void OPPROTO op_movl_crN_T0(void)
{
helper_movl_crN_T0(PARAM1);
}
/* DR registers access */
void OPPROTO op_movl_drN_T0(void)
{
helper_movl_drN_T0(PARAM1);
}
void OPPROTO op_lmsw_T0(void)
{
/* only 4 lower bits of CR0 are modified */
T0 = (env->cr[0] & ~0xf) | (T0 & 0xf);
helper_movl_crN_T0(0);
}
void OPPROTO op_invlpg_A0(void)
{
helper_invlpg(A0);
}
void OPPROTO op_movl_T0_env(void)
{
T0 = *(uint32_t *)((char *)env + PARAM1);
}
void OPPROTO op_movl_env_T0(void)
{
*(uint32_t *)((char *)env + PARAM1) = T0;
}
void OPPROTO op_movl_env_T1(void)
{
*(uint32_t *)((char *)env + PARAM1) = T1;
}
void OPPROTO op_clts(void)
{
env->cr[0] &= ~CR0_TS_MASK;
}
/* flags handling */
/* slow jumps cases : in order to avoid calling a function with a
@@ -1021,8 +1085,7 @@ void OPPROTO op_set_cc_op(void)
CC_OP = PARAM1;
}
#define FL_UPDATE_MASK32 (TF_MASK | AC_MASK | ID_MASK)
#define FL_UPDATE_MASK16 (TF_MASK)
#define FL_UPDATE_MASK16 (FL_UPDATE_MASK32 & 0xffff)
void OPPROTO op_movl_eflags_T0(void)
{
@@ -1031,7 +1094,8 @@ void OPPROTO op_movl_eflags_T0(void)
CC_SRC = eflags & (CC_O | CC_S | CC_Z | CC_A | CC_P | CC_C);
DF = 1 - (2 * ((eflags >> 10) & 1));
/* we also update some system flags as in user mode */
env->eflags = (env->eflags & ~FL_UPDATE_MASK32) | (eflags & FL_UPDATE_MASK32);
env->eflags = (env->eflags & ~FL_UPDATE_MASK32) |
(eflags & FL_UPDATE_MASK32);
}
void OPPROTO op_movw_eflags_T0(void)
@@ -1041,7 +1105,18 @@ void OPPROTO op_movw_eflags_T0(void)
CC_SRC = eflags & (CC_O | CC_S | CC_Z | CC_A | CC_P | CC_C);
DF = 1 - (2 * ((eflags >> 10) & 1));
/* we also update some system flags as in user mode */
env->eflags = (env->eflags & ~FL_UPDATE_MASK16) | (eflags & FL_UPDATE_MASK16);
env->eflags = (env->eflags & ~FL_UPDATE_MASK16) |
(eflags & FL_UPDATE_MASK16);
}
void OPPROTO op_movl_eflags_T0_cpl0(void)
{
load_eflags(T0, FL_UPDATE_CPL0_MASK);
}
void OPPROTO op_movw_eflags_T0_cpl0(void)
{
load_eflags(T0, FL_UPDATE_CPL0_MASK & 0xffff);
}
#if 0
@@ -1346,28 +1421,40 @@ void OPPROTO op_fildll_FT0_A0(void)
void OPPROTO op_flds_ST0_A0(void)
{
int new_fpstt;
new_fpstt = (env->fpstt - 1) & 7;
#ifdef USE_FP_CONVERT
FP_CONVERT.i32 = ldl((void *)A0);
ST0 = FP_CONVERT.f;
env->fpregs[new_fpstt] = FP_CONVERT.f;
#else
ST0 = ldfl((void *)A0);
env->fpregs[new_fpstt] = ldfl((void *)A0);
#endif
env->fpstt = new_fpstt;
env->fptags[new_fpstt] = 0; /* validate stack entry */
}
void OPPROTO op_fldl_ST0_A0(void)
{
int new_fpstt;
new_fpstt = (env->fpstt - 1) & 7;
#ifdef USE_FP_CONVERT
FP_CONVERT.i64 = ldq((void *)A0);
ST0 = FP_CONVERT.d;
env->fpregs[new_fpstt] = FP_CONVERT.d;
#else
ST0 = ldfq((void *)A0);
env->fpregs[new_fpstt] = ldfq((void *)A0);
#endif
env->fpstt = new_fpstt;
env->fptags[new_fpstt] = 0; /* validate stack entry */
}
#ifdef USE_X86LDOUBLE
void OPPROTO op_fldt_ST0_A0(void)
{
ST0 = *(long double *)A0;
int new_fpstt;
new_fpstt = (env->fpstt - 1) & 7;
env->fpregs[new_fpstt] = *(long double *)A0;
env->fpstt = new_fpstt;
env->fptags[new_fpstt] = 0; /* validate stack entry */
}
#else
void OPPROTO op_fldt_ST0_A0(void)
@@ -1381,17 +1468,29 @@ void OPPROTO op_fldt_ST0_A0(void)
void helper_fild_ST0_A0(void)
{
ST0 = (CPU86_LDouble)ldsw((void *)A0);
int new_fpstt;
new_fpstt = (env->fpstt - 1) & 7;
env->fpregs[new_fpstt] = (CPU86_LDouble)ldsw((void *)A0);
env->fpstt = new_fpstt;
env->fptags[new_fpstt] = 0; /* validate stack entry */
}
void helper_fildl_ST0_A0(void)
{
ST0 = (CPU86_LDouble)((int32_t)ldl((void *)A0));
int new_fpstt;
new_fpstt = (env->fpstt - 1) & 7;
env->fpregs[new_fpstt] = (CPU86_LDouble)((int32_t)ldl((void *)A0));
env->fpstt = new_fpstt;
env->fptags[new_fpstt] = 0; /* validate stack entry */
}
void helper_fildll_ST0_A0(void)
{
ST0 = (CPU86_LDouble)((int64_t)ldq((void *)A0));
int new_fpstt;
new_fpstt = (env->fpstt - 1) & 7;
env->fpregs[new_fpstt] = (CPU86_LDouble)((int64_t)ldq((void *)A0));
env->fpstt = new_fpstt;
env->fptags[new_fpstt] = 0; /* validate stack entry */
}
void OPPROTO op_fild_ST0_A0(void)
@@ -1413,32 +1512,44 @@ void OPPROTO op_fildll_ST0_A0(void)
void OPPROTO op_fild_ST0_A0(void)
{
int new_fpstt;
new_fpstt = (env->fpstt - 1) & 7;
#ifdef USE_FP_CONVERT
FP_CONVERT.i32 = ldsw((void *)A0);
ST0 = (CPU86_LDouble)FP_CONVERT.i32;
env->fpregs[new_fpstt] = (CPU86_LDouble)FP_CONVERT.i32;
#else
ST0 = (CPU86_LDouble)ldsw((void *)A0);
env->fpregs[new_fpstt] = (CPU86_LDouble)ldsw((void *)A0);
#endif
env->fpstt = new_fpstt;
env->fptags[new_fpstt] = 0; /* validate stack entry */
}
void OPPROTO op_fildl_ST0_A0(void)
{
int new_fpstt;
new_fpstt = (env->fpstt - 1) & 7;
#ifdef USE_FP_CONVERT
FP_CONVERT.i32 = (int32_t) ldl((void *)A0);
ST0 = (CPU86_LDouble)FP_CONVERT.i32;
env->fpregs[new_fpstt] = (CPU86_LDouble)FP_CONVERT.i32;
#else
ST0 = (CPU86_LDouble)((int32_t)ldl((void *)A0));
env->fpregs[new_fpstt] = (CPU86_LDouble)((int32_t)ldl((void *)A0));
#endif
env->fpstt = new_fpstt;
env->fptags[new_fpstt] = 0; /* validate stack entry */
}
void OPPROTO op_fildll_ST0_A0(void)
{
int new_fpstt;
new_fpstt = (env->fpstt - 1) & 7;
#ifdef USE_FP_CONVERT
FP_CONVERT.i64 = (int64_t) ldq((void *)A0);
ST0 = (CPU86_LDouble)FP_CONVERT.i64;
env->fpregs[new_fpstt] = (CPU86_LDouble)FP_CONVERT.i64;
#else
ST0 = (CPU86_LDouble)((int64_t)ldq((void *)A0));
env->fpregs[new_fpstt] = (CPU86_LDouble)((int64_t)ldq((void *)A0));
#endif
env->fpstt = new_fpstt;
env->fptags[new_fpstt] = 0; /* validate stack entry */
}
#endif
+6 -7
View File
@@ -2,7 +2,6 @@
void OPPROTO glue(glue(op_movs, SUFFIX), STRING_SUFFIX)(void)
{
int v, inc;
inc = (DF << SHIFT);
v = glue(ldu, SUFFIX)(SI_ADDR);
glue(st, SUFFIX)(DI_ADDR, v);
inc = (DF << SHIFT);
@@ -86,7 +85,7 @@ void OPPROTO glue(glue(op_scas, SUFFIX), STRING_SUFFIX)(void)
v = glue(ldu, SUFFIX)(DI_ADDR);
inc = (DF << SHIFT);
INC_DI();
CC_SRC = EAX;
CC_SRC = v;
CC_DST = EAX - v;
}
@@ -105,7 +104,7 @@ void OPPROTO glue(glue(op_repz_scas, SUFFIX), STRING_SUFFIX)(void)
if (v1 != v2)
break;
} while (CX != 0);
CC_SRC = v1;
CC_SRC = v2;
CC_DST = v1 - v2;
CC_OP = CC_OP_SUBB + SHIFT;
}
@@ -127,7 +126,7 @@ void OPPROTO glue(glue(op_repnz_scas, SUFFIX), STRING_SUFFIX)(void)
if (v1 == v2)
break;
} while (CX != 0);
CC_SRC = v1;
CC_SRC = v2;
CC_DST = v1 - v2;
CC_OP = CC_OP_SUBB + SHIFT;
}
@@ -142,7 +141,7 @@ void OPPROTO glue(glue(op_cmps, SUFFIX), STRING_SUFFIX)(void)
inc = (DF << SHIFT);
INC_SI();
INC_DI();
CC_SRC = v1;
CC_SRC = v2;
CC_DST = v1 - v2;
}
@@ -160,7 +159,7 @@ void OPPROTO glue(glue(op_repz_cmps, SUFFIX), STRING_SUFFIX)(void)
if (v1 != v2)
break;
} while (CX != 0);
CC_SRC = v1;
CC_SRC = v2;
CC_DST = v1 - v2;
CC_OP = CC_OP_SUBB + SHIFT;
}
@@ -181,7 +180,7 @@ void OPPROTO glue(glue(op_repnz_cmps, SUFFIX), STRING_SUFFIX)(void)
if (v1 == v2)
break;
} while (CX != 0);
CC_SRC = v1;
CC_SRC = v2;
CC_DST = v1 - v2;
CC_OP = CC_OP_SUBB + SHIFT;
}
+40 -337
View File
@@ -93,8 +93,8 @@ static int glue(compute_all_sub, SUFFIX)(void)
{
int cf, pf, af, zf, sf, of;
int src1, src2;
src1 = CC_SRC;
src2 = CC_SRC - CC_DST;
src1 = CC_DST + CC_SRC;
src2 = CC_SRC;
cf = (DATA_TYPE)src1 < (DATA_TYPE)src2;
pf = parity_table[(uint8_t)CC_DST];
af = (CC_DST ^ src1 ^ src2) & 0x10;
@@ -107,8 +107,8 @@ static int glue(compute_all_sub, SUFFIX)(void)
static int glue(compute_c_sub, SUFFIX)(void)
{
int src1, src2, cf;
src1 = CC_SRC;
src2 = CC_SRC - CC_DST;
src1 = CC_DST + CC_SRC;
src2 = CC_SRC;
cf = (DATA_TYPE)src1 < (DATA_TYPE)src2;
return cf;
}
@@ -117,8 +117,8 @@ static int glue(compute_all_sbb, SUFFIX)(void)
{
int cf, pf, af, zf, sf, of;
int src1, src2;
src1 = CC_SRC;
src2 = CC_SRC - CC_DST - 1;
src1 = CC_DST + CC_SRC + 1;
src2 = CC_SRC;
cf = (DATA_TYPE)src1 <= (DATA_TYPE)src2;
pf = parity_table[(uint8_t)CC_DST];
af = (CC_DST ^ src1 ^ src2) & 0x10;
@@ -131,8 +131,8 @@ static int glue(compute_all_sbb, SUFFIX)(void)
static int glue(compute_c_sbb, SUFFIX)(void)
{
int src1, src2, cf;
src1 = CC_SRC;
src2 = CC_SRC - CC_DST - 1;
src1 = CC_DST + CC_SRC + 1;
src2 = CC_SRC;
cf = (DATA_TYPE)src1 <= (DATA_TYPE)src2;
return cf;
}
@@ -234,8 +234,8 @@ static int glue(compute_all_sar, SUFFIX)(void)
void OPPROTO glue(op_jb_sub, SUFFIX)(void)
{
int src1, src2;
src1 = CC_SRC;
src2 = CC_SRC - CC_DST;
src1 = CC_DST + CC_SRC;
src2 = CC_SRC;
if ((DATA_TYPE)src1 < (DATA_TYPE)src2)
JUMP_TB(PARAM1, 0, PARAM2);
@@ -256,8 +256,8 @@ void OPPROTO glue(op_jz_sub, SUFFIX)(void)
void OPPROTO glue(op_jbe_sub, SUFFIX)(void)
{
int src1, src2;
src1 = CC_SRC;
src2 = CC_SRC - CC_DST;
src1 = CC_DST + CC_SRC;
src2 = CC_SRC;
if ((DATA_TYPE)src1 <= (DATA_TYPE)src2)
JUMP_TB(PARAM1, 0, PARAM2);
@@ -278,8 +278,8 @@ void OPPROTO glue(op_js_sub, SUFFIX)(void)
void OPPROTO glue(op_jl_sub, SUFFIX)(void)
{
int src1, src2;
src1 = CC_SRC;
src2 = CC_SRC - CC_DST;
src1 = CC_DST + CC_SRC;
src2 = CC_SRC;
if ((DATA_STYPE)src1 < (DATA_STYPE)src2)
JUMP_TB(PARAM1, 0, PARAM2);
@@ -291,8 +291,8 @@ void OPPROTO glue(op_jl_sub, SUFFIX)(void)
void OPPROTO glue(op_jle_sub, SUFFIX)(void)
{
int src1, src2;
src1 = CC_SRC;
src2 = CC_SRC - CC_DST;
src1 = CC_DST + CC_SRC;
src2 = CC_SRC;
if ((DATA_STYPE)src1 <= (DATA_STYPE)src2)
JUMP_TB(PARAM1, 0, PARAM2);
@@ -361,8 +361,8 @@ void OPPROTO glue(op_jecxz, SUFFIX)(void)
void OPPROTO glue(op_setb_T0_sub, SUFFIX)(void)
{
int src1, src2;
src1 = CC_SRC;
src2 = CC_SRC - CC_DST;
src1 = CC_DST + CC_SRC;
src2 = CC_SRC;
T0 = ((DATA_TYPE)src1 < (DATA_TYPE)src2);
}
@@ -375,8 +375,8 @@ void OPPROTO glue(op_setz_T0_sub, SUFFIX)(void)
void OPPROTO glue(op_setbe_T0_sub, SUFFIX)(void)
{
int src1, src2;
src1 = CC_SRC;
src2 = CC_SRC - CC_DST;
src1 = CC_DST + CC_SRC;
src2 = CC_SRC;
T0 = ((DATA_TYPE)src1 <= (DATA_TYPE)src2);
}
@@ -389,8 +389,8 @@ void OPPROTO glue(op_sets_T0_sub, SUFFIX)(void)
void OPPROTO glue(op_setl_T0_sub, SUFFIX)(void)
{
int src1, src2;
src1 = CC_SRC;
src2 = CC_SRC - CC_DST;
src1 = CC_DST + CC_SRC;
src2 = CC_SRC;
T0 = ((DATA_STYPE)src1 < (DATA_STYPE)src2);
}
@@ -398,135 +398,14 @@ void OPPROTO glue(op_setl_T0_sub, SUFFIX)(void)
void OPPROTO glue(op_setle_T0_sub, SUFFIX)(void)
{
int src1, src2;
src1 = CC_SRC;
src2 = CC_SRC - CC_DST;
src1 = CC_DST + CC_SRC;
src2 = CC_SRC;
T0 = ((DATA_STYPE)src1 <= (DATA_STYPE)src2);
}
/* shifts */
void OPPROTO glue(glue(op_rol, SUFFIX), _T0_T1_cc)(void)
{
int count, src;
count = T1 & SHIFT_MASK;
if (count) {
CC_SRC = cc_table[CC_OP].compute_all() & ~(CC_O | CC_C);
src = T0;
T0 &= DATA_MASK;
T0 = (T0 << count) | (T0 >> (DATA_BITS - count));
CC_SRC |= (lshift(src ^ T0, 11 - (DATA_BITS - 1)) & CC_O) |
(T0 & CC_C);
CC_OP = CC_OP_EFLAGS;
}
FORCE_RET();
}
void OPPROTO glue(glue(op_rol, SUFFIX), _T0_T1)(void)
{
int count;
count = T1 & SHIFT_MASK;
if (count) {
T0 &= DATA_MASK;
T0 = (T0 << count) | (T0 >> (DATA_BITS - count));
}
FORCE_RET();
}
void OPPROTO glue(glue(op_ror, SUFFIX), _T0_T1_cc)(void)
{
int count, src;
count = T1 & SHIFT_MASK;
if (count) {
CC_SRC = cc_table[CC_OP].compute_all() & ~(CC_O | CC_C);
src = T0;
T0 &= DATA_MASK;
T0 = (T0 >> count) | (T0 << (DATA_BITS - count));
CC_SRC |= (lshift(src ^ T0, 11 - (DATA_BITS - 1)) & CC_O) |
((T0 >> (DATA_BITS - 1)) & CC_C);
CC_OP = CC_OP_EFLAGS;
}
FORCE_RET();
}
void OPPROTO glue(glue(op_ror, SUFFIX), _T0_T1)(void)
{
int count;
count = T1 & SHIFT_MASK;
if (count) {
T0 &= DATA_MASK;
T0 = (T0 >> count) | (T0 << (DATA_BITS - count));
}
FORCE_RET();
}
void OPPROTO glue(glue(op_rcl, SUFFIX), _T0_T1_cc)(void)
{
int count, res, eflags;
unsigned int src;
count = T1 & 0x1f;
#if DATA_BITS == 16
count = rclw_table[count];
#elif DATA_BITS == 8
count = rclb_table[count];
#endif
if (count) {
eflags = cc_table[CC_OP].compute_all();
T0 &= DATA_MASK;
src = T0;
res = (T0 << count) | ((eflags & CC_C) << (count - 1));
if (count > 1)
res |= T0 >> (DATA_BITS + 1 - count);
T0 = res;
CC_SRC = (eflags & ~(CC_C | CC_O)) |
(lshift(src ^ T0, 11 - (DATA_BITS - 1)) & CC_O) |
((src >> (DATA_BITS - count)) & CC_C);
CC_OP = CC_OP_EFLAGS;
}
FORCE_RET();
}
void OPPROTO glue(glue(op_rcr, SUFFIX), _T0_T1_cc)(void)
{
int count, res, eflags;
unsigned int src;
count = T1 & 0x1f;
#if DATA_BITS == 16
count = rclw_table[count];
#elif DATA_BITS == 8
count = rclb_table[count];
#endif
if (count) {
eflags = cc_table[CC_OP].compute_all();
T0 &= DATA_MASK;
src = T0;
res = (T0 >> count) | ((eflags & CC_C) << (DATA_BITS - count));
if (count > 1)
res |= T0 << (DATA_BITS + 1 - count);
T0 = res;
CC_SRC = (eflags & ~(CC_C | CC_O)) |
(lshift(src ^ T0, 11 - (DATA_BITS - 1)) & CC_O) |
((src >> (count - 1)) & CC_C);
CC_OP = CC_OP_EFLAGS;
}
FORCE_RET();
}
void OPPROTO glue(glue(op_shl, SUFFIX), _T0_T1_cc)(void)
{
int count;
count = T1 & 0x1f;
if (count) {
CC_SRC = (DATA_TYPE)T0 << (count - 1);
T0 = T0 << count;
CC_DST = T0;
CC_OP = CC_OP_SHLB + SHIFT;
}
FORCE_RET();
}
void OPPROTO glue(glue(op_shl, SUFFIX), _T0_T1)(void)
{
int count;
@@ -535,20 +414,6 @@ void OPPROTO glue(glue(op_shl, SUFFIX), _T0_T1)(void)
FORCE_RET();
}
void OPPROTO glue(glue(op_shr, SUFFIX), _T0_T1_cc)(void)
{
int count;
count = T1 & 0x1f;
if (count) {
T0 &= DATA_MASK;
CC_SRC = T0 >> (count - 1);
T0 = T0 >> count;
CC_DST = T0;
CC_OP = CC_OP_SARB + SHIFT;
}
FORCE_RET();
}
void OPPROTO glue(glue(op_shr, SUFFIX), _T0_T1)(void)
{
int count;
@@ -558,20 +423,6 @@ void OPPROTO glue(glue(op_shr, SUFFIX), _T0_T1)(void)
FORCE_RET();
}
void OPPROTO glue(glue(op_sar, SUFFIX), _T0_T1_cc)(void)
{
int count, src;
count = T1 & 0x1f;
if (count) {
src = (DATA_STYPE)T0;
CC_SRC = src >> (count - 1);
T0 = src >> count;
CC_DST = T0;
CC_OP = CC_OP_SARB + SHIFT;
}
FORCE_RET();
}
void OPPROTO glue(glue(op_sar, SUFFIX), _T0_T1)(void)
{
int count, src;
@@ -581,166 +432,11 @@ void OPPROTO glue(glue(op_sar, SUFFIX), _T0_T1)(void)
FORCE_RET();
}
#if DATA_BITS == 16
/* XXX: overflow flag might be incorrect in some cases in shldw */
void OPPROTO glue(glue(op_shld, SUFFIX), _T0_T1_im_cc)(void)
{
int count;
unsigned int res;
count = PARAM1;
T1 &= 0xffff;
res = T1 | (T0 << 16);
CC_SRC = res >> (32 - count);
res <<= count;
if (count > 16)
res |= T1 << (count - 16);
T0 = res >> 16;
CC_DST = T0;
}
#undef MEM_WRITE
#include "ops_template_mem.h"
void OPPROTO glue(glue(op_shld, SUFFIX), _T0_T1_ECX_cc)(void)
{
int count;
unsigned int res;
count = ECX & 0x1f;
if (count) {
T1 &= 0xffff;
res = T1 | (T0 << 16);
CC_SRC = res >> (32 - count);
res <<= count;
if (count > 16)
res |= T1 << (count - 16);
T0 = res >> 16;
CC_DST = T0;
CC_OP = CC_OP_SARB + SHIFT;
}
FORCE_RET();
}
void OPPROTO glue(glue(op_shrd, SUFFIX), _T0_T1_im_cc)(void)
{
int count;
unsigned int res;
count = PARAM1;
res = (T0 & 0xffff) | (T1 << 16);
CC_SRC = res >> (count - 1);
res >>= count;
if (count > 16)
res |= T1 << (32 - count);
T0 = res;
CC_DST = T0;
}
void OPPROTO glue(glue(op_shrd, SUFFIX), _T0_T1_ECX_cc)(void)
{
int count;
unsigned int res;
count = ECX & 0x1f;
if (count) {
res = (T0 & 0xffff) | (T1 << 16);
CC_SRC = res >> (count - 1);
res >>= count;
if (count > 16)
res |= T1 << (32 - count);
T0 = res;
CC_DST = T0;
CC_OP = CC_OP_SARB + SHIFT;
}
FORCE_RET();
}
#endif
#if DATA_BITS == 32
void OPPROTO glue(glue(op_shld, SUFFIX), _T0_T1_im_cc)(void)
{
int count;
count = PARAM1;
T0 &= DATA_MASK;
T1 &= DATA_MASK;
CC_SRC = T0 << (count - 1);
T0 = (T0 << count) | (T1 >> (DATA_BITS - count));
CC_DST = T0;
}
void OPPROTO glue(glue(op_shld, SUFFIX), _T0_T1_ECX_cc)(void)
{
int count;
count = ECX & 0x1f;
if (count) {
T0 &= DATA_MASK;
T1 &= DATA_MASK;
CC_SRC = T0 << (count - 1);
T0 = (T0 << count) | (T1 >> (DATA_BITS - count));
CC_DST = T0;
CC_OP = CC_OP_SHLB + SHIFT;
}
FORCE_RET();
}
void OPPROTO glue(glue(op_shrd, SUFFIX), _T0_T1_im_cc)(void)
{
int count;
count = PARAM1;
T0 &= DATA_MASK;
T1 &= DATA_MASK;
CC_SRC = T0 >> (count - 1);
T0 = (T0 >> count) | (T1 << (DATA_BITS - count));
CC_DST = T0;
}
void OPPROTO glue(glue(op_shrd, SUFFIX), _T0_T1_ECX_cc)(void)
{
int count;
count = ECX & 0x1f;
if (count) {
T0 &= DATA_MASK;
T1 &= DATA_MASK;
CC_SRC = T0 >> (count - 1);
T0 = (T0 >> count) | (T1 << (DATA_BITS - count));
CC_DST = T0;
CC_OP = CC_OP_SARB + SHIFT;
}
FORCE_RET();
}
#endif
/* carry add/sub (we only need to set CC_OP differently) */
void OPPROTO glue(glue(op_adc, SUFFIX), _T0_T1_cc)(void)
{
int cf;
cf = cc_table[CC_OP].compute_c();
CC_SRC = T0;
T0 = T0 + T1 + cf;
CC_DST = T0;
CC_OP = CC_OP_ADDB + SHIFT + cf * 3;
}
void OPPROTO glue(glue(op_sbb, SUFFIX), _T0_T1_cc)(void)
{
int cf;
cf = cc_table[CC_OP].compute_c();
CC_SRC = T0;
T0 = T0 - T1 - cf;
CC_DST = T0;
CC_OP = CC_OP_SUBB + SHIFT + cf * 3;
}
void OPPROTO glue(glue(op_cmpxchg, SUFFIX), _T0_T1_EAX_cc)(void)
{
CC_SRC = EAX;
CC_DST = EAX - T0;
if ((DATA_TYPE)CC_DST == 0) {
T0 = T1;
} else {
EAX = (EAX & ~DATA_MASK) | (T0 & DATA_MASK);
}
FORCE_RET();
}
#define MEM_WRITE
#include "ops_template_mem.h"
/* bit operations */
#if DATA_BITS >= 16
@@ -756,7 +452,7 @@ void OPPROTO glue(glue(op_bts, SUFFIX), _T0_T1_cc)(void)
{
int count;
count = T1 & SHIFT_MASK;
CC_SRC = T0 >> count;
T1 = T0 >> count;
T0 |= (1 << count);
}
@@ -764,7 +460,7 @@ void OPPROTO glue(glue(op_btr, SUFFIX), _T0_T1_cc)(void)
{
int count;
count = T1 & SHIFT_MASK;
CC_SRC = T0 >> count;
T1 = T0 >> count;
T0 &= ~(1 << count);
}
@@ -772,7 +468,7 @@ void OPPROTO glue(glue(op_btc, SUFFIX), _T0_T1_cc)(void)
{
int count;
count = T1 & SHIFT_MASK;
CC_SRC = T0 >> count;
T1 = T0 >> count;
T0 ^= (1 << count);
}
@@ -814,6 +510,13 @@ void OPPROTO glue(glue(op_bsr, SUFFIX), _T0_cc)(void)
#endif
#if DATA_BITS == 32
void OPPROTO op_update_bt_cc(void)
{
CC_SRC = T1;
}
#endif
/* string operations */
/* XXX: maybe use lower level instructions to ease 16 bit / segment handling */
@@ -828,7 +531,7 @@ void OPPROTO glue(glue(op_bsr, SUFFIX), _T0_cc)(void)
#define STRING_SUFFIX _a32
#define SI_ADDR (uint8_t *)A0 + ESI
#define DI_ADDR env->seg_cache[R_ES].base + EDI
#define DI_ADDR env->segs[R_ES].base + EDI
#define INC_SI() ESI += inc
#define INC_DI() EDI += inc
#define CX ECX
@@ -837,7 +540,7 @@ void OPPROTO glue(glue(op_bsr, SUFFIX), _T0_cc)(void)
#define STRING_SUFFIX _a16
#define SI_ADDR (uint8_t *)A0 + (ESI & 0xffff)
#define DI_ADDR env->seg_cache[R_ES].base + (EDI & 0xffff)
#define DI_ADDR env->segs[R_ES].base + (EDI & 0xffff)
#define INC_SI() ESI = (ESI & ~0xffff) | ((ESI + inc) & 0xffff)
#define INC_DI() EDI = (EDI & ~0xffff) | ((EDI + inc) & 0xffff)
#define CX (ECX & 0xffff)
+429
View File
@@ -0,0 +1,429 @@
/*
* i386 micro operations (included several times to generate
* different operand sizes)
*
* Copyright (c) 2003 Fabrice Bellard
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
#ifdef MEM_WRITE
#if DATA_BITS == 8
#define MEM_SUFFIX b_mem
#elif DATA_BITS == 16
#define MEM_SUFFIX w_mem
#elif DATA_BITS == 32
#define MEM_SUFFIX l_mem
#endif
#else
#define MEM_SUFFIX SUFFIX
#endif
void OPPROTO glue(glue(op_rol, MEM_SUFFIX), _T0_T1_cc)(void)
{
int count, src;
count = T1 & SHIFT_MASK;
if (count) {
src = T0;
T0 &= DATA_MASK;
T0 = (T0 << count) | (T0 >> (DATA_BITS - count));
#ifdef MEM_WRITE
glue(st, SUFFIX)((uint8_t *)A0, T0);
#else
/* gcc 3.2 workaround. This is really a bug in gcc. */
asm volatile("" : : "r" (T0));
#endif
CC_SRC = (cc_table[CC_OP].compute_all() & ~(CC_O | CC_C)) |
(lshift(src ^ T0, 11 - (DATA_BITS - 1)) & CC_O) |
(T0 & CC_C);
CC_OP = CC_OP_EFLAGS;
}
FORCE_RET();
}
void OPPROTO glue(glue(op_ror, MEM_SUFFIX), _T0_T1_cc)(void)
{
int count, src;
count = T1 & SHIFT_MASK;
if (count) {
src = T0;
T0 &= DATA_MASK;
T0 = (T0 >> count) | (T0 << (DATA_BITS - count));
#ifdef MEM_WRITE
glue(st, SUFFIX)((uint8_t *)A0, T0);
#else
/* gcc 3.2 workaround. This is really a bug in gcc. */
asm volatile("" : : "r" (T0));
#endif
CC_SRC = (cc_table[CC_OP].compute_all() & ~(CC_O | CC_C)) |
(lshift(src ^ T0, 11 - (DATA_BITS - 1)) & CC_O) |
((T0 >> (DATA_BITS - 1)) & CC_C);
CC_OP = CC_OP_EFLAGS;
}
FORCE_RET();
}
void OPPROTO glue(glue(op_rol, MEM_SUFFIX), _T0_T1)(void)
{
int count;
count = T1 & SHIFT_MASK;
if (count) {
T0 &= DATA_MASK;
T0 = (T0 << count) | (T0 >> (DATA_BITS - count));
#ifdef MEM_WRITE
glue(st, SUFFIX)((uint8_t *)A0, T0);
#endif
}
FORCE_RET();
}
void OPPROTO glue(glue(op_ror, MEM_SUFFIX), _T0_T1)(void)
{
int count;
count = T1 & SHIFT_MASK;
if (count) {
T0 &= DATA_MASK;
T0 = (T0 >> count) | (T0 << (DATA_BITS - count));
#ifdef MEM_WRITE
glue(st, SUFFIX)((uint8_t *)A0, T0);
#endif
}
FORCE_RET();
}
void OPPROTO glue(glue(op_rcl, MEM_SUFFIX), _T0_T1_cc)(void)
{
int count, res, eflags;
unsigned int src;
count = T1 & 0x1f;
#if DATA_BITS == 16
count = rclw_table[count];
#elif DATA_BITS == 8
count = rclb_table[count];
#endif
if (count) {
eflags = cc_table[CC_OP].compute_all();
T0 &= DATA_MASK;
src = T0;
res = (T0 << count) | ((eflags & CC_C) << (count - 1));
if (count > 1)
res |= T0 >> (DATA_BITS + 1 - count);
T0 = res;
#ifdef MEM_WRITE
glue(st, SUFFIX)((uint8_t *)A0, T0);
#endif
CC_SRC = (eflags & ~(CC_C | CC_O)) |
(lshift(src ^ T0, 11 - (DATA_BITS - 1)) & CC_O) |
((src >> (DATA_BITS - count)) & CC_C);
CC_OP = CC_OP_EFLAGS;
}
FORCE_RET();
}
void OPPROTO glue(glue(op_rcr, MEM_SUFFIX), _T0_T1_cc)(void)
{
int count, res, eflags;
unsigned int src;
count = T1 & 0x1f;
#if DATA_BITS == 16
count = rclw_table[count];
#elif DATA_BITS == 8
count = rclb_table[count];
#endif
if (count) {
eflags = cc_table[CC_OP].compute_all();
T0 &= DATA_MASK;
src = T0;
res = (T0 >> count) | ((eflags & CC_C) << (DATA_BITS - count));
if (count > 1)
res |= T0 << (DATA_BITS + 1 - count);
T0 = res;
#ifdef MEM_WRITE
glue(st, SUFFIX)((uint8_t *)A0, T0);
#endif
CC_SRC = (eflags & ~(CC_C | CC_O)) |
(lshift(src ^ T0, 11 - (DATA_BITS - 1)) & CC_O) |
((src >> (count - 1)) & CC_C);
CC_OP = CC_OP_EFLAGS;
}
FORCE_RET();
}
void OPPROTO glue(glue(op_shl, MEM_SUFFIX), _T0_T1_cc)(void)
{
int count, src;
count = T1 & 0x1f;
if (count) {
src = (DATA_TYPE)T0 << (count - 1);
T0 = T0 << count;
#ifdef MEM_WRITE
glue(st, SUFFIX)((uint8_t *)A0, T0);
#endif
CC_SRC = src;
CC_DST = T0;
CC_OP = CC_OP_SHLB + SHIFT;
}
FORCE_RET();
}
void OPPROTO glue(glue(op_shr, MEM_SUFFIX), _T0_T1_cc)(void)
{
int count, src;
count = T1 & 0x1f;
if (count) {
T0 &= DATA_MASK;
src = T0 >> (count - 1);
T0 = T0 >> count;
#ifdef MEM_WRITE
glue(st, SUFFIX)((uint8_t *)A0, T0);
#endif
CC_SRC = src;
CC_DST = T0;
CC_OP = CC_OP_SARB + SHIFT;
}
FORCE_RET();
}
void OPPROTO glue(glue(op_sar, MEM_SUFFIX), _T0_T1_cc)(void)
{
int count, src;
count = T1 & 0x1f;
if (count) {
src = (DATA_STYPE)T0;
T0 = src >> count;
src = src >> (count - 1);
#ifdef MEM_WRITE
glue(st, SUFFIX)((uint8_t *)A0, T0);
#endif
CC_SRC = src;
CC_DST = T0;
CC_OP = CC_OP_SARB + SHIFT;
}
FORCE_RET();
}
#if DATA_BITS == 16
/* XXX: overflow flag might be incorrect in some cases in shldw */
void OPPROTO glue(glue(op_shld, MEM_SUFFIX), _T0_T1_im_cc)(void)
{
int count;
unsigned int res, tmp;
count = PARAM1;
T1 &= 0xffff;
res = T1 | (T0 << 16);
tmp = res >> (32 - count);
res <<= count;
if (count > 16)
res |= T1 << (count - 16);
T0 = res >> 16;
#ifdef MEM_WRITE
glue(st, SUFFIX)((uint8_t *)A0, T0);
#endif
CC_SRC = tmp;
CC_DST = T0;
}
void OPPROTO glue(glue(op_shld, MEM_SUFFIX), _T0_T1_ECX_cc)(void)
{
int count;
unsigned int res, tmp;
count = ECX & 0x1f;
if (count) {
T1 &= 0xffff;
res = T1 | (T0 << 16);
tmp = res >> (32 - count);
res <<= count;
if (count > 16)
res |= T1 << (count - 16);
T0 = res >> 16;
#ifdef MEM_WRITE
glue(st, SUFFIX)((uint8_t *)A0, T0);
#endif
CC_SRC = tmp;
CC_DST = T0;
CC_OP = CC_OP_SARB + SHIFT;
}
FORCE_RET();
}
void OPPROTO glue(glue(op_shrd, MEM_SUFFIX), _T0_T1_im_cc)(void)
{
int count;
unsigned int res, tmp;
count = PARAM1;
res = (T0 & 0xffff) | (T1 << 16);
tmp = res >> (count - 1);
res >>= count;
if (count > 16)
res |= T1 << (32 - count);
T0 = res;
#ifdef MEM_WRITE
glue(st, SUFFIX)((uint8_t *)A0, T0);
#endif
CC_SRC = tmp;
CC_DST = T0;
}
void OPPROTO glue(glue(op_shrd, MEM_SUFFIX), _T0_T1_ECX_cc)(void)
{
int count;
unsigned int res, tmp;
count = ECX & 0x1f;
if (count) {
res = (T0 & 0xffff) | (T1 << 16);
tmp = res >> (count - 1);
res >>= count;
if (count > 16)
res |= T1 << (32 - count);
T0 = res;
#ifdef MEM_WRITE
glue(st, SUFFIX)((uint8_t *)A0, T0);
#endif
CC_SRC = tmp;
CC_DST = T0;
CC_OP = CC_OP_SARB + SHIFT;
}
FORCE_RET();
}
#endif
#if DATA_BITS == 32
void OPPROTO glue(glue(op_shld, MEM_SUFFIX), _T0_T1_im_cc)(void)
{
int count, tmp;
count = PARAM1;
T0 &= DATA_MASK;
T1 &= DATA_MASK;
tmp = T0 << (count - 1);
T0 = (T0 << count) | (T1 >> (DATA_BITS - count));
#ifdef MEM_WRITE
glue(st, SUFFIX)((uint8_t *)A0, T0);
#endif
CC_SRC = tmp;
CC_DST = T0;
}
void OPPROTO glue(glue(op_shld, MEM_SUFFIX), _T0_T1_ECX_cc)(void)
{
int count, tmp;
count = ECX & 0x1f;
if (count) {
T0 &= DATA_MASK;
T1 &= DATA_MASK;
tmp = T0 << (count - 1);
T0 = (T0 << count) | (T1 >> (DATA_BITS - count));
#ifdef MEM_WRITE
glue(st, SUFFIX)((uint8_t *)A0, T0);
#endif
CC_SRC = tmp;
CC_DST = T0;
CC_OP = CC_OP_SHLB + SHIFT;
}
FORCE_RET();
}
void OPPROTO glue(glue(op_shrd, MEM_SUFFIX), _T0_T1_im_cc)(void)
{
int count, tmp;
count = PARAM1;
T0 &= DATA_MASK;
T1 &= DATA_MASK;
tmp = T0 >> (count - 1);
T0 = (T0 >> count) | (T1 << (DATA_BITS - count));
#ifdef MEM_WRITE
glue(st, SUFFIX)((uint8_t *)A0, T0);
#endif
CC_SRC = tmp;
CC_DST = T0;
}
void OPPROTO glue(glue(op_shrd, MEM_SUFFIX), _T0_T1_ECX_cc)(void)
{
int count, tmp;
count = ECX & 0x1f;
if (count) {
T0 &= DATA_MASK;
T1 &= DATA_MASK;
tmp = T0 >> (count - 1);
T0 = (T0 >> count) | (T1 << (DATA_BITS - count));
#ifdef MEM_WRITE
glue(st, SUFFIX)((uint8_t *)A0, T0);
#endif
CC_SRC = tmp;
CC_DST = T0;
CC_OP = CC_OP_SARB + SHIFT;
}
FORCE_RET();
}
#endif
/* carry add/sub (we only need to set CC_OP differently) */
void OPPROTO glue(glue(op_adc, MEM_SUFFIX), _T0_T1_cc)(void)
{
int cf;
cf = cc_table[CC_OP].compute_c();
T0 = T0 + T1 + cf;
#ifdef MEM_WRITE
glue(st, SUFFIX)((uint8_t *)A0, T0);
#endif
CC_SRC = T1;
CC_DST = T0;
CC_OP = CC_OP_ADDB + SHIFT + cf * 3;
}
void OPPROTO glue(glue(op_sbb, MEM_SUFFIX), _T0_T1_cc)(void)
{
int cf;
cf = cc_table[CC_OP].compute_c();
T0 = T0 - T1 - cf;
#ifdef MEM_WRITE
glue(st, SUFFIX)((uint8_t *)A0, T0);
#endif
CC_SRC = T1;
CC_DST = T0;
CC_OP = CC_OP_SUBB + SHIFT + cf * 3;
}
void OPPROTO glue(glue(op_cmpxchg, MEM_SUFFIX), _T0_T1_EAX_cc)(void)
{
unsigned int src, dst;
src = T0;
dst = EAX - T0;
if ((DATA_TYPE)dst == 0) {
T0 = T1;
} else {
EAX = (EAX & ~DATA_MASK) | (T0 & DATA_MASK);
}
#ifdef MEM_WRITE
glue(st, SUFFIX)((uint8_t *)A0, T0);
#endif
CC_SRC = src;
CC_DST = dst;
FORCE_RET();
}
#undef MEM_SUFFIX
#undef MEM_WRITE
+2 -1
View File
@@ -3074,7 +3074,8 @@ static int print_insn_powerpc(FILE *, unsigned long insn, unsigned memaddr, int
int print_insn_ppc (bfd_vma pc, disassemble_info *info)
{
return print_insn_powerpc (info->stream, *(unsigned *)(long)pc, pc,
return print_insn_powerpc (info->stream,
(unsigned int)bfd_getb32((bfd_byte *)pc), pc,
PPC_OPCODE_PPC | PPC_OPCODE_601);
}
+533 -41
View File
@@ -1,51 +1,87 @@
\input texinfo @c -*- texinfo -*-
@settitle QEMU x86 Emulator Reference Documentation
@settitle QEMU CPU Emulator Reference Documentation
@titlepage
@sp 7
@center @titlefont{QEMU x86 Emulator Reference Documentation}
@center @titlefont{QEMU CPU Emulator Reference Documentation}
@sp 3
@end titlepage
@chapter Introduction
QEMU is an x86 processor emulator. Its purpose is to run x86 Linux
processes on non-x86 Linux architectures such as PowerPC. By using
dynamic translation it achieves a reasonnable speed while being easy to
port on new host CPUs. Its main goal is to be able to launch the
@code{Wine} Windows API emulator (@url{http://www.winehq.org}) or
@code{DOSEMU} (@url{http://www.dosemu.org}) on non-x86 CPUs.
@section Features
QEMU features:
QEMU is a FAST! processor emulator. By using dynamic translation it
achieves a reasonnable speed while being easy to port on new host
CPUs.
QEMU has two operating modes:
@itemize
@item User mode emulation. In this mode, QEMU can launch Linux processes
compiled for one CPU on another CPU. Linux system calls are converted
because of endianness and 32/64 bit mismatches. The Wine Windows API
emulator (@url{http://www.winehq.org}) and the DOSEMU DOS emulator
(@url{www.dosemu.org}) are the main targets for QEMU.
@item Full system emulation. In this mode, QEMU emulates a full
system, including a processor and various peripherials. Currently, it
is only used to launch an x86 Linux kernel on an x86 Linux system. It
enables easier testing and debugging of system code. It can also be
used to provide virtual hosting of several virtual PCs on a single
server.
@end itemize
As QEMU requires no host kernel patches to run, it is very safe and
easy to use.
QEMU generic features:
@itemize
@item User space only x86 emulator.
@item Currently ported on i386, PowerPC. Work in progress for S390, Alpha and Sparc.
@item User space only or full system emulation.
@item Using dynamic translation to native code for reasonnable speed.
@item The virtual x86 CPU supports 16 bit and 32 bit addressing with segmentation.
User space LDT and GDT are emulated. VM86 mode is also supported.
@item Working on x86 and PowerPC hosts. Being tested on ARM, Sparc32, Alpha and S390.
@item Self-modifying code support.
@item Precise exceptions support.
@item The virtual CPU is a library (@code{libqemu}) which can be used
in other projects.
@end itemize
QEMU user mode emulation features:
@itemize
@item Generic Linux system call converter, including most ioctls.
@item clone() emulation using native CPU clone() to use Linux scheduler for threads.
@item Accurate signal handling by remapping host signals to virtual x86 signals.
@item Accurate signal handling by remapping host signals to target signals.
@end itemize
@end itemize
@item Precise user space x86 exceptions.
QEMU full system emulation features:
@itemize
@item Using mmap() system calls to simulate the MMU
@end itemize
@item Self-modifying code support.
@section x86 emulation
@item Support of host page sizes bigger than 4KB.
QEMU x86 target features:
@itemize
@item The virtual x86 CPU supports 16 bit and 32 bit addressing with segmentation.
LDT/GDT and IDT are emulated. VM86 mode is also supported to run DOSEMU.
@item Support of host page sizes bigger than 4KB in user mode emulation.
@item QEMU can emulate itself on x86.
@item The virtual x86 CPU is a library (@code{libqemu}) which can be used
in other projects.
@item An extensive Linux x86 CPU test program is included @file{tests/test-i386}.
It can be used to test other x86 virtual CPUs.
@@ -62,18 +98,43 @@ Current QEMU limitations:
@item IPC syscalls are missing.
@item The x86 segment limits and access rights are not tested at every
memory access (and will never be to have good performances).
memory access.
@item On non x86 host CPUs, @code{double}s are used instead of the non standard
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.
@end itemize
@chapter Invocation
@section ARM emulation
@itemize
@item ARM emulation can currently launch small programs while using the
generic dynamic code generation architecture of QEMU.
@item No FPU support (yet).
@item No automatic regression testing (yet).
@end itemize
@chapter QEMU User space emulator invocation
@section Quick Start
If you need to compile QEMU, please read the @file{README} which gives
the related information.
In order to launch a Linux process, QEMU needs the process executable
itself and all the target (x86) dynamic libraries used by it.
@@ -171,27 +232,421 @@ Activate log (logfile=/tmp/qemu.log)
Act as if the host page size was 'pagesize' bytes
@end table
@chapter QEMU System emulator invocation
@section Quick Start
This section explains how to launch a Linux kernel inside QEMU.
@enumerate
@item
Download the archive @file{vl-test-xxx.tar.gz} containing a Linux
kernel and a disk image. The archive also contains a precompiled
version of @file{vl}, the QEMU System emulator.
@item Optional: If you want network support (for example to launch X11 examples), you
must copy the script @file{vl-ifup} in @file{/etc} and configure
properly @code{sudo} so that the command @code{ifconfig} contained in
@file{vl-ifup} can be executed as root. You must verify that your host
kernel supports the TUN/TAP network interfaces: the device
@file{/dev/net/tun} must be present.
When network is enabled, there is a virtual network connection between
the host kernel and the emulated kernel. The emulated kernel is seen
from the host kernel at IP address 172.20.0.2 and the host kernel is
seen from the emulated kernel at IP address 172.20.0.1.
@item Launch @code{vl.sh}. You should have the following output:
@example
> ./vl.sh
connected to host network interface: tun0
Uncompressing Linux... Ok, booting the kernel.
Linux version 2.4.20 (fabrice@localhost.localdomain) (gcc version 2.96 20000731 (Red Hat Linux 7.3 2.96-110)) #22 lun jui 7 13:37:41 CEST 2003
BIOS-provided physical RAM map:
BIOS-e801: 0000000000000000 - 000000000009f000 (usable)
BIOS-e801: 0000000000100000 - 0000000002000000 (usable)
32MB LOWMEM available.
On node 0 totalpages: 8192
zone(0): 4096 pages.
zone(1): 4096 pages.
zone(2): 0 pages.
Kernel command line: root=/dev/hda ide1=noprobe ide2=noprobe ide3=noprobe ide4=noprobe ide5=noprobe
ide_setup: ide1=noprobe
ide_setup: ide2=noprobe
ide_setup: ide3=noprobe
ide_setup: ide4=noprobe
ide_setup: ide5=noprobe
Initializing CPU#0
Detected 501.285 MHz processor.
Calibrating delay loop... 989.59 BogoMIPS
Memory: 29268k/32768k available (907k kernel code, 3112k reserved, 212k data, 52k init, 0k highmem)
Dentry cache hash table entries: 4096 (order: 3, 32768 bytes)
Inode cache hash table entries: 2048 (order: 2, 16384 bytes)
Mount-cache hash table entries: 512 (order: 0, 4096 bytes)
Buffer-cache hash table entries: 1024 (order: 0, 4096 bytes)
Page-cache hash table entries: 8192 (order: 3, 32768 bytes)
CPU: Intel Pentium Pro stepping 03
Checking 'hlt' instruction... OK.
POSIX conformance testing by UNIFIX
Linux NET4.0 for Linux 2.4
Based upon Swansea University Computer Society NET3.039
Initializing RT netlink socket
apm: BIOS not found.
Starting kswapd
Journalled Block Device driver loaded
pty: 256 Unix98 ptys configured
Serial driver version 5.05c (2001-07-08) with no serial options enabled
ttyS00 at 0x03f8 (irq = 4) is a 16450
Uniform Multi-Platform E-IDE driver Revision: 6.31
ide: Assuming 50MHz system bus speed for PIO modes; override with idebus=xx
hda: QEMU HARDDISK, ATA DISK drive
ide0 at 0x1f0-0x1f7,0x3f6 on irq 14
hda: 12288 sectors (6 MB) w/256KiB Cache, CHS=12/16/63
Partition check:
hda: unknown partition table
ne.c:v1.10 9/23/94 Donald Becker (becker@scyld.com)
Last modified Nov 1, 2000 by Paul Gortmaker
NE*000 ethercard probe at 0x300: 52 54 00 12 34 56
eth0: NE2000 found at 0x300, using IRQ 9.
RAMDISK driver initialized: 16 RAM disks of 4096K size 1024 blocksize
NET4: Linux TCP/IP 1.0 for NET4.0
IP Protocols: ICMP, UDP, TCP, IGMP
IP: routing cache hash table of 512 buckets, 4Kbytes
TCP: Hash tables configured (established 2048 bind 4096)
NET4: Unix domain sockets 1.0/SMP for Linux NET4.0.
EXT2-fs warning: mounting unchecked fs, running e2fsck is recommended
VFS: Mounted root (ext2 filesystem).
Freeing unused kernel memory: 52k freed
sh: can't access tty; job control turned off
#
@end example
@item
Then you can play with the kernel inside the virtual serial console. You
can launch @code{ls} for example. Type @key{Ctrl-a h} to have an help
about the keys you can type inside the virtual serial console. In
particular, use @key{Ctrl-a x} to exit QEMU and use @key{Ctrl-a b} as
the Magic SysRq key.
@item
If the network is enabled, launch the script @file{/etc/linuxrc} in the
emulator (don't forget the leading dot):
@example
. /etc/linuxrc
@end example
Then enable X11 connections on your PC from the emulated Linux:
@example
xhost +172.20.0.2
@end example
You can now launch @file{xterm} or @file{xlogo} and verify that you have
a real Virtual Linux system !
@end enumerate
NOTES:
@enumerate
@item
A 2.5.74 kernel is also included in the vl-test archive. Just
replace the bzImage in vl.sh to try it.
@item
vl creates a temporary file in @var{$VLTMPDIR} (@file{/tmp} is the
default) containing all the simulated PC memory. If possible, try to use
a temporary directory using the tmpfs filesystem to avoid too many
unnecessary disk accesses.
@item
In order to exit cleanly for vl, you can do a @emph{shutdown} inside
vl. vl will automatically exit when the Linux shutdown is done.
@item
You can boot slightly faster by disabling the probe of non present IDE
interfaces. To do so, add the following options on the kernel command
line:
@example
ide1=noprobe ide2=noprobe ide3=noprobe ide4=noprobe ide5=noprobe
@end example
@item
The example disk image is a modified version of the one made by Kevin
Lawton for the plex86 Project (@url{www.plex86.org}).
@end enumerate
@section Invocation
@example
usage: vl [options] bzImage [kernel parameters...]
@end example
@file{bzImage} is a Linux kernel image.
General options:
@table @option
@item -hda file
@item -hdb file
Use 'file' as hard disk 0 or 1 image (@xref{disk_images}).
@item -snapshot
Write to temporary files instead of disk image files. In this case,
the raw disk image you use is not written back. You can however force
the write back by pressing @key{C-a s} (@xref{disk_images}).
@item -m megs
Set virtual RAM size to @var{megs} megabytes.
@item -n script
Set network init script [default=/etc/vl-ifup]. This script is
launched to configure the host network interface (usually tun0)
corresponding to the virtual NE2000 card.
@item -initrd file
Use 'file' as initial ram disk.
@end table
Debug options:
@table @option
@item -s
Wait gdb connection to port 1234.
@item -p port
Change gdb connection port.
@item -d
Output log in /tmp/vl.log
@end table
During emulation, use @key{C-a h} to get terminal commands:
@table @key
@item C-a h
Print this help
@item C-a x
Exit emulatior
@item C-a s
Save disk data back to file (if -snapshot)
@item C-a b
Send break (magic sysrq)
@item C-a C-a
Send C-a
@end table
@node disk_images
@section Disk Images
@subsection Raw disk images
The disk images can simply be raw images of the hard disk. You can
create them with the command:
@example
dd if=/dev/zero of=myimage bs=1024 count=mysize
@end example
where @var{myimage} is the image filename and @var{mysize} is its size
in kilobytes.
@subsection Snapshot mode
If you use the option @option{-snapshot}, all disk images are
considered as read only. When sectors in written, they are written in
a temporary file created in @file{/tmp}. You can however force the
write back to the raw disk images by pressing @key{C-a s}.
NOTE: The snapshot mode only works with raw disk images.
@subsection Copy On Write disk images
QEMU also supports user mode Linux
(@url{http://user-mode-linux.sourceforge.net/}) Copy On Write (COW)
disk images. The COW disk images are much smaller than normal images
as they store only modified sectors. They also permit the use of the
same disk image template for many users.
To create a COW disk images, use the command:
@example
vlmkcow -f myrawimage.bin mycowimage.cow
@end example
@file{myrawimage.bin} is a raw image you want to use as original disk
image. It will never be written to.
@file{mycowimage.cow} is the COW disk image which is created by
@code{vlmkcow}. You can use it directly with the @option{-hdx}
options. You must not modify the original raw disk image if you use
COW images, as COW images only store the modified sectors from the raw
disk image. QEMU stores the original raw disk image name and its
modified time in the COW disk image so that chances of mistakes are
reduced.
If the raw disk image is not read-only, by pressing @key{C-a s} you
can flush the COW disk image back into the raw disk image, as in
snapshot mode.
COW disk images can also be created without a corresponding raw disk
image. It is useful to have a big initial virtual disk image without
using much disk space. Use:
@example
vlmkcow mycowimage.cow 1024
@end example
to create a 1 gigabyte empty COW disk image.
NOTES:
@enumerate
@item
COW disk images must be created on file systems supporting
@emph{holes} such as ext2 or ext3.
@item
Since holes are used, the displayed size of the COW disk image is not
the real one. To know it, use the @code{ls -ls} command.
@end enumerate
@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):
@enumerate
@item
The kernel must be mapped at 0x90000000 (the default is
0xc0000000). You must modify only two lines in the kernel source:
In @file{include/asm/page.h}, replace
@example
#define __PAGE_OFFSET (0xc0000000)
@end example
by
@example
#define __PAGE_OFFSET (0x90000000)
@end example
And in @file{arch/i386/vmlinux.lds}, replace
@example
. = 0xc0000000 + 0x100000;
@end example
by
@example
. = 0x90000000 + 0x100000;
@end example
@item
If you want to enable SMP (Symmetric Multi-Processing) support, you
must make the following change in @file{include/asm/fixmap.h}. Replace
@example
#define FIXADDR_TOP (0xffffX000UL)
@end example
by
@example
#define FIXADDR_TOP (0xa7ffX000UL)
@end example
(X is 'e' or 'f' depending on the kernel version). Although you can
use an SMP kernel with QEMU, it only supports one CPU.
@item
If you are not using a 2.5 kernel as host kernel but if you use a target
2.5 kernel, you must also ensure that the 'HZ' define is set to 100
(1000 is the default) as QEMU cannot currently emulate timers at
frequencies greater than 100 Hz on host Linux systems < 2.5. In
@file{include/asm/param.h}, replace:
@example
# define HZ 1000 /* Internal kernel timer frequency */
@end example
by
@example
# define HZ 100 /* Internal kernel timer frequency */
@end example
@end enumerate
The file config-2.x.x gives the configuration of the example kernels.
Just type
@example
make bzImage
@end example
As you would do to make a real kernel. Then you can use with QEMU
exactly the same kernel as you would boot on your PC (in
@file{arch/i386/boot/bzImage}).
@section PC Emulation
QEMU emulates the following PC peripherials:
@itemize
@item
PIC (interrupt controler)
@item
PIT (timers)
@item
CMOS memory
@item
Dumb VGA (to print the @code{Uncompressing Linux} message)
@item
Serial port (port=0x3f8, irq=4)
@item
NE2000 network adapter (port=0x300, irq=9)
@item
IDE disk interface (port=0x1f0, irq=14)
@end itemize
@section GDB usage
QEMU has a primitive support to work with gdb, so that you can do
'Ctrl-C' while the kernel is running and inspect its state.
In order to use gdb, launch vl with the '-s' option. It will wait for a
gdb connection:
@example
> vl -s arch/i386/boot/bzImage initrd-2.4.20.img root=/dev/ram0 ramdisk_size=6144
Connected to host network interface: tun0
Waiting gdb connection on port 1234
@end example
Then launch gdb on the 'vmlinux' executable:
@example
> gdb vmlinux
@end example
In gdb, connect to QEMU:
@example
(gdb) target remote locahost:1234
@end example
Then you can use gdb normally. For example, type 'c' to launch the kernel:
@example
(gdb) c
@end example
WARNING: breakpoints and single stepping are not yet supported.
@chapter QEMU Internals
@section QEMU compared to other emulators
Unlike bochs [3], QEMU emulates only a user space x86 CPU. It means that
you cannot launch an operating system with it. The benefit is that it is
simpler and faster due to the fact that some of the low level CPU state
can be ignored (in particular, no virtual memory needs to be emulated).
Like bochs [3], QEMU emulates an x86 CPU. But QEMU is much faster than
bochs as it uses dynamic compilation and because it uses the host MMU to
simulate the x86 MMU. The downside is that currently the emulation is
not as accurate as bochs (for example, you cannot currently run Windows
inside QEMU).
Like Valgrind [2], QEMU does user space emulation and dynamic
translation. Valgrind is mainly a memory debugger while QEMU has no
support for it (QEMU could be used to detect out of bound memory accesses
as Valgrind, but it has no support to track uninitialised data as
Valgrind does). Valgrind dynamic translator generates better code than
QEMU (in particular it does register allocation) but it is closely tied
to an x86 host.
support for it (QEMU could be used to detect out of bound memory
accesses as Valgrind, but it has no support to track uninitialised data
as Valgrind does). The Valgrind dynamic translator generates better code
than QEMU (in particular it does register allocation) but it is closely
tied to an x86 host and target and has no support for precise exceptions
and system emulation.
EM86 [4] is the closest project to QEMU (and QEMU still uses some of its
code, in particular the ELF file loader). EM86 was limited to an alpha
host and used a proprietary and slow interpreter (the interpreter part
of the FX!32 Digital Win32 code translator [5]).
EM86 [4] is the closest project to user space QEMU (and QEMU still uses
some of its code, in particular the ELF file loader). EM86 was limited
to an alpha host and used a proprietary and slow interpreter (the
interpreter part of the FX!32 Digital Win32 code translator [5]).
TWIN [6] is a Windows API emulator like Wine. It is less accurate than
Wine but includes a protected mode x86 interpreter to launch x86 Windows
@@ -200,11 +655,25 @@ Windows API is executed natively but it is far more difficult to develop
because all the data structures and function parameters exchanged
between the API and the x86 code must be converted.
User mode Linux [7] was the only solution before QEMU to launch a Linux
kernel as a process while not needing any host kernel patches. However,
user mode Linux requires heavy kernel patches while QEMU accepts
unpatched Linux kernels. It would be interesting to compare the
performance of the two approaches.
The new Plex86 [8] PC virtualizer is done in the same spirit as the QEMU
system emulator. It requires a patched Linux kernel to work (you cannot
launch the same kernel on your PC), but the patches are really small. As
it is a PC virtualizer (no emulation is done except for some priveledged
instructions), it has the potential of being faster than QEMU. The
downside is that a complicated (and potentially unsafe) host kernel
patch is needed.
@section Portable dynamic translation
QEMU is a dynamic translator. When it first encounters a piece of code,
it converts it to the host instruction set. Usually dynamic translators
are very complicated and highly CPU dependant. QEMU uses some tricks
are very complicated and highly CPU dependent. QEMU uses some tricks
which make it relatively easily portable and simple while achieving good
performances.
@@ -304,7 +773,7 @@ Correct translated code invalidation is done efficiently by maintaining
a linked list of every translated block contained in a given page. Other
linked lists are also maintained to undo direct block chaining.
Althought the overhead of doing @code{mprotect()} calls is important,
Although the overhead of doing @code{mprotect()} calls is important,
most MSDOS programs can be emulated at reasonnable speed with QEMU and
DOSEMU.
@@ -373,7 +842,7 @@ reentrancy.
@section Self-virtualization
QEMU was conceived so that ultimately it can emulate itself. Althought
QEMU was conceived so that ultimately it can emulate itself. Although
it is not very useful, it is an important test to show the power of the
emulator.
@@ -382,6 +851,16 @@ space conflicts. QEMU solves this problem by being an executable ELF
shared object as the ld-linux.so ELF interpreter. That way, it can be
relocated at load time.
@section MMU emulation
For system emulation, QEMU uses the mmap() system call to emulate the
target CPU MMU. It works as long the emulated OS does not use an area
reserved by the host OS (such as the area above 0xc0000000 on x86
Linux).
It is planned to add a slower but more precise MMU emulation
with a software MMU.
@section Bibliography
@table @asis
@@ -412,18 +891,31 @@ Chernoff and Ray Hookway.
@url{http://www.willows.com/}, Windows API library emulation from
Willows 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.
@end table
@chapter Regression Tests
In the directory @file{tests/}, various interesting x86 testing programs
In the directory @file{tests/}, various interesting testing programs
are available. There are used for regression testing.
@section @file{hello}
@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
+1
View File
@@ -25,3 +25,4 @@ struct target_pt_regs {
#define ARM_r0 uregs[0]
#define ARM_ORIG_r0 uregs[17]
#define ARM_SYSCALL_BASE 0x900000
+1 -1
View File
@@ -1,6 +1,6 @@
gmon.out
testsig
hello
hello-i386
hello-arm
sha1.test.c
sha1.c
+2 -2
View File
@@ -12,9 +12,9 @@ QEMU=../qemu
all: $(TESTS)
hello: hello.c
hello-i386: hello-i386.c
$(CC) -nostdlib $(CFLAGS) -static $(LDFLAGS) -o $@ $<
strip hello
strip $@
testclone: testclone.c
$(CC) $(CFLAGS) $(LDFLAGS) -o $@ $<
File renamed without changes.
+17
View File
@@ -77,4 +77,21 @@ myfunc2:
code16_end:
/* other 32 bits tests */
.code32
.globl func_lret32
func_lret32:
movl $0x87654321, %eax
lret
.globl func_iret32
func_iret32:
movl $0xabcd4321, %eax
iret
+30 -4
View File
@@ -1,10 +1,12 @@
#define _GNU_SOURCE
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <inttypes.h>
#include <math.h>
#include <signal.h>
#include <setjmp.h>
#include <errno.h>
#include <sys/ucontext.h>
#include <sys/mman.h>
#include <asm/vm86.h>
@@ -591,7 +593,7 @@ void test_fbcd(double a)
asm("fld1\n"\
prefix "fnstenv %1\n"\
prefix "fldenv %1\n"\
: "=t" (res) : "m" (*(env)) : "st");\
: "=t" (res) : "m" (*(env)));\
printf("res=%f\n", res);\
printf("fpuc=%04x fpus=%04x fptag=%04x\n",\
(env)->fpuc,\
@@ -601,7 +603,7 @@ void test_fbcd(double a)
asm("fld1\n"\
prefix "fnsave %1\n"\
prefix "frstor %1\n"\
: "=t" (res) : "m" (*(env)) : "st");\
: "=t" (res) : "m" (*(env)));\
printf("res=%f\n", res);\
printf("fpuc=%04x fpus=%04x fptag=%04x\n",\
(env)->fpuc,\
@@ -854,7 +856,6 @@ void test_segs(void)
#endif
/* do some tests with fs or gs */
asm volatile ("movl %0, %%fs" : : "r" (MK_SEL(1)));
asm volatile ("movl %0, %%gs" : : "r" (MK_SEL(2)));
seg_data1[1] = 0xaa;
seg_data2[1] = 0x55;
@@ -862,7 +863,12 @@ void test_segs(void)
asm volatile ("fs movzbl 0x1, %0" : "=r" (res));
printf("FS[1] = %02x\n", res);
asm volatile ("gs movzbl 0x1, %0" : "=r" (res));
asm volatile ("pushl %%gs\n"
"movl %1, %%gs\n"
"gs movzbl 0x1, %0\n"
"popl %%gs\n"
: "=r" (res)
: "r" (MK_SEL(2)));
printf("GS[1] = %02x\n", res);
/* tests with ds/ss (implicit segment case) */
@@ -937,6 +943,9 @@ void test_code16(void)
printf("func3() = 0x%08x\n", res);
}
extern char func_lret32;
extern char func_iret32;
void test_misc(void)
{
char table[256];
@@ -946,6 +955,21 @@ void test_misc(void)
res = 0x12345678;
asm ("xlat" : "=a" (res) : "b" (table), "0" (res));
printf("xlat: EAX=%08x\n", res);
asm volatile ("pushl %%cs ; call %1"
: "=a" (res)
: "m" (func_lret32): "memory", "cc");
printf("func_lret32=%x\n", res);
asm volatile ("pushfl ; pushl %%cs ; call %1"
: "=a" (res)
: "m" (func_iret32): "memory", "cc");
printf("func_iret32=%x\n", res);
/* specific popl test */
asm volatile ("pushl $12345432 ; pushl $0x9abcdef ; popl (%%esp) ; popl %0"
: "=g" (res));
printf("popl esp=%x\n", res);
}
uint8_t str_buffer[4096];
@@ -1231,6 +1255,8 @@ void test_exceptions(void)
printf("PF exception:\n");
if (setjmp(jmp_env) == 0) {
val = 1;
/* we add a nop to test a weird PC retrieval case */
asm volatile ("nop");
/* now store in an invalid address */
*(char *)0x1234 = 1;
}
+3
View File
@@ -236,6 +236,7 @@ void thunk_register_struct(int id, const char *name, const argtype *types);
void thunk_register_struct_direct(int id, const char *name, StructEntry *se1);
const argtype *thunk_convert(void *dst, const void *src,
const argtype *type_ptr, int to_host);
#ifndef NO_THUNK_TYPE_SIZE
extern StructEntry struct_entries[];
@@ -312,6 +313,8 @@ static inline int thunk_type_align(const argtype *type_ptr, int is_host)
}
}
#endif /* NO_THUNK_TYPE_SIZE */
unsigned int target_to_host_bitmask(unsigned int x86_mask,
bitmask_transtbl * trans_tbl);
unsigned int host_to_target_bitmask(unsigned int alpha_mask,
+196 -45
View File
@@ -34,6 +34,8 @@ typedef struct DisasContext {
struct TranslationBlock *tb;
} DisasContext;
#define DISAS_JUMP_NEXT 4
/* XXX: move that elsewhere */
static uint16_t *gen_opc_ptr;
static uint32_t *gen_opparam_ptr;
@@ -333,10 +335,11 @@ static void disas_arm_insn(DisasContext *s)
/* if not always execute, we generate a conditional jump to
next instruction */
gen_test_cc[cond ^ 1]((long)s->tb, (long)s->pc);
s->is_jmp = 1;
s->is_jmp = DISAS_JUMP_NEXT;
}
if ((insn & 0x0c000000) == 0 &&
(insn & 0x00000090) != 0x90) {
if (((insn & 0x0e000000) == 0 &&
(insn & 0x00000090) != 0x90) ||
((insn & 0x0e000000) == (1 << 25))) {
int set_cc, logic_cc, shiftop;
op1 = (insn >> 21) & 0xf;
@@ -367,7 +370,7 @@ static void disas_arm_insn(DisasContext *s)
}
}
} else {
rs = (insn >> 16) & 0xf;
rs = (insn >> 8) & 0xf;
gen_movl_T0_reg(s, rs);
if (logic_cc) {
gen_shift_T1_T0_cc[shiftop]();
@@ -385,10 +388,14 @@ static void disas_arm_insn(DisasContext *s)
case 0x00:
gen_op_andl_T0_T1();
gen_movl_reg_T0(s, rd);
if (logic_cc)
gen_op_logic_T0_cc();
break;
case 0x01:
gen_op_xorl_T0_T1();
gen_movl_reg_T0(s, rd);
if (logic_cc)
gen_op_logic_T0_cc();
break;
case 0x02:
if (set_cc)
@@ -435,11 +442,13 @@ static void disas_arm_insn(DisasContext *s)
case 0x08:
if (set_cc) {
gen_op_andl_T0_T1();
gen_op_logic_T0_cc();
}
break;
case 0x09:
if (set_cc) {
gen_op_xorl_T0_T1();
gen_op_logic_T0_cc();
}
break;
case 0x0a:
@@ -455,22 +464,28 @@ static void disas_arm_insn(DisasContext *s)
case 0x0c:
gen_op_orl_T0_T1();
gen_movl_reg_T0(s, rd);
if (logic_cc)
gen_op_logic_T0_cc();
break;
case 0x0d:
gen_movl_reg_T1(s, rd);
if (logic_cc)
gen_op_logic_T1_cc();
break;
case 0x0e:
gen_op_bicl_T0_T1();
gen_movl_reg_T0(s, rd);
if (logic_cc)
gen_op_logic_T0_cc();
break;
default:
case 0x0f:
gen_op_notl_T1();
gen_movl_reg_T1(s, rd);
if (logic_cc)
gen_op_logic_T1_cc();
break;
}
if (logic_cc)
gen_op_logic_cc();
} else {
/* other instructions */
op1 = (insn >> 24) & 0xf;
@@ -494,7 +509,7 @@ static void disas_arm_insn(DisasContext *s)
gen_op_addl_T0_T1();
}
if (insn & (1 << 20))
gen_op_logic_cc();
gen_op_logic_T0_cc();
gen_movl_reg_T0(s, rd);
} else {
/* 64 bit mul */
@@ -551,10 +566,12 @@ static void disas_arm_insn(DisasContext *s)
/* store */
gen_op_stw_T0_T1();
}
if (!(insn & (1 << 24)))
if (!(insn & (1 << 24))) {
gen_add_datah_offset(s, insn);
if (insn & (1 << 21))
gen_movl_reg_T1(s, rn);
} else if (insn & (1 << 21)) {
gen_movl_reg_T1(s, rn);
}
}
break;
case 0x4:
@@ -582,40 +599,94 @@ static void disas_arm_insn(DisasContext *s)
else
gen_op_stl_T0_T1();
}
if (!(insn & (1 << 24)))
if (!(insn & (1 << 24))) {
gen_add_data_offset(s, insn);
if (insn & (1 << 21))
gen_movl_reg_T1(s, rn);
} else if (insn & (1 << 21))
gen_movl_reg_T1(s, rn); {
}
break;
case 0x08:
case 0x09:
/* load/store multiple words */
if (insn & (1 << 22))
goto illegal_op; /* only usable in supervisor mode */
rn = (insn >> 16) & 0xf;
gen_movl_T1_reg(s, rn);
val = 4;
if (!(insn & (1 << 23)))
val = -val;
for(i=0;i<16;i++) {
if (insn & (1 << i)) {
if (insn & (1 << 24))
gen_op_addl_T1_im(val);
if (insn & (1 << 20)) {
/* load */
gen_op_ldl_T0_T1();
gen_movl_reg_T0(s, i);
{
int j, n;
/* load/store multiple words */
/* XXX: store correct base if write back */
if (insn & (1 << 22))
goto illegal_op; /* only usable in supervisor mode */
rn = (insn >> 16) & 0xf;
gen_movl_T1_reg(s, rn);
/* compute total size */
n = 0;
for(i=0;i<16;i++) {
if (insn & (1 << i))
n++;
}
/* XXX: test invalid n == 0 case ? */
if (insn & (1 << 23)) {
if (insn & (1 << 24)) {
/* pre increment */
gen_op_addl_T1_im(4);
} else {
/* store */
gen_movl_T0_reg(s, i);
gen_op_stl_T0_T1();
/* post increment */
}
if (!(insn & (1 << 24)))
gen_op_addl_T1_im(val);
} else {
if (insn & (1 << 24)) {
/* pre decrement */
gen_op_addl_T1_im(-(n * 4));
} else {
/* post decrement */
if (n != 1)
gen_op_addl_T1_im(-((n - 1) * 4));
}
}
j = 0;
for(i=0;i<16;i++) {
if (insn & (1 << i)) {
if (insn & (1 << 20)) {
/* load */
gen_op_ldl_T0_T1();
gen_movl_reg_T0(s, i);
} else {
/* store */
if (i == 15) {
/* special case: r15 = PC + 12 */
val = (long)s->pc + 8;
gen_op_movl_TN_im[0](val);
} else {
gen_movl_T0_reg(s, i);
}
gen_op_stl_T0_T1();
}
j++;
/* no need to add after the last transfer */
if (j != n)
gen_op_addl_T1_im(4);
}
}
if (insn & (1 << 21)) {
/* write back */
if (insn & (1 << 23)) {
if (insn & (1 << 24)) {
/* pre increment */
} else {
/* post increment */
gen_op_addl_T1_im(4);
}
} else {
if (insn & (1 << 24)) {
/* pre decrement */
if (n != 1)
gen_op_addl_T1_im(-((n - 1) * 4));
} else {
/* post decrement */
gen_op_addl_T1_im(-(n * 4));
}
}
gen_movl_reg_T1(s, rn);
}
}
if (insn & (1 << 21))
gen_movl_reg_T1(s, rn);
break;
case 0xa:
case 0xb:
@@ -641,6 +712,66 @@ static void disas_arm_insn(DisasContext *s)
gen_op_swi();
s->is_jmp = DISAS_JUMP;
break;
case 0xc:
case 0xd:
rd = (insn >> 12) & 0x7;
rn = (insn >> 16) & 0xf;
gen_movl_T1_reg(s, rn);
val = (insn) & 0xff;
if (!(insn & (1 << 23)))
val = -val;
switch((insn >> 8) & 0xf) {
case 0x1:
/* load/store */
if ((insn & (1 << 24)))
gen_op_addl_T1_im(val);
/* XXX: do it */
if (!(insn & (1 << 24)))
gen_op_addl_T1_im(val);
if (insn & (1 << 21))
gen_movl_reg_T1(s, rn);
break;
case 0x2:
{
int n, i;
/* load store multiple */
if ((insn & (1 << 24)))
gen_op_addl_T1_im(val);
switch(insn & 0x00408000) {
case 0x00008000: n = 1; break;
case 0x00400000: n = 2; break;
case 0x00408000: n = 3; break;
default: n = 4; break;
}
for(i = 0;i < n; i++) {
/* XXX: do it */
}
if (!(insn & (1 << 24)))
gen_op_addl_T1_im(val);
if (insn & (1 << 21))
gen_movl_reg_T1(s, rn);
}
break;
default:
goto illegal_op;
}
break;
case 0x0e:
/* float ops */
/* XXX: do it */
switch((insn >> 20) & 0xf) {
case 0x2: /* wfs */
break;
case 0x3: /* rfs */
break;
case 0x4: /* wfc */
break;
case 0x5: /* rfc */
break;
default:
goto illegal_op;
}
break;
default:
illegal_op:
gen_op_movl_T0_im((long)s->pc - 4);
@@ -655,7 +786,7 @@ static void disas_arm_insn(DisasContext *s)
/* generate intermediate code in gen_opc_buf and gen_opparam_buf for
basic block 'tb'. If search_pc is TRUE, also generate PC
information for each intermediate instruction. */
int gen_intermediate_code(TranslationBlock *tb, int search_pc)
static inline int gen_intermediate_code_internal(TranslationBlock *tb, int search_pc)
{
DisasContext dc1, *dc = &dc1;
uint16_t *gen_opc_end;
@@ -681,22 +812,27 @@ int gen_intermediate_code(TranslationBlock *tb, int search_pc)
lj++;
while (lj < j)
gen_opc_instr_start[lj++] = 0;
gen_opc_pc[lj] = (uint32_t)dc->pc;
gen_opc_instr_start[lj] = 1;
}
gen_opc_pc[lj] = (uint32_t)dc->pc;
gen_opc_instr_start[lj] = 1;
}
disas_arm_insn(dc);
} while (!dc->is_jmp && gen_opc_ptr < gen_opc_end &&
(dc->pc - pc_start) < (TARGET_PAGE_SIZE - 32));
/* we must store the eflags state if it is not already done */
if (dc->is_jmp != DISAS_TB_JUMP &&
dc->is_jmp != DISAS_JUMP) {
gen_op_movl_T0_im((long)dc->pc - 4);
gen_op_movl_reg_TN[0][15]();
}
if (dc->is_jmp != DISAS_TB_JUMP) {
switch(dc->is_jmp) {
case DISAS_JUMP_NEXT:
case DISAS_NEXT:
gen_op_jmp((long)dc->tb, (long)dc->pc);
break;
default:
case DISAS_JUMP:
/* indicate that the hash table must be used to find the next TB */
gen_op_movl_T0_0();
gen_op_exit_tb();
break;
case DISAS_TB_JUMP:
/* nothing more to generate */
break;
}
*gen_opc_ptr = INDEX_op_end;
@@ -717,6 +853,16 @@ int gen_intermediate_code(TranslationBlock *tb, int search_pc)
return 0;
}
int gen_intermediate_code(TranslationBlock *tb)
{
return gen_intermediate_code_internal(tb, 0);
}
int gen_intermediate_code_pc(TranslationBlock *tb)
{
return gen_intermediate_code_internal(tb, 1);
}
CPUARMState *cpu_arm_init(void)
{
CPUARMState *env;
@@ -746,5 +892,10 @@ void cpu_arm_dump_state(CPUARMState *env, FILE *f, int flags)
else
fprintf(f, " ");
}
fprintf(f, "CPSR=%08x", env->cpsr);
fprintf(f, "PSR=%08x %c%c%c%c\n",
env->cpsr,
env->cpsr & (1 << 31) ? 'N' : '-',
env->cpsr & (1 << 30) ? 'Z' : '-',
env->cpsr & (1 << 29) ? 'C' : '-',
env->cpsr & (1 << 28) ? 'V' : '-');
}
+790 -150
View File
File diff suppressed because it is too large. Load diff
+54 -15
View File
@@ -24,37 +24,55 @@
#include <inttypes.h>
#include "config.h"
#define IN_OP_I386
#include "cpu-" TARGET_ARCH ".h"
#if defined(TARGET_I386)
#include "cpu-i386.h"
#define OPC_CPU_H "opc-i386.h"
#elif defined(TARGET_ARM)
#include "cpu-arm.h"
#define OPC_CPU_H "opc-arm.h"
#else
#error unsupported target CPU
#endif
#include "exec.h"
#include "disas.h"
enum {
#define DEF(s, n, copy_size) INDEX_op_ ## s,
#include "opc-" TARGET_ARCH ".h"
#include OPC_CPU_H
#undef DEF
NB_OPS,
};
#include "dyngen.h"
#include "op-" TARGET_ARCH ".h"
#if defined(TARGET_I386)
#include "op-i386.h"
#elif defined(TARGET_ARM)
#include "op-arm.h"
#else
#error unsupported target CPU
#endif
uint16_t gen_opc_buf[OPC_BUF_SIZE];
uint32_t gen_opparam_buf[OPPARAM_BUF_SIZE];
uint32_t gen_opc_pc[OPC_BUF_SIZE];
uint8_t gen_opc_instr_start[OPC_BUF_SIZE];
#if defined(TARGET_I386)
uint8_t gen_opc_cc_op[OPC_BUF_SIZE];
#endif
#ifdef DEBUG_DISAS
static const char *op_str[] = {
#define DEF(s, n, copy_size) #s,
#include "opc-" TARGET_ARCH ".h"
#include OPC_CPU_H
#undef DEF
};
static uint8_t op_nb_args[] = {
#define DEF(s, n, copy_size) n,
#include "opc-" TARGET_ARCH ".h"
#include OPC_CPU_H
#undef DEF
};
@@ -95,7 +113,7 @@ int cpu_gen_code(TranslationBlock *tb,
uint8_t *gen_code_buf;
int gen_code_size;
if (gen_intermediate_code(tb, 0) < 0)
if (gen_intermediate_code(tb) < 0)
return -1;
/* generate machine code */
@@ -123,22 +141,20 @@ int cpu_gen_code(TranslationBlock *tb,
static const unsigned short opc_copy_size[] = {
#define DEF(s, n, copy_size) copy_size,
#include "opc-" TARGET_ARCH ".h"
#include OPC_CPU_H
#undef DEF
};
/* The simulated PC corresponding to
'searched_pc' in the generated code is searched. 0 is returned if
found. *found_pc contains the found PC.
/* The cpu state corresponding to 'searched_pc' is restored.
*/
int cpu_search_pc(TranslationBlock *tb,
uint32_t *found_pc, unsigned long searched_pc)
int cpu_restore_state(TranslationBlock *tb,
CPUState *env, unsigned long searched_pc)
{
int j, c;
unsigned long tc_ptr;
uint16_t *opc_ptr;
if (gen_intermediate_code(tb, 1) < 0)
if (gen_intermediate_code_pc(tb) < 0)
return -1;
/* find opc index corresponding to search_pc */
@@ -160,7 +176,30 @@ int cpu_search_pc(TranslationBlock *tb,
/* now find start of instruction before */
while (gen_opc_instr_start[j] == 0)
j--;
*found_pc = gen_opc_pc[j];
#if defined(TARGET_I386)
{
int cc_op;
#ifdef DEBUG_DISAS
if (loglevel) {
int i;
fprintf(logfile, "RESTORE:\n");
for(i=0;i<=j; i++) {
if (gen_opc_instr_start[i]) {
fprintf(logfile, "0x%04x: 0x%08x\n", i, gen_opc_pc[i]);
}
}
fprintf(logfile, "spc=0x%08lx j=0x%x eip=0x%lx cs_base=%lx\n",
searched_pc, j, gen_opc_pc[j] - tb->cs_base, tb->cs_base);
}
#endif
env->eip = gen_opc_pc[j] - tb->cs_base;
cc_op = gen_opc_cc_op[j];
if (cc_op != CC_OP_DYNAMIC)
env->cc_op = cc_op;
}
#elif defined(TARGET_ARM)
env->regs[15] = gen_opc_pc[j];
#endif
return 0;
}
+2891
View File
File diff suppressed because it is too large. Load diff
+55
View File
@@ -0,0 +1,55 @@
/*
* QEMU System Emulator header
*
* Copyright (c) 2003 Fabrice Bellard
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
#ifndef VL_H
#define VL_H
/* vl.c */
void *get_mmap_addr(unsigned long size);
/* block.c */
typedef struct BlockDriverState BlockDriverState;
BlockDriverState *bdrv_open(const char *filename, int snapshot);
void bdrv_close(BlockDriverState *bs);
int bdrv_read(BlockDriverState *bs, int64_t sector_num,
uint8_t *buf, int nb_sectors);
int bdrv_write(BlockDriverState *bs, int64_t sector_num,
const uint8_t *buf, int nb_sectors);
void bdrv_get_geometry(BlockDriverState *bs, int64_t *nb_sectors_ptr);
int bdrv_commit(BlockDriverState *bs);
/* user mode linux compatible COW file */
#define COW_MAGIC 0x4f4f4f4d /* MOOO */
#define COW_VERSION 2
struct cow_header_v2 {
uint32_t magic;
uint32_t long version;
char backing_file[1024];
int32_t mtime;
uint64_t size;
uint32_t sectorsize;
};
#endif /* VL_H */
+143
View File
@@ -0,0 +1,143 @@
/*
* create a COW disk image
*
* Copyright (c) 2003 Fabrice Bellard
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
#include <stdlib.h>
#include <stdio.h>
#include <stdarg.h>
#include <string.h>
#include <getopt.h>
#include <inttypes.h>
#include <unistd.h>
#include <sys/mman.h>
#include <fcntl.h>
#include <signal.h>
#include <time.h>
#include <sys/time.h>
#include <malloc.h>
#include <termios.h>
#include <sys/poll.h>
#include <errno.h>
#include <sys/wait.h>
#include <netinet/in.h>
#include "vl.h"
#define NO_THUNK_TYPE_SIZE
#include "thunk.h"
int cow_create(int cow_fd, const char *image_filename,
int64_t image_sectors)
{
struct cow_header_v2 cow_header;
int fd;
struct stat st;
memset(&cow_header, 0, sizeof(cow_header));
cow_header.magic = htonl(COW_MAGIC);
cow_header.version = htonl(COW_VERSION);
if (image_filename) {
fd = open(image_filename, O_RDONLY);
if (fd < 0) {
perror(image_filename);
exit(1);
}
image_sectors = lseek64(fd, 0, SEEK_END);
if (fstat(fd, &st) != 0) {
close(fd);
return -1;
}
close(fd);
image_sectors /= 512;
cow_header.mtime = htonl(st.st_mtime);
realpath(image_filename, cow_header.backing_file);
}
cow_header.sectorsize = htonl(512);
cow_header.size = image_sectors * 512;
#ifndef WORDS_BIGENDIAN
cow_header.size = bswap64(cow_header.size);
#endif
write(cow_fd, &cow_header, sizeof(cow_header));
/* resize to include at least all the bitmap */
ftruncate(cow_fd, sizeof(cow_header) + ((image_sectors + 7) >> 3));
lseek(cow_fd, 0, SEEK_SET);
return 0;
}
void help(void)
{
printf("vlmkcow version " QEMU_VERSION ", Copyright (c) 2003 Fabrice Bellard\n"
"usage: vlmkcow [-h] [-f disk_image] cow_image [cow_size]\n"
"Create a Copy On Write disk image from an optional raw disk image\n"
"\n"
"-f disk_image set the raw disk image name\n"
"cow_image the created cow_image\n"
"cow_size the create cow_image size in MB if no raw disk image is used\n"
"\n"
"Once the cow_image is created from a raw disk image, you must not modify the original raw disk image\n"
);
exit(1);
}
int main(int argc, char **argv)
{
const char *image_filename, *cow_filename;
int cow_fd, c, nb_args;
int64_t image_size;
image_filename = NULL;
image_size = 0;
for(;;) {
c = getopt(argc, argv, "hf:");
if (c == -1)
break;
switch(c) {
case 'h':
help();
break;
case 'f':
image_filename = optarg;
break;
}
}
if (!image_filename)
nb_args = 2;
else
nb_args = 1;
if (optind + nb_args != argc)
help();
cow_filename = argv[optind];
if (nb_args == 2) {
image_size = (int64_t)atoi(argv[optind + 1]) * 2 * 1024;
}
cow_fd = open(cow_filename, O_RDWR | O_CREAT | O_TRUNC, 0644);
if (!cow_fd < 0)
return -1;
if (cow_create(cow_fd, image_filename, image_size) < 0) {
fprintf(stderr, "%s: error while formating\n", cow_filename);
exit(1);
}
close(cow_fd);
return 0;
}