Compare commits

...
115 Commits
Author SHA1 Message Date
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
bellard de83cd02e0 arm emulation support
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@246 c046a42c-6fe2-441c-8c8c-71466251a162
2003-06-15 20:25:43 +00:00
bellard 6380ab5e26 added missing link scripts
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@245 c046a42c-6fe2-441c-8c8c-71466251a162
2003-06-15 20:25:04 +00:00
bellard b346ff468e ARM emulation support
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@244 c046a42c-6fe2-441c-8c8c-71466251a162
2003-06-15 20:05:50 +00:00
bellard 5a9fdfec7e factorized cpu defines
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@243 c046a42c-6fe2-441c-8c8c-71466251a162
2003-06-15 20:02:25 +00:00
bellard d19893dab5 extracted generic code
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@242 c046a42c-6fe2-441c-8c8c-71466251a162
2003-06-15 19:58:51 +00:00
bellard 2521d69883 factorized more definitions - suppressed broken sound ioctls
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@241 c046a42c-6fe2-441c-8c8c-71466251a162
2003-06-15 19:58:13 +00:00
bellard 2ab83ea784 automatic ioctl number conversion - minimum ARM fork() support
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@240 c046a42c-6fe2-441c-8c8c-71466251a162
2003-06-15 19:56:46 +00:00
bellard 2437490100 fixed serious ioctl parameter conversion issue - exported type size and align functions
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@239 c046a42c-6fe2-441c-8c8c-71466251a162
2003-06-15 19:52:54 +00:00
bellard e4533c7a8c main cpu loop is target independent
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@238 c046a42c-6fe2-441c-8c8c-71466251a162
2003-06-15 19:51:39 +00:00
bellard 1e5ffbedde fixed float to int overflow bug - added ARM host correct roundings for float rounding
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@237 c046a42c-6fe2-441c-8c8c-71466251a162
2003-06-15 19:49:16 +00:00
bellard 79638566e5 moved dyngen generic code to dyngen-exec.h
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@236 c046a42c-6fe2-441c-8c8c-71466251a162
2003-06-15 19:46:57 +00:00
bellard 03daf0e361 moved cache flush to dyngen header
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@235 c046a42c-6fe2-441c-8c8c-71466251a162
2003-06-15 19:45:20 +00:00
bellard d219f7e7ed output gen_op_xxx() in a separate file
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@234 c046a42c-6fe2-441c-8c8c-71466251a162
2003-06-15 19:44:49 +00:00
bellard 95cbfc643d changed disas() prototype for multi target support
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@233 c046a42c-6fe2-441c-8c8c-71466251a162
2003-06-15 19:44:10 +00:00
bellard 5898e81684 ARM emulation support
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@232 c046a42c-6fe2-441c-8c8c-71466251a162
2003-06-15 19:42:24 +00:00
bellard 394411ac74 added hello world for ARM
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@231 c046a42c-6fe2-441c-8c8c-71466251a162
2003-06-15 19:37:07 +00:00
bellard ea76864009 more precise float rounding tests
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@230 c046a42c-6fe2-441c-8c8c-71466251a162
2003-06-15 19:36:33 +00:00
bellard 43ce4dfe9e added static build option
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@229 c046a42c-6fe2-441c-8c8c-71466251a162
2003-06-09 19:53:12 +00:00
bellard ebc06f87ca alpha fix
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@228 c046a42c-6fe2-441c-8c8c-71466251a162
2003-06-09 19:46:12 +00:00
bellard 5bbe92995c disas endian fix
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@227 c046a42c-6fe2-441c-8c8c-71466251a162
2003-06-09 19:38:38 +00:00
bellard 411bffc41c update
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@226 c046a42c-6fe2-441c-8c8c-71466251a162
2003-06-09 15:38:23 +00:00
bellard ff1f20a3ee arm support - suppressed possibly unsafe sparc nop deletion
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@225 c046a42c-6fe2-441c-8c8c-71466251a162
2003-06-09 15:34:19 +00:00
bellard 9c5d1246c7 use -mflat for helper-i386.c on sparc - use custom ld script on sparc to free zero memory addresses for vm86 emulation - arm support
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@224 c046a42c-6fe2-441c-8c8c-71466251a162
2003-06-09 15:33:05 +00:00
bellard 8dd7cb0621 moved to disas.c
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@223 c046a42c-6fe2-441c-8c8c-71466251a162
2003-06-09 15:31:02 +00:00
bellard d30329297b removed unused dependancy if non x86
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@222 c046a42c-6fe2-441c-8c8c-71466251a162
2003-06-09 15:30:37 +00:00
bellard a95c67907c arm support
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@221 c046a42c-6fe2-441c-8c8c-71466251a162
2003-06-09 15:29:55 +00:00
bellard 0f533160c7 removed unused code
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@220 c046a42c-6fe2-441c-8c8c-71466251a162
2003-06-09 15:29:20 +00:00
bellard e163bca720 weird arm double format support
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@219 c046a42c-6fe2-441c-8c8c-71466251a162
2003-06-09 15:28:45 +00:00
bellard 8c6939c0b0 arm support - modified sparc to work with direct chaining
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@218 c046a42c-6fe2-441c-8c8c-71466251a162
2003-06-09 15:28:00 +00:00
bellard 2d0e9143e2 more code moved to helpers - sipmplified x86 float constants definitions
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@217 c046a42c-6fe2-441c-8c8c-71466251a162
2003-06-09 15:25:54 +00:00
bellard 87f4827e1d more code moved to helpers
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@216 c046a42c-6fe2-441c-8c8c-71466251a162
2003-06-09 15:24:58 +00:00
bellard 4a585ccb2f avoid unaligned file offset in anonymous mapping
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@215 c046a42c-6fe2-441c-8c8c-71466251a162
2003-06-09 15:24:18 +00:00
bellard aa0aa4fa31 added ARM and Sparc disassemblers
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@214 c046a42c-6fe2-441c-8c8c-71466251a162
2003-06-09 15:23:31 +00:00
bellard 84fa15d854 big endian/unaligned fix
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@213 c046a42c-6fe2-441c-8c8c-71466251a162
2003-06-09 15:20:55 +00:00
bellard 4add45b4f6 getdents for 64 bit cpus
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@212 c046a42c-6fe2-441c-8c8c-71466251a162
2003-06-05 01:52:59 +00:00
bellard 4f101ad7ff 64 bit fix
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@211 c046a42c-6fe2-441c-8c8c-71466251a162
2003-06-05 01:52:19 +00:00
bellard c1db2eb8c3 tested tools
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@210 c046a42c-6fe2-441c-8c8c-71466251a162
2003-06-05 01:05:11 +00:00
bellard 82d19dafe4 added helper-i386.c - alpha fixes
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@209 c046a42c-6fe2-441c-8c8c-71466251a162
2003-06-05 00:58:28 +00:00
bellard 5286db75a8 convert mmap flags (alpha fix)
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@208 c046a42c-6fe2-441c-8c8c-71466251a162
2003-06-05 00:57:30 +00:00
bellard 917f95fd4d alpha fix
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@207 c046a42c-6fe2-441c-8c8c-71466251a162
2003-06-05 00:56:37 +00:00
bellard fe31975692 fixed __op_label handling if RELA relocations are used
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@206 c046a42c-6fe2-441c-8c8c-71466251a162
2003-06-05 00:56:05 +00:00
bellard 95f7652d65 use 32 bit pointer for tb_next even on 64 bit archs
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@205 c046a42c-6fe2-441c-8c8c-71466251a162
2003-06-05 00:54:44 +00:00
bellard 3ec9c4fcc6 separated helpers from micro operations
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@204 c046a42c-6fe2-441c-8c8c-71466251a162
2003-06-05 00:54:09 +00:00
bellard 2f87c60799 Alpha update (Falk Hueffner)
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@203 c046a42c-6fe2-441c-8c8c-71466251a162
2003-06-02 20:38:09 +00:00
bellard 03bfca946a more FPU tests
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@202 c046a42c-6fe2-441c-8c8c-71466251a162
2003-05-29 20:06:57 +00:00
bellard ed2dcdf68e save FPU state in signal handler
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@201 c046a42c-6fe2-441c-8c8c-71466251a162
2003-05-29 20:06:27 +00:00
bellard 4304763ba2 misplaced #endif
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@200 c046a42c-6fe2-441c-8c8c-71466251a162
2003-05-29 20:05:35 +00:00
bellard c1e42a1397 search data in both .data and .sdata
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@199 c046a42c-6fe2-441c-8c8c-71466251a162
2003-05-29 20:05:18 +00:00
bellard d0a1ffc957 added fsave/frstor/fstenv/fldenv/fcomi - fixed cpuid - make lret/iret restartable
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@198 c046a42c-6fe2-441c-8c8c-71466251a162
2003-05-29 20:04:28 +00:00
66 changed files with 18779 additions and 3993 deletions

No files matched your search

+38 -4
View File
@@ -1,9 +1,43 @@
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
- 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)
+90 -26
View File
@@ -4,11 +4,17 @@ CFLAGS=-Wall -O2 -g
LDFLAGS=-g
LIBS=
DEFINES=-DHAVE_BYTESWAP_H
HELPER_CFLAGS=$(CFLAGS)
PROGS=qemu
ifdef CONFIG_STATIC
LDFLAGS+=-static
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
@@ -21,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)
@@ -37,6 +46,8 @@ ifeq ($(ARCH),sparc)
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
endif
ifeq ($(ARCH),sparc64)
@@ -50,7 +61,7 @@ ifeq ($(ARCH),alpha)
# for the constant constructions
OP_CFLAGS=-Wall -O2 -g
# Ensure there's only a single GP
CFLAGS += -msmall-data -msmall-text
CFLAGS += -msmall-data
LDFLAGS+=-Wl,-T,alpha.ld
endif
@@ -58,7 +69,12 @@ ifeq ($(ARCH),ia64)
OP_CFLAGS=$(CFLAGS)
endif
ifeq ($(GCC_MAJOR),3)
ifeq ($(ARCH),arm)
OP_CFLAGS=$(CFLAGS) -mno-sched-prolog
LDFLAGS+=-Wl,-T,arm.ld
endif
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
@@ -74,26 +90,46 @@ LDFLAGS+=-p
main.o: CFLAGS+=-p
endif
OBJS= elfload.o main.o syscall.o mmap.o signal.o vm86.o path.o
OBJS= elfload.o main.o syscall.o mmap.o signal.o path.o
ifeq ($(TARGET_ARCH), i386)
OBJS+= vm86.o
endif
SRCS:= $(OBJS:.o=.c)
OBJS+= libqemu.a
LIBOBJS+=thunk.o translate-i386.o op-i386.o exec-i386.o exec.o
# cpu emulator library
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
endif
ifeq ($(TARGET_ARCH), arm)
LIBOBJS+=translate-arm.o op-arm.o
endif
# NOTE: the disassembler code is only needed for debugging
LIBOBJS+=disas.o i386-dis.o dis-buf.o
ifeq ($(ARCH),alpha)
LIBOBJS+=disas.o
ifeq ($(findstring i386, $(TARGET_ARCH) $(ARCH)),i386)
LIBOBJS+=i386-dis.o
endif
ifeq ($(findstring alpha, $(TARGET_ARCH) $(ARCH)),alpha)
LIBOBJS+=alpha-dis.o
endif
ifeq ($(ARCH),ppc)
ifeq ($(findstring ppc, $(TARGET_ARCH) $(ARCH)),ppc)
LIBOBJS+=ppc-dis.o
endif
ifeq ($(findstring sparc, $(TARGET_ARCH) $(ARCH)),sparc)
LIBOBJS+=sparc-dis.o
endif
ifeq ($(findstring arm, $(TARGET_ARCH) $(ARCH)),arm)
LIBOBJS+=arm-dis.o
endif
ifeq ($(ARCH),ia64)
OBJS += ia64-syscall.o
endif
all: qemu qemu-doc.html
all: $(PROGS) qemu-doc.html
qemu: $(OBJS)
$(CC) $(LDFLAGS) -o $@ $^ $(LIBS)
@@ -103,6 +139,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
@@ -115,17 +158,29 @@ libqemu.a: $(LIBOBJS)
dyngen: dyngen.c
$(HOST_CC) -O2 -Wall -g $< -o $@
translate-i386.o: translate-i386.c op-i386.h opc-i386.h cpu-i386.h
translate-$(TARGET_ARCH).o: translate-$(TARGET_ARCH).c gen-op-$(TARGET_ARCH).h opc-$(TARGET_ARCH).h cpu-$(TARGET_ARCH).h
op-i386.h: op-i386.o dyngen
translate.o: translate.c op-$(TARGET_ARCH).h opc-$(TARGET_ARCH).h cpu-$(TARGET_ARCH).h
op-$(TARGET_ARCH).h: op-$(TARGET_ARCH).o dyngen
./dyngen -o $@ $<
opc-i386.h: op-i386.o dyngen
opc-$(TARGET_ARCH).h: op-$(TARGET_ARCH).o dyngen
./dyngen -c -o $@ $<
op-i386.o: op-i386.c opreg_template.h ops_template.h
gen-op-$(TARGET_ARCH).h: op-$(TARGET_ARCH).o dyngen
./dyngen -g -o $@ $<
op-$(TARGET_ARCH).o: op-$(TARGET_ARCH).c
$(CC) $(OP_CFLAGS) $(DEFINES) -c -o $@ $<
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 ops_template_mem.h
op-arm.o: op-arm.c op-arm-template.h
%.o: %.c
$(CC) $(CFLAGS) $(DEFINES) -c -o $@ $<
@@ -136,8 +191,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
@@ -152,17 +208,25 @@ qemu-doc.html: qemu-doc.texi
FILES= \
README README.distrib COPYING COPYING.LIB TODO Changelog VERSION \
dyngen.c ioctls.h ops_template.h op_string.h syscall_types.h\
Makefile elf.h thunk.c\
elfload.c main.c signal.c thunk.h exec.h\
cpu-i386.h qemu.h op-i386.c syscall-i386.h translate-i386.c\
syscall.c opreg_template.h syscall_defs.h vm86.c\
dis-asm.h dis-buf.c disas.c disas.h alpha-dis.c ppc-dis.c i386-dis.c\
ppc.ld s390.ld exec-i386.h exec-i386.c path.c exec.c mmap.c configure \
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/hello.c tests/hello tests/sha1.c \
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 \
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 gdbstub.c\
cpu-i386.h op-i386.c helper-i386.c syscall-i386.h translate-i386.c \
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-i386.c tests/hello-i386 \
tests/hello-arm.c tests/hello-arm \
tests/sha1.c \
tests/testsig.c tests/testclone.c tests/testthread.c \
tests/runcom.c tests/pi_10.com \
tests/test_path.c \
+29
View File
@@ -36,6 +36,35 @@ You can look at /usr/local/qemu-i386/bin/qemu-conf.sh so that QEMU is
automatically launched by the Linux kernel when you try to launch x86
executables.
Tested tool versions
--------------------
In order to compile QEMU succesfully, it is very important that you
have the right tools. The most important one is gcc. I cannot guaranty
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 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
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] Debian 3.0
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 [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
-------------
+10 -6
View File
@@ -1,15 +1,19 @@
- fix iret/lret/fpush not before mem load restarting
- optimize FPU operations (evaluate x87 stack pointer statically) and
fix cr0.TS emulation
- fix CCOP optimisation
- fix all remaining thread lock issues (must put TBs in a specific invalid
state, find a solution for tb_flush()).
- handle fp87 state in signals
- add gcc 2.96 test configure (some gcc3 flags are needed)
- optimize FPU operations (evaluate x87 stack pointer statically)
- 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
in syscall emulation code).
- fix thread stack freeing (use kernel 2.5.x CLONE_CHILD_CLEARTID)
+1 -1
View File
@@ -1 +1 @@
0.2
0.4.2
-13
View File
@@ -248,19 +248,6 @@ enum bfd_reloc_code_real {
BFD_RELOC_ALPHA_HINT
};
bfd_vma
bfd_getl32 (addr)
register const bfd_byte *addr;
{
unsigned long v;
v = (unsigned long) addr[0];
v |= (unsigned long) addr[1] << 8;
v |= (unsigned long) addr[2] << 16;
v |= (unsigned long) addr[3] << 24;
return (bfd_vma) v;
}
/* This file holds the Alpha AXP opcode table. The opcode table includes
almost all of the extended instruction mnemonics. This permits the
disassembler to use them, and simplifies the assembler logic, at the
+1675
View File
File diff suppressed because it is too large. Load diff
+128
View File
@@ -0,0 +1,128 @@
OUTPUT_FORMAT("elf32-littlearm", "elf32-littlearm",
"elf32-littlearm")
OUTPUT_ARCH(arm)
ENTRY(_start)
SEARCH_DIR(/lib); SEARCH_DIR(/usr/lib); SEARCH_DIR(/usr/local/lib); SEARCH_DIR(/usr/alpha-unknown-linux-gnu/lib);
SECTIONS
{
/* Read-only sections, merged into text segment: */
. = 0x60000000 + 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) }
/* 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 . */
}
+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
+61 -18
View File
@@ -20,6 +20,7 @@ TMPH="${TMPDIR1}/qemu-conf-${RANDOM}-$$-${RANDOM}.h"
# default parameters
prefix="/usr/local"
interp_prefix="/usr/gnemul/qemu-i386"
static="no"
cross_prefix=""
cc="gcc"
host_cc="gcc"
@@ -27,6 +28,7 @@ ar="ar"
make="make"
strip="strip"
target_cpu="x86"
target_bigendian="default"
cpu=`uname -m`
case "$cpu" in
i386|i486|i586|i686|i86pc|BePC)
@@ -102,8 +104,16 @@ for opt do
;;
--cpu=*) cpu=`echo $opt | cut -d '=' -f 2`
;;
--target-cpu=*) target_cpu=`echo $opt | cut -d '=' -f 2`
;;
--target-big-endian) target_bigendian="yes"
;;
--target-little-endian) target_bigendian="no"
;;
--enable-gprof) gprof="yes"
;;
--static) static="yes"
;;
esac
done
@@ -143,20 +153,25 @@ 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
if test "$target_cpu" = "x86" ; then
target_bigendian="no"
elif test "$target_cpu" = "arm" ; then
target_bigendian="no"
else
target_bigendian="no"
fi
fi
if test x"$1" = x"-h" -o x"$1" = x"--help" ; then
@@ -170,25 +185,30 @@ echo "Standard options:"
echo " --help print this message"
echo " --prefix=PREFIX install in PREFIX [$prefix]"
echo " --interp-prefix=PREFIX where to find shared libraries, etc. [$interp_prefix]"
echo " --target_cpu=CPU set target cpu (x86 or arm) [$target_cpu]"
echo ""
echo "Advanced options (experts only):"
echo " --source-path=PATH path of source code [$source_path]"
echo " --cross-prefix=PREFIX use PREFIX for compile tools [$cross_prefix]"
echo " --cc=CC use C compiler CC [$cc]"
echo " --make=MAKE use specified make [$make]"
echo " --static enable static build [$static]"
echo ""
echo "NOTE: The object files are build at the place where configure is launched"
exit 1
fi
echo "Install prefix $prefix"
echo "Source path $source_path"
echo "C compiler $cc"
echo "make $make"
echo "host CPU $cpu"
echo "Big Endian $bigendian"
echo "target CPU $target_cpu"
echo "gprof enabled $gprof"
echo "Install prefix $prefix"
echo "Source path $source_path"
echo "ELF interp prefix $interp_prefix"
echo "C compiler $cc"
echo "make $make"
echo "host CPU $cpu"
echo "host big endian $bigendian"
echo "target CPU $target_cpu"
echo "target big endian $target_bigendian"
echo "gprof enabled $gprof"
echo "static build $static"
echo "Creating config.mak and config.h"
@@ -199,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
@@ -240,10 +262,31 @@ if test "$bigendian" = "yes" ; then
echo "WORDS_BIGENDIAN=yes" >> config.mak
echo "#define WORDS_BIGENDIAN 1" >> $TMPH
fi
if test "$target_cpu" = "x86" ; then
echo "TARGET_ARCH=i386" >> config.mak
echo "#define TARGET_ARCH \"i386\"" >> $TMPH
echo "#define TARGET_I386 1" >> $TMPH
elif test "$target_cpu" = "arm" ; then
echo "TARGET_ARCH=arm" >> config.mak
echo "#define TARGET_ARCH \"arm\"" >> $TMPH
echo "#define TARGET_ARM 1" >> $TMPH
else
echo "Unsupported target CPU"
exit 1
fi
if test "$target_bigendian" = "yes" ; then
echo "TARGET_WORDS_BIGENDIAN=yes" >> config.mak
echo "#define TARGET_WORDS_BIGENDIAN 1" >> $TMPH
fi
if test "$gprof" = "yes" ; then
echo "TARGET_GPROF=yes" >> config.mak
echo "#define HAVE_GPROF 1" >> $TMPH
fi
if test "$static" = "yes" ; then
echo "CONFIG_STATIC=yes" >> config.mak
fi
echo -n "VERSION=" >>config.mak
head $source_path/VERSION >>config.mak
echo "" >>config.mak
+321
View File
@@ -0,0 +1,321 @@
/*
* defines common to all virtual CPUs
*
* 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
*/
#ifndef CPU_ALL_H
#define CPU_ALL_H
/* all CPU memory access use these macros */
static inline int ldub(void *ptr)
{
return *(uint8_t *)ptr;
}
static inline int ldsb(void *ptr)
{
return *(int8_t *)ptr;
}
static inline void stb(void *ptr, int v)
{
*(uint8_t *)ptr = v;
}
/* NOTE: on arm, putting 2 in /proc/sys/debug/alignment so that the
kernel handles unaligned load/stores may give better results, but
it is a system wide setting : bad */
#if defined(WORDS_BIGENDIAN) || defined(__arm__)
/* conservative code for little endian unaligned accesses */
static inline int lduw(void *ptr)
{
#ifdef __powerpc__
int val;
__asm__ __volatile__ ("lhbrx %0,0,%1" : "=r" (val) : "r" (ptr));
return val;
#else
uint8_t *p = ptr;
return p[0] | (p[1] << 8);
#endif
}
static inline int ldsw(void *ptr)
{
#ifdef __powerpc__
int val;
__asm__ __volatile__ ("lhbrx %0,0,%1" : "=r" (val) : "r" (ptr));
return (int16_t)val;
#else
uint8_t *p = ptr;
return (int16_t)(p[0] | (p[1] << 8));
#endif
}
static inline int ldl(void *ptr)
{
#ifdef __powerpc__
int val;
__asm__ __volatile__ ("lwbrx %0,0,%1" : "=r" (val) : "r" (ptr));
return val;
#else
uint8_t *p = ptr;
return p[0] | (p[1] << 8) | (p[2] << 16) | (p[3] << 24);
#endif
}
static inline uint64_t ldq(void *ptr)
{
uint8_t *p = ptr;
uint32_t v1, v2;
v1 = ldl(p);
v2 = ldl(p + 4);
return v1 | ((uint64_t)v2 << 32);
}
static inline void stw(void *ptr, int v)
{
#ifdef __powerpc__
__asm__ __volatile__ ("sthbrx %1,0,%2" : "=m" (*(uint16_t *)ptr) : "r" (v), "r" (ptr));
#else
uint8_t *p = ptr;
p[0] = v;
p[1] = v >> 8;
#endif
}
static inline void stl(void *ptr, int v)
{
#ifdef __powerpc__
__asm__ __volatile__ ("stwbrx %1,0,%2" : "=m" (*(uint32_t *)ptr) : "r" (v), "r" (ptr));
#else
uint8_t *p = ptr;
p[0] = v;
p[1] = v >> 8;
p[2] = v >> 16;
p[3] = v >> 24;
#endif
}
static inline void stq(void *ptr, uint64_t v)
{
uint8_t *p = ptr;
stl(p, (uint32_t)v);
stl(p + 4, v >> 32);
}
/* float access */
static inline float ldfl(void *ptr)
{
union {
float f;
uint32_t i;
} u;
u.i = ldl(ptr);
return u.f;
}
static inline void stfl(void *ptr, float v)
{
union {
float f;
uint32_t i;
} u;
u.f = v;
stl(ptr, u.i);
}
#if defined(__arm__) && !defined(WORDS_BIGENDIAN)
/* NOTE: arm is horrible as double 32 bit words are stored in big endian ! */
static inline double ldfq(void *ptr)
{
union {
double d;
uint32_t tab[2];
} u;
u.tab[1] = ldl(ptr);
u.tab[0] = ldl(ptr + 4);
return u.d;
}
static inline void stfq(void *ptr, double v)
{
union {
double d;
uint32_t tab[2];
} u;
u.d = v;
stl(ptr, u.tab[1]);
stl(ptr + 4, u.tab[0]);
}
#else
static inline double ldfq(void *ptr)
{
union {
double d;
uint64_t i;
} u;
u.i = ldq(ptr);
return u.d;
}
static inline void stfq(void *ptr, double v)
{
union {
double d;
uint64_t i;
} u;
u.d = v;
stq(ptr, u.i);
}
#endif
#else
static inline int lduw(void *ptr)
{
return *(uint16_t *)ptr;
}
static inline int ldsw(void *ptr)
{
return *(int16_t *)ptr;
}
static inline int ldl(void *ptr)
{
return *(uint32_t *)ptr;
}
static inline uint64_t ldq(void *ptr)
{
return *(uint64_t *)ptr;
}
static inline void stw(void *ptr, int v)
{
*(uint16_t *)ptr = v;
}
static inline void stl(void *ptr, int v)
{
*(uint32_t *)ptr = v;
}
static inline void stq(void *ptr, uint64_t v)
{
*(uint64_t *)ptr = v;
}
/* float access */
static inline float ldfl(void *ptr)
{
return *(float *)ptr;
}
static inline double ldfq(void *ptr)
{
return *(double *)ptr;
}
static inline void stfl(void *ptr, float v)
{
*(float *)ptr = v;
}
static inline void stfq(void *ptr, double v)
{
*(double *)ptr = v;
}
#endif
/* page related stuff */
#define TARGET_PAGE_SIZE (1 << TARGET_PAGE_BITS)
#define TARGET_PAGE_MASK ~(TARGET_PAGE_SIZE - 1)
#define TARGET_PAGE_ALIGN(addr) (((addr) + TARGET_PAGE_SIZE - 1) & TARGET_PAGE_MASK)
extern unsigned long real_host_page_size;
extern unsigned long host_page_bits;
extern unsigned long host_page_size;
extern unsigned long host_page_mask;
#define HOST_PAGE_ALIGN(addr) (((addr) + host_page_size - 1) & host_page_mask)
/* same as PROT_xxx */
#define PAGE_READ 0x0001
#define PAGE_WRITE 0x0002
#define PAGE_EXEC 0x0004
#define PAGE_BITS (PAGE_READ | PAGE_WRITE | PAGE_EXEC)
#define PAGE_VALID 0x0008
/* original state of the write flag (used when tracking self-modifying
code */
#define PAGE_WRITE_ORG 0x0010
void page_dump(FILE *f);
int page_get_flags(unsigned long address);
void page_set_flags(unsigned long start, unsigned long end, int flags);
void page_unprotect_range(uint8_t *data, unsigned long data_size);
#define SINGLE_CPU_DEFINES
#ifdef SINGLE_CPU_DEFINES
#if defined(TARGET_I386)
#define CPUState CPUX86State
#define cpu_init cpu_x86_init
#define cpu_exec cpu_x86_exec
#define cpu_gen_code cpu_x86_gen_code
#define cpu_interrupt cpu_x86_interrupt
#define cpu_signal_handler cpu_x86_signal_handler
#elif defined(TARGET_ARM)
#define CPUState CPUARMState
#define cpu_init cpu_arm_init
#define cpu_exec cpu_arm_exec
#define cpu_gen_code cpu_arm_gen_code
#define cpu_interrupt cpu_arm_interrupt
#define cpu_signal_handler cpu_arm_signal_handler
#else
#error unsupported target CPU
#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 */
+65
View File
@@ -0,0 +1,65 @@
/*
* ARM virtual CPU header
*
* 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
*/
#ifndef CPU_ARM_H
#define CPU_ARM_H
#include "config.h"
#include <setjmp.h>
#define EXCP_UDEF 1 /* undefined instruction */
#define EXCP_SWI 2 /* software interrupt */
#define EXCP_INTERRUPT 256 /* async interruption */
typedef struct CPUARMState {
uint32_t regs[16];
uint32_t cpsr;
/* cpsr flag cache for faster execution */
uint32_t CF; /* 0 or 1 */
uint32_t VF; /* V is the bit 31. All other bits are undefined */
uint32_t NZF; /* N is bit 31. Z is computed from NZF */
/* exception/interrupt handling */
jmp_buf jmp_env;
int exception_index;
int interrupt_request;
struct TranslationBlock *current_tb;
int user_mode_only;
/* user data */
void *opaque;
} CPUARMState;
CPUARMState *cpu_arm_init(void);
int cpu_arm_exec(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
is returned if the signal was handled by the virtual CPU. */
struct siginfo;
int cpu_arm_signal_handler(int host_signum, struct siginfo *info,
void *puc);
void cpu_arm_dump_state(CPUARMState *env, FILE *f, int flags);
#define TARGET_PAGE_BITS 12
#include "cpu-all.h"
#endif
+642
View File
@@ -0,0 +1,642 @@
/*
* i386 emulator main execution loop
*
* 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 "config.h"
#ifdef TARGET_I386
#include "exec-i386.h"
#endif
#ifdef TARGET_ARM
#include "exec-arm.h"
#endif
#include "disas.h"
//#define DEBUG_EXEC
//#define DEBUG_SIGNAL
#if defined(TARGET_ARM)
/* XXX: unify with i386 target */
void cpu_loop_exit(void)
{
longjmp(env->jmp_env, 1);
}
#endif
/* main execution loop */
int cpu_exec(CPUState *env1)
{
int saved_T0, saved_T1, saved_T2;
CPUState *saved_env;
#ifdef reg_EAX
int saved_EAX;
#endif
#ifdef reg_ECX
int saved_ECX;
#endif
#ifdef reg_EDX
int saved_EDX;
#endif
#ifdef reg_EBX
int saved_EBX;
#endif
#ifdef reg_ESP
int saved_ESP;
#endif
#ifdef reg_EBP
int saved_EBP;
#endif
#ifdef reg_ESI
int saved_ESI;
#endif
#ifdef reg_EDI
int saved_EDI;
#endif
#ifdef __sparc__
int saved_i7, tmp_T0;
#endif
int code_gen_size, ret, interrupt_request;
void (*gen_func)(void);
TranslationBlock *tb, **ptb;
uint8_t *tc_ptr, *cs_base, *pc;
unsigned int flags;
/* first we save global registers */
saved_T0 = T0;
saved_T1 = T1;
saved_T2 = T2;
saved_env = env;
env = env1;
#ifdef __sparc__
/* we also save i7 because longjmp may not restore it */
asm volatile ("mov %%i7, %0" : "=r" (saved_i7));
#endif
#if defined(TARGET_I386)
#ifdef reg_EAX
saved_EAX = EAX;
EAX = env->regs[R_EAX];
#endif
#ifdef reg_ECX
saved_ECX = ECX;
ECX = env->regs[R_ECX];
#endif
#ifdef reg_EDX
saved_EDX = EDX;
EDX = env->regs[R_EDX];
#endif
#ifdef reg_EBX
saved_EBX = EBX;
EBX = env->regs[R_EBX];
#endif
#ifdef reg_ESP
saved_ESP = ESP;
ESP = env->regs[R_ESP];
#endif
#ifdef reg_EBP
saved_EBP = EBP;
EBP = env->regs[R_EBP];
#endif
#ifdef reg_ESI
saved_ESI = ESI;
ESI = env->regs[R_ESI];
#endif
#ifdef reg_EDI
saved_EDI = EDI;
EDI = env->regs[R_EDI];
#endif
/* put eflags in CPU temporary format */
CC_SRC = env->eflags & (CC_O | CC_S | CC_Z | CC_A | CC_P | CC_C);
DF = 1 - (2 * ((env->eflags >> 10) & 1));
CC_OP = CC_OP_EFLAGS;
env->eflags &= ~(DF_MASK | CC_O | CC_S | CC_Z | CC_A | CC_P | CC_C);
#elif defined(TARGET_ARM)
{
unsigned int psr;
psr = env->cpsr;
env->CF = (psr >> 29) & 1;
env->NZF = (psr & 0xc0000000) ^ 0x40000000;
env->VF = (psr << 3) & 0x80000000;
env->cpsr = psr & ~0xf0000000;
}
#else
#error unsupported target CPU
#endif
env->exception_index = -1;
/* prepare setjmp context for exception handling */
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)
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);
#else
#error unsupported target CPU
#endif
}
#endif
/* we compute the CPU state. We assume it will not
change during the whole generated block. */
#if defined(TARGET_I386)
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];
#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);
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);
}
#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);
}
#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));
}
#endif
#ifdef __sparc__
T0 = tmp_T0;
#endif
/* see if we can patch the calling TB. XXX: remove TF test */
if (T0 != 0
#if defined(TARGET_I386)
&& !(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;
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");
#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");
#else
gen_func();
#endif
env->current_tb = NULL;
}
} else {
}
} /* for(;;) */
#if defined(TARGET_I386)
/* restore flags in standard format */
env->eflags = env->eflags | cc_table[CC_OP].compute_all() | (DF & DF_MASK);
/* restore global registers */
#ifdef reg_EAX
EAX = saved_EAX;
#endif
#ifdef reg_ECX
ECX = saved_ECX;
#endif
#ifdef reg_EDX
EDX = saved_EDX;
#endif
#ifdef reg_EBX
EBX = saved_EBX;
#endif
#ifdef reg_ESP
ESP = saved_ESP;
#endif
#ifdef reg_EBP
EBP = saved_EBP;
#endif
#ifdef reg_ESI
ESI = saved_ESI;
#endif
#ifdef reg_EDI
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);
}
#else
#error unsupported target CPU
#endif
#ifdef __sparc__
asm volatile ("mov %0, %%i7" : : "r" (saved_i7));
#endif
T0 = saved_T0;
T1 = saved_T1;
T2 = saved_T2;
env = saved_env;
return ret;
}
#if defined(TARGET_I386)
void cpu_x86_load_seg(CPUX86State *s, int seg_reg, int selector)
{
CPUX86State *saved_env;
saved_env = env;
env = s;
if (env->eflags & VM_MASK) {
SegmentCache *sc;
selector &= 0xffff;
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->flags = 0;
sc->selector = selector;
} else {
load_seg(seg_reg, selector, 0);
}
env = saved_env;
}
void cpu_x86_fsave(CPUX86State *s, uint8_t *ptr, int data32)
{
CPUX86State *saved_env;
saved_env = env;
env = s;
helper_fsave(ptr, data32);
env = saved_env;
}
void cpu_x86_frstor(CPUX86State *s, uint8_t *ptr, int data32)
{
CPUX86State *saved_env;
saved_env = env;
env = s;
helper_frstor(ptr, data32);
env = saved_env;
}
#endif /* TARGET_I386 */
#undef EAX
#undef ECX
#undef EDX
#undef EBX
#undef ESP
#undef EBP
#undef ESI
#undef EDI
#undef EIP
#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
signal set which should be restored */
static inline int handle_cpu_signal(unsigned long pc, unsigned long address,
int is_write, sigset_t *old_set)
{
TranslationBlock *tb;
int ret;
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 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 */
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)
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
#if defined(__i386__)
int cpu_signal_handler(int host_signum, struct siginfo *info,
void *puc)
{
struct ucontext *uc = puc;
unsigned long pc;
#ifndef REG_EIP
/* for glibc 2.1 */
#define REG_EIP EIP
#define REG_ERR ERR
#define REG_TRAPNO TRAPNO
#endif
pc = uc->uc_mcontext.gregs[REG_EIP];
return handle_cpu_signal(pc, (unsigned long)info->si_addr,
uc->uc_mcontext.gregs[REG_TRAPNO] == 0xe ?
(uc->uc_mcontext.gregs[REG_ERR] >> 1) & 1 : 0,
&uc->uc_sigmask);
}
#elif defined(__powerpc)
int cpu_signal_handler(int host_signum, struct siginfo *info,
void *puc)
{
struct ucontext *uc = puc;
struct pt_regs *regs = uc->uc_mcontext.regs;
unsigned long pc;
int is_write;
pc = regs->nip;
is_write = 0;
#if 0
/* ppc 4xx case */
if (regs->dsisr & 0x00800000)
is_write = 1;
#else
if (regs->trap != 0x400 && (regs->dsisr & 0x02000000))
is_write = 1;
#endif
return handle_cpu_signal(pc, (unsigned long)info->si_addr,
is_write, &uc->uc_sigmask);
}
#elif defined(__alpha__)
int cpu_signal_handler(int host_signum, struct siginfo *info,
void *puc)
{
struct ucontext *uc = puc;
uint32_t *pc = uc->uc_mcontext.sc_pc;
uint32_t insn = *pc;
int is_write = 0;
/* XXX: need kernel patch to get write flag faster */
switch (insn >> 26) {
case 0x0d: // stw
case 0x0e: // stb
case 0x0f: // stq_u
case 0x24: // stf
case 0x25: // stg
case 0x26: // sts
case 0x27: // stt
case 0x2c: // stl
case 0x2d: // stq
case 0x2e: // stl_c
case 0x2f: // stq_c
is_write = 1;
}
return handle_cpu_signal(pc, (unsigned long)info->si_addr,
is_write, &uc->uc_sigmask);
}
#elif defined(__sparc__)
int cpu_signal_handler(int host_signum, struct siginfo *info,
void *puc)
{
uint32_t *regs = (uint32_t *)(info + 1);
void *sigmask = (regs + 20);
unsigned long pc;
int is_write;
uint32_t insn;
/* XXX: is there a standard glibc define ? */
pc = regs[1];
/* XXX: need kernel patch to get write flag faster */
is_write = 0;
insn = *(uint32_t *)pc;
if ((insn >> 30) == 3) {
switch((insn >> 19) & 0x3f) {
case 0x05: // stb
case 0x06: // sth
case 0x04: // st
case 0x07: // std
case 0x24: // stf
case 0x27: // stdf
case 0x25: // stfsr
is_write = 1;
break;
}
}
return handle_cpu_signal(pc, (unsigned long)info->si_addr,
is_write, sigmask);
}
#elif defined(__arm__)
int cpu_signal_handler(int host_signum, struct siginfo *info,
void *puc)
{
struct ucontext *uc = puc;
unsigned long pc;
int is_write;
pc = uc->uc_mcontext.gregs[R15];
/* XXX: compute is_write */
is_write = 0;
return handle_cpu_signal(pc, (unsigned long)info->si_addr,
is_write,
&uc->uc_sigmask);
}
#else
#error host CPU specific signal handler needed
#endif
+84 -243
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,220 +248,33 @@ 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;
/* all CPU memory access use these macros */
static inline int ldub(void *ptr)
{
return *(uint8_t *)ptr;
}
static inline int ldsb(void *ptr)
{
return *(int8_t *)ptr;
}
static inline void stb(void *ptr, int v)
{
*(uint8_t *)ptr = v;
}
#ifdef WORDS_BIGENDIAN
/* conservative code for little endian unaligned accesses */
static inline int lduw(void *ptr)
{
#ifdef __powerpc__
int val;
__asm__ __volatile__ ("lhbrx %0,0,%1" : "=r" (val) : "r" (ptr));
return val;
#else
uint8_t *p = ptr;
return p[0] | (p[1] << 8);
#endif
}
static inline int ldsw(void *ptr)
{
#ifdef __powerpc__
int val;
__asm__ __volatile__ ("lhbrx %0,0,%1" : "=r" (val) : "r" (ptr));
return (int16_t)val;
#else
uint8_t *p = ptr;
return (int16_t)(p[0] | (p[1] << 8));
#endif
}
static inline int ldl(void *ptr)
{
#ifdef __powerpc__
int val;
__asm__ __volatile__ ("lwbrx %0,0,%1" : "=r" (val) : "r" (ptr));
return val;
#else
uint8_t *p = ptr;
return p[0] | (p[1] << 8) | (p[2] << 16) | (p[3] << 24);
#endif
}
static inline uint64_t ldq(void *ptr)
{
uint8_t *p = ptr;
uint32_t v1, v2;
v1 = ldl(p);
v2 = ldl(p + 4);
return v1 | ((uint64_t)v2 << 32);
}
static inline void stw(void *ptr, int v)
{
#ifdef __powerpc__
__asm__ __volatile__ ("sthbrx %1,0,%2" : "=m" (*(uint16_t *)ptr) : "r" (v), "r" (ptr));
#else
uint8_t *p = ptr;
p[0] = v;
p[1] = v >> 8;
#endif
}
static inline void stl(void *ptr, int v)
{
#ifdef __powerpc__
__asm__ __volatile__ ("stwbrx %1,0,%2" : "=m" (*(uint32_t *)ptr) : "r" (v), "r" (ptr));
#else
uint8_t *p = ptr;
p[0] = v;
p[1] = v >> 8;
p[2] = v >> 16;
p[3] = v >> 24;
#endif
}
static inline void stq(void *ptr, uint64_t v)
{
uint8_t *p = ptr;
stl(p, (uint32_t)v);
stl(p + 4, v >> 32);
}
/* float access */
static inline float ldfl(void *ptr)
{
union {
float f;
uint32_t i;
} u;
u.i = ldl(ptr);
return u.f;
}
static inline double ldfq(void *ptr)
{
union {
double d;
uint64_t i;
} u;
u.i = ldq(ptr);
return u.d;
}
static inline void stfl(void *ptr, float v)
{
union {
float f;
uint32_t i;
} u;
u.f = v;
stl(ptr, u.i);
}
static inline void stfq(void *ptr, double v)
{
union {
double d;
uint64_t i;
} u;
u.d = v;
stq(ptr, u.i);
}
#else
static inline int lduw(void *ptr)
{
return *(uint16_t *)ptr;
}
static inline int ldsw(void *ptr)
{
return *(int16_t *)ptr;
}
static inline int ldl(void *ptr)
{
return *(uint32_t *)ptr;
}
static inline uint64_t ldq(void *ptr)
{
return *(uint64_t *)ptr;
}
static inline void stw(void *ptr, int v)
{
*(uint16_t *)ptr = v;
}
static inline void stl(void *ptr, int v)
{
*(uint32_t *)ptr = v;
}
static inline void stq(void *ptr, uint64_t v)
{
*(uint64_t *)ptr = v;
}
/* float access */
static inline float ldfl(void *ptr)
{
return *(float *)ptr;
}
static inline double ldfq(void *ptr)
{
return *(double *)ptr;
}
static inline void stfl(void *ptr, float v)
{
*(float *)ptr = v;
}
static inline void stfq(void *ptr, double v)
{
*(double *)ptr = v;
}
#endif
#ifndef IN_OP_I386
void cpu_x86_outb(CPUX86State *env, int addr, int val);
void cpu_x86_outw(CPUX86State *env, int addr, int val);
@@ -430,12 +286,16 @@ 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);
/* simulate fsave/frstor */
void cpu_x86_fsave(CPUX86State *s, uint8_t *ptr, int data32);
void cpu_x86_frstor(CPUX86State *s, uint8_t *ptr, int data32);
/* you can call this signal handler from your SIGBUS and SIGSEGV
signal handlers to inform the virtual CPU of exceptions. non zero
is returned if the signal was handled by the virtual CPU. */
@@ -443,37 +303,18 @@ 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 */
void cpu_x86_dump_state(CPUX86State *env, FILE *f, int flags);
/* page related stuff */
#define TARGET_PAGE_BITS 12
#define TARGET_PAGE_SIZE (1 << TARGET_PAGE_BITS)
#define TARGET_PAGE_MASK ~(TARGET_PAGE_SIZE - 1)
#define TARGET_PAGE_ALIGN(addr) (((addr) + TARGET_PAGE_SIZE - 1) & TARGET_PAGE_MASK)
extern unsigned long real_host_page_size;
extern unsigned long host_page_bits;
extern unsigned long host_page_size;
extern unsigned long host_page_mask;
#define HOST_PAGE_ALIGN(addr) (((addr) + host_page_size - 1) & host_page_mask)
/* same as PROT_xxx */
#define PAGE_READ 0x0001
#define PAGE_WRITE 0x0002
#define PAGE_EXEC 0x0004
#define PAGE_BITS (PAGE_READ | PAGE_WRITE | PAGE_EXEC)
#define PAGE_VALID 0x0008
/* original state of the write flag (used when tracking self-modifying
code */
#define PAGE_WRITE_ORG 0x0010
void page_dump(FILE *f);
int page_get_flags(unsigned long address);
void page_set_flags(unsigned long start, unsigned long end, int flags);
void page_unprotect_range(uint8_t *data, unsigned long data_size);
#include "cpu-all.h"
#endif /* CPU_I386_H */
+23 -8
View File
@@ -73,16 +73,20 @@ enum bfd_architecture
bfd_arch_a29k, /* AMD 29000 */
bfd_arch_sparc, /* SPARC */
#define bfd_mach_sparc 1
/* The difference between v8plus and v9 is that v9 is a true 64 bit env. */
/* The difference between v8plus and v9 is that v9 is a true 64 bit env. */
#define bfd_mach_sparc_sparclet 2
#define bfd_mach_sparc_sparclite 3
#define bfd_mach_sparc_v8plus 4
#define bfd_mach_sparc_v8plusa 5 /* with ultrasparc add'ns */
#define bfd_mach_sparc_v9 6
#define bfd_mach_sparc_v9a 7 /* with ultrasparc add'ns */
/* Nonzero if MACH has the v9 instruction set. */
#define bfd_mach_sparc_v8plusa 5 /* with ultrasparc add'ns. */
#define bfd_mach_sparc_sparclite_le 6
#define bfd_mach_sparc_v9 7
#define bfd_mach_sparc_v9a 8 /* with ultrasparc add'ns. */
#define bfd_mach_sparc_v8plusb 9 /* with cheetah add'ns. */
#define bfd_mach_sparc_v9b 10 /* with cheetah add'ns. */
/* Nonzero if MACH has the v9 instruction set. */
#define bfd_mach_sparc_v9_p(mach) \
((mach) >= bfd_mach_sparc_v8plus && (mach) <= bfd_mach_sparc_v9a)
((mach) >= bfd_mach_sparc_v8plus && (mach) <= bfd_mach_sparc_v9b \
&& (mach) != bfd_mach_sparc_sparclite_le)
bfd_arch_mips, /* MIPS Rxxxx */
#define bfd_mach_mips3000 3000
#define bfd_mach_mips3900 3900
@@ -279,6 +283,9 @@ typedef struct disassemble_info {
zero if unknown. */
bfd_vma target2; /* Second target address for dref2 */
/* Command line options specific to the target disassembler. */
char * disassembler_options;
} disassemble_info;
@@ -299,8 +306,7 @@ extern int print_insn_h8300s PARAMS ((bfd_vma, disassemble_info*));
extern int print_insn_h8500 PARAMS ((bfd_vma, disassemble_info*));
extern int print_insn_alpha PARAMS ((bfd_vma, disassemble_info*));
extern disassembler_ftype arc_get_disassembler PARAMS ((int, int));
extern int print_insn_big_arm PARAMS ((bfd_vma, disassemble_info*));
extern int print_insn_little_arm PARAMS ((bfd_vma, disassemble_info*));
extern int print_insn_arm PARAMS ((bfd_vma, disassemble_info*));
extern int print_insn_sparc PARAMS ((bfd_vma, disassemble_info*));
extern int print_insn_big_a29k PARAMS ((bfd_vma, disassemble_info*));
extern int print_insn_little_a29k PARAMS ((bfd_vma, disassemble_info*));
@@ -381,6 +387,15 @@ extern int generic_symbol_at_address
(INFO).bytes_per_line = 0, \
(INFO).bytes_per_chunk = 0, \
(INFO).display_endian = BFD_ENDIAN_UNKNOWN, \
(INFO).disassembler_options = NULL, \
(INFO).insn_info_valid = 0
#define _(x) x
/* from libbfd */
bfd_vma bfd_getl32 (const bfd_byte *addr);
bfd_vma bfd_getb32 (const bfd_byte *addr);
typedef enum bfd_boolean {false, true} boolean;
#endif /* ! defined (DIS_ASM_H) */
-79
View File
@@ -1,79 +0,0 @@
/* Disassemble from a buffer, for GNU.
Copyright (C) 1993, 1994 Free Software Foundation, Inc.
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
This program 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 General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */
#include "dis-asm.h"
#include <errno.h>
/* Get LENGTH bytes from info's buffer, at target address memaddr.
Transfer them to myaddr. */
int
buffer_read_memory (memaddr, myaddr, length, info)
bfd_vma memaddr;
bfd_byte *myaddr;
int length;
struct disassemble_info *info;
{
if (memaddr < info->buffer_vma
|| memaddr + length > info->buffer_vma + info->buffer_length)
/* Out of bounds. Use EIO because GDB uses it. */
return EIO;
memcpy (myaddr, info->buffer + (memaddr - info->buffer_vma), length);
return 0;
}
/* Print an error message. We can assume that this is in response to
an error return from buffer_read_memory. */
void
perror_memory (status, memaddr, info)
int status;
bfd_vma memaddr;
struct disassemble_info *info;
{
if (status != EIO)
/* Can't happen. */
(*info->fprintf_func) (info->stream, "Unknown error %d\n", status);
else
/* 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);
}
/* This could be in a separate file, to save miniscule amounts of space
in statically linked executables. */
/* Just print the address is hex. This is included for completeness even
though both GDB and objdump provide their own (to print symbolic
addresses). */
void
generic_print_address (addr, info)
bfd_vma addr;
struct disassemble_info *info;
{
(*info->fprintf_func) (info->stream, "0x%x", addr);
}
/* Just return the given address. */
int
generic_symbol_at_address (addr, info)
bfd_vma addr;
struct disassemble_info * info;
{
return 1;
}
+111 -5
View File
@@ -1,15 +1,100 @@
/* General "disassemble this chunk" code. Used for debugging. */
#include "config.h"
#include "dis-asm.h"
#include "disas.h"
#include "elf.h"
#include <errno.h>
/* Filled in by elfload.c. Simplistic, but will do for now. */
unsigned int disas_num_syms;
void *disas_symtab;
const char *disas_strtab;
/* Disassemble this for me please... (debugging). */
void disas(FILE *out, void *code, unsigned long size, enum disas_type type)
/* Get LENGTH bytes from info's buffer, at target address memaddr.
Transfer them to myaddr. */
int
buffer_read_memory (memaddr, myaddr, length, info)
bfd_vma memaddr;
bfd_byte *myaddr;
int length;
struct disassemble_info *info;
{
if (memaddr < info->buffer_vma
|| memaddr + length > info->buffer_vma + info->buffer_length)
/* Out of bounds. Use EIO because GDB uses it. */
return EIO;
memcpy (myaddr, info->buffer + (memaddr - info->buffer_vma), length);
return 0;
}
/* Print an error message. We can assume that this is in response to
an error return from buffer_read_memory. */
void
perror_memory (status, memaddr, info)
int status;
bfd_vma memaddr;
struct disassemble_info *info;
{
if (status != EIO)
/* Can't happen. */
(*info->fprintf_func) (info->stream, "Unknown error %d\n", status);
else
/* 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);
}
/* This could be in a separate file, to save miniscule amounts of space
in statically linked executables. */
/* Just print the address is hex. This is included for completeness even
though both GDB and objdump provide their own (to print symbolic
addresses). */
void
generic_print_address (addr, info)
bfd_vma addr;
struct disassemble_info *info;
{
(*info->fprintf_func) (info->stream, "0x%x", addr);
}
/* Just return the given address. */
int
generic_symbol_at_address (addr, info)
bfd_vma addr;
struct disassemble_info * info;
{
return 1;
}
bfd_vma bfd_getl32 (const bfd_byte *addr)
{
unsigned long v;
v = (unsigned long) addr[0];
v |= (unsigned long) addr[1] << 8;
v |= (unsigned long) addr[2] << 16;
v |= (unsigned long) addr[3] << 24;
return (bfd_vma) v;
}
bfd_vma bfd_getb32 (const bfd_byte *addr)
{
unsigned long v;
v = (unsigned long) addr[0] << 24;
v |= (unsigned long) addr[1] << 16;
v |= (unsigned long) addr[2] << 8;
v |= (unsigned long) addr[3];
return (bfd_vma) v;
}
/* Disassemble this for me please... (debugging). 'flags' is only used
for i386: non zero means 16 bit code */
void disas(FILE *out, void *code, unsigned long size, int is_host, int flags)
{
uint8_t *pc;
int count;
@@ -22,7 +107,7 @@ void disas(FILE *out, void *code, unsigned long size, enum disas_type type)
disasm_info.buffer_vma = (unsigned long)code;
disasm_info.buffer_length = size;
if (type == DISAS_TARGET) {
if (is_host) {
#ifdef WORDS_BIGENDIAN
disasm_info.endian = BFD_ENDIAN_BIG;
#else
@@ -35,22 +120,43 @@ void disas(FILE *out, void *code, unsigned long size, enum disas_type type)
print_insn = print_insn_ppc;
#elif defined(__alpha__)
print_insn = print_insn_alpha;
#elif defined(__sparc__)
print_insn = print_insn_sparc;
#elif defined(__arm__)
print_insn = print_insn_arm;
#else
fprintf(out, "Asm output not supported on this arch\n");
return;
#endif
} else {
/* Currently only source supported in x86. */
#ifdef TARGET_WORDS_BIGENDIAN
disasm_info.endian = BFD_ENDIAN_BIG;
#else
disasm_info.endian = BFD_ENDIAN_LITTLE;
if (type == DISAS_I386_I386)
#endif
#if defined(TARGET_I386)
if (!flags)
disasm_info.mach = bfd_mach_i386_i386;
else
disasm_info.mach = bfd_mach_i386_i8086;
print_insn = print_insn_i386;
#elif defined(TARGET_ARM)
print_insn = print_insn_arm;
#else
fprintf(out, "Asm output not supported on this arch\n");
return;
#endif
}
for (pc = code; pc < (uint8_t *)code + size; pc += count) {
fprintf(out, "0x%08lx: ", (long)pc);
#ifdef __arm__
/* since data are included in the code, it is better to
display code data too */
if (is_host) {
fprintf(out, "%08x ", (int)bfd_getl32((const bfd_byte *)pc));
}
#endif
count = print_insn((unsigned long)pc, &disasm_info);
fprintf(out, "\n");
if (count < 0)
+1 -7
View File
@@ -1,14 +1,8 @@
#ifndef _QEMU_DISAS_H
#define _QEMU_DISAS_H
enum disas_type {
DISAS_I386_I386,
DISAS_I386_I8086,
DISAS_TARGET, /* whatever host is. */
};
/* Disassemble this for me please... (debugging). */
void disas(FILE *out, void *code, unsigned long size, enum disas_type type);
void disas(FILE *out, void *code, unsigned long size, int is_host, int flags);
/* Look up symbol for debugging purpose. Returns "" if unknown. */
const char *lookup_symbol(void *orig_addr);
+155
View File
@@ -0,0 +1,155 @@
/*
* dyngen defines for micro operation code
*
* 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
*/
typedef unsigned char uint8_t;
typedef unsigned short uint16_t;
typedef unsigned int uint32_t;
typedef unsigned long long uint64_t;
typedef signed char int8_t;
typedef signed short int16_t;
typedef signed int int32_t;
typedef signed long long int64_t;
#define bswap32(x) \
({ \
uint32_t __x = (x); \
((uint32_t)( \
(((uint32_t)(__x) & (uint32_t)0x000000ffUL) << 24) | \
(((uint32_t)(__x) & (uint32_t)0x0000ff00UL) << 8) | \
(((uint32_t)(__x) & (uint32_t)0x00ff0000UL) >> 8) | \
(((uint32_t)(__x) & (uint32_t)0xff000000UL) >> 24) )); \
})
typedef struct FILE FILE;
extern int fprintf(FILE *, const char *, ...);
extern int printf(const char *, ...);
#define NULL 0
#include <fenv.h>
#ifdef __i386__
#define AREG0 "ebp"
#define AREG1 "ebx"
#define AREG2 "esi"
#define AREG3 "edi"
#endif
#ifdef __powerpc__
#define AREG0 "r27"
#define AREG1 "r24"
#define AREG2 "r25"
#define AREG3 "r26"
#define AREG4 "r16"
#define AREG5 "r17"
#define AREG6 "r18"
#define AREG7 "r19"
#define AREG8 "r20"
#define AREG9 "r21"
#define AREG10 "r22"
#define AREG11 "r23"
#define USE_INT_TO_FLOAT_HELPERS
#define BUGGY_GCC_DIV64
#endif
#ifdef __arm__
#define AREG0 "r7"
#define AREG1 "r4"
#define AREG2 "r5"
#define AREG3 "r6"
#endif
#ifdef __mips__
#define AREG0 "s3"
#define AREG1 "s0"
#define AREG2 "s1"
#define AREG3 "s2"
#endif
#ifdef __sparc__
#define AREG0 "g6"
#define AREG1 "g1"
#define AREG2 "g2"
#define AREG3 "g3"
#define AREG4 "l0"
#define AREG5 "l1"
#define AREG6 "l2"
#define AREG7 "l3"
#define AREG8 "l4"
#define AREG9 "l5"
#define AREG10 "l6"
#define AREG11 "l7"
#define USE_FP_CONVERT
#endif
#ifdef __s390__
#define AREG0 "r10"
#define AREG1 "r7"
#define AREG2 "r8"
#define AREG3 "r9"
#endif
#ifdef __alpha__
/* Note $15 is the frame pointer, so anything in op-i386.c that would
require a frame pointer, like alloca, would probably loose. */
#define AREG0 "$15"
#define AREG1 "$9"
#define AREG2 "$10"
#define AREG3 "$11"
#define AREG4 "$12"
#define AREG5 "$13"
#define AREG6 "$14"
#endif
#ifdef __ia64__
#define AREG0 "r27"
#define AREG1 "r24"
#define AREG2 "r25"
#define AREG3 "r26"
#endif
/* force GCC to generate only one epilog at the end of the function */
#define FORCE_RET() asm volatile ("");
#ifndef OPPROTO
#define OPPROTO
#endif
#define xglue(x, y) x ## y
#define glue(x, y) xglue(x, y)
#ifdef __alpha__
/* the symbols are considered non exported so a br immediate is generated */
#define __hidden __attribute__((visibility("hidden")))
#else
#define __hidden
#endif
#ifdef __alpha__
/* Suggested by Richard Henderson. This will result in code like
ldah $0,__op_param1($29) !gprelhigh
lda $0,__op_param1($0) !gprellow
We can then conveniently change $29 to $31 and adapt the offsets to
emit the appropriate constant. */
extern int __op_param1 __hidden;
extern int __op_param2 __hidden;
extern int __op_param3 __hidden;
#define PARAM1 ({ int _r; asm("" : "=r"(_r) : "0" (&__op_param1)); _r; })
#define PARAM2 ({ int _r; asm("" : "=r"(_r) : "0" (&__op_param2)); _r; })
#define PARAM3 ({ int _r; asm("" : "=r"(_r) : "0" (&__op_param3)); _r; })
#else
extern int __op_param1, __op_param2, __op_param3;
#define PARAM1 ((long)(&__op_param1))
#define PARAM2 ((long)(&__op_param2))
#define PARAM3 ((long)(&__op_param3))
#endif
extern int __op_jmp0, __op_jmp1;
+343 -116
View File
@@ -79,6 +79,13 @@
#define elf_check_arch(x) ((x) == EM_SPARCV9)
#define ELF_USES_RELOCA
#elif defined(HOST_ARM)
#define ELF_CLASS ELFCLASS32
#define ELF_ARCH EM_ARM
#define elf_check_arch(x) ((x) == EM_ARM)
#define ELF_USES_RELOC
#else
#error unsupported CPU - please update the code
#endif
@@ -95,8 +102,21 @@ typedef uint64_t host_ulong;
#define swabls(x) swab64s(x)
#endif
#ifdef ELF_USES_RELOCA
#define SHT_RELOC SHT_RELA
#else
#define SHT_RELOC SHT_REL
#endif
#define NO_THUNK_TYPE_SIZE
#include "thunk.h"
enum {
OUT_GEN_OP,
OUT_CODE,
OUT_INDEX_OP,
};
/* all dynamically generated functions begin with this code */
#define OP_PREFIX "op_"
@@ -170,16 +190,24 @@ void elf_swap_phdr(struct elf_phdr *h)
swabls(&h->p_align); /* Segment alignment */
}
void elf_swap_rel(ELF_RELOC *rel)
{
swabls(&rel->r_offset);
swabls(&rel->r_info);
#ifdef ELF_USES_RELOCA
swabls(&rel->r_addend);
#endif
}
/* ELF file info */
int do_swap;
struct elf_shdr *shdr;
uint8_t **sdata;
struct elfhdr ehdr;
ElfW(Sym) *symtab;
int nb_syms;
char *strtab;
/* data section */
uint8_t *data_data;
int data_shndx;
int text_shndx;
uint16_t get16(uint16_t *p)
{
@@ -243,6 +271,19 @@ struct elf_shdr *find_elf_section(struct elf_shdr *shdr, int shnum, const char *
return NULL;
}
int find_reloc(int sh_index)
{
struct elf_shdr *sec;
int i;
for(i = 0; i < ehdr.e_shnum; i++) {
sec = &shdr[i];
if (sec->sh_type == SHT_RELOC && sec->sh_info == sh_index)
return i;
}
return 0;
}
void *load_data(int fd, long offset, unsigned int size)
{
char *data;
@@ -274,11 +315,111 @@ int strstart(const char *str, const char *val, const char **ptr)
return 1;
}
#ifdef HOST_ARM
int arm_emit_ldr_info(const char *name, unsigned long start_offset,
FILE *outfile, uint8_t *p_start, uint8_t *p_end,
ELF_RELOC *relocs, int nb_relocs)
{
uint8_t *p;
uint32_t insn;
int offset, min_offset, pc_offset, data_size;
uint8_t data_allocated[1024];
unsigned int data_index;
memset(data_allocated, 0, sizeof(data_allocated));
p = p_start;
min_offset = p_end - p_start;
while (p < p_start + min_offset) {
insn = get32((uint32_t *)p);
if ((insn & 0x0d5f0000) == 0x051f0000) {
/* ldr reg, [pc, #im] */
offset = insn & 0xfff;
if (!(insn & 0x00800000))
offset = -offset;
if ((offset & 3) !=0)
error("%s:%04x: ldr pc offset must be 32 bit aligned",
name, start_offset + p - p_start);
pc_offset = p - p_start + offset + 8;
if (pc_offset <= (p - p_start) ||
pc_offset >= (p_end - p_start))
error("%s:%04x: ldr pc offset must point inside the function code",
name, start_offset + p - p_start);
if (pc_offset < min_offset)
min_offset = pc_offset;
if (outfile) {
/* ldr position */
fprintf(outfile, " arm_ldr_ptr->ptr = gen_code_ptr + %d;\n",
p - p_start);
/* ldr data index */
data_index = ((p_end - p_start) - pc_offset - 4) >> 2;
fprintf(outfile, " arm_ldr_ptr->data_ptr = arm_data_ptr + %d;\n",
data_index);
fprintf(outfile, " arm_ldr_ptr++;\n");
if (data_index >= sizeof(data_allocated))
error("%s: too many data", name);
if (!data_allocated[data_index]) {
ELF_RELOC *rel;
int i, addend, type;
const char *sym_name, *p;
char relname[1024];
data_allocated[data_index] = 1;
/* data value */
addend = get32((uint32_t *)(p_start + pc_offset));
relname[0] = '\0';
for(i = 0, rel = relocs;i < nb_relocs; i++, rel++) {
if (rel->r_offset == (pc_offset + start_offset)) {
sym_name = strtab + symtab[ELFW(R_SYM)(rel->r_info)].st_name;
/* the compiler leave some unnecessary references to the code */
if (strstart(sym_name, "__op_param", &p)) {
snprintf(relname, sizeof(relname), "param%s", p);
} else {
snprintf(relname, sizeof(relname), "(long)(&%s)", sym_name);
}
type = ELF32_R_TYPE(rel->r_info);
if (type != R_ARM_ABS32)
error("%s: unsupported data relocation", name);
break;
}
}
fprintf(outfile, " arm_data_ptr[%d] = 0x%x",
data_index, addend);
if (relname[0] != '\0')
fprintf(outfile, " + %s", relname);
fprintf(outfile, ";\n");
}
}
}
p += 4;
}
data_size = (p_end - p_start) - min_offset;
if (data_size > 0 && outfile) {
fprintf(outfile, " arm_data_ptr += %d;\n", data_size >> 2);
}
/* the last instruction must be a mov pc, lr */
if (p == p_start)
goto arm_ret_error;
p -= 4;
insn = get32((uint32_t *)p);
if ((insn & 0xffff0000) != 0xe91b0000) {
arm_ret_error:
if (!outfile)
printf("%s: invalid epilog\n", name);
}
return p - p_start;
}
#endif
#define MAX_ARGS 3
/* generate op code */
void gen_code(const char *name, host_ulong offset, host_ulong size,
FILE *outfile, uint8_t *text, ELF_RELOC *relocs, int nb_relocs, int reloc_sh_type,
FILE *outfile, uint8_t *text, ELF_RELOC *relocs, int nb_relocs,
int gen_switch)
{
int copy_size = 0;
@@ -361,7 +502,7 @@ void gen_code(const char *name, host_ulong offset, host_ulong size,
case EM_SPARC:
case EM_SPARC32PLUS:
{
uint32_t start_insn, end_insn1, end_insn2, skip_insn;
uint32_t start_insn, end_insn1, end_insn2;
uint8_t *p;
p = (void *)(p_end - 8);
if (p <= p_start)
@@ -379,14 +520,14 @@ void gen_code(const char *name, host_ulong offset, host_ulong size,
} else {
error("No save at the beginning of %s", name);
}
#if 0
/* Skip a preceeding nop, if present. */
if (p > p_start) {
skip_insn = get32((uint32_t *)(p - 0x4));
if (skip_insn == 0x01000000)
p -= 4;
}
#endif
copy_size = p - p_start;
}
break;
@@ -421,6 +562,20 @@ void gen_code(const char *name, host_ulong offset, host_ulong size,
copy_size = p - p_start;
}
break;
#ifdef HOST_ARM
case EM_ARM:
if ((p_end - p_start) <= 16)
error("%s: function too small", name);
if (get32((uint32_t *)p_start) != 0xe1a0c00d ||
(get32((uint32_t *)(p_start + 4)) & 0xffff0000) != 0xe92d0000 ||
get32((uint32_t *)(p_start + 8)) != 0xe24cb004)
error("%s: invalid prolog", name);
p_start += 12;
start_offset += 12;
copy_size = arm_emit_ldr_info(name, start_offset, NULL, p_start, p_end,
relocs, nb_relocs);
break;
#endif
default:
error("unknown ELF architecture");
}
@@ -431,7 +586,7 @@ void gen_code(const char *name, host_ulong offset, host_ulong size,
for(i = 0, rel = relocs;i < nb_relocs; i++, rel++) {
if (rel->r_offset >= start_offset &&
rel->r_offset < start_offset + copy_size) {
rel->r_offset < start_offset + (p_end - p_start)) {
sym_name = strtab + symtab[ELFW(R_SYM)(rel->r_info)].st_name;
if (strstart(sym_name, "__op_param", &p)) {
n = strtoul(p, NULL, 10);
@@ -469,7 +624,7 @@ void gen_code(const char *name, host_ulong offset, host_ulong size,
for(i = 0, rel = relocs;i < nb_relocs; i++, rel++) {
if (rel->r_offset >= start_offset &&
rel->r_offset < start_offset + copy_size) {
rel->r_offset < start_offset + (p_end - p_start)) {
sym_name = strtab + symtab[ELFW(R_SYM)(rel->r_info)].st_name;
if (*sym_name &&
!strstart(sym_name, "__op_param", NULL) &&
@@ -499,11 +654,37 @@ void gen_code(const char *name, host_ulong offset, host_ulong size,
for(i = 0, sym = symtab; i < nb_syms; i++, sym++) {
sym_name = strtab + sym->st_name;
if (strstart(sym_name, "__op_label", &p)) {
uint8_t *ptr;
unsigned long offset;
/* test if the variable refers to a label inside
the code we are generating */
if (sym->st_shndx != data_shndx)
error("__op_labelN symbols must be in .data or .sdata section");
val = *(target_ulong *)(data_data + sym->st_value);
ptr = sdata[sym->st_shndx];
if (!ptr)
error("__op_labelN in invalid section");
offset = sym->st_value;
val = *(target_ulong *)(ptr + offset);
#ifdef ELF_USES_RELOCA
{
int reloc_shndx, nb_relocs1, j;
/* try to find a matching relocation */
reloc_shndx = find_reloc(sym->st_shndx);
if (reloc_shndx) {
nb_relocs1 = shdr[reloc_shndx].sh_size /
shdr[reloc_shndx].sh_entsize;
rel = (ELF_RELOC *)sdata[reloc_shndx];
for(j = 0; j < nb_relocs1; j++) {
if (rel->r_offset == offset) {
val = rel->r_addend;
break;
}
rel++;
}
}
}
#endif
if (val >= start_offset && val < start_offset + copy_size) {
n = strtol(p, NULL, 10);
fprintf(outfile, " label_offsets[%d] = %d + (gen_code_ptr - gen_code_buf);\n", n, val - start_offset);
@@ -685,7 +866,7 @@ void gen_code(const char *name, host_ulong offset, host_ulong size,
case R_ALPHA_BRSGP:
/* PC-relative jump. Tweak offset to skip the two instructions that try to
set up the gp from the pv. */
fprintf(outfile, " fix_bsr(gen_code_ptr + %ld, (uint8_t *) &%s - (gen_code_ptr + %ld) + 4);\n",
fprintf(outfile, " fix_bsr(gen_code_ptr + %ld, (uint8_t *) &%s - (gen_code_ptr + %ld + 4) + 8);\n",
rel->r_offset - start_offset, sym_name, rel->r_offset - start_offset);
break;
default:
@@ -844,6 +1025,44 @@ void gen_code(const char *name, host_ulong offset, host_ulong size,
}
}
}
#elif defined(HOST_ARM)
{
char name[256];
int type;
int addend;
arm_emit_ldr_info(name, start_offset, outfile, p_start, p_end,
relocs, nb_relocs);
for(i = 0, rel = relocs;i < nb_relocs; i++, rel++) {
if (rel->r_offset >= start_offset &&
rel->r_offset < start_offset + copy_size) {
sym_name = strtab + symtab[ELFW(R_SYM)(rel->r_info)].st_name;
/* the compiler leave some unnecessary references to the code */
if (sym_name[0] == '\0')
continue;
if (strstart(sym_name, "__op_param", &p)) {
snprintf(name, sizeof(name), "param%s", p);
} else {
snprintf(name, sizeof(name), "(long)(&%s)", sym_name);
}
type = ELF32_R_TYPE(rel->r_info);
addend = get32((uint32_t *)(text + rel->r_offset));
switch(type) {
case R_ARM_ABS32:
fprintf(outfile, " *(uint32_t *)(gen_code_ptr + %d) = %s + %d;\n",
rel->r_offset - start_offset, name, addend);
break;
case R_ARM_PC24:
fprintf(outfile, " arm_reloc_pc24((uint32_t *)(gen_code_ptr + %d), 0x%x, %s);\n",
rel->r_offset - start_offset, addend, name);
break;
default:
error("unsupported arm relocation (%d)", type);
}
}
}
}
#else
#error unsupported CPU
#endif
@@ -872,16 +1091,17 @@ void gen_code(const char *name, host_ulong offset, host_ulong size,
}
/* load an elf object file */
int load_elf(const char *filename, FILE *outfile, int do_print_enum)
int load_elf(const char *filename, FILE *outfile, int out_type)
{
int fd;
struct elf_shdr *sec, *symtab_sec, *strtab_sec, *text_sec;
int i, j;
ElfW(Sym) *sym;
char *shstr, *data_name;
char *shstr;
uint8_t *text;
void *relocs;
int nb_relocs, reloc_sh_type;
ELF_RELOC *relocs;
int nb_relocs;
ELF_RELOC *rel;
fd = open(filename, O_RDONLY);
if (fd < 0)
@@ -920,56 +1140,45 @@ int load_elf(const char *filename, FILE *outfile, int do_print_enum)
}
}
sec = &shdr[ehdr.e_shstrndx];
shstr = load_data(fd, sec->sh_offset, sec->sh_size);
/* read all section data */
sdata = malloc(sizeof(void *) * ehdr.e_shnum);
memset(sdata, 0, sizeof(void *) * ehdr.e_shnum);
for(i = 0;i < ehdr.e_shnum; i++) {
sec = &shdr[i];
if (sec->sh_type != SHT_NOBITS)
sdata[i] = load_data(fd, sec->sh_offset, sec->sh_size);
}
sec = &shdr[ehdr.e_shstrndx];
shstr = sdata[ehdr.e_shstrndx];
/* swap relocations */
for(i = 0; i < ehdr.e_shnum; i++) {
sec = &shdr[i];
if (sec->sh_type == SHT_RELOC) {
nb_relocs = sec->sh_size / sec->sh_entsize;
if (do_swap) {
for(j = 0, rel = (ELF_RELOC *)sdata[i]; j < nb_relocs; j++, rel++)
elf_swap_rel(rel);
}
}
}
/* text section */
text_sec = find_elf_section(shdr, ehdr.e_shnum, shstr, ".text");
if (!text_sec)
error("could not find .text section");
text = load_data(fd, text_sec->sh_offset, text_sec->sh_size);
text_shndx = text_sec - shdr;
text = sdata[text_shndx];
#if defined(HOST_PPC)
data_name = ".sdata";
#else
data_name = ".data";
#endif
sec = find_elf_section(shdr, ehdr.e_shnum, shstr, data_name);
if (!sec)
error("could not find %s section", data_name);
data_shndx = sec - shdr;
data_data = load_data(fd, sec->sh_offset, sec->sh_size);
/* find text relocations, if any */
nb_relocs = 0;
relocs = NULL;
reloc_sh_type = 0;
for(i = 0; i < ehdr.e_shnum; i++) {
sec = &shdr[i];
if ((sec->sh_type == SHT_REL || sec->sh_type == SHT_RELA) &&
sec->sh_info == (text_sec - shdr)) {
reloc_sh_type = sec->sh_type;
relocs = load_data(fd, sec->sh_offset, sec->sh_size);
nb_relocs = sec->sh_size / sec->sh_entsize;
if (do_swap) {
if (sec->sh_type == SHT_REL) {
ElfW(Rel) *rel = relocs;
for(j = 0, rel = relocs; j < nb_relocs; j++, rel++) {
swabls(&rel->r_offset);
swabls(&rel->r_info);
}
} else {
ElfW(Rela) *rel = relocs;
for(j = 0, rel = relocs; j < nb_relocs; j++, rel++) {
swabls(&rel->r_offset);
swabls(&rel->r_info);
swabls(&rel->r_addend);
}
}
}
break;
}
nb_relocs = 0;
i = find_reloc(text_shndx);
if (i != 0) {
relocs = (ELF_RELOC *)sdata[i];
nb_relocs = shdr[i].sh_size / shdr[i].sh_entsize;
}
symtab_sec = find_elf_section(shdr, ehdr.e_shnum, shstr, ".symtab");
@@ -977,8 +1186,8 @@ int load_elf(const char *filename, FILE *outfile, int do_print_enum)
error("could not find .symtab section");
strtab_sec = &shdr[symtab_sec->sh_link];
symtab = load_data(fd, symtab_sec->sh_offset, symtab_sec->sh_size);
strtab = load_data(fd, strtab_sec->sh_offset, strtab_sec->sh_size);
symtab = (ElfW(Sym) *)sdata[symtab_sec - shdr];
strtab = sdata[symtab_sec->sh_link];
nb_syms = symtab_sec->sh_size / sizeof(ElfW(Sym));
if (do_swap) {
@@ -990,38 +1199,36 @@ int load_elf(const char *filename, FILE *outfile, int do_print_enum)
}
}
if (do_print_enum) {
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;
if (strstart(name, OP_PREFIX, &p)) {
gen_code(name, sym->st_value, sym->st_size, outfile,
text, relocs, nb_relocs, reloc_sh_type, 2);
text, relocs, nb_relocs, 2);
}
}
} else if (out_type == OUT_GEN_OP) {
/* generate gen_xxx functions */
for(i = 0, sym = symtab; i < nb_syms; i++, sym++) {
const char *name;
name = strtab + sym->st_name;
if (strstart(name, OP_PREFIX, NULL)) {
if (sym->st_shndx != (text_sec - shdr))
error("invalid section for opcode (0x%x)", sym->st_shndx);
gen_code(name, sym->st_value, sym->st_size, outfile,
text, relocs, nb_relocs, 0);
}
}
} else {
/* generate big code generation switch */
#ifdef HOST_ALPHA
fprintf(outfile,
"register int gp asm(\"$29\");\n"
"static inline void immediate_ldah(void *p, int val) {\n"
" uint32_t *dest = p;\n"
" long high = ((val >> 16) + ((val >> 15) & 1)) & 0xffff;\n"
"\n"
" *dest &= ~0xffff;\n"
" *dest |= high;\n"
" *dest |= 31 << 16;\n"
"}\n"
"static inline void immediate_lda(void *dest, int val) {\n"
" *(uint16_t *) dest = val;\n"
"}\n"
"void fix_bsr(void *p, int offset) {\n"
" uint32_t *dest = p;\n"
" *dest &= ~((1 << 21) - 1);\n"
" *dest |= (offset >> 2) & ((1 << 21) - 1);\n"
"}\n");
#endif
fprintf(outfile,
"int dyngen_code(uint8_t *gen_code_buf,\n"
" uint16_t *label_offsets, uint16_t *jmp_offsets,\n"
@@ -1029,23 +1236,22 @@ fprintf(outfile,
"{\n"
" uint8_t *gen_code_ptr;\n"
" const uint16_t *opc_ptr;\n"
" const uint32_t *opparam_ptr;\n"
" const uint32_t *opparam_ptr;\n");
#ifdef HOST_ARM
fprintf(outfile,
" uint8_t *last_gen_code_ptr = gen_code_buf;\n"
" LDREntry *arm_ldr_ptr = arm_ldr_table;\n"
" uint32_t *arm_data_ptr = arm_data_table;\n");
#endif
fprintf(outfile,
"\n"
" gen_code_ptr = gen_code_buf;\n"
" opc_ptr = opc_buf;\n"
" opparam_ptr = opparam_buf;\n");
/* Generate prologue, if needed. */
switch(ELF_ARCH) {
case EM_SPARC:
fprintf(outfile, "*((uint32_t *)gen_code_ptr)++ = 0x9c23a080; /* sub %%sp, 128, %%sp */\n");
fprintf(outfile, "*((uint32_t *)gen_code_ptr)++ = 0xbc27a080; /* sub %%fp, 128, %%fp */\n");
break;
case EM_SPARCV9:
fprintf(outfile, "*((uint32_t *)gen_code_ptr)++ = 0x9c23a100; /* sub %%sp, 256, %%sp */\n");
fprintf(outfile, "*((uint32_t *)gen_code_ptr)++ = 0xbc27a100; /* sub %%fp, 256, %%fp */\n");
break;
};
fprintf(outfile,
" for(;;) {\n"
@@ -1063,14 +1269,39 @@ fprintf(outfile,
if (sym->st_shndx != (text_sec - shdr))
error("invalid section for opcode (0x%x)", sym->st_shndx);
gen_code(name, sym->st_value, sym->st_size, outfile,
text, relocs, nb_relocs, reloc_sh_type, 1);
text, relocs, nb_relocs, 1);
}
}
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"
" }\n");
#ifdef HOST_ARM
/* generate constant table if needed */
fprintf(outfile,
" if ((gen_code_ptr - last_gen_code_ptr) >= (MAX_FRAG_SIZE - MAX_OP_SIZE)) {\n"
" gen_code_ptr = arm_flush_ldr(gen_code_ptr, arm_ldr_table, arm_ldr_ptr, arm_data_table, arm_data_ptr, 1);\n"
" last_gen_code_ptr = gen_code_ptr;\n"
" arm_ldr_ptr = arm_ldr_table;\n"
" arm_data_ptr = arm_data_table;\n"
" }\n");
#endif
fprintf(outfile,
" }\n"
" the_end:\n"
);
@@ -1094,33 +1325,25 @@ fprintf(outfile,
break;
case EM_SPARC:
case EM_SPARC32PLUS:
fprintf(outfile, "*((uint32_t *)gen_code_ptr)++ = 0xbc07a080; /* add %%fp, 256, %%fp */\n");
fprintf(outfile, "*((uint32_t *)gen_code_ptr)++ = 0x81c62008; /* jmpl %%i0 + 8, %%g0 */\n");
fprintf(outfile, "*((uint32_t *)gen_code_ptr)++ = 0x9c03a080; /* add %%sp, 256, %%sp */\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");
}
/* flush instruction cache */
fprintf(outfile, "flush_icache_range((unsigned long)gen_code_buf, (unsigned long)gen_code_ptr);\n");
fprintf(outfile, "return gen_code_ptr - gen_code_buf;\n");
fprintf(outfile, "}\n\n");
/* generate gen_xxx functions */
/* XXX: suppress the use of these functions to simplify code */
for(i = 0, sym = symtab; i < nb_syms; i++, sym++) {
const char *name;
name = strtab + sym->st_name;
if (strstart(name, OP_PREFIX, NULL)) {
if (sym->st_shndx != (text_sec - shdr))
error("invalid section for opcode (0x%x)", sym->st_shndx);
gen_code(name, sym->st_value, sym->st_size, outfile,
text, relocs, nb_relocs, reloc_sh_type, 0);
}
}
}
close(fd);
@@ -1133,20 +1356,21 @@ void usage(void)
"usage: dyngen [-o outfile] [-c] objfile\n"
"Generate a dynamic code generator from an object file\n"
"-c output enum of operations\n"
"-g output gen_op_xx() functions\n"
);
exit(1);
}
int main(int argc, char **argv)
{
int c, do_print_enum;
int c, out_type;
const char *filename, *outfilename;
FILE *outfile;
outfilename = "out.c";
do_print_enum = 0;
out_type = OUT_CODE;
for(;;) {
c = getopt(argc, argv, "ho:c");
c = getopt(argc, argv, "ho:cg");
if (c == -1)
break;
switch(c) {
@@ -1157,7 +1381,10 @@ int main(int argc, char **argv)
outfilename = optarg;
break;
case 'c':
do_print_enum = 1;
out_type = OUT_INDEX_OP;
break;
case 'g':
out_type = OUT_GEN_OP;
break;
}
}
@@ -1167,7 +1394,7 @@ int main(int argc, char **argv)
outfile = fopen(outfilename, "w");
if (!outfile)
error("could not open '%s'", outfilename);
load_elf(filename, outfile, do_print_enum);
load_elf(filename, outfile, out_type);
fclose(outfile);
return 0;
}
+198
View File
@@ -0,0 +1,198 @@
/*
* dyngen helpers
*
* 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
*/
int __op_param1, __op_param2, __op_param3;
int __op_jmp0, __op_jmp1;
#ifdef __i386__
static inline void flush_icache_range(unsigned long start, unsigned long stop)
{
}
#endif
#ifdef __s390__
static inline void flush_icache_range(unsigned long start, unsigned long stop)
{
}
#endif
#ifdef __ia64__
static inline void flush_icache_range(unsigned long start, unsigned long stop)
{
}
#endif
#ifdef __powerpc__
#define MIN_CACHE_LINE_SIZE 8 /* conservative value */
static void inline flush_icache_range(unsigned long start, unsigned long stop)
{
unsigned long p;
p = start & ~(MIN_CACHE_LINE_SIZE - 1);
stop = (stop + MIN_CACHE_LINE_SIZE - 1) & ~(MIN_CACHE_LINE_SIZE - 1);
for (p = start; p < stop; p += MIN_CACHE_LINE_SIZE) {
asm volatile ("dcbst 0,%0" : : "r"(p) : "memory");
}
asm volatile ("sync" : : : "memory");
for (p = start; p < stop; p += MIN_CACHE_LINE_SIZE) {
asm volatile ("icbi 0,%0" : : "r"(p) : "memory");
}
asm volatile ("sync" : : : "memory");
asm volatile ("isync" : : : "memory");
}
#endif
#ifdef __alpha__
static inline void flush_icache_range(unsigned long start, unsigned long stop)
{
asm ("imb");
}
#endif
#ifdef __sparc__
static void inline flush_icache_range(unsigned long start, unsigned long stop)
{
unsigned long p;
p = start & ~(8UL - 1UL);
stop = (stop + (8UL - 1UL)) & ~(8UL - 1UL);
for (; p < stop; p += 8)
__asm__ __volatile__("flush\t%0" : : "r" (p));
}
#endif
#ifdef __arm__
static inline void flush_icache_range(unsigned long start, unsigned long stop)
{
register unsigned long _beg __asm ("a1") = start;
register unsigned long _end __asm ("a2") = stop;
register unsigned long _flg __asm ("a3") = 0;
__asm __volatile__ ("swi 0x9f0002" : : "r" (_beg), "r" (_end), "r" (_flg));
}
#endif
#ifdef __alpha__
register int gp asm("$29");
static inline void immediate_ldah(void *p, int val) {
uint32_t *dest = p;
long high = ((val >> 16) + ((val >> 15) & 1)) & 0xffff;
*dest &= ~0xffff;
*dest |= high;
*dest |= 31 << 16;
}
static inline void immediate_lda(void *dest, int val) {
*(uint16_t *) dest = val;
}
void fix_bsr(void *p, int offset) {
uint32_t *dest = p;
*dest &= ~((1 << 21) - 1);
*dest |= (offset >> 2) & ((1 << 21) - 1);
}
#endif /* __alpha__ */
#ifdef __arm__
#define MAX_OP_SIZE (128 * 4) /* in bytes */
/* max size of the code that can be generated without calling arm_flush_ldr */
#define MAX_FRAG_SIZE (1024 * 4)
//#define MAX_FRAG_SIZE (135 * 4) /* for testing */
typedef struct LDREntry {
uint8_t *ptr;
uint32_t *data_ptr;
} LDREntry;
static LDREntry arm_ldr_table[1024];
static uint32_t arm_data_table[1024];
extern char exec_loop;
static inline void arm_reloc_pc24(uint32_t *ptr, uint32_t insn, int val)
{
*ptr = (insn & ~0xffffff) | ((insn + ((val - (int)ptr) >> 2)) & 0xffffff);
}
static uint8_t *arm_flush_ldr(uint8_t *gen_code_ptr,
LDREntry *ldr_start, LDREntry *ldr_end,
uint32_t *data_start, uint32_t *data_end,
int gen_jmp)
{
LDREntry *le;
uint32_t *ptr;
int offset, data_size, target;
uint8_t *data_ptr;
uint32_t insn;
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 {
/* generate branch to skip the data */
if (data_size == 0)
return gen_code_ptr;
target = (long)gen_code_ptr + data_size + 4;
arm_reloc_pc24((uint32_t *)gen_code_ptr, 0xeafffffe, target);
gen_code_ptr += 4;
}
/* copy the data */
data_ptr = gen_code_ptr;
memcpy(gen_code_ptr, data_start, data_size);
gen_code_ptr += data_size;
/* patch the ldr to point to the data */
for(le = ldr_start; le < ldr_end; le++) {
ptr = (uint32_t *)le->ptr;
offset = ((unsigned long)(le->data_ptr) - (unsigned long)data_start) +
(unsigned long)data_ptr -
(unsigned long)ptr - 8;
insn = *ptr & ~(0xfff | 0x00800000);
if (offset < 0) {
offset = - offset;
} else {
insn |= 0x00800000;
}
if (offset > 0xfff) {
fprintf(stderr, "Error ldr offset\n");
abort();
}
insn |= offset;
*ptr = insn;
}
return gen_code_ptr;
}
#endif /* __arm__ */
+32
View File
@@ -0,0 +1,32 @@
/*
* ARM execution defines
*
* 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 "dyngen-exec.h"
register struct CPUARMState *env asm(AREG0);
register uint32_t T0 asm(AREG1);
register uint32_t T1 asm(AREG2);
register uint32_t T2 asm(AREG3);
#include "cpu-arm.h"
#include "exec.h"
void cpu_lock(void);
void cpu_unlock(void);
void cpu_loop_exit(void);
-430
View File
@@ -1,430 +0,0 @@
/*
* i386 emulator main execution loop
*
* 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 "exec-i386.h"
#include "disas.h"
//#define DEBUG_EXEC
//#define DEBUG_SIGNAL
/* main execution loop */
/* thread support */
spinlock_t global_cpu_lock = SPIN_LOCK_UNLOCKED;
void cpu_lock(void)
{
spin_lock(&global_cpu_lock);
}
void cpu_unlock(void)
{
spin_unlock(&global_cpu_lock);
}
void cpu_loop_exit(void)
{
/* NOTE: the register at this point must be saved by hand because
longjmp restore them */
#ifdef __sparc__
/* We have to stay in the same register window as our caller,
* thus this trick.
*/
__asm__ __volatile__("restore\n\t"
"mov\t%o0, %i0");
#endif
#ifdef reg_EAX
env->regs[R_EAX] = EAX;
#endif
#ifdef reg_ECX
env->regs[R_ECX] = ECX;
#endif
#ifdef reg_EDX
env->regs[R_EDX] = EDX;
#endif
#ifdef reg_EBX
env->regs[R_EBX] = EBX;
#endif
#ifdef reg_ESP
env->regs[R_ESP] = ESP;
#endif
#ifdef reg_EBP
env->regs[R_EBP] = EBP;
#endif
#ifdef reg_ESI
env->regs[R_ESI] = ESI;
#endif
#ifdef reg_EDI
env->regs[R_EDI] = EDI;
#endif
longjmp(env->jmp_env, 1);
}
int cpu_x86_exec(CPUX86State *env1)
{
int saved_T0, saved_T1, saved_A0;
CPUX86State *saved_env;
#ifdef reg_EAX
int saved_EAX;
#endif
#ifdef reg_ECX
int saved_ECX;
#endif
#ifdef reg_EDX
int saved_EDX;
#endif
#ifdef reg_EBX
int saved_EBX;
#endif
#ifdef reg_ESP
int saved_ESP;
#endif
#ifdef reg_EBP
int saved_EBP;
#endif
#ifdef reg_ESI
int saved_ESI;
#endif
#ifdef reg_EDI
int saved_EDI;
#endif
int code_gen_size, ret;
void (*gen_func)(void);
TranslationBlock *tb, **ptb;
uint8_t *tc_ptr, *cs_base, *pc;
unsigned int flags;
/* first we save global registers */
saved_T0 = T0;
saved_T1 = T1;
saved_A0 = A0;
saved_env = env;
env = env1;
#ifdef reg_EAX
saved_EAX = EAX;
EAX = env->regs[R_EAX];
#endif
#ifdef reg_ECX
saved_ECX = ECX;
ECX = env->regs[R_ECX];
#endif
#ifdef reg_EDX
saved_EDX = EDX;
EDX = env->regs[R_EDX];
#endif
#ifdef reg_EBX
saved_EBX = EBX;
EBX = env->regs[R_EBX];
#endif
#ifdef reg_ESP
saved_ESP = ESP;
ESP = env->regs[R_ESP];
#endif
#ifdef reg_EBP
saved_EBP = EBP;
EBP = env->regs[R_EBP];
#endif
#ifdef reg_ESI
saved_ESI = ESI;
ESI = env->regs[R_ESI];
#endif
#ifdef reg_EDI
saved_EDI = EDI;
EDI = env->regs[R_EDI];
#endif
/* put eflags in CPU temporary format */
CC_SRC = env->eflags & (CC_O | CC_S | CC_Z | CC_A | CC_P | CC_C);
DF = 1 - (2 * ((env->eflags >> 10) & 1));
CC_OP = CC_OP_EFLAGS;
env->eflags &= ~(DF_MASK | CC_O | CC_S | CC_Z | CC_A | CC_P | CC_C);
env->interrupt_request = 0;
/* prepare setjmp context for exception handling */
if (setjmp(env->jmp_env) == 0) {
T0 = 0; /* force lookup of first TB */
for(;;) {
if (env->interrupt_request) {
env->exception_index = EXCP_INTERRUPT;
cpu_loop_exit();
}
#ifdef DEBUG_EXEC
if (loglevel) {
/* XXX: save all volatile state in cpu state */
/* 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);
}
#endif
/* we compute the CPU state. We assume it will not
change during the whole generated block. */
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;
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);
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_x86_gen_code(tb, CODE_GEN_MAX_SIZE, &code_gen_size);
/* 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);
}
*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));
}
#endif
/* see if we can patch the calling TB */
if (T0 != 0 && !(env->eflags & TF_MASK)) {
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;
#ifdef __sparc__
__asm__ __volatile__("call %0\n\t"
" mov %%o7,%%i0"
: /* no outputs */
: "r" (gen_func)
: "i0", "i1", "i2", "i3", "i4", "i5");
#else
gen_func();
#endif
}
}
ret = env->exception_index;
/* restore flags in standard format */
env->eflags = env->eflags | cc_table[CC_OP].compute_all() | (DF & DF_MASK);
/* restore global registers */
#ifdef reg_EAX
EAX = saved_EAX;
#endif
#ifdef reg_ECX
ECX = saved_ECX;
#endif
#ifdef reg_EDX
EDX = saved_EDX;
#endif
#ifdef reg_EBX
EBX = saved_EBX;
#endif
#ifdef reg_ESP
ESP = saved_ESP;
#endif
#ifdef reg_EBP
EBP = saved_EBP;
#endif
#ifdef reg_ESI
ESI = saved_ESI;
#endif
#ifdef reg_EDI
EDI = saved_EDI;
#endif
T0 = saved_T0;
T1 = saved_T1;
A0 = saved_A0;
env = saved_env;
return ret;
}
void cpu_x86_interrupt(CPUX86State *s)
{
s->interrupt_request = 1;
}
void cpu_x86_load_seg(CPUX86State *s, int seg_reg, int selector)
{
CPUX86State *saved_env;
saved_env = env;
env = s;
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,
so we must load them here */
sc->base = (void *)(selector << 4);
sc->limit = 0xffff;
sc->seg_32bit = 0;
env->segs[seg_reg] = selector;
} else {
load_seg(seg_reg, selector, 0);
}
env = saved_env;
}
#undef EAX
#undef ECX
#undef EDX
#undef EBX
#undef ESP
#undef EBP
#undef ESI
#undef EDI
#undef EIP
#include <signal.h>
#include <sys/ucontext.h>
/* '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
signal set which should be restored */
static inline int handle_cpu_signal(unsigned long pc, unsigned long address,
int is_write, sigset_t *old_set)
{
TranslationBlock *tb;
int ret;
uint32_t found_pc;
#if defined(DEBUG_SIGNAL)
printf("qemu: SIGSEGV pc=0x%08lx address=%08lx wr=%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;
}
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_x86_search_pc(tb, &found_pc, pc);
if (ret < 0)
return 0;
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));
/* never comes here */
return 1;
} else {
return 0;
}
}
#if defined(__i386__)
int cpu_x86_signal_handler(int host_signum, struct siginfo *info,
void *puc)
{
struct ucontext *uc = puc;
unsigned long pc;
#ifndef REG_EIP
/* for glibc 2.1 */
#define REG_EIP EIP
#define REG_ERR ERR
#define REG_TRAPNO TRAPNO
#endif
pc = uc->uc_mcontext.gregs[REG_EIP];
return handle_cpu_signal(pc, (unsigned long)info->si_addr,
uc->uc_mcontext.gregs[REG_TRAPNO] == 0xe ?
(uc->uc_mcontext.gregs[REG_ERR] >> 1) & 1 : 0,
&uc->uc_sigmask);
}
#elif defined(__powerpc)
int cpu_x86_signal_handler(int host_signum, struct siginfo *info,
void *puc)
{
struct ucontext *uc = puc;
struct pt_regs *regs = uc->uc_mcontext.regs;
unsigned long pc;
int is_write;
pc = regs->nip;
is_write = 0;
#if 0
/* ppc 4xx case */
if (regs->dsisr & 0x00800000)
is_write = 1;
#else
if (regs->trap != 0x400 && (regs->dsisr & 0x02000000))
is_write = 1;
#endif
return handle_cpu_signal(pc, (unsigned long)info->si_addr,
is_write, &uc->uc_sigmask);
}
#else
#error CPU specific signal handler needed
#endif
+277 -145
View File
@@ -17,134 +17,59 @@
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
typedef unsigned char uint8_t;
typedef unsigned short uint16_t;
typedef unsigned int uint32_t;
typedef unsigned long long uint64_t;
#include "dyngen-exec.h"
typedef signed char int8_t;
typedef signed short int16_t;
typedef signed int int32_t;
typedef signed long long int64_t;
/* at least 4 register variables are defines */
register struct CPUX86State *env asm(AREG0);
register uint32_t T0 asm(AREG1);
register uint32_t T1 asm(AREG2);
register uint32_t T2 asm(AREG3);
#define bswap32(x) \
({ \
uint32_t __x = (x); \
((uint32_t)( \
(((uint32_t)(__x) & (uint32_t)0x000000ffUL) << 24) | \
(((uint32_t)(__x) & (uint32_t)0x0000ff00UL) << 8) | \
(((uint32_t)(__x) & (uint32_t)0x00ff0000UL) >> 8) | \
(((uint32_t)(__x) & (uint32_t)0xff000000UL) >> 24) )); \
})
#define A0 T2
#define NULL 0
#include <fenv.h>
/* if more registers are available, we define some registers too */
#ifdef AREG4
register uint32_t EAX asm(AREG4);
#define reg_EAX
#endif
#ifdef AREG5
register uint32_t ESP asm(AREG5);
#define reg_ESP
#endif
#ifdef AREG6
register uint32_t EBP asm(AREG6);
#define reg_EBP
#endif
#ifdef AREG7
register uint32_t ECX asm(AREG7);
#define reg_ECX
#endif
#ifdef AREG8
register uint32_t EDX asm(AREG8);
#define reg_EDX
#endif
#ifdef AREG9
register uint32_t EBX asm(AREG9);
#define reg_EBX
#endif
#ifdef AREG10
register uint32_t ESI asm(AREG10);
#define reg_ESI
#endif
#ifdef AREG11
register uint32_t EDI asm(AREG11);
#define reg_EDI
#endif
typedef struct FILE FILE;
extern FILE *logfile;
extern int loglevel;
extern int fprintf(FILE *, const char *, ...);
extern int printf(const char *, ...);
#ifdef __i386__
register unsigned int T0 asm("ebx");
register unsigned int T1 asm("esi");
register unsigned int A0 asm("edi");
register struct CPUX86State *env asm("ebp");
#endif
#ifdef __powerpc__
register unsigned int EAX asm("r16");
register unsigned int ECX asm("r17");
register unsigned int EDX asm("r18");
register unsigned int EBX asm("r19");
register unsigned int ESP asm("r20");
register unsigned int EBP asm("r21");
register unsigned int ESI asm("r22");
register unsigned int EDI asm("r23");
register unsigned int T0 asm("r24");
register unsigned int T1 asm("r25");
register unsigned int A0 asm("r26");
register struct CPUX86State *env asm("r27");
#define USE_INT_TO_FLOAT_HELPERS
#define BUGGY_GCC_DIV64
#define reg_EAX
#define reg_ECX
#define reg_EDX
#define reg_EBX
#define reg_ESP
#define reg_EBP
#define reg_ESI
#define reg_EDI
#endif
#ifdef __arm__
register unsigned int T0 asm("r4");
register unsigned int T1 asm("r5");
register unsigned int A0 asm("r6");
register struct CPUX86State *env asm("r7");
#endif
#ifdef __mips__
register unsigned int T0 asm("s0");
register unsigned int T1 asm("s1");
register unsigned int A0 asm("s2");
register struct CPUX86State *env asm("s3");
#endif
#ifdef __sparc__
register unsigned int EAX asm("l0");
register unsigned int ECX asm("l1");
register unsigned int EDX asm("l2");
register unsigned int EBX asm("l3");
register unsigned int ESP asm("l4");
register unsigned int EBP asm("l5");
register unsigned int ESI asm("l6");
register unsigned int EDI asm("l7");
register unsigned int T0 asm("g1");
register unsigned int T1 asm("g2");
register unsigned int A0 asm("g3");
register struct CPUX86State *env asm("g6");
#define USE_FP_CONVERT
#define reg_EAX
#define reg_ECX
#define reg_EDX
#define reg_EBX
#define reg_ESP
#define reg_EBP
#define reg_ESI
#define reg_EDI
#endif
#ifdef __s390__
register unsigned int T0 asm("r7");
register unsigned int T1 asm("r8");
register unsigned int A0 asm("r9");
register struct CPUX86State *env asm("r10");
#endif
#ifdef __alpha__
register unsigned int T0 asm("$9");
register unsigned int T1 asm("$10");
register unsigned int A0 asm("$11");
register unsigned int EAX asm("$12");
register unsigned int ESP asm("$13");
register unsigned int EBP asm("$14");
register struct CPUX86State *env asm("$15");
#define reg_EAX
#define reg_ESP
#define reg_EBP
#endif
#ifdef __ia64__
register unsigned int T0 asm("r24");
register unsigned int T1 asm("r25");
register unsigned int A0 asm("r26");
register struct CPUX86State *env asm("r27");
#endif
/* force GCC to generate only one epilog at the end of the function */
#define FORCE_RET() asm volatile ("");
#ifndef OPPROTO
#define OPPROTO
#endif
#define xglue(x, y) x ## y
#define glue(x, y) xglue(x, y)
#ifndef reg_EAX
#define EAX (env->regs[R_EAX])
@@ -187,26 +112,6 @@ register struct CPUX86State *env asm("r27");
#define FP_CONVERT (env->fp_convert)
#endif
#ifdef __alpha__
/* Suggested by Richard Henderson. This will result in code like
ldah $0,__op_param1($29) !gprelhigh
lda $0,__op_param1($0) !gprellow
We can then conveniently change $29 to $31 and adapt the offsets to
emit the appropriate constant. */
extern int __op_param1 __attribute__((visibility("hidden")));
extern int __op_param2 __attribute__((visibility("hidden")));
extern int __op_param3 __attribute__((visibility("hidden")));
#define PARAM1 ({ int _r; asm("" : "=r"(_r) : "0" (&__op_param1)); _r; })
#define PARAM2 ({ int _r; asm("" : "=r"(_r) : "0" (&__op_param2)); _r; })
#define PARAM3 ({ int _r; asm("" : "=r"(_r) : "0" (&__op_param3)); _r; })
#else
extern int __op_param1, __op_param2, __op_param3;
#define PARAM1 ((long)(&__op_param1))
#define PARAM2 ((long)(&__op_param2))
#define PARAM3 ((long)(&__op_param3))
#endif
extern int __op_jmp0, __op_jmp1;
#include "cpu-i386.h"
#include "exec.h"
@@ -218,13 +123,240 @@ typedef struct CCTable {
extern CCTable cc_table[];
void load_seg(int seg_reg, int selector, unsigned cur_eip);
void cpu_lock(void);
void cpu_unlock(void);
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);
void raise_exception(int exception_index);
void cpu_loop_exit(void);
void __hidden cpu_loop_exit(void);
void helper_fsave(uint8_t *ptr, int data32);
void helper_frstor(uint8_t *ptr, int data32);
void OPPROTO op_movl_eflags_T0(void);
void OPPROTO op_movl_T0_eflags(void);
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);
void raise_exception(int exception_index);
void helper_divl_EAX_T0(uint32_t eip);
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);
#ifdef USE_X86LDOUBLE
/* use long double functions */
#define lrint lrintl
#define llrint llrintl
#define fabs fabsl
#define sin sinl
#define cos cosl
#define sqrt sqrtl
#define pow powl
#define log logl
#define tan tanl
#define atan2 atan2l
#define floor floorl
#define ceil ceill
#define rint rintl
#endif
extern int lrint(CPU86_LDouble x);
extern int64_t llrint(CPU86_LDouble x);
extern CPU86_LDouble fabs(CPU86_LDouble x);
extern CPU86_LDouble sin(CPU86_LDouble x);
extern CPU86_LDouble cos(CPU86_LDouble x);
extern CPU86_LDouble sqrt(CPU86_LDouble x);
extern CPU86_LDouble pow(CPU86_LDouble, CPU86_LDouble);
extern CPU86_LDouble log(CPU86_LDouble x);
extern CPU86_LDouble tan(CPU86_LDouble x);
extern CPU86_LDouble atan2(CPU86_LDouble, CPU86_LDouble);
extern CPU86_LDouble floor(CPU86_LDouble x);
extern CPU86_LDouble ceil(CPU86_LDouble x);
extern CPU86_LDouble rint(CPU86_LDouble x);
#define RC_MASK 0xc00
#define RC_NEAR 0x000
#define RC_DOWN 0x400
#define RC_UP 0x800
#define RC_CHOP 0xc00
#define MAXTAN 9223372036854775808.0
#ifdef __arm__
/* we have no way to do correct rounding - a FPU emulator is needed */
#define FE_DOWNWARD FE_TONEAREST
#define FE_UPWARD FE_TONEAREST
#define FE_TOWARDZERO FE_TONEAREST
#endif
#ifdef USE_X86LDOUBLE
/* only for x86 */
typedef union {
long double d;
struct {
unsigned long long lower;
unsigned short upper;
} l;
} CPU86_LDoubleU;
/* the following deal with x86 long double-precision numbers */
#define MAXEXPD 0x7fff
#define EXPBIAS 16383
#define EXPD(fp) (fp.l.upper & 0x7fff)
#define SIGND(fp) ((fp.l.upper) & 0x8000)
#define MANTD(fp) (fp.l.lower)
#define BIASEXPONENT(fp) fp.l.upper = (fp.l.upper & ~(0x7fff)) | EXPBIAS
#else
/* NOTE: arm is horrible as double 32 bit words are stored in big endian ! */
typedef union {
double d;
#if !defined(WORDS_BIGENDIAN) && !defined(__arm__)
struct {
uint32_t lower;
int32_t upper;
} l;
#else
struct {
int32_t upper;
uint32_t lower;
} l;
#endif
#ifndef __arm__
int64_t ll;
#endif
} CPU86_LDoubleU;
/* the following deal with IEEE double-precision numbers */
#define MAXEXPD 0x7ff
#define EXPBIAS 1023
#define EXPD(fp) (((fp.l.upper) >> 20) & 0x7FF)
#define SIGND(fp) ((fp.l.upper) & 0x80000000)
#ifdef __arm__
#define MANTD(fp) (fp.l.lower | ((uint64_t)(fp.l.upper & ((1 << 20) - 1)) << 32))
#else
#define MANTD(fp) (fp.ll & ((1LL << 52) - 1))
#endif
#define BIASEXPONENT(fp) fp.l.upper = (fp.l.upper & ~(0x7ff << 20)) | (EXPBIAS << 20)
#endif
static inline void fpush(void)
{
env->fpstt = (env->fpstt - 1) & 7;
env->fptags[env->fpstt] = 0; /* validate stack entry */
}
static inline void fpop(void)
{
env->fptags[env->fpstt] = 1; /* invvalidate stack entry */
env->fpstt = (env->fpstt + 1) & 7;
}
#ifndef USE_X86LDOUBLE
static inline CPU86_LDouble helper_fldt(uint8_t *ptr)
{
CPU86_LDoubleU temp;
int upper, e;
uint64_t ll;
/* mantissa */
upper = lduw(ptr + 8);
/* XXX: handle overflow ? */
e = (upper & 0x7fff) - 16383 + EXPBIAS; /* exponent */
e |= (upper >> 4) & 0x800; /* sign */
ll = (ldq(ptr) >> 11) & ((1LL << 52) - 1);
#ifdef __arm__
temp.l.upper = (e << 20) | (ll >> 32);
temp.l.lower = ll;
#else
temp.ll = ll | ((uint64_t)e << 52);
#endif
return temp.d;
}
static inline void helper_fstt(CPU86_LDouble f, uint8_t *ptr)
{
CPU86_LDoubleU temp;
int e;
temp.d = f;
/* mantissa */
stq(ptr, (MANTD(temp) << 11) | (1LL << 63));
/* exponent + sign */
e = EXPD(temp) - EXPBIAS + 16383;
e |= SIGND(temp) >> 16;
stw(ptr + 8, e);
}
#endif
const CPU86_LDouble f15rk[7];
void helper_fldt_ST0_A0(void);
void helper_fstt_ST0_A0(void);
void helper_fbld_ST0_A0(void);
void helper_fbst_ST0_A0(void);
void helper_f2xm1(void);
void helper_fyl2x(void);
void helper_fptan(void);
void helper_fpatan(void);
void helper_fxtract(void);
void helper_fprem1(void);
void helper_fprem(void);
void helper_fyl2xp1(void);
void helper_fsqrt(void);
void helper_fsincos(void);
void helper_frndint(void);
void helper_fscale(void);
void helper_fsin(void);
void helper_fcos(void);
void helper_fxam_ST0(void);
void helper_fstenv(uint8_t *ptr, int data32);
void helper_fldenv(uint8_t *ptr, int data32);
void helper_fsave(uint8_t *ptr, int data32);
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);
}
+128 -3
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
@@ -70,7 +76,7 @@ unsigned long host_page_mask;
static PageDesc *l1_map[L1_SIZE];
void page_init(void)
static void page_init(void)
{
/* NOTE: we can always suppose that host_page_size >=
TARGET_PAGE_SIZE */
@@ -190,10 +196,11 @@ void page_set_flags(unsigned long start, unsigned long end, int flags)
spin_unlock(&tb_lock);
}
void cpu_x86_tblocks_init(void)
void cpu_exec_init(void)
{
if (!code_gen_ptr) {
code_gen_ptr = code_gen_buffer;
page_init();
}
}
@@ -562,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
+99 -10
View File
@@ -18,6 +18,32 @@
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
/* allow to see translation results - the slowdown should be negligible, so we leave it */
#define DEBUG_DISAS
/* is_jmp field values */
#define DISAS_NEXT 0 /* next instruction can be analyzed */
#define DISAS_JUMP 1 /* only pc was modified dynamically */
#define DISAS_UPDATE 2 /* cpu state was modified dynamically */
#define DISAS_TB_JUMP 3 /* only pc was modified statically */
struct TranslationBlock;
/* XXX: make safe guess about sizes */
#define MAX_OP_PER_INSTR 32
#define OPC_BUF_SIZE 512
#define OPC_MAX_SIZE (OPC_BUF_SIZE - MAX_OP_PER_INSTR)
#define OPPARAM_BUF_SIZE (OPC_BUF_SIZE * 3)
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)
#define GEN_FLAG_CODE32_SHIFT 0
#define GEN_FLAG_ADDSEG_SHIFT 1
#define GEN_FLAG_SS32_SHIFT 2
@@ -27,14 +53,21 @@
#define GEN_FLAG_CPL_SHIFT 9
#define GEN_FLAG_IOPL_SHIFT 12 /* same position as eflags */
struct TranslationBlock;
int cpu_x86_gen_code(struct TranslationBlock *tb,
int max_code_size, int *gen_code_size_ptr);
int cpu_x86_search_pc(struct TranslationBlock *tb,
uint32_t *found_pc, unsigned long searched_pc);
void cpu_x86_tblocks_init(void);
void page_init(void);
#endif
extern FILE *logfile;
extern int loglevel;
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_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 */
@@ -65,7 +98,7 @@ typedef struct TranslationBlock {
#ifdef USE_DIRECT_JUMP
uint16_t tb_jmp_offset[2]; /* offset of jump instruction */
#else
uint8_t *tb_next[2]; /* address of jump generated code */
uint32_t tb_next[2]; /* address of jump generated code */
#endif
/* list of TBs jumping to this one. This is a circular list using
the two least significant bits of the pointers to tell what is
@@ -142,7 +175,7 @@ static inline void tb_set_jmp_target(TranslationBlock *tb,
static inline void tb_set_jmp_target(TranslationBlock *tb,
int n, unsigned long addr)
{
tb->tb_next[n] = (void *)addr;
tb->tb_next[n] = addr;
}
#endif
@@ -167,6 +200,35 @@ TranslationBlock *tb_find_pc(unsigned long pc_ptr);
#define offsetof(type, field) ((size_t) &((type *)0)->field)
#endif
#if defined(__powerpc__)
/* on PowerPC we patch the jump instruction directly */
#define JUMP_TB(tbparam, n, eip)\
do {\
static void __attribute__((unused)) *__op_label ## n = &&label ## n;\
asm volatile ("b %0" : : "i" (&__op_jmp ## n));\
label ## n:\
T0 = (long)(tbparam) + (n);\
EIP = eip;\
} while (0)
#else
/* jump to next block operations (more portable code, does not need
cache flushing, but slower because of indirect jump) */
#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:\
} while (0)
#endif
#ifdef __powerpc__
static inline int testandset (int *p)
{
@@ -214,7 +276,7 @@ static inline int testandset (int *p)
#endif
#ifdef __alpha__
int testandset (int *p)
static inline int testandset (int *p)
{
int ret;
unsigned long one;
@@ -246,10 +308,23 @@ static inline int testandset (int *p)
}
#endif
#ifdef __arm__
static inline int testandset (int *spinlock)
{
register unsigned int ret;
__asm__ __volatile__("swp %0, %1, [%2]"
: "=r"(ret)
: "0"(1), "r"(spinlock));
return ret;
}
#endif
typedef int spinlock_t;
#define SPIN_LOCK_UNLOCKED 0
#if 1
static inline void spin_lock(spinlock_t *lock)
{
while (testandset(lock));
@@ -264,6 +339,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;
}
+1471
View File
File diff suppressed because it is too large. Load diff
+2 -2
View File
@@ -1164,8 +1164,8 @@ int
print_insn_x86 (pc, info, aflag, dflag)
bfd_vma pc;
disassemble_info *info;
int aflag;
int dflag;
int volatile aflag;
int volatile dflag;
{
struct dis386 *dp;
int i;
+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 . */
}
+40 -10
View File
@@ -17,13 +17,6 @@
#define ELF_START_MMAP 0x80000000
typedef uint32_t elf_greg_t;
#define ELF_NGREG (sizeof (struct target_pt_regs) / sizeof(elf_greg_t))
typedef elf_greg_t elf_gregset_t[ELF_NGREG];
typedef struct user_i387_struct elf_fpregset_t;
/*
* This is used to ensure we don't load something for the wrong architecture.
*/
@@ -45,6 +38,45 @@ typedef struct user_i387_struct elf_fpregset_t;
A value of 0 tells we have no such handler. */
#define ELF_PLAT_INIT(_r) _r->edx = 0
static inline void init_thread(struct target_pt_regs *regs, struct image_info *infop)
{
regs->esp = infop->start_stack;
regs->eip = infop->entry;
}
#define USE_ELF_CORE_DUMP
#define ELF_EXEC_PAGESIZE 4096
#endif
#ifdef TARGET_ARM
#define ELF_START_MMAP 0x80000000
#define elf_check_arch(x) ( (x) == EM_ARM )
#define ELF_CLASS ELFCLASS32
#ifdef TARGET_WORDS_BIGENDIAN
#define ELF_DATA ELFDATA2MSB
#else
#define ELF_DATA ELFDATA2LSB
#endif
#define ELF_ARCH EM_ARM
#define ELF_PLAT_INIT(_r) _r->ARM_r0 = 0
static inline void init_thread(struct target_pt_regs *regs, struct image_info *infop)
{
target_long *stack = (void *)infop->start_stack;
memset(regs, 0, sizeof(*regs));
regs->ARM_cpsr = 0x10;
regs->ARM_pc = infop->entry;
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 */
}
#define USE_ELF_CORE_DUMP
#define ELF_EXEC_PAGESIZE 4096
@@ -758,7 +790,6 @@ static int load_elf_binary(struct linux_binprm * bprm, struct target_pt_regs * r
}
/* Now read in all of the header information */
elf_phdata = (struct elf_phdr *)malloc(elf_ex.e_phentsize*elf_ex.e_phnum);
if (elf_phdata == NULL) {
return -ENOMEM;
@@ -1156,8 +1187,7 @@ int elf_exec(const char * filename, char ** argv, char ** envp,
}
if(retval>=0) {
/* success. Initialize important registers */
regs->esp = infop->start_stack;
regs->eip = infop->entry;
init_thread(regs, infop);
return retval;
}
+8 -4
View File
@@ -150,6 +150,7 @@
IOCTL(CDROM_DISC_STATUS, 0, TYPE_NULL)
IOCTL(CDROMAUDIOBUFSIZ, 0, TYPE_INT)
#if 0
IOCTL(SNDCTL_COPR_HALT, IOC_RW, MK_PTR(TYPE_INT))
IOCTL(SNDCTL_COPR_LOAD, IOC_RW, MK_PTR(TYPE_INT))
IOCTL(SNDCTL_COPR_RCODE, IOC_RW, MK_PTR(TYPE_INT))
@@ -160,14 +161,15 @@
IOCTL(SNDCTL_COPR_SENDMSG, IOC_RW, MK_PTR(TYPE_INT))
IOCTL(SNDCTL_COPR_WCODE, IOC_W, MK_PTR(TYPE_INT))
IOCTL(SNDCTL_COPR_WDATA, IOC_W, MK_PTR(TYPE_INT))
#endif
IOCTL(SNDCTL_DSP_CHANNELS, IOC_RW, MK_PTR(TYPE_INT))
IOCTL(SNDCTL_DSP_GETBLKSIZE, IOC_RW, MK_PTR(TYPE_INT))
IOCTL(SNDCTL_DSP_GETCAPS, IOC_R, MK_PTR(TYPE_INT))
IOCTL(SNDCTL_DSP_GETFMTS, IOC_R, MK_PTR(TYPE_INT))
IOCTL(SNDCTL_DSP_GETIPTR, IOC_R, MK_PTR(TYPE_INT))
IOCTL(SNDCTL_DSP_GETISPACE, IOC_R, MK_PTR(TYPE_INT))
IOCTL(SNDCTL_DSP_GETOPTR, IOC_R, MK_PTR(TYPE_INT))
IOCTL(SNDCTL_DSP_GETOSPACE, IOC_R, MK_PTR(TYPE_INT))
IOCTL(SNDCTL_DSP_GETIPTR, IOC_R, MK_PTR(MK_STRUCT(STRUCT_count_info)))
IOCTL(SNDCTL_DSP_GETOPTR, IOC_R, MK_PTR(MK_STRUCT(STRUCT_count_info)))
IOCTL(SNDCTL_DSP_GETISPACE, IOC_R, MK_PTR(MK_STRUCT(STRUCT_audio_buf_info)))
IOCTL(SNDCTL_DSP_GETOSPACE, IOC_R, MK_PTR(MK_STRUCT(STRUCT_audio_buf_info)))
IOCTL(SNDCTL_DSP_GETTRIGGER, IOC_R, MK_PTR(TYPE_INT))
IOCTL(SNDCTL_DSP_MAPINBUF, IOC_R, MK_PTR(TYPE_INT))
IOCTL(SNDCTL_DSP_MAPOUTBUF, IOC_R, MK_PTR(TYPE_INT))
@@ -183,6 +185,7 @@
IOCTL(SNDCTL_DSP_STEREO, IOC_RW, MK_PTR(TYPE_INT))
IOCTL(SNDCTL_DSP_SUBDIVIDE, IOC_RW, MK_PTR(TYPE_INT))
IOCTL(SNDCTL_DSP_SYNC, 0, TYPE_NULL)
#if 0
IOCTL(SNDCTL_FM_4OP_ENABLE, IOC_W, MK_PTR(TYPE_INT))
IOCTL(SNDCTL_FM_LOAD_INSTR, IOC_W, MK_PTR(TYPE_INT))
IOCTL(SNDCTL_MIDI_INFO, IOC_RW, MK_PTR(TYPE_INT))
@@ -222,6 +225,7 @@
IOCTL(SOUND_PCM_READ_CHANNELS, IOC_R, MK_PTR(TYPE_INT))
IOCTL(SOUND_PCM_READ_BITS, IOC_R, MK_PTR(TYPE_INT))
IOCTL(SOUND_PCM_READ_FILTER, IOC_R, MK_PTR(TYPE_INT))
#endif
IOCTL(SOUND_MIXER_INFO, IOC_R, MK_PTR(TYPE_INT))
IOCTL(SOUND_MIXER_ACCESS, 0, TYPE_PTRVOID)
IOCTL(SOUND_MIXER_PRIVATE1, IOC_RW, MK_PTR(TYPE_INT))
+90 -15
View File
@@ -26,8 +26,6 @@
#include "qemu.h"
#include "cpu-i386.h"
#define DEBUG_LOGFILE "/tmp/qemu.log"
FILE *logfile = NULL;
@@ -38,6 +36,7 @@ static const char *interp_prefix = CONFIG_QEMU_PREFIX;
/* Force usage of an ELF interpreter even if it is an ELF shared
object ! */
const char interp[] __attribute__((section(".interp"))) = "/lib/ld-linux.so.2";
#endif
/* for recent libc, we add these dummies symbol which are not declared
when generating a linked object (bug in ld ?) */
@@ -48,8 +47,6 @@ long __fini_array_start[0];
long __fini_array_end[0];
#endif
#endif
/* XXX: on x86 MAP_GROWSDOWN only works if ESP <= address + 32, so
we allocate a bigger stack. Need a better solution, for example
by remapping the process stack directly at the right place */
@@ -64,6 +61,7 @@ void gemu_log(const char *fmt, ...)
va_end(ap);
}
#ifdef TARGET_I386
/***********************************************************/
/* CPUX86 core interface */
@@ -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();
@@ -239,20 +242,76 @@ void cpu_loop(CPUX86State *env)
process_pending_signals(env);
}
}
#endif
#ifdef TARGET_ARM
#define ARM_SYSCALL_BASE 0x900000
void cpu_loop(CPUARMState *env)
{
int trapnr;
unsigned int n, insn;
target_siginfo_t info;
for(;;) {
trapnr = cpu_arm_exec(env);
switch(trapnr) {
case EXCP_UDEF:
info.si_signo = SIGILL;
info.si_errno = 0;
info.si_code = TARGET_ILL_ILLOPN;
info._sifields._sigfault._addr = env->regs[15];
queue_signal(info.si_signo, &info);
break;
case EXCP_SWI:
{
/* system call */
insn = ldl((void *)(env->regs[15] - 4));
n = insn & 0xffffff;
if (n >= ARM_SYSCALL_BASE) {
/* linux syscall */
n -= ARM_SYSCALL_BASE;
env->regs[0] = do_syscall(env,
n,
env->regs[0],
env->regs[1],
env->regs[2],
env->regs[3],
env->regs[4],
0);
} else {
goto error;
}
}
break;
default:
error:
fprintf(stderr, "qemu: unhandled CPU exception 0x%x - aborting\n",
trapnr);
cpu_arm_dump_state(env, stderr, 0);
abort();
}
process_pending_signals(env);
}
}
#endif
void usage(void)
{
printf("qemu version " QEMU_VERSION ", Copyright (c) 2003 Fabrice Bellard\n"
"usage: qemu [-h] [-d] [-L path] [-s size] program [arguments...]\n"
"Linux x86 emulator\n"
"Linux CPU emulator (compiled for %s emulation)\n"
"\n"
"-h print this help\n"
"-L path set the x86 elf interpreter prefix (default=%s)\n"
"-s size set the x86 stack size in bytes (default=%ld)\n"
"-L path set the elf interpreter prefix (default=%s)\n"
"-s size set the stack size in bytes (default=%ld)\n"
"\n"
"debug options:\n"
"-d activate log (logfile=%s)\n"
"-p pagesize set the host page size to 'pagesize'\n",
TARGET_ARCH,
interp_prefix,
x86_stack_size,
DEBUG_LOGFILE);
@@ -260,7 +319,10 @@ void usage(void)
}
/* XXX: currently only used for async signals (see signal.c) */
CPUX86State *global_env;
CPUState *global_env;
/* used only if single thread */
CPUState *cpu_single_env = NULL;
/* used to free thread contexts */
TaskState *first_task_state;
@@ -270,7 +332,7 @@ int main(int argc, char **argv)
struct target_pt_regs regs1, *regs = &regs1;
struct image_info info1, *info = &info1;
TaskState ts1, *ts = &ts1;
CPUX86State *env;
CPUState *env;
int optind;
const char *r;
@@ -338,8 +400,8 @@ int main(int argc, char **argv)
/* NOTE: we need to init the CPU at this stage to get the
host_page_size */
env = cpu_x86_init();
env = cpu_init();
if (elf_exec(filename, argv+optind, environ, regs, info) != 0) {
printf("Error loading %s\n", filename);
_exit(1);
@@ -354,8 +416,7 @@ int main(int argc, char **argv)
fprintf(logfile, "end_data 0x%08lx\n" , info->end_data);
fprintf(logfile, "start_stack 0x%08lx\n" , info->start_stack);
fprintf(logfile, "brk 0x%08lx\n" , info->brk);
fprintf(logfile, "esp 0x%08lx\n" , regs->esp);
fprintf(logfile, "eip 0x%08lx\n" , regs->eip);
fprintf(logfile, "entry 0x%08lx\n" , info->entry);
}
target_set_brk((char *)info->brk);
@@ -368,7 +429,9 @@ 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 */
env->regs[R_EAX] = regs->eax;
env->regs[R_EBX] = regs->ebx;
@@ -421,6 +484,18 @@ int main(int argc, char **argv)
cpu_x86_load_seg(env, R_FS, __USER_DS);
cpu_x86_load_seg(env, R_GS, __USER_DS);
#elif defined(TARGET_ARM)
{
int i;
for(i = 0; i < 16; i++) {
env->regs[i] = regs->uregs[i];
}
env->cpsr = regs->uregs[16];
}
#else
#error unsupported target CPU
#endif
cpu_loop(env);
/* never exits */
return 0;
+12 -1
View File
@@ -188,6 +188,11 @@ long target_mmap(unsigned long start, unsigned long len, int prot,
host_start = start & host_page_mask;
if (!(flags & MAP_FIXED)) {
#if defined(__alpha__) || defined(__sparc__)
/* tell the kenel to search at the same place as i386 */
if (host_start == 0)
host_start = 0x40000000;
#endif
if (host_page_size != real_host_page_size) {
/* NOTE: this code is only for debugging with '-p' option */
/* reserve a memory area */
@@ -277,8 +282,13 @@ long target_mmap(unsigned long start, unsigned long len, int prot,
/* map the middle (easier) */
if (host_start < host_end) {
unsigned long offset1;
if (flags & MAP_ANONYMOUS)
offset1 = 0;
else
offset1 = offset + host_start - start;
ret = (long)mmap((void *)host_start, host_end - host_start,
prot, flags, fd, offset + host_start - start);
prot, flags, fd, offset1);
if (ret == -1)
return ret;
}
@@ -286,6 +296,7 @@ long target_mmap(unsigned long start, unsigned long len, int prot,
page_set_flags(start, start + len, prot | PAGE_VALID);
the_end:
#ifdef DEBUG_MMAP
printf("ret=0x%lx\n", (long)start);
page_dump(stdout);
printf("\n");
#endif
+23 -6
View File
@@ -6,9 +6,14 @@
#include <signal.h>
#include "syscall_defs.h"
#ifdef TARGET_I386
#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.
@@ -33,6 +38,7 @@ struct image_info {
int personality;
};
#ifdef TARGET_I386
/* Information about the current linux thread */
struct vm86_saved_state {
uint32_t eax; /* return code */
@@ -47,16 +53,19 @@ struct vm86_saved_state {
uint32_t eip;
uint16_t cs, ss, ds, es, fs, gs;
};
#endif
/* NOTE: we force a big alignment so that the stack stored after is
aligned too */
typedef struct TaskState {
struct TaskState *next;
#ifdef TARGET_I386
struct target_vm86plus_struct *target_v86;
struct vm86_saved_state vm86_saved_regs;
struct target_vm86plus_struct vm86plus;
uint32_t v86flags;
uint32_t v86mask;
#endif
int used; /* non zero if used */
uint8_t stack[0];
} __attribute__((aligned(16))) TaskState;
@@ -71,23 +80,31 @@ void syscall_init(void);
long do_syscall(void *cpu_env, int num, long arg1, long arg2, long arg3,
long arg4, long arg5, long arg6);
void gemu_log(const char *fmt, ...) __attribute__((format(printf,1,2)));
extern CPUX86State *global_env;
void cpu_loop(CPUX86State *env);
void process_pending_signals(void *cpu_env);
void signal_init(void);
int queue_signal(int sig, target_siginfo_t *info);
extern CPUState *global_env;
void cpu_loop(CPUState *env);
void init_paths(const char *prefix);
const char *path(const char *pathname);
extern int loglevel;
extern FILE *logfile;
/* signal.c */
void process_pending_signals(void *cpu_env);
void signal_init(void);
int queue_signal(int sig, target_siginfo_t *info);
void host_to_target_siginfo(target_siginfo_t *tinfo, const siginfo_t *info);
void target_to_host_siginfo(siginfo_t *info, const target_siginfo_t *tinfo);
long do_sigreturn(CPUState *env);
long do_rt_sigreturn(CPUState *env);
#ifdef TARGET_I386
/* vm86.c */
void save_v86_state(CPUX86State *env);
void handle_vm86_trap(CPUX86State *env, int trapno);
void handle_vm86_fault(CPUX86State *env);
int do_vm86(CPUX86State *env, long subfunction,
struct target_vm86plus_struct * target_v86);
#endif
/* mmap.c */
int target_mprotect(unsigned long start, unsigned long len, int prot);
+54 -47
View File
@@ -318,7 +318,7 @@ static void host_signal_handler(int host_signum, siginfo_t *info,
/* the CPU emulator uses some host signals to detect exceptions,
we we forward to it some signals */
if (host_signum == SIGSEGV || host_signum == SIGBUS) {
if (cpu_x86_signal_handler(host_signum, info, puc))
if (cpu_signal_handler(host_signum, info, puc))
return;
}
@@ -333,7 +333,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_x86_interrupt(global_env);
cpu_interrupt(global_env, CPU_INTERRUPT_EXIT);
}
}
@@ -517,10 +517,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,22 +532,19 @@ 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);
#if 0
tmp = save_i387(fpstate);
if (tmp < 0)
err = 1;
else
err |= __put_user(tmp ? fpstate : NULL, &sc->fpstate);
#else
err |= __put_user(0, &sc->fpstate);
#endif
err |= __put_user(env->segs[R_SS].selector, (unsigned int *)&sc->ss);
cpu_x86_fsave(env, (void *)fpstate, 1);
fpstate->status = fpstate->sw;
err |= __put_user(0xffff, &fpstate->magic);
err |= __put_user(fpstate, &sc->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;
}
@@ -570,13 +567,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,
@@ -721,25 +719,6 @@ restore_sigcontext(CPUX86State *env, struct target_sigcontext *sc, int *peax)
{
unsigned int err = 0;
#define COPY(x) err |= __get_user(regs->x, &sc->x)
#define COPY_SEG(seg) \
{ unsigned short tmp; \
err |= __get_user(tmp, &sc->seg); \
regs->x##seg = tmp; }
#define COPY_SEG_STRICT(seg) \
{ unsigned short tmp; \
err |= __get_user(tmp, &sc->seg); \
regs->x##seg = tmp|3; }
#define GET_SEG(seg) \
{ unsigned short tmp; \
err |= __get_user(tmp, &sc->seg); \
loadsegment(seg,tmp); }
cpu_x86_load_seg(env, R_GS, lduw(&sc->gs));
cpu_x86_load_seg(env, R_FS, lduw(&sc->fs));
cpu_x86_load_seg(env, R_ES, lduw(&sc->es));
@@ -764,17 +743,18 @@ restore_sigcontext(CPUX86State *env, struct target_sigcontext *sc, int *peax)
// regs->orig_eax = -1; /* disable syscall checks */
}
#if 0
{
struct _fpstate * buf;
err |= __get_user(buf, &sc->fpstate);
buf = (void *)ldl(&sc->fpstate);
if (buf) {
#if 0
if (verify_area(VERIFY_READ, buf, sizeof(*buf)))
goto badframe;
err |= restore_i387(buf);
#endif
cpu_x86_frstor(env, (void *)buf, 1);
}
}
#endif
*peax = ldl(&sc->eax);
return err;
#if 0
@@ -845,6 +825,33 @@ badframe:
return 0;
}
#else
static void setup_frame(int sig, struct emulated_sigaction *ka,
target_sigset_t *set, CPUState *env)
{
fprintf(stderr, "setup_frame: not implemented\n");
}
static void setup_rt_frame(int sig, struct emulated_sigaction *ka,
target_siginfo_t *info,
target_sigset_t *set, CPUState *env)
{
fprintf(stderr, "setup_rt_frame: not implemented\n");
}
long do_sigreturn(CPUState *env)
{
fprintf(stderr, "do_sigreturn: not implemented\n");
return -ENOSYS;
}
long do_rt_sigreturn(CPUState *env)
{
fprintf(stderr, "do_rt_sigreturn: not implemented\n");
return -ENOSYS;
}
#endif
void process_pending_signals(void *cpu_env)
+114 -21
View File
@@ -68,11 +68,6 @@
#define VFAT_IOCTL_READDIR_BOTH _IOR('r', 1, struct dirent [2])
#define VFAT_IOCTL_READDIR_SHORT _IOR('r', 2, struct dirent [2])
void host_to_target_siginfo(target_siginfo_t *tinfo, const siginfo_t *info);
void target_to_host_siginfo(siginfo_t *info, const target_siginfo_t *tinfo);
long do_sigreturn(CPUX86State *env);
long do_rt_sigreturn(CPUX86State *env);
#define __NR_sys_uname __NR_uname
#define __NR_sys_getcwd1 __NR_getcwd
#define __NR_sys_statfs __NR_statfs
@@ -702,8 +697,8 @@ enum {
#undef STRUCT_SPECIAL
typedef struct IOCTLEntry {
int target_cmd;
int host_cmd;
unsigned int target_cmd;
unsigned int host_cmd;
const char *name;
int access;
const argtype arg_type[5];
@@ -715,7 +710,7 @@ typedef struct IOCTLEntry {
#define MAX_STRUCT_SIZE 4096
const IOCTLEntry ioctl_entries[] = {
IOCTLEntry ioctl_entries[] = {
#define IOCTL(cmd, access, types...) \
{ TARGET_ ## cmd, cmd, #cmd, access, { types } },
#include "ioctls.h"
@@ -958,7 +953,19 @@ StructEntry struct_termios_def = {
.align = { __alignof__(struct target_termios), __alignof__(struct host_termios) },
};
#ifdef TARGET_I386
static bitmask_transtbl mmap_flags_tbl[] = {
{ TARGET_MAP_SHARED, TARGET_MAP_SHARED, MAP_SHARED, MAP_SHARED },
{ TARGET_MAP_PRIVATE, TARGET_MAP_PRIVATE, MAP_PRIVATE, MAP_PRIVATE },
{ TARGET_MAP_FIXED, TARGET_MAP_FIXED, MAP_FIXED, MAP_FIXED },
{ TARGET_MAP_ANONYMOUS, TARGET_MAP_ANONYMOUS, MAP_ANONYMOUS, MAP_ANONYMOUS },
{ TARGET_MAP_GROWSDOWN, TARGET_MAP_GROWSDOWN, MAP_GROWSDOWN, MAP_GROWSDOWN },
{ TARGET_MAP_DENYWRITE, TARGET_MAP_DENYWRITE, MAP_DENYWRITE, MAP_DENYWRITE },
{ TARGET_MAP_EXECUTABLE, TARGET_MAP_EXECUTABLE, MAP_EXECUTABLE, MAP_EXECUTABLE },
{ TARGET_MAP_LOCKED, TARGET_MAP_LOCKED, MAP_LOCKED, MAP_LOCKED },
{ 0, 0, 0, 0 }
};
#if defined(TARGET_I386)
/* NOTE: there is really one LDT for all the threads */
uint8_t *ldt_table;
@@ -1075,28 +1082,28 @@ int do_modify_ldt(CPUX86State *env, int func, void *ptr, unsigned long bytecount
return ret;
}
#endif /* defined(TARGET_I386) */
/* this stack is the equivalent of the kernel stack associated with a
thread/process */
#define NEW_STACK_SIZE 8192
static int clone_func(void *arg)
{
CPUX86State *env = arg;
CPUState *env = arg;
cpu_loop(env);
/* never exits */
return 0;
}
int do_fork(CPUX86State *env, unsigned int flags, unsigned long newsp)
int do_fork(CPUState *env, unsigned int flags, unsigned long newsp)
{
int ret;
TaskState *ts;
uint8_t *new_stack;
CPUX86State *new_env;
CPUState *new_env;
if (flags & CLONE_VM) {
if (!newsp)
newsp = env->regs[R_ESP];
ts = malloc(sizeof(TaskState) + NEW_STACK_SIZE);
memset(ts, 0, sizeof(TaskState));
new_stack = ts->stack;
@@ -1105,10 +1112,21 @@ int do_fork(CPUX86State *env, unsigned int flags, unsigned long newsp)
ts->next = first_task_state;
first_task_state = ts;
/* we create a new CPU instance. */
new_env = cpu_x86_init();
memcpy(new_env, env, sizeof(CPUX86State));
new_env = cpu_init();
memcpy(new_env, env, sizeof(CPUState));
#if defined(TARGET_I386)
if (!newsp)
newsp = env->regs[R_ESP];
new_env->regs[R_ESP] = newsp;
new_env->regs[R_EAX] = 0;
#elif defined(TARGET_ARM)
if (!newsp)
newsp = env->regs[13];
new_env->regs[13] = newsp;
new_env->regs[0] = 0;
#else
#error unsupported target CPU
#endif
new_env->opaque = ts;
#ifdef __ia64__
ret = clone2(clone_func, new_stack + NEW_STACK_SIZE, flags, new_env);
@@ -1124,8 +1142,6 @@ int do_fork(CPUX86State *env, unsigned int flags, unsigned long newsp)
return ret;
}
#endif
static long do_fcntl(int fd, int cmd, unsigned long arg)
{
struct flock fl;
@@ -1176,11 +1192,43 @@ static long do_fcntl(int fd, int cmd, unsigned long arg)
void syscall_init(void)
{
IOCTLEntry *ie;
const argtype *arg_type;
int size;
#define STRUCT(name, list...) thunk_register_struct(STRUCT_ ## name, #name, struct_ ## name ## _def);
#define STRUCT_SPECIAL(name) thunk_register_struct_direct(STRUCT_ ## name, #name, &struct_ ## name ## _def);
#include "syscall_types.h"
#undef STRUCT
#undef STRUCT_SPECIAL
/* we patch the ioctl size if necessary. We rely on the fact that
no ioctl has all the bits at '1' in the size field */
ie = ioctl_entries;
while (ie->target_cmd != 0) {
if (((ie->target_cmd >> TARGET_IOC_SIZESHIFT) & TARGET_IOC_SIZEMASK) ==
TARGET_IOC_SIZEMASK) {
arg_type = ie->arg_type;
if (arg_type[0] != TYPE_PTR) {
fprintf(stderr, "cannot patch size for ioctl 0x%x\n",
ie->target_cmd);
exit(1);
}
arg_type++;
size = thunk_type_size(arg_type, 0);
ie->target_cmd = (ie->target_cmd &
~(TARGET_IOC_SIZEMASK << TARGET_IOC_SIZESHIFT)) |
(size << TARGET_IOC_SIZESHIFT);
}
/* automatic consistency check if same arch */
#if defined(__i386__) && defined(TARGET_I386)
if (ie->target_cmd != ie->host_cmd) {
fprintf(stderr, "ERROR: ioctl: target=0x%x host=0x%x\n",
ie->target_cmd, ie->host_cmd);
}
#endif
ie++;
}
}
long do_syscall(void *cpu_env, int num, long arg1, long arg2, long arg3,
@@ -1744,7 +1792,9 @@ long do_syscall(void *cpu_env, int num, long arg1, long arg2, long arg3,
v4 = tswap32(vptr[3]);
v5 = tswap32(vptr[4]);
v6 = tswap32(vptr[5]);
ret = get_errno(target_mmap(v1, v2, v3, v4, v5, v6));
ret = get_errno(target_mmap(v1, v2, v3,
target_to_host_bitmask(v4, mmap_flags_tbl),
v5, v6));
}
break;
#endif
@@ -1753,7 +1803,9 @@ long do_syscall(void *cpu_env, int num, long arg1, long arg2, long arg3,
#else
case TARGET_NR_mmap:
#endif
ret = get_errno(target_mmap(arg1, arg2, arg3, arg4, arg5,
ret = get_errno(target_mmap(arg1, arg2, arg3,
target_to_host_bitmask(arg4, mmap_flags_tbl),
arg5,
arg6 << TARGET_PAGE_BITS));
break;
case TARGET_NR_munmap:
@@ -1999,7 +2051,47 @@ long do_syscall(void *cpu_env, int num, long arg1, long arg2, long arg3,
case TARGET_NR_getdents:
#if TARGET_LONG_SIZE != 4
#error not supported
#endif
#elif TARGET_LONG_SIZE == 4 && HOST_LONG_SIZE == 8
{
struct target_dirent *target_dirp = (void *)arg2;
struct dirent *dirp;
long count = arg3;
dirp = malloc(count);
if (!dirp)
return -ENOMEM;
ret = get_errno(sys_getdents(arg1, dirp, count));
if (!is_error(ret)) {
struct dirent *de;
struct target_dirent *tde;
int len = ret;
int reclen, treclen;
int count1, tnamelen;
count1 = 0;
de = dirp;
tde = target_dirp;
while (len > 0) {
reclen = de->d_reclen;
treclen = reclen - (2 * (sizeof(long) - sizeof(target_long)));
tde->d_reclen = tswap16(treclen);
tde->d_ino = tswapl(de->d_ino);
tde->d_off = tswapl(de->d_off);
tnamelen = treclen - (2 * sizeof(target_long) + 2);
if (tnamelen > 256)
tnamelen = 256;
strncpy(tde->d_name, de->d_name, tnamelen);
de = (struct dirent *)((char *)de + reclen);
len -= reclen;
tde = (struct dirent *)((char *)tde + treclen);
count1 += treclen;
}
ret = count1;
}
free(dirp);
}
#else
{
struct dirent *dirp = (void *)arg2;
long count = arg3;
@@ -2022,6 +2114,7 @@ long do_syscall(void *cpu_env, int num, long arg1, long arg2, long arg3,
}
}
}
#endif
break;
case TARGET_NR_getdents64:
{
File diff suppressed because it is too large. Load diff
+9
View File
@@ -67,3 +67,12 @@ STRUCT(dirent,
STRUCT(kbentry,
TYPE_CHAR, TYPE_CHAR, TYPE_SHORT)
STRUCT(audio_buf_info,
TYPE_INT, TYPE_INT, TYPE_INT, TYPE_INT)
STRUCT(count_info,
TYPE_INT, TYPE_INT, TYPE_INT)
STRUCT(mixer_info,
MK_ARRAY(TYPE_CHAR, 16), MK_ARRAY(TYPE_CHAR, 32), TYPE_INT, MK_ARRAY(TYPE_INT, 10))
+26 -24
View File
@@ -41,22 +41,22 @@ static inline int is_revectored(int nr, struct target_revectored_struct *bitmap)
static inline void vm_putw(uint8_t *segptr, unsigned int reg16, unsigned int val)
{
*(uint16_t *)(segptr + (reg16 & 0xffff)) = tswap16(val);
stw(segptr + (reg16 & 0xffff), val);
}
static inline void vm_putl(uint8_t *segptr, unsigned int reg16, unsigned int val)
{
*(uint32_t *)(segptr + (reg16 & 0xffff)) = tswap32(val);
stl(segptr + (reg16 & 0xffff), val);
}
static inline unsigned int vm_getw(uint8_t *segptr, unsigned int reg16)
{
return tswap16(*(uint16_t *)(segptr + (reg16 & 0xffff)));
return lduw(segptr + (reg16 & 0xffff));
}
static inline unsigned int vm_getl(uint8_t *segptr, unsigned int reg16)
{
return tswap32(*(uint32_t *)(segptr + (reg16 & 0xffff)));
return ldl(segptr + (reg16 & 0xffff));
}
void save_v86_state(CPUX86State *env)
@@ -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:
+48
View File
@@ -0,0 +1,48 @@
/*
* ARM micro operations (templates for various register related
* operations)
*
* 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
*/
void OPPROTO glue(op_movl_T0_, REGNAME)(void)
{
T0 = REG;
}
void OPPROTO glue(op_movl_T1_, REGNAME)(void)
{
T1 = REG;
}
void OPPROTO glue(op_movl_T2_, REGNAME)(void)
{
T2 = REG;
}
void OPPROTO glue(glue(op_movl_, REGNAME), _T0)(void)
{
REG = T0;
}
void OPPROTO glue(glue(op_movl_, REGNAME), _T1)(void)
{
REG = T1;
}
#undef REG
#undef REGNAME
+665
View File
@@ -0,0 +1,665 @@
/*
* ARM micro operations
*
* 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 "exec-arm.h"
#define REGNAME r0
#define REG (env->regs[0])
#include "op-arm-template.h"
#define REGNAME r1
#define REG (env->regs[1])
#include "op-arm-template.h"
#define REGNAME r2
#define REG (env->regs[2])
#include "op-arm-template.h"
#define REGNAME r3
#define REG (env->regs[3])
#include "op-arm-template.h"
#define REGNAME r4
#define REG (env->regs[4])
#include "op-arm-template.h"
#define REGNAME r5
#define REG (env->regs[5])
#include "op-arm-template.h"
#define REGNAME r6
#define REG (env->regs[6])
#include "op-arm-template.h"
#define REGNAME r7
#define REG (env->regs[7])
#include "op-arm-template.h"
#define REGNAME r8
#define REG (env->regs[8])
#include "op-arm-template.h"
#define REGNAME r9
#define REG (env->regs[9])
#include "op-arm-template.h"
#define REGNAME r10
#define REG (env->regs[10])
#include "op-arm-template.h"
#define REGNAME r11
#define REG (env->regs[11])
#include "op-arm-template.h"
#define REGNAME r12
#define REG (env->regs[12])
#include "op-arm-template.h"
#define REGNAME r13
#define REG (env->regs[13])
#include "op-arm-template.h"
#define REGNAME r14
#define REG (env->regs[14])
#include "op-arm-template.h"
#define REGNAME r15
#define REG (env->regs[15])
#include "op-arm-template.h"
void OPPROTO op_movl_T0_0(void)
{
T0 = 0;
}
void OPPROTO op_movl_T0_im(void)
{
T0 = PARAM1;
}
void OPPROTO op_movl_T1_im(void)
{
T1 = PARAM1;
}
void OPPROTO op_movl_T2_im(void)
{
T2 = PARAM1;
}
void OPPROTO op_addl_T1_im(void)
{
T1 += PARAM1;
}
void OPPROTO op_addl_T1_T2(void)
{
T1 += T2;
}
void OPPROTO op_subl_T1_T2(void)
{
T1 -= T2;
}
void OPPROTO op_addl_T0_T1(void)
{
T0 += T1;
}
void OPPROTO op_addl_T0_T1_cc(void)
{
unsigned int src1;
src1 = T0;
T0 += T1;
env->NZF = T0;
env->CF = T0 < src1;
env->VF = (src1 ^ T1 ^ -1) & (src1 ^ T0);
}
void OPPROTO op_adcl_T0_T1(void)
{
T0 += T1 + env->CF;
}
void OPPROTO op_adcl_T0_T1_cc(void)
{
unsigned int src1;
src1 = T0;
if (!env->CF) {
T0 += T1;
env->CF = T0 < src1;
} else {
T0 += T1 + 1;
env->CF = T0 <= src1;
}
env->VF = (src1 ^ T1 ^ -1) & (src1 ^ T0);
env->NZF = T0;
FORCE_RET();
}
#define OPSUB(sub, sbc, T0, T1) \
\
void OPPROTO op_ ## sub ## l_T0_T1(void) \
{ \
T0 -= T1; \
} \
\
void OPPROTO op_ ## sub ## l_T0_T1_cc(void) \
{ \
unsigned int src1; \
src1 = T0; \
T0 -= T1; \
env->NZF = T0; \
env->CF = src1 < T1; \
env->VF = (src1 ^ T1) & (src1 ^ T0); \
} \
\
void OPPROTO op_ ## sbc ## l_T0_T1(void) \
{ \
T0 = T0 - T1 + env->CF - 1; \
} \
\
void OPPROTO op_ ## sbc ## l_T0_T1_cc(void) \
{ \
unsigned int src1; \
src1 = T0; \
if (!env->CF) { \
T0 = T0 - T1 - 1; \
T0 += T1; \
env->CF = src1 < T1; \
} else { \
T0 = T0 - T1; \
env->CF = src1 <= T1; \
} \
env->VF = (src1 ^ T1) & (src1 ^ T0); \
env->NZF = T0; \
FORCE_RET(); \
}
OPSUB(sub, sbc, T0, T1)
OPSUB(rsb, rsc, T1, T0)
void OPPROTO op_andl_T0_T1(void)
{
T0 &= T1;
}
void OPPROTO op_xorl_T0_T1(void)
{
T0 ^= T1;
}
void OPPROTO op_orl_T0_T1(void)
{
T0 |= T1;
}
void OPPROTO op_bicl_T0_T1(void)
{
T0 &= ~T1;
}
void OPPROTO op_notl_T1(void)
{
T1 = ~T1;
}
void OPPROTO op_logic_cc(void)
{
env->NZF = T0;
}
#define EIP (env->regs[15])
void OPPROTO op_test_eq(void)
{
if (env->NZF == 0)
JUMP_TB(PARAM1, 0, PARAM2);
FORCE_RET();
}
void OPPROTO op_test_ne(void)
{
if (env->NZF != 0)
JUMP_TB(PARAM1, 0, PARAM2);
FORCE_RET();
}
void OPPROTO op_test_cs(void)
{
if (env->CF != 0)
JUMP_TB(PARAM1, 0, PARAM2);
FORCE_RET();
}
void OPPROTO op_test_cc(void)
{
if (env->CF == 0)
JUMP_TB(PARAM1, 0, PARAM2);
FORCE_RET();
}
void OPPROTO op_test_mi(void)
{
if ((env->NZF & 0x80000000) != 0)
JUMP_TB(PARAM1, 0, PARAM2);
FORCE_RET();
}
void OPPROTO op_test_pl(void)
{
if ((env->NZF & 0x80000000) == 0)
JUMP_TB(PARAM1, 0, PARAM2);
FORCE_RET();
}
void OPPROTO op_test_vs(void)
{
if ((env->VF & 0x80000000) != 0)
JUMP_TB(PARAM1, 0, PARAM2);
FORCE_RET();
}
void OPPROTO op_test_vc(void)
{
if ((env->VF & 0x80000000) == 0)
JUMP_TB(PARAM1, 0, PARAM2);
FORCE_RET();
}
void OPPROTO op_test_hi(void)
{
if (env->CF != 0 && env->NZF != 0)
JUMP_TB(PARAM1, 0, PARAM2);
FORCE_RET();
}
void OPPROTO op_test_ls(void)
{
if (env->CF == 0 || env->NZF == 0)
JUMP_TB(PARAM1, 0, PARAM2);
FORCE_RET();
}
void OPPROTO op_test_ge(void)
{
if (((env->VF ^ env->NZF) & 0x80000000) == 0)
JUMP_TB(PARAM1, 0, PARAM2);
FORCE_RET();
}
void OPPROTO op_test_lt(void)
{
if (((env->VF ^ env->NZF) & 0x80000000) != 0)
JUMP_TB(PARAM1, 0, PARAM2);
FORCE_RET();
}
void OPPROTO op_test_gt(void)
{
if (env->NZF != 0 && ((env->VF ^ env->NZF) & 0x80000000) == 0)
JUMP_TB(PARAM1, 0, PARAM2);
FORCE_RET();
}
void OPPROTO op_test_le(void)
{
if (env->NZF == 0 || ((env->VF ^ env->NZF) & 0x80000000) != 0)
JUMP_TB(PARAM1, 0, PARAM2);
FORCE_RET();
}
void OPPROTO op_jmp(void)
{
JUMP_TB(PARAM1, 1, PARAM2);
}
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);
}
/* NOTE: N = 1 and Z = 1 cannot be stored currently */
void OPPROTO op_movl_psr_T0(void)
{
unsigned int psr;
psr = T0;
env->CF = (psr >> 29) & 1;
env->NZF = (psr & 0xc0000000) ^ 0x40000000;
env->VF = (psr << 3) & 0x80000000;
/* for user mode we do not update other state info */
}
void OPPROTO op_mul_T0_T1(void)
{
T0 = T0 * T1;
}
/* 64 bit unsigned mul */
void OPPROTO op_mull_T0_T1(void)
{
uint64_t res;
res = T0 * T1;
T1 = res >> 32;
T0 = res;
}
/* 64 bit signed mul */
void OPPROTO op_imull_T0_T1(void)
{
uint64_t res;
res = (int32_t)T0 * (int32_t)T1;
T1 = res >> 32;
T0 = res;
}
void OPPROTO op_addq_T0_T1(void)
{
uint64_t res;
res = ((uint64_t)T1 << 32) | T0;
res += ((uint64_t)(env->regs[PARAM2]) << 32) | (env->regs[PARAM1]);
T1 = res >> 32;
T0 = res;
}
void OPPROTO op_logicq_cc(void)
{
env->NZF = (T1 & 0x80000000) | ((T0 | T1) != 0);
}
/* memory access */
void OPPROTO op_ldub_T0_T1(void)
{
T0 = ldub((void *)T1);
}
void OPPROTO op_ldsb_T0_T1(void)
{
T0 = ldsb((void *)T1);
}
void OPPROTO op_lduw_T0_T1(void)
{
T0 = lduw((void *)T1);
}
void OPPROTO op_ldsw_T0_T1(void)
{
T0 = ldsw((void *)T1);
}
void OPPROTO op_ldl_T0_T1(void)
{
T0 = ldl((void *)T1);
}
void OPPROTO op_stb_T0_T1(void)
{
stb((void *)T1, T0);
}
void OPPROTO op_stw_T0_T1(void)
{
stw((void *)T1, T0);
}
void OPPROTO op_stl_T0_T1(void)
{
stl((void *)T1, T0);
}
void OPPROTO op_swpb_T0_T1(void)
{
int tmp;
cpu_lock();
tmp = ldub((void *)T1);
stb((void *)T1, T0);
T0 = tmp;
cpu_unlock();
}
void OPPROTO op_swpl_T0_T1(void)
{
int tmp;
cpu_lock();
tmp = ldl((void *)T1);
stl((void *)T1, T0);
T0 = tmp;
cpu_unlock();
}
/* shifts */
/* T1 based */
void OPPROTO op_shll_T1_im(void)
{
T1 = T1 << PARAM1;
}
void OPPROTO op_shrl_T1_im(void)
{
T1 = (uint32_t)T1 >> PARAM1;
}
void OPPROTO op_sarl_T1_im(void)
{
T1 = (int32_t)T1 >> PARAM1;
}
void OPPROTO op_rorl_T1_im(void)
{
int shift;
shift = PARAM1;
T1 = ((uint32_t)T1 >> shift) | (T1 << (32 - shift));
}
/* T1 based, set C flag */
void OPPROTO op_shll_T1_im_cc(void)
{
env->CF = (T1 >> (32 - PARAM1)) & 1;
T1 = T1 << PARAM1;
}
void OPPROTO op_shrl_T1_im_cc(void)
{
env->CF = (T1 >> (PARAM1 - 1)) & 1;
T1 = (uint32_t)T1 >> PARAM1;
}
void OPPROTO op_sarl_T1_im_cc(void)
{
env->CF = (T1 >> (PARAM1 - 1)) & 1;
T1 = (int32_t)T1 >> PARAM1;
}
void OPPROTO op_rorl_T1_im_cc(void)
{
int shift;
shift = PARAM1;
env->CF = (T1 >> (shift - 1)) & 1;
T1 = ((uint32_t)T1 >> shift) | (T1 << (32 - shift));
}
/* T2 based */
void OPPROTO op_shll_T2_im(void)
{
T2 = T2 << PARAM1;
}
void OPPROTO op_shrl_T2_im(void)
{
T2 = (uint32_t)T2 >> PARAM1;
}
void OPPROTO op_sarl_T2_im(void)
{
T2 = (int32_t)T2 >> PARAM1;
}
void OPPROTO op_rorl_T2_im(void)
{
int shift;
shift = PARAM1;
T2 = ((uint32_t)T2 >> shift) | (T2 << (32 - shift));
}
/* T1 based, use T0 as shift count */
void OPPROTO op_shll_T1_T0(void)
{
int shift;
shift = T0 & 0xff;
if (shift >= 32)
T1 = 0;
else
T1 = T1 << shift;
FORCE_RET();
}
void OPPROTO op_shrl_T1_T0(void)
{
int shift;
shift = T0 & 0xff;
if (shift >= 32)
T1 = 0;
else
T1 = (uint32_t)T1 >> shift;
FORCE_RET();
}
void OPPROTO op_sarl_T1_T0(void)
{
int shift;
shift = T0 & 0xff;
if (shift >= 32)
shift = 31;
T1 = (int32_t)T1 >> shift;
}
void OPPROTO op_rorl_T1_T0(void)
{
int shift;
shift = T0 & 0x1f;
if (shift) {
T1 = ((uint32_t)T1 >> shift) | (T1 << (32 - shift));
}
FORCE_RET();
}
/* T1 based, use T0 as shift count and compute CF */
void OPPROTO op_shll_T1_T0_cc(void)
{
int shift;
shift = T0 & 0xff;
if (shift >= 32) {
if (shift == 32)
env->CF = T1 & 1;
else
env->CF = 0;
T1 = 0;
} else if (shift != 0) {
env->CF = (T1 >> (32 - shift)) & 1;
T1 = T1 << shift;
}
FORCE_RET();
}
void OPPROTO op_shrl_T1_T0_cc(void)
{
int shift;
shift = T0 & 0xff;
if (shift >= 32) {
if (shift == 32)
env->CF = (T1 >> 31) & 1;
else
env->CF = 0;
T1 = 0;
} else if (shift != 0) {
env->CF = (T1 >> (shift - 1)) & 1;
T1 = (uint32_t)T1 >> shift;
}
FORCE_RET();
}
void OPPROTO op_sarl_T1_T0_cc(void)
{
int shift;
shift = T0 & 0xff;
if (shift >= 32) {
env->CF = (T1 >> 31) & 1;
T1 = (int32_t)T1 >> 31;
} else {
env->CF = (T1 >> (shift - 1)) & 1;
T1 = (int32_t)T1 >> shift;
}
FORCE_RET();
}
void OPPROTO op_rorl_T1_T0_cc(void)
{
int shift1, shift;
shift1 = T0 & 0xff;
shift = shift1 & 0x1f;
if (shift == 0) {
if (shift1 != 0)
env->CF = (T1 >> 31) & 1;
} else {
env->CF = (T1 >> (shift - 1)) & 1;
T1 = ((uint32_t)T1 >> shift) | (T1 << (32 - shift));
}
FORCE_RET();
}
/* exceptions */
void OPPROTO op_swi(void)
{
env->exception_index = EXCP_SWI;
cpu_loop_exit();
}
void OPPROTO op_undef_insn(void)
{
env->exception_index = EXCP_UDEF;
cpu_loop_exit();
}
/* thread support */
spinlock_t global_cpu_lock = SPIN_LOCK_UNLOCKED;
void cpu_lock(void)
{
spin_lock(&global_cpu_lock);
}
void cpu_unlock(void)
{
spin_unlock(&global_cpu_lock);
}
+234 -969
View File
File diff suppressed because it is too large. Load diff
+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)
+423
View File
@@ -0,0 +1,423 @@
/*
* 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);
#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);
#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 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
+3214
View File
File diff suppressed because it is too large. Load diff
+128
View File
@@ -0,0 +1,128 @@
OUTPUT_FORMAT("elf32-sparc", "elf32-sparc",
"elf32-sparc")
OUTPUT_ARCH(sparc)
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: */
. = 0x60000000 + 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) }
/* 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 . */
}
+27
View File
@@ -0,0 +1,27 @@
/* this struct defines the way the registers are stored on the
stack during a system call. */
struct target_pt_regs {
target_long uregs[18];
};
#define ARM_cpsr uregs[16]
#define ARM_pc uregs[15]
#define ARM_lr uregs[14]
#define ARM_sp uregs[13]
#define ARM_ip uregs[12]
#define ARM_fp uregs[11]
#define ARM_r10 uregs[10]
#define ARM_r9 uregs[9]
#define ARM_r8 uregs[8]
#define ARM_r7 uregs[7]
#define ARM_r6 uregs[6]
#define ARM_r5 uregs[5]
#define ARM_r4 uregs[4]
#define ARM_r3 uregs[3]
#define ARM_r2 uregs[2]
#define ARM_r1 uregs[1]
#define ARM_r0 uregs[0]
#define ARM_ORIG_r0 uregs[17]
-914
View File
@@ -1,491 +1,3 @@
/* from linux/unistd.h */
#define TARGET_NR_exit 1
#define TARGET_NR_fork 2
#define TARGET_NR_read 3
#define TARGET_NR_write 4
#define TARGET_NR_open 5
#define TARGET_NR_close 6
#define TARGET_NR_waitpid 7
#define TARGET_NR_creat 8
#define TARGET_NR_link 9
#define TARGET_NR_unlink 10
#define TARGET_NR_execve 11
#define TARGET_NR_chdir 12
#define TARGET_NR_time 13
#define TARGET_NR_mknod 14
#define TARGET_NR_chmod 15
#define TARGET_NR_lchown 16
#define TARGET_NR_break 17
#define TARGET_NR_oldstat 18
#define TARGET_NR_lseek 19
#define TARGET_NR_getpid 20
#define TARGET_NR_mount 21
#define TARGET_NR_umount 22
#define TARGET_NR_setuid 23
#define TARGET_NR_getuid 24
#define TARGET_NR_stime 25
#define TARGET_NR_ptrace 26
#define TARGET_NR_alarm 27
#define TARGET_NR_oldfstat 28
#define TARGET_NR_pause 29
#define TARGET_NR_utime 30
#define TARGET_NR_stty 31
#define TARGET_NR_gtty 32
#define TARGET_NR_access 33
#define TARGET_NR_nice 34
#define TARGET_NR_ftime 35
#define TARGET_NR_sync 36
#define TARGET_NR_kill 37
#define TARGET_NR_rename 38
#define TARGET_NR_mkdir 39
#define TARGET_NR_rmdir 40
#define TARGET_NR_dup 41
#define TARGET_NR_pipe 42
#define TARGET_NR_times 43
#define TARGET_NR_prof 44
#define TARGET_NR_brk 45
#define TARGET_NR_setgid 46
#define TARGET_NR_getgid 47
#define TARGET_NR_signal 48
#define TARGET_NR_geteuid 49
#define TARGET_NR_getegid 50
#define TARGET_NR_acct 51
#define TARGET_NR_umount2 52
#define TARGET_NR_lock 53
#define TARGET_NR_ioctl 54
#define TARGET_NR_fcntl 55
#define TARGET_NR_mpx 56
#define TARGET_NR_setpgid 57
#define TARGET_NR_ulimit 58
#define TARGET_NR_oldolduname 59
#define TARGET_NR_umask 60
#define TARGET_NR_chroot 61
#define TARGET_NR_ustat 62
#define TARGET_NR_dup2 63
#define TARGET_NR_getppid 64
#define TARGET_NR_getpgrp 65
#define TARGET_NR_setsid 66
#define TARGET_NR_sigaction 67
#define TARGET_NR_sgetmask 68
#define TARGET_NR_ssetmask 69
#define TARGET_NR_setreuid 70
#define TARGET_NR_setregid 71
#define TARGET_NR_sigsuspend 72
#define TARGET_NR_sigpending 73
#define TARGET_NR_sethostname 74
#define TARGET_NR_setrlimit 75
#define TARGET_NR_getrlimit 76 /* Back compatible 2Gig limited rlimit */
#define TARGET_NR_getrusage 77
#define TARGET_NR_gettimeofday 78
#define TARGET_NR_settimeofday 79
#define TARGET_NR_getgroups 80
#define TARGET_NR_setgroups 81
#define TARGET_NR_select 82
#define TARGET_NR_symlink 83
#define TARGET_NR_oldlstat 84
#define TARGET_NR_readlink 85
#define TARGET_NR_uselib 86
#define TARGET_NR_swapon 87
#define TARGET_NR_reboot 88
#define TARGET_NR_readdir 89
#define TARGET_NR_mmap 90
#define TARGET_NR_munmap 91
#define TARGET_NR_truncate 92
#define TARGET_NR_ftruncate 93
#define TARGET_NR_fchmod 94
#define TARGET_NR_fchown 95
#define TARGET_NR_getpriority 96
#define TARGET_NR_setpriority 97
#define TARGET_NR_profil 98
#define TARGET_NR_statfs 99
#define TARGET_NR_fstatfs 100
#define TARGET_NR_ioperm 101
#define TARGET_NR_socketcall 102
#define TARGET_NR_syslog 103
#define TARGET_NR_setitimer 104
#define TARGET_NR_getitimer 105
#define TARGET_NR_stat 106
#define TARGET_NR_lstat 107
#define TARGET_NR_fstat 108
#define TARGET_NR_olduname 109
#define TARGET_NR_iopl 110
#define TARGET_NR_vhangup 111
#define TARGET_NR_idle 112
#define TARGET_NR_vm86old 113
#define TARGET_NR_wait4 114
#define TARGET_NR_swapoff 115
#define TARGET_NR_sysinfo 116
#define TARGET_NR_ipc 117
#define TARGET_NR_fsync 118
#define TARGET_NR_sigreturn 119
#define TARGET_NR_clone 120
#define TARGET_NR_setdomainname 121
#define TARGET_NR_uname 122
#define TARGET_NR_modify_ldt 123
#define TARGET_NR_adjtimex 124
#define TARGET_NR_mprotect 125
#define TARGET_NR_sigprocmask 126
#define TARGET_NR_create_module 127
#define TARGET_NR_init_module 128
#define TARGET_NR_delete_module 129
#define TARGET_NR_get_kernel_syms 130
#define TARGET_NR_quotactl 131
#define TARGET_NR_getpgid 132
#define TARGET_NR_fchdir 133
#define TARGET_NR_bdflush 134
#define TARGET_NR_sysfs 135
#define TARGET_NR_personality 136
#define TARGET_NR_afs_syscall 137 /* Syscall for Andrew File System */
#define TARGET_NR_setfsuid 138
#define TARGET_NR_setfsgid 139
#define TARGET_NR__llseek 140
#define TARGET_NR_getdents 141
#define TARGET_NR__newselect 142
#define TARGET_NR_flock 143
#define TARGET_NR_msync 144
#define TARGET_NR_readv 145
#define TARGET_NR_writev 146
#define TARGET_NR_getsid 147
#define TARGET_NR_fdatasync 148
#define TARGET_NR__sysctl 149
#define TARGET_NR_mlock 150
#define TARGET_NR_munlock 151
#define TARGET_NR_mlockall 152
#define TARGET_NR_munlockall 153
#define TARGET_NR_sched_setparam 154
#define TARGET_NR_sched_getparam 155
#define TARGET_NR_sched_setscheduler 156
#define TARGET_NR_sched_getscheduler 157
#define TARGET_NR_sched_yield 158
#define TARGET_NR_sched_get_priority_max 159
#define TARGET_NR_sched_get_priority_min 160
#define TARGET_NR_sched_rr_get_interval 161
#define TARGET_NR_nanosleep 162
#define TARGET_NR_mremap 163
#define TARGET_NR_setresuid 164
#define TARGET_NR_getresuid 165
#define TARGET_NR_vm86 166
#define TARGET_NR_query_module 167
#define TARGET_NR_poll 168
#define TARGET_NR_nfsservctl 169
#define TARGET_NR_setresgid 170
#define TARGET_NR_getresgid 171
#define TARGET_NR_prctl 172
#define TARGET_NR_rt_sigreturn 173
#define TARGET_NR_rt_sigaction 174
#define TARGET_NR_rt_sigprocmask 175
#define TARGET_NR_rt_sigpending 176
#define TARGET_NR_rt_sigtimedwait 177
#define TARGET_NR_rt_sigqueueinfo 178
#define TARGET_NR_rt_sigsuspend 179
#define TARGET_NR_pread 180
#define TARGET_NR_pwrite 181
#define TARGET_NR_chown 182
#define TARGET_NR_getcwd 183
#define TARGET_NR_capget 184
#define TARGET_NR_capset 185
#define TARGET_NR_sigaltstack 186
#define TARGET_NR_sendfile 187
#define TARGET_NR_getpmsg 188 /* some people actually want streams */
#define TARGET_NR_putpmsg 189 /* some people actually want streams */
#define TARGET_NR_vfork 190
#define TARGET_NR_ugetrlimit 191 /* SuS compliant getrlimit */
#define TARGET_NR_mmap2 192
#define TARGET_NR_truncate64 193
#define TARGET_NR_ftruncate64 194
#define TARGET_NR_stat64 195
#define TARGET_NR_lstat64 196
#define TARGET_NR_fstat64 197
#define TARGET_NR_lchown32 198
#define TARGET_NR_getuid32 199
#define TARGET_NR_getgid32 200
#define TARGET_NR_geteuid32 201
#define TARGET_NR_getegid32 202
#define TARGET_NR_setreuid32 203
#define TARGET_NR_setregid32 204
#define TARGET_NR_getgroups32 205
#define TARGET_NR_setgroups32 206
#define TARGET_NR_fchown32 207
#define TARGET_NR_setresuid32 208
#define TARGET_NR_getresuid32 209
#define TARGET_NR_setresgid32 210
#define TARGET_NR_getresgid32 211
#define TARGET_NR_chown32 212
#define TARGET_NR_setuid32 213
#define TARGET_NR_setgid32 214
#define TARGET_NR_setfsuid32 215
#define TARGET_NR_setfsgid32 216
#define TARGET_NR_pivot_root 217
#define TARGET_NR_mincore 218
#define TARGET_NR_madvise 219
#define TARGET_NR_madvise1 219 /* delete when C lib stub is removed */
#define TARGET_NR_getdents64 220
#define TARGET_NR_fcntl64 221
#define TARGET_NR_security 223 /* syscall for security modules */
#define TARGET_NR_gettid 224
#define TARGET_NR_readahead 225
#define TARGET_NR_setxattr 226
#define TARGET_NR_lsetxattr 227
#define TARGET_NR_fsetxattr 228
#define TARGET_NR_getxattr 229
#define TARGET_NR_lgetxattr 230
#define TARGET_NR_fgetxattr 231
#define TARGET_NR_listxattr 232
#define TARGET_NR_llistxattr 233
#define TARGET_NR_flistxattr 234
#define TARGET_NR_removexattr 235
#define TARGET_NR_lremovexattr 236
#define TARGET_NR_fremovexattr 237
#define TARGET_NR_tkill 238
#define TARGET_NR_sendfile64 239
#define TARGET_NR_futex 240
#define TARGET_NR_sched_setaffinity 241
#define TARGET_NR_sched_getaffinity 242
#define TARGET_NR_set_thread_area 243
#define TARGET_NR_get_thread_area 244
#define TARGET_NR_io_setup 245
#define TARGET_NR_io_destroy 246
#define TARGET_NR_io_getevents 247
#define TARGET_NR_io_submit 248
#define TARGET_NR_io_cancel 249
#define TARGET_NR_fadvise64 250
#define TARGET_NR_exit_group 252
#define TARGET_NR_lookup_dcookie 253
#define TARGET_NR_epoll_create 254
#define TARGET_NR_epoll_ctl 255
#define TARGET_NR_epoll_wait 256
#define TARGET_NR_remap_file_pages 257
#define TARGET_NR_set_tid_address 258
#define TARGET_NR_timer_create 259
#define TARGET_NR_timer_settime (TARGET_NR_timer_create+1)
#define TARGET_NR_timer_gettime (TARGET_NR_timer_create+2)
#define TARGET_NR_timer_getoverrun (TARGET_NR_timer_create+3)
#define TARGET_NR_timer_delete (TARGET_NR_timer_create+4)
#define TARGET_NR_clock_settime (TARGET_NR_timer_create+5)
#define TARGET_NR_clock_gettime (TARGET_NR_timer_create+6)
#define TARGET_NR_clock_getres (TARGET_NR_timer_create+7)
#define TARGET_NR_clock_nanosleep (TARGET_NR_timer_create+8)
#define TARGET_SIG_BLOCK 0 /* for blocking signals */
#define TARGET_SIG_UNBLOCK 1 /* for unblocking signals */
#define TARGET_SIG_SETMASK 2 /* for setting the signal mask */
struct target_stat {
unsigned short st_dev;
unsigned short __pad1;
target_ulong st_ino;
unsigned short st_mode;
unsigned short st_nlink;
unsigned short st_uid;
unsigned short st_gid;
unsigned short st_rdev;
unsigned short __pad2;
target_ulong st_size;
target_ulong st_blksize;
target_ulong st_blocks;
target_ulong target_st_atime;
target_ulong __unused1;
target_ulong target_st_mtime;
target_ulong __unused2;
target_ulong target_st_ctime;
target_ulong __unused3;
target_ulong __unused4;
target_ulong __unused5;
};
/* This matches struct stat64 in glibc2.1, hence the absolutely
* insane amounts of padding around dev_t's.
*/
struct target_stat64 {
unsigned short st_dev;
unsigned char __pad0[10];
#define TARGET_STAT64_HAS_BROKEN_ST_INO 1
target_ulong __st_ino;
unsigned int st_mode;
unsigned int st_nlink;
target_ulong st_uid;
target_ulong st_gid;
unsigned short st_rdev;
unsigned char __pad3[10];
long long st_size;
target_ulong st_blksize;
target_ulong st_blocks; /* Number 512-byte blocks allocated. */
target_ulong __pad4; /* future possible st_blocks high bits */
target_ulong target_st_atime;
target_ulong __pad5;
target_ulong target_st_mtime;
target_ulong __pad6;
target_ulong target_st_ctime;
target_ulong __pad7; /* will be high 32 bits of ctime someday */
unsigned long long st_ino;
} __attribute__((packed));
#define TARGET_SA_NOCLDSTOP 0x00000001
#define TARGET_SA_NOCLDWAIT 0x00000002 /* not supported yet */
#define TARGET_SA_SIGINFO 0x00000004
#define TARGET_SA_ONSTACK 0x08000000
#define TARGET_SA_RESTART 0x10000000
#define TARGET_SA_NODEFER 0x40000000
#define TARGET_SA_RESETHAND 0x80000000
#define TARGET_SA_RESTORER 0x04000000
#define TARGET_SIGHUP 1
#define TARGET_SIGINT 2
#define TARGET_SIGQUIT 3
#define TARGET_SIGILL 4
#define TARGET_SIGTRAP 5
#define TARGET_SIGABRT 6
#define TARGET_SIGIOT 6
#define TARGET_SIGBUS 7
#define TARGET_SIGFPE 8
#define TARGET_SIGKILL 9
#define TARGET_SIGUSR1 10
#define TARGET_SIGSEGV 11
#define TARGET_SIGUSR2 12
#define TARGET_SIGPIPE 13
#define TARGET_SIGALRM 14
#define TARGET_SIGTERM 15
#define TARGET_SIGSTKFLT 16
#define TARGET_SIGCHLD 17
#define TARGET_SIGCONT 18
#define TARGET_SIGSTOP 19
#define TARGET_SIGTSTP 20
#define TARGET_SIGTTIN 21
#define TARGET_SIGTTOU 22
#define TARGET_SIGURG 23
#define TARGET_SIGXCPU 24
#define TARGET_SIGXFSZ 25
#define TARGET_SIGVTALRM 26
#define TARGET_SIGPROF 27
#define TARGET_SIGWINCH 28
#define TARGET_SIGIO 29
#define TARGET_SIGRTMIN 32
struct target_old_sigaction {
target_ulong _sa_handler;
target_ulong sa_mask;
target_ulong sa_flags;
target_ulong sa_restorer;
};
struct target_sigaction {
target_ulong _sa_handler;
target_ulong sa_flags;
target_ulong sa_restorer;
target_sigset_t sa_mask;
};
typedef union target_sigval {
int sival_int;
target_ulong sival_ptr;
} target_sigval_t;
#define TARGET_SI_MAX_SIZE 128
#define TARGET_SI_PAD_SIZE ((TARGET_SI_MAX_SIZE/sizeof(int)) - 3)
typedef struct target_siginfo {
int si_signo;
int si_errno;
int si_code;
union {
int _pad[TARGET_SI_PAD_SIZE];
/* kill() */
struct {
pid_t _pid; /* sender's pid */
uid_t _uid; /* sender's uid */
} _kill;
/* POSIX.1b timers */
struct {
unsigned int _timer1;
unsigned int _timer2;
} _timer;
/* POSIX.1b signals */
struct {
pid_t _pid; /* sender's pid */
uid_t _uid; /* sender's uid */
target_sigval_t _sigval;
} _rt;
/* SIGCHLD */
struct {
pid_t _pid; /* which child */
uid_t _uid; /* sender's uid */
int _status; /* exit code */
target_clock_t _utime;
target_clock_t _stime;
} _sigchld;
/* SIGILL, SIGFPE, SIGSEGV, SIGBUS */
struct {
target_ulong _addr; /* faulting insn/memory ref. */
} _sigfault;
/* SIGPOLL */
struct {
int _band; /* POLL_IN, POLL_OUT, POLL_MSG */
int _fd;
} _sigpoll;
} _sifields;
} target_siginfo_t;
/*
* si_code values
* Digital reserves positive values for kernel-generated signals.
*/
#define TARGET_SI_USER 0 /* sent by kill, sigsend, raise */
#define TARGET_SI_KERNEL 0x80 /* sent by the kernel from somewhere */
#define TARGET_SI_QUEUE -1 /* sent by sigqueue */
#define TARGET_SI_TIMER -2 /* sent by timer expiration */
#define TARGET_SI_MESGQ -3 /* sent by real time mesq state change */
#define TARGET_SI_ASYNCIO -4 /* sent by AIO completion */
#define TARGET_SI_SIGIO -5 /* sent by queued SIGIO */
/*
* SIGILL si_codes
*/
#define TARGET_ILL_ILLOPN (2) /* illegal operand */
/*
* SIGFPE si_codes
*/
#define TARGET_FPE_INTDIV (1) /* integer divide by zero */
#define TARGET_FPE_INTOVF (2) /* integer overflow */
#define TARGET_FPE_FLTDIV (3) /* floating point divide by zero */
#define TARGET_FPE_FLTOVF (4) /* floating point overflow */
#define TARGET_FPE_FLTUND (5) /* floating point underflow */
#define TARGET_FPE_FLTRES (6) /* floating point inexact result */
#define TARGET_FPE_FLTINV (7) /* floating point invalid operation */
#define TARGET_FPE_FLTSUB (8) /* subscript out of range */
#define TARGET_NSIGFPE 8
/*
* SIGSEGV si_codes
*/
#define TARGET_SEGV_MAPERR (1) /* address not mapped to object */
#define TARGET_SEGV_ACCERR (2) /* invalid permissions for mapped object */
/*
* SIGTRAP si_codes
*/
#define TARGET_TRAP_BRKPT (1) /* process breakpoint */
#define TARGET_TRAP_TRACE (2) /* process trace trap */
/* default linux values for the selectors */
#define __USER_CS (0x23)
#define __USER_DS (0x2B)
@@ -510,261 +22,6 @@ struct target_pt_regs {
/* ioctls */
/*
* The following is for compatibility across the various Linux
* platforms. The i386 ioctl numbering scheme doesn't really enforce
* a type field. De facto, however, the top 8 bits of the lower 16
* bits are indeed used as a type field, so we might just as well make
* this explicit here. Please be sure to use the decoding macros
* below from now on.
*/
#define TARGET_IOC_NRBITS 8
#define TARGET_IOC_TYPEBITS 8
#define TARGET_IOC_SIZEBITS 14
#define TARGET_IOC_DIRBITS 2
#define TARGET_IOC_NRMASK ((1 << TARGET_IOC_NRBITS)-1)
#define TARGET_IOC_TYPEMASK ((1 << TARGET_IOC_TYPEBITS)-1)
#define TARGET_IOC_SIZEMASK ((1 << TARGET_IOC_SIZEBITS)-1)
#define TARGET_IOC_DIRMASK ((1 << TARGET_IOC_DIRBITS)-1)
#define TARGET_IOC_NRSHIFT 0
#define TARGET_IOC_TYPESHIFT (TARGET_IOC_NRSHIFT+TARGET_IOC_NRBITS)
#define TARGET_IOC_SIZESHIFT (TARGET_IOC_TYPESHIFT+TARGET_IOC_TYPEBITS)
#define TARGET_IOC_DIRSHIFT (TARGET_IOC_SIZESHIFT+TARGET_IOC_SIZEBITS)
/*
* Direction bits.
*/
#define TARGET_IOC_NONE 0U
#define TARGET_IOC_WRITE 1U
#define TARGET_IOC_READ 2U
#define TARGET_IOC(dir,type,nr,size) \
(((dir) << TARGET_IOC_DIRSHIFT) | \
((type) << TARGET_IOC_TYPESHIFT) | \
((nr) << TARGET_IOC_NRSHIFT) | \
((size) << TARGET_IOC_SIZESHIFT))
/* used to create numbers */
#define TARGET_IO(type,nr) TARGET_IOC(TARGET_IOC_NONE,(type),(nr),0)
#define TARGET_IOR(type,nr,size) TARGET_IOC(TARGET_IOC_READ,(type),(nr),sizeof(size))
#define TARGET_IOW(type,nr,size) TARGET_IOC(TARGET_IOC_WRITE,(type),(nr),sizeof(size))
#define TARGET_IOWR(type,nr,size) TARGET_IOC(TARGET_IOC_READ|TARGET_IOC_WRITE,(type),(nr),sizeof(size))
/* 0x54 is just a magic number to make these relatively unique ('T') */
#define TARGET_TCGETS 0x5401
#define TARGET_TCSETS 0x5402
#define TARGET_TCSETSW 0x5403
#define TARGET_TCSETSF 0x5404
#define TARGET_TCGETA 0x5405
#define TARGET_TCSETA 0x5406
#define TARGET_TCSETAW 0x5407
#define TARGET_TCSETAF 0x5408
#define TARGET_TCSBRK 0x5409
#define TARGET_TCXONC 0x540A
#define TARGET_TCFLSH 0x540B
#define TARGET_TIOCEXCL 0x540C
#define TARGET_TIOCNXCL 0x540D
#define TARGET_TIOCSCTTY 0x540E
#define TARGET_TIOCGPGRP 0x540F
#define TARGET_TIOCSPGRP 0x5410
#define TARGET_TIOCOUTQ 0x5411
#define TARGET_TIOCSTI 0x5412
#define TARGET_TIOCGWINSZ 0x5413
#define TARGET_TIOCSWINSZ 0x5414
#define TARGET_TIOCMGET 0x5415
#define TARGET_TIOCMBIS 0x5416
#define TARGET_TIOCMBIC 0x5417
#define TARGET_TIOCMSET 0x5418
#define TARGET_TIOCGSOFTCAR 0x5419
#define TARGET_TIOCSSOFTCAR 0x541A
#define TARGET_FIONREAD 0x541B
#define TARGET_TIOCINQ FIONREAD
#define TARGET_TIOCLINUX 0x541C
#define TARGET_TIOCCONS 0x541D
#define TARGET_TIOCGSERIAL 0x541E
#define TARGET_TIOCSSERIAL 0x541F
#define TARGET_TIOCPKT 0x5420
#define TARGET_FIONBIO 0x5421
#define TARGET_TIOCNOTTY 0x5422
#define TARGET_TIOCSETD 0x5423
#define TARGET_TIOCGETD 0x5424
#define TARGET_TCSBRKP 0x5425 /* Needed for POSIX tcsendbreak() */
#define TARGET_TIOCTTYGSTRUCT 0x5426 /* For debugging only */
#define TARGET_TIOCSBRK 0x5427 /* BSD compatibility */
#define TARGET_TIOCCBRK 0x5428 /* BSD compatibility */
#define TARGET_TIOCGSID 0x5429 /* Return the session ID of FD */
#define TARGET_TIOCGPTN TARGET_IOR('T',0x30, unsigned int) /* Get Pty Number (of pty-mux device) */
#define TARGET_TIOCSPTLCK TARGET_IOW('T',0x31, int) /* Lock/unlock Pty */
#define TARGET_FIONCLEX 0x5450 /* these numbers need to be adjusted. */
#define TARGET_FIOCLEX 0x5451
#define TARGET_FIOASYNC 0x5452
#define TARGET_TIOCSERCONFIG 0x5453
#define TARGET_TIOCSERGWILD 0x5454
#define TARGET_TIOCSERSWILD 0x5455
#define TARGET_TIOCGLCKTRMIOS 0x5456
#define TARGET_TIOCSLCKTRMIOS 0x5457
#define TARGET_TIOCSERGSTRUCT 0x5458 /* For debugging only */
#define TARGET_TIOCSERGETLSR 0x5459 /* Get line status register */
#define TARGET_TIOCSERGETMULTI 0x545A /* Get multiport config */
#define TARGET_TIOCSERSETMULTI 0x545B /* Set multiport config */
#define TARGET_TIOCMIWAIT 0x545C /* wait for a change on serial input line(s) */
#define TARGET_TIOCGICOUNT 0x545D /* read serial port inline interrupt counts */
#define TARGET_TIOCGHAYESESP 0x545E /* Get Hayes ESP configuration */
#define TARGET_TIOCSHAYESESP 0x545F /* Set Hayes ESP configuration */
/* Used for packet mode */
#define TARGET_TIOCPKT_DATA 0
#define TARGET_TIOCPKT_FLUSHREAD 1
#define TARGET_TIOCPKT_FLUSHWRITE 2
#define TARGET_TIOCPKT_STOP 4
#define TARGET_TIOCPKT_START 8
#define TARGET_TIOCPKT_NOSTOP 16
#define TARGET_TIOCPKT_DOSTOP 32
#define TARGET_TIOCSER_TEMT 0x01 /* Transmitter physically empty */
/* from asm/termbits.h */
#define TARGET_NCCS 19
struct target_termios {
unsigned int c_iflag; /* input mode flags */
unsigned int c_oflag; /* output mode flags */
unsigned int c_cflag; /* control mode flags */
unsigned int c_lflag; /* local mode flags */
unsigned char c_line; /* line discipline */
unsigned char c_cc[TARGET_NCCS]; /* control characters */
};
/* c_iflag bits */
#define TARGET_IGNBRK 0000001
#define TARGET_BRKINT 0000002
#define TARGET_IGNPAR 0000004
#define TARGET_PARMRK 0000010
#define TARGET_INPCK 0000020
#define TARGET_ISTRIP 0000040
#define TARGET_INLCR 0000100
#define TARGET_IGNCR 0000200
#define TARGET_ICRNL 0000400
#define TARGET_IUCLC 0001000
#define TARGET_IXON 0002000
#define TARGET_IXANY 0004000
#define TARGET_IXOFF 0010000
#define TARGET_IMAXBEL 0020000
/* c_oflag bits */
#define TARGET_OPOST 0000001
#define TARGET_OLCUC 0000002
#define TARGET_ONLCR 0000004
#define TARGET_OCRNL 0000010
#define TARGET_ONOCR 0000020
#define TARGET_ONLRET 0000040
#define TARGET_OFILL 0000100
#define TARGET_OFDEL 0000200
#define TARGET_NLDLY 0000400
#define TARGET_NL0 0000000
#define TARGET_NL1 0000400
#define TARGET_CRDLY 0003000
#define TARGET_CR0 0000000
#define TARGET_CR1 0001000
#define TARGET_CR2 0002000
#define TARGET_CR3 0003000
#define TARGET_TABDLY 0014000
#define TARGET_TAB0 0000000
#define TARGET_TAB1 0004000
#define TARGET_TAB2 0010000
#define TARGET_TAB3 0014000
#define TARGET_XTABS 0014000
#define TARGET_BSDLY 0020000
#define TARGET_BS0 0000000
#define TARGET_BS1 0020000
#define TARGET_VTDLY 0040000
#define TARGET_VT0 0000000
#define TARGET_VT1 0040000
#define TARGET_FFDLY 0100000
#define TARGET_FF0 0000000
#define TARGET_FF1 0100000
/* c_cflag bit meaning */
#define TARGET_CBAUD 0010017
#define TARGET_B0 0000000 /* hang up */
#define TARGET_B50 0000001
#define TARGET_B75 0000002
#define TARGET_B110 0000003
#define TARGET_B134 0000004
#define TARGET_B150 0000005
#define TARGET_B200 0000006
#define TARGET_B300 0000007
#define TARGET_B600 0000010
#define TARGET_B1200 0000011
#define TARGET_B1800 0000012
#define TARGET_B2400 0000013
#define TARGET_B4800 0000014
#define TARGET_B9600 0000015
#define TARGET_B19200 0000016
#define TARGET_B38400 0000017
#define TARGET_EXTA B19200
#define TARGET_EXTB B38400
#define TARGET_CSIZE 0000060
#define TARGET_CS5 0000000
#define TARGET_CS6 0000020
#define TARGET_CS7 0000040
#define TARGET_CS8 0000060
#define TARGET_CSTOPB 0000100
#define TARGET_CREAD 0000200
#define TARGET_PARENB 0000400
#define TARGET_PARODD 0001000
#define TARGET_HUPCL 0002000
#define TARGET_CLOCAL 0004000
#define TARGET_CBAUDEX 0010000
#define TARGET_B57600 0010001
#define TARGET_B115200 0010002
#define TARGET_B230400 0010003
#define TARGET_B460800 0010004
#define TARGET_CIBAUD 002003600000 /* input baud rate (not used) */
#define TARGET_CRTSCTS 020000000000 /* flow control */
/* c_lflag bits */
#define TARGET_ISIG 0000001
#define TARGET_ICANON 0000002
#define TARGET_XCASE 0000004
#define TARGET_ECHO 0000010
#define TARGET_ECHOE 0000020
#define TARGET_ECHOK 0000040
#define TARGET_ECHONL 0000100
#define TARGET_NOFLSH 0000200
#define TARGET_TOSTOP 0000400
#define TARGET_ECHOCTL 0001000
#define TARGET_ECHOPRT 0002000
#define TARGET_ECHOKE 0004000
#define TARGET_FLUSHO 0010000
#define TARGET_PENDIN 0040000
#define TARGET_IEXTEN 0100000
/* c_cc character offsets */
#define TARGET_VINTR 0
#define TARGET_VQUIT 1
#define TARGET_VERASE 2
#define TARGET_VKILL 3
#define TARGET_VEOF 4
#define TARGET_VTIME 5
#define TARGET_VMIN 6
#define TARGET_VSWTC 7
#define TARGET_VSTART 8
#define TARGET_VSTOP 9
#define TARGET_VSUSP 10
#define TARGET_VEOL 11
#define TARGET_VREPRINT 12
#define TARGET_VDISCARD 13
#define TARGET_VWERASE 14
#define TARGET_VLNEXT 15
#define TARGET_VEOL2 16
#define TARGET_LDT_ENTRIES 8192
#define TARGET_LDT_ENTRY_SIZE 8
@@ -779,7 +36,6 @@ struct target_modify_ldt_ldt_s {
unsigned int flags;
};
/* vm86 defines */
#define TARGET_BIOSSEG 0x0f000
@@ -910,11 +166,6 @@ struct target_ipc_kludge {
int msgtyp;
};
struct alpha_msgbuf {
long mtype;
char mtext[4096];
};
struct target_ipc_perm {
int key;
unsigned short uid;
@@ -967,168 +218,3 @@ union target_semun {
unsigned int __pad; /* really void* */
};
#define TARGET_F_DUPFD 0 /* dup */
#define TARGET_F_GETFD 1 /* get close_on_exec */
#define TARGET_F_SETFD 2 /* set/clear close_on_exec */
#define TARGET_F_GETFL 3 /* get file->f_flags */
#define TARGET_F_SETFL 4 /* set file->f_flags */
#define TARGET_F_GETLK 5
#define TARGET_F_SETLK 6
#define TARGET_F_SETLKW 7
#define TARGET_F_SETOWN 8 /* for sockets. */
#define TARGET_F_GETOWN 9 /* for sockets. */
#define TARGET_F_SETSIG 10 /* for sockets. */
#define TARGET_F_GETSIG 11 /* for sockets. */
#define TARGET_F_GETLK64 12 /* using 'struct flock64' */
#define TARGET_F_SETLK64 13
#define TARGET_F_SETLKW64 14
struct target_flock {
short l_type;
short l_whence;
target_ulong l_start;
target_ulong l_len;
int l_pid;
};
struct target_flock64 {
short l_type;
short l_whence;
unsigned long long l_start;
unsigned long long l_len;
int l_pid;
};
/* soundcard defines (XXX: move them to generic file syscall_defs.h) */
#define TARGET_SNDCTL_COPR_HALT 0xc0144307
#define TARGET_SNDCTL_COPR_LOAD 0xcfb04301
#define TARGET_SNDCTL_COPR_RCODE 0xc0144303
#define TARGET_SNDCTL_COPR_RCVMSG 0x8fa44309
#define TARGET_SNDCTL_COPR_RDATA 0xc0144302
#define TARGET_SNDCTL_COPR_RESET 0x00004300
#define TARGET_SNDCTL_COPR_RUN 0xc0144306
#define TARGET_SNDCTL_COPR_SENDMSG 0xcfa44308
#define TARGET_SNDCTL_COPR_WCODE 0x40144305
#define TARGET_SNDCTL_COPR_WDATA 0x40144304
#define TARGET_SNDCTL_DSP_CHANNELS 0xc0045006
#define TARGET_SNDCTL_DSP_GETBLKSIZE 0xc0045004
#define TARGET_SNDCTL_DSP_GETCAPS 0x8004500f
#define TARGET_SNDCTL_DSP_GETFMTS 0x8004500b
#define TARGET_SNDCTL_DSP_GETIPTR 0x800c5011
#define TARGET_SNDCTL_DSP_GETISPACE 0x8010500d
#define TARGET_SNDCTL_DSP_GETOPTR 0x800c5012
#define TARGET_SNDCTL_DSP_GETOSPACE 0x8010500c
#define TARGET_SNDCTL_DSP_GETTRIGGER 0x80045010
#define TARGET_SNDCTL_DSP_MAPINBUF 0x80085013
#define TARGET_SNDCTL_DSP_MAPOUTBUF 0x80085014
#define TARGET_SNDCTL_DSP_NONBLOCK 0x0000500e
#define TARGET_SNDCTL_DSP_POST 0x00005008
#define TARGET_SNDCTL_DSP_RESET 0x00005000
#define TARGET_SNDCTL_DSP_SAMPLESIZE 0xc0045005
#define TARGET_SNDCTL_DSP_SETDUPLEX 0x00005016
#define TARGET_SNDCTL_DSP_SETFMT 0xc0045005
#define TARGET_SNDCTL_DSP_SETFRAGMENT 0xc004500a
#define TARGET_SNDCTL_DSP_SETSYNCRO 0x00005015
#define TARGET_SNDCTL_DSP_SETTRIGGER 0x40045010
#define TARGET_SNDCTL_DSP_SPEED 0xc0045002
#define TARGET_SNDCTL_DSP_STEREO 0xc0045003
#define TARGET_SNDCTL_DSP_SUBDIVIDE 0xc0045009
#define TARGET_SNDCTL_DSP_SYNC 0x00005001
#define TARGET_SNDCTL_FM_4OP_ENABLE 0x4004510f
#define TARGET_SNDCTL_FM_LOAD_INSTR 0x40285107
#define TARGET_SNDCTL_MIDI_INFO 0xc074510c
#define TARGET_SNDCTL_MIDI_MPUCMD 0xc0216d02
#define TARGET_SNDCTL_MIDI_MPUMODE 0xc0046d01
#define TARGET_SNDCTL_MIDI_PRETIME 0xc0046d00
#define TARGET_SNDCTL_PMGR_ACCESS 0xcfb85110
#define TARGET_SNDCTL_PMGR_IFACE 0xcfb85001
#define TARGET_SNDCTL_SEQ_CTRLRATE 0xc0045103
#define TARGET_SNDCTL_SEQ_GETINCOUNT 0x80045105
#define TARGET_SNDCTL_SEQ_GETOUTCOUNT 0x80045104
#define TARGET_SNDCTL_SEQ_NRMIDIS 0x8004510b
#define TARGET_SNDCTL_SEQ_NRSYNTHS 0x8004510a
#define TARGET_SNDCTL_SEQ_OUTOFBAND 0x40085112
#define TARGET_SNDCTL_SEQ_PANIC 0x00005111
#define TARGET_SNDCTL_SEQ_PERCMODE 0x40045106
#define TARGET_SNDCTL_SEQ_RESET 0x00005100
#define TARGET_SNDCTL_SEQ_RESETSAMPLES 0x40045109
#define TARGET_SNDCTL_SEQ_SYNC 0x00005101
#define TARGET_SNDCTL_SEQ_TESTMIDI 0x40045108
#define TARGET_SNDCTL_SEQ_THRESHOLD 0x4004510d
#define TARGET_SNDCTL_SEQ_TRESHOLD 0x4004510d
#define TARGET_SNDCTL_SYNTH_INFO 0xc08c5102
#define TARGET_SNDCTL_SYNTH_MEMAVL 0xc004510e
#define TARGET_SNDCTL_TMR_CONTINUE 0x00005404
#define TARGET_SNDCTL_TMR_METRONOME 0x40045407
#define TARGET_SNDCTL_TMR_SELECT 0x40045408
#define TARGET_SNDCTL_TMR_SOURCE 0xc0045406
#define TARGET_SNDCTL_TMR_START 0x00005402
#define TARGET_SNDCTL_TMR_STOP 0x00005403
#define TARGET_SNDCTL_TMR_TEMPO 0xc0045405
#define TARGET_SNDCTL_TMR_TIMEBASE 0xc0045401
#define TARGET_SOUND_PCM_WRITE_FILTER 0xc0045007
#define TARGET_SOUND_PCM_READ_RATE 0x80045002
#define TARGET_SOUND_PCM_READ_CHANNELS 0x80045006
#define TARGET_SOUND_PCM_READ_BITS 0x80045005
#define TARGET_SOUND_PCM_READ_FILTER 0x80045007
#define TARGET_SOUND_MIXER_INFO 0x80304d65
#define TARGET_SOUND_MIXER_ACCESS 0xc0804d66
#define TARGET_SOUND_MIXER_PRIVATE1 0xc0044d6f
#define TARGET_SOUND_MIXER_PRIVATE2 0xc0044d70
#define TARGET_SOUND_MIXER_PRIVATE3 0xc0044d71
#define TARGET_SOUND_MIXER_PRIVATE4 0xc0044d72
#define TARGET_SOUND_MIXER_PRIVATE5 0xc0044d73
#define TARGET_SOUND_MIXER_READ_VOLUME 0x80044d00
#define TARGET_SOUND_MIXER_READ_BASS 0x80044d01
#define TARGET_SOUND_MIXER_READ_TREBLE 0x80044d02
#define TARGET_SOUND_MIXER_READ_SYNTH 0x80044d03
#define TARGET_SOUND_MIXER_READ_PCM 0x80044d04
#define TARGET_SOUND_MIXER_READ_SPEAKER 0x80044d05
#define TARGET_SOUND_MIXER_READ_LINE 0x80044d06
#define TARGET_SOUND_MIXER_READ_MIC 0x80044d07
#define TARGET_SOUND_MIXER_READ_CD 0x80044d08
#define TARGET_SOUND_MIXER_READ_IMIX 0x80044d09
#define TARGET_SOUND_MIXER_READ_ALTPCM 0x80044d0a
#define TARGET_SOUND_MIXER_READ_RECLEV 0x80044d0b
#define TARGET_SOUND_MIXER_READ_IGAIN 0x80044d0c
#define TARGET_SOUND_MIXER_READ_OGAIN 0x80044d0d
#define TARGET_SOUND_MIXER_READ_LINE1 0x80044d0e
#define TARGET_SOUND_MIXER_READ_LINE2 0x80044d0f
#define TARGET_SOUND_MIXER_READ_LINE3 0x80044d10
#define TARGET_SOUND_MIXER_READ_MUTE 0x80044d1f
#define TARGET_SOUND_MIXER_READ_ENHANCE 0x80044d1f
#define TARGET_SOUND_MIXER_READ_LOUD 0x80044d1f
#define TARGET_SOUND_MIXER_READ_RECSRC 0x80044dff
#define TARGET_SOUND_MIXER_READ_DEVMASK 0x80044dfe
#define TARGET_SOUND_MIXER_READ_RECMASK 0x80044dfd
#define TARGET_SOUND_MIXER_READ_STEREODEVS 0x80044dfb
#define TARGET_SOUND_MIXER_READ_CAPS 0x80044dfc
#define TARGET_SOUND_MIXER_WRITE_VOLUME 0xc0044d00
#define TARGET_SOUND_MIXER_WRITE_BASS 0xc0044d01
#define TARGET_SOUND_MIXER_WRITE_TREBLE 0xc0044d02
#define TARGET_SOUND_MIXER_WRITE_SYNTH 0xc0044d03
#define TARGET_SOUND_MIXER_WRITE_PCM 0xc0044d04
#define TARGET_SOUND_MIXER_WRITE_SPEAKER 0xc0044d05
#define TARGET_SOUND_MIXER_WRITE_LINE 0xc0044d06
#define TARGET_SOUND_MIXER_WRITE_MIC 0xc0044d07
#define TARGET_SOUND_MIXER_WRITE_CD 0xc0044d08
#define TARGET_SOUND_MIXER_WRITE_IMIX 0xc0044d09
#define TARGET_SOUND_MIXER_WRITE_ALTPCM 0xc0044d0a
#define TARGET_SOUND_MIXER_WRITE_RECLEV 0xc0044d0b
#define TARGET_SOUND_MIXER_WRITE_IGAIN 0xc0044d0c
#define TARGET_SOUND_MIXER_WRITE_OGAIN 0xc0044d0d
#define TARGET_SOUND_MIXER_WRITE_LINE1 0xc0044d0e
#define TARGET_SOUND_MIXER_WRITE_LINE2 0xc0044d0f
#define TARGET_SOUND_MIXER_WRITE_LINE3 0xc0044d10
#define TARGET_SOUND_MIXER_WRITE_MUTE 0xc0044d1f
#define TARGET_SOUND_MIXER_WRITE_ENHANCE 0xc0044d1f
#define TARGET_SOUND_MIXER_WRITE_LOUD 0xc0044d1f
#define TARGET_SOUND_MIXER_WRITE_RECSRC 0xc0044dff
#define TARGET_VFAT_IOCTL_READDIR_BOTH 0x82187201
#define TARGET_VFAT_IOCTL_READDIR_SHORT 0x82187202
#define TARGET_SIOCATMARK 0x8905
+2 -1
View File
@@ -1,6 +1,7 @@
gmon.out
testsig
hello
hello-i386
hello-arm
sha1.test.c
sha1.c
test-i386
+12 -3
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 $@ $<
@@ -35,9 +35,11 @@ test-i386: test-i386.c test-i386-code16.S test-i386-vm86.S \
$(CC) $(CFLAGS) $(LDFLAGS) -o $@ test-i386.c \
test-i386-code16.S test-i386-vm86.S -lm
test: test-i386
ifeq ($(ARCH),i386)
test: test-i386
./test-i386 > test-i386.ref
else
test:
endif
$(QEMU) test-i386 > test-i386.out
@if diff -u test-i386.ref test-i386.out ; then echo "Auto Test OK"; fi
@@ -57,5 +59,12 @@ speed: sha1 sha1-i386
runcom: runcom.c
$(CC) $(CFLAGS) $(LDFLAGS) -o $@ $<
# arm test
hello-arm: hello-arm.o
arm-linux-ld -o $@ $<
hello-arm.o: hello-arm.c
arm-linux-gcc -Wall -g -O2 -c -o $@ $<
clean:
rm -f *~ *.o $(TESTS)
+113
View File
@@ -0,0 +1,113 @@
#define __NR_SYSCALL_BASE 0x900000
#define __NR_exit1 (__NR_SYSCALL_BASE+ 1)
#define __NR_write (__NR_SYSCALL_BASE+ 4)
#define __sys2(x) #x
#define __sys1(x) __sys2(x)
#ifndef __syscall
#define __syscall(name) "swi\t" __sys1(__NR_##name) "\n\t"
#endif
#define __syscall_return(type, res) \
do { \
return (type) (res); \
} while (0)
#define _syscall0(type,name) \
type name(void) { \
long __res; \
__asm__ __volatile__ ( \
__syscall(name) \
"mov %0,r0" \
:"=r" (__res) : : "r0","lr"); \
__syscall_return(type,__res); \
}
#define _syscall1(type,name,type1,arg1) \
type name(type1 arg1) { \
long __res; \
__asm__ __volatile__ ( \
"mov\tr0,%1\n\t" \
__syscall(name) \
"mov %0,r0" \
: "=r" (__res) \
: "r" ((long)(arg1)) \
: "r0","lr"); \
__syscall_return(type,__res); \
}
#define _syscall2(type,name,type1,arg1,type2,arg2) \
type name(type1 arg1,type2 arg2) { \
long __res; \
__asm__ __volatile__ ( \
"mov\tr0,%1\n\t" \
"mov\tr1,%2\n\t" \
__syscall(name) \
"mov\t%0,r0" \
: "=r" (__res) \
: "r" ((long)(arg1)),"r" ((long)(arg2)) \
: "r0","r1","lr"); \
__syscall_return(type,__res); \
}
#define _syscall3(type,name,type1,arg1,type2,arg2,type3,arg3) \
type name(type1 arg1,type2 arg2,type3 arg3) { \
long __res; \
__asm__ __volatile__ ( \
"mov\tr0,%1\n\t" \
"mov\tr1,%2\n\t" \
"mov\tr2,%3\n\t" \
__syscall(name) \
"mov\t%0,r0" \
: "=r" (__res) \
: "r" ((long)(arg1)),"r" ((long)(arg2)),"r" ((long)(arg3)) \
: "r0","r1","r2","lr"); \
__syscall_return(type,__res); \
}
#define _syscall4(type,name,type1,arg1,type2,arg2,type3,arg3,type4,arg4) \
type name(type1 arg1, type2 arg2, type3 arg3, type4 arg4) { \
long __res; \
__asm__ __volatile__ ( \
"mov\tr0,%1\n\t" \
"mov\tr1,%2\n\t" \
"mov\tr2,%3\n\t" \
"mov\tr3,%4\n\t" \
__syscall(name) \
"mov\t%0,r0" \
: "=r" (__res) \
: "r" ((long)(arg1)),"r" ((long)(arg2)),"r" ((long)(arg3)),"r" ((long)(arg4)) \
: "r0","r1","r2","r3","lr"); \
__syscall_return(type,__res); \
}
#define _syscall5(type,name,type1,arg1,type2,arg2,type3,arg3,type4,arg4,type5,arg5) \
type name(type1 arg1, type2 arg2, type3 arg3, type4 arg4, type5 arg5) { \
long __res; \
__asm__ __volatile__ ( \
"mov\tr0,%1\n\t" \
"mov\tr1,%2\n\t" \
"mov\tr2,%3\n\t" \
"mov\tr3,%4\n\t" \
"mov\tr4,%5\n\t" \
__syscall(name) \
"mov\t%0,r0" \
: "=r" (__res) \
: "r" ((long)(arg1)),"r" ((long)(arg2)),"r" ((long)(arg3)),"r" ((long)(arg4)), \
"r" ((long)(arg5)) \
: "r0","r1","r2","r3","r4","lr"); \
__syscall_return(type,__res); \
}
_syscall1(int,exit1,int,status);
_syscall3(int,write,int,fd,const char *,buf, int, len);
void _start(void)
{
write(1, "Hello World\n", 12);
exit1(0);
}
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
+108 -5
View File
@@ -1,6 +1,7 @@
#define _GNU_SOURCE
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <inttypes.h>
#include <math.h>
#include <signal.h>
@@ -9,7 +10,8 @@
#include <sys/mman.h>
#include <asm/vm86.h>
#define TEST_CMOV 0
#define TEST_CMOV 0
#define TEST_FCOMI 0
#define xglue(x, y) x ## y
#define glue(x, y) xglue(x, y)
@@ -510,12 +512,28 @@ void test_fcmp(double a, double b)
a, b, a > b);
printf("(%f<=%f)=%d\n",
a, b, a >= b);
if (TEST_FCOMI) {
unsigned int eflags;
/* test f(u)comi instruction */
asm("fcomi %2, %1\n"
"pushf\n"
"pop %0\n"
: "=r" (eflags)
: "t" (a), "u" (b));
printf("fcomi(%f %f)=%08x\n", a, b, eflags & (CC_Z | CC_P | CC_C));
}
}
void test_fcvt(double a)
{
float fa;
long double la;
int16_t fpuc;
int i;
int64_t lla;
int ia;
int16_t wa;
double ra;
fa = a;
la = a;
@@ -524,9 +542,21 @@ void test_fcvt(double a)
printf("a=%016Lx\n", *(long long *)&a);
printf("la=%016Lx %04x\n", *(long long *)&la,
*(unsigned short *)((char *)(&la) + 8));
printf("a=%f floor(a)=%f\n", a, floor(a));
printf("a=%f ceil(a)=%f\n", a, ceil(a));
printf("a=%f rint(a)=%f\n", a, rint(a));
/* test all roundings */
asm volatile ("fstcw %0" : "=m" (fpuc));
for(i=0;i<4;i++) {
asm volatile ("fldcw %0" : : "m" ((fpuc & ~0x0c00) | (i << 10)));
asm volatile ("fist %0" : "=m" (wa) : "t" (a));
asm volatile ("fistl %0" : "=m" (ia) : "t" (a));
asm volatile ("fistpll %0" : "=m" (lla) : "t" (a) : "st");
asm volatile ("frndint ; fstl %0" : "=m" (ra) : "t" (a));
asm volatile ("fldcw %0" : : "m" (fpuc));
printf("(short)a = %d\n", wa);
printf("(int)a = %d\n", ia);
printf("(int64_t)a = %Ld\n", lla);
printf("rint(a) = %f\n", ra);
}
}
#define TEST(N) \
@@ -556,6 +586,57 @@ void test_fbcd(double a)
a, bcd[4], bcd[3], bcd[2], bcd[1], bcd[0], b);
}
#define TEST_ENV(env, prefix)\
{\
memset((env), 0xaa, sizeof(*(env)));\
asm("fld1\n"\
prefix "fnstenv %1\n"\
prefix "fldenv %1\n"\
: "=t" (res) : "m" (*(env)));\
printf("res=%f\n", res);\
printf("fpuc=%04x fpus=%04x fptag=%04x\n",\
(env)->fpuc,\
(env)->fpus & 0xff00,\
(env)->fptag);\
memset((env), 0xaa, sizeof(*(env)));\
asm("fld1\n"\
prefix "fnsave %1\n"\
prefix "frstor %1\n"\
: "=t" (res) : "m" (*(env)));\
printf("res=%f\n", res);\
printf("fpuc=%04x fpus=%04x fptag=%04x\n",\
(env)->fpuc,\
(env)->fpus & 0xff00,\
(env)->fptag);\
printf("ST(0) = %Lf\n",\
(env)->fpregs[0]);\
}
void test_fenv(void)
{
struct __attribute__((packed)) {
uint16_t fpuc;
uint16_t dummy1;
uint16_t fpus;
uint16_t dummy2;
uint16_t fptag;
uint16_t dummy3;
uint32_t ignored[4];
long double fpregs[8];
} float_env32;
struct __attribute__((packed)) {
uint16_t fpuc;
uint16_t fpus;
uint16_t fptag;
uint16_t ignored[4];
long double fpregs[8];
} float_env16;
double res;
TEST_ENV(&float_env16, "data16 ");
TEST_ENV(&float_env32, "");
}
void test_floats(void)
{
test_fops(2, 3);
@@ -563,12 +644,16 @@ void test_floats(void)
test_fcmp(2, -1);
test_fcmp(2, 2);
test_fcmp(2, 3);
test_fcvt(0.5);
test_fcvt(-0.5);
test_fcvt(1.0/7.0);
test_fcvt(-1.0/9.0);
test_fcvt(1e30);
test_fcvt(32768);
test_fcvt(-1e20);
test_fconst();
test_fbcd(1234567890123456);
test_fbcd(-123451234567890);
test_fenv();
}
/**********************************************/
@@ -853,6 +938,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];
@@ -862,6 +950,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];
+2 -74
View File
@@ -29,80 +29,7 @@
#define MAX_STRUCTS 128
/* XXX: make it dynamic */
static StructEntry struct_entries[MAX_STRUCTS];
static inline int thunk_type_size(const argtype *type_ptr, int is_host)
{
int type, size;
const StructEntry *se;
type = *type_ptr;
switch(type) {
case TYPE_CHAR:
return 1;
case TYPE_SHORT:
return 2;
case TYPE_INT:
return 4;
case TYPE_LONGLONG:
case TYPE_ULONGLONG:
return 8;
case TYPE_LONG:
case TYPE_ULONG:
case TYPE_PTRVOID:
case TYPE_PTR:
if (is_host) {
return HOST_LONG_SIZE;
} else {
return TARGET_LONG_SIZE;
}
break;
case TYPE_ARRAY:
size = type_ptr[1];
return size * thunk_type_size(type_ptr + 2, is_host);
case TYPE_STRUCT:
se = struct_entries + type_ptr[1];
return se->size[is_host];
default:
return -1;
}
}
static inline int thunk_type_align(const argtype *type_ptr, int is_host)
{
int type;
const StructEntry *se;
type = *type_ptr;
switch(type) {
case TYPE_CHAR:
return 1;
case TYPE_SHORT:
return 2;
case TYPE_INT:
return 4;
case TYPE_LONGLONG:
case TYPE_ULONGLONG:
return 8;
case TYPE_LONG:
case TYPE_ULONG:
case TYPE_PTRVOID:
case TYPE_PTR:
if (is_host) {
return HOST_LONG_SIZE;
} else {
return TARGET_LONG_SIZE;
}
break;
case TYPE_ARRAY:
return thunk_type_align(type_ptr + 2, is_host);
case TYPE_STRUCT:
se = struct_entries + type_ptr[1];
return se->align[is_host];
default:
return -1;
}
}
StructEntry struct_entries[MAX_STRUCTS];
static inline const argtype *thunk_type_next(const argtype *type_ptr)
{
@@ -167,6 +94,7 @@ void thunk_register_struct(int id, const char *name, const argtype *types)
offset += size;
if (align > max_align)
max_align = align;
type_ptr = thunk_type_next(type_ptr);
}
offset = (offset + max_align - 1) & ~(max_align - 1);
se->size[i] = offset;
+80 -4
View File
@@ -61,15 +61,13 @@
#endif
#ifdef WORDS_BIGENDIAN
#if defined(WORDS_BIGENDIAN) != defined(TARGET_WORDS_BIGENDIAN)
#define BSWAP_NEEDED
#endif
/* XXX: autoconf */
#define TARGET_I386
#define TARGET_LONG_BITS 32
#if defined(__alpha__) || defined (__ia64__)
#define HOST_LONG_BITS 64
#else
@@ -77,7 +75,7 @@
#endif
#define TARGET_LONG_SIZE (TARGET_LONG_BITS / 8)
#define HOST_LONG_SIZE (TARGET_LONG_BITS / 8)
#define HOST_LONG_SIZE (HOST_LONG_BITS / 8)
static inline uint16_t bswap16(uint16_t x)
{
@@ -238,6 +236,84 @@ 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[];
static inline int thunk_type_size(const argtype *type_ptr, int is_host)
{
int type, size;
const StructEntry *se;
type = *type_ptr;
switch(type) {
case TYPE_CHAR:
return 1;
case TYPE_SHORT:
return 2;
case TYPE_INT:
return 4;
case TYPE_LONGLONG:
case TYPE_ULONGLONG:
return 8;
case TYPE_LONG:
case TYPE_ULONG:
case TYPE_PTRVOID:
case TYPE_PTR:
if (is_host) {
return HOST_LONG_SIZE;
} else {
return TARGET_LONG_SIZE;
}
break;
case TYPE_ARRAY:
size = type_ptr[1];
return size * thunk_type_size(type_ptr + 2, is_host);
case TYPE_STRUCT:
se = struct_entries + type_ptr[1];
return se->size[is_host];
default:
return -1;
}
}
static inline int thunk_type_align(const argtype *type_ptr, int is_host)
{
int type;
const StructEntry *se;
type = *type_ptr;
switch(type) {
case TYPE_CHAR:
return 1;
case TYPE_SHORT:
return 2;
case TYPE_INT:
return 4;
case TYPE_LONGLONG:
case TYPE_ULONGLONG:
return 8;
case TYPE_LONG:
case TYPE_ULONG:
case TYPE_PTRVOID:
case TYPE_PTR:
if (is_host) {
return HOST_LONG_SIZE;
} else {
return TARGET_LONG_SIZE;
}
break;
case TYPE_ARRAY:
return thunk_type_align(type_ptr + 2, is_host);
case TYPE_STRUCT:
se = struct_entries + type_ptr[1];
return se->align[is_host];
default:
return -1;
}
}
#endif /* NO_THUNK_TYPE_SIZE */
unsigned int target_to_host_bitmask(unsigned int x86_mask,
bitmask_transtbl * trans_tbl);
+760
View File
@@ -0,0 +1,760 @@
/*
* ARM translation
*
* 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 <stdarg.h>
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <inttypes.h>
#include "cpu-arm.h"
#include "exec.h"
#include "disas.h"
/* internal defines */
typedef struct DisasContext {
uint8_t *pc;
int is_jmp;
struct TranslationBlock *tb;
} DisasContext;
/* XXX: move that elsewhere */
static uint16_t *gen_opc_ptr;
static uint32_t *gen_opparam_ptr;
extern FILE *logfile;
extern int loglevel;
enum {
#define DEF(s, n, copy_size) INDEX_op_ ## s,
#include "opc-arm.h"
#undef DEF
NB_OPS,
};
#include "gen-op-arm.h"
typedef void (GenOpFunc)(void);
typedef void (GenOpFunc1)(long);
typedef void (GenOpFunc2)(long, long);
typedef void (GenOpFunc3)(long, long, long);
static GenOpFunc2 *gen_test_cc[14] = {
gen_op_test_eq,
gen_op_test_ne,
gen_op_test_cs,
gen_op_test_cc,
gen_op_test_mi,
gen_op_test_pl,
gen_op_test_vs,
gen_op_test_vc,
gen_op_test_hi,
gen_op_test_ls,
gen_op_test_ge,
gen_op_test_lt,
gen_op_test_gt,
gen_op_test_le,
};
const uint8_t table_logic_cc[16] = {
1, /* and */
1, /* xor */
0, /* sub */
0, /* rsb */
0, /* add */
0, /* adc */
0, /* sbc */
0, /* rsc */
1, /* andl */
1, /* xorl */
0, /* cmp */
0, /* cmn */
1, /* orr */
1, /* mov */
1, /* bic */
1, /* mvn */
};
static GenOpFunc1 *gen_shift_T1_im[4] = {
gen_op_shll_T1_im,
gen_op_shrl_T1_im,
gen_op_sarl_T1_im,
gen_op_rorl_T1_im,
};
static GenOpFunc1 *gen_shift_T2_im[4] = {
gen_op_shll_T2_im,
gen_op_shrl_T2_im,
gen_op_sarl_T2_im,
gen_op_rorl_T2_im,
};
static GenOpFunc1 *gen_shift_T1_im_cc[4] = {
gen_op_shll_T1_im_cc,
gen_op_shrl_T1_im_cc,
gen_op_sarl_T1_im_cc,
gen_op_rorl_T1_im_cc,
};
static GenOpFunc *gen_shift_T1_T0[4] = {
gen_op_shll_T1_T0,
gen_op_shrl_T1_T0,
gen_op_sarl_T1_T0,
gen_op_rorl_T1_T0,
};
static GenOpFunc *gen_shift_T1_T0_cc[4] = {
gen_op_shll_T1_T0_cc,
gen_op_shrl_T1_T0_cc,
gen_op_sarl_T1_T0_cc,
gen_op_rorl_T1_T0_cc,
};
static GenOpFunc *gen_op_movl_TN_reg[3][16] = {
{
gen_op_movl_T0_r0,
gen_op_movl_T0_r1,
gen_op_movl_T0_r2,
gen_op_movl_T0_r3,
gen_op_movl_T0_r4,
gen_op_movl_T0_r5,
gen_op_movl_T0_r6,
gen_op_movl_T0_r7,
gen_op_movl_T0_r8,
gen_op_movl_T0_r9,
gen_op_movl_T0_r10,
gen_op_movl_T0_r11,
gen_op_movl_T0_r12,
gen_op_movl_T0_r13,
gen_op_movl_T0_r14,
gen_op_movl_T0_r15,
},
{
gen_op_movl_T1_r0,
gen_op_movl_T1_r1,
gen_op_movl_T1_r2,
gen_op_movl_T1_r3,
gen_op_movl_T1_r4,
gen_op_movl_T1_r5,
gen_op_movl_T1_r6,
gen_op_movl_T1_r7,
gen_op_movl_T1_r8,
gen_op_movl_T1_r9,
gen_op_movl_T1_r10,
gen_op_movl_T1_r11,
gen_op_movl_T1_r12,
gen_op_movl_T1_r13,
gen_op_movl_T1_r14,
gen_op_movl_T1_r15,
},
{
gen_op_movl_T2_r0,
gen_op_movl_T2_r1,
gen_op_movl_T2_r2,
gen_op_movl_T2_r3,
gen_op_movl_T2_r4,
gen_op_movl_T2_r5,
gen_op_movl_T2_r6,
gen_op_movl_T2_r7,
gen_op_movl_T2_r8,
gen_op_movl_T2_r9,
gen_op_movl_T2_r10,
gen_op_movl_T2_r11,
gen_op_movl_T2_r12,
gen_op_movl_T2_r13,
gen_op_movl_T2_r14,
gen_op_movl_T2_r15,
},
};
static GenOpFunc *gen_op_movl_reg_TN[2][16] = {
{
gen_op_movl_r0_T0,
gen_op_movl_r1_T0,
gen_op_movl_r2_T0,
gen_op_movl_r3_T0,
gen_op_movl_r4_T0,
gen_op_movl_r5_T0,
gen_op_movl_r6_T0,
gen_op_movl_r7_T0,
gen_op_movl_r8_T0,
gen_op_movl_r9_T0,
gen_op_movl_r10_T0,
gen_op_movl_r11_T0,
gen_op_movl_r12_T0,
gen_op_movl_r13_T0,
gen_op_movl_r14_T0,
gen_op_movl_r15_T0,
},
{
gen_op_movl_r0_T1,
gen_op_movl_r1_T1,
gen_op_movl_r2_T1,
gen_op_movl_r3_T1,
gen_op_movl_r4_T1,
gen_op_movl_r5_T1,
gen_op_movl_r6_T1,
gen_op_movl_r7_T1,
gen_op_movl_r8_T1,
gen_op_movl_r9_T1,
gen_op_movl_r10_T1,
gen_op_movl_r11_T1,
gen_op_movl_r12_T1,
gen_op_movl_r13_T1,
gen_op_movl_r14_T1,
gen_op_movl_r15_T1,
},
};
static GenOpFunc1 *gen_op_movl_TN_im[3] = {
gen_op_movl_T0_im,
gen_op_movl_T1_im,
gen_op_movl_T2_im,
};
static inline void gen_movl_TN_reg(DisasContext *s, int reg, int t)
{
int val;
if (reg == 15) {
/* normaly, since we updated PC, we need only to add 4 */
val = (long)s->pc + 4;
gen_op_movl_TN_im[t](val);
} else {
gen_op_movl_TN_reg[t][reg]();
}
}
static inline void gen_movl_T0_reg(DisasContext *s, int reg)
{
gen_movl_TN_reg(s, reg, 0);
}
static inline void gen_movl_T1_reg(DisasContext *s, int reg)
{
gen_movl_TN_reg(s, reg, 1);
}
static inline void gen_movl_T2_reg(DisasContext *s, int reg)
{
gen_movl_TN_reg(s, reg, 2);
}
static inline void gen_movl_reg_TN(DisasContext *s, int reg, int t)
{
gen_op_movl_reg_TN[t][reg]();
if (reg == 15) {
s->is_jmp = DISAS_JUMP;
}
}
static inline void gen_movl_reg_T0(DisasContext *s, int reg)
{
gen_movl_reg_TN(s, reg, 0);
}
static inline void gen_movl_reg_T1(DisasContext *s, int reg)
{
gen_movl_reg_TN(s, reg, 1);
}
static inline void gen_add_data_offset(DisasContext *s, unsigned int insn)
{
int val, rm, shift;
if (!(insn & (1 << 25))) {
/* immediate */
val = insn & 0xfff;
if (!(insn & (1 << 23)))
val = -val;
gen_op_addl_T1_im(val);
} else {
/* shift/register */
rm = (insn) & 0xf;
shift = (insn >> 7) & 0x1f;
gen_movl_T2_reg(s, rm);
if (shift != 0) {
gen_shift_T2_im[(insn >> 5) & 3](shift);
}
if (!(insn & (1 << 23)))
gen_op_subl_T1_T2();
else
gen_op_addl_T1_T2();
}
}
static inline void gen_add_datah_offset(DisasContext *s, unsigned int insn)
{
int val, rm;
if (insn & (1 << 22)) {
/* immediate */
val = (insn & 0xf) | ((insn >> 4) & 0xf0);
if (!(insn & (1 << 23)))
val = -val;
gen_op_addl_T1_im(val);
} else {
/* register */
rm = (insn) & 0xf;
gen_movl_T2_reg(s, rm);
if (!(insn & (1 << 23)))
gen_op_subl_T1_T2();
else
gen_op_addl_T1_T2();
}
}
static void disas_arm_insn(DisasContext *s)
{
unsigned int cond, insn, val, op1, i, shift, rm, rs, rn, rd, sh;
insn = ldl(s->pc);
s->pc += 4;
cond = insn >> 28;
if (cond == 0xf)
goto illegal_op;
if (cond != 0xe) {
/* 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;
}
if ((insn & 0x0c000000) == 0 &&
(insn & 0x00000090) != 0x90) {
int set_cc, logic_cc, shiftop;
op1 = (insn >> 21) & 0xf;
set_cc = (insn >> 20) & 1;
logic_cc = table_logic_cc[op1] & set_cc;
/* data processing instruction */
if (insn & (1 << 25)) {
/* immediate operand */
val = insn & 0xff;
shift = ((insn >> 8) & 0xf) * 2;
if (shift)
val = (val >> shift) | (val << (32 - shift));
gen_op_movl_T1_im(val);
/* XXX: is CF modified ? */
} else {
/* register */
rm = (insn) & 0xf;
gen_movl_T1_reg(s, rm);
shiftop = (insn >> 5) & 3;
if (!(insn & (1 << 4))) {
shift = (insn >> 7) & 0x1f;
if (shift != 0) {
if (logic_cc) {
gen_shift_T1_im_cc[shiftop](shift);
} else {
gen_shift_T1_im[shiftop](shift);
}
}
} else {
rs = (insn >> 16) & 0xf;
gen_movl_T0_reg(s, rs);
if (logic_cc) {
gen_shift_T1_T0_cc[shiftop]();
} else {
gen_shift_T1_T0[shiftop]();
}
}
}
if (op1 != 0x0f && op1 != 0x0d) {
rn = (insn >> 16) & 0xf;
gen_movl_T0_reg(s, rn);
}
rd = (insn >> 12) & 0xf;
switch(op1) {
case 0x00:
gen_op_andl_T0_T1();
gen_movl_reg_T0(s, rd);
break;
case 0x01:
gen_op_xorl_T0_T1();
gen_movl_reg_T0(s, rd);
break;
case 0x02:
if (set_cc)
gen_op_subl_T0_T1_cc();
else
gen_op_subl_T0_T1();
gen_movl_reg_T0(s, rd);
break;
case 0x03:
if (set_cc)
gen_op_rsbl_T0_T1_cc();
else
gen_op_rsbl_T0_T1();
gen_movl_reg_T0(s, rd);
break;
case 0x04:
if (set_cc)
gen_op_addl_T0_T1_cc();
else
gen_op_addl_T0_T1();
gen_movl_reg_T0(s, rd);
break;
case 0x05:
if (set_cc)
gen_op_adcl_T0_T1_cc();
else
gen_op_adcl_T0_T1();
gen_movl_reg_T0(s, rd);
break;
case 0x06:
if (set_cc)
gen_op_sbcl_T0_T1_cc();
else
gen_op_sbcl_T0_T1();
gen_movl_reg_T0(s, rd);
break;
case 0x07:
if (set_cc)
gen_op_rscl_T0_T1_cc();
else
gen_op_rscl_T0_T1();
gen_movl_reg_T0(s, rd);
break;
case 0x08:
if (set_cc) {
gen_op_andl_T0_T1();
}
break;
case 0x09:
if (set_cc) {
gen_op_xorl_T0_T1();
}
break;
case 0x0a:
if (set_cc) {
gen_op_subl_T0_T1_cc();
}
break;
case 0x0b:
if (set_cc) {
gen_op_addl_T0_T1_cc();
}
break;
case 0x0c:
gen_op_orl_T0_T1();
gen_movl_reg_T0(s, rd);
break;
case 0x0d:
gen_movl_reg_T1(s, rd);
break;
case 0x0e:
gen_op_bicl_T0_T1();
gen_movl_reg_T0(s, rd);
break;
default:
case 0x0f:
gen_op_notl_T1();
gen_movl_reg_T1(s, rd);
break;
}
if (logic_cc)
gen_op_logic_cc();
} else {
/* other instructions */
op1 = (insn >> 24) & 0xf;
switch(op1) {
case 0x0:
case 0x1:
sh = (insn >> 5) & 3;
if (sh == 0) {
if (op1 == 0x0) {
rd = (insn >> 16) & 0xf;
rn = (insn >> 12) & 0xf;
rs = (insn >> 8) & 0xf;
rm = (insn) & 0xf;
if (!(insn & (1 << 23))) {
/* 32 bit mul */
gen_movl_T0_reg(s, rs);
gen_movl_T1_reg(s, rm);
gen_op_mul_T0_T1();
if (insn & (1 << 21)) {
gen_movl_T1_reg(s, rn);
gen_op_addl_T0_T1();
}
if (insn & (1 << 20))
gen_op_logic_cc();
gen_movl_reg_T0(s, rd);
} else {
/* 64 bit mul */
gen_movl_T0_reg(s, rs);
gen_movl_T1_reg(s, rm);
if (insn & (1 << 22))
gen_op_mull_T0_T1();
else
gen_op_imull_T0_T1();
if (insn & (1 << 21))
gen_op_addq_T0_T1(rn, rd);
if (insn & (1 << 20))
gen_op_logicq_cc();
gen_movl_reg_T0(s, rn);
gen_movl_reg_T1(s, rd);
}
} else {
/* SWP instruction */
rn = (insn >> 16) & 0xf;
rd = (insn >> 12) & 0xf;
rm = (insn) & 0xf;
gen_movl_T0_reg(s, rm);
gen_movl_T1_reg(s, rn);
if (insn & (1 << 22)) {
gen_op_swpb_T0_T1();
} else {
gen_op_swpl_T0_T1();
}
gen_movl_reg_T0(s, rd);
}
} else {
/* load/store half word */
rn = (insn >> 16) & 0xf;
rd = (insn >> 12) & 0xf;
gen_movl_T1_reg(s, rn);
if (insn & (1 << 25))
gen_add_datah_offset(s, insn);
if (insn & (1 << 20)) {
/* load */
switch(sh) {
case 1:
gen_op_lduw_T0_T1();
break;
case 2:
gen_op_ldsb_T0_T1();
break;
default:
case 3:
gen_op_ldsw_T0_T1();
break;
}
} else {
/* store */
gen_op_stw_T0_T1();
}
if (!(insn & (1 << 24)))
gen_add_datah_offset(s, insn);
if (insn & (1 << 21))
gen_movl_reg_T1(s, rn);
}
break;
case 0x4:
case 0x5:
case 0x6:
case 0x7:
/* load/store byte/word */
rn = (insn >> 16) & 0xf;
rd = (insn >> 12) & 0xf;
gen_movl_T1_reg(s, rn);
if (insn & (1 << 24))
gen_add_data_offset(s, insn);
if (insn & (1 << 20)) {
/* load */
if (insn & (1 << 22))
gen_op_ldub_T0_T1();
else
gen_op_ldl_T0_T1();
gen_movl_reg_T0(s, rd);
} else {
/* store */
gen_movl_T0_reg(s, rd);
if (insn & (1 << 22))
gen_op_stb_T0_T1();
else
gen_op_stl_T0_T1();
}
if (!(insn & (1 << 24)))
gen_add_data_offset(s, insn);
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);
} else {
/* store */
gen_movl_T0_reg(s, i);
gen_op_stl_T0_T1();
}
if (!(insn & (1 << 24)))
gen_op_addl_T1_im(val);
}
}
if (insn & (1 << 21))
gen_movl_reg_T1(s, rn);
break;
case 0xa:
case 0xb:
{
int offset;
/* branch (and link) */
val = (int)s->pc;
if (insn & (1 << 24)) {
gen_op_movl_T0_im(val);
gen_op_movl_reg_TN[0][14]();
}
offset = (((int)insn << 8) >> 8);
val += (offset << 2) + 4;
gen_op_jmp((long)s->tb, val);
s->is_jmp = DISAS_TB_JUMP;
}
break;
case 0xf:
/* swi */
gen_op_movl_T0_im((long)s->pc);
gen_op_movl_reg_TN[0][15]();
gen_op_swi();
s->is_jmp = DISAS_JUMP;
break;
default:
illegal_op:
gen_op_movl_T0_im((long)s->pc - 4);
gen_op_movl_reg_TN[0][15]();
gen_op_undef_insn();
s->is_jmp = DISAS_JUMP;
break;
}
}
}
/* 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. */
static inline int gen_intermediate_code_internal(TranslationBlock *tb, int search_pc)
{
DisasContext dc1, *dc = &dc1;
uint16_t *gen_opc_end;
int j, lj;
uint8_t *pc_start;
/* generate intermediate code */
pc_start = (uint8_t *)tb->pc;
dc->tb = tb;
gen_opc_ptr = gen_opc_buf;
gen_opc_end = gen_opc_buf + OPC_MAX_SIZE;
gen_opparam_ptr = gen_opparam_buf;
dc->is_jmp = DISAS_NEXT;
dc->pc = pc_start;
lj = -1;
do {
if (search_pc) {
j = gen_opc_ptr - gen_opc_buf;
if (lj < j) {
lj++;
while (lj < j)
gen_opc_instr_start[lj++] = 0;
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) {
/* indicate that the hash table must be used to find the next TB */
gen_op_movl_T0_0();
}
*gen_opc_ptr = INDEX_op_end;
#ifdef DEBUG_DISAS
if (loglevel) {
fprintf(logfile, "----------------\n");
fprintf(logfile, "IN: %s\n", lookup_symbol(pc_start));
disas(logfile, pc_start, dc->pc - pc_start, 0, 0);
fprintf(logfile, "\n");
fprintf(logfile, "OP:\n");
dump_ops(gen_opc_buf, gen_opparam_buf);
fprintf(logfile, "\n");
}
#endif
if (!search_pc)
tb->size = dc->pc - pc_start;
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;
cpu_exec_init();
env = malloc(sizeof(CPUARMState));
if (!env)
return NULL;
memset(env, 0, sizeof(CPUARMState));
return env;
}
void cpu_arm_close(CPUARMState *env)
{
free(env);
}
void cpu_arm_dump_state(CPUARMState *env, FILE *f, int flags)
{
int i;
for(i=0;i<16;i++) {
fprintf(f, "R%02d=%08x", i, env->regs[i]);
if ((i % 4) == 3)
fprintf(f, "\n");
else
fprintf(f, " ");
}
fprintf(f, "CPSR=%08x", env->cpsr);
}
+870 -391
View File
File diff suppressed because it is too large. Load diff
+205
View File
@@ -0,0 +1,205 @@
/*
* Host code generation
*
* 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 <stdarg.h>
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <inttypes.h>
#include "config.h"
#define IN_OP_I386
#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_CPU_H
#undef DEF
NB_OPS,
};
#include "dyngen.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_CPU_H
#undef DEF
};
static uint8_t op_nb_args[] = {
#define DEF(s, n, copy_size) n,
#include OPC_CPU_H
#undef DEF
};
void dump_ops(const uint16_t *opc_buf, const uint32_t *opparam_buf)
{
const uint16_t *opc_ptr;
const uint32_t *opparam_ptr;
int c, n, i;
opc_ptr = opc_buf;
opparam_ptr = opparam_buf;
for(;;) {
c = *opc_ptr++;
n = op_nb_args[c];
fprintf(logfile, "0x%04x: %s",
(int)(opc_ptr - opc_buf - 1), op_str[c]);
for(i = 0; i < n; i++) {
fprintf(logfile, " 0x%x", opparam_ptr[i]);
}
fprintf(logfile, "\n");
if (c == INDEX_op_end)
break;
opparam_ptr += n;
}
}
#endif
/* return non zero if the very first instruction is invalid so that
the virtual CPU can trigger an exception.
'*gen_code_size_ptr' contains the size of the generated code (host
code).
*/
int cpu_gen_code(TranslationBlock *tb,
int max_code_size, int *gen_code_size_ptr)
{
uint8_t *gen_code_buf;
int gen_code_size;
if (gen_intermediate_code(tb) < 0)
return -1;
/* generate machine code */
tb->tb_next_offset[0] = 0xffff;
tb->tb_next_offset[1] = 0xffff;
gen_code_buf = tb->tc_ptr;
gen_code_size = dyngen_code(gen_code_buf, tb->tb_next_offset,
#ifdef USE_DIRECT_JUMP
tb->tb_jmp_offset,
#else
NULL,
#endif
gen_opc_buf, gen_opparam_buf);
*gen_code_size_ptr = gen_code_size;
#ifdef DEBUG_DISAS
if (loglevel) {
fprintf(logfile, "OUT: [size=%d]\n", *gen_code_size_ptr);
disas(logfile, gen_code_buf, *gen_code_size_ptr, 1, 0);
fprintf(logfile, "\n");
fflush(logfile);
}
#endif
return 0;
}
static const unsigned short opc_copy_size[] = {
#define DEF(s, n, copy_size) copy_size,
#include OPC_CPU_H
#undef DEF
};
/* The cpu state corresponding to 'searched_pc' is restored.
*/
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_pc(tb) < 0)
return -1;
/* find opc index corresponding to search_pc */
tc_ptr = (unsigned long)tb->tc_ptr;
if (searched_pc < tc_ptr)
return -1;
j = 0;
opc_ptr = gen_opc_buf;
for(;;) {
c = *opc_ptr;
if (c == INDEX_op_end)
return -1;
tc_ptr += opc_copy_size[c];
if (searched_pc < tc_ptr)
break;
opc_ptr++;
}
j = opc_ptr - gen_opc_buf;
/* now find start of instruction before */
while (gen_opc_instr_start[j] == 0)
j--;
#if defined(TARGET_I386)
{
int cc_op;
#ifdef DEBUG_DISAS
if (loglevel) {
int i;
for(i=0;i<=j; i++) {
if (gen_opc_instr_start[i]) {
fprintf(logfile, "0x%04x: 0x%08x", i, gen_opc_pc[i]);
}
}
fprintf(logfile, "j=0x%x eip=0x%lx cs_base=%lx\n",
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;
}